😽
Terraform+CodeDeployでAWS LambdaをBlue/Green、Canary(カナリア)デプロイするサンプルコード
作ったもの
- TerraformでLambda、CodeDeployをプロビジョニング
- Lambdaに何らかの変更が加わった場合のみ、追加でCodeDeployを利用してBlue/Green or Canary(カナリア)デプロイをする
を実現するミニマルなサンプルコードです。
図で表すと、まずLambdaとCodeDeployの作成 or 更新が走り、
完了後に、Lambdaが更新されていれば、追加でCodeDeployのデプロイメントをトリガーします。
ポイント
TerraformでCodeDeployを起動する方法
Terraform本体には、CodeDeployのデプロイメントを起動する仕組みが存在しないため、自前で実装する必要があります。
今回は、null_resource
中のlocal-exec
で、aws cliを呼び出して実現しています。
# ----------------------------------------------------------
# Trigger of deployment
# ----------------------------------------------------------
resource "null_resource" "run_codedeploy" {
・・・
provisioner "local-exec" {
# Only trigger deploy when lambda version is updated (=lambda version is not 1)
command = "if [ ${var.lambda_version} -ne 1 ] ;then aws deploy create-deployment --application-name ${aws_codedeploy_app.sample.name} --deployment-group-name ${aws_codedeploy_deployment_group.sample.deployment_group_name} --revision '{\"revisionType\":\"AppSpecContent\",\"appSpecContent\":{\"content\":\"{\\\"version\\\":0,\\\"Resources\\\":[{\\\"${var.lambda_function_name}\\\":{\\\"Type\\\":\\\"AWS::Lambda::Function\\\",\\\"Properties\\\":{\\\"Name\\\":\\\"${var.lambda_function_name}\\\",\\\"Alias\\\":\\\"${var.lambda_alias_name}\\\",\\\"CurrentVersion\\\":\\\"${var.lambda_alias_version}\\\",\\\"TargetVersion\\\":\\\"${var.lambda_version}\\\"}}}]}\"}}';fi"
}
}
かなり見づらいですが、使っているのは、
$ aws deploy create-deployment
です。
今回は、できるだけ外部ファイルへの参照をなくした実装としたかったため、ワンライナーで書いていますが、オプションの
--cli-input-yaml or --cli-input-json
を使って、外部ファイルからの読み込みとすることも可能です。
CodeDeployのトリガータイミング
デプロイを発火するタイミングは、Lambdaのバージョンが上がったタイミングとしています。
先程のnull_resource
内にtriggers
を設定して実現しています。
triggers = {
# Run codedeploy when lambda version is updated
lambda_version = var.lambda_version
}
provisioner "local-exec" {
# Only trigger deploy when lambda version is updated (=lambda version is not 1)
command = "if [ ${var.lambda_version} -ne 1 ] ;then aws deploy create-deployment --application-name ${aws_codedeploy_app.sample.name} --deployment-group-name ${aws_codedeploy_deployment_group.sample.deployment_group_name} --revision '{\"revisionType\":\"AppSpecContent\",\"appSpecContent\":{\"content\":\"{\\\"version\\\":0,\\\"Resources\\\":[{\\\"${var.lambda_function_name}\\\":{\\\"Type\\\":\\\"AWS::Lambda::Function\\\",\\\"Properties\\\":{\\\"Name\\\":\\\"${var.lambda_function_name}\\\",\\\"Alias\\\":\\\"${var.lambda_alias_name}\\\",\\\"CurrentVersion\\\":\\\"${var.lambda_alias_version}\\\",\\\"TargetVersion\\\":\\\"${var.lambda_version}\\\"}}}]}\"}}';fi"
}
}
デプロイ戦略を変えたい場合
デフォルトの実装では、「2分ごとに10%ずつ新バージョンにトラフィックを向けるBlue/Greenデプロイ」になっています。
こちらは、aws_codedeploy_app
で設定しているので、デプロイ戦略を変えたい場合はこちらをカスタムしましょう。
resource "aws_codedeploy_deployment_group" "sample" {
app_name = aws_codedeploy_app.sample.name
deployment_group_name = "SampleDeploymentGroup"
service_role_arn = aws_iam_role.codedeploy_deployment_group_sample.arn
deployment_config_name = "CodeDeployDefault.LambdaLinear10PercentEvery2Minutes"
deployment_style {
deployment_option = "WITH_TRAFFIC_CONTROL"
deployment_type = "BLUE_GREEN"
}
}
注意点
デプロイ(=aliasとversionの紐付け)をCodeDeployに任せることになるので、terraformコードでLambdaのaliasとversionを管理することはできなくなります。
Blue/Green、Canary(カナリア)デプロイできるメリットとのトレードオフになりますので、ケースによって使い分けましょう。
IaCといい感じに共存できるデプロイ戦略を見つけていきたいですね。
Discussion