ハンズオン(簡易版): CFnテンプレート入門(EC2::EIPAssociation)

事前作業2.3. CFnリソースファイルの作成 (EC2::Instance タグ名指定(スタック名) Instance0)

手順の目的 [why]

リソース(Instance0)のCloudFormationリソースファイルを作成します。

設定値の指定

設定値の指定

手順に必要な設定値を変数に格納をします。

0. リージョンの指定

リージョンを指定します。

環境変数の設定:

export AWS_DEFAULT_REGION='ap-northeast-1'

1. CloudFormationリソース名

CloudFormationリソース名を指定します。

変数の設定:

TEMPLATE_CFN_RESOURCE_NAME='Instance0'

2. リソースファイル用ディレクトリ

リソースファイル用ディレクトリを指定します。

変数の設定:

DIR_TEMPLATE_CFN_RESOURCE="${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources"

ディレクトリが存在することを確認します。

コマンド:

ls -d ${DIR_TEMPLATE_CFN_RESOURCE}

結果(例:存在する場合):

${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources

存在しない場合は作成します。

コマンド:

mkdir -p ${DIR_TEMPLATE_CFN_RESOURCE}

結果(例):

(出力なし)

3. リソースファイル名

リソースファイル名を指定します。

変数の設定:

FILE_TEMPLATE_CFN_RESOURCE="${DIR_TEMPLATE_CFN_RESOURCE}/${TEMPLATE_CFN_RESOURCE_NAME}.txt" \
  && echo ${FILE_TEMPLATE_CFN_RESOURCE}

結果(例):

${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources/Instance0.txt

4. 起動時に利用するAMIイメージ名

起動時に利用するAMIイメージ名の指定します。

変数の設定:

EC2_INSTANCE_IMAGE_NAME="amzn2-ami-hvm-2.0.20210721.2-x86_64-gp2"

5. サブネットのタグ名

サブネットのタグ名の指定します。

変数の設定:

TEMPLATE_CFN_RESOURCE_NAME_EC2_SUBNET='Subnet0'

6. セキュリティグループ名

セキュリティグループ名の指定します。

変数の設定:

TEMPLATE_CFN_RESOURCE_NAME_EC2_SECURITY_GROUP='SecurityGroup0'

7. EC2インスタンスのインスタンスタイプ

EC2インスタンスのインスタンスタイプの指定します。

変数の設定:

EC2_INSTANCE_TYPE="t2.micro"

8. ユーザデータファイル

ユーザデータファイルの指定します。

変数の設定:

USER_DATA_NAME='handson-cli-cfn-ec2-EIPAssociation-httpd-userdata'

変数の設定:

DIR_USER_DATA="${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation"

変数の設定:

FILE_USER_DATA="${DIR_USER_DATA}/${USER_DATA_NAME}.bash" \
  && echo ${FILE_USER_DATA}

結果(例):

${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/handson-cli-cfn-ec2-EIPAssociation-httpd-userdata.bash

設定値の確認

各変数に正しい設定値が格納されていることを確認しながら保存します。

変数の確認:

cat << END

  # 0. AWS_DEFAULT_REGION:"ap-northeast-1"
       AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}"

  # 1. TEMPLATE_CFN_RESOURCE_NAME:"Instance0"
       TEMPLATE_CFN_RESOURCE_NAME="${TEMPLATE_CFN_RESOURCE_NAME}"
  # 2. DIR_TEMPLATE_CFN_RESOURCE:"${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources"
       DIR_TEMPLATE_CFN_RESOURCE="${DIR_TEMPLATE_CFN_RESOURCE}"
  # 3. FILE_TEMPLATE_CFN_RESOURCE:"${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources/Instance0.txt"
       FILE_TEMPLATE_CFN_RESOURCE="${FILE_TEMPLATE_CFN_RESOURCE}"
  # 4. EC2_INSTANCE_IMAGE_NAME:"amzn2-ami-hvm-2.0.20210721.2-x86_64-gp2"
       EC2_INSTANCE_IMAGE_NAME="${EC2_INSTANCE_IMAGE_NAME}"
  # 5. TEMPLATE_CFN_RESOURCE_NAME_EC2_SUBNET:"Subnet0"
       TEMPLATE_CFN_RESOURCE_NAME_EC2_SUBNET="${TEMPLATE_CFN_RESOURCE_NAME_EC2_SUBNET}"
  # 6. TEMPLATE_CFN_RESOURCE_NAME_EC2_SECURITY_GROUP:"SecurityGroup0"
       TEMPLATE_CFN_RESOURCE_NAME_EC2_SECURITY_GROUP="${TEMPLATE_CFN_RESOURCE_NAME_EC2_SECURITY_GROUP}"
  # 7. EC2_INSTANCE_TYPE:"t2.micro"
       EC2_INSTANCE_TYPE="${EC2_INSTANCE_TYPE}"
  # 8. FILE_USER_DATA:"${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/handson-cli-cfn-ec2-EIPAssociation-httpd-userdata.bash"
       FILE_USER_DATA="${FILE_USER_DATA}"

END

下段の変数が入っていない、もしくは上段と同等の値が入っていない場合は、それぞれの手順番号に戻って変数の設定を行います。

処理の実行

イメージIDを取得します。

コマンド:

EC2_INSTANCE_IMAGE_ID=$( \
  aws ec2 describe-images \
    --filters Name=name,Values="${EC2_INSTANCE_IMAGE_NAME}" \
    --query 'Images[].ImageId' \
    --output text \
) \
  && echo ${EC2_INSTANCE_IMAGE_ID}

結果(例):

ami-09ebacdc178ae23b7

CFnリソースファイルを作成します。

変数の確認:

cat << END

  # FILE_TEMPLATE_CFN_RESOURCE:"${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources/Instance0.txt"
    FILE_TEMPLATE_CFN_RESOURCE="${FILE_TEMPLATE_CFN_RESOURCE}"
  # TEMPLATE_CFN_RESOURCE_NAME:"Instance0"
    TEMPLATE_CFN_RESOURCE_NAME="${TEMPLATE_CFN_RESOURCE_NAME}"
  # EC2_INSTANCE_IMAGE_ID:"ami-09ebacdc178ae23b7"
    EC2_INSTANCE_IMAGE_ID="${EC2_INSTANCE_IMAGE_ID}"
  # EC2_INSTANCE_TYPE:"t2.micro"
    EC2_INSTANCE_TYPE="${EC2_INSTANCE_TYPE}"
  # TEMPLATE_CFN_RESOURCE_NAME_EC2_SUBNET:"Subnet0"
    TEMPLATE_CFN_RESOURCE_NAME_EC2_SUBNET="${TEMPLATE_CFN_RESOURCE_NAME_EC2_SUBNET}"
  # TEMPLATE_CFN_RESOURCE_NAME_EC2_SECURITY_GROUP:"SecurityGroup0"
    TEMPLATE_CFN_RESOURCE_NAME_EC2_SECURITY_GROUP="${TEMPLATE_CFN_RESOURCE_NAME_EC2_SECURITY_GROUP}"

END

コマンド:

cat << EOF > ${FILE_TEMPLATE_CFN_RESOURCE}
  ${TEMPLATE_CFN_RESOURCE_NAME}:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ${EC2_INSTANCE_IMAGE_ID}
      InstanceType: ${EC2_INSTANCE_TYPE}
      SubnetId: !Ref ${TEMPLATE_CFN_RESOURCE_NAME_EC2_SUBNET}
      SecurityGroupIds: 
        - !Ref ${TEMPLATE_CFN_RESOURCE_NAME_EC2_SECURITY_GROUP}
      Tags:
        - Key: Name
          Value: !Ref AWS::StackName
EOF
cat ${FILE_TEMPLATE_CFN_RESOURCE}

結果(例):

Instance0:
  Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-09ebacdc178ae23b7
      InstanceType: t2.micro
      SubnetId: !Ref Subnet0
      SecurityGroupIds:
        - !Ref SecurityGroup0
      Tags:
        - Key: Name
          Value: !Ref AWS::StackName

ユーザーデーターを追記します。

変数の確認:

cat << END

  # FILE_TEMPLATE_CFN_RESOURCE:"${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources/Instance0.txt"
    FILE_TEMPLATE_CFN_RESOURCE="${FILE_TEMPLATE_CFN_RESOURCE}"
  # FILE_USER_DATA:"${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/handson-cli-cfn-ec2-EIPAssociation-httpd-userdata.bash"
    FILE_USER_DATA="${FILE_USER_DATA}"

END

コマンド:

if [ ! $( grep 'UserData:' ${FILE_TEMPLATE_CFN_RESOURCE}) ];then
cat << EOF >> ${FILE_TEMPLATE_CFN_RESOURCE}
      UserData: !Base64 |
EOF
fi

cat ${FILE_USER_DATA} \
  | sed '/^$/d' \
  | sed "s/^/        /" \
  >> ${FILE_TEMPLATE_CFN_RESOURCE}

cat ${FILE_TEMPLATE_CFN_RESOURCE}

結果(例):

Instance0:
  Type: AWS::EC2::Instance
  Properties:
    ImageId: ami-09ebacdc178ae23b7
    InstanceType: t3.micro
    SubnetId: !Ref Subnet0
    SecurityGroupIds:
      - !Ref SecurityGroup0
    Tags:
      - Key: Name
        Value: !Ref AWS::StackName
    UserData: !Base64 |
      #!/bin/bash
      GIT_REPOSITORY_ORIGIN='https://github.com/opelab/jawsug-cli-sample-web.git'
      GIT_REPOSITORY_NAME='jawsug-cli-sample-web'
      yum -y update
      # setup httpd
      yum install -y httpd
      systemctl start httpd.service
      systemctl enable httpd.service
      yum -y install git
      # get contents
      cd /tmp/ \
        && git clone ${GIT_REPOSITORY_ORIGIN}
      # setup contents
      cp /tmp/${GIT_REPOSITORY_NAME}/* /var/www/html/
      #
      # logs agent
      #
      readonly EC2_METADATA_SECOND='900'
      readonly EC2_METADATA_TOKEN=$( \
        curl -s \
          -X PUT "http://169.254.169.254/latest/api/token" \
          -H "X-aws-ec2-metadata-token-ttl-seconds: ${EC2_METADATA_SECOND}" \
      )
      readonly EC2_METADATA_HEADER="X-aws-ec2-metadata-token: ${EC2_METADATA_TOKEN}"
      readonly EC2_REGION_NAME=$( \
        curl -s -H "${EC2_METADATA_HEADER}" \
          http://169.254.169.254/latest/meta-data/placement/availability-zone \
        | sed -e 's/[a-z]*$//' \
      )
      # install cloudwatch agent
      readonly URL_DOWNLOAD_LINK="https://s3.${EC2_REGION_NAME}.amazonaws.com/amazoncloudwatch-agent-${EC2_REGION_NAME}/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm"
      cd /tmp/
      wget ${URL_DOWNLOAD_LINK}
      rpm -U ./amazon-cloudwatch-agent.rpm
      # setup cloudwatch agent
      readonly LOGS_CONF='/opt/aws/amazon-cloudwatch-agent/etc/logs.conf'
      # logs.conf
      cat << EOF > ${LOGS_CONF}
      {
        "agent": {
          "logfile": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log"
        },
        "logs": {
          "logs_collected": {
            "files": {
              "collect_list": [
                {
                  "file_path": "/var/log/httpd/access_log*",
                  "log_group_name": "httpd/access_log",
                  "timezone": "UTC"
                }
              ]
            }
          },
          "log_stream_name": "{instance_id}",
          "force_flush_interval" : 15
        }
      }
      EOF
      # start cloudwatch agent
      /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
        -a fetch-config \
        -m ec2 \
        -c file:${LOGS_CONF} \
        -s

完了確認

本手順の主処理は、以下の完了条件を満たしたときに成功したものとします。

完了条件1: リソースファイル"${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources/Instance0.txt"が存在する。

「リソースファイル"${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources/Instance0.txt"が存在する。」ことを確認します。

コマンド:

ls ${FILE_TEMPLATE_CFN_RESOURCE}

結果(例):

${HOME}/environment/conf-handson-cli-cfn-ec2-EIPAssociation/resources/Instance0.txt

手順の完了