GAE アプリを Cloud Bulid で CI/CD して Slackbot でトラフィック移行する!

Author
qushot
Lv:14 Exp:52307

映画好きエンジニア。
GAEとかGKEやってます!Goが好きです!

みなさんは GAE 使ってますか?デプロイはどうしてますか??
私は最近まで手動でデプロイ先のプロジェクトを切り替え、手動でデプロイをしていました。その方が温かみのあるアプリケーションに仕上がるかと思い・・・
冗談はさておき、今回は簡単な GAE のサンプルアプリを GCP プロダクトを用いて CI/CD する方法について解説していきます!平成も終わったことですし、手動でのデプロイも終わらせましょう!

GAE アプリを作成してデプロイしてみよう!

GAE とは

GAE は GCP の中でも最も歴史のある PaaS です。コードを書いてデプロイするだけで、 Google の管理する強固なインフラ上でアプリを動かせることや、急激なトラフィックの増加にも柔軟に対応し、スケールしてくれるところが魅力です。今回は GAE の Standard Environment (SE) 上に Go で書いた簡単なアプリをデプロイします。
公式ドキュメント

アプリの作成とデプロイ

GAE へデプロイするためには GCP プロジェクトと Cloud SDK が必要となりますので、準備がお済みでない方は下記記事を参考にしてみてください!
【apps-gcp】初心者のためのGCPプロジェクト始め方入門
【apps-gcp】Cloud SDKコンポーネント、gcloudコマンドの使い方を解説!!

※ 今回はプロジェクトIDを「your-project-id」としているので、実際に試して見る際はご自身のプロジェクトIDに置き換えてください。

今回のアプリの構成です。デプロイすることが目的なので、アクセスした際に「Hello, 世界!」と表示するだけの最小限の構成となっております。

$ tree ./appengine
./appengine
├── app.yaml
└── main.go
app.yaml
runtime: go111
main.go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/hello", helloHandler)
	http.ListenAndServe(":8080", nil)
}

func helloHandler(w http.ResponseWriter, r *http.Request)  {
	fmt.Fprint(w, "Hello, 世界!")
}

まずは下記コマンドで GAE アプリを作成します。
$ gcloud app create

下記コマンドでアプリを GAE へデプロイします。
$ gcloud app deploy --project=your-project-id ./appengine/app.yaml

ブラウザで https://your-project-id.appspot.com/hello へアクセスし、画面に「Hello, 世界!」と表示されていればデプロイは成功です。

Cloud Build の設定をして動作確認してみよう!

Cloud Build とは

Cloud Build は GCP のインフラでビルドを行うサービスで、Docker コンテナや Java Archive などを生成することができます。また、ビルド構成ファイル内で gcloud app deploy コマンドを実行することで任意のアプリを GAE にデプロイすることもできます。
公式ドキュメント
Cloud Build についてより詳細に書かれた入門記事もありますので、こちらも併せてご覧になってみてください!

ビルドトリガーを設定する

トリガーの作成は gcloud コマンドからはできないため、ブラウザでクラウドコンソールにアクセスして設定します。


「トリガーを作成」をクリックします。


ソースリポジトリは GitHub を選択し、「リポジトリ接続サービスの〜」にチェックを入れ、「続行」をクリックします。


対象のリポジトリを選択し、「続行」をクリックします。


トリガー名は「example-trigger」としておきます。トリガーのタイプはブランチを選択し、ブランチは先頭に「issue/」と付くものを対象とします。
ビルド設定は「Cloud Build構成ファイル」を選択します。プロジェクト配下に「cloudbuild.yaml」ファイルを作成しておくことで、ビルド構成ファイルにしたがって Cloud Build がビルドを行います。「トリガーの作成」をクリックします。

また、このタイミングで コンソール にアクセスし、 App Engine Admin API を有効にしておきます。

クラウドコンソールにアクセスし、Cloud Build のサービスアカウント(your-project-number@cloudbuild.gserviceaccount.com)に AppEngineデプロイ担当者 の権限を付与します。

Slack Bot User を作成してトークンを取得しよう!

Qiitaの記事を参考に Slack Bot User を作成します。
Slack への投稿時に利用するので xoxb- から始まる「Bot User OAuth Access Token」をメモしておきましょう。

Cloud KMS で鍵を用意しよう!

Cloud KMS とは

Slack Bot User 作成時に取得したトークンは Cloud Functions で利用します。Functions 内での環境変数として .env.yaml ファイルに書き込みますが、トークンの書かれたファイルをそのまま GitHub などに上げるわけにはいきません。
そこで Cloud KMS(Key Management Service)を利用して暗号化します。
公式ドキュメント

Cloud KMS の強力な機能「鍵ローテーション」について詳細に検証をした記事もご覧になってみてください!

暗号鍵の作成

まずは コンソールから KMS の API を有効化します。

KMS で暗号化を行うためには、Keyring と Key の作成を行う必要があります。

Keyringの作成
$ gcloud kms keyrings create keyring-name --location=asia-northeast1
Keyの作成
$ gcloud kms keys create key-name --keyring=keyring-name --location=asia-northeast1

暗号化・復号化する際には Keyring と Keyと暗号化ファイルパス、平文ファイルパスを指定します。

暗号化
$ gcloud kms encrypt --keyring=keyring-name --key=key-name --location=asia-northeast1 --plaintext-file=file --ciphertext-file=file.enc
復号化
$ gcloud kms decrypt --keyring=keyring-name --key=key-name --location=asia-northeast1 --ciphertext-file=file.enc --plaintext-file=file

Cloud Functions で関数を作成しよう!

Cloud Functions とは

Cloud Functions はイベント駆動型のサーバレスコンピューティングプラットフォームです。HTTP リクエストや GCS へのアップロード、Pub/Sub トピックへのメッセージのパブリッシュをトリガーとして、GCP へデプロイされた関数を実行します。現在は Node.js や Python、Go などで書かれたコードを実行することができます。
公式ドキュメント

Cloud Functions についてより詳しく知りたい方はこちらの記事もご覧になってみてください!

Slackbot で利用する関数

今回の Slackbot では以下の3つの関数を利用します。
1. Challenge 用の関数
2. Cloud Build のビルド結果を Pub/Sub から受け取り Slack へメッセージを送信する関数
3. Slack のインタラクティブメッセージの選択結果を受け取り GAE のバージョンを切り替える関数

App Engine Admin API について

App Engine Admin API ではクラウドコンソールで行うような GAE のバージョン切り替えやドメインマッピング、ファイアーウォールルールの設定などを API から操作することができます。
公式ドキュメント
APIs Explorerを利用すればコードを書かずに API の機能を試すことができます!

Challenge 用の関数

Challenge とは Slack のイベント通知先に設定したサーバを所有していることを証明するために、Slack がサーバに対してリクエストを送るので、そのリクエストに含まれている challenge というパラメータをそのまま返すことです。
この際、Verification Token というものも必要になるので、Slack Bot の管理画面から値を確認しておき、環境変数用の yaml ファイルに追記しておきましょう。

Cloud Build のビルド結果を Pub/Sub から受け取り Slack へメッセージを送信する関数

Cloud Build でのビルド結果は Pub/Sub へパブリッシュされ、Functions のトリガーとして関数を実行することができます。
関数内で Cloud Build のビルド時の情報(ステータス、リポジトリ、ブランチ名)を受け取れるので、ステータスが成功、もしくは失敗だった場合に Slack へメッセージを送信します。実は GAE へのデプロイ時にも Cloud Build が発火しているので、GitHub への Push による Build なのか GAE へのデプロイによる Build なのかを判別する必要があります。
GAE へのデプロイによる Build の場合はビルド情報にブランチ名が含まれなくなるので、私の場合はそれを判断材料としています。
また、この関数内で App Engine Admin API を利用して GAE のバージョン一覧を取得し、インタラクティブメッセージのセレクトボックスに表示します。

Slack のインタラクティブメッセージの選択結果を受け取り GAE のバージョンを切り替える関数

この関数では、上記関数で送信したインタラクティブメッセージのセレクトボックスで選択したバージョンの結果を受け取り、App Engine Admin API を利用してトラフィックを切り替えます。
また、この関数では最初にインタラクティブメッセージを Slack から削除する処理も含めています(何度も選択するとその度にトラフィックを切り替える処理が走ってしまうため)。
トラフィックの切り替えには、1つ以上のバージョンとそれぞれのバージョンに割り振るトラフィック量を指定します。今回は指定したバージョンにすべてのトラフィックを流します。切り替えに成功した場合には成功した旨のメッセージを Slack へ送信します。

まとめ

今回の記事では GAE アプリのソースを GitHub に Push した際に自動でデプロイし、Slack に通知、Bot から App Engine Admin API でバージョンの切り替えを行いました。また、記事では省略してしまいましたが、Cloud Build 内でテストコードを実行させることもできますし、GAE だけでなく GKE へのデプロイも行うことができます。
ソースコードは 弊社のGitHub に置いてありますので、ぜひご参考にしてください! コードがイケてない感があるのでPRもお待ちしております! 記事へのご意見・ご指摘は Twitter にて受け付けております。

最後になりますが弊社クラウドエース株式会社は Google Cloud のプレミアパートナーとして、Google Cloud Platform 利用にあたっての支払代行サービスや技術サポート・構築・開発・トレーニングなど Google Cloud に関するサービスを幅広く提供しております。ご相談ございましたらお気軽にお問い合わせください!

次の記事を読み込んでいます
次の記事を読み込んでいます
次の記事を読み込んでいます
次の記事を読み込んでいます
次の記事を読み込んでいます