Amazon recently announced its hosted EC2 Container Registry. Now that support for Amazon ECR has been released, we’re here to show you how you can integrate ECR into your CI/CD pipeline at Codeship.
ECR behaves similarly to a standard Docker registry where you can push and pull images and reference the registry when building your images. That being said, there are some differences between integrating Docker Hub or Quay and integrating with ECR. Let’s explore integrating with ECR, with a focus on Codeship tooling.
How It Works
Build on the reliable AWS infrastructure, Amazon provides a highly available container registry that integrates directly with the core AWS toolset. This sits behind standard AWS authentication and routing and allows you to easily co-locate your container images with your container cluster.
Quay and Docker Hub, which provide a single endpoint for interaction, use credentials to determine access and visibility. ECR provides a unique URL for each registry, which is tied to a specific user account. This means that different repositories may belong to different registries and have different URLs depending on what user account they were created under. The AWS CLI lets you specify this registry ID when creating repositories.
ECR is compatible with the Docker registry V2 API, which means you can run standard docker pull
and docker push
commands against your registry. However, this is protected by a layer of security.
In order to do a docker login
, you must use the AWS CLI to get a temporary login token, which you can configure to expire up to 36 hours. This means that standard practices of keeping a dockercfg with persistent registry credentials locally, and as part of your encrypted CI databag, will not work with for ECR. We’ll talk in more detail about how we solve this for the Codeship CI/CD pipeline later.
Getting Started
In order to begin using ECR and then integrate it with our CI/CD pipeline, we’ll need to first set up the AWS CLI, create a repository, and determine our registry URL.
To set up the AWS cli, follow the instructions in the AWS CLI docs and then run aws configure
to provide the tool with your AWS access credentials.
From here on, all ECR-related commands are available via the aws ecr
section and can be listed by running aws ecr help
:
$ aws ecr help NAME ecr - DESCRIPTION The Amazon EC2 Container Registry makes it easier to manage public and private Docker images for AWS or on-premises environments. Amazon ECR supports resource-level permissions to control who can create, update, use or delete images. Users and groups can be created individually in AWS Identity and Access Management (IAM) or federated with enterprise directories such as Microsoft Active Directory. Images are stored on highly durable AWS infrastructure and include built-in caching so that starting hundreds of containers is as fast as a single container. AVAILABLE COMMANDS o batch-check-layer-availability o batch-delete-image o batch-get-image o complete-layer-upload o create-repository o delete-repository o delete-repository-policy o describe-repositories o get-authorization-token o get-download-url-for-layer o get-login o get-repository-policy o help o initiate-layer-upload o list-images o put-image o set-repository-policy o upload-layer-part
Let’s start by creating a repository within our registry for a sample application, myuser/myapp
. This will allow us to push and pull images using the Docker cli and API.
$ aws ecr create-repository --repository-name myuser/myapp { "repository": { "registryId": "108487657846", "repositoryName": "myuser/myapp", "repositoryArn": "arn:aws:ecr:us-east-1:108487657846:repository/myuser/myapp" } }
We can now use the registryId
field to determine the registry URL via the template https://${REGISTRY_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com
. This will be needed later when referencing images. You can also get the registry URL from a generated ECR dockercfg.
Generating Credentials
Since ECR adheres to standard AWS authentication, you must use a secondary, temporary token rather than an AWS keypair in order to push or pull images. This can be accomplished by either generating a Docker login via the AWS cli or simply generating a Docker auth token which can be used to log in.
$ aws ecr get-login docker login -u AWS -p CiBwm0YaIyYjCVV+BAIBEICCAoo55cBYr9IBaPchhO8Ba0iPy8xRFuvIOSaw2yHVV/lE1/v5e9FZGck03lrA7q/rAFHRjvCrOdSS+/cvV2kpFv1drVEiMR9EEDRKdgLEw4ung3YrKDHqVZjXhxWaRiC2mFIKaDFNjyNYxY6Kmg5JCJTCwHRjOoWADJ0SJRDJdcqN8oKkyUvCEgW8idIWsFw5pjCLtQNtI2VX3XrnE8s5GLddQIsJOG3d1ak3a8LFzXUVb+V3eOysAuLtrCcZlPGyODZHI1nfcgcqjh16zeNitqRI2+H8G+kGAL2Xlbzwp8gVNkH+AX/vkbi0/1QFy/8KgyC7jvnn3+gedXqjNSW4sDS0yjCyp6pL+S4MVTkyq8fkrB/tdgRtJm5n1G6uqeekXuoXXPe5UFce9Rq8/14xKABgEBAgB4cJtGGiEiXkbSZuZ9RurqnnpF7qF1z3uVBXHvUavP9eMAAALXMIIC0wYsXHix4VRzWyzUbB8PANn/Qojf1oMQkQ2u15CZJ8Tol0LHgDi5/qGZ+wHTn+sz/dilpwlmrTuo+6avfZdfQy9r47+EPohNB0OquH03gt3fSjR5efU0ldE62VL/GrgHpgOH9qfSsCDvnKDuwfD5lFEIc3npcLh3djbcchTzCSqHdjAjgQgMQh54JSojL3TydS8WclKg6/W7wQIaozk+zfOoETPq90nO1UtT9QbBxbBBqL1JOs9Wu1owX1Ec9wS5oIuwXYNpHqDTA0EQTV4jZsZ335JMAijcM5GHN7MJ2ukOXOffonmHKoVdNJ7RpLBdz8moVKewhOF4jSh8GMbWu19W3uJsGHyS1oMfZz17whuWdetF77cf5cSUF7HXJEW77zDGRUVo0PWqg2CNEdCaonasScWKLQcT1AjhrQ+ctiXZcjoZGRRxFIZ8qR6t3lwn+sZIGszRkdhEI3lKW7EfZl4PfJVieip8m4sccbcetUzjLeSJeJKoZIhvcNAQcGoIICxDCCAsACAQAwggK5BgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDGyzVF8QSt9pZg9PIg== -e none https://108487657846.dkr.ecr.us-east-1.amazonaws.com
The generated command contains the URL for the ECR registry. This command can be directly executed via a subshell:
$ $(aws ecr get-login) WARNING: login credentials saved in /root/.docker/config.json Login Succeeded
Alternatively, you can manually generate a token using the AWS cli:
$ aws ecr get-authorization-token --query authorizationData[].authorizationToken --output text | base64 -d | cut -d: -f2 CiBwm0YaIyYjCVV+BAIBEICCAoo55cBYr9IBaPchhO8Ba0iPy8xRFuvIOSaw2yHVV/lE1/v5e9FZGck03lrA7q/rAFHRjvCrOdSS+/cvV2kpFv1drVEiMR9EEDRKdgLEw4ung3YrKDHqVZjXhxWaRiC2mFIKaDFNjyNYxY6Kmg5JCJTCwHRjOoWADJ0SJRDJdcqN8oKkyUvCEgW8idIWsFw5pjCLtQNtI2VX3XrnE8s5GLddQIsJOG3d1ak3a8LFzXUVb+V3eOysAuLtrCcZlPGyODZHI1nfcgcqjh16zeNitqRI2+H8G+kGAL2Xlbzwp8gVNkH+AX/vkbi0/1QFy/8KgyC7jvnn3+gedXqjNSW4sDS0yjCyp6pL+S4MVTkyq8fkrB/tdgRtJm5n1G6uqeekXuoXXPe5UFce9Rq8/14xKABgEBAgB4cJtGGiEiXkbSZuZ9RurqnnpF7qF1z3uVBXHvUavP9eMAAALXMIIC0wYsXHix4VRzWyzUbB8PANn/Qojf1oMQkQ2u15CZJ8Tol0LHgDi5/qGZ+wHTn+sz/dilpwlmrTuo+6avfZdfQy9r47+EPohNB0OquH03gt3fSjR5efU0ldE62VL/GrgHpgOH9qfSsCDvnKDuwfD5lFEIc3npcLh3djbcchTzCSqHdjAjgQgMQh54JSojL3TydS8WclKg6/W7wQIaozk+zfOoETPq90nO1UtT9QbBxbBBqL1JOs9Wu1owX1Ec9wS5oIuwXYNpHqDTA0EQTV4jZsZ335JMAijcM5GHN7MJ2ukOXOffonmHKoVdNJ7RpLBdz8moVKewhOF4jSh8GMbWu19W3uJsGHyS1oMfZz17whuWdetF77cf5cSUF7HXJEW77zDGRUVo0PWqg2CNEdCaonasScWKLQcT1AjhrQ+ctiXZcjoZGRRxFIZ8qR6t3lwn+sZIGszRkdhEI3lKW7EfZl4PfJVieip8m4sccbcetUzjLeSJeJKoZIhvcNAQcGoIICxDCCAsACAQAwggK5BgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDGyzVF8QSt9pZg9PIg==
You can then use the returned authorization token in the same docker login
command aws ecr get-login
generates.
Authentication with ECR in Codeship
Traditionally, static Docker credentials are encoded in the project databag and decrypted in order to push or pull images from a registry.
Due to the short-lived nature of ECR credentials, Codeship has added support for dockercfg generation services. You can now specify a service with which to generate a dockercfg for authenticating a specific service or step. You can find out more about this in the Codeship documentation. For the purposes of ECR support, we maintain a Docker image that you can extend or use directly.
A typical integration involves defining a service to generate a dockercfg for your registry in your services file and listing that as the authentication source for specific services and/or steps.
# codeship-services.yml app: build: image: 108487657846.dkr.ecr.us-east-1.amazonaws.com/myuser/myapp dockerfile_path: ./Dockerfile aws_generator: image: codeship/aws-ecr-dockercfg-generator encrypted_env_file: aws_creds.encrypted # contains Secret, AccessKey and Region add_docker: true
# codeship-steps.yml - type: push service: app registry: https://108487657846.dkr.ecr.us-east-1.amazonaws.com image_name: 108487657846.dkr.ecr.us-east-1.amazonaws.com/myuser/myapp dockercfg_service: aws_generator
The aws_generator
service will be run as needed and provides credentials to allow Codeship to interact with your ECR registry. In this example, we’re simply building an image and having our CD pipeline push it to ECR.
Using ECR Base Images and Caching
Along with explicitly pushing images to ECR as part of your pipeline, you can leverage your registry to host private base images used during a Codeship build.
In this case, as long as the step or service referencing the image being built references the dockercfg_service
, and the FROM
declaration in your Dockerfile references the full ECR image name, the build will work. Similarly, this will allow you to use ECR to populate your local Docker image cache during builds by specifying cached: true
on relevant services.
# Dockerfile FROM 108487657846.dkr.ecr.us-east-1.amazonaws.com/myuser/myapp ADD ./ /opt/app
# codeship-services.yml app: build: image: myuser/myapp dockerfile_path: ./Dockerfile dockercfg_service: aws_generator cached: true aws_generator: image: codeship/aws-ecr-dockercfg-generator encrypted_env_file: aws_creds.encrypted # contains Secret, AccessKey and Region
Conclusion
Using dockercfg generator services from Codeship and integrating your existing CI/CD pipeline with ECR is a simple task. By adding a generator service, updating your image names, and replacing any existing dockercfg references with references to the new dockercfg generator service, you can push your images to ECR without making complex changes to your pipeline.
With the ability to co-locate your image registry with your containers, ECR is a powerful tool to help speed up the deployment and scaling of your AWS infrastructure.