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

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

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

#サンプルプログラムのセット
##GoogleのサンプルアプリケーションをCloneする
https://cloud.google.com/kubernetes-engine/docs/tutorials/hello-app?hl=ja

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

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

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

#GitHub Actionsのセット
https://docs.github.com/ja/actions/guides/deploying-to-google-kubernetes-engine

##GCPの設定
###Kubernetes Engine及びContainer Registry APIを有効化
```
gcloud config set <project-name>

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

###サービスアカウントの作成、シークレットの保存
```shell:サービスアカウントの作成
gcloud iam service-accounts create <service-account-name>
```

```shell:サービスアカウントのメールアドレスの取得
gcloud iam service-accounts list
```

```shell:サービスアカウントにロールを付与
gcloud projects add-iam-policy-binding <project-name> \
  --member=serviceAccount:<service-account-mailaddress> \
  --role=roles/container.admin \
  --role=roles/storage.admin
```

```shell:サービスアカウントのJSONキーファイルをダウンロードする
gcloud iam service-accounts keys create key.json --iam-account=<service-account-mailaddress>
```

```shell:JSONキー内容を出力する（出力は後続の手順のシークレット登録時に使用）
cat key.json | base64
```

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/e0d1bef5-9cc0-bcd1-9c9a-de080fbe0320.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/8dbcc1d8-4f82-c3d3-7112-b8c9f4f965e0.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/04adeaa2-2149-540b-59ee-5f3a22a32644.png)

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

 - GKE_PROJECT_DEV：開発環境のGCPのプロジェクトID
 - GKE_SA_KEY_DEV：出力したサービスアカウントJSONキーの内容
 
##GitHub Actionsを登録する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/5da695ec-e605-58e7-7297-00631ec90302.png)

~/.github/workflows/　Actions用にyamlファイルが作成される
今回はdevelopment.ymlというファイル名にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/3d839e7c-a9b4-ffa4-6dc4-edec7b954df5.png)


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

今回は開発環境へデプロイする前提で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/setup-gcloud@v0.2.0
      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/get-gke-credentials@v0.2.1
      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を設定する必要がある。

```yaml: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([参考](https://qiita.com/yakisuzu/items/6b6a65d9cbc0422f4b3d))を動かすために、hello-app/manifestsに以下ファイルを作成し、どのマニフェストファイルがデプロイ対象なのか設定する

```yaml: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タブに移動すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/2ed4f517-0d91-d3ba-148f-36d5d1f88250.png)

対象のワークフローをクリックすると詳細に移動できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/99b5b6eb-772c-1af5-a01d-a32b7309dd03.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/712d0010-b76b-6357-eb81-20d16e810543.png)


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

##アプリケーションの確認
```
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画面にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/3a05413a-f1a5-fd0a-5b60-02b552219198.png)

デプロイできた！

#GigHub Actionsで発生したエラー
##Required "container.clusters.get" permission(s) 
サービスアカウントへのcontaner.adminのロール付与がうまくいってなかったので、手動で設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/ba233496-95ca-d2e9-da1c-8952617ef795.png)