AWS CodePipelineからCodeBuildを呼んでlambdaで古いAMIを消すといい感じになる
前回の続き
AWSでAMIの作成をCodeBuildを使って自動化したけど、CodeBuildが動く部分も自動化したいので、Githubに置いてあるリポジトリのmasterにマージされたタイミングで自動的にAMIが作られるといい感じなんじゃないかと思って、「これくらい簡単にできるっしょ」ってやろうとしたらCodeBuildのトリガーなんてものはないと気づいてAWSめんどいってなったので、めんどい部分を書いておきます。
これ作ってから言うのもアレなんですが、CodePipelineはAWSコンソールから操作する分にはある程度自動化されていて便利な反面、 自前でAMI周りの権限をうまくつけるのは結構面倒なので、terraformとかでCodePipeline/CodeBuild/Lambda/CloudWatchLogs/IAM/S3まわりを一気に設定するのは骨が折れるなあという感想です。
まあ、やろうと思えばできます。ただただ面倒です。なんとかならんのか。
で、本題なんですが、CodePipelineっていうのはCIツール的なやつで、CodeBuildがビルド周りしか担当しないのに対して、CodePipelineはソースの取得、ビルドタスクの実行、ビルド後のタスクなどなど、パイプラインの名の通り色々なタスクをルールに従って処理してくれるやつです。
ビルドの並列化などもできるので、CodeBuildだけで足りないところをいい感じに補ってくれるやつと捉えておくといいかもしれません。
CodePipelineのソースにgithubのリポジトリを指定して、masterブランチを監視しておけば、Pull Request単位でレビューをしてmasterにマージされたタイミングで自動的にCodeBuildを走らせるなんてことが簡単にできます。
便利ですね。
流れとしては
- githubのブランチを監視、変更があればソースで取り込む
- CodeBuildでAMIを生成
- Lambdaで古いAMIを削除
という感じになります。
CodePipeline
CodePipeline自体はUIをみたらなんとなく使い方はわかるくらい簡単なので、特に説明はしないのですが、いくつか気になったところだけ補足します。
ソースはアーティファクトの出力が必要
ソースフェーズで取り込んだgithubのリポジトリをCodeBuildに渡す際にアーティファクトという形でs3を経由する必要があります。
まあ、ソースなんでそのソースはs3に置くでしょという感じな気もするのですが、一時的にs3に置かれるのはちょっと面倒だなあという感想もあります。
なんか、噂によるとパーミッション周りが消えるとかいう話もあるし、ソースじゃなくて単なるトリガーみたいなのをつくれないのかなあという気持ちはあります。
ここはあんまり気にせずいきましょう。必要な権限があればCodeBuildのprebuildとかでつければいいかなという感想です。
タイムアウト時間には余裕を持っておく
CodeBuildもLambdaもですが、意外にも時間がかかることがあるのでタイムアウト時間が短すぎるとエラー扱いになります。
CodeBuildは初回実行時におおよその時間を割り出しておくと良いでしょう。LambdaはAMI削除程度なら15秒もあれば十分かなという程度です。(実際には2秒程度で終わる)
LambdaからCodePipelineのタスクが成功したかどうかは自分で報告する必要がある
地味にハマった問題で、タスク呼び出しで呼んだLambdaが成功したかどうかはLambdaでCodePipelineに通知する必要があります。
そうしないと、たとえLambdaが正常終了したとしてもタイムアウトまで待った上で失敗扱いになるので、見栄え上よくないです。
これはテンプレート的に成功の場合は通知処理を書いておけばまあ問題にはならないでしょう。
Lambdaで古いAMIを削除する
まあ、消しましょう。Jenkinsのように古いビルドとアーティファクトを消すものはないので自前で作る必要があります。面倒ですね。
Lambdaなので、Pythonでサクッと実行します。itemgetter
あたりが知らなかったので勉強になりましたね。
images_limit
とかは適当にいじってやるといいと思います。ec2のAPIを呼ぶのでこのLambdaにはEC2の操作権限をつけないといけません。
あと、上で書いたCodepipelineへの通知は code_pipeline.put_job_success_result(jobId=event['CodePipeline.job']['id'])
のところになります。
もうなんかとりあえず最後にこれを置いておくかという感じですね。
終わりに
とりあえず、AMI作成はこれで自動化できるようになりました。
あとは本投入周りのことは考える必要がありますが、まあその辺がインフラエンジニアの腕の見せどころでしょう。
正直この辺はハンコなのでインフラエンジニアは隠居していたいところなのですが、まあサービスしておきましょう。
はー、こんなことより早くアプリケーション側から呼ばれているMySQLのめっちゃ遅いクエリ消さないとなー!!!
Terraformのcodebuild_projectでParameter Storeがサポートされてない件、普通にissueとPull Requestが出ていたけど、テスト周りでゴニョゴニョしてる感じっぽい。しかもここ最近触られててタイムリー
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月23日
あ、書くの忘れてたんですが、terraformだと今のところCodeBuildの環境変数設定でParameter Storeを指定することができないので、CodeBuildのタスク内で秘密情報はSSMから取ってくる必要があります。
まあそのうち改善しそうですが、具体的にはansible-vaultのパスワードみたいなのは自分で取ってくる必要があるという感じです。頑張って下さい。
なんか雑にginとGORMでWebAPIを書き始めたけど意外といい感じに動きそうな感じになってきた
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月22日
最近暇すぎてGolangを勉強がてら書いてます。
本当はGoroutineを使った並列処理とかそういうのを書きたいんですが、ベンチマーカーくらいしかそんな用途なさそう。
だいたい速度面で困ってないし。
MySQLくん、10万程度のrows_examineでも重いことに気づかれないので優秀なのかもしれない(秒で治せるんだけどな
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月22日
次回はこの辺書くかなという感じです。世界を笑顔に。