Using the AWS EC2 Container Registry with EC2 Container Service

Posted on Wed 06 January 2016 in aws

AWS announced recently that it's EC2 Container Registry (ECR) is now available. ECR simplifies hosting private images. Previously, you had to manually push your docker.io credentials to each EC2 instance -- likely a deliberate pain-point encouraging you to use ECR. With ECR, EC2 container hosts can easily fetch private images using IAM authentication.

Here are some of the gotchyas and stumbling blocks to help you get your repository up quickly and painlessly.

Prerequisites

1. aws-cli should be 1.9.15 or greater.

# check Version
$ aws --version
aws-cli/1.9.15
# update via homebrew (osx) if needed
$ brew update
$ brew upgrade aws-cli

2. Your ECS instances need to be running agent v1.7.0.

# check your agent Version -- should be 1.7.0
$ aws ecs describe-container-instances --container-instances=0000000-aaa-bbbb-ccc-000000000 --cluster=www-project-com | jq '.containerInstances[].versionInfo.agentVersion'
"1.7.0"

if you're not >= 1.7.0, get your instance ids and update the instances

# get the ids
aws ecs list-container-instances --cluster=www-project-com|jq '.containerInstanceArns[]'
"arn:aws:ecs:us-east-1:999999999999:container-instance/0000000-aaa-bbbb-ccc-000000000"

Update the agent on each one

aws ecs update-container-agent --cluster=www-project-com --container-instance=0000000-aaa-bbbb-ccc-000000000

3. Your EC2 instance role must have the appropriate access to the ECR service

The docs on using ECR with ECS show that you need to add these to your EC2 container instance role. This gives the instances the rights needed to generate credentials for the ECR registry. It's easiest to add this to your current role like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecs:CreateCluster",
                "ecs:DeregisterContainerInstance",
                "ecs:DiscoverPollEndpoint",
                "ecs:Poll",
                "ecs:RegisterContainerInstance",
                "ecs:StartTelemetrySession",
                "ecs:Submit*",
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:GetDownloadUrlForLayer",
                "ecr:GetAuthorizationToken"
            ],
            "Resource": "*"
        }
    ]
}

Create the ECR repository

It's best to use project/image-name

# aws ecr create-repository --repository-name project-a/nginx-web-app
{
             "repository": {
                 "registryId": "<aws_account_id>",
                 "repositoryName": "project-a/nginx-web-app",
                 "repositoryArn": "arn:aws:ecr:us-west-2:<aws_account_id>:repository/project-a/nginx-web-app"
             }
         }

Tag Your Image And Push to the Repository

# log into the repository
$ eval $(aws ecr get-login)
# tag your image with your complete repository url
$ docker tag drupal-proto:latest 999999999999.dkr.ecr.us-east-1.amazonaws.com/project-a/nginx-web-app:latest
# push the image
$ docker push 999999999999.dkr.ecr.us-east-1.amazonaws.com/project-a/nginx-web-app:latest

Conclusion

At this point you can use the complete image url in your container definitions. ECS will handle the credentials when pulling images.

Here is an example of what the image URL should look like

$ aws ecs describe-task-definition --task-definition=www-project-com:12|jq '.taskDefinition.containerDefinitions[].image'
"999999999999.dkr.ecr.us-east-1.amazonaws.com/project-a/nginx-web-app:latest"