😽

Terraform+CodeDeployでAWS LambdaをBlue/Green、Canary(カナリア)デプロイするサンプルコード

2021/05/21に公開

作ったもの

  1. TerraformでLambda、CodeDeployをプロビジョニング
  2. Lambdaに何らかの変更が加わった場合のみ、追加でCodeDeployを利用してBlue/Green or Canary(カナリア)デプロイをする

を実現するミニマルなサンプルコードです。

https://github.com/Jimon-s/terraform-example-codedeploy-lambda

図で表すと、まず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(カナリア)デプロイできるメリットとのトレードオフになりますので、ケースによって使い分けましょう。

https://github.com/Jimon-s/terraform-example-codedeploy-lambda

IaCといい感じに共存できるデプロイ戦略を見つけていきたいですね。

Discussion