このチュートリアルでは、一般的な GitOps 手法を使用して、Terraform と Jenkins によりインフラストラクチャをコードとして管理する方法について説明します。このチュートリアルは、ソフトウェア アプリケーションを管理する方法でインフラストラクチャを管理するためのベスト プラクティスを探しているデベロッパーとオペレーターを対象としています。この記事は、Terraform、Jenkins、GitHub、Google Kubernetes Engine(GKE)、Google Cloud を理解していることを前提としています。
アーキテクチャ
このチュートリアルで使用されているアーキテクチャは、GitHub ブランチ(dev
と prod
)を使用して、実際の開発環境と本番環境を表します。これらの環境は、Google Cloud プロジェクトの Virtual Private Cloud(VPC)ネットワーク(dev
と prod
)によって定義されます。
インフラストラクチャの提案
次のアーキテクチャ図に示すように、デベロッパーまたはオペレーターが、GitHub の保護されていないブランチ(通常は機能ブランチ)にインフラストラクチャ プロポーザルを行うと、プロセスが開始されます。該当する場合、dev
ブランチへの pull リクエスト(PR)を介して開発環境にプロモーションを行うことができます。その後、Jenkins によってジョブが自動的にトリガーされ、検証パイプラインが実行されます。このジョブは terraform plan
コマンドを実行して、検証結果を GitHub に報告し、詳細なインフラストラクチャ変更レポートへのリンクを含めます。潜在的な変更を共同編集者と話し合ってレビューし、変更が dev
ブランチにマージされる前にフォローアップ commit を追加できるため、この手順は重要です。
Dev
デプロイ
検証プロセスが正常に完了し、提案されたインフラストラクチャの変更を承認すると、pull リクエストを dev
ブランチにマージできます。次の図は、このプロセスを示しています。
マージが完了すると、Jenkins によって別のジョブがトリガーされ、デプロイ パイプラインが実行されます。このシナリオでは、開発環境の Terraform マニフェストが開発環境で適用されます。Terraform コードを本番環境にプロモートする前にテストできるため、この手順は重要です。
Prod
デプロイ
テストを行い、変更を本番環境に昇格する準備が整ったら、dev
ブランチを prod
ブランチにマージして、本番環境へのインフラストラクチャのインストールをトリガーする必要があります。次の図は、このプロセスを示しています。
pull リクエストを作成する場合も、同じ検証プロセスが実行されます。このプロセスにより、運用チームは本番環境で提案された変更を確認して承認できます。
目標
- GitHub リポジトリを設定します。
- Terraform リモート状態ストレージを作成します。
- GKE クラスタを作成して Jenkins をインストールします。
- 機能ブランチで環境構成を変更します。
- 開発環境への変更を促進します。
- 本番環境への変更を促進します。
料金
このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。新しい Google Cloud ユーザーは無料トライアルをご利用いただけます。
このチュートリアルを終了した後、作成したリソースを削除すると、それ以上の請求は発生しません。詳しくは、クリーンアップをご覧ください。
始める前に
- Google アカウントにログインします。
Google アカウントをまだお持ちでない場合は、新しいアカウントを登録します。
-
Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。
-
Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトに対して課金が有効になっていることを確認する方法を学習する。
-
Cloud Console で、Cloud Shell をアクティブにします。
Cloud Console の下部にある Cloud Shell セッションが開始し、コマンドライン プロンプトが表示されます。Cloud Shell はシェル環境です。
gcloud
コマンドライン ツールなどの Cloud SDK がすでにインストールされており、現在のプロジェクトの値もすでに設定されています。セッションが初期化されるまで数秒かかることがあります。 - Cloud Shell で、プロジェクト ID を構成し、GitHub ユーザー名とメールアドレスを設定します。
PROJECT_ID=PROJECT_ID GITHUB_USER=YOUR_GITHUB_USER GITHUB_EMAIL=YOUR_EMAIL_ADDRESS gcloud config set project $PROJECT_ID
Cloud Shell から GitHub にまだアクセスしたことがない場合、次のように、ユーザー名とメールアドレスで GitHub を構成できます。
git config --global user.email "$GITHUB_EMAIL" git config --global user.name "$GITHUB_USER"
GitHub はこの情報を使用して、Cloud Shell で作成する commit の作成者を識別します。
GitHub リポジトリを設定する
このチュートリアルでは、単一の GitHub リポジトリを使用してクラウド インフラストラクチャを定義します。異なる環境に対応するさまざまなブランチを持つことで、このインフラストラクチャをオーケストレートします。
dev
ブランチには、開発環境に適用される最新の変更が含まれています。prod
ブランチには、本番環境に適用される最新の変更が含まれています。
このインフラストラクチャを使用すると、常にリポジトリを参照してそれぞれの環境で必要とされる構成の内容を把握し、最初に dev
環境にマージすることにより、新たな変更を提案できます。次に dev
ブランチを prod
ブランチにマージして、変更をプロモートします。
開始するには、solutions-terraform-jenkins-gitops
リポジトリをフォークする必要があります。
- GitHub で
solutions-terraform-jenkins-gitops
リポジトリに移動します。 [フォーク] をクリックします。
これで、ソースファイルを格納する
solutions-terraform-jenkins-gitops
リポジトリのコピーが作成されます。Cloud Shell で、このフォークされたリポジトリのクローンを作成します。
cd ~ git clone https://github.com/$GITHUB_USER/solutions-terraform-jenkins-gitops.git cd ~/solutions-terraform-jenkins-gitops
このリポジトリのコードは次のように構成されています。
example-pipelines/
フォルダ: このチュートリアルで使用するパイプラインの例が含まれるサブフォルダがあります。example-create/
: 環境で仮想マシンを作成するための Terraform コードが含まれています。environments/
: バックエンド構成でdev
環境フォルダとprod
環境フォルダが含まれ、example-create/
フォルダのファイルへのリンクが含まれています。jenkins-gke/
フォルダ: 新しい GKE クラスタに Jenkins をデプロイするために必要なスクリプトが含まれています。tf-gke/
: GKE にデプロイし、Jenkins とその依存リソースをインストールするための Terraform コードが含まれています。
Terraform リモート状態ストレージを作成する
Terraform の状態はデフォルトでローカルに保存されます。ただし、リモート セントラル ストレージに状態を保存して、どのシステムからもアクセスできるようにすることをおすすめします。このアプローチは、異なるシステム上で複数のコピーを作成し、インフラストラクチャの構成と状態の不一致を引き起こす可能性を回避するのに役立ちます。
このセクションでは、Terraform のリモート状態を保存する Cloud Storage バケットを構成します。
Cloud Shell で、Cloud Storage バケットを作成します。
gsutil mb gs://${PROJECT_ID}-tfstate
オブジェクトのバージョニングを有効にして、状態の履歴を保持します。
gsutil versioning set on gs://${PROJECT_ID}-tfstate
terraform.tfvars
ファイルとbackend.tf
ファイルの両方で PROJECT_ID プレースホルダをプロジェクト ID に置き換えます。sed -i.bak "s/PROJECT_ID/${PROJECT_ID}/g" ./example-pipelines/environments/*/terraform.tfvars sed -i.bak "s/PROJECT_ID/${PROJECT_ID}/g" ./example-pipelines/environments/*/backend.tf sed -i.bak "s/PROJECT_ID/${PROJECT_ID}/g" ./jenkins-gke/tf-gke/terraform.tfvars sed -i.bak "s/PROJECT_ID/${PROJECT_ID}/g" ./jenkins-gke/tf-gke/backend.tf
すべてのファイルが更新されたかどうかを確認します。
git status
出力は次のようになります。
On branch dev Your branch is up-to-date with 'origin/dev'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: example-pipelines/environments/dev/backend.tf modified: example-pipelines/environments/dev/terraform.tfvars modified: example-pipelines/environments/prod/backend.tf modified: example-pipelines/environments/prod/terraform.tfvars modified: jenkins-gke/tf-gke/backend.tf modified: jenkins-gke/tf-gke/terraform.tfvars
変更を commit して push します。
git add --all git commit -m "Update project IDs and buckets" git push origin dev
GitHub の構成によっては、前述の変更を push するために認証する必要があります。
GKE クラスタの作成と Jenkins のインストール
このセクションでは、Terraform と Helm を使用して、コードとしてのインフラストラクチャを管理する環境を設定します。まず、Terraform と Cloud Foundations Toolkit を使用して、Virtual Private Cloud、GKE クラスタ、Workload Identity を構成します。次に、helm を使用して、この環境に Jenkins をインストールします。
Terraform コマンドの実行を開始する前に、GitHub の個人アクセス トークンを作成する必要があります。このトークンは、フォークされたリポジトリに Jenkins からアクセスできるようにするために必要です。
GitHub 個人アクセス トークンを作成する
- GitHub にログインします。
- プロフィール写真をクリックし、[設定] をクリックします。
- [デベロッパー設定]、[個人用アクセス トークン] の順にクリックします。
- [新しいトークンを生成] をクリックし、[メモ] フィールドでトークンの説明を入力して、repo スコープを選択します。
[トークンを生成] をクリックし、新しく作成したトークンをクリップボードにコピーします。
Cloud Shell で、
GITHUB_TOKEN
変数にトークンを保存します。この変数の内容は、後で GKE クラスタの Secret として保存されます。GITHUB_TOKEN="NEWLY_CREATED_TOKEN"
GKE クラスタを作成して Jenkins をインストールします。
GKE クラスタを作成します。このクラスタには、Workload Identity jenkins-wi-jenkins@PROJECT_ID.iam.gserviceaccount.com
)が含まれ、これにより Jenkins が Cloud Console の [サービス アカウント] ページで必要とする権限をJenkins に付与できます。セキュリティのプロパティと管理性の向上により、Workload Identity を使用して GKE 内から Google Cloud サービスにアクセスすることをおすすめします。
Google Cloud インフラストラクチャをコードとして管理するには、Jenkins で Google Cloud API を使用するための認証を行う必要があります。以下の手順により、Terraform を使用して Jenkinsが Google サービス アカウント(GSA)として機能するために使用する Kubernetes サービス アカウント(KSA)を構成します。この構成により、Google Cloud API にアクセスすると、Jenkins が自動的に GSA として認証されます。
説明をわかりやすくするため、このチュートリアルではプロジェクト エディタへのアクセス権を付与します。ただし、このロールにはさまざまな権限があるため、本番環境では、通常は最小限のアクセス権を付与する、会社の IT セキュリティに関するベスト プラクティスに従う必要があります。
Cloud Shell で、Terraform をインストールします。
wget https://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_linux_amd64.zip unzip terraform_0.12.24_linux_amd64.zip sudo mv terraform /usr/local/bin/ rm terraform_0.12.24_linux_amd64.zip
GKE クラスタを作成して Jenkins をインストールします。
cd jenkins-gke/tf-gke/ terraform init terraform plan --var "github_username=$GITHUB_USER" --var "github_token=$GITHUB_TOKEN" terraform apply --auto-approve --var "github_username=$GITHUB_USER" --var "github_token=$GITHUB_TOKEN"
この処理が完了するまでに数分かかる場合があります。出力は次のようになります。
Apply complete! Resources: 28 added, 0 changed, 0 destroyed. Outputs: ca_certificate = LS0tLS1CRU.. client_token = <sensitive> cluster_name = jenkins gcp_service_account_email = jenkins-wi-jenkins@PROJECT_ID.iam.gserviceaccount.com jenkins_k8s_config_secrets = jenkins-k8s-config jenkins_project_id = PROJECT_ID k8s_service_account_name = jenkins-wi-jenkins kubernetes_endpoint = <sensitive> service_account = tf-gke-jenkins-k253@PROJECT_ID.iam.gserviceaccount.com zone = us-east4-a
新しく作成された GKE クラスタに Jenkins がデプロイされると、Helm チャートのドキュメントに従って、Jenkins ホーム ディレクトリが永続ボリュームに保存されます。このデプロイには、
example-pipelines/environments/Jenkinsfile
を使用して事前構成されたマルチブランチ パイプラインも付属します。これは pull リクエストでトリガーされ、dev
ブランチとprod
ブランチにマージされます。メインフォルダに戻ります。
cd ../..
先ほど作成したクラスタ認証情報を取得します。
gcloud container clusters get-credentials jenkins --zone=us-east4-a --project=${PROJECT_ID}
Jenkins の URL と認証情報を取得します。
JENKINS_IP=$(kubectl get service jenkins -o jsonpath='{.status.loadBalancer.ingress[0].ip}') JENKINS_PASSWORD=$(kubectl get secret jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo printf "Jenkins url: http://$JENKINS_IP\nJenkins user: admin\nJenkins password: $JENKINS_PASSWORD\n"
前の手順の出力情報を使用して、Jenkins にログインします。
GitHub でビルドに直接アクセスするリンクを作成できるように、Jenkins のロケーションを構成します。[Manage Jenkins] > [Configure System] をクリックし、[Jenkins URL] フィールドで Jenkins URL を設定します。
新機能ブランチで環境構成を変更する
ほとんどの環境が構成されました。次はコードを変更してみましょう。
Cloud Shell で、チームの他のメンバーに影響を与えることなく作業できる新機能ブランチを作成します。
git checkout -b change-vm-name
仮想マシン名を変更します。
cd example-pipelines/example-create sed -i.bak "s/\${var.environment}-001/\${var.environment}-new/g" main.tf
example-create
フォルダにあるmain.tf
ファイルを変更します。このファイルはdev
環境フォルダとprod
環境フォルダによってリンクされています。つまり、変更が両方の環境に伝播されます。コードの変更を GitHub 機能ブランチに push します。
git commit -am "change vm name" git push --set-upstream origin change-vm-name
GitHub で、フォークされたリポジトリのメインページに移動します。
リポジトリの [Pull requests] タブをクリックし、[New pull request] をクリックします。
ベース リポジトリの場合は、フォークされたリポジトリを選択します。
ベースには
dev
を選択し、比較にはchange-vm-name
を選択します。[Create pull request] をクリックします。
pull リクエストが開くと、Jenkins ジョブが自動的に開始されます(Jenkins で新しい pull リクエストが確認されるまで数分かかる場合があります)。[Show all checks] をクリックし、チェックが緑色になるまで待ちます。
[Details] をクリックして、
terraform plan
コマンドの出力などの詳細情報を表示します。
Jenkins ジョブで Jenkinsfile
で定義されたパイプラインを実行しました。このパイプラインは取得されるブランチに応じて異なる動作をします。ビルドは、TARGET_ENV
変数が環境フォルダと一致するかどうかを確認します。一致する場合、Jenkins はその環境に対して terraform plan
を実行します。それ以外の場合、Jenkins はすべての環境に対して terraform plan
を実行し、提案された変更がすべての環境に適用されることを確認します。これらの計画のいずれかの実行が失敗すると、ビルドが失敗します。
提案されている変更がすべての環境に確実に適用されるよう、terraform plan
がすべての example-pipelines/environments
サブフォルダで実行されます。この方法により、pull リクエストをマージする前にプランを確認して、許可されていないエンティティへのアクセスを許可しないなどの保証ができます。
JENKINSFILE
の terraform plan
コードは次のとおりです。
同様に、terraform apply
コマンドは環境ブランチに対して実行されますが、それ以外の場合は無視されます。このセクションでは、新しいブランチにコード変更を送信したため、Cloud プロジェクトにインフラストラクチャの展開は適用されませんでした。
JENKINSFILE
の terraform apply
コードは次のとおりです。
ブランチをマージする前に Jenkins の実行成功を必須とする
Jenkins ジョブが成功した場合にのみ、マージが適用されるようにできます。
- GitHub で、フォークされたリポジトリのメインページに移動します。
- リポジトリ名の下にある [Settings] をクリックします。
- [STRONGBranches] をクリックします。
- [Branch protection rules] で、[Add rule] をクリックします。
- [Branch name pattern] に「
dev
」と入力します。 [Protect matching branches] で [Require status checks to pass before merging] を選択し、[
continuous-integration/jenkins/pr-merge
] を選択します。(省略可)未審査と未承認の pull リクエストが本番環境にマージされないように、[Require pull request reviews before merging] オプションと [Include administrators] オプションを有効にすることを検討してください。
[作成] をクリックします。
手順 4~7 を繰り返し、[Branch name pattern] を
prod
に設定します。
この構成は、dev
ブランチと prod
ブランチを保護するうえで重要です。つまり、最初に commit を別のブランチに push してから、保護されたブランチにマージする必要があります。このチュートリアルでは、Jenkins ジョブの実行が成功してはじめてマージが許可されることで保護が有効になります。新しく作成された pull リクエストで構成が適用されたかどうかを確認できます。緑のチェックマークを探します。
開発環境の変更を促進する
マージされるのを待っている pull リクエストがあります。必要な状態を dev
環境に適用できます。
- GitHub で、フォークされたリポジトリのメインページに移動します。
- リポジトリ名の下で、[Pull requests] をクリックします。
- 作成した pull リクエストをクリックします。
[Merge pull request]、[Confirm merge] の順にクリックします。
Jenkins で [Blue Ocean を開く] をクリックします。次に、
terraform-jenkins-create-demo
マルチブランチ プロジェクトの [Branchs] タブで、ステータス アイコンを調べて、新しい dev ジョブがトリガーされたかどうかを確認します。起動には 1 分程度かかる場合があります。Cloud Console で [VM インスタンス] ページに移動し、新しい名前の VM があるかどうかを確認します。
本番環境の変更の促進
開発環境をテストしたので、インフラストラクチャ コードを本番環境に昇格させることが可能です。
- GitHub で、フォークされたリポジトリのメインページに移動します。
- [New pull request] をクリックします。
ベース リポジトリの場合は、フォークしたリポジトリを選択します。
ベースには
prod
を選択し、比較にはdev
を選択します。[Create pull request] をクリックします。
タイトルには「
Promoting vm name change
」などのタイトルを入力し、[Create pull request] をクリックします。チェッカーが緑色になるまで待ち(1 ~ 2 分かかる場合があります)、[
continuous-integration/jenkins/pr-merge
] の横にある [Details] リンクをクリックします。Jenkins で
TF Plan
を選択し、ログで提案された変更を確認します。提案された変更が正しく表示されている場合は、GitHub で [Merge pull request] をクリックしてから [Confirm merge] をクリックします。
Cloud Console で [VM インスタンス] ページを開き、本番環境 VM がデプロイされていることを確認します。
Jenkins で Infrastructure as Code パイプラインを構成しました。今後、次のことをお試しください。
- 個別のユースケースのデプロイメントを追加します。
- ニーズを反映する追加の環境を作成します。
- 環境ごとの VPC ではなく、環境ごとのプロジェクトを使用します。
クリーンアップ
このチュートリアルで使用したリソースについて、Google Cloud Platform アカウントに課金されないようにする手順は次のとおりです。
プロジェクトの削除
- Cloud Console で [リソースの管理] ページに移動します。
- プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
- ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。
次のステップ
- 内部 Jenkins から Google Cloud への安全なアクセスのデプロイと承認の詳細については、Google Cloud での Jenkins をご覧ください。
- Introducing Workload Identity: Better authentication for your GKE applications をご覧ください。
- Terraform と Cloud Build を使用してインフラストラクチャをコードとして管理するで、インフラストラクチャをコードとして管理する方法を学習する。
- Cloud Foundation Toolkit テンプレートを使用して、再現可能なエンタープライズ対応の基盤を Google Cloud で迅速に構築することを検討する。
- Cloud Build を使用した GitOps スタイルの継続的デリバリーをご覧ください。
- Cloud Build のより高度な機能を試す。
- Google Cloud のその他の機能を試す。チュートリアルをご覧ください。