LoginSignup
2

More than 3 years have passed since last update.

posted at

updated at

Organization

GKEにkustomizeでデプロイするためのCI/CD環境

概要

この記事は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"]
docker-compose.yaml
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が意図した挙動をしていることが確認できました。

スクリーンショット 2019-12-23 23.30.49.png

1. CIの初期準備

CI用のサービスアカウント作成

CIがGKEにデプロイするイメージをGCRにプッシュさせるため、CI/CD用のサービスアカウントを作成します。
今後のデプロイも考えて、ストレージ管理者Kubernetes Engine管理者 の2つのロールを渡したSAを作成しました。
image.png
発行したSAから吐き出された鍵(jsonファイル)の中身をコピってEnvironmental Variablesに貼り付けます。
image.png
ついでに使いそうなものも入れておきました。

これで.circleci/config.ymlからこの環境変数を扱えるようになったので、config.ymlを書いていきます。

ちなみに自分はyaml派です。皆さんもそうだと思います。
ただ、config.yamlで作成すると読み込んでくれません。断腸の思いでconfig.ymlにしましょう。

2. イメージプッシュ

config.yml作成

config.ymlを書いてGCRにイメージをpushしていきます。
masterマージをトリガーにしてイメージプッシュとデプロイをcloud Buildに任せる方法もありますが、個人的には管理が分散しないのでcircleCIに一元管理させるほうが好きです。

config.yml
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がインストールされているイメージを使用するのであればこの手順入りません。

これを実行すると
image.png

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は全環境で共通の項目しか書かないので非常にコンパクトになります。

base/deployment.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を作成しました。

build.sh
#!/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を入れることで

overlays/production/kustomize.yaml
...
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

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

kubectlkustomizeをインストールさせるタスクを用意しました。
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が作成されました。

スクリーンショット 2019-12-23 23.15.13.png

動作確認

serviceはtype LoadBalancerで作成したので、生成された外部IPアドレスにアクセスすると

スクリーンショット 2019-12-23 23.18.40.png

無事動いていることが確認できました:tada:

まとめ

kustomizeでCI/CDを実現するためのフローを舐めていきました。
結論このgithubにコードがすべて詰まっているのでそっちを見てください。各章ごとにコミット分けています。
まさかり大歓迎です。

それではみなさん、良いお年を。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
2