AWS CloudFormationを使ってテンプレートを書くとき、頻繁に登場するのが「!Ref(Ref関数)」と「!Sub(Sub関数)」です。
どちらもテンプレート内で「値を動的に扱う」ための関数ですが、それぞれに明確な役割と使いどころがあります。
この記事では、「!Ref(Ref関数)」と「!Sub(Sub関数)」の違い・使い方・使い分けをサンプルコードを用いてわかりやすく解説します。
!Refとは?(Ref関数)
!Refは「参照(Reference)」の略で、テンプレート内で定義したパラメータやリソースを参照するための関数です。つまり、他の場所で定義した値を取得して利用したいときに使います。
主な使い方は以下の2パターンです。
- パラメータの参照
Parametersセクションで定義した値を参照する
- リソースの物理IDの参照
- 作成されたAWSリソースの物理ID(バケット名やインスタンスIDなど)を参照する
パラメータの参照
!Refの最も基本的な使い方は、Parametersセクションで定義した値を参照することです。以下にサンプルコードを示します。
Parameters:
InstanceType:
Description: EC2 instance type
Type: String
Default: t2.micro
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceTypeここで!Ref InstanceTypeは"t2.micro"という値に置き換えられます。つまり、「パラメータの値をそのまま使う」というのが!Refの役割です。
同じことを!Subを使って!Sub "${InstanceType}"と書けますが、単にパラメータを参照するだけなら!Refが最適です。!Subは文字列の中で変数を組み合わせたいときに使います(後ほど解説します)。
リソースの物理IDの参照
!Refはリソースを参照することもできます。リソースの場合は、AWS側でAWSリソースの物理ID(バケット名やインスタンスIDなど)を参照します。
CloudFormationがリソースを作成すると、そのリソースには物理IDが割り当てられます。このIDは、そのリソースを一意に識別するためのものです。
以下に新しく作成されたS3バケットの名前を参照しているサンプルコードを示します。
Resources:
MyS3Bucket:
Type: "AWS::S3::Bucket"
Outputs:
BucketName:
Value: !Ref MyS3Bucketここでは、MyS3Bucketという論理IDでS3バケットを定義しています。!Ref MyS3Bucketは、このバケットの「S3バケット名(物理ID)」を返します。なお、EC2インスタンスの場合は「インスタンスID(物理ID)」を返します。このように、!Refが返す値(物理ID)は、リソースの種類によって異なります。
!Subとは?(Sub関数)
!Subは「Substitute(置換する)」の略で、文字列内に変数を埋め込む(置き換える)ための関数です。
!Subを使うと、${}の中に変数名を書くだけで自動的に値が展開されます。
主な使い方は以下の3パターンです。
- パラメータを文字列に埋め込む
Parametersセクションで定義した値を文字列に埋め込む
- リソースの物理IDを文字列に組み込む
- 作成されたAWSリソースの物理ID(バケット名やインスタンスIDなど)を文字列に埋め込む
- 複数の値を組み合わせて動的な名前を作る
パラメータを文字列に埋め込む
!Sub内では${}でパラメータを直接参照できます。以下にサンプルコードを示します。
Parameters:
EnvName:
Type: String
Default: dev
Resources:
MyS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "${EnvName}-bucket"上記では、${EnvName}がdevに置き換わるため、BucketNameは"dev-bucket"になります。
リソースの物理IDを文字列に組み込む
!Subでは${}の中にリソース名も書けます。これにより、リソースの物理IDを文字列の中で使えます。以下にサンプルコードを示します。
Resources:
MyS3Bucket:
Type: "AWS::S3::Bucket"
Outputs:
Message:
Value: !Sub "The bucket name is ${MyS3Bucket}"この場合、${MyS3Bucket}が実際のバケット名に置き換わります。
複数の値を組み合わせて動的な名前を作る
!Subの最大の特徴は、文字列を柔軟に組み立てられることです。環境名やプロジェクト名などを組み合わせて、動的なリソース名を作れます。以下にサンプルコードを示します。
Parameters:
EnvName:
Type: String
ProjectName:
Type: String
Resources:
MyS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "${EnvName}-${ProjectName}-bucket"例えば、EnvName=prod、ProjectName=appの場合、作成されるバケット名は"prod-app-bucket"になります。
!Refと!Subの「違い」と「使い分け」
「!Ref(Ref関数)」と「!Sub(Sub関数)」の違いを表形式でまとめます。
| 比較項目 | !Ref | !Sub |
|---|---|---|
| 主な用途 | 単純な値の参照 | 動的な文字列の生成 |
| 書き方 | !Ref ParamName | !Sub "文字列 ${Param}" |
| 戻り値 | パラメータ値 or リソースID | 文字列 |
| リソース参照時 | 物理IDを返す | ${}の中で同様に物理IDを展開 |
| 特徴 | シンプルに値を取得 | 変数展開や命名に便利 |
そのため、!Refと!Subは以下のように使い分けます。
- 値をそのまま使いたいとき →
!Ref- 例:パラメータやリソースのIDを単純に参照する場合。
- 値を組み合わせて文字列を作りたいとき →
!Sub- 例:
${EnvName}-${ProjectName}-bucketのように、環境名やプロジェクト名を連結して命名したい場合。
- 例:
本記事のまとめ
この記事では「!Ref(Ref関数)」と「!Sub(Sub関数)」について説明しました。
CloudFormationのテンプレートを記述する上で、!Refと!Subは欠かせない基本関数です。
!Refは「値をそのまま参照」する関数- 値をそのまま使いたいときに使う
!Subは「文字列の中で変数を展開」する関数- 文字列を組み立てたいときに使う
この2つを使いこなせば、テンプレートの再利用性や可読性が大きく向上します。
お読みいただきありがとうございました。