Help us understand the problem. What is going on with this article?

[JAWS-UG CLI] ECS #1 ECSクラスタとECSコンテナインスタンスの構築

More than 5 years have passed since last update.

前提条件

ECSへの権限

  • ECSに対してフル権限があること。

EC2への権限

  • EC2に対してフル権限があること。

デフォルトVPCの存在

  • デフォルトVPCが存在すること。
コマンド
VPC_ID=` \
        aws ec2 describe-vpcs \
          --filters Name=isDefault,Values=true \
          --query 'Vpcs[].VpcId' \
          --output text \
` \
        && echo ${VPC_ID}
結果(例)
      vpc-xxxxxxxx

AWS CLIのバージョン

  • 以下のバージョンで動作確認済

    • AWS CLI 1.7.36
コマンド
aws --version
結果(例)
aws-cli/1.7.36 Python/2.7.5 Darwin/13.4.0

0. 準備

0.1. リージョンの決定

変数の設定
export AWS_DEFAULT_REGION='ap-northeast-1'

0.2. 変数の確認

変数の確認
aws configure list
結果(例)
            Name                    Value             Type    Location
            ----                    -----             ----    --------
         profile  ec2ecs_full-prjZ-mbp13               env    AWS_DEFAULT_PROFILE
      access_key     ****************LOAQ shared-credentials-file
      secret_key     ****************I1O1 shared-credentials-file
          region           ap-northeast-1              env    AWS_DEFAULT_REGION

0.3. 稼動インスタンスを確認

同一リージョンでインスタンスが起動していないことを確認します。

コマンド
aws ec2 describe-instances \
        --filters Name=instance-state-name,Values=running
結果
      {
          "Reservations": []
      }

0.4. IAMインスタンスプロファイルの決定

コマンド
aws iam list-instance-profiles \
  --query 'InstanceProfiles[].InstanceProfileName'

'ecsInstanceRole' が存在しない場合は、 http://qiita.com/tcsh/items/8daed4cf04d5bc56e2a7 を実施してください。

変数の設定
IAM_INSTANCE_PROFILE_NAME='ecsInstanceRole'
コマンド
aws iam get-instance-profile \
        --instance-profile-name ${IAM_INSTANCE_PROFILE_NAME}
結果
{
    "InstanceProfile": {
        "InstanceProfileId": "AIPAXXXXXXXXXXXXXXXXX", 
        "Roles": [
            {
                "AssumeRolePolicyDocument": {
                    "Version": "2008-10-17", 
                    "Statement": [
                        {
                            "Action": "sts:AssumeRole", 
                            "Principal": {
                                "Service": "ec2.amazonaws.com"
                            }, 
                            "Effect": "Allow", 
                            "Sid": ""
                        }
                    ]
                }, 
                "RoleId": "AROAXXXXXXXXXXXXXXXXX", 
                "CreateDate": "2015-07-05T01:23:45Z", 
                "RoleName": "ecsInstanceRole", 
                "Path": "/", 
                "Arn": "arn:aws:iam::XXXXXXXXXXXX:role/ecsInstanceRole"
            }
        ], 
        "CreateDate": "2015-07-05T01:23:45Z", 
        "InstanceProfileName": "ecsInstanceRole", 
        "Path": "/", 
        "Arn": "arn:aws:iam::XXXXXXXXXXXX:instance-profile/ecsInstanceRole"
    }
}

0.5. セキュリティグループの確認

まず、セキュリティグループの一覧を確認します。

コマンド
aws ec2 describe-security-groups \
        --query 'SecurityGroups[].GroupName'

'ec2-http-https-ssh-global-inbound'が存在しない場合は、 http://qiita.com/tcsh/items/1d6a499b03b776355ee2 を実施してください。

利用するセキュリティグループ名を指定します。

変数の設定
VPC_SG_NAME='ec2-http-https-ssh-global-inbound'
コマンド
VPC_SG_ID=` \
        aws ec2 describe-security-groups \
          --filter Name=group-name,Values=${VPC_SG_NAME} \
          --query 'SecurityGroups[].GroupId' \
          --output text \
` \
        && echo ${VPC_SG_ID}
結果(例)
sg-xxxxxxxx
変数の設定
ARRAY_VPC_SG_ID="${VPC_SG_ID} ${ARRAY_VPC_SG_ID}" \
        && echo ${ARRAY_VPC_SG_ID}

0.6. キーペアの確認

まず、キーペアの一覧を確認します。

コマンド
aws ec2 describe-key-pairs \
        --query 'KeyPairs[].KeyName'

キーペアが存在しない場合は、 http://qiita.com/tcsh/items/59303d9506ca7d13f744 を実施してください。

利用するキーペア名を指定します。

変数の設定
EC2_KEY_NAME=<キーペア名>

利用するキーペアの秘密鍵ファイルを指定します。

変数の設定
FILE_SSH_KEY=<秘密鍵ファイル>

1. 事前作業

1.1. インスタンスタイプの決定

変数の設定
EC2_INSTANCE_TYPE='t2.micro'

1.2. イメージIDの決定

ECSに最適化されたAMIを選択します。

変数の設定
AMZLINUX_VERSION='2015.03.d'
EC2_IMAGE_NAME="amzn-ami-${AMZLINUX_VERSION}-amazon-ecs-optimized"
コマンド
EC2_IMAGE_ID=` \
        aws ec2 describe-images \
          --filters Name=name,Values="${EC2_IMAGE_NAME}" \
          --query 'Images[].ImageId' --output text \
` \
        && echo ${EC2_IMAGE_ID}
結果(例)
      ami-XXXXXXXX

1.3. クラスタ名の決定

変数の設定
ECS_CLUSTER_NAME='handson-cluster'

同名のクラスタが存在しないことを確認します。

コマンド
aws ecs describe-clusters \
  --clusters ${ECS_CLUSTER_NAME}
結果(例)
      {
        "clusters": [],
        "failures": [
          {
              "reason": "MISSING",
              "arn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/handson-cluster"
          }
        ]
      }

1.4. User Dataの作成

変数の設定
FILE_EC2_USERDATA="ecs-userdata-${ECS_CLUSTER_NAME}.bash"
変数の確認
cat << ETX

        ECS_CLUSTER_NAME:  ${ECS_CLUSTER_NAME}
        FILE_EC2_USERDATA: ${FILE_EC2_USERDATA}

ETX
コマンド
cat << EOF > ${FILE_EC2_USERDATA}
#!/bin/bash
echo ECS_CLUSTER=${ECS_CLUSTER_NAME} > /etc/ecs/ecs.config
EOF

cat ${FILE_EC2_USERDATA}

2. クラスタの作成

2.1. クラスタの作成

変数の確認
cat << ETX

        ECS_CLUSTER_NAME: ${ECS_CLUSTER_NAME}

ETX
コマンド
aws ecs create-cluster \
        --cluster-name ${ECS_CLUSTER_NAME}
結果(例)
      {
        "cluster": {
          "status": "ACTIVE",
          "clusterName": "handson-cluster",
          "registeredContainerInstancesCount": 0,
          "pendingTasksCount": 0,
          "runningTasksCount": 0,
          "activeServicesCount": 0,
          "clusterArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/handson-cluster"
        }
      }

2.2. クラスタの確認

コマンド
aws ecs describe-clusters \
        --clusters ${ECS_CLUSTER_NAME}
結果(例)
      {
        "clusters": [
          {
              "status": "ACTIVE",
              "clusterName": "handson-cluster",
              "registeredContainerInstancesCount": 0,
              "pendingTasksCount": 0,
              "runningTasksCount": 0,
              "activeServicesCount": 0,
              "clusterArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/handson-cluster"
          }
        ],
        "failures": []
      }

3. インスタンス起動

3.1. インスタンス起動

変数の確認
cat << ETX

        EC2_IMAGE_ID:      ${EC2_IMAGE_ID}
        EC2_INSTANCE_TYPE: ${EC2_INSTANCE_TYPE}
        ARRAY_VPC_SG_ID:   ${ARRAY_VPC_SG_ID}
        EC2_KEY_NAME:      ${EC2_KEY_NAME}
        FILE_EC2_USERDATA: ${FILE_EC2_USERDATA}
        IAM_INSTANCE_PROFILE_NAME: ${IAM_INSTANCE_PROFILE_NAME}

ETX
コマンド
aws ec2 run-instances \
        --image-id ${EC2_IMAGE_ID} \
        --instance-type ${EC2_INSTANCE_TYPE} \
        --security-group-ids ${ARRAY_VPC_SG_ID} \
        --key-name ${EC2_KEY_NAME} \
        --associate-public-ip-address \
        --user-data file://${FILE_EC2_USERDATA} \
        --iam-instance-profile Name=${IAM_INSTANCE_PROFILE_NAME}
結果(例)
      {
        "OwnerId": "XXXXXXXXXXXX",
        "ReservationId": "r-xxxxxxxx",
        "Groups": [],
        "Instances": [
          {
              "Monitoring": {
                  "State": "disabled"
              },
              "PublicDnsName": "",
              "RootDeviceType": "ebs",
              "State": {
                  "Code": 0,
                  "Name": "pending"
              },
              "EbsOptimized": false,
              "LaunchTime": "2015-07-05T01:23:45.678",
              "PrivateIpAddress": "172.xxx.xxx.xxx",
              "ProductCodes": [],
              "VpcId": "vpc-xxxxxxxx",
              "StateTransitionReason": "",
              "InstanceId": "i-xxxxxxxx",
              "ImageId": "ami-xxxxxxxx",
              "PrivateDnsName": "ip-172-xxx-xxx-xxx.ap-northeast-1.compute.internal",
              "KeyName": "prj08-ap-northeast-1-ec2",
              "SecurityGroups": [
                  {
                      "GroupName": "ec2-http-https-ssh-global-inbound",
                      "GroupId": "sg-xxxxxxxx"
                  }
              ],
              "ClientToken": "",
              "SubnetId": "subnet-xxxxxxxx",
              "InstanceType": "t2.micro",
              "NetworkInterfaces": [
                  {
                      "Status": "in-use",
                      "MacAddress": "xx:xx:xx:xx:xx:xx",
                      "SourceDestCheck": true,
                      "VpcId": "vpc-xxxxxxxx",
                      "Description": "",
                      "NetworkInterfaceId": "eni-xxxxxxxx",
                      "PrivateIpAddresses": [
                          {
                              "PrivateDnsName": "ip-172-xxx-xxx-xxx.ap-northeast-1.compute.internal",
                              "Primary": true,
                              "PrivateIpAddress": "172.xxx.xxx.xxx"
                          }
                      ],
                      "PrivateDnsName": "ip-172-xxx-xxx-xxx.ap-northeast-1.compute.internal",
                      "Attachment": {
                          "Status": "attaching",
                          "DeviceIndex": 0,
                          "DeleteOnTermination": true,
                          "AttachmentId": "eni-attach-xxxxxxxx",
                          "AttachTime": "2015-07-05T01:23:45.678Z"
                      },
                      "Groups": [
                          {
                              "GroupName": "ec2-http-https-ssh-global-inbound",
                              "GroupId": "sg-xxxxxxxx"
                          }
                      ],
                      "SubnetId": "subnet-xxxxxxxx",
                      "OwnerId": "XXXXXXXXXXXX",
                      "PrivateIpAddress": "172.xxx.xxx.xxx"
                  }
              ],
              "SourceDestCheck": true,
              "Placement": {
                  "Tenancy": "handson-cluster",
                  "GroupName": "",
                  "AvailabilityZone": "ap-northeast-1a"
              },
              "Hypervisor": "xen",
              "BlockDeviceMappings": [],
              "Architecture": "x86_64",
              "StateReason": {
                  "Message": "pending",
                  "Code": "pending"
              },
              "IamInstanceProfile": {
                  "Id": "AIPAXXXXXXXXXXXXXXXXX",
                  "Arn": "arn:aws:iam::XXXXXXXXXXXX:instance-profile/ecsInstanceRole"
              },
              "RootDeviceName": "/dev/xvda",
              "VirtualizationType": "hvm",
              "AmiLaunchIndex": 0
          }
        ]
      }

3.2. インスタンスIDの取得

起動中のインスタンスからインスタンスIDを取得します。

起動中の場合

コマンド(起動中の場合)
EC2_INSTANCE_ID=` \
        aws ec2 describe-instances \
          --filters Name=instance-state-name,Values=pending \
          --query 'Reservations[].Instances[].InstanceId' \
          --output text \
` \
        && echo ${EC2_INSTANCE_ID}
結果(例)
      i-xxxxxxxx

起動完了後の場合

コマンド(起動完了後の場合)
ARRAY_EC2_INSTANCE_ID=` \
        aws ec2 describe-instances \
          --filters Name=instance-state-name,Values=running \
          --query 'Reservations[].Instances[].InstanceId' \
          --output text \
` \
        && echo ${ARRAY_EC2_INSTANCE_ID}
変数の設定
EC2_INSTANCE_ID=$(echo ${ARRAY_EC2_INSTANCE_ID} | sed 's/ .*$//') \
        && echo ${EC2_INSTANCE_ID}
結果(例)
      i-xxxxxxxx

3.3 インスタンスのステータス確認

コマンド
EC2_INSTANCE_STATE=` \
        aws ec2 describe-instances \
        --instance-ids ${EC2_INSTANCE_ID} \
        --query 'Reservations[].Instances[].State.Name' \
        --output text \
` \
        && echo ${EC2_INSTANCE_STATE}
結果
      running

4. インスタンスの確認

4.1. パブリックIPアドレスの取得

コマンド
EC2_PUBLIC_IP=` \
        aws ec2 describe-instances \
          --instance-id ${EC2_INSTANCE_ID} \
          --query "Reservations[].Instances[].PublicIpAddress" \
          --output text \
` \
        && echo ${EC2_PUBLIC_IP}
結果(例)
      54.xxx.xxx.xxx

4.2. SSHログイン

変数の確認
cat << ETX

        FILE_SSH_KEY:  ${FILE_SSH_KEY}
        EC2_PUBLIC_IP: ${EC2_PUBLIC_IP}

ETX
コマンド
ssh -i ${FILE_SSH_KEY} ec2-user@${EC2_PUBLIC_IP}
結果(例)
      The authenticity of host '54.xxx.xxx.xxx (54.xxx.xxx.xxx)' can't be established.
      RSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx.
      Are you sure you want to continue connecting (yes/no)?
入力
yes
結果(例)
      Warning: Permanently added '54.xxx.xxx.xxx' (RSA) to the list of known hosts.

             __|  __|_  )
             _|  (     /   Amazon Linux AMI

      https://aws.amazon.com/amazon-linux-ami/2015.03-release-notes/

4.3. ECSエージェントの確認

コマンド(EC2インスタンス)
ps ax |grep [a]mazon-ecs-init
結果(例)
      2379 ?        Ssl    0:00 /usr/libexec/amazon-ecs-init start

4.4. ECSクラスタ設定の確認

コマンド(EC2インスタンス)
cat /etc/ecs/ecs.config
結果(例)
      ECS_CLUSTER='handson-cluster'

4.5. ECSメタ設定の確認

コマンド(EC2インスタンス)
echo -e "\n" \
        && curl http://localhost:51678/v1/metadata \
        && echo -e "\n"
結果(例)
      {"Cluster":"\ |ECS_CLUSTER_NAME|\ ","ContainerInstanceArn":"arn:aws:ecs:\ |AWS_DEFAULT_REGION|\ :XXXXXXXXXXXX:container-instance/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","Version":"Amazon ECS Agent - v1.2.1 (5da1555)"}

4.6. 起動ログの確認

コマンド(EC2インスタンス)
cat /var/log/ecs/ecs-init.log.* 
結果
2015-07-05T08:54:04Z [INFO] pre-start
2015-07-05T08:54:05Z [INFO] start
2015-07-05T08:54:05Z [INFO] No existing agent container to remove.
2015-07-05T08:54:05Z [INFO] Starting Amazon EC2 Container Service Agent

4.7. エージェントログの確認

コマンド(EC2インスタンス)
cat /var/log/ecs/ecs-agent.log.* 
結果
2015-07-05T08:54:06Z [INFO] Starting Agent: Amazon ECS Agent - v1.2.1 (5da1555)
2015-07-05T08:54:06Z [INFO] Loading configuration
2015-07-05T08:54:06Z [INFO] Checkpointing is enabled. Attempting to load state
2015-07-05T08:54:06Z [INFO] Loading state! module="statemanager"
2015-07-05T08:54:06Z [INFO] Registering Instance with ECS
2015-07-05T08:54:06Z [INFO] Registered! module="api client"
2015-07-05T08:54:06Z [INFO] Registration completed successfully. I am running as 'arn:was:ecs:ap-northeast-1:XXXXXXXXXXXX:container-instance/xxxxxxxx-xxxx-xxxx-xxxx-aa37ad9f3927' in cluster 'handson-cluster'
2015-07-05T08:54:06Z [INFO] Saving state! module="statemanager"
2015-07-05T08:54:06Z [INFO] Beginning Polling for updates
2015-07-05T08:54:06Z [INFO] Creating poll dialer module="ws client" host="ecs-a-1.ap-northeast-1.amazonaws.com"
2015-07-05T08:54:06Z [ERROR] Error getting message from ws backend module="ws client" err="websocket: close 1011 Server Error"
2015-07-05T08:54:06Z [INFO] Error from acs; backing off module="acs handler" err="websocket: close 1011 Server Error"
2015-07-05T08:54:07Z [INFO] Creating poll dialer module="ws client" host="ecs-a-1.ap-northeast-1.amazonaws.com"
2015-07-05T08:54:16Z [INFO] Saving state! module="statemanager"
2015-07-05T08:54:23Z [INFO] Handling http request module="Handlers" method="GET" from="172.xxx.xxx.xxx:34872" uri="/v1/metadata"

4.8. ログアウト

ログアウトします。

コマンド(EC2インスタンス)
exit
結果(例)
      logout
      Connection to 54.xxx.xxx.xxx closed.

5. クラスタの確認

5.1. クラスタの確認

コマンド
aws ecs describe-clusters \
  --clusters ${ECS_CLUSTER_NAME}
結果(例)
       {
         "clusters": [
           {
             "status": "ACTIVE",
             "clusterName": "handson-cluster",
             "registeredContainerInstancesCount": 1,
             "pendingTasksCount": 0,
             "runningTasksCount": 0,
             "activeServicesCount": 0,
             "clusterArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:cluster/handson-cluster"
           }
         ],
         "failures": []
      }

5.2. コンテナインスタンスの確認

コマンド
ECS_INSTANCES=$( \
        aws ecs list-container-instances \
          --cluster ${ECS_CLUSTER_NAME} \
          --query 'containerInstanceArns[]' \
          --output text | \
        sed 's|^arn:aws:ecs:.*:container-instance/||' \
) \
        && echo ${ECS_INSTANCES}
結果(例)
      xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
コマンド
aws ecs describe-container-instances \
  --cluster ${ECS_CLUSTER_NAME} \
  --container-instances "${ECS_INSTANCES}" 
結果(例)
      {
        "failures": [],
        "containerInstances": [
          {
              "status": "ACTIVE",
              "registeredResources": [
                  {
                      "integerValue": 1024,
                      "longValue": 0,
                      "type": "INTEGER",
                      "name": "CPU",
                      "doubleValue": 0.0
                  },
                  {
                      "integerValue": 996,
                      "longValue": 0,
                      "type": "INTEGER",
                      "name": "MEMORY",
                      "doubleValue": 0.0
                  },
                  {
                      "name": "PORTS",
                      "longValue": 0,
                      "doubleValue": 0.0,
                      "stringSetValue": [
                          "22",
                          "2376",
                          "2375",
                          "51678"
                      ],
                      "type": "STRINGSET",
                      "integerValue": 0
                  },
                  {
                      "name": "PORTS_UDP",
                      "longValue": 0,
                      "doubleValue": 0.0,
                      "stringSetValue": [],
                      "type": "STRINGSET",
                      "integerValue": 0
                  }
              ],
              "ec2InstanceId": "i-xxxxxxxx",
              "agentConnected": true,
              "containerInstanceArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:container-instance/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
              "pendingTasksCount": 0,
              "remainingResources": [
                  {
                      "integerValue": 1024,
                      "longValue": 0,
                      "type": "INTEGER",
                      "name": "CPU",
                      "doubleValue": 0.0
                  },
                  {
                      "integerValue": 996,
                      "longValue": 0,
                      "type": "INTEGER",
                      "name": "MEMORY",
                      "doubleValue": 0.0
                  },
                  {
                      "name": "PORTS",
                      "longValue": 0,
                      "doubleValue": 0.0,
                      "stringSetValue": [
                          "22",
                          "2376",
                          "2375",
                          "51678"
                      ],
                      "type": "STRINGSET",
                      "integerValue": 0
                  },
                  {
                      "name": "PORTS_UDP",
                      "longValue": 0,
                      "doubleValue": 0.0,
                      "stringSetValue": [],
                      "type": "STRINGSET",
                      "integerValue": 0
                  }
              ],
              "runningTasksCount": 0,
              "versionInfo": {
                  "agentVersion": "1.2.1",
                  "agentHash": "5da1555",
                  "dockerVersion": "DockerVersion: 1.6.2"
              }
          }
        ]
      }

完了

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away