はじめに
こんにちは!
株式会社BFT名古屋支店・インフラ女子(?)のやまぐちです。
このブログでは「GithubへのpushをトリガーとしてAWS側でCI/CDを実行する」を2回に分けて解説しています(実際はCDだけ。CIは後で実装予定)。
前回の記事はこちらです。
bftnagoya.hateblo.jp
季節は冬なのに、なぜバカンスなアイキャッチ画像にしたのか…
GithubでのpushをトリガーにAWSでコードをデプロイする! (2/2)
全2回のうちの2回目である今回は、以下図の赤枠内が記載範囲です。前回はGithub → Lambda → EventBridgeの連携を説明しましたので、今回はEventBridge → Systems Managerでコマンドを実行するまでをご紹介します。
Systems Managerで実行するコマンドは「ドキュメント」と呼ばれるテンプレートを作成して使用します。ドキュメント作成後にEventBridgeのルールでパラメータを指定してそのドキュメント実行するだけです。あら簡単。
SSMドキュメント作成
簡単、と言っても実際に作ろうと思ってかなり混乱したのがドキュメントのスキーマバージョンです。バージョンには1系と2系があり、書き方が異なります。
バージョン1.2 | バージョン2.2 | 詳細 |
---|---|---|
runtimeConfig | mainSteps | 実行するステップ |
properties | inputs | ステップのパラメータ |
commands | runCommand | 実行するコマンド |
id | action | (それぞれ異なる?) |
- | name | ユーザ定義名 |
また、ドキュメントには実行対象(のAWSサービス)によって種類が複数あります。今回はSystems Managerで管理しているノードでコマンドを実行するため、「Run Command」がサポートされている「AWS-RunShellScript」のドキュメントを使用します。
ポイントは「parameters」に「commands」、「workingDirectory」「executionTimeout」と投入するパラメータを変数とする部分です。そうすることで「runtimeConfig.aws:runShellScript.properties」で値に {{ 変数 }} を使用し、実行時に指定ができます。
これはEventBridgeからパラメータを指定するために必須です。ハードコーディングしたい方は変数にはせずそのまま記載してもOKですが。
記載は以下のようにしました。
{ "schemaVersion": "1.2", "description": "Run a shell script or specify the commands to run.", "parameters": { "commands": { "type": "StringList", "description": "(Required) Specify a shell script or a command to run.", "minItems": 1, "displayType": "textarea" }, "workingDirectory": { "type": "String", "default": "", "description": "(Optional) The path to the working directory on your instance.", "maxChars": 4096 }, "executionTimeout": { "type": "String", "default": "3600", "description": "(Optional) The time in seconds for a command to complete before it is considered to have failed. Default is 3600 (1 hour). Maximum is 172800 (48 hours).", "allowedPattern": "([1-9][0-9]{0,3})|(1[0-9]{1,4})|(2[0-7][0-9]{1,3})|(28[0-7][0-9]{1,2})|(28800)" } }, "runtimeConfig": { "aws:runShellScript": { "properties": [ { "id": "0.aws:runShellScript", "runCommand": "{{ commands }}", "workingDirectory": "{{ workingDirectory }}", "timeoutSeconds": "{{ executionTimeout }}" } ] } } }
作成後は「Run Command」メニューからパラメータ指定で実行できることを確認してください。
EventBridgeでルールの作成
EventBridgeにはgithubのイベントが流れてきます(前回の実装範囲)。そのイベントをトリガーにSystems Managerのドキュメントを実行します。
イベントバスの作成
イベントバスはdefaultでも構いませんが、一応AWSの推奨としてはSaaSサービスからのイベントは分ける、とのことなので作成することにしました。イベントバスを分ける利点はリソースベースのポリシーでアクセス制御できることです(今回はポリシーを設定しないのでdefaultでも構いません)。
ちなみに前回の作業でLambda側ではイベントバスを [ default ] で作成しているのでこの後に設定変更します(イベントバス名はLambdaの環境変数で設定されています)。
EventBridgeで [ イベントバスを作成 ] を押します。
任意の名前を付与し、[ 作成 ] します(イベントアーカイブはイベントを残したい場合に有効化する)。
ルールの作成
githubの複数のリポジトリに対してpushイベントを検知するルールを登録する予定のため、明確にどのリポジトリが更新されたかをイベントパターンへ指定します。
[ ルール ] から [ ルールを作成 ] を押し、先ほど作成したイベントバスを選択して任意のルール名を付与します。
イベントソースを [ AWS イベントまたは EventBridge パートナーイベント ] とし、サンプルイベントも [ EventBridge パートナーイベント ] とします。するとサンプルイベントのリストでGithubのpushが選択できます。このサンプルイベントを元に次のイベントパターンを作成します。
今回はrepositoryのssh_urlをイベントパターンに指定しました(特定できれば何でも構いません)。
このターゲットの指定が今回最も苦労した部分です。ポイントは2つ、1つ目はターゲットキーに実行対象をタグで指定するということ、2つ目はパラメータの指定の仕方です。
あとは必要に応じてタグを付け、確認した上で作成完了です。
Lambdaから連携するイベントのイベントバス変更
ルールをdefaultのイベントバスで作成した場合はこの部分の実行は不要です。
Lambdaの環境変数でイベントバスを設定しているので、Lambdaで変更してもよいのですが、ここではCloudFormationで変更する手順を記載します。そもそもこのLambdaはCloudFormationで作成されているためです。
- CloudFormationのスタックで「GitHubInboundWebhookStack~」を探します(2022/12現在)。
[ 既存スタックの変更セットを作成 ] を選択します。
パラメータを指定するだけなのでそのまま [ 次へ ] を押します。
EventBusNameに作成したイベントバス名を入力し [ 次へ ] を押します。
後は何も変更せず、変更セットを作成し、[ 変更セットを実行 ] します。どうやらイベントバスを変更するとLambdaに適用するRoleも自動的に変えてくれる様子。優しい。
CloudFormationのイベントステータスが [ UPDATE_COMPLETE ] になったらLambdaで環境変数が変更されていることを確認しましょう。ちゃんと変わってますね。
動作確認
やり方は前回と同様です。Gitlabへpushすることで、Githubへミラーリングされ、そのpushをトリガーにLambda関数URLへWebhook、そのイベントはEventBridgeを介してルールが実行され、Systems Managerのドキュメントで指定するコマンドを実行します。
実行されたコマンドはSystems managerで確認できます。
まずは作業PCからGitlabへのコマンド実行の様子です。
anna@LAPTOP-RNA0J544:~/condoransible/condoru$ anna@LAPTOP-RNA0J544:~/condoransible/condoru$ git add README.md anna@LAPTOP-RNA0J544:~/condoransible/condoru$ git commit -m "update README.md" [main f2d501c] update README.md 1 file changed, 1 insertion(+), 1 deletion(-) anna@LAPTOP-RNA0J544:~/condoransible/condoru$ git push origin main Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Delta compression using up to 8 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 297 bytes | 297.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0) To gitlab.com:a-yamaguchi1/condoru.git 0d8cf45..f2d501c main -> main anna@LAPTOP-RNA0J544:~/condoransible/condoru$ anna@LAPTOP-RNA0J544:~/condoransible/condoru$ anna@LAPTOP-RNA0J544:~/condoransible/condoru$ git status On branch main Your branch is up to date with 'origin/main'. nothing to commit, working tree clean anna@LAPTOP-RNA0J544:~/condoransible/condoru$
Gitlabは該当レポジトリの [ 設定 ] - [ リポジトリ ] のミラーしているリポジトリで確認です。
Githubは該当リポジトリの [ Settings ] - [ Webhooks ] で設定しているWebhookの左端が緑チェックになっていればOKです。
Run Commandの実行は履歴から確認できます。
あとはコマンドが失敗した際に検知できるようにCloudWatchでアラーム設定が必要そうですね。
このコードのデプロイは開発環境用なので、この後に自動テストを実装したい…ですが、それはまた次の機会に。
終わりに
後はコマンド実行するだけじゃーん、と思いつつ、結構ハマりました。Systems Manaerのドキュメント作成と実行対象の指定部分です。
ドキュメントの実行対象としてInstanceIDか'tag:
解決方法としては、Systems ManagerのRun Commandで対象を選択すると [ AWSコマンドラインインターフェイスのコマンド ] と表示されるのでここで確認!
これで一連の流れは完了! EventBridgeで指定するコマンドをgit pullにすればコードの更新は完了です。
以上、ここまで読んでいただきありがとうございました~ ^ ^