1
/
5

GKEでGitOps

Tutorial Advent Calendar 2020 14日目になります。
この記事は田尻が書いています。


前にGit Feature Flowという運用を始めた話をブログに書きましたが、そもそもGitの運用方法を明確にしたのは自動デプロイをしたかったためです。
今回は私たちがGitOpsでGKEにアプリケーションの自動デプロイを行っている実例を紹介します。

使用ツール

・CloudBuild(GCP)

・シークレットマネージャー(GCP)

・Container Registry(GCP)

・GKE(GCP)

・github

弊社はインフラに主にGCPを使っていますので、Cloudbuildとの相性が非常に良いです。
また、お値段もCloudbuildはリーズナブルだと思います。
https://cloud.google.com/cloud-build/pricing

参考

Cloud Build を使用した GitOps スタイルの継続的デリバリー

非公開 GitHub リポジトリへのアクセス

構造



ステージング環境とプロダクション環境でKubernatesのマニフェストが若干異なっていたので、deploy-repoリポジトリでトリガーとなるブランチはstaging用とproduction用で分けています。

ビルド構成ファイル

app-devリポジトリ
ビルド用のビルド構成ファイルになります。


cloudbuild.yaml

steps:
  # start build
  - name: gcr.io/cloud-builders/docker
    args: [
      'build',
      '-t', 'gcr.io/$PROJECT_ID/app-repo:${SHORT_SHA}',
      '-f', 'vendor/docker/app/Dockerfile',
      '.'
    ]
    id: 'build-app'

  # start test step
  - name: gcr.io/cloud-builders/docker
    args: [
      'build',
      '-t', 'gcr.io/$PROJECT_ID/app-repo:run-test',
      '-f', 'vendor/docker/app/Dockerfile.test',
      '.'
    ]
    id: 'build-app-test'

  # start push
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'push'
      - 'gcr.io/$PROJECT_ID/app-repo:${SHORT_SHA}'
    id: 'push-app'

  # git clone
  - name: 'gcr.io/cloud-builders/gcloud'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        gcloud secrets versions access latest --secret=secret-name > /root/.ssh/id_github
    volumes:
      - name: 'ssh'
        path: /root/.ssh
    waitFor: ['push-app']
    id: 'get-secret'

  - name: 'gcr.io/cloud-builders/git'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        chmod 600 /root/.ssh/id_github
        cat <<EOF >/root/.ssh/config
        Hostname github.com
        IdentityFile /root/.ssh/id_github
        EOF
        ssh-keyscan -t rsa github.com > /root/.ssh/known_hosts
    volumes:
      - name: 'ssh'
        path: /root/.ssh
    waitFor: ['get-secret']
    id: 'set-up-key-domain'

  - name: 'gcr.io/cloud-builders/git'
    args:
      - clone
      - --recurse-submodules
      - git@github.com:Tutorial-Inc/deploy-repo.git
    volumes:
      - name: 'ssh'
        path: /root/.ssh
    waitFor: ['set-up-key-domain']
    id: 'clone-deploy-repo'

  - name: 'gcr.io/cloud-builders/git'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        cd deploy-repo && \
        git checkout candidate_production && \
        git config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)')
    waitFor: ['clone-deploy-repo']
    id: 'checkout-deploy-repo'

  - name: 'gcr.io/cloud-builders/git'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        cd deploy-repo/prod && \
        sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_ID}/g" deployment.yaml.tpl | \
        sed "s/COMMIT_SHA/${SHORT_SHA}/g" > deployment.yaml && \
        sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_ID}/g" job_migrate.yaml.tpl | \
        sed "s/COMMIT_SHA/${SHORT_SHA}/g" > job_migrate.yaml
    waitFor: ['checkout-deploy-repo']
    id: 'generate-manifest'

  - name: 'gcr.io/cloud-builders/git'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        set -x && \
        cd deploy-repo && \
        git add . && \
        git commit -m "Deploying image gcr.io/$PROJECT_ID/deploy-repo:${SHORT_SHA}
        Built from commit ${COMMIT_SHA} of repository deploy-repo
        Author: $(git log --format='%an <%ae>' -n 1 HEAD)" && \
        git push origin candidate_production
    volumes:
      - name: 'ssh'
        path: /root/.ssh
    waitFor: ['generate-manifest']
    id: 'push-manifest'

timeout: 1800s



deploy-devリポジトリ


デプロイ用のビルド構成ファイルになります。


cloudbuild.yaml

steps:
  # deploy start
  - name: 'gcr.io/cloud-builders/kubectl'
    args:
      - 'apply'
      - '-f'
      - 'prod/job_migrate.yaml'
    env:
      - 'CLOUDSDK_COMPUTE_ZONE=<your zone>'
      - 'CLOUDSDK_CONTAINER_CLUSTER=<your cluster name>'
    id: 'deploy-job-migrate'

  - name: 'gcr.io/cloud-builders/kubectl'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        sh check_complete_migration.sh
    env:
      - 'CLOUDSDK_COMPUTE_ZONE=<your zone>'
      - 'CLOUDSDK_CONTAINER_CLUSTER=<your cluster name>'
    waitFor: ['deploy-job-migrate']
    id: 'check-complete-job-migrate'

  - name: 'gcr.io/cloud-builders/kubectl'
    args:
      - 'delete'
      - '-f'
      - 'prod/job_migrate.yaml'
    env:
      - 'CLOUDSDK_COMPUTE_ZONE=<your zone>'
      - 'CLOUDSDK_CONTAINER_CLUSTER=<your cluster name>'
    waitFor: ['check-complete-job-migrate']
    id: 'delete-job-migrate'

  - name: 'gcr.io/cloud-builders/kubectl'
    args:
      - 'apply'
      - '-f'
      - 'prod/deployment.yaml'
    env:
      - 'CLOUDSDK_COMPUTE_ZONE=<your zone>'
      - 'CLOUDSDK_CONTAINER_CLUSTER=<your cluster name>'
    waitFor: ['check-complete-job-migrate']
    id: 'deploy-deployment'

  # copy start
  - name: 'gcr.io/cloud-builders/gcloud'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        gcloud secrets versions access latest --secret=secret-name > /root/.ssh/id_github
    volumes:
      - name: 'ssh'
        path: /root/.ssh
    waitFor: ['deploy-deployment']
    id: 'get-secret'

  - name: 'gcr.io/cloud-builders/git'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        chmod 600 /root/.ssh/id_github
        cat <<EOF >/root/.ssh/config
        Hostname github.com
        IdentityFile /root/.ssh/id_github
        EOF
        ssh-keyscan -t rsa github.com > /root/.ssh/known_hosts
    volumes:
      - name: 'ssh'
        path: /root/.ssh
    waitFor: ['get-secret']
    id: 'set-up-key-domain'

  - name: 'gcr.io/cloud-builders/git'
    args:
      - clone
      - --recurse-submodules
      - git@github.com:Tutorial-Inc/deploy-repo.git
    volumes:
      - name: 'ssh'
        path: /root/.ssh
    waitFor: ['set-up-key-domain']
    id: 'clone-deploy-repo'

  - name: 'gcr.io/cloud-builders/git'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        cd deploy-repo && \
        git config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)') && \
        git checkout production && \
        git checkout $COMMIT_SHA prod/. && \
        git commit -am "Manifest from commit $COMMIT_SHA
        $(git log --format=%B -n 1 $COMMIT_SHA)" && \
        git push origin production
    volumes:
      - name: 'ssh'
        path: /root/.ssh
    waitFor: ['clone-deploy-repo']
    id: 'copy-to-production-branch'

jobのステータスがCompletedになるまで待っています。
ちゃんとcontextはenvで指定しているクラスタになります。

ハマったポイント

cloudbuildからgithubのprivateリポジトリへのアクセス
これが結構ハマってしまいました。ビルド構成ファイルごとにSSHの情報をconfigに書かないといけないので、若干面倒でした。
GCPのCloud Source Repositoriesだともっとシンプルに書けるようです。
詳しい説明は公式のドキュメントに書いてありますので、貼っておきます。
https://cloud.google.com/cloud-build/docs/access-private-github-repos


マイグレーションの完了を待つ
スクリプトを書く以外の方法がなさそうでした。
スクリプトを書いて確認するようにしたら無事に成功したのでよかったです。

まとめ

想像以上に簡単にできました。公式のドキュメントにも具体的なやり方が書いてあったので、助かりました。
弊社は目標として毎日リリースするというのを目指しています。実際は2日に1回くらいのリリース頻度ですが、自動ビルド・自動デプロイはとても助かっています。
また、手動でやった時のオペレーションミスがなくなるので、最高です。

オートロ株式会社からお誘い
この話題に共感したら、メンバーと話してみませんか?
オートロ株式会社では一緒に働く仲間を募集しています
4 いいね!
4 いいね!

今週のランキング

田尻 彩夏さんにいいねを伝えよう
田尻 彩夏さんや会社があなたに興味を持つかも