CodeBuildとは
AWSのなかでCI/CDを担うCode三兄弟のひとつ、という説明では一切何もわからなかったので、軽く触った理解をメモとして残します。
AWS CodeBuildは、Jenkinsジョブ相当のものを「Build project」と呼び、任意のDockerイメージを起動して、コンテナ内で任意のコマンドを起動できるサービスと理解しました。
私自身はCircleCIあるし時間の無駄でしょと思って敬遠してましたが、CI/CDという色眼鏡を外すと、活用の幅が非常に広い面白い製品です。使わないのはもったいない!
こんなことに使えそう
- CircleCIやTravisCIなどの CI as a Service を利用されてるなら、料金面や速度など強い不満なければ、わざわざ移設するほどのものではありません
- EC2サーバーにJenkinsを立ててCI/CDに供しているなら、一部のJenkinsジョブをCodeBuildのBuild Projectに移設すると、Dockerコンテナで動かせるフルマネージドサービスなど利点を享受できる可能性があります
- EC2サーバーにSSHして定型作業をしているなら、CodeBuildのBuildProjectとして定型化できる可能性があります
- EC2サーバー1台でcronジョブを動かして、SPOFや性能面のスケールに課題を感じているなら、CodeBuildのBuildProjectに移設し利点を享受できる可能性があります
- ウェブアプリのリリース時のRDBマイグレーションの実行場所に悩んでるなら、CodeBuildのBuildProjectに移設できる可能性があります
- DockerコンテナをLambdaで動かしたいよなあ、という妄想は、CodeBuildで実現できそう
CodeBuildの制限
私が思いついた使い道の範囲でも、色々と制限が絡んできます。
-
CodeBuild の制限 - AWS CodeBuild
- 初期値での並列実行数はそんなに多くない
-
Amazon VPC の制限 - Amazon Virtual Private Cloud
- VPCでも動かすなら、起動中はENIとIPを使うことを念頭に。実行が終わったら、CodeBuildがENIは削除、IPは開放してくれる。
-
IAM エンティティおよびオブジェクトの制限 - AWS Identity and Access Management
- BuildProjectごとにIAM管理ポリシーを勝手に作らせると、気がついたら上限到達してそう。
-
AWS サービスの制限 - アマゾン ウェブ サービス
- 環境変数の値をSSMパラメータストアから取ってくるなら念頭に。最近緩和されましたが同時接続数なども。
サンプル: CodeBuildでGithubリポジトリを取ってきてRDS MySQLに接続する
妄想を並べるのもどうかと思うので、動きそうなサンプルを組んでみました。
- GitHubリポジトリを持ってくる
- CodeBuild提供ではないDockerイメージで動かす
- VPCで動かす
- MySQLに接続する
- MySQLの接続情報はSSMパラメータストア(暗号化)から取ってくる
- 定期実行させる
これだけ要素を押さえれば、cronジョブ実行に使えそうだとか、RDBマイグレにも使えそうだとかわかりそうなので。
作業するあなたは IAMFullAccess 権限を有している必要があります
CodeBuildのBuildProjectを作成する過程で、IAM権限を構成させるためです。
VPCを準備する
VPCで動作させるなら、以下の準備が必要です。
- Publicサブネットを用意する
- PublicサブネットにNATゲートウェイを立てる
- Privateサブネットを用意する
- Privateサブネットのルートテーブルに、0.0.0.0/0がNATゲートウェイを経由するよう記載
RDSを立てる
VPC Privateサブネットに立てておきます。VPCで動くCodeBuildから接続できるよう、RDS側セキュリティグループに穴を開けておきます。
SSMパラメータストアに、RDS接続パスワードをテキトーな名前で入れておく
- 名前は「sasasin-aurora-serverless-admin-passwd」
- 利用枠は標準
- タイプは「安全な文字列」
- KMS主要なソースは「現在のアカウント」
- KMSキーIDは「alias/aws/ssm」
GitHubリポジトリを準備する
とりあえず作るだけなので、README.mdだけ転がってるリポジトリでよいです。
CodeBuild に Build Project を作る
CodeBuild管理画面を開く。Create Build Project。
- 名前は hello-codebuild-vpc-mysql
- SourceProviderは GitHub
- Repository in my GitHub Account で準備したGitHubリポジトリを指定
- 初回はOAuth認証を要求されるので、Authしてあげて
- webhook
- 設定組むと「特定のブランチでpushされたら」などが実現できる。今回は割愛
- Envirionment
- Environment Image: Custom image
- Environment Type: Linux
- External Image URL: library/amazonlinux:2
- Service Role: New
- Role Name: hello-codebuild-vpc-mysql
- 追加設定
- VPC, Subnet, Security Group: 用意したPrivateサブネットを選択。セキュリティグープは、RDSに接続可能なものを選択。
- Environment variables:
- RDS_USER: (RDSに接続す
るユーザーを)、Plaintext - RDS_ENDPOINT: (RDSのエンドポイントURLを)、Plaintext
- RDS_PASSWD: (SSMパラメータストアの名前を)、Parameter
- こいつだけ Parameterなことに注意
- 私は「sasasin-aurora-serverless-admin-passwd」としていました
- RDS_USER: (RDSに接続す
- BuildSpec
- insert
- switch to editor 押して、内容は以下
version: 0.2
phases:
install:
commands:
- yum install -y mariadb-server
build:
commands:
- env | sort
- mysql -u${RDS_USER} -p${RDS_PASSWD} -h${RDS_ENDPOINT} -e "show databases;"
amazonlinux:2では、mysqlコマンドはmariadb-serverに含まれている。mysqlではなくmariadbなのでこのように。
envを見ているのは、まあ、環境変数で指定した値や、SSMパラメータストアから取ることにした環境変数は、このように取れますよというご確認で。
できあがり
こんな。
Build Projectを実行してみる
Start Buildボタン押したら、しばらくして実行されます。
今回の作例ではyum installが時間食って2分くらいかかってますね。実行頻度や料金が気になってきたら、予めyum installしたコンテナイメージをECRかDockerhubに入れて使うと良いでしょう。
定期実行させる
なんも悩む要素ないです。build projectを選んで、Build triggers、create triggerで実行周期を設定するだけです。書いた時刻はGMTで解釈されるようです。
他の方法で実行させる
- webhookで実行する
- 設定組むと「特定のブランチでpushされたら」などが実現できる。今回は割愛
- 任意のタイミングで、AWS SDKのCodeBuild.Client.start_build()で実行する
- AWSイベントをLambdaで受けて、CodeBuildのBuild Projectを実行する
- 任意のイベントをZapier経由でLambdaで受けて、CodeBuildのBuild Projectを実行する
などなど
ここまでをコード化する
TerraformかCloudFormationでしょう。
- https://www.terraform.io/docs/providers/aws/r/codebuild_project.html
- https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-codebuild-project.html
buildspec.ymlをどこで管理するのが正解か。私は今のところ、TerraformかCloudFormationと一緒に置いておくのが良いのではないかなあという気がしています。正直、buildspec.ymlだけ見たところで何もわからない。ジョブ定義の全体を見なければわからない。
自前のDockerfileがあるなら、同じくTerraformかCloudFormationと一緒に置いておくと、見通しが良いように感じてます。
ハマりどころ
- VPCで実行さすと10~20秒、余分にかかる。VPCで実行する確かな理由がないなら、VPC指定無しで実行するのが総合的に正しい
- ca-certificateが入ってないDockerイメージを使い、かつ、SSMパラメータストアの暗号化した値を取り出そうとするとハマる。buildspec.ymlで入れようとしても、それより前の段階でSSMパラメータストアから復号化してるため間に合わない。具体的にはalpineでDOWNLOAD_SOURCEという段階で、こんなエラーログが出ます。今回はAmazonLinux2のイメージを利用し回避しました。
[Container] 2019/05/06 07:53:44 Phase complete: DOWNLOAD_SOURCE State: FAILED
[Container] 2019/05/06 07:53:44 Phase context status code: Decrypted Variables Error Message: RequestError: send request failed
caused by: Post https://ssm.us-east-2.amazonaws.com/: x509: certificate signed by unknown authority