GKE での Jenkins マルチブランチ パイプライン

1. 概要

Jenkins は、最も人気のある継続的インテグレーション ソリューションの一つです。ソフトウェア開発プロセスの人間以外の重要な部分を自動化するために使用されます。Jenkins を Google Cloud の Kubenetes にデプロイし、GKE プラグインを使用すると、必要に応じてビルド エグゼキュータを迅速かつ自動的にスケーリングできます。Cloud Storage と組み合わせることで、最小限の労力でアプリケーションを構築してテストできます。

演習内容

  • Jenkins を Kubernetes クラスタにデプロイする
  • Jenkins GKE プラグインをデプロイして構成し、Jenkins がエグゼキュータ ノードとして Pod を作成および破棄できるようにする
  • サンプルの SpringBoot アプリケーションをビルドしてテストする
  • コンテナをビルドして Google Container Registry に公開する
  • サンプル アプリケーションをステージング環境と本番環境の GKE 環境にデプロイする

必要なもの

  • 課金が設定されている Google Cloud プロジェクト。アカウントがない場合は、作成する必要があります。

2. 設定方法

この Codelab は、ローカルでのインストールや構成なしで Google Cloud Platform で完全に実行できます。

Cloud Shell

この Codelab では、Cloud Shell のコマンドラインを使用して、さまざまなクラウド リソースとサービスをプロビジョニングして管理します。

API を有効にする

プロジェクトで有効にする必要がある API は次のとおりです。

  • Compute Engine API - 仮想マシンを作成して実行します。
  • Kubernetes Engine API - コンテナベースのアプリケーションを構築して管理します。
  • Cloud Build API - Google Cloud の継続的インテグレーションと継続的デリバリー プラットフォーム
  • Service Management API - サービス プロデューサーが Google Cloud Platform でサービスを公開できるようにします。
  • Cloud Resource Manager API - Google Cloud リソース コンテナのメタデータの作成、読み取り、更新

次の gcloud コマンドを使用して、必要な API を有効にします。

gcloud services enable compute.googleapis.com \
container.googleapis.com \
cloudbuild.googleapis.com \
servicemanagement.googleapis.com \
cloudresourcemanager.googleapis.com \
--project ${GOOGLE_CLOUD_PROJECT}

GCS バケットを作成する

テスト用ワークをアップロードするには、GCS バケットが必要です。一意の名前を確保するために、名前にプロジェクト ID を使用してバケットを作成します。

gsutil mb gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket/ 

3. Kubernetes クラスタの作成

クラスタを作成する

次に、ワーカーノードとしてディスパッチされる Pod など、Jenkins システムをホストする GKE クラスタを作成します。--scopes フラグで指定された追加スコープにより、Jenkins は Cloud Source Repositories と Container Registry にアクセスできるようになります。Cloud コンソールで、次のコマンドを実行します。

gcloud container clusters create jenkins-cd \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--scopes "https://www.googleapis.com/auth/source.read_write,cloud-platform" \
--cluster-version latest

また、2 つのクラスタをデプロイして、サンプル アプリケーションのステージング ビルドと本番環境ビルドをホストします。

gcloud container clusters create staging \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--cluster-version latest
gcloud container clusters create prod \
--machine-type n1-standard-2 --num-nodes 2 \
--zone us-east1-d \
--cluster-version latest

28b45298e1e82748.png 確認

クラスタが作成されたら、gcloud container clusters list を使用してクラスタが実行されていることを確認できます。

出力の STATUS 列に RUNNING が含まれているはずです。

NAME        LOCATION    MASTER_VERSION  MASTER_IP     MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
jenkins-cd  us-east1-d  1.15.9-gke.9    34.74.77.124  n1-standard-2  1.15.9-gke.9  2          RUNNING
prod        us-east1-d  1.15.9-gke.9    35.229.98.12  n1-standard-2  1.15.9-gke.9  2          RUNNING
staging     us-east1-d  1.15.9-gke.9    34.73.92.228  n1-standard-2  1.15.9-gke.9  2          RUNNING

4. Helm を使用して Jenkins をデプロイする

Helm をインストールする

Kubernetes 用のアプリケーション パッケージ マネージャーである Helm を使用して、クラスタに Jenkins をインストールします。まず、Jenkins のデプロイに使用する Kubernetes マニフェストを含むプロジェクトをダウンロードします。

git clone https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes.git ~/continuous-deployment-on-kubernetes

現在の作業ディレクトリをプロジェクト ディレクトリに変更します。

cd ~/continuous-deployment-on-kubernetes/

クラスタ ロール バインディングを作成して、cluster-admin ロールの権限を付与します。

kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)

認証情報を取得して、Jenkins クラスタに接続します。

gcloud container clusters get-credentials jenkins-cd --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

Helm バイナリを Cloud コンソールにダウンロードします。

wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.1-linux-amd64.tar.gz

ファイルを解凍し、含まれている Helm ファイルを現在の作業ディレクトリにコピーします。

tar zxfv helm-v2.14.1-linux-amd64.tar.gz && \
cp linux-amd64/helm .

Tiller は、Kubernetes クラスタで実行される Helm のサーバーサイドです。tiller という名前のサービス アカウントを作成します。

kubectl create serviceaccount tiller \
--namespace kube-system

変更できるように、cluster-admin クラスタロールにバインドします。

kubectl create clusterrolebinding tiller-admin-binding \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:tiller

これで、Helm を初期化してリポジトリを更新できます。

./helm init --service-account=tiller && \
./helm repo update

28b45298e1e82748.png 確認

./helm version を使用して、Helm が正常に動作していることを確認します。これにより、クライアントとサーバーのバージョン番号が返されます。

Client: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}

Jenkins をインストールする

Helm がクラスタにインストールされたので、Jenkins のインストールの準備が整いました。

./helm install stable/jenkins -n cd \
-f jenkins/values.yaml \
--version 1.2.2 --wait

28b45298e1e82748.png 確認

Pod を確認しましょう。

kubectl get pods

出力には、ステータスが RUNNING の Jenkins Pod が表示されます。

NAME                          READY     STATUS    RESTARTS   AGE
cd-jenkins-7c786475dd-vbhg4   1/1       Running   0          1m

Jenkins サービスが適切に作成されたことを確認します。

kubectl get svc

出力結果は次のようになります。

NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
cd-jenkins         ClusterIP   10.35.241.170   <none>        8080/TCP    2m27s
cd-jenkins-agent   ClusterIP   10.35.250.57    <none>        50000/TCP   2m27s
kubernetes         ClusterIP   10.35.240.1     <none>        443/TCP     75m

Jenkins インストールでは、Kubernetes プラグインを使用してビルダー エージェントを作成します。これらのエージェントは、必要に応じて Jenkins マスターによって自動的に起動されます。エージェントは処理の完了時に自動的に終了されて、エージェントのリソースがクラスタのリソースプールに戻されます。

Jenkins に接続する

Jenkins はクラスタで実行されていますが、UI にアクセスするには、Cloud Shell からポート転送を設定します。

export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=cd" -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8080:8080 >> /dev/null &

インストール中に管理者パスワードが生成されました。取得してみましょう。

printf $(kubectl get secret cd-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo

Cloud Shell の上部にあるウェブでプレビュー アイコン 7ddf5a65fd556dd6.png をクリックし、[ポート 8080 でプレビュー] を選択します。

1d614c831a621cff.png

Jenkins のログイン画面が表示されます。ここで、ユーザー名として admin と、前の手順で返されたパスワードを入力します。

9cba23e856cbc84f.png

[ログイン] をクリックすると、Jenkins のメインページが表示されます。

9261f3e914829137.png

5. GKE プラグインをインストールして構成する

Google Kubernetes Engine プラグインを使用すると、Jenkins 内でビルドされたデプロイメントを GKE 内で実行されている Kubernetes クラスタに公開できます。プロジェクトの IAM 権限で行う必要がある構成があります。この構成を Terraform を使用してデプロイします。

まず、GKE プラグイン プロジェクトをダウンロードします。

git clone https://github.com/jenkinsci/google-kubernetes-engine-plugin.git ~/google-kubernetes-engine-plugin

IAM 権限の自動構成

現在の作業ディレクトリを、前にクローンを作成した GKE プロジェクトの rbac ディレクトリに変更します。

cd ~/google-kubernetes-engine-plugin/docs/rbac/

gcp-sa-setup.tf は、制限付きの権限を持つカスタム GCP IAM ロールと、そのロールを付与する GCP サービス アカウントを作成する Terraform 構成ファイルです。このファイルには、プロジェクト、リージョン、サービス アカウント名の変数の値が必要です。これらの値は、まず次の環境変数を宣言することで指定します。

export TF_VAR_project=${GOOGLE_CLOUD_PROJECT}
export TF_VAR_region=us-east1-d
export TF_VAR_sa_name=kaniko-role

Terraform を初期化してプランを生成し、適用します。

terraform init
terraform plan -out /tmp/tf.plan
terraform apply /tmp/tf.plan && rm /tmp/tf.plan

サービス アカウントには、Cloud Storage バケットに保存するためのストレージ管理者権限が必要です。

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
--member serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com \
--role 'roles/storage.admin'

また、パイプラインのデプロイ ステージのコンテナ権限も必要です。

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} --member \
serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com --role 'roles/container.developer'

これで、Helm を使用して、gke robot deployer を使用して GKE プラグインのクラスタ権限を設定できます。作業ディレクトリを GKE プロジェクトの helm ディレクトリに変更します。

cd ~/google-kubernetes-engine-plugin/docs/helm/

提供された Helm チャートを使用してインストールします。

export TARGET_NAMESPACE=kube-system && \
envsubst < gke-robot-deployer/values.yaml | helm install ./gke-robot-deployer --name gke-robot-deployer -f -

6. Jenkins を構成する

サービス アカウント キー

サービス アカウントが正常に機能するように、秘密鍵ファイルを生成して Kubernetes Secret として追加する必要があります。まず、次の gcloud コマンドでファイルを生成します。

gcloud iam service-accounts keys create /tmp/kaniko-secret.json --iam-account kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com

このファイルを使用して、Kubernetes Secret ストアに Secret Key を作成します。

kubectl create secret generic jenkins-int-samples-kaniko-secret --from-file=/tmp/kaniko-secret.json 

Cloud Shell の 3 つのドット メニューから [ファイルをダウンロード] アイテムにアクセスして、json ファイルをローカルディスクにダウンロードします。

c40378e72013b843.png

ファイルパス /tmp/kaniko-secret.json を入力し、[ダウンロード] をクリックします。

Jenkins ページに戻り、左側のペインで [認証情報]、[システム] の順にクリックします。

6c140f7e6bb82f8.png

3b874912cdc8019b.png

ページの [システム] セクションで、左側の [グローバル認証情報]、[認証情報を追加] の順にクリックします。

4350c0e68561119b.png

3d3526551cdae8b.png

[Kind] プルダウンで、[Google Service Account from private key] を選択します。名前として「kaniko-role」と入力し、前の手順で作成した JSON キーをアップロードして、[OK] をクリックします。

b0502213408e730e.png

環境変数

マルチブランチ パイプラインを作成する前に、Jenkins で定義する必要がある環境変数がいくつかあります。それらは次のとおりです。

  • JENK_INT_IT_ZONE - Kubernetes クラスタのゾーン。ここでは us-east1-d とします。
  • JENK_INT_IT_PROJECT_ID - Jenkins のこのインスタンスをホストする GCP プロジェクト ID を参照します。
  • JENK_INT_IT_STAGING - ステージング クラスタ名。デモ用に staging に設定します。
  • JENK_INT_IT_PROD - プロダクション クラスタの名前。デモ用に prod にします。
  • JENK_INT_IT_BUCKET - 前の手順で作成した Google Cloud Storage バケット
  • JENK_INT_IT_CRED_ID - 前の手順で JSON を使用して作成した認証情報を参照します。この値は、指定した名前 kaniko-role と一致している必要があります。

これらを追加するには、[Manage Jenkins] に移動します。

d54f279190a07878.png

次に、[Configure System] をクリックします。

ce79d218b2799640.png

[グローバル プロパティ] というセクションがあり、[環境変数] チェックボックスをオンにすると、[追加] ボタンが表示されます。このボタンをクリックして、上記の変数を Key-Value ペアとして追加します。

81aa222a2b17b2cc.png

ページの下部にある [保存] ボタンをクリックして変更を適用します。

7. パイプラインを設定する

Jenkins で [New Item] をクリックします。

8d1270ce4d7b6a8a.png

名前に「jenkins-integration-sample」と入力し、プロジェクトの種類として [Multibranch Pipeline] を選択し、[OK] をクリックします。

eb071ecfbb4d775b.png

パイプラインの構成ページにリダイレクトされます。[Branch Sources] で、[Project Repository] に https://github.com/GoogleCloudPlatform/jenkins-integration-samples.git と入力します。[ビルド構成] で、[スクリプトパス] に「gke/Jenkinsfile」と入力します。

5135bd6b0374508c.png

[保存] をクリックして、これらの設定を適用します。保存すると、Jenkins はリポジトリのスキャンを開始し、ブランチごとにその後のビルドを開始します。ビルドの進行に伴い、[Kubernetes ワークロード] ページに Pod の作成、実行、破棄が表示されます。

ビルドが完了すると、Kubernetes ワークロード ページに「jenkins-integration-samples-gke」という名前の 2 つの項目が表示されます。それぞれ、本番環境クラスタまたはテストクラスタに対応しています。ステータスは OK になります。

bdec6b1753d1ba07.png

次の gcloud コマンドを使用すると、パイプラインに応じて Google Container Registry にコンテナ イメージがアップロードされていることがわかります。

gcloud container images list

ブラウザでワークロードを表示するには、本番環境クラスタの認証情報を取得します。

gcloud container clusters get-credentials prod --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

次を実行して、シェルのポート 8081 からワークロードのポート 8080 へのポート転送を設定します。

export POD_NAME=$(kubectl get pods -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8081:8080 >> /dev/null &

Cloud Shell の上部にある [ウェブでプレビュー] アイコンをクリックし、[ポート 8081 でプレビュー] を選択します。

1b19b5b56f1bae7.png

e80e995e71763bb2.png

8. クリーンアップ

Kubernetes に Jenkins とマルチブランチ パイプラインのサンプルをデプロイする方法について説明しました。次に、作成したリソースをプロジェクトからクリーンアップします。

プロジェクトを削除する

必要に応じて、プロジェクト全体を削除することもできます。GCP Console で、[Cloud Resource Manager] ページに移動します。

プロジェクト リストで、目的のプロジェクトを選択し、[削除] をクリックします。プロジェクト ID を入力するように求められます。入力して [シャットダウン] をクリックします。

または、gcloud を使用してプロジェクト全体を Cloud Shell から直接削除することもできます。

gcloud projects delete $GOOGLE_CLOUD_PROJECT

課金対象コンポーネントを 1 つずつ削除する場合は、次のセクションに進みます。

Kubernetes クラスタ

gcloud を使用して Kubernetes クラスタ全体を削除します。

gcloud container clusters delete jenkins-cd --zone=us-east1-d

ストレージ バケット

アップロードしたファイルをすべて削除し、gsutil を使用してバケットを削除します。

gsutil rm -r gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket

Google Container Registry イメージ

イメージ ダイジェストを使用して Google Container Registry イメージを削除します。まず、次のコマンドでダイジェストを取得します。

gcloud container images list-tags gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke --format="value(digest)"

次に、返された各ダイジェストに対して次の操作を行います。

gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke@sha256:<DIGEST>

9. 完了

これで完了です。GKE に Jenkins をデプロイし、Kubernetes クラスタにジョブをディスパッチする方法について学習しました。

学習した内容

  • Kubernetes クラスタをデプロイし、Helm を使用して Jenkins をインストールしました
  • Jenkins が Kubernetes クラスタにビルド アーティファクトをデプロイできるように、GKE プラグインをインストールして構成しました。
  • GKE クラスタに作業をディスパッチするマルチブランチ パイプラインを設定するように Jenkins を構成しました。