GitHubでNGINX設定を管理する

NGINX | 2023年12月04日

ソフトウェアの設定やオプション、構成には、さまざまな形式があります。一方には、直感的に操作でき、無効な状態にならないよう制御する、洗練された応答性の高いGUIがあります。もう一方にあるのが、テキストファイルです。テキストファイルは、その明快さ、自動化の可能性、最小限の利用要件(ターミナルウィンドウをいくつか開いていますよね?)から、エンジニアにもDevOpsチームにも高く評価されていますが、テキストファイルによるソフトウェア構成には明確なトレードオフがあります。たとえば、テキストファイルの設定を誤ってソフトウェアパッケージをクラッシュさせたことがないLinuxユーザーを探してみてください。

ソフトウェアプロキシ、ロードバランサー、Webサーバー、APIゲートウェイを一体化した唯一のソリューションであるNGINXは、現代のインターネットインフラストラクチャを支える重要なコンポーネントです。このインフラストラクチャの多くは、Linuxカーネルを基盤とするオペレーティングシステム上に構築されています。NGINXは、このエコシステムとそれを支える専門家のニーズに適合するため、テキストベースの設定を広く採用しています。

F5 NGINX Instance Managerモジュールは、長年にわたりNGINX関連の構成オーケストレーションに広く利用されてきました。直感的なユーザーインターフェイスとAPIを通じて、リモートでの一括構成管理に役立つ高度な機能を提供し、関連ドキュメントやガードレールも備えています。一方、個々のNGINX構成ファイルはコードによく似ており、ソフトウェアチームにはすでにコード管理のための優れたツール、Gitがあります。Gitは、テキストファイルのワークフロー管理に適した多彩な機能を開発チームと運用チームに提供します。

Instance ManagerとGitなどの外部システムとの新たな統合により、バージョン管理、分散型の共同作業、承認ワークフロー、チーム間の調整といった機能を利用できます。GitHubやGitLabなどのプラットフォームでは、Webベースのユーザーインターフェースを通じて、継続的インテグレーション/継続的デプロイメント(CI/CD)、コラボレーション、課題追跡などの有用な機能も利用できます。

このブログ記事では、GitHubを使用してNGINXの設定を管理し、変更が加えられるたびに各インスタンスへ自動的にプッシュする方法をご紹介します。

Instance Manager API

Instance Managerは、Webユーザーインターフェースを補完する豊富なREST APIを提供します。このAPIの主な利点の1つは、管理対象のデータプレーンインスタンスの設定ファイルを更新できることです。最近、この機能を拡張し、設定の更新をファイルの特定のバージョンに関連付けられるようにしました。Gitリポジトリで管理する場合、設定にGitコミットハッシュをタグとして付けることができます。さらに、外部管理されている設定向けにInstance Managerへ新しい状態を実装し、設定が外部管理下にあることを、ファイルを編集しようとするユーザーに警告できるようにしました。

GitHub Actions

GitHubでは、「Actions」という機能を使用して、開発者がリポジトリ内にカスタムデプロイパイプラインを作成できます。ユーザーは独自のアクションを定義するか、「YAML定義」を介して既存のスクリプトを呼び出すことができます。これらのパイプラインは、コミットやプルリクエストのマージによってリポジトリが更新されたときなど、さまざまな方法でトリガーできます。

このブログの例では、標準のGitHub ActionsとLinuxコマンドを使用します。これらを使用し、Instance Manager APIを介して、GitHubで管理されているNGINX構成ファイルをNGINXインスタンス上で更新する方法を説明します。まず、GitHub Docsの手順に従って、リポジトリでActionsを実行するための新しいYAMLファイルを作成します。

Actionsシークレットの設定

Instance Managerは、さまざまな認証方式をサポートしています。この例では、Basic Authentication方式を使用しますが、本番環境ではOIDC認証をプロビジョニングすることを推奨します。

Instance Managerの認証情報をリポジトリに保存する代わりに、GitHubではリポジトリ変数としてシークレットを定義できます。これらの変数にはActions環境からアクセスできますが、ログには表示されません。こちらの手順に従ってInstance Managerのユーザー名とパスワードのキーをシークレットとして保存し、API呼び出しの認証に使用できるようにします。

ここでは、これらの変数を「NMS_USERNAME」と「NMS_PASSWORD」に設定しています。

リポジトリシークレットのオプションを表示している技術プラットフォームのスクリーンショット

Actions変数の設定

同様に、YAMLで定数変数を定義する代わりに、変数を切り出してGitHubのユーザーインターフェースで管理すると便利です。Variablesページでは、リポジトリ内のすべてのActionsに適用される変数を定義する方法を確認できます。この例では、Instance ManagerのFQDNまたはIP(NMS_HOSTNAME)、NGINXが稼働しているシステムの識別子(SYSTEM_ID)、更新対象となる特定のNGINXインスタンスの識別子(INSTANCE_ID)を定義します。

リポジトリ変数のオプションを表示している技術プラットフォームのスクリーンショット

注: この例を簡略化するためにこれらの変数を設定していますが、Instance Manager、System、NGINXの識別情報は別の方法で管理することもできます。たとえば、リポジトリ内にインスタンスごとの設定を格納するディレクトリを作成し、システムIDまたはインスタンスIDをディレクトリ名として使用できます。そのうえで、ディレクトリ名を読み取り、対応するインスタンス上の設定ファイルを更新するように、YAMLまたはActionスクリプトを変更できます。

NGINX構成を更新するInstance Manager REST API呼び出しの構造

Instance Managerの構成更新REST API呼び出しを機能させるには、いくつかの主要なコンポーネントが必要です。YAMLでこれらの各パラメーターを定義し、適切な形式でAPI呼び出しに組み込む必要があります。

この例では、単一のインスタンスを更新するAPI呼び出しを使用します。ただし、Instance Manager内でインスタンスグループを構成することもできます。これにより、GitHubから新しい構成がプッシュされるたびに、グループ内のすべてのインスタンスを更新できます。詳しくは、「構成の公開に関するハウツーガイド」をご覧ください。

以下に、Instance Managerの「構成更新」REST API呼び出しの内訳を示します。

https://{INSTANCE MANAGER HOSTNAME}/api/platform/v1/systems/{SYSTEM ID}/instances/{INSTANCE ID}/config' 
--header "accept: application/json" 
--header "Authorization: Basic {LOGIN CREDENTIALS}" 
--header 'Content-Type: application/json'
--data '{
    "configFiles": '{
        "rootDir": "/etc/nginx",
        "files": [{
            "contents": "{NGINX CONFIGURATION FILE}",
            "name": "{PATH TO CONFIGURATION FILE ON SYSTEM}"
        }]
    },
    "externalIdType": "{SOURCE OF CONFIGS}",
    "externalId": "{COMMIT HASH}",
    "updateTime": "{TIMESTAMP}"
}'}'

URIパラメーター

  • システム識別子 – NGINXが稼働しているシステムを識別する一意のキーです。この例では、このデータはGitHub ActionsのVariablesインターフェースで定義されています。
  • NGINXインスタンス識別子 – システム上の特定のNGINXインスタンスを識別する一意のキーです。この例では、このデータはGitHub ActionsのVariablesインターフェースで定義されています。

ヘッダーパラメーター

  • Authorization – Instance ManagerがAPI呼び出しの認証に使用する認証方式とBase64エンコードされた認証情報です。この例では、リポジトリに設定されたシークレットの認証情報データを使用してBasic認証を行います。

JSONデータパラメーター

  • configFiles – 更新対象の設定ファイルをBase64でエンコードした内容と、NGINXを実行しているシステム上での各ファイルの場所です。また、NGINX設定ファイルのルートディレクトリへのパスも指定する必要があります。通常は次のように設定されています:/etc/nginx。
  • externalIdType – Instance Managerに対して構成ファイルの取得元を識別するラベルです。指定可能な値は「git」または「other」です。この例では、このパラメーターを「git」にハードコードします。
  • externalId – 構成ファイルへの変更を識別するGitコミットのSecure Hash Algorithm(SHA)です。
  • updateTime – 現在の日付と時刻を %Y-%m-%dT%H:%M:%SZ 形式で格納する文字列。

Base64エンコーディング

Instance ManagerのAPI仕様に対応するには、特定のデータをBase64形式でエンコードして変換する必要があります。既存のGitHub Actionsにはこれを実現するネイティブな方法はありませんが、YAMLから利用できるLinuxツールを使用できます。

Instance Managerの認証情報

まず、先ほどシークレットとして定義したInstance Managerのログイン認証情報を参照し、連結します。次に、その文字列をBase64に変換し、Linux変数(NMS_LOGIN)としてechoで出力して、その結果をActionsランナーからアクセス可能な定義済みの環境変数(GITHUB_ENV)に追加します。

run: echo "NMS_LOGIN=`echo -n "${{ secrets.NMS_USERNAME }}:${{ secrets.NMS_PASSWORD }}" | base64`" >> $GITHUB_ENV

タイムスタンプ

Instance Manager APIでは、特定のAPIペイロードとともに、指定された形式のタイムスタンプを送信する必要があります。Linuxの「date」コマンドを使用すると、その形式のタイムスタンプを生成できます。前の例と同様に、生成した文字列を変数としてLinux環境に追加します。

run: echo "NMS_TIMESTAMP=`date -u +"%Y-%m-%dT%H:%M:%SZ"`" >> $GITHUB_ENV

NGINXの設定

次に、管理する予定のNGINX設定をリポジトリに追加します。GitHubリポジトリにファイルを追加する方法はいくつもあります。詳細については、GitHubのドキュメントにある「こちらのガイド」を参照してください。この例に沿って進める場合は、インスタンスと同じディレクトリ構造をGitHubリポジトリに作成できます。

以下のYAMLエントリは、前述と同様に、リポジトリから構成ファイルを読み取り、その内容をBase64でエンコードして、結果を環境変数に追加します。

run: echo "NGINX_CONF_CONFIG_FILE=`cat nginx-server/etc/nginx/nginx.conf | base64 -w 0`" >> $GITHUB_ENV

この例では、GitHubリポジトリ内のすべての設定ファイルに対して、この処理を繰り返します。

すべてを組み合わせる

最後に、GitHubのサンプルリファレンス実装を使用して、これまでに学んだ内容を実際に動作するYAMLファイルにまとめることができます。このファイルの定義に従い、ユーザーがコミットまたはプルリクエストを通じてリポジトリを更新するたびに、関連するすべてのGitHub Actionsスクリプトが実行されます。YAMLの最後のエントリでは、curlコマンドが実行され、Instance Managerが関連するすべての構成ファイルを更新するために必要なデータを含む、適切なAPI呼び出しが行われます。

注:YAMLで複数行のrunエントリ(run: |)を使用してcurlコマンドを実行してください。これにより、YAMLインタープリターはエントリのパラメーター部分にあるコロン「:」をテキストとして扱います。

name: Managing NGINX configs with GitHub and GitHub Actions 
# Controls when the workflow will run 
on: 
  # Triggers the workflow on push or pull request events but only for the "main" branch 
  push: 
    branches: [ "main" ] 
  pull_request: 
    branches: [ "main" ] 
  
  # Allows you to run this workflow manually from the Actions tab 
  workflow_dispatch: 

# A workflow run is made up of one or more jobs that can run sequentially or in parallel 
jobs: 
  # This workflow contains a single job called "build" 
  build: 
    # The type of runner that the job will run on 
    runs-on: ubuntu-latest 

    # Steps represent a sequence of tasks that will be executed as part of the job 
    steps: 
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 
      - uses: actions/checkout@v4 

      - name: Set environment variable for NMS API login credentials 
        run: echo "NMS_LOGIN=`echo -n "${{ secrets.NMS_USERNAME }}:${{ secrets.NMS_PASSWORD }}" | base64`" >> $GITHUB_ENV 

      - name: Set environment variable for NMS API timestamp 
        run: echo "NMS_TIMESTAMP=`date -u +"%Y-%m-%dT%H:%M:%SZ"`" >> $GITHUB_ENV 

      - name: Set environment variable for base64 encoded config file 
        run: echo "NGINX_CONF_CONFIG_FILE=`cat app-sfo-01/etc/nginx/nginx.conf | base64 -w 0`" >> $GITHUB_ENV 

      - name: Set environment variable for base64 encoded config file 
        run: echo "MIME_TYPES_CONFIG_FILE=`cat app-sfo-01/etc/nginx/mime.types | base64 -w 0`" >> $GITHUB_ENV 

      - name: Set environment variable for base64 encoded config file 
        run: echo "DEFAULT_CONF_CONFIG_FILE=`cat app-sfo-01/etc/nginx/conf.d/default.conf | base64 -w 0`" >> $GITHUB_ENV 

      - name: Set environment variable for base64 encoded config file 
        run: echo "SSL_CONF_CONFIG_FILE=`cat app-sfo-01/etc/nginx/conf.d/ssl.conf | base64 -w 0`" >> $GITHUB_ENV 

      - name: API call to Instance Manager 
        run: | 
          curl --location 'https://${{ vars.NMS_HOSTNAME }}/api/platform/v1/systems/${{ vars.SYSTEM_ID }}/instances/${{ vars.INSTANCE_ID }}/config' --header "accept: application/json" --header "Authorization: Basic ${{ env.NMS_LOGIN }}" --header 'Content-Type: application/json' --data '{"configFiles": {"rootDir": "/etc/nginx","files": [{"contents": "${{ env.NGINX_CONF_CONFIG_FILE }}","name": "/etc/nginx/nginx.conf"},{"contents": "${{ env.MIME_TYPES_CONFIG_FILE }}","name": "/etc/nginx/mime.types"},{"contents": "${{ env.DEFAULT_CONF_CONFIG_FILE }}","name": "/etc/nginx/conf.d/default.conf"},{"contents": "${{ env.SSL_CONF_CONFIG_FILE }}","name": "/etc/nginx/conf.d/ssl.conf"}]},"externalIdType": "git","externalId": "${{ github.sha }}","updateTime": "${{ env.NMS_TIMESTAMP }}"}' 

NGINXリファレンス実装

ファイルの変更後に構成更新API呼び出しを実行する方法はいくつかあります。GitHubを使用している場合はGitHub Actionsが最も便利ですが、GitLabやスタンドアロンのGit実装では機能しません。こうしたユースケースに対応するため、コマンドラインからトリガーすることも、カスタムスクリプトから呼び出すこともできる付属のシェルスクリプトによるリファレンス実装を開発しました。

まとめると、Instance Manager APIの新しい拡張機能は、構成の更新、ロールバック、バージョン履歴を最新の分散型アプローチで管理するための強力なツールです。この拡張機能をGitHubなどのサードパーティ製テキストファイル/コード管理プラットフォームと連携させることで、直感的なWebベースのユーザーインターフェースから、ワークフロー、CI/CD、コラボレーション、課題追跡の追加機能を利用できます。

ぜひご意見をお聞かせください。実際にお試しいただき、コメント欄またはNGINX Community Slackチャンネルでご感想をお寄せください。


共有
タグ: F5 NGINX, Tech

関連するブログ記事

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
NGINX | 2024/01/18

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する

OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
NGINX | 2023/05/31

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正

Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
NGINX | 2023/02/09

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法

Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINX | 2022/05/24

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング

NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
NGINX | 2018/08/17

SELinuxでNGINXおよびNGINX Plusを使用する

Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。

NGINX PlusによるAWS Auto Scalingグループの負荷分散
NGINX | 2017/03/06

NGINX PlusによるAWS Auto Scalingグループの負荷分散

新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります