[EN] Set Up Amazon ECR Pull-Through Cache for Docker Hub
![[EN] Set Up Amazon ECR Pull-Through Cache for Docker Hub](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fuploads%2Fcovers%2F631dd8693e8d6f3497ad63e7%2F1ca35a5a-6303-4a86-badb-91961cf65694.jpg&w=3840&q=75)
The Problem
The developers are actively build and test their projects. There are dozens of projects that can be built in a day. This sometimes causes the disk of the CI/CD system (e.g., Jenkins, self-hosted runner) to be full, so we always delete unused images and build cache after each build. When a project needs to be rebuilt, it has to pull the base images from Docker Hub. But there is a rate limit from dockerhub, 100 pulls/6h unauthenticated, 200 authenticated per IPv4 address. If we use more than this, the build pipeline will fail.
The Solution
Because I use AWS, I can utilize AWS ECR pull-through cache to pull images from dockerhub, store them in ECR, then I can pull unlimited images from ECR. No dependency on Docker Hub uptime/rate limits. If Hub goes down, you can still pull (assuming the image you need is already cached on ECR). However, ECR storage cost for cached images. Mitigate it with lifecycle policies to evict old/unused tags.
Create a Docker Hub personal access token
This will be used by ECR to login to the Dockerhub. Token is used instead of your Docker hub password.
Log into Docker Hub
Navigate to Account Settings > Settings > Personal access tokens
Click the "Generate new token" button
Fill the token description, set the expiration date, and the permissions. Usually, I only give read-only permission.
Write down the generated PAT for the next step in AWS configuration.
Setting up the ECR pull-through rule
First, you need to store your Docker Hub credentials in AWS Secrets Manager with a specific naming convention. Use this AWS CLI command:
aws secretsmanager create-secret \ --name "ecr-pullthroughcache/docker-hub" \ --description "Docker Hub credentials for ECR pull through cache" \ --secret-string '{ "username": "<your-docker-username>", "accessToken": "<your-docker-access-token>" }' \ --region <region>Important: The secret name must use the
ecr-pullthroughcache/prefix and be in the same account and region as your pull-through cache rule.Proceed with creating the pull-through rule. You can use this AWS CLI command:
aws ecr create-pull-through-cache-rule \ --ecr-repository-prefix docker-hub \ --upstream-registry-url registry-1.docker.io \ --credential-arn <secretsmanager-arn-you-got-from-the-previous-command> \ --region <region>Or, if you prefer to use the console, navigate to ECR > Private Registry > Pull through cache > Add Rule.
Set the Upstream registry to Docker Hub.
In the Authentication section, select the Use an existing AWS secret and select the secret created in step 1. Note that you can also skip step 1 and create the secrets from here if you use the console.
In the Step 3: Specify namespaces, configure the prefix configuration for both the cache and upstream namespace. I usually select use a specific prefix for the namespace, and no prefix in the Upstream namespace.
On Step 4: Review and create, review your configuration and choose Create
Pull the image through the cache
# Login to the ECR private registry
aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <your-acc-id>.dkr.ecr.<region>.amazonaws.com
# Pull an image from docker hub:
docker pull aws_account_id.dkr.ecr.region.amazonaws.com/docker-hub/library/image_name:tag
Notice the library in the repository URL is specific to Docker Hub's official images and reflects how Docker Hub organizes its repositories internally.
# Original Docker Hub command:
docker pull nginx:latest
docker pull alpine:3.23.4
# ECR pull-through cache equivalent:
docker pull aws_account_id.dkr.ecr.region.amazonaws.com/docker-hub/library/nginx:latest
When you pull these images, ECR creates repositories with these exact names:
docker-hub/library/nginxdocker-hub/library/alpine
Setting up the Repository Policy
I personally use a repository policy template to automatically apply a policy when ECR create Dockerhub pull-through repository. Such as, to only keep the last 6 images.
Navigate to ECR > Private Registry > Features & Settings > Repository creation templates > Configure > Create Template.
On Step 1: Define template > Template details > Applied for select the
Pull through cache. Because I use a prefix in the previous step, I select the Aspecific prefixand set the prefix there.On Step 2: Add repository creation configuration > Repository lifecycle policy, you can select predefined templates in the Lifecycle policy examples.
On Step 4: Review and create, review your configuration and choose Create
Now, if you pull a Dockerhub image through ECR, a lifecycle policy will be automatically applied.
![[EN] Track progress of MySQL Import/Export process using PV](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2Fjf1EomjlQi0%2Fupload%2Fa7ee07f61c1dc2ad71b4cf2bb4523765.jpeg&w=3840&q=75)
![[EN] Lesson learned from using the wrong AWS ElastiCache Redis endpoint](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2FemolMCqnKfg%2Fupload%2Fc7eb8197eb9ef632459ae6612b861cc6.jpeg&w=3840&q=75)
![[EN] My experience taking the KCNA certification](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2FKXwPJtAJLfU%2Fupload%2F3deba4b52e1b8e442179a495944ccb9e.jpeg&w=3840&q=75)
![[EN] How I Stopped Copy-Pasting AWS EC2 IPs and Started SSHing Smarter](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2FDXRP2PKlsFQ%2Fupload%2F8767e91ce57fa7ff90bca9149c142626.jpeg&w=3840&q=75)