CloudFormation에서 Fn::ForEach 반복 함수를 사용할 수 있게 되었습니다.

CloudFormation에서 Fn::ForEach 반복 함수를 사용할 수 있게 업데이트 되었으므로 정리해 봤습니다.
2023.09.06

안녕하세요 클래스메소드 김재욱(Kim Jaewook) 입니다. 이번에는 CloudFormation에서 Fn::ForEach 반복 함수를 사용할 수 있게 업데이트 되었으므로 정리해 봤습니다.

업데이트 내용

2023년 7월 26일 CloudFormation에서 Fn::ForEach 반복 함수를 사용할 수 있게 업데이트 되었습니다.

AWS CloudFormation은 Fn::ForEach 내장 함수를 사용하는 반복 기능을 발표했습니다. Fn::ForEach를 통해 최소한의 코드 줄로 템플릿의 일부를 복제할 수 있습니다. Fn::ForEach를 사용하여 템플릿 레이아웃을 단순화하고 동료가 코드를 더 쉽고 빠르게 검토할 수 있도록 할 수 있습니다. Fn::ForEach는 잘못된 속성을 업데이트하거나 템플릿에서 여러 대상 속성 업데이트 누락 등의 인적 오류를 줄이는 데 도움이 됩니다.

업데이트 내용을 살펴보면, Fn::ForEach 함수를 통해서 최소한의 코드로 템플릿을 복제할 수 있으며, 업데이트 누락과 오류를 줄이는 데 도움이 된다고 안내하고 있습니다.

보다 상세한 업데이트 내용은 아래 공식 문서를 참고해 주세요.

Fn::ForEach 업데이트 이전에는?

이번 Fn::ForEach 함수가 업데이트되기 이전에는 반복 처리를 할 수 있는 기능이 없었기 때문에 동일한 리소스를 여러 개 생성하기 위해 기존의 내용을 그대로 붙여 넣는 수작업을 진행해야 했습니다.

이렇게 리소스가 동일한 리소스를 여러 개 생성하게 된다면, CloudFormation 코드도 길어지며, 관리하기도 껄끄러워진다는 단점이 있었습니다.

AWSTemplateFormatVersion: 2010-09-09
Description: Create SNS Topic
Resources:
  Topic1:
    Type: "AWS::SNS::Topic"
    Properties:
      TopicName: test1
  Topic2:
    Type: "AWS::SNS::Topic"
    Properties:
      TopicName: test2
  Topic3:
    Type: "AWS::SNS::Topic"
    Properties:
      TopicName: test3
  Topic4:
    Type: "AWS::SNS::Topic"
    Properties:
      TopicName: test4

실제로 같은 내용의 SNS Topic을 생성할 때, 상기 코드와 같이 동일한 코드를 4번 반복해야 합니다.

여기서 SNS Topic의 정책과 그 외 옵션까지 추가한다면 코드도 길어질 것이며, 불필요한 코드로 인해 코드 관리 또한 힘들어질 것입니다.

이번에는 SNS Topic이 아닌, EC2 인스턴스 3대를 생성한다면 어떻게 될까요?

AWSTemplateFormatVersion: 2010-09-09
Description: Create EC2
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
  TestProdKeyPair:
    Description: EC2 Key Pair
    Type: "AWS::EC2::KeyPair::KeyName"
  TestProdAMI:
    Description: Test-prod EC2 AMI
    Type: String
    Default: ami-xxxxxx
# ------------------------------------------------------------#
#  Create EC2 Instance Test1
# ------------------------------------------------------------#
Resources:
  Test1ProdEC2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref TestProdAMI
      InstanceType: m5.xlarge
      KeyName: !Ref TestProdKeyPair
      DisableApiTermination: true
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 1024
            VolumeType: gp3
      SubnetId: subnet-xxxxxx
      SecurityGroupIds:
        - Fn::ImportValue: !Sub xxxx
  # ------------------------------------------------------------#
  #  Create EC2 Instance Test2
  # ------------------------------------------------------------#
  Test2ProdEC2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref TestProdAMI
      InstanceType: m5.4xlarge
      KeyName: !Ref TestProdKeyPair
      DisableApiTermination: true
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 1024
            VolumeType: gp3
      SubnetId: subnet-xxxxxx
      SecurityGroupIds:
        - Fn::ImportValue: !Sub xxxx
  # ------------------------------------------------------------#
  #  Create EC2 Instance Test3
  # ------------------------------------------------------------#
  Test2ProdEC3:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref TestProdAMI
      InstanceType: c5.2xlarge
      KeyName: !Ref TestProdKeyPair
      DisableApiTermination: true
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 1024
            VolumeType: gp3
      SubnetId: subnet-xxxxxx
      SecurityGroupIds:
        - Fn::ImportValue: !Sub xxxx

상기 코드처럼 3대를 생성했음에도 코드가 확연히 길어지고 있음을 알 수 있습니다.

여기서 EC2 인스턴스가 3대가 아니라 5대 7대 등등 점점 더 늘어난다면, 그만큼 코드도 길어지고 관리하기 힘들어질 것입니다.

이런 문제점을 해결하기 위해서는 Fn::ForEach 함수를 사용해, 코드 낭비를 줄이며, 보다 편하게 리소스들을 관리할 수 있습니다.

Fn::ForEach 사용해 보기

먼저 Fn::ForEach를 사용하기 위해서는「AWS::LanguageExtensions」를 선언할 필요가 있습니다.

AWS::LanguageExtensions의 경우 CloudFormation에 기본적으로 포함되지 않은 내장 함수 및 기타 기능을 사용할 수 있도록 해주는 기능입니다.

AWS::LanguageExtensions에 대한 보다 상세한 내용은 아래 공식 문서를 참고해 주세요.

AWSTemplateFormatVersion: 2010-09-09
Transform: 'AWS::LanguageExtensions'
Parameters:
  SNSName:
    Description: SNS Topic Name
    Type: CommaDelimitedList
Resources:
  'Fn::ForEach::Topics':
    - TopicName
    - !Ref SNSName
    - 'SnsTopic${TopicName}':
        Type: 'AWS::SNS::Topic'
        Properties:
          TopicName: !Ref TopicName

Fn::ForEach 함수를 이용해서 각기 다른 이름의 SNS 토픽을 생성합니다.

스택을 생성할 때, 각 SNS 토픽의 이름을 설정합니다.

SNS 콘솔 화면에서 확인해 보면 문제 없이 지정한 이름으로 SNS 토픽이 생성된 것을 확인할 수 있습니다.

AWSTemplateFormatVersion: 2010-09-09
Transform: 'AWS::LanguageExtensions'
Mappings:
  Instances:
    InstanceType:
      B: m5.4xlarge
      C: c5.2xlarge
    ImageId:
      A: ami-xxxxxxxx
Resources:
  'Fn::ForEach::Instances':
  - Identifier
  - [A, B, C]
  - 'Instance${Identifier}':
      Type: 'AWS::EC2::Instance'
      Properties:
        InstanceType: !FindInMap [Instances, InstanceType, !Ref 'Identifier', {DefaultValue: m5.xlarge}]
        ImageId: !FindInMap [Instances, ImageId, !Ref 'Identifier', {DefaultValue: ami-xxxxxxxx}]
        SubnetId: subnet-xxxxxxxx
Outputs:
  SecondInstanceId:
    Description: Instance Id for InstanceB
    Value: !Ref 'InstanceB'
  SecondPrivateIp:
    Description: Private IP for InstanceB
    Value: !GetAtt [InstanceB, PrivateIp]

다음은 Fn::ForEach 함수로 3개의 EC2 인스턴스를 만드는 코드입니다.

각각 다른 인스턴스 타입으로 EC2 인스턴스가 생성된 것을 확인할 수 있습니다.

OutPut도 문제 없이 출력됩니다.

그 외 예시 코드는 아래 AWS 공식 문서를 참고해 주세요.

본 블로그 게시글을 읽고 궁금한 사항이 있으신 분들은 kis2702@naver.com로 보내주시면 감사하겠습니다.