Ansible と Spinnaker を使用した Compute Engine 上での継続的デプロイ

このチュートリアルでは、次の図に示すように、AnsibleSpinnakerGoogle Compute Engine を使って継続的デリバリー パイプラインをセットアップする方法について説明します。このアーキテクチャは、不変イメージのベイクとデプロイを例として使用しています。

不変イメージのベイクとデプロイのアーキテクチャ

Spinnaker は、ソフトウェアをクラウド リソースにデプロイする継続的デリバリー パイプラインをオーケストレートするためのオープンソース ツールです。一般的には、Debian パッケージをベースとするデプロイに使用されますが、Packer テンプレートを使用して、特定のプロビジョナーをサポートするように Spinnaker を設定することができます。

オープンソースの構成管理ツール Ansible をすでにお使いの場合は、infrastructure as code という概念をご存知でしょう。Spinnaker を使用するときは、infrastructure as code と「不変のインフラ」が対になります。不変のインフラでは、変更内容を「ベイク」した結果として仮想マシン(VM)イメージやコンテナ イメージなどのアーティファクトが作成されます。つまり、長期間稼働しているサーバーに変更内容を少しずつ適用していくわけではありません。

目標

  • Google Cloud Deployment Manager を使用して Spinnaker を Compute Engine にデプロイする。
  • Spinnaker パイプラインで使用するための GitHub リポジトリを用意する。
  • 3 ステージ Spinnaker パイプライン(テスト、ベイク、デプロイ)を作成する。
  • このパイプラインを 2 通りの方法で実行する(手動による方法と、GitHub pull リクエストを使用する方法)。
  • Red/Black デプロイ ストラテジーを使用して変更をロールバックする。

費用

このチュートリアルでは、次のような Cloud Platform の課金対象コンポーネントを使用します。

  • Compute Engine
  • Google Cloud Load Balancing
  • Google Cloud Storage
  • Google Cloud IAM

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを出すことができます。

Cloud Platform を初めて使用する方は、無料トライアルをご利用いただけます。

始める前に

  1. Google アカウントにログインします。

    Google アカウントをまだお持ちでない場合は、新しいアカウントを登録します。

  2. GCP プロジェクトを選択または作成します。

    [リソースの管理] ページに移動

  3. プロジェクトに対して課金が有効になっていることを確認します。

    課金を有効にする方法について

  4. Compute Engine API を有効にします。

    APIを有効にする

残りのコンポーネント(Spinnaker 環境とサンプルアプリなど)を GitHub からダウンロードしてデプロイします。

スタックをデプロイする前に、チュートリアルの実行に必要な IAM の役割がデフォルトのサービス アカウントに付与されていることを確認する必要があります。

  1. Google Cloud Platform Console の Cloud IAM のページに移動します。

    Cloud IAM に移動

  2. 使用する Google API サービス アカウントに、次の Cloud IAM の役割が付与されていることを確認します。

    • Compute インスタンス管理者(v1)
    • Compute ネットワーク管理者
    • Compute ストレージ管理者
    • ストレージ管理者

    サービス アカウントを作成して Cloud IAM の役割をセットアップする方法について詳しくは、新しいサービス アカウントを作成するをご覧ください。

  3. このチュートリアルでのターミナル コマンドはすべて Cloud Shell から実行します。

    Cloud Shell を開く

Spinnaker をデプロイする

最初に、Deployment Manager を使用して Spinnaker を Compute Engine にデプロイします。

  1. 用意されている GitHub リポジトリから、Deployment Manager を使用して Spinnaker 環境を起動します。

    git clone https://github.com/GoogleCloudPlatform/spinnaker-deploymentmanager
    cd spinnaker-deploymentmanager
    export GOOGLE_PROJECT=$(gcloud config get-value project)
    export DEPLOYMENT_NAME="${USER}-test1"
    export JENKINS_PASSWORD=$(openssl rand -base64 15)
    gcloud deployment-manager deployments create --template config.jinja ${DEPLOYMENT_NAME} --properties jenkinsPassword:${JENKINS_PASSWORD}

    デプロイが完了するまで数分ほどかかることがあります。完了すると Spinnaker インスタンスを使用できる状態になります。

  2. インスタンス URI を、後で簡単に参照できるように変数に保存します。

    export SPINNAKER_VM=$(gcloud compute instances list --filter="name~${DEPLOYMENT_NAME}-spinnaker.+" --uri)
  3. SSH を使用して Spinnaker インスタンスに接続し、Spinnaker UI と Jenkins UI のポートを Cloud Shell に転送します。

    gcloud compute ssh ${SPINNAKER_VM} -- -L 8081:localhost:8081 -L 8082:localhost:8082

    Spinnaker は startup-script を使用して構成されます。構成が完了するまでには最大 10 分かかります。スクリプトが完了して Spinnaker が使用できる状態になると、次のようなメッセージが /var/log/syslog に出力されます。

    $ tail /var/log/syslog
    ...
    INFO startup-script: Return code 0.
    INFO Finished running startup scripts.
    ...
    
  4. Cloud Shell の [ウェブでプレビュー] ボタンをクリックします。

  5. [ポートの変更] > [ポート 8081] をクリックして Spinnaker UI をブラウザで開きます。

    プレビュー ボタンをクリック

    Spinnaker は新しいタブで開きます。

    Spinnaker は新しいタブで開きます

Ansible でベイクするようにアプリケーションを構成する

このチュートリアルでは、サンプル アプリケーション(sample-app)をデプロイします。

  1. 自分のアカウントに、GitHub にあるリポジトリをフォークします。
  2. sample-app のクローンを自分のパソコンに作成します。

    git clone git@github.com:YOUR_GH_USER/sample-app.git
    

このリポジトリの中には、bake.yml, というファイルがあります。これは Ansible のプレイブックであり、ベイクステップのときに Packer によってローカルで実行されます。このプレイブックが、アプリケーションのビルドと必要なサービスのインストールを行います。このイメージを指定して Compute Engine インスタンスが起動されると、該当するサービスが自動的に起動され、トラフィックを処理できる状態になります。build.sh というファイルもリポジトリの中にあります。このスクリプトは、Jenkins によって Spinnaker パイプラインのテストステージで起動されます。このスクリプトがアプリケーションのテストを実行し、テストに合格するとエラーコード 0 を返します。

Spinnaker によって起動される Packer テンプレートの例を次に示します

    "provisioners": [
        {
        "type": "shell",
        "inline": ["sudo apt-add-repository -y ppa:ansible/ansible",
                "sudo apt-get update",
                "sudo apt-get install -y ansible=2.3.0.0-1ppa~xenial
    git=1:2.7.4-0ubuntu1",
                "sudo git clone [[user 'repository']] /opt/go/src/deploy",
                "cd /opt/go/src/deploy && sudo git checkout [[user
    'repository_hash']]",
                "sudo ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook -i
    'localhost,' bake.yml"]
        }
    ]

このテンプレートは、デプロイのときに Spinnaker VM に追加されて /opt/rosco/config/packer/gce-ansible.json に書き出されます。このテンプレートは後で、パイプラインを構成するときに参照されます。

Packer テンプレートの中のプロビジョナーは、次のことを行います。

  • Ansible を Personal Packages Archive(PPA)からインストールします。
  • リポジトリのクローンを作成し、パイプラインから渡された commit ハッシュをチェックアウトします。
  • bake.yml プレイブック ファイルを使用して Ansible を実行します。

この例では、Ansible プレイブックは次のことを行います。

  • Nginx をインストールし、アプリケーション ポートにアップストリームするように構成します。
  • golang をダウンロードしてインストールします。
  • アプリケーションをコンパイルしてインストールします。
  • アプリケーションを起動時に実行するための systemd サービスをインストールします。

Ansible のプレイブックは、実際のアプリケーションに合わせて調整してください。プレイブック完了時にランタイムの依存関係、構成、ロギング、サービス起動のすべてがインストールされた状態になり、そのイメージで作成されたインスタンスの初回起動時に実行されるようにする必要があります。これはイメージのベイクの中核的な概念です。イメージが作成された後にイメージが変更されることはないからです。

Spinnaker アプリケーションを作成する

このセクションでは、新しい Spinnaker アプリケーションを作成し、ロードバランサとファイアウォールを追加してサンプル アプリケーションのパイプラインで使用できるよう準備します。GCP のロードバランサでは転送ルールが使用されるので、トラフィックを許可するようにインスタンスにファイアウォール ルールを適用する必要があります。転送ルールを作成して適用するプロセスは抽象化されており、Spinnaker 内で自動的にプロビジョニングされます。

Spinnaker の [Applications] タブで次の手順を行います。

  1. UI の右上の [Actions] > [Create Application] をクリックします。
  2. [Name] を sample に設定します。
  3. [Owner Email] を自分のメールアドレスに設定します。
  4. [Account(s)] を my-google-account に設定します。
  5. [Create] をクリックします。

    画像

ロードバランサを作成する

次に、ロードバランサを作成し、HTTP ヘルスチェックを行うように設定します。

  1. UI の右上にある [Load Balancers] をクリックします。
  2. [Create Load Balancer] ボタンをクリックします。
  3. ロードバランサのタイプとして [Network] を選択します。
  4. [Create network load balancer] をクリックします。
  5. [TCP Port Range] を 80 に設定します。
  6. [Enable health check?] チェックボックスをオンにします。
  7. [Create] をクリックします。

    画像

Spinnaker によって自動的に、必要なタスクが GCP アカウントで実行され、ロードバランサと転送ルールが作成されます。

ファイアウォールを作成する

次に、このアプリケーションのファイアウォールを作成します。

  1. 右上にある [Firewalls] をクリックします。
  2. [Create Firewall] をクリックし、次のとおりに選択します。

    • [Location] の下で、[Detail] を http に設定し、[Description] を allow-http に設定します。
    • [Targets] の下で、[Targets] プルダウンをクリックし、[Specify target tags] をクリックし、[Add New Target Tag] をクリックしてから「allow-http」と入力します。
    • [Source Filters] の [Source CIDRs] の下で、[Add New Source CIDR]、[0.0.0.0/0] をクリックします。
    • [Ingress] の下で、[Add New Protocol and Port Range] をクリックし、[Protocol] を TCP に設定し、[Start Port] と [End Port] の両方を 80 に設定します。
  3. [Create] をクリックします。

    画像

Spinnaker によって、必要なタスクが GCP アカウントで実行され、ファイアウォールのルールが作成されます。

Spinnaker パイプラインを作成する

このセクションでは、アプリケーションのテスト、ベイク、デプロイの各ステージで構成されるパイプラインを定義します。これらのステージは、GitHub Webhook を使用してトリガーされます。

画像

このサンプル アプリケーションでは、次の手順でパイプラインを作成します。

  1. [Pipelines] をクリックし、[Create Pipeline or Strategy] をクリックします。

    画像

  2. [Type] を [Pipeline] に設定します。

  3. [Pipeline Name] を sample-app に設定します。

  4. [Create Pipeline] をクリックします。

トリガーを構成してパラメータを追加する

ここで作成するトリガーは、sample-app リポジトリに対して commit が行われたときに、パイプラインが新しいバージョンをビルドしてデプロイするようにするためのものです。パラメータはパイプラインの各ステージに渡され、gce-ansible.json テンプレートの中で参照されます。パラメータにはパイプラインの汎用性を高める効果もあり、そのパイプラインをテンプレートとして他のアプリケーションに利用できるようになります。

  1. GitHub Webhook を構成し、このリポジトリに関する commit 通知を受信するための署名シークレットを指定します。
  2. ローカル ターミナルからシークレットを生成します。これは、Spinnaker パイプライン構成との間で共有されます。

    export GH_WEBHOOK_SECRET=$(openssl rand -base64 15)
    echo $GH_WEBHOOK_SECRET
  3. Spinnaker UI の [Automated Triggers] の下で、[Add Trigger] をクリックしてから、次のとおりにフィールドに入力します。

    • [Type] で Git を選択します。
    • [Repo Type] で github を選択します。
    • [Organization or User] はリポジトリのオーナーに設定します。
    • [Project] はリポジトリ名、つまり sample-app に設定します。
    • [Branch] を master に設定します。
    • [Secret] を、前の手順で生成した GH_WEBHOOK_SECRET の値に設定します。
  4. [Save Changes] をクリックします。

    画像

パイプライン パラメータを追加する

リポジトリ URL を指定するパイプライン パラメータを追加します。このパラメータは後で使用します。

  1. [Parameters] の下の [Add Parameter] をクリックします。
  2. [Name] を「repository」に設定します。
  3. [Default Value] を、GitHub リポジトリの HTTPS クローン URL に設定します。[YOUR_GH_USER] は GitHub ユーザー名で置き換えてください。

    https://github.com/[YOUR_GH_USER]/sample-app.git
    
  4. [Save Changes] をクリックします。

    画像

テストステージを作成する

テストステージでは Jenkins ジョブが起動され、このジョブがアプリケーションをデプロイの前にテストします。このジョブは、リポジトリのルートにある build.sh スクリプトを呼び出します。

  1. [Pipeline configuration] ページの一番上にある [Add stage] をクリックします。
  2. [Type] で [Jenkins] を選択します。
  3. [Stage Name] に「Test」と入力してから、次のとおりに選択します。

    • [Jenkins Configuration] の下の [Master] で [Jenkins] を選択します。
    • [Job] で [runSpinnakerScript] を選択します。
  4. [Job Parameters] の下で次のとおりに選択します。

    • [COMMAND] を bash build.sh に設定します。
    • [REPO_URL] を ${parameters.repository} に設定します。
  5. [Save Changes] をクリックします。

    画像

ベイクステージを作成する

「Ansible でベイク」ステージは、テストステージの後に実行されます。独自の gce-ansible.json テンプレートを使用して Ansible プロビジョナーを実行し、デプロイ用の新しい不変イメージを生成します。

  1. [Add Stage] をクリックします。
  2. [Type] として [Bake] を選択します。
  3. [Stage Name] に「Bake with Ansible」と入力してから、[Depends On] が Test に設定されていることを確認します。
  4. [Bake Configuration] の下で、次のとおりに選択します。

    • [Package] を none に設定します。
    • [Base OS] では [xenial (v16.04)] をクリックします。
    • [Base Label] では [Release] をクリックします。
    • [Rebake] では [Rebake image without regard to the status of any existing bake] チェックボックスをオンにします。
  5. [Show Advanced Options] をクリックします。

  6. [Template File Name] を gce-ansible.json に設定します。

  7. [Add Extended Attribute] をクリックします。

    • [Key] を repository に設定し、[Value] を ${parameters.repository} に設定してから [Add] をクリックします。
    • [Add Extended Attribute] をもう一度クリックし、[Key] を repository_hash に設定し、[Value] を ${trigger.hash ?: 'master'} に設定してから [Add] をクリックします。
    • [Base Image] を ubuntu-1604-xenial-v20170328 に設定します。
  8. [Save Changes] をクリックします。

    画像

デプロイ ステージを作成する

デプロイ ステージは「Ansible でベイク」ステージの後に実行されます。このステージでは、ベイクされたイメージから起動される VM の新しいサーバー グループを作成するためのすべての自動処理が実行されます。サーバー グループはロードバランサに追加され、古いサーバー グループは red/black(blue/green)ストラテジーを使用してスワップアウトされるので、変更内容のロールバックが可能です。

  1. [Add stage] ボタンをクリックします。
  2. [Type] として [Deploy] を選択します。
  3. [Stage Name] を [Deploy] に設定し、[Depends On] が Bake with Ansible に設定されていることを確認します。
  4. [Deploy Configuration] の下の [Add server group] ボタンをクリックします。
  5. [Copy configuration from] で [None] を選択します。
  6. [Continue without a template] をクリックし、次のとおりに選択します。

    • [Stack] を nginx に設定します。
    • [Strategy] で [Red/Black] を選択します。
    • [Maximum number of server groups to leave] を 2 に設定します。
    • [Load Balancers] の下で、前の手順で作成したロードバランサ sample を選択します。
    • [Firewalls] の下で、前の手順で作成したファイアウォール sample-http を選択します。

    画像

デプロイ クラスタ構成を続ける

  1. [Instance Type] の下で [General Purpose] を選択し、サイズは [Small] を選択します。
  2. [AutoHealing Policy] の下の [Enable AutoHealing] チェックボックスをオンにします。
  3. [HTTP Health Check] を sample-hc- ヘルスチェックに設定します。これは、前の手順でロードバランサを作成したときに自動的に作成されたものです。
  4. [Metric:] で [percent] を選択し、[Max Unavailable] を 10% に設定します。
  5. [Advanced Settings] で、sample-http- タグが [Tags] に追加されていることを確認します。
  6. [Add] をクリックし、[Save Changes] をクリックします。

パイプラインを手動で実行する

これで、パイプラインの 3 つのステージがすべて作成されたので、commit トリガーを有効化する前に、手動での実行を開始してこれらのステージが適切に実行されてデプロイされることを確認します。

  1. サンプル アプリケーション ビューの一番上にある [Pipelines] リストをクリックします。
  2. sample-app パイプラインの [Start Manual Execution] ボタンをクリックし、[Run] をクリックします。これで、パイプラインが初めて実行されます。

テスト、Ansible でベイク、デプロイの各ステージが実行されて sample-app リポジトリのマスター ブランチがデプロイされます。

パイプラインの各ステージをモニタリングするには、そのステージをクリックして詳細情報を展開します。ベイクステージの実行中は、[View Bakery Details] リンクをクリックすると新しいタブが開き、Packer 実行による出力が表示されます。

画像

すべてのステージにパスすると、数分後にアプリはロードバランサの IP アドレスで使用可能になります。

ロードバランサの IP アドレスを Spinnaker UI で見つける手順は次のとおりです。

  1. [Load Balancers] ボタンをクリックします。
  2. sample ロードバランサの下のリージョン [US-WEST1] をクリックします。
  3. IP アドレスは [DNS Name] フィールドの下に表示されます。

GitHub webhook からビルドをトリガーする

次に、GitHub リポジトリの構成を行います。ここでは、新しいビルドをトリガーする Spinnaker API に通知を送信するように設定します。webhook は一般的に、ソース リポジトリ内の変更を検出する方法としてポーリングよりも好まれています。webhook を使用すると、リポジトリ ホストへの全体的な負荷を軽減できるとともに、詳細な commit 変更を抽出するのが簡単になります。

このソリューションでは Deployment Manager テンプレートを使用したので、Spinnaker webhook API エンドポイント /gate/webhooks/git/github が自動的に公開されました。GitHub からこのエンドポイントに通知が送信されます。セキュリティ上の理由から、ロードバランサによって公開される Spinnaker API エンドポイントはこれだけです。

GitHub webhook を構成する

  1. Spinnaker API を指しているグローバル転送ルールの IP アドレスを見つけます。これは、Cloud Deployment Manager テンプレートを使用して作成されたものです。

    gcloud compute forwarding-rules list --regexp="${DEPLOYMENT_NAME}-spinnaker-api-lb"
    
  2. webhook を次の URL に設定します。

    http://HTTP_LB_IP/gate/webhooks/git/github
    

    上記の URL に含まれる HTTP_LB_IP は転送ルールの IP アドレスです。

  3. 次に、GitHub リポジトリの設定を開きます。

    https://github.com/[YOUR_GH_USER]/sample-app/settings/hooks
    

    上記の URL の [YOUR_GH_USER] は、sample-app リポジトリのフォーク先となったユーザーまたは組織です。

  4. [Add Webhook] ボタンをクリックします。

  5. [Payload URL] を webhook URL に設定します。

  6. [Content type] を application/json に設定します。

  7. [Secret] を、すでに作成済みの GH_WEBHOOK_SECRET の値に設定します。

  8. [Add webhook] をクリックします。

    画像

[Add webhook] をクリックした後に、テスト ペイロードが Spinnaker に送信されます。これに成功すると、緑色のチェックマークが GitHub ページのこの webhook の横に表示されます。

画像

webhook が受信されたことは、Spinnaker VM 上の Echo サービスのログにも記録されます。

grep Webhook /var/log/spinnaker/echo/echo.log

Spinnaker パイプラインをトリガーするために pull リクエストをマージする

GitHub で pull リクエストをマージすることは、新しい変更を Git リポジトリ内のブランチから commit するのと同じことです。pull リクエストは共同レビューを行う場合のベスト プラクティスと見なされており、GitHub 上のオープンソース ソフトウェアをより安全にマージできます。

  1. html.go ファイルを編集するために GitHub コードブラウザで開きます。
  2. [Color] を [Green] から [Blue] に変更してから、[Create a new branch for this commit and start a pull request] を選択します。
  3. [Commit changes] ボタンをクリックします。

pull リクエストをマージした後で、Spinnaker パイプラインがトリガーされてパイプラインの各ステージの実行が開始します。

画像

今回は実行のソースが GIT であることに注目してください。

画像

デプロイが完了すると、[Clusters] の下に V000V001 という 2 つのサーバー グループが追加されています。サーバー グループ V000 は無効化されています。

クラスタを以前のバージョンにロールバックする

パイプラインのデプロイ ステージを構成するときに、Red/Black ストラテジーを指定しました。これは、サーバー グループの古いバージョンをそのまま残しますが、無効化するので、古いバージョンはロードバランサのメンバーにはなりません。ある変更をロールバックする必要がある場合も、古いサーバー グループが利用できる状態で残っているので、再作成は必要ありません。

以前のバージョンの sample-app にロールバックする方法は次のとおりです。

  1. サンプル アプリケーション ビューの一番上にある [Clusters] をクリックします。
  2. V001 サーバー グループをクリックします。
  3. UI の右上にある [Server Group Actions] ボタンをクリックし、[Rollback] を選択します。
  4. [Restore to] で [sample-nginx-v000] を選択します。
  5. アカウントの名前をダイアログの一番下のフィールドに入力します。
  6. [Submit] をクリックします。

    画像

これで、さまざまなタスクが実行されて V000 サーバー グループが再度有効化され、ロードバランサに追加されます。

数分後に、ロードバランサへのトラフィックには pull リクエストが commit される前の sample-app の状態が反映されます。

次に、pull リクエストを使用して html.go ファイルで別の変更を commit し、パイプラインをトリガーして V002 をロールアウトします。

クリーンアップ

このチュートリアルで使用するリソースについて、Google Cloud Platform アカウントに課金されないようにする手順は次のとおりです。

Spinnaker のパイプライン構成は Cloud Storage バケットに格納されているので、設定は Spinnaker サーバーの再起動後も永続化されています。Spinnaker スタックを作成したデプロイを削除する前に、この Cloud Storage バケットを削除する必要があります。

下記の手順を実施すると、このチュートリアルで作成されたリソースがすべてクリーンアップされて削除されるので、それ以降は課金が発生することはありません。

Spinnaker を使用してリソースを削除する

Spinnaker UI で次の手順を行います。

  1. [Pipelines] の下の [Configure] を選択して sample-app パイプラインの構成画面を開きます。この画面で [Pipeline Actions] をクリックし、[Delete] を選択してこのパイプラインを削除します。
  2. [Clusters] の下のすべてのサーバー グループを破棄します。
  3. [Load Balancers] の下でロードバランサを削除します。
  4. [Firewalls] の下でファイアウォールを削除します。
  5. メイン アプリケーション ページの [Config] をクリックし、[Delete application] をクリックします。

ローカル ターミナルを使用してリソースを削除する

ローカル ターミナルから、下記のコードを実行して front50 を停止し、オブジェクトとバケットを削除してから、デプロイを削除します。

gcloud compute ssh ${SPINNAKER_VM} -- sudo service front50 stop
gsutil rm -r gs://spinnaker-${GOOGLE_PROJECT}-${DEPLOYMENT_NAME}/front50
gsutil rb gs://spinnaker-${GOOGLE_PROJECT}-${DEPLOYMENT_NAME}

ローカル ターミナルから、Packer で作成されたイメージを 1 つずつ削除します。

gcloud compute images list --filter="name~'none-all-[0-9]{13}.+-xenial'"

ローカル ターミナルから、デプロイを削除します。

gcloud deployment-manager deployments delete ${DEPLOYMENT_NAME}

次のステップ

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...