In private with Docker– Amazon Elastic Container Registry

Adrian Piętka
Nov 11, 2020 - 10 min read

Docker has become ubiquitous in projects I work on. It helps maintain consistent development environments and makes it easy to experiment with external services. Most importantly, in the context of this article, Docker enables the creation of final application artifacts.

Every application release can be packaged as a Docker Image, named and tagged with the appropriate version number, and published into an image registry like Docker Hub or the above-mentioned AWS ECR. Using these registries it becomes easy to build a database of application releases, each of which can be launched in a Docker container with a single docker run.

In this article, I will show you how to start working with one of these private Docker Image registries - the AWS ECR.

What is ECR?

Elastic Container Registry (or ECR in short) is a managed private registry for Docker Images. It works in a similar manner to Docker Hub, save for one key difference, which is that ECR ONLY works with PRIVATE images, so they cannot be accessed without authorization. ECR lets the users store and download images using the Docker CLI.

ECR is part of the AWS platform and makes it easy to run containerized applications with services like ECS (Amazon Elastic Container Service), EKS (Amazon Elastic Kubernetes Service) or AWS Elastic Beanstalk.

AWS CLI

The primary way to work with AWS services is the AWS Console, which can be used to perform virtually any management task through its web-based interface.

For simple interactions with AWS services, however, I would recommend the AWS CLI. It is a command-line tool that becomes very intuitive with use. Be sure to check the well-written installation and configuration instructions in the AWS documentation if you’re interested.

Creating a repository

To start working with the ECR service, we are going to need a new repository, which will become the target space for publishing our image versions. Keep in mind that one repository is designed to hold one Docker image, so if a solution is packaged into multiple Docker images, each of them will have to be placed in a separate repository.

Let’s create our first repository, called hello-api:

$: aws ecr create-repository --repository-name hello-api

Executing this command results in a response like this:

{
    "repository": {
        "repositoryArn": "arn:aws:ecr:eu-west-1:022084067179:repository/hello-api",
        "registryId": "022084067179",
        "repositoryName": "hello-api",
        "repositoryUri": "022084067179.dkr.ecr.eu-west-1.amazonaws.com/hello-api",
        "createdAt": 1578320155.0
    }
}

The strange-looking 02208406717 number is the so-called AWS Account ID and it is strictly tied to your AWS account. The content of the repositoryUri field can be used to download the image.

To list the available repositories you can use the following command:

$: aws ecr describe-repositories

In my case, two repositories show up, including the one we just created:

{
     "repositories": [
        {
            "repositoryArn": "arn:aws:ecr:eu-west-1:022084067179:repository/hello-ui",
            "registryId": "022084067179",
            "repositoryName": "hello-ui",
            "repositoryUri": "022084067179.dkr.ecr.eu-west-1.amazonaws.com/hello-ui",
            "createdAt": 1557145046.0
        },
        {
            "repositoryArn": "arn:aws:ecr:eu-west-1:022084067179:repository/hello-api",
            "registryId": "022084067179",
            "repositoryName": "hello-api",
            "repositoryUri": "022084067179.dkr.ecr.eu-west-1.amazonaws.com/hello-api",
            "createdAt": 1578320155.0
        }
   ]
}

Authorization

When you use the AWS CLI you are by default only allowed to create, list and modify services in your own account. To publish and download Docker images you have to authorize with the AWS ECR service. This allows the Docker client to communicate directly with the registry. To do this, use the following command:

$: $(aws ecr get-login --no-include-email)

Running this command is all that is needed to enable the docker pull and docker push commands that are used to download and publish images, respectively.

One more way to authorize is by using the Docker Credential Helper. I will not cover this in detail here, as this article focuses only on the basics of AWS ECR usage, but feel free to read about it in this AWS blog post.

Publishing an image into the registry

For the example, I will use one of my existing applications, described in my article about Docker and AWS CloudWatch.

Let’s start by building the application image:

$: docker build --tag hello-api:1.0.0 .

The result is a locally built image which needs to be tagged with a prefix that will contain our ECR domain. For this, we can use the value of the repositoryUri field, as returned when we created the repository.

$: docker tag hello-api:1.0.0 022084067179.dkr.ecr.eu-west-1.amazonaws.com/hello-api:1.0.0

Publishing to the ECR registry is then done using the _docker push _command. All we need to provide is the tag above and the locally built application image gets uploaded to the registry.

$: docker push 022084067179.dkr.ecr.eu-west-1.amazonaws.com/hello-api:1.0.0

To check the result in the registry, you can use the following command:

$: aws ecr list-images --repository-name hello-api

The result is a list of images that are present in the repository:

{
    "imageIds": [
        {
            "imageDigest": "sha256:e64fdf05d31008939c478d84665bd2d23519a4dd98a1e3d18f6747ae04d357ce",
            "imageTag": "1.0.0"
        }
    ]
}

Alternatively, you can also use the describe-images command, which will provide more comprehensive information about images, including file sizes and more:

$: aws ecr describe-images --repository-name hello-api

Running this gets us:

{
    "imageDetails": [
        {
            "registryId": "022084067179",
            "repositoryName": "hello-api",
            "imageDigest": "sha256:e64fdf05d31008939c478d84665bd2d23519a4dd98a1e3d18f6747ae04d357ce",
            "imageTags": [
                "1.0.0"
            ],
            "imageSizeInBytes": 24349083,
            "imagePushedAt": 1578339891.0
        }
    ]
}

One way or another, you can see the operations were successful and the image was published into the repository.

Downloading images from the registry

Since we have successfully authorized into the private registry, we can also download the images we need. To do this, we use the docker pull command and provide the full address of the registry followed by the image name:

$: docker pull 022084067179.dkr.ecr.eu-west-1.amazonaws.com/hello-api:1.0.0

What is left for us to do is to verify if the application we downloaded starts properly. We can do this using the run command:

$: docker run -p 3000:3000 022084067179.dkr.ecr.eu-west-1.amazonaws.com/hello-api:1.0.0

As a result, a container is launched, based on the image downloaded from our own private Docker registry created with the AWS Elastic Container Registry:

> [email protected] start /usr/src/app
> node index.js

{"level":30,"time":1605467776097,"msg":"Server listening at http://0.0.0.0:3000","pid":21,"hostname":"0e16a3d0ea4f","v":1}
{"level":30,"time":1605467776098,"msg":"server listening on 3000","pid":21,"hostname":"0e16a3d0ea4f","v":1}

So by now we have successfully created a Docker image of an application; published it into a private image registry; downloaded it back and run it in a container. By doing this we have in fact closed the loop of a basic deployment process - from the creation of an artifact, through cloud-based distribution, to the launching of a working application.

Further features of the AWS ECR

AWS ECR is more than a simple repository tool and goes well beyond what we covered above. Especially as its functionality keeps growing and becomes more refined over time. Among its more advanced features, I would especially recommend you to check out:

  • Helm Chart – support for publishing of Open Container Initiative (OCI) artifacts, including Helm Charts
  • Lifecycle policies – which can be used to define useful rules, for example to determine when images should be automatically deleted from the registry
  • Image scanning – a great way to check the software included in published images for known security vulnerabilities
  • Tag immutability – a mechanism that can protect tagged images from modification and overwriting

These additional features can truly make it easier to work with Docker Images.

Summary

As with many AWS services, ECR is offered with a limited free plan which gets you 500 MB of storage space for a year. Outgoing traffic, so in this case image downloads, remains free up to 1 GB per month. Beyond these limits, every 1 GB of transfer will cost you 0.09 USD (but this rate gets lower as the transfer volume increases) and each 1 GB of additional storage space you use is 0.10 USD.

Thanks to the ECR, we can quickly create a repository for private images. As an AWS service, ECR readily integrates with other services available on the platform. Advanced functions of the ECR help automate processes such as image life cycle management and software vulnerability scanning, greatly improving security.

The advanced features are not available for free, but in my experience, stemming from maintaining multiple projects and several dozen images over the last two years, the costs are not too high. In this age of clouds and containerization, ECR is well worth its price and definitely worth trying out.

Adrian Piętka
Chief Technology Officer

Designs, creates and implements solutions based on Node.js. Adrian publishes about this technology within his own initiative named NodeStart. He is also a founder and co-owner of DevEnv - a podcast, YouTube channel and knowledge sharing platform for developers.