LoginSignup
0
0

More than 1 year has passed since last update.

[GCP]CloudBuild + CloudKMS + GitHubでタグプッシュデプロイを実現する

Last updated at Posted at 2021-05-30

やりたいこと

  • GoogleCloudBuildを利用
  • ソースコードはGitHubで管理
  • GitHubのリポジトリにタグPushGoogleAppEngineにデプロイ
  • CloudBuild⇆GitHubのSSH鍵はGoogleKeyManagementServiceを利用 GAE+CB+KMS+GitHub.jpg

前提

  • GCP(Google Cloud Platform)のアカウントを所持している
  • GCPにプロジェクトを作成できる
  • GitHubのアカウントを所持している
  • サンプルで利用する言語はGo言語
  • 投稿者の環境はMacOS(intel, Catalina)

サンプルのディレクトリ構成

cloudbuild-helloworld
.
├── .github_cloudbuild.enc
├── .known_hosts
├── submodule # submodule
|   └── submodule_dummy.txt
├── app.yaml
├── cloudbuild.yaml
└── helloworld.go

事前準備

  1. GitHubにリポジトリの作成(private) ※既存のリポジトリを利用する場合はOwner権限が必要
  2. GCPにプロジェクトを作成

Cloud KMS(Cloud Key Management Service API)の設定

  • APIの有効化 KMS検索.png KMSAPI有効化.png
  • Keyringの作成(後述)
  • Keyの作成(後述)

App Engine Applicationの作成(今回初めてGAEを使う人)

$ gcloud app create

Please choose the region where you want your App Engine application 
located:

 [1] asia-east2    (supports standard and flexible and search_api)
 [2] asia-northeast1 (supports standard and flexible and search_api)
 [3] asia-northeast2 (supports standard and flexible and search_api)
 [4] asia-northeast3 (supports standard and flexible and search_api)
 [5] asia-south1   (supports standard and flexible and search_api)
 [6] asia-southeast2 (supports standard and flexible and search_api)
 [7] australia-southeast1 (supports standard and flexible and search_api)
 [8] europe-central2 (supports standard and flexible)
 [9] europe-west   (supports standard and flexible and search_api)
 [10] europe-west2  (supports standard and flexible and search_api)
 [11] europe-west3  (supports standard and flexible and search_api)
 [12] europe-west6  (supports standard and flexible and search_api)
 [13] northamerica-northeast1 (supports standard and flexible and search_api)
 [14] southamerica-east1 (supports standard and flexible and search_api)
 [15] us-central    (supports standard and flexible and search_api)
 [16] us-east1      (supports standard and flexible and search_api)
 [17] us-east4      (supports standard and flexible and search_api)
 [18] us-west2      (supports standard and flexible and search_api)
 [19] us-west3      (supports standard and flexible and search_api)
 [20] us-west4      (supports standard and flexible and search_api)
 [21] cancel
Please enter your numeric choice:  3 # 好きなロケーションのインデックスを入力する。この場合はasia-northeast2

Creating App Engine application in project [cloudbuild-qiita] and region [asia-northeast2]....done.                                                                                                                                                    
Success! The app is now created. Please use `gcloud app deploy` to deploy your first app.

App Engine Admin APIの設定

  • APIの有効化 スクリーンショット.png AppEngineAdminAPI有効化.png

Cloud Buildの設定

  • CloudBuildトリガーの作成&GitHubリポジトリの接続 CloudBuildTrigger.png Trigger設定.png リポジトリ接続.png リポジトリ接続2.png GitHubモーダル.png GitHubモーダル2.png リポジトリ選択.png リポジトリ接続同意&接続.png Trigger設定2.png Trigger設定3.png

IAM(Cloud Identity and Access Management)の設定

  • cloudbuild.gserviceaccount.comアカウントへ下記権限の付与
    • AppEngineデプロイ担当者:デプロイに必要
    • AppEngineサービス管理者:デプロイ後のトラフィック変更に必要
    • CloudBuildサービスアカウント:元々付与されている
    • クラウドKMS暗号鍵の復号化:GitHubとの連携時KMSを利用する場合には必要
    • サービスアカウントユーザー:新しいバージョンをデプロイするために必要, IAMからは追加できず、CloudBuildの設定から有効にする
    • ストレージ管理者:GitHubリポジトリのミラーリングに必要

GitHubの設定

  • Adminロールの設定(CloudBuildの接続に利用するGitHubアカウント)

手順

KMSを利用したGitHubSSH鍵の暗号化(※コードブロック内大文字は自由入力)

1. 意図しないプロジェクトへの接続を防ぐため、config再セット
$ gcloud config set project PROJECT_NAME
(PROJECT_NAMEは連携設定をするプロジェクト名)
2. 暗号鍵のキーリングを作成
$ gcloud kms keyrings create KEYRING \ 
--location LOCATION
(KEYRINGは設定したいkeyringの名称)
example
$ gcloud kms keyrings create github-deploy-keyring \
$ --location global
3. 暗号鍵のキーを作成
$ gcloud kms keys create KEY \
--keyring KEYRING \
--location LOCATION \
--purpose encryption
(KEYは設定したいkeyの名称, KEYRINGは手順2で設定したkeyringの名称, LOCATIONはkeyを保管したいCloudの場所)
example
$ gcloud kms keys create github-key \
--keyring github-deploy-keyring \
--location global \
--purpose encryption
4. SSH鍵の作成
$ cd ~/.ssh
$ ssh-keygen -t ed25519 -C ”your_mail@email.sample”
$ Enter file in which to save the key: id_ed25519
$ Enter passphrase (empty for no passphrase):
$ Enter same passphrase again:

下記メッセージが出れば成功

Your identification has been saved in id_ed25519.
Your public key has been saved in id_ed25519.pub.
5. ssh-agentへの登録

バックグラウンドでssh-agentを開始

$ eval "$(ssh-agent -s)" 
> Agent pid 59566

~/.ssh/configファイルの確認

$ open ~/.ssh/config
> The file /Users/you/.ssh/config does not exist.

上記エラーの時はファイルが存在しないので、ファイルを作成する

$ touch ~/.ssh/config

~/.ssh/config ファイルを開いて今回の接続情報を作成する

~/.ssh/config
Host cloudbuild-qiita  # 好きな名前を設定, 汎用の場合は'*'
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_ed25519  # id_ed25519キーの場所と名前がデフォルト以外の場合はここを置き換える
6. SSH 秘密鍵をssh-agentに追加して、パスフレーズをキーチェーンに保存
$ ssh-add -K ~/.ssh/id_ed25519
7. 作成したSSH鍵をGitHubへ登録

公開鍵をクリップボードへコピー

$ pbcopy < id_ed25519.pub
  • GitHubのプロフィール画像をクリックし、続いてSettingsをクリック
  • ユーザ設定サイドバーでSSH and GPG keysをクリック
  • [Add SSH key]をクリック
  • [Title]フィールドで、新しいキーを説明するラベルを追加
  • キーを[Key]フィールドに貼り付ける
  • [Add SSH key]をクリック
8. KMSを利用したSSH鍵の暗号化
$ gcloud kms encrypt \
--key KEY \
--keyring KEYRING \
--location LOCATION \
--plaintext-file id_ed25519 \
--ciphertext-file CIPHERTEXT_FILE
(KEY/KEYRING/LOCATIONは手順3までで設定したもの, CIPHERTEXT_FILEは設定したい名称)
example
$ gcloud kms encrypt \
--key github-key \
--keyring github-deploy-keyring \
--location global \
--plaintext-file id_ed25519 \
--ciphertext-file .github_cloudbuild.enc
9. 暗号化したSSH鍵をプロジェクトフォルダ内に移動させる
$ mv CIPHERTEXT_FILE ~/go/src/github.com/YOUR_PROJECT_DIRECTORY/
(CIPHERTEXT_FILEは手順8で設定した名称、YOUR_PROJECT_DIRECTORYはCloudBuildでデプロイしたいプロジェクトのディレクトリPATH)
example
$ mv .github_cloudbuild.enc ~/go/src/github.com/Rererr/cloudbuild-helloworld/
10.下記コマンドで、プロジェクトフォルダに.known_hostファイルを作成
$ ssh-keyscan -t rsa github.com > ~/go/src/github.com/YOUR_PROJECT_DIRECTORY/.known_hosts
example
$ ssh-keyscan -t rsa github.com > ~/go/src/github.com/Rererr/cloudbuild-helloworld/.known_hosts
11. プロジェクトディレクトリに必要なファイル群の確認
  • CIPHERTEXT_FILE ex.) .github_cloudbuild.enc
  • .known_hosts

cloudbuild.yamlの設定

  1. SSH鍵の複合化を実行, 複合化したキーを/root/.ssh/id_ed25519へ保存
  2. /root/.ssh/id_ed25519の権限変更
  3. /root/.ssh/configへ接続情報の書き込み
  4. known_hostsの移動
  5. submodule update --initの実行
  6. app deployの実行
  7. 最新19バージョンを残し、古いバージョンの削除を実行
cloudbuild.yaml
steps:
  - name: "gcr.io/cloud-builders/gcloud"
    args:
      - --project=$PROJECT_ID
      - kms
      - decrypt
      - --ciphertext-file=.github_cloudbuild.enc
      - --plaintext-file=/root/.ssh/id_ed25519
      - --location=global
      - --keyring=github-deploy-keyring
      - --key=github-key
    volumes:
      - name: "ssh"
        path: /root/.ssh
    id: 'decrypt-ssh'

  - name: "gcr.io/cloud-builders/git"
    entrypoint: "bash"
    args:
      - "-c"
      - |
        chmod 600 /root/.ssh/id_ed25519
        cat <<EOF >/root/.ssh/config
        Hostname github.com
        IdentityFile /root/.ssh/id_ed25519
        EOF
        mv .known_hosts /root/.ssh/known_hosts
    volumes:
      - name: "ssh"
        path: /root/.ssh
    waitFor:
      - 'decrypt-ssh'
    id: 'git-ssh'

 - name: gcr.io/cloud-builders/git
    args: ["submodule", "update", "--init"]
    volumes:
      - name: "ssh"
        path: /root/.ssh
    waitFor:
      - 'git-ssh'
    id: 'git-submodule-update'

  - name: "gcr.io/cloud-builders/gcloud"
    args:
      - "app"
      - "deploy"
      - "--project=$PROJECT_ID"
      - "app.yaml"
    waitFor:
      - 'git-submodule-update'
    timeout: 3600s

  - name: "gcr.io/cloud-builders/gcloud"
    entrypoint: "bash"
    args:
      - "-c"
      - "gcloud app versions list | sort -rk 4,4 | tail -n +20 | awk '{print $2;}' | xargs -I {} gcloud app versions delete {}"

timeout: 3600s 

app.yamlの記載(本筋じゃないのでruntimeのみ記載)

app.yaml
runtime: go115

hello.goの作成(本筋じゃないのでHello, World!を返すだけのHTTP Server)

helloworld.go
package main

import (
        "fmt"
        "log"
        "net/http"
        "os"
)

func main() {
        http.HandleFunc("/", handle)
        port := os.Getenv("PORT")
        if port == "" {
                port = "8080"
        }
        log.Printf("Listening on port %s", port)
        if err := http.ListenAndServe(":"+port, nil); err != nil {
                log.Fatal(err)
        }
}

func handle(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" {
                http.NotFound(w, r)
                return
        }
        fmt.Fprint(w, "Hello world!")
}

GitHubへタグプッシュ

$ git branch # 念の為現在のブランチの確認
$ git tag dev-2021053001 # tagの作成
$ git push origin dev-2021053001 # tagのpush

CloudBuildでビルド&デプロイができているか確認

ビルドデプロイ実行中.png
ビルドデプロイ完了.png

AppEngineへのデプロイ確認

デプロイ確認.png
Hello world!が表示されていれば成功
HelloWorld.png

後片付け

プロジェクトの削除(今回のために作成したプロジェクトならこれが一番早くて確実)

プロジェクト削除1.png
プロジェクト削除2.png
プロジェクト削除3.png

KMS(プロジェクトを消せないなら)

KMSの課金は、アクティブな鍵に対して行われるので、鍵を非アクティブに変更します
KMS削除.png
KMS削除2.png
KMS削除3.png
KMS削除4.png

GitHub

今回のために作成したSSH鍵の削除
GitHubSSH削除.png
あと、リポジトリも不要なら消しておきましょう!

~/.ssh/config

今回追記した部分は削除しておきましょう

~/.ssh/config 下記部分は削除
Host cloudbuild-qiita
     AddKeysToAgent yes
     UseKeychain yes
     IdentityFile ~/.ssh/id_ed25519

あとがき

思ったよりもめちゃくちゃ長くなりました....
もし不明な点や追記希望などありましたら、コメントや編集リクエストいただけると嬉しいです。

0
0
0

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
  3. You can use dark theme
What you can do with signing up
0
0