こんにちは、シタテルの鶴巻です。
devops&インフラ担当です。
シタテルのプロダクトのリリース作業を少し楽にするために、
Slack+Lambda+Golangを用いて開発した話をします。
リリースの流れ
シタテルでは、GitフローやGitHubフローを採用しています。
また、本番環境へのデプロイは、以下の流れで実施しています。
- developブランチからreleaseブランチを作成
- ステージング環境でreleaseブランチをデプロイ&動作確認
- 本番環境にデプロイ
ちなみに、1.でreleaseブランチを作成すると、CircleCIによって2.のステージング環境へのデプロイは自動で行われます。
地味に面倒なリリース作業
ステージング環境へのデプロイは自動化されているとはいえ、小さな手作業が合間に発生し、地味に面倒でした。
具体的には以下のような作業です。
- developブランチからreleaseブランチの作成
- ローカルPCでdevelopブランチを最新の状態にpullして、releaseブランチ作成してGitHubにpush
- releaseブランチのプルリクエスト作成
- GitHubのUIをポチポチ
- リリースタグの作成
- 前回のリリース以降でマージされたプルリクエストを見て、リリース内容を記述
手作業はSlackからコマンドを叩くだけにしました
Slackから以下のコマンドを叩くだけで、地味に面倒くさかった作業を自動で行うようにしました。
/release <repository> <release branch>
実際には、以下の内容を実施するGolangプログラムをLambdaで実行しています。
- 対象のリポジトリをクローンし、developブランチからreleaseブランチを作成し、GitHubにpush
- releaseブランチのプルリクエストを作成
- 前回のリリース以降にマージされたプルリクエストのタイトルのリストを記述したリリースタグのドラフトを作成
構成
Slack -> API Gateway -> Lambda01(同期) -> Lambda02(非同期) -> GitHub
- Slackからコマンドを叩くと、Lambda01にリクエストを送信します。
- Lambda01は、Lambda02に対象レポジトリとブランチ名を付与してリクエストを送信します。
- Lambda02で作業を実行します。
Lambdaを2つ使用している理由
Slackはリクエスト送信後3秒でタイムアウトするためです。
実行したいプログラムは3秒以上かかるため、実際の作業は非同期で実施する必要がありました。
そのため、Lambda01はLambda02に処理を投げて、Slackに200を返し、実際の処理はLambda02で実施します。
Lambda01はLambda02を非同期実行で呼び出すので、リクエストをキューに入れた後は、Lambda01は関数を終了することができます。
Lambdaの呼び出しタイプ(同期・非同期)
Lambdaは、呼び出しタイプ(InvocationType)を指定することで、同期実行や非同期実行を選択することができます。
例:InvocationTypeで"Event"を指定することで、非同期実行でLambdaを呼び出せます。
input := &lambda.InvokeInput{
FunctionName: aws.String("xxxx"),
Payload: jsonBytes,
InvocationType: aws.String("Event"),
}
※同期実行は"RequestResponse"を指定します
今回使用したGitHub操作のためのGoライブラリ
- go-git https://github.com/src-d/go-git
- インメモリでgitクローンするために使用
- go-github https://github.com/google/go-github
- google製
- プルリク作成やリリースタグ作成に使用
その他ハマったポイント
- APIGatewayの統合リクエストのマッピングテンプレートを使いこなせず。デバッグのやり方もわからず、使うのを諦めました。
まとめ
- 少しの手間が自動化されるだけで、すごく楽になります。これからももっとやっていきたいです。
- GitHub操作のライブラリはとても便利でした。
- シタテルのサービスはRails + vue.jsが主ですが、自分の好きなGo言語を使えたので楽しかったです。