【CloudFormation】!Refと!Subの「違い」と「使い分け」を解説!

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=prodProjectName=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つを使いこなせば、テンプレートの再利用性や可読性が大きく向上します。

お読みいただきありがとうございました。

スポンサーリンク