Docker images are usually stored on Docker Hub, but AWS’s Elastic Container Registry can also be used. It’s a great solution and this post teaches you how to push Docker images to AWS’ Elastic Container Registry (ECR).

Create a Repository

Let’s start by using the aws-cli to create a repository.

1
aws ecr create-repository --repository-name myname

This command successfully creates a repository and outputs the following JSON:

1
2
3
4
5
6
7
8
9
{
  "repository": {
    "repositoryArn": "arn:aws:ecr:eu-west-1:098765432123:repository/myname",
    "registryId": "098765432123",
    "repositoryName": "myname",
    "repositoryUri": "098765432123.dkr.ecr.eu-west-1.amazonaws.com/myname",
    "createdAt": 1543162198.0
  }
}

It’s good to also point out that additionally, running a life-cycle policy to clean up older versions will save yourself a ton of time down the line. You can run it here as follows. It’s useful so that you don’t get blocked from pushing a new version in a bit.

1
aws ecr put-lifecycle-policy --registry-id 098765432123 --repository-name myname --lifecycle-policy-text '{"rules":[{"rulePriority":10,"description":"Expire older images","selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":100},"action":{"type":"expire"}}]}'

There are various other ways to clean up, such as by age. For now, though, we will clean up once there are 100 images in the repo.

Pushing and Pulling Images Locally

Start by authenticating your local Docker daemon against the ECR registry.

1
aws ecr get-login --registry-ids 098765432123 --no-include-email

This outputs a docker login and adds a new user-password pair for the Docker configuration. Copy-paste it, or run it like this instead:

1
$(aws ecr get-login --registry-ids 098765432123 --no-include-email)

Now pushing and pulling images is the same as what is usually done with Docker itself.

1
2
3
docker push 098765432123.dkr.ecr.eu-west-1.amazonaws.com/myname:0.0.1

docker pull 098765432123.dkr.ecr.eu-west-1.amazonaws.com/myname:0.0.1

Privileges required for Pushing Images

As ECR is within AWS, you use IAM users’ permissions to get the job done. It is always recommended to only give the permissions required to achieve a particular job and nothing more.

There are three policies that could be used for this:

  1. AmazonEC2ContainerRegistryFullAccess
  2. AmazonEC2ContainerRegistryPowerUser
  3. AmazonEC2ContainerRegistryReadOnly

You can attach these policies to an IAM user like this:

1
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly  --user-name andrewodendaal

You can also create your own policies, say for a CI/CD user to perform builds.

Start by creating an IAM group:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
aws iam create-group --group-name myname-developers
    {
          "Group": {
          "Path": "/",
          "GroupName": "myname-developers",
          "GroupId": "BBB4JRDMJSHFNJSNF3ARET8KJ",
          "Arn": "arn:aws:iam::098765432123:group/myname-developers",
          "CreateDate": "2018-10-25T11:45:42Z"
          }
    }

Now add a user:

1
aws iam add-user-to-group --group-name myname-developers --user-name andrewodendaal

This is what will be output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{ 
   "Version": "2012-10-17", 
   "Statement": [{ 
         "Effect": "Allow", 
         "Action": [ 
               "ecr:GetAuthorizationToken", 
               "ecr:BatchCheckLayerAvailability", 
               "ecr:GetDownloadUrlForLayer", 
               "ecr:GetRepositoryPolicy", 
               "ecr:DescribeRepositories", 
               "ecr:ListImages", 
               "ecr:DescribeImages", 
               "ecr:BatchGetImage", 
               "ecr:InitiateLayerUpload", 
               "ecr:UploadLayerPart", 
               "ecr:CompleteLayerUpload", 
               "ecr:PutImage"
          ], 
         "Resource": "arn:aws:ecr:eu-west-1:098765432123:repository/myname" 
   }] 
}

To create the policy, build out the following JSON and run a create-policy with it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
aws iam create-policy --policy-name EcrPushPullMynameDevelopers --policy-document file://./policy.json
    
    {
          "Policy": {
          "PolicyName": "EcrPushPullMynameDevelopers",
          "PolicyId": "ANPAITNBFTFWZMI4WFOY6",
          "Arn": "arn:aws:iam::098765432123:policy/EcrPushPullMynameDevelopers",
          "Path": "/",
          "DefaultVersionId": "v1",
          "AttachmentCount": 0,
          "PermissionsBoundaryUsageCount": 0,
          "IsAttachable": true,
          "CreateDate": "2018-10-25T12:00:15Z",
          "UpdateDate": "2018-10-25T12:00:15Z"
          }
    }

Then finally attach it:

1
aws iam attach-group-policy --group-name myname-developers --policy-arn arn:aws:iam::098765432123:policy/EcrPushPullMynameDevelopers

Use ECR images in Kubernetes

When we attached the IAM policy AmazonEC2ContainerRegistryReadOnly, it made every image available to every AWS account in the cluster.

To use it properly though, you should set the image field of the pod template on your manifest to point to it:

1
image: 098765432123.dkr.ecr.eu-west-1.amazonaws.com/myname:0.0.1.

Tagging images

All Docker images push to a registry needs to be identified by a tag. This should be any alphanumeric value.

It’s always good practice to add semantic versioning into tags.

MAJOR.MINOR.PATCH, such as 1.0.2.