👥

AWS SAMでマルチアカウントデプロイ

2023/07/22に公開

概要

AWS SAMにて、マルチアカウントデプロイを設定する機会がありました。
その際、以下の点で悩みました。

  • AWSアカウントを指定して sam deploy コマンドを実行するにはどうしたらよいか
  • Cloudformationテンプレート( template.yaml ) にて、AWSアカウント別に、IDなどの固定パラメータを設定するにはどうすればよいか
    • 固定パラメータの例) 既に生成しているVPC(およびサブネット)のID など

自分の頭を整理する意味も込めて、自分が選択した解決策を投下します。

想定する状況

以下のどちらにも当てはまる状況を想定します。

  • AWS SAMで開発したアプリケーションを、複数環境へデプロイしたい場合
  • 複数環境を、異なるAWSアカウントで管理している場合
    • 言い換えると、一つのAWSアカウントにて、開発/本番の両環境を運用している場合は対象外
  • AWSアカウント別に、固定パラメータを設定してデプロイしたい場合
    • VPCIDなど

話さないこと

  • AWS SAMとは何か
  • AWS SAMの導入方法
  • Cloudformation とは何か

結論

アカウント指定

AWSアカウントを指定してデプロイするには、sam deploy --profile オプションを活用する。

固定パラメータ設定

環境情報(dev/prodなど)をやり取りできるよう、SAMプロジェクトを設定する。
Cloudformation側で環境情報を受け取り、環境情報に応じて参照するパラメータを変更できるようにする。

アカウント指定

方針

sam deploy --profile オプションにて、aws/credentialsに設定したクレデンシャル名を指定できる。
この機能を利用する。

手順

  1. デプロイしたいAWSアカウントのクレデンシャル情報を設定する
  2. --profile オプションでクレデンシャル名 を指定する

1. デプロイしたいAWSアカウントのクレデンシャル情報を設定する

.aws/credentials

[default]
...

[prod_myproject]
aws_access_key_id = xxx
aws_secret_access_key = xxx

2. --profile オプションでクレデンシャル名 を指定する

公式ドキュメントに則り、--profileオプションにて、クレデンシャル名を指定します。

--profile TEXT | AWS 認証情報を取得する、認証情報ファイルから特定のプロファイルです。

デプロイコマンド

sam deploy --profile prod_myproject

以上。
prod_myproject部分に、任意の値をご使用ください。

固定パラメータ設定

方針

CLIからCloudformationへ環境情報(dev/prodなど)をやり取りさせ、環境情報に応じて参照するパラメータを変更できるようにする。

  • Cloudformationテンプレートに環境情報を渡せるよう、 SAMプロジェクトを設定する
    • 同時に、 sam deploy --config-env オプションにて、CLIから環境情報を指定できるようになる
  • Cloudformationテンプレートでは、上記環境情報を受け取り、環境情報に応じて固定パラメータを使い分けられるようにする

手順

  1. Cloudformationテンプレートに環境情報(dev/prodなど)を渡せるよう、 samconfig.tomlを設定する
  2. Cloudformationテンプレートの Parametersセクションにて、手順1で設定した環境情報を定義
  3. Cloudformationテンプレートの Mappingsセクションを作成する
    • ここで、環境情報別のID情報を定義する
  4. 必要に応じて、手順3で設定したマッピング情報を参照する

1. Cloudformationテンプレートに環境情報(dev/prodなど)を渡せるよう、 samconfig.tomlを設定する

samconfig.yanl を編集し、Cloudformationテンプレートに渡すパラメータを追記します。

[prod.deploy.parameters]  // ココに、cliで指定する環境名
capabilities = "CAPABILITY_IAM"
confirm_changeset = true
resolve_s3 = true
s3_prefix = "sample-app"
region = "ap-northeast-1"
image_repositories = []
parameter_overrides = "ENV=\"prod\"" // ココに、Cloudformationへ渡す変数名&値

parameter_overrides 部分で、Cloudformationテンプレートに渡す環境情報を設定します。
上記の記述では、Cloudformation側に ENVという変数名で、prodという値を渡すことになります。

テーブル名 ( 先頭の、[prod.deploy.parameters] 部分)は、以下のルールに則って記述します。

  • コマンドの場合、テーブルヘッダーの形式は [`environment`.`command`.parameters] になります。例えば、default 環境の sam deploy コマンドでは、設定テーブルのヘッダーが [default.deploy.parameters] になります。

引用 : 公式ドキュメント

テーブル名の environment 部分は、sam deploy コマンドの --config-env で 指定します。

  • デフォルトの環境名は default です。デフォルトの環境名は、--config-env パラメータを使用して上書きできます。

引用 : 公式ドキュメント

以上をまとめると、[prod.deploy.parameters]設定を呼び出す、最終的な sam deployコマンドは以下の通りです。

sam deploy --config-env prod

プロファイルも、併せて指定できます。

sam deploy --profile ${.aws/credentialsで定義したクレデンシャル名} --config-env prod

このコマンドを実行すると、 [prod.deploy.parameters] 部分の設定を読み込みつつ、 Cloudformationテンプレートを読み込み、 デプロイ処理が走ります。

2. Cloudformationテンプレートの Parametersセクションにて、手順1で設定した環境情報を定義する

Cloudformation の Parametersセクション部分の文法に則り、samconfig.tomlparameter_overrides から渡ってくる環境情報を定義します。

Parameters:
  ENV: // samconfig.tomlのparameter_overridesで指定した変数名
    Type: String
    Default: "dev"
    AllowedValues: //使用したい環境情報名を定義
      - prod
      - dev

3. Cloudformationテンプレートの Mappingsセクションを作成する

Cloudformation の Parametersセクション部分の文法に則り、環境(≒AWSアカウント)別に個別定義したい固定パラメータを定義します。

Mappings:
  EnvResourceMap: // 任意の名前
    "dev": // Parametersセクションで定義した、AllowedValuesの値
      "SecurityGrouId": xxx // ここに、AWSアカウント別に指定したいパラメータを設定していく
      "Subnet1": xxx
      "Subnet2": xxx
    "prod":
      "SecurityGroupId": yyy
      "Subnet1": yyy
      "Subnet2": yyy

4. 必要に応じて、手順3で設定したマッピング情報を参照する

Cloudformation 組込み関数である Fn::FindInMap 関数を使用して、手順3で設定したMappingsセクションの値を参照します。

構文は、公式ドキュメントをご確認ください。

template.yaml サンプル

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sample-app

  Sample SAM Template for sample-app

Parameters:
  ENV:
    Type: String
    Default: "dev"
    AllowedValues:
      - prod
      - dev

Mappings:
  EnvResourceMap:
    "dev":
      "SecurityGroupId": xxx
      "Subnet1": xxx
      "Subnet2": xxx
    "prod":
      "SecurityGroupId": yyy
      "Subnet1": yyy
      "Subnet2": yyy

Resources:
  ...

Mapping 参照部分

      VpcConfig:
        SecurityGroupIds:
          - !FindInMap [EnvResourceMap, !Ref ENV, SecurityGroupId]
		SubnetIds:
	      - !FindInMap [EnvResourceMap, !Ref ENV, Subnet1]
	      - !FindInMap [EnvResourceMap, !Ref ENV, Subnet2]

以上。

所感

これらの設定により、以下の状況を作り出すことが出来ました。

  • sam deploy オプションをいじるだけで、デプロイしたいAWS環境を変更できる
  • パラメータを追加したい場合は、CloudformationのMappingsセクションをいじるだけ

もしかしたら、他に優れた手法が存在するかもしれませんが、現状はこの設定で満足できそうです。

同じ問題で悩んでいる方の参考になればと思います。

参考文献

Discussion