概要
この記事はCI/CDアドベントカレンダー 25日目の記事です。クリスマスに投稿する暇があるということはそういうことです。察してください。
GKEにkustomizeで簡単なwebサーバをデプロイするためのCI/CD環境を作ったので、それをまとめていきます。ついでにkustomizeあたりの部分もちょろっと。
解説は
0. コンテナ化
1. CIの初期準備
2. イメージをGCRにプッシュ
3. kustomizeでmanifest作成
4. GKEにデプロイさせるCD作成
この流れになってます。
実際に作成したものはこちらのgithubに置いていますのでついでに確認してください。
0. コンテナ化
Dockerfileの用意
ここは本質とずれるのでささっと
http://localhost:8080/?name=hoge
というリクエストに対してhello, hoge
と返してくれる簡単なものををgolangで用意しました。
マルチステージビルドさせるDockerfileもシュッと書きました。
docker-composeもないと生きていけない体になっているのでついでに。
FROM golang:1.12 as builder
ENV GO111MODULE=on
ENV GOOS=linux
ENV GOARCH=amd64
COPY ./ /usr/local/deploy-gke
WORKDIR /usr/local/deploy-gke
RUN cd server && go build -o binfile
RUN chmod +x server/binfile
FROM alpine
ENV GOOS=linux
ENV GOARCH=amd64
EXPOSE 8080
COPY --from=builder /usr/local/deploy-gke/server/binfile ./
RUN mkdir /lib64
RUN ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
CMD ["/binfile"]
version: "3.7"
services:
server:
image: server
build:
context: ./
dockerfile: ./server/Dockerfile
container_name: server
ports:
- 8080:8080
一部Alpine環境でバイナリ実行時に怒られる部分があるのでシンボリックリンク張っています
参考:https://stackoverflow.com/questions/34729748/installed-go-binary-not-found-in-path-on-alpine-linux-docker
ローカルの動作確認
これでdocker-compose build
からの docker-compose up -d
でlocalhost:8080が意図した挙動をしていることが確認できました。
1. CIの初期準備
CI用のサービスアカウント作成
CIがGKEにデプロイするイメージをGCRにプッシュさせるため、CI/CD用のサービスアカウントを作成します。
今後のデプロイも考えて、ストレージ管理者
と Kubernetes Engine管理者
の2つのロールを渡したSAを作成しました。
発行したSAから吐き出された鍵(jsonファイル)の中身をコピってEnvironmental Variables
に貼り付けます。
ついでに使いそうなものも入れておきました。
これで.circleci/config.yml
からこの環境変数を扱えるようになったので、config.yml
を書いていきます。
ちなみに自分はyaml
派です。皆さんもそうだと思います。
ただ、config.yaml
で作成すると読み込んでくれません。断腸の思いでconfig.yml
にしましょう。
2. イメージプッシュ
config.yml作成
config.yml
を書いてGCRにイメージをpushしていきます。
masterマージをトリガーにしてイメージプッシュとデプロイをcloud Buildに任せる方法もありますが、個人的には管理が分散しないのでcircleCIに一元管理させるほうが好きです。
version: 2
references:
setup_env: &setup_env
name: Set Environment Variable
command: |
echo 'export GCP_PROJECT=${GCP_PROJECT}' >> $BASH_ENV
echo 'export GO111MODUELE="on"' >> $BASH_ENV
echo 'export IMAGE_PATH="asia.gcr.io/${GCP_PROJECT}/deploy-gke"' >> $BASH_ENV
source $BASH_ENV
install_dc: &install_dc
name: Install docker-compose
command: |
curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` > ~/docker-compose
chmod +x ~/docker-compose
mv ~/docker-compose /usr/local/bin/docker-compose
auth_gcloud: &auth_gcloud
name: Authenticate gcloud
command: |
echo $CICD_SA > gcloud-service-key.json
gcloud auth activate-service-account --key-file gcloud-service-key.json
gcloud --quiet auth configure-docker
gcloud --quiet config set project ${GCP_PROJECT}
gcloud --quiet config set compute/zone asia-northeast1-a
gcloud --quiet container clusters get-credentials deploy-gke
build: &build
working_directory: ~/deploy-gke
name: docker-compose build
command: docker-compose build
push_image: &push_image
name: push_image
command: |
docker tag server ${IMAGE_PATH}:${CIRCLE_SHA1}
docker push ${IMAGE_PATH}:${CIRCLE_SHA1}
jobs:
push_image:
working_directory: ~/deploy-gke
docker:
- image: google/cloud-sdk
steps:
- checkout
- setup_remote_docker
- run: *setup_env
- run: *install_dc
- run: *auth_gcloud
- run: *build
- run: *push_image
workflows:
version: 2
build_and_push:
jobs:
- push_image
このconfig.yml
で
setup_env : 環境変数をセット
install_dc : docker-composeをインストール
auth_gcloud: glcoudコマンドの認証 & 予め作成していたクラスタの設定
build: イメージ生成 & コミットハッシュでタグ付け
push_image: そのイメージをGCRにpush
を実行しています。
ちなみにdocker-composeをインストールする手順はcircleciが公開しています
https://circleci.com/docs/ja/2.0/docker-compose/
もちろん、すでにdocker-composeがインストールされているイメージを使用するのであればこの手順入りません。
GCRにイメージがpushされているのが確認できました。
3. kustomizeでmanifest作成
続いて、デプロイするためにkustomizeでkubeのmanifestを作成していきます。
kustomizeのディレクトリ構成
k8s
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
├── manifest
│ └── production
│ └── output.yaml
└── overlays
└── production
├── build.sh
├── deployment.yaml
├── kustomization.yaml
└── service.yaml
ディレクトリの切り方は何でもいいですが、公式の推奨がこれなのでこれに則ります。
kustomizeについて
ざっくりkustomizeについて説明すると、baseにあるyamlに対してoverlays以下のyamlを付け加えることで一つのマニフェストを吐き出せるヤツです。(ここらへんの指定はbuild.shで管理しています)
各環境ごとにディレクトリを切れば各環境のyamlを生成できるし、labelやイメージの設定などの共通項はkustomization.yaml
に内包させることができます。
そのため、baseにあるyamlは全環境で共通の項目しか書かないので非常にコンパクトになります。
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-gke-deployment
また、このkustomization.yaml
の内容はkustomize edit
コマンドで変更することができるので、CI上で作成したimageのパスを kustomize edit
コマンドに渡すことで、そのimageを取り込んだkustomization.yaml
を作成でき、それをもとにマニフェストを作成することができます。
今回はその仕組を使用してCD環境を構築します。
詳しくはリポジトリをみてください。
ちなみに今回は、type LoadBalancerのserviceとreplicasが1のDeploymentを作成しました。
#!/bin/sh
cd `dirname $0`
IMAGE_NAME="$1"
kustomize edit set image app-name="${IMAGE_NAME}"
kustomize build . > ../../manifest/production/output.yaml
このbuild.sh
が何をやっているかというと、./build.sh args:latest
を実行することで、さっきの説明の、
そのimageを取り込んだ
kustomization.yaml
を作成でき、それをもとにマニフェストを作成することができます。
までを一気にやっています。
実行時の引数にargs:latest
を入れることで
...
images:
- name: app-name
newName: args
newTag: latest
のようにkustomization.yamlが書き換わり、
kustomize build . > ../../manifest/production/output.yaml
buildすることで
そのimageを用いたmanifestがmanifest/production/output.yaml
に生成されます。
ここまでくればあとは、CIで./build.sh {前のジョブでプッシュしたイメージのパス}
を実行するだけです。
build.shですが、kubectlが1.14になってkustomizeコマンドが統合されたので、kubectl -k
を使えばkustomize edit
の操作がなくなっていいかも知れません。(GKEのデフォルトバージョンはまだ1.13なので注意)
4. GKEにデプロイさせるCDを作る
デプロイ周りのconfig.yml
apt-get_update: &apt-get_update
name: apt-get update
command: |
apt-get update
apt-get install -y wget
install_kubectl: &install_kubectl
name: install kubectl
command: |
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
mv kubectl /usr/local/bin
chmod +x /usr/local/bin/kubectl
kubectl version
install_kustomize: &install_kustomize
name: install kustomize
command: |
wget https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv3.5.1/kustomize_v3.5.1_linux_amd64.tar.gz
tar xvzf kustomize_v3.5.1_linux_amd64.tar.gz
mv kustomize /usr/local/bin
chmod +x /usr/local/bin/kustomize
kustomize version
deploy: &deploy
working_directory: ~/deploy-gke
name: deploy gke
command: |
./k8s/overlays/production/build.sh ${IMAGE_PATH}:${CIRCLE_SHA1}
kubectl apply -f ./k8s/manifest/production/output.yaml
kubectl
とkustomize
をインストールさせるタスクを用意しました。
deployタスクでは先程説明したように、build.shに、引数にGCRのイメージパスを指定して実行します。
後は出力されたyamlをapplyして完成。
ちなみにjobとworkflowはこんな感じ
deploy:
working_directory: ~/deploy-gke
docker:
- image: google/cloud-sdk
steps:
- checkout
- setup_remote_docker
- run: *apt-get_update
- run: *auth_gcloud
- run: *install_kubectl
- run: *install_kustomize
- run: *deploy
workflows:
version: 2
build_and_push:
jobs:
- push_image
- deploy:
requires:
- push_image
無事jobがすべて成功してserviceとdeploymentが作成されました。
動作確認
serviceはtype LoadBalancerで作成したので、生成された外部IPアドレスにアクセスすると
無事動いていることが確認できました
まとめ
kustomizeでCI/CDを実現するためのフローを舐めていきました。
結論このgithubにコードがすべて詰まっているのでそっちを見てください。各章ごとにコミット分けています。
まさかり大歓迎です。
それではみなさん、良いお年を。