Amazon Web Services ブログ

AWS Proton Terraform テンプレート

この記事は AWS Proton Terraform Templates (記事公開日: 2022 年 3 月 23 日) を翻訳したものです。

re:Invent 2020 において、AWS はサーバーレスおよびコンテナベースのアプリケーションのインフラプロビジョニングとコードデプロイメントの自動化と管理を目的とした新サービス AWS Proton をローンチしました。ローンチ当初は AWS Proton を使ったインフラストラクチャをプロビジョニングするための唯一のオプションとして AWS CloudFormation が、お客様に提供されました。HashiCorp Terraform のサポートは、現在公開されているロードマップの中で最も投票された項目のため、ローンチ後の優先事項としてすぐに決まりました。

2021 年、AWS Proton は 2 つの新機能のサポートを開始しました。

  1. HCL (HashiCorp Configuration Language) で記述された AWS Proton のテンプレートを登録する機能
  2. お客様所有の Git リポジトリへのプルリクエストによる自己管理型プロビジョニングのワークフロー

今回は、このリリースに関する 2 つの記事のうちの 1 つをご紹介します。この記事では、上記の最初の機能である、 Terraform を使った AWS Proton テンプレートの作成について取り上げます。

2 つ目の機能を説明している後編を読みたい方は、AWS Proton 自己管理型プロビジョニングにアクセスしてください。

AWS Proton の概要

この機能の具体的な説明に入る前に、製品としての AWS Proton について簡単に説明します。すでに製品についてご存知の方は、このセクションをスキップしてください。

AWS Proton は、テンプレート管理とテンプレートデプロイの 2 つの主要なエクスペリエンスに分かれています。テンプレートは、組織内のインフラストラクチャの専門家が、再利用可能なインフラストラクチャをコードバンドルとして作成できるようにするための抽象化レイヤーです。AWS Proton のテンプレートは、基本的に一人の管理者が CloudFormation ファイルなどのコードテンプレートで汎用的なインフラストラクチャを書き上げ、設定可能なパラメータを抽出することができます。そして、開発者はデプロイ時にそれらのパラメータを指定するだけで、同等のインフラストラクチャを稼働させることができます。

この抽象概念は、さらに環境とサービスという 2 種類のリソースに分解されます。環境とは、その環境で動作しているサービスインスタンスが利用できる共有リソースの集まりのことです。そして、サービスとは、開発するアプリケーションに必要なインフラストラクチャのことです。サービスインスタンスは、環境にデプロイされます。これは AWS Proton の重要なコンセプトです。

環境を作成する際、管理者が AWS Proton に提供しなければならないものの中には、AWS Proton が関連するインフラストラクチャのプロビジョニングを補助するためのいくつかのメタデータがあります。このメタデータの主要なコンポーネントは、AWS サービスロール、AWS Proton 環境アカウント接続、または本機能リリース時点では、Git リポジトリのいずれかです。

A how it works diagram of AWS Proton

Terraform テンプレートバンドルの作成

AWS Proton のテンプレートバンドルの作成にアプローチする際には、大きく 2 つのことを考える必要があります。

  1. プロビジョニングしたいインフラストラクチャ (およびそれを表現するために使用したい言語)
  2. AWS Proton 内でテンプレートを再利用するために、インプットとして何を抽象化したいか

この次のセクションでは、AWS Proton 環境で構成された VPC 内で実行される Lambda 関数を生成するサービステンプレートの作成について見ていきます (以下の図は、私たちが取り組んでいることを示しています)。

Diagram of AWS Proton Service Template

前の図の中で、いくつか注意していただきたいことがあります。AWS Proton Lambda Service Template と書かれた緑色のボックスは、これから実装するサービステンプレートを表しており、2 つの VPC 環境にリソースをデプロイします。VPC Environment Template と Service Template を結ぶ赤い線は、VPC 環境のテンプレートと私たちのサービステンプレートの間に関連があることを示しています。AWS Proton では、サービステンプレートは環境のプロビジョニングからアウトプットを継承することができるので、その仕組みも見ていきましょう。

複数の Terraform ファイル

今回のローンチで新たに追加された機能は、バンドル内に 1 つ以上の Infrastructure-as-Code ファイルを含めることができることです。CloudFormation ではバンドル内に 1 つのファイルのみ指定するといった要件が残っていますが、Terraform では論理的な .tf ファイルの分離が一般的なので、AWS Proton 内で Terraform テンプレートを作成する際にも、このエクスペリエンスの一貫性を確保するためです。

HCL 変数

CloudFormation では、パラメータ化は、人気のあるテンプレートエンジンである Jinja を介して処理されます。HCL はすでに非常に成熟した変数システムを持っているので、Jinja を再利用する代わりに、AWS Proton の入力のパラメータ化には、HCL の変数システムを使うことにしました。

AWS Proton のテンプレートに変換する前に、今回使用する Terraform の構成の概要から説明します。

my-tf-lambda-function/
  /config.tf  # general terraform configuration
  /lambda.tf  # lambda specific configuration
  /outputs.tf # output configuration

config.tf

最初のファイル config.tf では、AWS プロバイダーを使用することを指定しています。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.5.0"
    }
  }

  backend "s3" {}
}

# Configure the AWS Provider
provider "aws" {}

lambda.tf

lambda.tf では、Amazon S3 に格納されているソースコードを使用して、VPC 内で実行される関数と、Lambda がその関数を実行するために引き受けるロールを作成しています。

resource "aws_iam_role" "iam_for_lambda" {
  name = "iam_for_lambda"

  managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"]

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}
resource "aws_lambda_function" "my_lambda" {
  function_name = "lambda_function_name"
  role          = aws_iam_role.iam_for_lambda.arn
  handler       = "index.test"

  s3_bucket     = "deployment-artifacts"
  s3_key        = "function.zip"

  runtime       = "nodejs12.x"

  vpc_config {
    subnet_ids         = ["subnet-071f712345678e7c8"],
    security_group_ids = ["sg-085912345678492fb"]
  }
}

outputs.tf

最後に outputs.tf は、作成した関数の Amazon Resource Name (ARN) を出力しています。

outputs "lambda_arn" {
  value = my_lambda.arn
}

ここでのゴールは、関数が VPC 内で実行され、Lambda に対して特定のアクセス許可のみが付与されている Lambda 関数用の再利用可能な AWS Proton サービステンプレートを作成することです。

まず、他の場所に新しいディレクトリを作成します。このディレクトリは、構造的には次のようになります。

acme-corp-secure-lambda/
  instance_infrastructure/
    manifest.yaml
    config.tf
    lambda.tf
    outputs.tf
  schema/
    schema.yaml

manifest.yamlschema.yaml の 2 つの新しいファイルを導入し、さらに AWS Proton のテンプレートバンドル構造に合わせて構造を少し再編成しました。

マニフェストの目的は、AWS Proton に対して、そのディレクトリのどのファイルに関心を持つべきかを示すことです。現在、Terraform では .tf で終わるファイルのみがサポートされています。以下は、manifest.yaml の内容です。

infrastructure:
  templates:
    - file: "*"
      rendering_engine: hcl
      template_language: terraform

さて、次はより興味深い部分です。lambda.tf ファイルの中で、テンプレートをデプロイしようとする人が設定したいものが何か考えてみましょう。組織内の開発者は Lambda ランタイムをうまく組み合わせて使いたいので、AWS Proton の管理者またはプラットフォームチームとして、その設定とそれに関連するもの (つまり、関数の場所、ハンドラ、名前など) を設定できるようにする必要があります。さらに、VPC 情報の提供を要求したいです。しかし、先ほどの図を思い出すとテンプレートをデプロイする人ではなく、環境から提供されるようにしたいです。

それでは、関数への入力を宣言するために使用される AWS Proton の schema.yaml を書きましょう。

schema:
  format:
    openapi: "3.0.0"
  service_input_type: "LambdaFunctionInput"

  types:
    LambdaFunctionInput:
      type: object
      description: "Input properties for a Secure Lambda function."
      properties:
        function_name:
          type: string
          description: "The name for the function."
          minLength: 1
          maxLength: 50
        handler:
          type: string
          description: "The handler path for the function."
          minLength: 1
          maxLength: 50
        lambda_runtime:
          type: string
          description: "The runtime for your Lambda service"
          enum: ["nodejs12.x", "python3.8", "ruby2.7", "java11", "go1.x", "dotnetcore3.1"]
        function_s3_bucket:
          type: string
          description: "The s3 bucket where the function code is stored"
          minLength: 1
          maxLength: 200
        function_s3_key:
          type: string
          description: "The s3 key where the function code is stored"
          minLength: 1
          maxLength: 200

VPC の情報がないことに気付いたかもしれません。冗長に聞こえるかもしれませんが、安心してください、それは環境から取得することになります。このスキーマは、デプロイ時に開発者が直接提供する必要がある情報を宣言するためのものです。

そして最後に、これらの変数入力を取り込むために、lambda.tf に必要な変更を加えましょう。

resource "aws_lambda_function" "my_lambda" {
  function_name = var.service_instance.inputs.function_name
  handler       = var.service_instance.inputs.handler

  s3_bucket = var.service_instance.inputs.function_s3_bucket
  s3_key    = var.service_instance.inputs.function_s3_key

  runtime = var.service_instance.inputs.lambda_runtime

  vpc_config {
    subnet_ids         = [var.environment.outputs.subnet_id]
    security_group_ids = [var.environment.outputs.security_group_id]
  }
}

これらの変数に目を通すと、2 つの異なる名前空間の変数を参照していることがわかります。最初の名前空間である var.service_instance.inputs はスキーマから来たものなので、馴染みのあるものへの参照を含んでいるはずです。2 番目の名前空間である var.environment.outputs は新しいものです。ここでは、service_instance をデプロイした環境から出力を取得するように AWS Proton に指示しています。この場合、VPC 環境ではサブネットとセキュリティグループを出力する必要があります。

テンプレートスコープに基づいて使用可能なパラメータのリストについては、AWS Proton 管理者ガイドのパラメータをご覧ください。

環境テンプレート互換性についての注意事項

サービステンプレートが必要な出力を備えた環境に確実にデプロイされるようにする方法について、疑問に思うかもしれません。そのために、AWS Proton では環境テンプレートとサービステンプレートの間に互換性という概念があります。これはサービステンプレートの登録時に宣言されます。そして、サービス作成時に、互換性のあるテンプレートを使ってインスタンス化された環境にのみ、インスタンスをデプロイすることができます。

これで完了です。次は AWS Proton にテンプレートを登録する方法を確認します。

テンプレートの登録

すでに AWS Proton テンプレートの登録手順に慣れている方は、このセクションをスキップしてください。これは、テンプレートを登録する方法のウォークスルーです。Terraform テンプレートの良いところは、作成が完了したら AWS Proton に登録するプロセスが CloudFormation ベースのテンプレートのプロセスと同じところです。

前提条件

このウォークスルーに沿って作業する場合は、以下のものが必要です。

  • AWS アカウント
  • S3 バケット

ウォークスルー

ここでは物事を単純化するために、サンプルリポジトリに使用できる環境テンプレートをすでに作成しています。まず、https://github.com/aws-samples/aws-proton-terraform-sample-templates をクローンしてください。ここにはいくつかのテンプレートがあります。私たちが興味を持っているテンプレートは lambda-vpc/sample-vpc-environment-template/v1 に置かれています。何を作っているのか確認してみましょう。VPC の設定は Terraform Amazon VPC モジュールに依存しています。ぜひ見てほしいのが、infrastructure/outputs.tf です。以下のようになっているはずです。AWS Proton 用にテンプレート化した lambda.tf ファイルを見返すと、その outputs が参照した環境の outputs と一致していることがわかります。

output "vpc_arn" {
  value = module.vpc.vpc_arn
}

output "subnet_id" {
  value = one(module.vpc.private_subnets)
}

output "security_group_id" {
  value = module.vpc.default_security_group_id
}
  1. リポジトリのルートで次のコマンドを実行します。
    $ cd lambda-vpc/sample-vpc-environment-template/v1/
    $ tar -zcvf terraform-vpc-env.tar.gz *
  2. 次に、terraform-vpc-env.tar.gz を S3 バケットの任意の場所にアップロードします。
  3. AWS マネジメントコンソール にサインインし、https://console.aws.amazon.com/proton/home#/templates/environments に移動したら、環境テンプレートを作成のリンクを選択し、フォームに記入します。独自のテンプレートバンドルを使用を選択し、S3 ロケーションを聞かれるので、テンプレートをアップロードした場所を確認します。
  4. 次に、テンプレートの詳細ページに移動します。数秒以内に、公開できるようになるはずです。
  5. v1.0 を公開というボタンが表示されたら、それを選択します。

これで公開され、デプロイできるようになりました!今はまだデプロイしません。後編の AWS Proton 自己管理型プロビジョニングで見ていきます。

面白い事実があります!このリポジトリは、実は AWS Proton の別の新機能であるテンプレート同期と連携されるように設定されています。もしテンプレートの同期設定ついてもっと学びたい場合は、AWS Proton 管理者ガイド のテンプレートの同期設定をチェックしてください。

これで、この記事の前半で作成したテンプレートを登録する準備が整いました。

このフォームは、最後のステップに従った場合、かなり見慣れたものになるはずです。サービステンプレートを作成する際に理解すべき主な違いは、サービステンプレートは与えられた環境テンプレートとの互換性を宣言しなければならないということです。そこで、先ほど作成した環境テンプレートを選択するようにしてください。残りの項目を入力し、同じ手順で公開します。

これで終了です! AWS Proton 内にサービステンプレートを書き、登録することに成功しました。

これらの Terraform テンプレートをデプロイする方法を知りたい方は、この 2 部構成の記事の後編である AWS Proton 自己管理型プロビジョニングに進むか、サンプルリポジトリの Wiki を確認してください。

最後に

クラウドのフットプリントをきちんと管理することは、非常に難しいことです。開発者が自分の能力を最大限に発揮してアプリケーションを構築できるような柔軟性を提供しながら、セキュリティと信頼性のベストプラクティスを実施するという、バランスのとれた方法を見出したいと考えます。さらに、組織内で発生する重複作業を減らしたいというニーズもあります。AWS Proton は、これらの目標を達成するためのプロセスをより管理しやすいものにすることを目的としています。このタスクの一部は、あなたが知っていて好きなツールをサポートすることでもあり、HCL で作成されたテンプレートを使用することは、その目標を達成するための最初のステップに過ぎません。

さあ、テンプレートの作成を始めましょう!

翻訳はプロフェッショナルサービスの高橋たまが担当しました。原文はこちらです。