「AWS Hands-on for Beginners AWS 環境のコード管理 AWS CloudFormationで Web システムを構築する」をAWS CLIでやってみる

https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-cfn-2022-reg-event.html?trk=aws_introduction_page

上記、「AWS Hands-on for Beginners AWS 環境のコード管理 AWS CloudFormationで Web システムを構築する」 をAWS CLIでやってみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3297641/b583fe16-b31c-f69a-44b6-1cfa1ca12808.png)
ハンズオンから引用

# 03 開発環境の構築 (CloudShellで実施)
:::note warn
ハンズオンではCloud9から実施するようになっているが、すべてCloudShellから実施することも可
:::
## 変数
```bash:コマンド
# 名前
CLOUD9_ENVIRONMENT_NAME="handson" \
&& echo ${CLOUD9_ENVIRONMENT_NAME}

# 説明
CLOUD9_DSCTRIPTION="handson" \
&& echo ${CLOUD9_DSCTRIPTION}

# インスタンスタイプ
CLOUD9_INSTANCE_TYPE="t2.micro" \
&& echo ${CLOUD9_INSTANCE_TYPE}

# プラットフォーム
CLOUD9_IMAGE_ID="resolve:ssm:/aws/service/cloud9/amis/amazonlinux-2-x86_64" \
&& echo ${CLOUD9_IMAGE_ID}
```
```bash:出力
[cloudshell-user@ip-10-134-14-43 ~]$ # Cloud9
[cloudshell-user@ip-10-134-14-43 ~]$ # 名前
[cloudshell-user@ip-10-134-14-43 ~]$ CLOUD9_ENVIRONMENT_NAME="handson" \
> && echo ${CLOUD9_ENVIRONMENT_NAME}
handson
[cloudshell-user@ip-10-134-14-43 ~]$ 
[cloudshell-user@ip-10-134-14-43 ~]$ # 説明
[cloudshell-user@ip-10-134-14-43 ~]$ CLOUD9_DSCTRIPTION="handson" \
> && echo ${CLOUD9_DSCTRIPTION}
handson
[cloudshell-user@ip-10-134-14-43 ~]$ 
[cloudshell-user@ip-10-134-14-43 ~]$ # インスタンスタイプ
[cloudshell-user@ip-10-134-14-43 ~]$ CLOUD9_INSTANCE_TYPE="t2.micro" \
> && echo ${CLOUD9_INSTANCE_TYPE}
t2.micro
[cloudshell-user@ip-10-134-14-43 ~]$ 
[cloudshell-user@ip-10-134-14-43 ~]$ # プラットフォーム
[cloudshell-user@ip-10-134-14-43 ~]$ CLOUD9_IMAGE_ID="resolve:ssm:/aws/service/cloud9/amis/amazonlinux-2-x86_64" \
> && echo ${CLOUD9_IMAGE_ID}
resolve:ssm:/aws/service/cloud9/amis/amazonlinux-2-x86_64
```
## 環境作成
```bash:コマンド
# Cloud9環境作成
CLOUD9_ENVIRONMENT_ID=$(
    aws cloud9 create-environment-ec2 \
        --name ${CLOUD9_ENVIRONMENT_NAME} \
        --description ${CLOUD9_DSCTRIPTION} \
        --instance-type ${CLOUD9_INSTANCE_TYPE} \
        --image-id ${CLOUD9_IMAGE_ID} \
        --connection-type CONNECT_SSM \
        --automatic-stop-time-minutes 30 \
        --query environmentId \
        --output text
) \
&& echo ${CLOUD9_ENVIRONMENT_ID}
```
```bash:出力
[cloudshell-user@ip-10-134-14-43 ~]$ # Cloud9環境作成
[cloudshell-user@ip-10-134-14-43 ~]$ CLOUD9_ENVIRONMENT_ID=$(
>     aws cloud9 create-environment-ec2 \
>         --name ${CLOUD9_ENVIRONMENT_NAME} \
>         --description ${CLOUD9_DSCTRIPTION} \
>         --instance-type ${CLOUD9_INSTANCE_TYPE} \
>         --image-id ${CLOUD9_IMAGE_ID} \
>         --connection-type CONNECT_SSM \
>         --automatic-stop-time-minutes 30 \
>         --query environmentId \
>         --output text
> ) \
> && echo ${CLOUD9_ENVIRONMENT_ID}
9295554b15a245ac9bd32be3a214dc92
```
# 04 テンプレートの実行方法、VPCの作成 (Cloud9で実施)
## 作業用ディレクトリ作成
```bash:コマンド
mkdir cfn
```
```bash:出力
admin:~/environment $ mkdir cfn
```
## 変数
```bash:コマンド
# スタック名
STACK_NAME="handson-cfn" \
&& echo ${STACK_NAME}

# テンプレートファイル
CFN_TEMPLATE="01_vpc.yml" \
&& echo ${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # スタック名
admin:~/environment $ STACK_NAME="handson-cfn" \
> && echo ${STACK_NAME}
handson-cfn
admin:~/environment $ 
admin:~/environment $ # テンプレートファイル
admin:~/environment $ CFN_TEMPLATE="01_vpc.yml" \
> && echo ${CFN_TEMPLATE}
01_vpc.yml
```
## YAMLファイル作成
```bash:コマンド
cat << "EOF" > cfn/${CFN_TEMPLATE}
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for VPC

Resources:
  CFnVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: handson-cfn

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.0.0/24
      VpcId: !Ref CFnVPC
      AvailabilityZone: !Select [ 0, !GetAZs ]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: PublicSubnet1

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.1.0/24
      VpcId: !Ref CFnVPC
      AvailabilityZone: !Select [ 1, !GetAZs ]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: PublicSubnet2

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.2.0/24
      VpcId: !Ref CFnVPC
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: PrivateSubnet1

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.3.0/24
      VpcId: !Ref CFnVPC
      AvailabilityZone: !Select [ 1, !GetAZs ]
      Tags:
        - Key: Name
          Value: PrivateSubnet2

  CFnVPCIGW:
    Type: AWS::EC2::InternetGateway
    Properties: 
      Tags:
        - Key: Name
          Value: handson-cfn

  CFnVPCIGWAttach:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties: 
      InternetGatewayId: !Ref CFnVPCIGW
      VpcId: !Ref CFnVPC

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CFnVPC
      Tags:
        - Key: Name
          Value: Public Route

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: CFnVPCIGW
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref CFnVPCIGW

  PublicSubnet1Association:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PublicSubnet2Association:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

Outputs:
  VPCID:
    Description: VPC ID
    Value: !Ref CFnVPC
    Export:
      Name: !Sub ${AWS::StackName}-VPCID

  PublicSubnet1:
    Description: PublicSubnet1
    Value: !Ref PublicSubnet1
    Export:
      Name: !Sub ${AWS::StackName}-PublicSubnet1

  PublicSubnet2:
    Description: PublicSubnet2
    Value: !Ref PublicSubnet2
    Export:
      Name: !Sub ${AWS::StackName}-PublicSubnet2

  PrivateSubnet1:
    Description: PrivateSubnet1
    Value: !Ref PrivateSubnet1
    Export:
      Name: !Sub ${AWS::StackName}-PrivateSubnet1

  PrivateSubnet2:
    Description: PrivateSubnet2
    Value: !Ref PrivateSubnet2
    Export:
      Name: !Sub ${AWS::StackName}-PrivateSubnet2
EOF
```
```bash:出力
admin:~/environment $ cat << "EOF" > cfn/${CFN_TEMPLATE}
> AWSTemplateFormatVersion: 2010-09-09
> Description: Hands-on template for VPC
> 
> Resources:
>   CFnVPC:
>     Type: AWS::EC2::VPC
>     Properties:
>       CidrBlock: 10.0.0.0/16
>       InstanceTenancy: default
>       EnableDnsSupport: true
>       EnableDnsHostnames: true
>       Tags:
>         - Key: Name
>           Value: handson-cfn
> 
>   PublicSubnet1:
>     Type: AWS::EC2::Subnet
>     Properties:
>       CidrBlock: 10.0.0.0/24
>       VpcId: !Ref CFnVPC
>       AvailabilityZone: !Select [ 0, !GetAZs ]
>       MapPublicIpOnLaunch: true
>       Tags:
>         - Key: Name
>           Value: PublicSubnet1
> 
>   PublicSubnet2:
>     Type: AWS::EC2::Subnet
>     Properties:
>       CidrBlock: 10.0.1.0/24
>       VpcId: !Ref CFnVPC
>       AvailabilityZone: !Select [ 1, !GetAZs ]
>       MapPublicIpOnLaunch: true
>       Tags:
>         - Key: Name
>           Value: PublicSubnet2
> 
>   PrivateSubnet1:
>     Type: AWS::EC2::Subnet
>     Properties:
>       CidrBlock: 10.0.2.0/24
>       VpcId: !Ref CFnVPC
>       AvailabilityZone: !Select [ 0, !GetAZs ]
>       Tags:
>         - Key: Name
>           Value: PrivateSubnet1
> 
>   PrivateSubnet2:
>     Type: AWS::EC2::Subnet
>     Properties:
>       CidrBlock: 10.0.3.0/24
>       VpcId: !Ref CFnVPC
>       AvailabilityZone: !Select [ 1, !GetAZs ]
>       Tags:
>         - Key: Name
>           Value: PrivateSubnet2
> 
>   CFnVPCIGW:
>     Type: AWS::EC2::InternetGateway
>     Properties: 
>       Tags:
>         - Key: Name
>           Value: handson-cfn
> 
>   CFnVPCIGWAttach:
>     Type: AWS::EC2::VPCGatewayAttachment
>     Properties: 
>       InternetGatewayId: !Ref CFnVPCIGW
>       VpcId: !Ref CFnVPC
> 
>   PublicRouteTable:
>     Type: AWS::EC2::RouteTable
>     Properties:
>       VpcId: !Ref CFnVPC
>       Tags:
>         - Key: Name
>           Value: Public Route
> 
>   PublicRoute:
>     Type: AWS::EC2::Route
>     DependsOn: CFnVPCIGW
>     Properties:
>       RouteTableId: !Ref PublicRouteTable
>       DestinationCidrBlock: 0.0.0.0/0
>       GatewayId: !Ref CFnVPCIGW
> 
>   PublicSubnet1Association:
>     Type: AWS::EC2::SubnetRouteTableAssociation
>     Properties:
>       SubnetId: !Ref PublicSubnet1
>       RouteTableId: !Ref PublicRouteTable
> 
>   PublicSubnet2Association:
>     Type: AWS::EC2::SubnetRouteTableAssociation
>     Properties:
>       SubnetId: !Ref PublicSubnet2
>       RouteTableId: !Ref PublicRouteTable
> 
> Outputs:
>   VPCID:
>     Description: VPC ID
>     Value: !Ref CFnVPC
>     Export:
>       Name: !Sub ${AWS::StackName}-VPCID
> 
>   PublicSubnet1:
>     Description: PublicSubnet1
>     Value: !Ref PublicSubnet1
>     Export:
>       Name: !Sub ${AWS::StackName}-PublicSubnet1
> 
>   PublicSubnet2:
>     Description: PublicSubnet2
>     Value: !Ref PublicSubnet2
>     Export:
>       Name: !Sub ${AWS::StackName}-PublicSubnet2
> 
>   PrivateSubnet1:
>     Description: PrivateSubnet1
>     Value: !Ref PrivateSubnet1
>     Export:
>       Name: !Sub ${AWS::StackName}-PrivateSubnet1
> 
>   PrivateSubnet2:
>     Description: PrivateSubnet2
>     Value: !Ref PrivateSubnet2
>     Export:
>       Name: !Sub ${AWS::StackName}-PrivateSubnet2
> EOF
```
## スタック作成
```bash:コマンド
# create
aws cloudformation create-stack \
    --stack-name ${STACK_NAME} \
    --template-body file://cfn/${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # create
admin:~/environment $ aws cloudformation create-stack \
>     --stack-name ${STACK_NAME} \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5"
}
```
## リソース一覧確認
```bash:コマンド
aws cloudformation describe-stack-resources \
    --stack-name ${STACK_NAME} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stack-resources \
>     --stack-name ${STACK_NAME} \
>     --no-cli-pager
{
    "StackResources": [
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "CFnVPC",
            "PhysicalResourceId": "vpc-00e1f8bcfca58ffdf",
            "ResourceType": "AWS::EC2::VPC",
            "Timestamp": "2024-08-10T12:17:54.152000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "CFnVPCIGW",
            "PhysicalResourceId": "igw-0cdd448e3deff017a",
            "ResourceType": "AWS::EC2::InternetGateway",
            "Timestamp": "2024-08-10T12:17:58.166000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "CFnVPCIGWAttach",
            "PhysicalResourceId": "IGW|vpc-00e1f8bcfca58ffdf",
            "ResourceType": "AWS::EC2::VPCGatewayAttachment",
            "Timestamp": "2024-08-10T12:17:57.375000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PrivateSubnet1",
            "PhysicalResourceId": "subnet-07d92abad18918935",
            "ResourceType": "AWS::EC2::Subnet",
            "Timestamp": "2024-08-10T12:17:59.251000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PrivateSubnet2",
            "PhysicalResourceId": "subnet-0b6ceb531c69a539c",
            "ResourceType": "AWS::EC2::Subnet",
            "Timestamp": "2024-08-10T12:17:59.224000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicRoute",
            "PhysicalResourceId": "rtb-09f7f89c25efc069b|0.0.0.0/0",
            "ResourceType": "AWS::EC2::Route",
            "Timestamp": "2024-08-10T12:18:08.486000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicRouteTable",
            "PhysicalResourceId": "rtb-09f7f89c25efc069b",
            "ResourceType": "AWS::EC2::RouteTable",
            "Timestamp": "2024-08-10T12:18:06.232000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicSubnet1",
            "PhysicalResourceId": "subnet-036055bb9649baeab",
            "ResourceType": "AWS::EC2::Subnet",
            "Timestamp": "2024-08-10T12:17:59.577000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicSubnet1Association",
            "PhysicalResourceId": "rtbassoc-069fad9a7cdfc8159",
            "ResourceType": "AWS::EC2::SubnetRouteTableAssociation",
            "Timestamp": "2024-08-10T12:18:01.753000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicSubnet2",
            "PhysicalResourceId": "subnet-02d1e69375b6cbbb3",
            "ResourceType": "AWS::EC2::Subnet",
            "Timestamp": "2024-08-10T12:17:59.574000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicSubnet2Association",
            "PhysicalResourceId": "rtbassoc-0590898ae9be96824",
            "ResourceType": "AWS::EC2::SubnetRouteTableAssociation",
            "Timestamp": "2024-08-10T12:18:01.759000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
## YAMLファイルの更新 (PublicSubnet1名変更)
```bash:コマンド
cat << "EOF" > cfn/${CFN_TEMPLATE}
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for VPC

Resources:
  CFnVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: handson-cfn

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.0.0/24
      VpcId: !Ref CFnVPC
      AvailabilityZone: !Select [ 0, !GetAZs ]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: PublicSubnet1-update

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.1.0/24
      VpcId: !Ref CFnVPC
      AvailabilityZone: !Select [ 1, !GetAZs ]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: PublicSubnet2

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.2.0/24
      VpcId: !Ref CFnVPC
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
        - Key: Name
          Value: PrivateSubnet1

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.3.0/24
      VpcId: !Ref CFnVPC
      AvailabilityZone: !Select [ 1, !GetAZs ]
      Tags:
        - Key: Name
          Value: PrivateSubnet2

  CFnVPCIGW:
    Type: AWS::EC2::InternetGateway
    Properties: 
      Tags:
        - Key: Name
          Value: handson-cfn

  CFnVPCIGWAttach:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties: 
      InternetGatewayId: !Ref CFnVPCIGW
      VpcId: !Ref CFnVPC

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CFnVPC
      Tags:
        - Key: Name
          Value: Public Route

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: CFnVPCIGW
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref CFnVPCIGW

  PublicSubnet1Association:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PublicSubnet2Association:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

Outputs:
  VPCID:
    Description: VPC ID
    Value: !Ref CFnVPC
    Export:
      Name: !Sub ${AWS::StackName}-VPCID

  PublicSubnet1:
    Description: PublicSubnet1
    Value: !Ref PublicSubnet1
    Export:
      Name: !Sub ${AWS::StackName}-PublicSubnet1

  PublicSubnet2:
    Description: PublicSubnet2
    Value: !Ref PublicSubnet2
    Export:
      Name: !Sub ${AWS::StackName}-PublicSubnet2

  PrivateSubnet1:
    Description: PrivateSubnet1
    Value: !Ref PrivateSubnet1
    Export:
      Name: !Sub ${AWS::StackName}-PrivateSubnet1

  PrivateSubnet2:
    Description: PrivateSubnet2
    Value: !Ref PrivateSubnet2
    Export:
      Name: !Sub ${AWS::StackName}-PrivateSubnet2
EOF
```
```bash:出力
admin:~/environment $ cat << "EOF" > cfn/${CFN_TEMPLATE}
> AWSTemplateFormatVersion: 2010-09-09
> Description: Hands-on template for VPC
> 
> Resources:
>   CFnVPC:
>     Type: AWS::EC2::VPC
>     Properties:
>       CidrBlock: 10.0.0.0/16
>       InstanceTenancy: default
>       EnableDnsSupport: true
>       EnableDnsHostnames: true
>       Tags:
>         - Key: Name
>           Value: handson-cfn
> 
>   PublicSubnet1:
>     Type: AWS::EC2::Subnet
>     Properties:
>       CidrBlock: 10.0.0.0/24
>       VpcId: !Ref CFnVPC
>       AvailabilityZone: !Select [ 0, !GetAZs ]
>       MapPublicIpOnLaunch: true
>       Tags:
>         - Key: Name
>           Value: PublicSubnet1-update
> 
>   PublicSubnet2:
>     Type: AWS::EC2::Subnet
>     Properties:
>       CidrBlock: 10.0.1.0/24
>       VpcId: !Ref CFnVPC
>       AvailabilityZone: !Select [ 1, !GetAZs ]
>       MapPublicIpOnLaunch: true
>       Tags:
>         - Key: Name
>           Value: PublicSubnet2
> 
>   PrivateSubnet1:
>     Type: AWS::EC2::Subnet
>     Properties:
>       CidrBlock: 10.0.2.0/24
>       VpcId: !Ref CFnVPC
>       AvailabilityZone: !Select [ 0, !GetAZs ]
>       Tags:
>         - Key: Name
>           Value: PrivateSubnet1
> 
>   PrivateSubnet2:
>     Type: AWS::EC2::Subnet
>     Properties:
>       CidrBlock: 10.0.3.0/24
>       VpcId: !Ref CFnVPC
>       AvailabilityZone: !Select [ 1, !GetAZs ]
>       Tags:
>         - Key: Name
>           Value: PrivateSubnet2
> 
>   CFnVPCIGW:
>     Type: AWS::EC2::InternetGateway
>     Properties: 
>       Tags:
>         - Key: Name
>           Value: handson-cfn
> 
>   CFnVPCIGWAttach:
>     Type: AWS::EC2::VPCGatewayAttachment
>     Properties: 
>       InternetGatewayId: !Ref CFnVPCIGW
>       VpcId: !Ref CFnVPC
> 
>   PublicRouteTable:
>     Type: AWS::EC2::RouteTable
>     Properties:
>       VpcId: !Ref CFnVPC
>       Tags:
>         - Key: Name
>           Value: Public Route
> 
>   PublicRoute:
>     Type: AWS::EC2::Route
>     DependsOn: CFnVPCIGW
>     Properties:
>       RouteTableId: !Ref PublicRouteTable
>       DestinationCidrBlock: 0.0.0.0/0
>       GatewayId: !Ref CFnVPCIGW
> 
>   PublicSubnet1Association:
>     Type: AWS::EC2::SubnetRouteTableAssociation
>     Properties:
>       SubnetId: !Ref PublicSubnet1
>       RouteTableId: !Ref PublicRouteTable
> 
>   PublicSubnet2Association:
>     Type: AWS::EC2::SubnetRouteTableAssociation
>     Properties:
>       SubnetId: !Ref PublicSubnet2
>       RouteTableId: !Ref PublicRouteTable
> 
> Outputs:
>   VPCID:
>     Description: VPC ID
>     Value: !Ref CFnVPC
>     Export:
>       Name: !Sub ${AWS::StackName}-VPCID
> 
>   PublicSubnet1:
>     Description: PublicSubnet1
>     Value: !Ref PublicSubnet1
>     Export:
>       Name: !Sub ${AWS::StackName}-PublicSubnet1
> 
>   PublicSubnet2:
>     Description: PublicSubnet2
>     Value: !Ref PublicSubnet2
>     Export:
>       Name: !Sub ${AWS::StackName}-PublicSubnet2
> 
>   PrivateSubnet1:
>     Description: PrivateSubnet1
>     Value: !Ref PrivateSubnet1
>     Export:
>       Name: !Sub ${AWS::StackName}-PrivateSubnet1
> 
>   PrivateSubnet2:
>     Description: PrivateSubnet2
>     Value: !Ref PrivateSubnet2
>     Export:
>       Name: !Sub ${AWS::StackName}-PrivateSubnet2
> EOF
```
## スタックファイルの更新
```bash:コマンド
# validate
aws cloudformation validate-template \
    --template-body file://cfn/${CFN_TEMPLATE}

# update
aws cloudformation update-stack \
    --stack-name ${STACK_NAME} \
    --template-body file://cfn/${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # validate
admin:~/environment $ aws cloudformation validate-template \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "Parameters": [],
    "Description": "Hands-on template for VPC"
}
admin:~/environment $ 
admin:~/environment $ # update
admin:~/environment $ aws cloudformation update-stack \
>     --stack-name ${STACK_NAME} \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5"
}
```
## リソース一覧確認
```bash:コマンド
aws cloudformation describe-stack-resources \
    --stack-name ${STACK_NAME} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stack-resources \
>     --stack-name ${STACK_NAME} \
>     --no-cli-pager
{
    "StackResources": [
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "CFnVPC",
            "PhysicalResourceId": "vpc-00e1f8bcfca58ffdf",
            "ResourceType": "AWS::EC2::VPC",
            "Timestamp": "2024-08-10T12:17:54.152000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "CFnVPCIGW",
            "PhysicalResourceId": "igw-0cdd448e3deff017a",
            "ResourceType": "AWS::EC2::InternetGateway",
            "Timestamp": "2024-08-10T12:17:58.166000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "CFnVPCIGWAttach",
            "PhysicalResourceId": "IGW|vpc-00e1f8bcfca58ffdf",
            "ResourceType": "AWS::EC2::VPCGatewayAttachment",
            "Timestamp": "2024-08-10T12:17:57.375000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PrivateSubnet1",
            "PhysicalResourceId": "subnet-07d92abad18918935",
            "ResourceType": "AWS::EC2::Subnet",
            "Timestamp": "2024-08-10T12:17:59.251000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PrivateSubnet2",
            "PhysicalResourceId": "subnet-0b6ceb531c69a539c",
            "ResourceType": "AWS::EC2::Subnet",
            "Timestamp": "2024-08-10T12:17:59.224000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicRoute",
            "PhysicalResourceId": "rtb-09f7f89c25efc069b|0.0.0.0/0",
            "ResourceType": "AWS::EC2::Route",
            "Timestamp": "2024-08-10T12:18:08.486000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicRouteTable",
            "PhysicalResourceId": "rtb-09f7f89c25efc069b",
            "ResourceType": "AWS::EC2::RouteTable",
            "Timestamp": "2024-08-10T12:18:06.232000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicSubnet1",
            "PhysicalResourceId": "subnet-036055bb9649baeab",
            "ResourceType": "AWS::EC2::Subnet",
            "Timestamp": "2024-08-10T12:24:55.276000+00:00",
            "ResourceStatus": "UPDATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicSubnet1Association",
            "PhysicalResourceId": "rtbassoc-069fad9a7cdfc8159",
            "ResourceType": "AWS::EC2::SubnetRouteTableAssociation",
            "Timestamp": "2024-08-10T12:18:01.753000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicSubnet2",
            "PhysicalResourceId": "subnet-02d1e69375b6cbbb3",
            "ResourceType": "AWS::EC2::Subnet",
            "Timestamp": "2024-08-10T12:17:59.574000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "PublicSubnet2Association",
            "PhysicalResourceId": "rtbassoc-0590898ae9be96824",
            "ResourceType": "AWS::EC2::SubnetRouteTableAssociation",
            "Timestamp": "2024-08-10T12:18:01.759000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
## スタック詳細
```bash:コマンド
aws cloudformation describe-stacks \
    --stack-name ${STACK_NAME} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stacks \
>     --stack-name ${STACK_NAME} \
>     --no-cli-pager
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn/88de90d0-5712-11ef-8a6e-065519c9cca5",
            "StackName": "handson-cfn",
            "Description": "Hands-on template for VPC",
            "CreationTime": "2024-08-10T12:17:38.970000+00:00",
            "LastUpdatedTime": "2024-08-10T12:24:41.046000+00:00",
            "RollbackConfiguration": {},
            "StackStatus": "UPDATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Outputs": [
                {
                    "OutputKey": "PrivateSubnet1",
                    "OutputValue": "subnet-07d92abad18918935",
                    "Description": "PrivateSubnet1",
                    "ExportName": "handson-cfn-PrivateSubnet1"
                },
                {
                    "OutputKey": "PrivateSubnet2",
                    "OutputValue": "subnet-0b6ceb531c69a539c",
                    "Description": "PrivateSubnet2",
                    "ExportName": "handson-cfn-PrivateSubnet2"
                },
                {
                    "OutputKey": "VPCID",
                    "OutputValue": "vpc-00e1f8bcfca58ffdf",
                    "Description": "VPC ID",
                    "ExportName": "handson-cfn-VPCID"
                },
                {
                    "OutputKey": "PublicSubnet2",
                    "OutputValue": "subnet-02d1e69375b6cbbb3",
                    "Description": "PublicSubnet2",
                    "ExportName": "handson-cfn-PublicSubnet2"
                },
                {
                    "OutputKey": "PublicSubnet1",
                    "OutputValue": "subnet-036055bb9649baeab",
                    "Description": "PublicSubnet1",
                    "ExportName": "handson-cfn-PublicSubnet1"
                }
            ],
            "Tags": [],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
# 05 EC2の作成 その1 (Cloud9で実施)
## 変数
```bash:コマンド
# スタック名
STACK_NAME_EC2="handson-cfn-ec2" \
&& echo ${STACK_NAME_EC2}

# テンプレートファイル
CFN_TEMPLATE="02_ec2.yml" \
&& echo ${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # スタック名
admin:~/environment $ STACK_NAME_EC2="handson-cfn-ec2" \
> && echo ${STACK_NAME_EC2}
handson-cfn-ec2
admin:~/environment $ 
admin:~/environment $ # テンプレートファイル
admin:~/environment $ CFN_TEMPLATE="02_ec2.yml" \
> && echo ${CFN_TEMPLATE}
02_ec2.yml
```
## YAMLファイル作成
```bash:コマンド
cat << "EOF" > cfn/${CFN_TEMPLATE}
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for EC2

Parameters:
  VPCStack:
    Type: String
    Default: handson-cfn
  EC2AMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
  EC2WebServer01:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref EC2AMI
      InstanceType: t2.micro

Outputs:
  EC2WebServer01:
    Value: !Ref EC2WebServer01
    Export:
      Name: !Sub ${AWS::StackName}-EC2WebServer01
EOF
```
```bash:出力
admin:~/environment $ cat << "EOF" > cfn/${CFN_TEMPLATE}
> AWSTemplateFormatVersion: 2010-09-09
> Description: Hands-on template for EC2
> 
> Parameters:
>   VPCStack:
>     Type: String
>     Default: handson-cfn
>   EC2AMI:
>     Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
>     Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
> 
> Resources:
>   EC2WebServer01:
>     Type: AWS::EC2::Instance
>     Properties:
>       ImageId: !Ref EC2AMI
>       InstanceType: t2.micro
> 
> Outputs:
>   EC2WebServer01:
>     Value: !Ref EC2WebServer01
>     Export:
>       Name: !Sub ${AWS::StackName}-EC2WebServer01
> EOF
```
## スタック作成
```bash:コマンド
# create
aws cloudformation create-stack \
    --stack-name ${STACK_NAME_EC2} \
    --template-body file://cfn/${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # create
admin:~/environment $ aws cloudformation create-stack \
>     --stack-name ${STACK_NAME_EC2} \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5"
}
```
## リソース一覧確認
```bash:コマンド
aws cloudformation describe-stack-resources \
    --stack-name ${STACK_NAME_EC2} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stack-resources \
>     --stack-name ${STACK_NAME_EC2} \
>     --no-cli-pager
{
    "StackResources": [
        {
            "StackName": "handson-cfn-ec2",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "EC2WebServer01",
            "PhysicalResourceId": "i-09901dd8ead627178",
            "ResourceType": "AWS::EC2::Instance",
            "Timestamp": "2024-08-10T13:42:11.274000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
## パラメータ一覧確認
```bash:コマンド
aws cloudformation describe-stacks \
    --stack-name ${STACK_NAME_EC2} \
    --query 'Stacks[0].Parameters'
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stacks \
>     --stack-name ${STACK_NAME_EC2} \
>     --query 'Stacks[0].Parameters'
[
    {
        "ParameterKey": "VPCStack",
        "ParameterValue": "handson-cfn"
    },
    {
        "ParameterKey": "EC2AMI",
        "ParameterValue": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
        "ResolvedValue": "ami-092957e65e64cc357"
    }
]
```
## YAMLファイルの更新 (SubnetId指定追加)
```bash:コマンド
cat << "EOF" > cfn/${CFN_TEMPLATE}
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for EC2

Parameters:
  VPCStack:
    Type: String
    Default: handson-cfn
  EC2AMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
  EC2WebServer01:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref EC2AMI
      InstanceType: t2.micro
      SubnetId:
        Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1

Outputs:
  EC2WebServer01:
    Value: !Ref EC2WebServer01
    Export:
      Name: !Sub ${AWS::StackName}-EC2WebServer01
EOF
```
```bash:出力
admin:~/environment $ cat << "EOF" > cfn/${CFN_TEMPLATE}
> AWSTemplateFormatVersion: 2010-09-09
> Description: Hands-on template for EC2
> 
> Parameters:
>   VPCStack:
>     Type: String
>     Default: handson-cfn
>   EC2AMI:
>     Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
>     Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
> 
> Resources:
>   EC2WebServer01:
>     Type: AWS::EC2::Instance
>     Properties:
>       ImageId: !Ref EC2AMI
>       InstanceType: t2.micro
>       SubnetId:
>         Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
> 
> Outputs:
>   EC2WebServer01:
>     Value: !Ref EC2WebServer01
>     Export:
>       Name: !Sub ${AWS::StackName}-EC2WebServer01
> EOF
```
## YAMLファイルの検証
```bash:コマンド
# validate
aws cloudformation validate-template \
    --template-body file://cfn/${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # validate
admin:~/environment $ aws cloudformation validate-template \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "Parameters": [
        {
            "ParameterKey": "VPCStack",
            "DefaultValue": "handson-cfn",
            "NoEcho": false
        },
        {
            "ParameterKey": "EC2AMI",
            "DefaultValue": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
            "NoEcho": false
        }
    ],
    "Description": "Hands-on template for EC2"
}
```
## YAMLファイルの更新 (UserData追加)
```bash:コマンド
cat << "EOF" > cfn/02_ec2.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for EC2

Parameters:
  VPCStack:
    Type: String
    Default: handson-cfn
  EC2AMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
  EC2WebServer01:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref EC2AMI
      InstanceType: t2.micro
      SubnetId:
        Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
      UserData: !Base64 |
        #! /bin/bash
        yum update -y
        amazon-linux-extras install php7.2 -y
        yum -y install mysql httpd php-mbstring php-xml
        
        wget http://ja.wordpress.org/latest-ja.tar.gz -P /tmp/
        tar zxvf /tmp/latest-ja.tar.gz -C /tmp
        cp -r /tmp/wordpress/* /var/www/html/
        touch /var/www/html/.check_alive
        chown apache:apache -R /var/www/html
        
        systemctl enable httpd.service
        systemctl start httpd.service

Outputs:
  EC2WebServer01:
    Value: !Ref EC2WebServer01
    Export:
      Name: !Sub ${AWS::StackName}-EC2WebServer01
EOF
```
```bash:出力
admin:~/environment $ cat << "EOF" > cfn/02_ec2.yml
> AWSTemplateFormatVersion: 2010-09-09
> Description: Hands-on template for EC2
> 
> Parameters:
>   VPCStack:
>     Type: String
>     Default: handson-cfn
>   EC2AMI:
>     Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
>     Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
> 
> Resources:
>   EC2WebServer01:
>     Type: AWS::EC2::Instance
>     Properties:
>       ImageId: !Ref EC2AMI
>       InstanceType: t2.micro
>       SubnetId:
>         Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
>       UserData: !Base64 |
>         #! /bin/bash
>         yum update -y
>         amazon-linux-extras install php7.2 -y
>         yum -y install mysql httpd php-mbstring php-xml
>         
>         wget http://ja.wordpress.org/latest-ja.tar.gz -P /tmp/
>         tar zxvf /tmp/latest-ja.tar.gz -C /tmp
>         cp -r /tmp/wordpress/* /var/www/html/
>         touch /var/www/html/.check_alive
>         chown apache:apache -R /var/www/html
>         
>         systemctl enable httpd.service
>         systemctl start httpd.service
> 
> Outputs:
>   EC2WebServer01:
>     Value: !Ref EC2WebServer01
>     Export:
>       Name: !Sub ${AWS::StackName}-EC2WebServer01
> EOF
```
## スタックファイルの更新
```bash:コマンド
# validate
aws cloudformation validate-template \
    --template-body file://cfn/${CFN_TEMPLATE}

# update
aws cloudformation update-stack \
    --stack-name ${STACK_NAME_EC2}  \
    --template-body file://cfn/${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # validate
admin:~/environment $ aws cloudformation validate-template \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "Parameters": [
        {
            "ParameterKey": "VPCStack",
            "DefaultValue": "handson-cfn",
            "NoEcho": false
        },
        {
            "ParameterKey": "EC2AMI",
            "DefaultValue": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
            "NoEcho": false
        }
    ],
    "Description": "Hands-on template for EC2"
}
admin:~/environment $ 
admin:~/environment $ # update
admin:~/environment $ aws cloudformation update-stack \
>     --stack-name ${STACK_NAME_EC2}  \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5"
}
```
## リソース一覧確認
```bash:コマンド
aws cloudformation describe-stack-resources \
    --stack-name ${STACK_NAME_EC2} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stack-resources \
>     --stack-name ${STACK_NAME_EC2} \
>     --no-cli-pager
{
    "StackResources": [
        {
            "StackName": "handson-cfn-ec2",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "EC2WebServer01",
            "PhysicalResourceId": "i-0ef1d788ec0c18a5a",
            "ResourceType": "AWS::EC2::Instance",
            "Timestamp": "2024-08-10T13:50:43.161000+00:00",
            "ResourceStatus": "UPDATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
# 06 EC2の作成 その2 (Cloud9で実施)
## YAMLファイルの更新 (セキュリティグループの作成)
```bash:コマンド
cat << "EOF" > cfn/02_ec2.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for EC2

Parameters:
  VPCStack:
    Type: String
    Default: handson-cfn
  EC2AMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
  EC2WebServer01:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref EC2AMI
      InstanceType: t2.micro
      SubnetId:
        Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
      UserData: !Base64 |
        #! /bin/bash
        yum update -y
        amazon-linux-extras install php7.2 -y
        yum -y install mysql httpd php-mbstring php-xml
        
        wget http://ja.wordpress.org/latest-ja.tar.gz -P /tmp/
        tar zxvf /tmp/latest-ja.tar.gz -C /tmp
        cp -r /tmp/wordpress/* /var/www/html/
        touch /var/www/html/.check_alive
        chown apache:apache -R /var/www/html
        
        systemctl enable httpd.service
        systemctl start httpd.service
  EC2SG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: sg for web server
      VpcId:
        Fn::ImportValue: !Sub ${VPCStack}-VPCID
      SecurityGroupIngress: 
        - IpProtocol: tcp
          CidrIp: 10.0.0.0/16
          FromPort: 80
          ToPort: 80

Outputs:
  EC2WebServer01:
    Value: !Ref EC2WebServer01
    Export:
      Name: !Sub ${AWS::StackName}-EC2WebServer01
EOF
```
```bash:出力
admin:~/environment $ cat << "EOF" > cfn/02_ec2.yml
> AWSTemplateFormatVersion: 2010-09-09
> Description: Hands-on template for EC2
> 
> Parameters:
>   VPCStack:
>     Type: String
>     Default: handson-cfn
>   EC2AMI:
>     Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
>     Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
> 
> Resources:
>   EC2WebServer01:
>     Type: AWS::EC2::Instance
>     Properties:
>       ImageId: !Ref EC2AMI
>       InstanceType: t2.micro
>       SubnetId:
>         Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
>       UserData: !Base64 |
>         #! /bin/bash
>         yum update -y
>         amazon-linux-extras install php7.2 -y
>         yum -y install mysql httpd php-mbstring php-xml
>         
>         wget http://ja.wordpress.org/latest-ja.tar.gz -P /tmp/
>         tar zxvf /tmp/latest-ja.tar.gz -C /tmp
>         cp -r /tmp/wordpress/* /var/www/html/
>         touch /var/www/html/.check_alive
>         chown apache:apache -R /var/www/html
>         
>         systemctl enable httpd.service
>         systemctl start httpd.service
>   EC2SG:
>     Type: AWS::EC2::SecurityGroup
>     Properties:
>       GroupDescription: sg for web server
>       VpcId:
>         Fn::ImportValue: !Sub ${VPCStack}-VPCID
>       SecurityGroupIngress: 
>         - IpProtocol: tcp
>           CidrIp: 10.0.0.0/16
>           FromPort: 80
>           ToPort: 80
> 
> Outputs:
>   EC2WebServer01:
>     Value: !Ref EC2WebServer01
>     Export:
>       Name: !Sub ${AWS::StackName}-EC2WebServer01
> EOF
```
## スタックファイルの更新
```bash:コマンド
# validate
aws cloudformation validate-template \
    --template-body file://cfn/${CFN_TEMPLATE}

# update
aws cloudformation update-stack \
    --stack-name ${STACK_NAME_EC2}  \
    --template-body file://cfn/${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # validate
admin:~/environment $ aws cloudformation validate-template \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "Parameters": [
        {
            "ParameterKey": "VPCStack",
            "DefaultValue": "handson-cfn",
            "NoEcho": false
        },
        {
            "ParameterKey": "EC2AMI",
            "DefaultValue": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
            "NoEcho": false
        }
    ],
    "Description": "Hands-on template for EC2"
}
admin:~/environment $ 
admin:~/environment $ # update
admin:~/environment $ aws cloudformation update-stack \
>     --stack-name ${STACK_NAME_EC2}  \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5"
}
```
## リソース一覧確認
```bash:コマンド
aws cloudformation describe-stack-resources \
    --stack-name ${STACK_NAME_EC2} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stack-resources \
>     --stack-name ${STACK_NAME_EC2} \
>     --no-cli-pager
{
    "StackResources": [
        {
            "StackName": "handson-cfn-ec2",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "EC2SG",
            "PhysicalResourceId": "sg-07fb844f584b369c2",
            "ResourceType": "AWS::EC2::SecurityGroup",
            "Timestamp": "2024-08-10T14:36:28.722000+00:00",
            "ResourceStatus": "UPDATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn-ec2",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "EC2WebServer01",
            "PhysicalResourceId": "i-0ef1d788ec0c18a5a",
            "ResourceType": "AWS::EC2::Instance",
            "Timestamp": "2024-08-10T13:50:43.161000+00:00",
            "ResourceStatus": "UPDATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
## YAMLファイルの更新 (EC2にセキュリティグループの適用)
```bash:コマンド
cat << "EOF" > cfn/02_ec2.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for EC2

Parameters:
  VPCStack:
    Type: String
    Default: handson-cfn
  EC2AMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
  EC2WebServer01:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref EC2AMI
      InstanceType: t2.micro
      SubnetId:
        Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
      UserData: !Base64 |
        #! /bin/bash
        yum update -y
        amazon-linux-extras install php7.2 -y
        yum -y install mysql httpd php-mbstring php-xml
        
        wget http://ja.wordpress.org/latest-ja.tar.gz -P /tmp/
        tar zxvf /tmp/latest-ja.tar.gz -C /tmp
        cp -r /tmp/wordpress/* /var/www/html/
        touch /var/www/html/.check_alive
        chown apache:apache -R /var/www/html
        
        systemctl enable httpd.service
        systemctl start httpd.service
      SecurityGroupIds:
        - !Ref EC2SG
  EC2SG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: sg for web server
      VpcId:
        Fn::ImportValue: !Sub ${VPCStack}-VPCID
      SecurityGroupIngress: 
        - IpProtocol: tcp
          CidrIp: 10.0.0.0/16
          FromPort: 80
          ToPort: 80

Outputs:
  EC2WebServer01:
    Value: !Ref EC2WebServer01
    Export:
      Name: !Sub ${AWS::StackName}-EC2WebServer01
EOF
```
```bash:出力
admin:~/environment $ cat << "EOF" > cfn/02_ec2.yml
> AWSTemplateFormatVersion: 2010-09-09
> Description: Hands-on template for EC2
> 
> Parameters:
>   VPCStack:
>     Type: String
>     Default: handson-cfn
>   EC2AMI:
>     Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
>     Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
> 
> Resources:
>   EC2WebServer01:
>     Type: AWS::EC2::Instance
>     Properties:
>       ImageId: !Ref EC2AMI
>       InstanceType: t2.micro
>       SubnetId:
>         Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
>       UserData: !Base64 |
>         #! /bin/bash
>         yum update -y
>         amazon-linux-extras install php7.2 -y
>         yum -y install mysql httpd php-mbstring php-xml
>         
>         wget http://ja.wordpress.org/latest-ja.tar.gz -P /tmp/
>         tar zxvf /tmp/latest-ja.tar.gz -C /tmp
>         cp -r /tmp/wordpress/* /var/www/html/
>         touch /var/www/html/.check_alive
>         chown apache:apache -R /var/www/html
>         
>         systemctl enable httpd.service
>         systemctl start httpd.service
>       SecurityGroupIds:
>         - !Ref EC2SG
>   EC2SG:
>     Type: AWS::EC2::SecurityGroup
>     Properties:
>       GroupDescription: sg for web server
>       VpcId:
>         Fn::ImportValue: !Sub ${VPCStack}-VPCID
>       SecurityGroupIngress: 
>         - IpProtocol: tcp
>           CidrIp: 10.0.0.0/16
>           FromPort: 80
>           ToPort: 80
> 
> Outputs:
>   EC2WebServer01:
>     Value: !Ref EC2WebServer01
>     Export:
>       Name: !Sub ${AWS::StackName}-EC2WebServer01
> EOF
```
## スタックファイルの更新
```bash:コマンド
# validate
aws cloudformation validate-template \
    --template-body file://cfn/${CFN_TEMPLATE}

# update
aws cloudformation update-stack \
    --stack-name ${STACK_NAME_EC2}  \
    --template-body file://cfn/${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # validate
admin:~/environment $ aws cloudformation validate-template \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "Parameters": [
        {
            "ParameterKey": "VPCStack",
            "DefaultValue": "handson-cfn",
            "NoEcho": false
        },
        {
            "ParameterKey": "EC2AMI",
            "DefaultValue": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
            "NoEcho": false
        }
    ],
    "Description": "Hands-on template for EC2"
}
admin:~/environment $ 
admin:~/environment $ # update
admin:~/environment $ aws cloudformation update-stack \
>     --stack-name ${STACK_NAME_EC2}  \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5"
}
```
## リソース一覧確認
```bash:コマンド
aws cloudformation describe-stack-resources \
    --stack-name ${STACK_NAME_EC2} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stack-resources \
>     --stack-name ${STACK_NAME_EC2} \
>     --no-cli-pager
{
    "StackResources": [
        {
            "StackName": "handson-cfn-ec2",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "EC2SG",
            "PhysicalResourceId": "sg-07fb844f584b369c2",
            "ResourceType": "AWS::EC2::SecurityGroup",
            "Timestamp": "2024-08-10T14:36:28.722000+00:00",
            "ResourceStatus": "UPDATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn-ec2",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5",
            "LogicalResourceId": "EC2WebServer01",
            "PhysicalResourceId": "i-0ef1d788ec0c18a5a",
            "ResourceType": "AWS::EC2::Instance",
            "Timestamp": "2024-08-10T14:39:06.476000+00:00",
            "ResourceStatus": "UPDATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
## スタック詳細
```bash:コマンド
aws cloudformation describe-stacks \
    --stack-name ${STACK_NAME_EC2} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stacks \
>     --stack-name ${STACK_NAME_EC2} \
>     --no-cli-pager
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-ec2/42600880-571e-11ef-8a6e-065519c9cca5",
            "StackName": "handson-cfn-ec2",
            "Description": "Hands-on template for EC2",
            "Parameters": [
                {
                    "ParameterKey": "VPCStack",
                    "ParameterValue": "handson-cfn"
                },
                {
                    "ParameterKey": "EC2AMI",
                    "ParameterValue": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
                    "ResolvedValue": "ami-092957e65e64cc357"
                }
            ],
            "CreationTime": "2024-08-10T13:41:34.743000+00:00",
            "LastUpdatedTime": "2024-08-10T14:39:01.241000+00:00",
            "RollbackConfiguration": {},
            "StackStatus": "UPDATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Outputs": [
                {
                    "OutputKey": "EC2WebServer01",
                    "OutputValue": "i-0ef1d788ec0c18a5a",
                    "ExportName": "handson-cfn-ec2-EC2WebServer01"
                }
            ],
            "Tags": [],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
# 07 RDS, ELBの作成、スタックのライフサイクル・分割
## RDSの作成
```bash:コマンド
# スタック名
STACK_NAME_RDS="handson-cfn-rds" \
&& echo ${STACK_NAME_RDS}

# テンプレートファイル
CFN_TEMPLATE="03_rds.yml" \
&& echo ${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # スタック名
admin:~/environment $ STACK_NAME_RDS="handson-cfn-rds" \
> && echo ${STACK_NAME_RDS}
handson-cfn-rds
admin:~/environment $ 
admin:~/environment $ # テンプレートファイル
admin:~/environment $ CFN_TEMPLATE="03_rds.yml" \
> && echo ${CFN_TEMPLATE}
03_rds.yml
```
### YAMLファイル作成
```bash:コマンド
cat << "EOF" > cfn/${CFN_TEMPLATE}
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for RDS

Parameters:
  VPCStack:
    Type: String
    Default: handson-cfn
  DBUser:
    Type: String
    Default: dbmaster
  DBPassword:
    Type: String
    Default: H&ppyHands0n
    NoEcho: true

  
Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Delete
    Properties:
      DBInstanceClass: db.t3.micro
      AllocatedStorage: "10"
      StorageType: gp2
      Engine: MySQL
      MasterUsername: !Ref DBUser
      MasterUserPassword: !Ref DBPassword
      DBName: wordpress
      BackupRetentionPeriod: 0
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !Ref DBSecurityGroup

  DBSubnetGroup: 
    Type: AWS::RDS::DBSubnetGroup
    Properties: 
      DBSubnetGroupDescription: DB Subnet Group for Private Subnet
      SubnetIds: 
        - Fn::ImportValue: !Sub ${VPCStack}-PrivateSubnet1
        - Fn::ImportValue: !Sub ${VPCStack}-PrivateSubnet2

  DBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: !Sub ${AWS::StackName}-MySQL
      VpcId:
        Fn::ImportValue: !Sub ${VPCStack}-VPCID
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          CidrIp: 10.0.0.0/16


Outputs:
  DBEndpoint:
    Value: !GetAtt DBInstance.Endpoint.Address
    Export:
      Name: !Sub ${AWS::StackName}-DBEndpoint
EOF
```
```bash:出力
admin:~/environment $ cat << "EOF" > cfn/${CFN_TEMPLATE}
> AWSTemplateFormatVersion: 2010-09-09
> Description: Hands-on template for RDS
> 
> Parameters:
>   VPCStack:
>     Type: String
>     Default: handson-cfn
>   DBUser:
>     Type: String
>     Default: dbmaster
>   DBPassword:
>     Type: String
>     Default: H&ppyHands0n
>     NoEcho: true
> 
>   
> Resources:
>   DBInstance:
>     Type: AWS::RDS::DBInstance
>     DeletionPolicy: Delete
>     Properties:
>       DBInstanceClass: db.t3.micro
>       AllocatedStorage: "10"
>       StorageType: gp2
>       Engine: MySQL
>       MasterUsername: !Ref DBUser
>       MasterUserPassword: !Ref DBPassword
>       DBName: wordpress
>       BackupRetentionPeriod: 0
>       DBSubnetGroupName: !Ref DBSubnetGroup
>       VPCSecurityGroups:
>         - !Ref DBSecurityGroup
> 
>   DBSubnetGroup: 
>     Type: AWS::RDS::DBSubnetGroup
>     Properties: 
>       DBSubnetGroupDescription: DB Subnet Group for Private Subnet
>       SubnetIds: 
>         - Fn::ImportValue: !Sub ${VPCStack}-PrivateSubnet1
>         - Fn::ImportValue: !Sub ${VPCStack}-PrivateSubnet2
> 
>   DBSecurityGroup:
>     Type: AWS::EC2::SecurityGroup
>     Properties: 
>       GroupDescription: !Sub ${AWS::StackName}-MySQL
>       VpcId:
>         Fn::ImportValue: !Sub ${VPCStack}-VPCID
>       SecurityGroupIngress:
>         - IpProtocol: tcp
>           FromPort: 3306
>           ToPort: 3306
>           CidrIp: 10.0.0.0/16
> 
> 
> Outputs:
>   DBEndpoint:
>     Value: !GetAtt DBInstance.Endpoint.Address
>     Export:
>       Name: !Sub ${AWS::StackName}-DBEndpoint
> EOF
```
### スタック作成
```bash:コマンド
# create
aws cloudformation create-stack \
    --stack-name ${STACK_NAME_RDS} \
    --template-body file://cfn/${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # create
admin:~/environment $ aws cloudformation create-stack \
>     --stack-name ${STACK_NAME_RDS} \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-rds/024ef7a0-5729-11ef-bec7-0663b114b127"
}
```
### リソース一覧確認
```bash:コマンド
aws cloudformation describe-stack-resources \
    --stack-name ${STACK_NAME_RDS} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stack-resources \
>     --stack-name ${STACK_NAME_RDS} \
>     --no-cli-pager
{
    "StackResources": [
        {
            "StackName": "handson-cfn-rds",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-rds/024ef7a0-5729-11ef-bec7-0663b114b127",
            "LogicalResourceId": "DBInstance",
            "PhysicalResourceId": "handson-cfn-rds-dbinstance-gkxorqw5feoe",
            "ResourceType": "AWS::RDS::DBInstance",
            "Timestamp": "2024-08-10T15:01:43.837000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn-rds",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-rds/024ef7a0-5729-11ef-bec7-0663b114b127",
            "LogicalResourceId": "DBSecurityGroup",
            "PhysicalResourceId": "sg-0c44fd4ce31a23436",
            "ResourceType": "AWS::EC2::SecurityGroup",
            "Timestamp": "2024-08-10T14:58:37.822000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn-rds",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-rds/024ef7a0-5729-11ef-bec7-0663b114b127",
            "LogicalResourceId": "DBSubnetGroup",
            "PhysicalResourceId": "handson-cfn-rds-dbsubnetgroup-om1dh8gcn15d",
            "ResourceType": "AWS::RDS::DBSubnetGroup",
            "Timestamp": "2024-08-10T14:58:36.276000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
### スタック詳細
```bash:コマンド
aws cloudformation describe-stacks \
    --stack-name ${STACK_NAME_RDS} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stacks \
>     --stack-name ${STACK_NAME_RDS} \
>     --no-cli-pager
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-rds/024ef7a0-5729-11ef-bec7-0663b114b127",
            "StackName": "handson-cfn-rds",
            "Description": "Hands-on template for RDS",
            "Parameters": [
                {
                    "ParameterKey": "DBPassword",
                    "ParameterValue": "****"
                },
                {
                    "ParameterKey": "DBUser",
                    "ParameterValue": "dbmaster"
                },
                {
                    "ParameterKey": "VPCStack",
                    "ParameterValue": "handson-cfn"
                }
            ],
            "CreationTime": "2024-08-10T14:58:31.641000+00:00",
            "RollbackConfiguration": {},
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Outputs": [
                {
                    "OutputKey": "DBEndpoint",
                    "OutputValue": "handson-cfn-rds-dbinstance-gkxorqw5feoe.clacqicsiqrt.ap-northeast-1.rds.amazonaws.com",
                    "ExportName": "handson-cfn-rds-DBEndpoint"
                }
            ],
            "Tags": [],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
## ELBの作成
### 変数
```bash:コマンド
# スタック名
STACK_NAME_ELB="handson-cfn-elb" \
&& echo ${STACK_NAME_ELB}

# テンプレートファイル
CFN_TEMPLATE="04_elb.yml" \
&& echo ${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # スタック名
admin:~/environment $ STACK_NAME_ELB="handson-cfn-elb" \
> && echo ${STACK_NAME_ELB}
handson-cfn-elb
admin:~/environment $ 
admin:~/environment $ # テンプレートファイル
admin:~/environment $ CFN_TEMPLATE="04_elb.yml" \
> && echo ${CFN_TEMPLATE}
04_elb.yml
```
### YAMLファイル作成
```bash:コマンド
cat << "EOF" > cfn/${CFN_TEMPLATE}
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for ALB

Parameters:
  VPCStack:
    Type: String
    Default: handson-cfn
  EC2Stack:
    Type: String
    Default: handson-cfn-ec2

Resources:
  FrontLB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Ref AWS::StackName
      Subnets:
        - Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
        - Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet2
      SecurityGroups: 
        - !Ref SecurityGroupLB

  FrontLBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref FrontLB
      Port: 80
      Protocol: HTTP 
      DefaultActions: 
        - Type: forward
          TargetGroupArn: !Ref FrontLBTargetGroup

  FrontLBTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${AWS::StackName}-tg
      VpcId:
        Fn::ImportValue: !Sub ${VPCStack}-VPCID
      Port: 80
      Protocol: HTTP
      HealthCheckPath: /.check_alive
      Targets:
        - Id:
            Fn::ImportValue: !Sub ${EC2Stack}-EC2WebServer01

  SecurityGroupLB:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: !Ref AWS::StackName
      VpcId:
        Fn::ImportValue: !Sub ${VPCStack}-VPCID
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0

Outputs:
  FrontLBEndpoint:
    Value: !GetAtt FrontLB.DNSName
    Export:
      Name: !Sub ${AWS::StackName}-Endpoint
EOF
```
```bash:出力
admin:~/environment $ cat << "EOF" > cfn/${CFN_TEMPLATE}
> AWSTemplateFormatVersion: 2010-09-09
> Description: Hands-on template for ALB
> 
> Parameters:
>   VPCStack:
>     Type: String
>     Default: handson-cfn
>   EC2Stack:
>     Type: String
>     Default: handson-cfn-ec2
> 
> Resources:
>   FrontLB:
>     Type: AWS::ElasticLoadBalancingV2::LoadBalancer
>     Properties:
>       Name: !Ref AWS::StackName
>       Subnets:
>         - Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
>         - Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet2
>       SecurityGroups: 
>         - !Ref SecurityGroupLB
> 
>   FrontLBListener:
>     Type: AWS::ElasticLoadBalancingV2::Listener
>     Properties:
>       LoadBalancerArn: !Ref FrontLB
>       Port: 80
>       Protocol: HTTP 
>       DefaultActions: 
>         - Type: forward
>           TargetGroupArn: !Ref FrontLBTargetGroup
> 
>   FrontLBTargetGroup:
>     Type: AWS::ElasticLoadBalancingV2::TargetGroup
>     Properties:
>       Name: !Sub ${AWS::StackName}-tg
>       VpcId:
>         Fn::ImportValue: !Sub ${VPCStack}-VPCID
>       Port: 80
>       Protocol: HTTP
>       HealthCheckPath: /.check_alive
>       Targets:
>         - Id:
>             Fn::ImportValue: !Sub ${EC2Stack}-EC2WebServer01
> 
>   SecurityGroupLB:
>     Type: AWS::EC2::SecurityGroup
>     Properties: 
>       GroupDescription: !Ref AWS::StackName
>       VpcId:
>         Fn::ImportValue: !Sub ${VPCStack}-VPCID
>       SecurityGroupIngress:
>         - IpProtocol: tcp
>           FromPort: 80
>           ToPort: 80
>           CidrIp: 0.0.0.0/0
> 
> Outputs:
>   FrontLBEndpoint:
>     Value: !GetAtt FrontLB.DNSName
>     Export:
>       Name: !Sub ${AWS::StackName}-Endpoint
> EOF
```
### スタック作成
```bash:コマンド
# create
aws cloudformation create-stack \
    --stack-name ${STACK_NAME_ELB} \
    --template-body file://cfn/${CFN_TEMPLATE}
```
```bash:出力
admin:~/environment $ # create
admin:~/environment $ aws cloudformation create-stack \
>     --stack-name ${STACK_NAME_ELB} \
>     --template-body file://cfn/${CFN_TEMPLATE}
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-elb/f06066e0-5729-11ef-a599-0e54d4b8961d"
}
```
### リソース一覧確認
```bash:コマンド
aws cloudformation describe-stack-resources \
    --stack-name ${STACK_NAME_ELB} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stack-resources \
>     --stack-name ${STACK_NAME_ELB} \
>     --no-cli-pager
{
    "StackResources": [
        {
            "StackName": "handson-cfn-elb",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-elb/f06066e0-5729-11ef-a599-0e54d4b8961d",
            "LogicalResourceId": "FrontLB",
            "PhysicalResourceId": "arn:aws:elasticloadbalancing:ap-northeast-1:999999999999:loadbalancer/app/handson-cfn-elb/b5dbb13c88778e0c",
            "ResourceType": "AWS::ElasticLoadBalancingV2::LoadBalancer",
            "Timestamp": "2024-08-10T15:08:23.641000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn-elb",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-elb/f06066e0-5729-11ef-a599-0e54d4b8961d",
            "LogicalResourceId": "FrontLBListener",
            "PhysicalResourceId": "arn:aws:elasticloadbalancing:ap-northeast-1:999999999999:listener/app/handson-cfn-elb/b5dbb13c88778e0c/67f0b6991e9025bb",
            "ResourceType": "AWS::ElasticLoadBalancingV2::Listener",
            "Timestamp": "2024-08-10T15:08:25.723000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn-elb",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-elb/f06066e0-5729-11ef-a599-0e54d4b8961d",
            "LogicalResourceId": "FrontLBTargetGroup",
            "PhysicalResourceId": "arn:aws:elasticloadbalancing:ap-northeast-1:999999999999:targetgroup/handson-cfn-elb-tg/6a8a2524885a1675",
            "ResourceType": "AWS::ElasticLoadBalancingV2::TargetGroup",
            "Timestamp": "2024-08-10T15:05:30.528000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackName": "handson-cfn-elb",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-elb/f06066e0-5729-11ef-a599-0e54d4b8961d",
            "LogicalResourceId": "SecurityGroupLB",
            "PhysicalResourceId": "sg-0fa024cf6ba742651",
            "ResourceType": "AWS::EC2::SecurityGroup",
            "Timestamp": "2024-08-10T15:05:17.290000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
### スタック詳細
```bash:コマンド
aws cloudformation describe-stacks \
    --stack-name ${STACK_NAME_ELB} \
    --no-cli-pager
```
```bash:出力
admin:~/environment $ aws cloudformation describe-stacks \
>     --stack-name ${STACK_NAME_ELB} \
>     --no-cli-pager
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:999999999999:stack/handson-cfn-elb/f06066e0-5729-11ef-a599-0e54d4b8961d",
            "StackName": "handson-cfn-elb",
            "Description": "Hands-on template for ALB",
            "Parameters": [
                {
                    "ParameterKey": "EC2Stack",
                    "ParameterValue": "handson-cfn-ec2"
                },
                {
                    "ParameterKey": "VPCStack",
                    "ParameterValue": "handson-cfn"
                }
            ],
            "CreationTime": "2024-08-10T15:05:11.050000+00:00",
            "RollbackConfiguration": {},
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Outputs": [
                {
                    "OutputKey": "FrontLBEndpoint",
                    "OutputValue": "handson-cfn-elb-1292321126.ap-northeast-1.elb.amazonaws.com",
                    "ExportName": "handson-cfn-elb-Endpoint"
                }
            ],
            "Tags": [],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
```
# 08 まとめ 、削除
## CloudFormationスタック削除 (Cloud9で実施)
```bash:コマンド
# handson-cfn-elb
aws cloudformation delete-stack \
    --stack-name ${STACK_NAME_ELB}

# handson-cfn-rds
aws cloudformation delete-stack \
    --stack-name ${STACK_NAME_RDS}

# handson-cfn-ec2
aws cloudformation delete-stack \
    --stack-name ${STACK_NAME_EC2}

# handson-cfn
aws cloudformation delete-stack \
    --stack-name ${STACK_NAME}
```
```bash:出力
admin:~/environment $ # handson-cfn-elb
admin:~/environment $ aws cloudformation delete-stack \
>   --stack-name ${STACK_NAME_ELB}
admin:~/environment $ 
admin:~/environment $ # handson-cfn-rds
admin:~/environment $ aws cloudformation delete-stack \
>     --stack-name ${STACK_NAME_RDS}
admin:~/environment $ 
admin:~/environment $ # handson-cfn-ec2
admin:~/environment $ aws cloudformation delete-stack \
>     --stack-name ${STACK_NAME_EC2}
admin:~/environment $ 
admin:~/environment $ # handson-cfn
admin:~/environment $ aws cloudformation delete-stack \
>     --stack-name ${STACK_NAME}
```
## Cloud9 環境削除 (CloudShellで実施)
```bash:コマンド
aws cloud9 delete-environment \
    --environment-id ${CLOUD9_ENVIRONMENT_ID}
```
```bash:出力
[cloudshell-user@ip-10-130-46-148 ~]$ aws cloud9 delete-environment \
>     --environment-id ${CLOUD9_ENVIRONMENT_ID}
```