AWS
docker
aws-cli
ECS
ECR

Amazon ECR + ECS CLI ハンズオン

More than 1 year has passed since last update.


ECR とは

AWSのマネージドサービスなdocker互換コンテナレジストリです。(EC2 Container Registry)

デフォルトでは自アカウントのみアクセス可能になっており、外に置きたくないコンテナイメージをAWS内で管理するのに適しています。

ECSもバージョンアップしてコンテナインスタンス(ECS最適化EC2インスタンス)にDocker 1.9.1が搭載されました。

今回は、Webサーバコンテナを作成してECRレポジトリに登録し、ECSクラスタでWebサービスを構築します。

コンテナを強制停止しても自動的に新しいコンテナが起動し、サービスが継続されることを確認します。

みんな大好きAWSCLIでやってみましょう。


前提条件


作業端末

AWS CLIがインストールされていること。

jsonlint, jq コマンドがインストールされていること。


実行権限

EC2インスタンスを新しく起動できること。

IAMの操作権限があること。


AWS CLIのバージョン

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


  • AWS CLI 1.10.0


コマンド

aws --version



結果(例)

      aws-cli/1.10.0 Python/2.6.6 Linux/2.6.32-573.8.1.el6.x86_64 botocore/1.3.22



0. 事前作業


0.1. リージョンの決定

ECRは現在のところ us-east-1(バージニア)、us-west-2(オレゴン)リージョンにしかありません。(2016年3月オレゴンが追加されたので追記)

今回はus-east-1リージョン使うように設定します。

(カレントユーザが利用するカレントリージョンも切り変わります。)


変数の設定

export AWS_DEFAULT_REGION='us-east-1'



0.2. 変数の確認

プロファイルとリージョンが想定のものになっていることを確認します。


コマンド

aws configure list



結果(例)

            Name                    Value             Type    Location

---- ----- ---- --------
profile <not set> None None
access_key ****************M73Q shared-credentials-file
secret_key ****************YWg/ shared-credentials-file
region us-west-2 env AWS_DEFAULT_REGION


1. レポジトリの構築

ecr-handson-httpd というレポジトリを作成してみます。


1.1. レポジトリの作成


コマンド

ECR_REPOSITORY=ecr-handson-httpd

aws ecr create-repository --repository-name ${ECR_REPOSITORY}


結果(例)

      {

"repository": {
"registryId": "454200CLI555",
"repositoryName": "ecr-handson-httpd",
"repositoryArn": "arn:aws:ecr:us-east-1:454200CLI555:repository/ecr-handson-httpd"
}
}


1.2. レポジトリの確認


コマンド

aws ecr describe-repositories



結果(例)

      {

"repositories": [
{
"registryId": "454200CLI555",
"repositoryName": "ecr-handson-httpd",
"repositoryArn": "arn:aws:ecr:us-east-1:454200CLI555:repository/ecr-handson-httpd"
}
]
}


1.3. (参考)レポジトリのアクセス権付与

(この項目は権限付与の例です。ハンズオンの動作には不要なので飛ばしても構いません)

ECRは作成した状態では自アカウントのみアクセスできるようになっています。

他のアカウントからアクセスできるようにする場合は、JSONでポリシーを書いて登録します。これは誰でもpullのみできるように設定する例です。

まずはポリシーをJSONファイルで作成します。


コマンド

ECR_POLICY_NAME=ecr-handson-policy

cat << EOF > ${ECR_POLICY_NAME}.json
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": "*",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability"
]
}
]
}
EOF


結果

      返り値なし


JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。


コマンド

jsonlint -q ${ECR_POLICY_NAME}.json



結果

      返り値なし


レポジトリへポリシーを設定します。


コマンド

aws ecr set-repository-policy --repository-name ${ECR_REPOSITORY} --policy-text file://${ECR_POLICY_NAME}.json



結果(例)

      {

"policyText": "{\n \"Version\" : \"2008-10-17\",\n \"Statement\" : [ {\n \"Sid\" : \"ecr-handson-policy\",\n \"Effect\" : \"Allow\",\n \"Principal\" : \"*\",\n \"Action\" : [ \"ecr:GetDownloadUrlForLayer\", \"ecr:BatchGetImage\", \"ecr:BatchCheckLayerAvailability\" ]\n } ]\n}",
"repositoryName": "ecr-handson-httpd",
"registryId": "454200CLI555"
}

設定した場合は get-repository-policy で現在の設定状況を確認できます。


コマンド

aws ecr get-repository-policy --repository-name ${ECR_REPOSITORY}



結果(例)

      {

"policyText": "{\n \"Version\" : \"2008-10-17\",\n \"Statement\" : [ {\n \"Sid\" : \"ecr-handson-policy\",\n \"Effect\" : \"Allow\",\n \"Principal\" : \"*\",\n \"Action\" : [ \"ecr:GetDownloadUrlForLayer\", \"ecr:BatchGetImage\", \"ecr:BatchCheckLayerAvailability\" ]\n } ]\n}",
"repositoryName": "ecr-handson-httpd",
"registryId": "454200CLI555"
}

設定コマンドの出力と同じ内容が出力されれば正しく設定されています。

なお、何も設定していない場合はエラーとなります。(自分のみアクセス可能)


2. コンテナインスタンスの作成


2.1. IAMロールの作成


コマンド

ROLE_NAME="ecr-handson-role"

aws iam create-role --role-name ${ROLE_NAME} --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com"}, "Action": "sts:AssumeRole" } ] }'


結果(例)

      {

"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}
]
},
"RoleId": "AROAIXFYSOEMNKZQ6532G",
"CreateDate": "2015-12-21T06:00:03.792Z",
"RoleName": "ecr-handson-role",
"Path": "/",
"Arn": "arn:aws:iam::454200CLI555:role/ecr-handson-role"
}
}


2.2. IAMロールへPolicyを追加

ECSに必要なポリシーである AmazonEC2ContainerServiceforEC2Role をIAMロールへ付与します。


コマンド

POLICY_ARN="arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"

aws iam attach-role-policy --role-name ${ROLE_NAME} --policy-arn ${POLICY_ARN}


結果

      返り値なし



2.3. インスタンスプロファイルの作成


コマンド

INSTANCE_PROFILE_NAME="ecr-handson-profile"

aws iam create-instance-profile --instance-profile-name ${INSTANCE_PROFILE_NAME}


結果(例)

      {

"InstanceProfile": {
"InstanceProfileId": "AIPAIWWQNUCXKCYHEZ46O",
"Roles": [],
"CreateDate": "2015-12-21T05:54:47.445Z",
"InstanceProfileName": "ecr-handson-profile",
"Path": "/",
"Arn": "arn:aws:iam::454200CLI555:instance-profile/ecr-handson-profile"
}
}


2.4. インスタンスプロファイルへIAMロールを追加


コマンド

aws iam add-role-to-instance-profile --instance-profile-name ${INSTANCE_PROFILE_NAME} --role-name ${ROLE_NAME}



結果

      返り値なし



2.5. 鍵ペアの作成

鍵ペア virginia を作成します。

秘密鍵ファイルは ~/.ssh/virginia.pem に保存されます。


コマンド

EC2_KEY_NAME="virginia"

FILE_SSH_KEY="${HOME}/.ssh/${EC2_KEY_NAME}.pem"
aws ec2 create-key-pair --key-name ${EC2_KEY_NAME} --query 'KeyMaterial' --output text > ${FILE_SSH_KEY} && cat ${FILE_SSH_KEY} && chmod 600 ${FILE_SSH_KEY}


結果(例)

      -----BEGIN RSA PRIVATE KEY-----

MIIEowIBAAKCAQEAg4AFnT934UdMmuSADElYSWzOQ/XpXUc0570zKwtDB3RXS9Fi8YP8J5jv6QRl
(本当はもっと長い)
MfRletfQDp2Hbth3SnNu2MaFQs8C+ODyx7XTx/13LW247AGVsSfq63jovntOL7PRuFA=
-----END RSA PRIVATE KEY-----


2.6. セキュリティグループの作成

セキュリティグループ ecr-handson-sg を作成します。


コマンド

SG_NAME="ecr-handson-sg"

aws ec2 create-security-group --group-name ${SG_NAME} --description ${SG_NAME}
SG_ID=`aws ec2 describe-security-groups --filter Name=group-name,Values=${SG_NAME} --query 'SecurityGroups[].GroupId' --output text` && echo ${SG_ID}


結果(例)

      {

"GroupId": "sg-59c3e63d"
}

sg-59c3e63d


外部からのHTTP接続をセキュリティグループに追加。


コマンド

aws ec2 authorize-security-group-ingress --group-id ${SG_ID} --protocol 'tcp' --port 80 --cidr 0.0.0.0/0



結果

      (返り値なし)


作業中端末のIPアドレスをSSHログインを追加します。


コマンド

TERM_IP=`curl -s http://ip-api.com/json | jq -r '.query'` && echo ${TERM_IP}

aws ec2 authorize-security-group-ingress --group-id ${SG_ID} --protocol 'tcp' --port 22 --cidr ${TERM_IP}/32


結果(例)

      54.32.10.999



2.7. コンテナインスタンスの起動

AMI IDの取得


コマンド

AMZLINUX_VERSION='2015.09.g'

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-33b48a59


インスタンスの起動


コマンド

EC2_INSTANCE_TYPE='t2.micro'

aws ec2 run-instances --image-id ${EC2_IMAGE_ID} --instance-type ${EC2_INSTANCE_TYPE} --security-group-ids ${SG_ID} --key-name ${EC2_KEY_NAME} --associate-public-ip-address --iam-instance-profile Name=${INSTANCE_PROFILE_NAME}


結果(例)

      {

"OwnerId": "454200CLI555",
"ReservationId": "r-9f30ff37",
"Groups": [],
"Instances": [
{
"Monitoring": {
"State": "disabled"
},
"PublicDnsName": "",
"RootDeviceType": "ebs",
"State": {
"Code": 0,
"Name": "pending"
},
"EbsOptimized": false,
"LaunchTime": "2016-01-02T04:15:23.000Z",
"PrivateIpAddress": "172.31.55.69",
"ProductCodes": [],
"VpcId": "vpc-121f2877",
"StateTransitionReason": "",
"InstanceId": "i-52e7a0e3",
"ImageId": "ami-33b48a59",
(中略)
"IamInstanceProfile": {
"Id": "AIPAIMKAR2A47DJUFOI7C",
"Arn": "arn:aws:iam::454200CLI555:instance-profile/ecr-handson-profile"
},
"RootDeviceName": "/dev/xvda",
"VirtualizationType": "hvm",
"AmiLaunchIndex": 0
}
]
}


2.8. インスタンス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-52e7a0e3


結果は1つだけのはずですが、何らかの原因で何も表示されなかったり複数表示された場合はうまくいきません。

この場合は2.7.での出力結果22行目あたりに

"InstanceId": "i-52e7a0e3",

といった項目があるので、この値を手動で

EC2_INSTANCE_ID="i-52e7a0e3"

のように手動でコマンドを打ち環境変数へ格納してください。


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


コマンド

EC2_PUBLIC_IP=`aws ec2 describe-instances --instance-id ${EC2_INSTANCE_ID} --query "Reservations[].Instances[].PublicIpAddress" --output text` && echo ${EC2_PUBLIC_IP}



結果(例)

      54.32.10.999



3. コンテナの構築・ECRレポジトリへのpush


3.1. ECRログイン情報の取得

ECRへの接続にはログインが必要です。

Docker互換のレポジトリですが本家のように簡単にid/pwでは接続出来ないため専用のコマンドが用意されています。


コマンド

aws ecr get-login



結果(例)

      docker login -u AWS -p CiBwm0YaISJeRtJm5n1G6uqeekXuoXXPe5UFce9Rq8/14xKSBgEBAgB4cJtGGiEiXkbSZuZ9RurqnnpF7qF1z3uVBXHvUavP9eHNJMLpMIIC5QYJKoZIhvcNAQcGoIIC1jCCAtICAQAwggLLBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDGcFa1BBiuP6lX7hUAIBEICCApyJiPPIOIYXGxxxB+tbTyukXmxXi9h0qHvkcuNG1kHClFX9FdKYDGWhxV3tVbvtekjG1BnYI5M5R5NGa18M9hhnpclS9x9tMLyheKlJKCND8sa8UA/egl9/lTsQHSe1q/Vy9CmvjwHJgl6KQEC68kIWqmdKwGo6lV1K8RHSqWONmwrhENGwJZoZ4eWOuVEtxsJW9TvpASQzLo0GEJERlPeDWlxyZ+7Uah3Ewv3FGx9Y9I8lBHfn7hVjBtTNvmftvM8n2zELLdCdxcbrlM7088ZLPW+UcqppHzWiykwqYEww4x7jFTX2UHuCi7mheeQgAHgmHElVj2Rbi5Mt4jJ/k3zczqhffOvmCKqINZ7gPobjlZXRW1/qw5xWwQNK0sR5AloH6uKGXAJU3UYzizTkxfwcpspzmU1B2Ncva1Ug9cmXu1IMo5mhheFSWPblktFxCWi5xhXBhakkmX+TCXaal/jaCKOn3PEz6djeHqJ+w8fP3ZR7NY0GOWvO0BUZcb3gLQbHXutttxYXaNqWIq261CoRHY7PcI6qwpeiROlUFjoAUTUkHhesBun5uOnRuEk3itwIb25lakgSaxDsq4p4WC3QJjA9VsMNp+LcTJ5sF4NmUgC81qxTtt8G2iikpD1rLhMdeHlwHiHND7VtSLVZgUWFeL8QKuzJH55iR4XrMLIL1ahRHs8MjdGj7so3e13sFzby3Jv2NOcpOkfW431IS/60M5+Zb/4QPfYhDNeQOVkqWDXJGvvvYPr9h5CHJo1u3DFYHuuHgCyWInN4ueMEFjo7YW8mWrnn36dF4FSuc+34WyxIHQyQnJaiROmN3WVNf//FTuO+9V4Cv5kQLIqOMT0NyoDg6BQnnrVeGH2+mkBuTb8Eg9nMchPZCP2vhw== -e none https://454200CLI555.dkr.ecr.us-east-1.amazonaws.com


非常に長いですがこれで1行です。

この後で使うのでメモ帳などにコピーしておいてください。


3.2. コンテナインスタンスへのログイン


コマンド

ssh -l ec2-user -i ${FILE_SSH_KEY} ${EC2_PUBLIC_IP}


(何か聞かれたら yes と答える)


結果(例)

         __|  __|  __|

_| ( \__ \ Amazon ECS-Optimized Amazon Linux AMI 2015.09.d
____|\___|____/

For documentation visit, http://aws.amazon.com/documentation/ecs
7 package(s) needed for security, out of 14 available
Run "sudo yum update" to apply all updates.


以下この章はコンテナインスタンス上で作業を行います。


3.3. ECRへログイン

先ほど 3.1. で取得したログイン情報(非常に長い1行)をペーストして実行します。


コマンド(例)

docker login -u AWS -p CiBwm0YaISJeRtJm5n1G6uqeekXuoXXPe5UFce9Rq8/14xKSBgEBAgB4cJtGGiEiXkbSZuZ9RurqnnpF7qF1z3uVBXHvUavP9eHNJMLpMIIC5QYJKoZIhvcNAQcGoIIC1jCCAtICAQAwggLLBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDGcFa1BBiuP6lX7hUAIBEICCApyJiPPIOIYXGxxxB+tbTyukXmxXi9h0qHvkcuNG1kHClFX9FdKYDGWhxV3tVbvtekjG1BnYI5M5R5NGa18M9hhnpclS9x9tMLyheKlJKCND8sa8UA/egl9/lTsQHSe1q/Vy9CmvjwHJgl6KQEC68kIWqmdKwGo6lV1K8RHSqWONmwrhENGwJZoZ4eWOuVEtxsJW9TvpASQzLo0GEJERlPeDWlxyZ+7Uah3Ewv3FGx9Y9I8lBHfn7hVjBtTNvmftvM8n2zELLdCdxcbrlM7088ZLPW+UcqppHzWiykwqYEww4x7jFTX2UHuCi7mheeQgAHgmHElVj2Rbi5Mt4jJ/k3zczqhffOvmCKqINZ7gPobjlZXRW1/qw5xWwQNK0sR5AloH6uKGXAJU3UYzizTkxfwcpspzmU1B2Ncva1Ug9cmXu1IMo5mhheFSWPblktFxCWi5xhXBhakkmX+TCXaal/jaCKOn3PEz6djeHqJ+w8fP3ZR7NY0GOWvO0BUZcb3gLQbHXutttxYXaNqWIq261CoRHY7PcI6qwpeiROlUFjoAUTUkHhesBun5uOnRuEk3itwIb25lakgSaxDsq4p4WC3QJjA9VsMNp+LcTJ5sF4NmUgC81qxTtt8G2iikpD1rLhMdeHlwHiHND7VtSLVZgUWFeL8QKuzJH55iR4XrMLIL1ahRHs8MjdGj7so3e13sFzby3Jv2NOcpOkfW431IS/60M5+Zb/4QPfYhDNeQOVkqWDXJGvvvYPr9h5CHJo1u3DFYHuuHgCyWInN4ueMEFjo7YW8mWrnn36dF4FSuc+34WyxIHQyQnJaiROmN3WVNf//FTuO+9V4Cv5kQLIqOMT0NyoDg6BQnnrVeGH2+mkBuTb8Eg9nMchPZCP2vhw== -e none https://454200CLI555.dkr.ecr.us-east-1.amazonaws.com



結果

      WARNING: login credentials saved in /home/ec2-user/.docker/config.json

Login Succeeded

コピーペーストした長い長いコマンドの一番最後に https://....で始まる文字列があります。

このhttps://の後ろの、数字で始まる部分から最後まで(この例では 454200CLI555.dkr.ecr.us-east-1.amazonaws.com )をコピーペーストして変数へ格納します。

これは自分のECRレジストリです。(レポジトリが置かれている場所)


コマンド(例)

ECR_REGISTRY=454200CLI555.dkr.ecr.us-east-1.amazonaws.com



結果

      返り値なし



  • このコマンド(ECR_REGISTRY=....)は後でもう一度実行するのでメモしておいてください。


3.4. Dockerfile ファイルの作成

ハンズオン用にWebサーバのコンテナを作成します。

今回はCentOS6をベースにapache httpdのコンテナを作成します。

まずは Dockerfile を作成します。

注意:コマンド1行目のECR_REPOSITORYは 1.1. と必ず同一内容にしてください


コマンド

ECR_REPOSITORY=ecr-handson-httpd

mkdir ${ECR_REPOSITORY}
cat << EOF > ${ECR_REPOSITORY}/Dockerfile
FROM centos:6
RUN yum -y install httpd
RUN chkconfig httpd off
CMD ["/usr/sbin/apachectl", "-DFOREGROUND"]
EOF


結果

      返り値なし



3.5. コンテナイメージのビルド


コマンド

docker build -t ${ECR_REGISTRY}/${ECR_REPOSITORY} ${ECR_REPOSITORY}



結果(例)

      Sending build context to Docker daemon 3.072 kB

Step 1 : FROM centos:6
6: Pulling from library/centos
fa5be2806d4c: Pull complete
ebdbe10e9b33: Pull complete
366219586e86: Pull complete
501f51238f9e: Pull complete
1a895dd3954a: Pull complete
Digest: sha256:7d1c9d44f0b3b81c3aa4e77b744782b021af795478e163723b34a40176bbff2a
Status: Downloaded newer image for centos:6
---> 1a895dd3954a
Step 2 : RUN yum -y install httpd
---> Running in 9bacc73ba4d1
Loaded plugins: fastestmirror
Setting up Install Process
Resolving Dependencies

(中略)

Complete!
---> cf75917dcaf9
Removing intermediate container 9bacc73ba4d1
Step 3 : RUN chkconfig httpd off
---> b69e4c86cfa3
Removing intermediate container 26bd1a3ca590
Step 4 : CMD apachectl -DFOREGROUND
---> Running in 9fab593e1e6c
---> 068ca71d4c15
Removing intermediate container 9fab593e1e6c
Successfully built 068ca71d4c15


最後の行に Successfully built と出ていれば成功です。


3.6. コンテナイメージのpush


コマンド

docker push ${ECR_REGISTRY}/${ECR_REPOSITORY}:latest



結果(例)

      The push refers to a repository [454200CLI555.dkr.ecr.us-east-1.amazonaws.com/ecr-handson-httpd] (len: 1)

068ca71d4c15: Pushed
b69e4c86cfa3: Pushed
cf75917dcaf9: Pushed
ebdbe10e9b33: Pushed
latest: digest: sha256:221868f77451e576f1159c2ee6e0ef73b83c5d623592dc81dff8d8972349f416 size: 12345


3.7. コンテナインスタンスからログアウトする


コマンド

logout



結果(例)

      Connection to 54.32.10.999 closed.


ログアウトして作業端末に戻りました。

(必ずログアウトしてください。ECS用インスタンスにはAWSCLIが存在しないので以後の


3.8. コンテナイメージがpushされたか確認します


コマンド

aws ecr list-images --repository-name ${ECR_REPOSITORY} --output text



結果(例)

IMAGEIDS        sha256:221868f77451e576f1159c2ee6e0ef73b83c5d623592dc81dff8d8972349f416 latest


pushされたecr-handson-httpdレポジトリのIMAGE IDのsha256ハッシュ値と、3.6.最下行のプッシュしたコンテナイメージのsha256ハッシュ値が一致していることを確認します。


4. ECSクラスタを構築しコンテナ稼働

dockerコンテナを直接起動しても動作しますが、コンテナのメリットは落ちたときに自動的に新しいコンテナが起動されることです。これをECSクラスタで実現します。


4.1. ECRレジストリの環境変数への格納

先ほど 3.3. でメモしたコマンド(ECR_REGISTRY=...)を実行します。

これは作業用インスタンスに戻ったため、変数に値が無いためです。


コマンド(例)

ECR_REGISTRY=454200CLI555.dkr.ecr.us-east-1.amazonaws.com



結果

      返り値なし



4.2. タスク定義の登録

タスクが実行するコンテナの定義をJSONファイルで作成します。


コマンド

ECS_TASK="ecr-handson-task"

cat << EOF > ${ECS_TASK}.json
[
{
"name": "
${ECS_TASK}",
"image": "
${ECR_REGISTRY}/${ECR_REPOSITORY}:latest",
"cpu": 0,
"memory": 256,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true
}
]
EOF


結果

      返り値なし


JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。


コマンド

jsonlint -q ${ECS_TASK}.json



結果

      返り値なし


タスクを定義します。


コマンド

aws ecs register-task-definition --family ${ECS_TASK} --container-definitions file://${ECS_TASK}.json



結果(例)

      {

"taskDefinition": {
"status": "ACTIVE",
"family": "ecr-handson-task",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
}
],
"volumes": [],
"taskDefinitionArn": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:1",
"containerDefinitions": [
{
"environment": [],
"name": "ecr-handson-task",
"mountPoints": [],
"image": "454200CLI555.dkr.ecr.us-east-1.amazonaws.com/ecr-handson-httpd:latest",
"cpu": 0,
"portMappings": [
{
"protocol": "tcp",
"containerPort": 80,
"hostPort": 80
}
],
"memory": 256,
"essential": true,
"volumesFrom": []
}
],
"revision": 1
}
}

最後から3行目に revision という項目があります。最初に登録すると 1 です。

この register-task-definition は登録のみで変更コマンドはありません。

再度を実行するとその内容に上書き更新されます。その際 revision が増加します。


4.3. サービスの登録

実行させたタスクをサービスとして登録します。


コマンド

ECS_SERVICE="ecr-handson-service"

aws ecs create-service --service-name ${ECS_SERVICE} --task-definition ${ECS_TASK} --desired-count 1


結果(例)

      {

"service": {
"status": "ACTIVE",
"taskDefinition": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:1",
"pendingCount": 0,
"loadBalancers": [],
"desiredCount": 1,
"serviceName": "ecr-handson-service",
"clusterArn": "arn:aws:ecs:us-east-1:454200CLI555:cluster/default",
"serviceArn": "arn:aws:ecs:us-east-1:454200CLI555:service/ecr-handson-service",
"deploymentConfiguration": {
"maximumPercent": 200,
"minimumHealthyPercent": 100
},
"deployments": [
{
"status": "PRIMARY",
"pendingCount": 0,
"createdAt": 1452242241.0799999,
"desiredCount": 1,
"taskDefinition": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:1",
"updatedAt": 1452242241.0799999,
"id": "ecs-svc/9223370584612534727",
"runningCount": 0
}
],
"events": [],
"runningCount": 0
}
}

最下部の runningCount がまだ 0 でサービス登録直後はタスクがまだ実行されていないことがわかります。


4.4. サービス稼働の確認

ECSへサービスを登録してから実際にタスクが実行状態となるまで30秒ぐらいかかります。しばらく待ってからコマンドを実行します。


コマンド

aws ecs describe-services --services ${ECS_SERVICE}



結果(例)

      {

"services": [
{
"status": "ACTIVE",
"taskDefinition": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:3",
"pendingCount": 0,
"loadBalancers": [],
"desiredCount": 1,
"serviceName": "ecr-handson-service",
"clusterArn": "arn:aws:ecs:us-east-1:454200CLI555:cluster/default",
"serviceArn": "arn:aws:ecs:us-east-1:454200CLI555:service/ecr-handson-service",
"deploymentConfiguration": {
"maximumPercent": 200,
"minimumHealthyPercent": 100
},
"deployments": [
{
"status": "PRIMARY",
"pendingCount": 0,
"createdAt": 1453376205.6140001,
"desiredCount": 1,
"taskDefinition": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:3",
"updatedAt": 1453376205.6140001,
"id": "ecs-svc/9223370583478570167",
"runningCount": 1
}
],
"events": [
{
"message": "(service ecr-handson-service) has started 1 tasks: (task 9aa85d4f-af74-4c7e-ad08-6738a47b8827).",
"id": "2d178819-4d3a-4981-9b57-188073d4c654",
"createdAt": 1453376231.079
}
],
"runningCount": 1
}
],
"failures": []
}

先ほど 0 だった runningCount が 1 になっていますね。

0のままの場合はもう少し待ってから再実行してみてください。(遅くても数分なのでそれ以上待っても0の場合は失敗しています)


4.5. Webブラウザで動作確認

Webブラウザで実際に動作確認しましょう。インスタンスのIPアドレスを確認します。


コマンド

EC2_PUBLIC_IP=`aws ec2 describe-instances --instance-id ${EC2_INSTANCE_ID} --query "Reservations[].Instances[].PublicIpAddress" --output text` && echo ${EC2_PUBLIC_IP}



結果(例)

      54.32.10.999


WebブラウザでIPアドレスを指定してアクセスしてみます。

http://54.32.10.999/

Apache httpdのテストページが表示されれば成功です。

また後でアクセスするので画面はそのままにしておきましょう。


5. コンテナを強制終了させてECSによる自動再稼働を確認する


5.1. コンテナインスタンスへのログイン


コマンド

ssh -l ec2-user -i ${FILE_SSH_KEY} ${EC2_PUBLIC_IP}



結果(例)

         __|  __|  __|

_| ( \__ \ Amazon ECS-Optimized Amazon Linux AMI 2015.09.c
____|\___|____/

For documentation visit, http://aws.amazon.com/documentation/ecs
7 package(s) needed for security, out of 14 available
Run "sudo yum update" to apply all updates.


以下この章はコンテナインスタンス上で作業を行います。


5.2. dockerコンテナのコンテナIDを確認する


コマンド

docker ps



結果(例)

      CONTAINER ID        IMAGE                                                      COMMAND                CREATED             STATUS              PORTS                        NAMES

e0818845425f 454200CLI555.dkr.ecr.us-east-1.amazonaws.com/ecr-handson-httpd:latest "/bin/sh -c /etc/rc. 5 hours ago Up 5 hours 0.0.0.0:80->80/tcp ecs-handson-task-2-hoge-task-9ae6cda0a8e793b28a01
da9c1af0f7fc amazon/amazon-ecs-agent:latest "/agent" 6 days ago Up 6 days 127.0.0.1:51678->51678/tcp ecs-agent

複数行表示されますが、ecr-handson-httpdを探します。(この例では1行目)

その行の先頭の文字列(e0818845425f)がコンテナIDです。


5.3. dockerコンテナを強制終了させる

取得したコンテナIDを指定してdocker killコマンドを実行します。


コマンド(例)

docker kill e0818845425f



結果(例)

      e0818845425f



5.4. Webブラウザで落ちたか確認

Webブラウザをリロードしてエラーとなり表示されないことを確認します。

普通に表示される!?

そんなこともあります。ECSのサービス再起動は優秀ですぐに復活するため、表示されたとしても気にしない。

結果がどうあれ次へ進みます。


5.5. コンテナIDの変化を確認する

ECSによってサービスが再起動されたことを論理的に確認するために、旧コンテナが消滅し新しいコンテナが起動されたことを確認します。


コマンド

docker ps



結果(例)

      CONTAINER ID        IMAGE                                                      COMMAND                CREATED              STATUS              PORTS                        NAMES

5064009cf70f 454200CLI555.dkr.ecr.us-east-1.amazonaws.com/ecr-handson-httpd:latest "/bin/sh -c /etc/rc. About a minute ago Up About a minute 0.0.0.0:80->80/tcp ecs-hoge-task-2-hoge-task-a2b6eb91d4cae0d5e701
da9c1af0f7fc amazon/amazon-ecs-agent:latest "/agent" 6 days ago Up 6 days 127.0.0.1:51678->51678/tcp ecs-agent

コンテナIDを先ほど 5.3.でdocker killした物と見比べます。新しいコンテナIDになっている事が確認できるはずです。

先ほどWebブラウザで落ちたか確認できなかったとしても、コンテナIDの変化で新しいコンテナが起動されたのを確認できます。


5.6. コンテナインスタンスからログアウトする


コマンド

logout



結果(例)

      Connection to 54.32.10.999 closed.


ログアウトして再び作業端末に戻ります。


5.7. Webブラウザでサービス復旧を確認

Webブラウザをリロードして再びWebページが表示されることを確認します。

以上でハンズオンの目的は達成されました。お疲れ様でした。


6. 後片付け


6.1. サービスARNの取得


コマンド

SERVICE_ARN=`aws ecs list-services --query serviceArns --output text` && echo ${SERVICE_ARN}



結果(例)

      arn:aws:ecs:us-east-1:454200CLI555:service/ecr-handson-service



6.2. サービスの起動数を0にする

サービスを削除するには、まずサービスの起動数(desired-count)を0にしなければなりません。


コマンド

aws ecs update-service --service ${ECS_SERVICE} --desired-count 0



結果(例)

      {

"service": {
"status": "ACTIVE",
"taskDefinition": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:1",
"pendingCount": 0,
"loadBalancers": [],
"desiredCount": 0,
"serviceName": "ecr-handson-service",
"clusterArn": "arn:aws:ecs:us-east-1:454200CLI555:cluster/default",
"serviceArn": "arn:aws:ecs:us-east-1:454200CLI555:service/ecr-handson-service",
"deploymentConfiguration": {
"maximumPercent": 200,
"minimumHealthyPercent": 100
},
"deployments": [
{
"status": "PRIMARY",
"pendingCount": 0,
"createdAt": 1452497056.9389999,
"desiredCount": 0,
"taskDefinition": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:1",
"updatedAt": 1452497056.9389999,
"id": "ecs-svc/9223370584357718868",
"runningCount": 1
}

(中略)

],
"runningCount": 1
}
}



6.3. サービスを削除する


コマンド

aws ecs delete-service --service ${ECS_SERVICE}



結果(例)

      {

"service": {
"status": "DRAINING",
"taskDefinition": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:1",
"pendingCount": 0,
"loadBalancers": [],
"desiredCount": 0,
"serviceName": "ecr-handson-service",
"clusterArn": "arn:aws:ecs:us-east-1:454200CLI555:cluster/default",
"serviceArn": "arn:aws:ecs:us-east-1:454200CLI555:service/ecr-handson-service",
"deploymentConfiguration": {
"maximumPercent": 200,
"minimumHealthyPercent": 100
},
"deployments": [
{
"status": "PRIMARY",
"pendingCount": 0,
"createdAt": 1452497056.9389999,
"desiredCount": 0,
"taskDefinition": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:1",
"updatedAt": 1452501689.8380001,
"id": "ecs-svc/9223370584357718868",
"runningCount": 0
}
],

(中略)

],
"runningCount": 0
}
}



6.4. タスク定義ARNの取得


コマンド

TASK_ARN=`aws ecs list-task-definitions --query taskDefinitionArns --output text` && echo ${TASK_ARN}



結果(例)

      arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:1



6.5. タスク定義の登録解除


コマンド

aws ecs deregister-task-definition --task-definition ${TASK_ARN}



結果(例)

      {

"taskDefinition": {
"status": "INACTIVE",
"family": "ecr-handson-task",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
}
],
"volumes": [],
"taskDefinitionArn": "arn:aws:ecs:us-east-1:454200CLI555:task-definition/ecr-handson-task:1",
"containerDefinitions": [
{
"environment": [],
"name": "ecr-handson-task",
"mountPoints": [],
"image": "454200CLI555.dkr.ecr.us-east-1.amazonaws.com/ecr-handson-httpd:latest",
"cpu": 0,
"portMappings": [
{
"protocol": "tcp",
"containerPort": 80,
"hostPort": 80
}
],
"memory": 256,
"essential": true,
"volumesFrom": []
}
],
"revision": 1
}
}

タスク定義を削除することはできないようです。

これはマネジメントコンソールからも同じで、現在の仕様と思われます。


6.6. コンテナインスタンスARNの取得


コマンド

EC2_INSTANCE_ARN=`aws ecs list-container-instances --query containerInstanceArns --output text` && echo ${EC2_INSTANCE_ARN}



結果(例)

      arn:aws:ecs:us-east-1:454200CLI555:container-instance/e43a1bbf-b89d-4128-8f4b-8189dac29d2c



6.7. コンテナインスタンスの登録解除


コマンド

aws ecs deregister-container-instance --container-instance ${EC2_INSTANCE_ARN} --force



結果(例)

{

"containerInstance": {
"status": "INACTIVE",
"registeredResources": [
{
"integerValue": 1024,
"longValue": 0,
"type": "INTEGER",
"name": "CPU",
"doubleValue": 0.0
},

(中略)

{
"name": "com.amazonaws.ecs.capability.ecr-auth"
}
],
"versionInfo": {
"agentVersion": "1.7.0",
"agentHash": "191dbd5",
"dockerVersion": "DockerVersion: 1.7.1"
}
}
}



6.8. ECSクラスタの削除


コマンド

aws ecs delete-cluster --cluster default



結果(例)

{

"cluster": {
"status": "INACTIVE",
"clusterName": "default",
"registeredContainerInstancesCount": 0,
"pendingTasksCount": 0,
"runningTasksCount": 0,
"activeServicesCount": 0,
"clusterArn": "arn:aws:ecs:us-east-1:454200CLI555:cluster/default"
}
}


6.9. コンテナインスタンスの削除(ターミネート)


コマンド

aws ec2 terminate-instances --instance-ids ${EC2_INSTANCE_ID}



結果(例)

{

"TerminatingInstances": [
{
"InstanceId": "i-52e7a0e3",
"CurrentState": {
"Code": 32,
"Name": "shutting-down"
},
"PreviousState": {
"Code": 16,
"Name": "running"
}
}
]
}


6.10. レポジトリの削除


コマンド

aws ecr delete-repository --repository-name ${ECR_REPOSITORY} --force



結果(例)

{

"repository": {
"registryId": "454200CLI555",
"repositoryName": "ecr-handson-httpd",
"repositoryArn": "arn:aws:ecr:us-east-1:454200CLI555:repository/ecr-handson-httpd"
}
}


まとめ

コンテナはもともとCLIで使う物なのでAWS CLIとの相性が良いですね。

気になる点は。

レポジトリのポリシー制御が、マネジメントコンソールだと複数項目を任意に設定・削除できるのに対し、CLIでは一括設定・削除しかなく、変更する場合は変更後の内容を自分で作ってJSONで引き渡すしかありません。

これはECRに限らず他のサービスでもそうなので現在のAWSCLIの仕様なのでしょう。

ECRにはVPCエンドポイントがありません。

AWSという同一AS内で通信が完結しているから気にしなくて良いとも思えますが会社の方針で使用許可が下りない場合もありそうですね。

今後に期待しましょう。