GitHub Actions を使用してGKEにアプリケーションをデプロイする


GKE用のサンプルアプリケーションを、GitHub Actionsを使ってソースがPUSHされたら自動でデプロイされるようにする

前提

  • GitHubにリポジトリは作成済み
  • GKE クラスタは作成済み
  • Cloud Shell使用

サンプルプログラムのセット

GoogleのサンプルアプリケーションをCloneする

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
cd kubernetes-engine-samples/hello-app

リモートリポジトリのセット

予め作っておいたリモートリポジトリを登録する

git remote remove origin
git remote add origin <githubのURL>

GitHub Actionsのセット

GCPの設定

Kubernetes Engine及びContainer Registry APIを有効化

gcloud config set <project-name>

gcloud services enable \
    containerregistry.googleapis.com \
    container.googleapis.com

サービスアカウントの作成、シークレットの保存

サービスアカウントの作成
gcloud iam service-accounts create <service-account-name>
サービスアカウントのメールアドレスの取得
gcloud iam service-accounts list
サービスアカウントにロールを付与
gcloud projects add-iam-policy-binding <project-name> \
  --member=serviceAccount:<service-account-mailaddress> \
  --role=roles/container.admin \
  --role=roles/storage.admin
サービスアカウントのJSONキーファイルをダウンロードする
gcloud iam service-accounts keys create key.json --iam-account=<service-account-mailaddress>
JSONキー内容を出力する(出力は後続の手順のシークレット登録時に使用)
cat key.json | base64

GitHubにシークレットを登録する





登録するシークレットは以下

  • GKE_PROJECT_DEV:開発環境のGCPのプロジェクトID
  • GKE_SA_KEY_DEV:出力したサービスアカウントJSONキーの内容

GitHub Actionsを登録する

~/.github/workflows/ Actions用にyamlファイルが作成される
今回はdevelopment.ymlというファイル名にする

本番環境へのデプロイを分けたければ、起動条件、シークレットを分けた別yamlを作れば可能となる。

今回は開発環境へデプロイする前提でyamlファイルを作ってみる

development.yml
name: Build and Deploy to GKE

on:
  push:
    branches:    #以下の名前のブランチがプッシュされたら起動
      - 'feature/*'
      - 'bugfix/*'

env:
  PROJECT_ID: ${{ secrets.GKE_PROJECT_DEV }}
  GKE_CLUSTER: <cluster-name>
  GKE_ZONE: <cluster-zone>
  DEPLOYMENT_NAME: <deployment-name>
  IMAGE: hello-app

jobs:
  setup-build-publish-deploy:
    name: Setup, Build, Publish, and Deploy
    runs-on: ubuntu-latest
    steps:

    - name: Checkout
      uses: actions/checkout@v2

    # gcloud CLI のセットアップ
    - uses: google-github-actions/[email protected]
      with:
        service_account_key: ${{ secrets.GKE_SA_KEY_DEV }}
        project_id: ${{ secrets.GKE_PROJECT_DEV }}

    # gcloud コマンドラインツールを認証情報ヘルパーとして使用するようにDockerを設定する
    - run: |-
        gcloud --quiet auth configure-docker

    # GKE 認証情報を取得して、クラスタにデプロイできるようにする
    - uses: google-github-actions/[email protected]
      with:
        cluster_name: ${{ env.GKE_CLUSTER }}
        location: ${{ env.GKE_ZONE }}
        credentials: ${{ secrets.GKE_SA_KEY_DEV }}

    # Docker イメージをビルドする
    - name: Build
      run: |-
        docker build \
          --tag "gcr.io/$PROJECT_ID/$IMAGE:$GITHUB_SHA" \
          --build-arg GITHUB_SHA="$GITHUB_SHA" \
          --build-arg GITHUB_REF="$GITHUB_REF" \
          hello-app/

    # Docker イメージを Google Container Registry にプッシュする
    - name: Publish
      run: |-
        docker push "gcr.io/$PROJECT_ID/$IMAGE:$GITHUB_SHA"

    # kustomize を設定する
    - name: Set up Kustomize
      run: |-
        curl -sfLo kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v3.1.0/kustomize_3.1.0_linux_amd64
        chmod u+x ./kustomize

    # Docker イメージを GKE クラスタにデプロイする
    - name: Deploy
      run: |-
        cd hello-app/manifests
        ../../kustomize edit set image gcr.io/$PROJECT_ID/$IMAGE:v1=gcr.io/$PROJECT_ID/$IMAGE:$GITHUB_SHA
        ../../kustomize build . | kubectl apply -f -
        kubectl rollout status deployment/$DEPLOYMENT_NAME
        kubectl get services -o wide

googleのサンプルmanifestの注意点

ポート設定

デフォルトではhelloweb-deployment.yamlの方はポートが8080設定なのに、
helloweb-service-load-balancer.yamlの方はポート80設定で、ターゲットポートが設定されていないため、アプリケーションにアクセスできない。(アプリケーションはポート8080で待ち受けているのに、80にフォワーディングされる)
helloweb-service-load-balancer.yamlにターゲットポート8080を設定する必要がある。

helloweb-service-load-balancer.yaml
apiVersion: v1
kind: Service
metadata:
  name: helloweb
  labels:
    app: hello
    tier: web
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080 #この部分の追記必要
  selector:
    app: hello
    tier: web

kustomize設定

kustomize(参考)を動かすために、hello-app/manifestsに以下ファイルを作成し、どのマニフェストファイルがデプロイ対象なのか設定する

kustomization.yml
resources:
- helloweb-deployment.yaml
- helloweb-service-load-balancer.yaml

GitHub Actionsを動かす

トリガーとなるブランチをPUSHする

master ブランチの変更をコミットしておく

serviceのyamlを更新し、kustomization.ymlを追加したので変更をコミットしておく

master(main)ブランチの変更をマージしておく

ActionsはGitHub上で作成したので、ローカル環境のmaster(main)にマージしておく
このあたりちょっとややこしいのだが、GitHubのデフォルトリポジトリが2020年後半にmainとなっており、Googleのサンプルがmasterブランチになっているので、mainブランチをつくってそちらにGitHubの変更をマージし、masterブランチは削除する

git branch main
git checkout main
git branch -d master
git fetch
git branch --set-upstream-to=origin/main main
git merge --allow-unrelated-histories origin/main

ブランチを作成する

feature/* のブランチ名のPUSHがトリガーなので、feature/testというブランチを作成する

git branch feature/test
git checkout feature/test

feature/testブランチをPUSHする

git push origin HEAD

Actionsの実行画面

Actionsタブに移動すると

対象のワークフローをクリックすると詳細に移動できる

成功すると緑のチェックマークつく

アプリケーションの確認

kubectl get pod -o wide

NAME                                READY   STATUS    RESTARTS   AGE    IP          NODE                                           NOMINATED NODE   READINESS GATES
helloweb-6459bd8599-l56vb           1/1     Running   0          111s   10.0.0.11   gke-dev-cluster-1-default-pool-6646ab54-rbrl   <none>           <none>
kubectl get service

NAME              TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
helloweb          LoadBalancer   10.3.240.183   *.*.*.*   80:30222/TCP   2m42s

実際のWeb画面にアクセス

デプロイできた!

GigHub Actionsで発生したエラー

Required "container.clusters.get" permission(s)

サービスアカウントへのcontaner.adminのロール付与がうまくいってなかったので、手動で設定