2018年9月9日日曜日

GKE 上で Jenkins を動かしてアプリの Canary デプロイを試してみた

概要

GKE 上で Jenkins を動かすことで Canary リリースを簡単に実現することができます
GKE で k8s クラスタを構築しそこに Jenkins をデプロイします
そして Cloud Source Repository 上でアプリのソースコードを管理して、Canary デプロイを実現します
今回は k8s + Jenkins の構築方法と実際にアプリを修正して Canary リリースまでやってみました
なお作業は Google Cloud Shell 上ですべて行います

環境

  • Google Kubernetes Engine (2018/09/04 時点)
  • Google Cloud Source Repository (2018/09/04 時点)
  • Google Cloud Shell
  • Jenkins 2.121.3

ディスク作成

  • gcloud config set compute/zone us-east1-d
  • gcloud compute disks create cd-jenkins

Jenkins の永続領域として使います

クラスタ作成

  • gcloud container clusters create jenkins-cd --num-nodes 2 --machine-type n1-standard-2 --scopes "https://www.googleapis.com/auth/projecthosting,cloud-platform"
  • gcloud container clusters get-credentials jenkins-cd
  • kubectl get pods

クラスタ内のノードは 2 台です
クラスタの認証情報を保存して kubectl でアクセスできることを確認します

サンプルアプリの取得

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

ここに k8s 上にデプロイする Jenkins の定義やサンプルアプリの定義が含まれています
基本はこれを使っていきます

helm インストール

  • wget https://storage.googleapis.com/kubernetes-helm/helm-v2.9.1-linux-amd64.tar.gz
  • tar zxfv helm-v2.9.1-linux-amd64.tar.gz
  • cp linux-amd64/helm .

helm を使って Jenkins をデプロイするために使います

RBAC 設定

  • kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)
  • kubectl create serviceaccount tiller --namespace kube-system
  • kubectl create clusterrolebinding tiller-admin-binding --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
  • ./helm init --service-account=tiller
  • ./helm update
  • ./helm version

helm を使ってクラスタにアクセスするサービスアカウントを作成します
アカウント名などは変更しても OK ですがそのままでも OK です

Jenkins デプロイ

  • ./helm install -n cd stable/jenkins -f jenkins/values.yaml --version 0.16.6 --wait
  • kubectl get pods
NAME                          READY     STATUS    RESTARTS   AGE
cd-jenkins-7c786475dd-smknn   1/1       Running   0          1h

Jenkins 用の Pod が Running になるまで待ちましょう
もしうまく Pod が上がらない場合は一旦削除して再度試してみてください

  • ./helm del --purge cd

Jenkins ログイン

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

8080 で LISTEN していることを確認します
Google Cloud Shell のプレビュー機能を使って Jenkins を開きます

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

これで admin ユーザのパスワードが表示できるのでログインしましょう

サンプルアプリのデプロイ

とりあえず手動でデプロイします

  • cd sample-app
  • kubectl create ns production
  • kubectl --namespace=production apply -f k8s/production
  • kubectl --namespace=production apply -f k8s/canary
  • kubectl --namespace=production apply -f k8s/services
  • kubectl --namespace=production scale deployment gceme-frontend-production --replicas=4
  • kubectl --namespace=production get service gceme-frontend

これでアプリにアクセスするための EXTERNAL-IP を確認しましょう
LoadBalancer を作成しているので有効になるのに少々時間がかかります

NAME             TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
gceme-frontend   LoadBalancer   10.59.255.179   35.193.81.133   80:31835/TCP   58m

これでブラウザでアクセスすると青色のアプリの画面が確認できると思います

  • export FRONTEND_SERVICE_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}" --namespace=production services gceme-frontend)
  • while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done

この 2 つのコマンドはアプリを Canary リリースしたときに確認するコマンドなのでまだ実行しないで大丈夫です

Cloud Source Repository にアプリをコミットする

  • cd sample-app
  • git init
  • git config credential.helper gcloud.sh
  • gcloud source repos create gceme
  • git remote add origin https://source.developers.google.com/p/your-project-id/r/gceme
  • git config --global user.email "your-mail-address@domain.com"
  • git config --global user.name "your-name"
  • git add .
  • git commit -m "Initial commit"
  • git push origin master

とりあえず現在のソースを Cloud Resource Repository をプッシュします
ここに変更を加えてブランチを作成しブランチを Canary デプロイします

Jenkins に Credential を登録する

GKE 上にアクセスするための Credential を登録します

  1. 左メニュー認証情報を選択
  2. global を選択
  3. 認証情報の追加を選択
  4. 種類 -> Google Service Account from metadata を選択
  5. OK

gke_with_jenkins1.png

Jenkins にデプロイジョブの作成

Cloud Resource Repository から GKE にブランチをデプロイするためのジョブを作成します

  1. Jenkins のトップに戻る
  2. 「新しいジョブを作成」を選択
  3. 「Multibranch Pipeline」を選択して名前を「sample-app」で入力しジョブを作成
  4. Branch Sources -> Add source -> Git -> https://source.developers.google.com/p/your-project-id/r/gceme
  5. 認証情報はプロジェクト ID を選択
  6. Scan Multibranch Pipeline Triggers -> 他のビルドが起動していなければ定期的に起動 -> 間隔 -> 1 minute に設定

gke_with_jenkins2.png

Canary ブランチをデプロイしてみる

少し修正を加えてそれを Canary デプロイしてみます

  • git checkout -b canary
  • vim Jenkinsfile

冒頭の project の部分を自分のプロジェクト ID に変更します

-def project = 'PROJECT_ID'
+def project = 'your-project-id'

続いて canary ブランチになったのがわかるように色を変更します

  • vim html.go
-<div class="card blue">
+<div class="card orange">

バージョンも変更します

  • vim main.go
-const version string = "1.0.0"
+const version string = "2.0.0"

上記の変更を push します

  • git add .
  • git commit -m "Version 2"
  • git push origin canary

push が完了したら Jenkins のジョブに戻って「Scan Multibranch Pipeline Now」をスタートしましょう
gke_with_jenkins3.png

ビルドが完了したあとでブラウザでアプリにアクセスし続けるとオレンジの画面がたまに表示されるようになります
Canary デプロイはすべてのアプリを切り替えるのではなく一部のアプリだけを切り替えることができます
gke_with_jenkins4.png

master にマージする

  • git checkout master
  • git merge canary
  • git push origin master

再度「Scan Multibranch Pipeline Now」をスタートしてビルドが完了したあとにアプリにアクセスするとすべてのアクセスが 2.0.0 のアプリになっています

お掃除

  • gcloud compute disks delete cd-jenkins
  • gcloud container clusters delete jenkins-cd
  • gcloud source repos delete gceme

最後に

GKE 上に Jenkins をデプロイしてアプリの CI/CD 環境を構築してみました
ほぼサンプルを試しただけなので Jenkins のパイプラインの詳細は追っていませんが GKE 上で CI/CD する流れは掴めたかなと思います

アプリをデプロイするときは Slave 用の pod が立ち上がりデプロイするようです
公式のやり方ではあるのでこれで問題はないですが、既存の Jenkins がある場合はそこからデプロイするための連携とかしたいかなと個人的には思っています
Jenkins の k8s のプラグインをうまく設定すればできると思いますが、なぜか k8s と Jenkins の連携をするサンプルのほとんどが k8s 上に Jenkins もデプロイする方法なのが気になりました

参考サイト

0 件のコメント:

コメントを投稿