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

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

:2021/5/20 サンプルコード

どんな記事?
  • Terraform – Lambda + CodeDeployのサンプルコード紹介記事
  • LambdaのBlue/Green、Canary(カナリア)デプロイを実現しています

作ったもの

  1. TerraformでLambda、CodeDeployをプロビジョニング
  2. Lambdaに何らかの変更が加わった場合のみ、追加でCodeDeployを利用してBlue/Greenor 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

を使って、外部ファイルからの読み込みとすることも可能です。

ただし、aws deploy create-deploymentに少しクセがあって、読み込むファイルはCodeDeployといえば、な「appspec.yml」ではないため注意しましょう。

CodeDeployのトリガータイミング

デプロイを発火するタイミングは、Lambdaのバージョンが上がったタイミングとしています。

先程のnull_resource内にtriggersを設定して実現しています。

resource "null_resource" "run_codedeploy" {
  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"
  }
}

注意点

デプロイをCodeDeployに任せることになるので、terraformコードでlambdaのaliasとversionを管理することはできなくなります。

Blue/Green、Canary(カナリア)デプロイできるメリットとのトレードオフになりますので、ケースによって使い分けてください。

あとがき

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

最後までご覧いただきありがとうございました。
Jimon(@jimon_s)でした。

-サンプルコード

関連記事



CATEGORY
更新チェックはこちらから!