Back in November 2021 AWS announced that you can cache containers from DockerHub through to ECS.
Announcing Pull Through Cache Repositories for Amazon Elastic Container Registry
However, it comes with this little fine print which in my situation it's just not going to float.
The solution
It's easy to set this up using CodeBuild & Event Bridge all wrapped up in a Cloudformation Stack!
Here are resources/services we will be working with.
- A nightly Event Bridge rule will trigger the CodeBuild Project
- Codebuild project will perform the interaction with DockerHub for the target container image and sync the latest 5 tags
The Cloudformation Stack
The stack requires two parameters
- ImageRepoName - DockerHub Image Repo name
hashicorp/terraform
- ImageTagCount - Number of tags to retrive
2
---
AWSTemplateFormatVersion: 2010-09-09
Description: Creates a CodeBuild project to sync containers from DockerHub
Parameters:
ImageRepoName:
Description: 'Target Image Repo, this name should be identical to the one hosted on DockerHub'
Type: String
Default: 'hashicorp/terraform'
ImageTagCount:
Description: 'The number of tags to keep updated, simple head from curl output to query tags on DockerHub'
Type: Number
Default: 2
Resources:
Repository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Ref ImageRepoName
ImageScanningConfiguration:
ScanOnPush: true
CodeBuild:
Type: AWS::IAM::Role
Properties:
RoleName: !Join
- '-'
- - !Ref 'AWS::StackName'
- CodeBuild
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
-
Action: 'sts:AssumeRole'
Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Policies:
- PolicyName: ECR
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- ecr:BatchCheckLayerAvailability
- ecr:CompleteLayerUpload
- ecr:GetAuthorizationToken
- ecr:InitiateLayerUpload
- ecr:PutImage
- ecr:UploadLayerPart
Effect: Allow
Resource: '*'
- PolicyName: LogGroup
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Effect: Allow
Resource: !Sub 'arn:aws:logs:ap-southeast-2:${AWS::AccountId}:log-group:/aws/codebuild/*'
DockerHubSync:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: NO_ARTIFACTS
Source:
Type: NO_SOURCE
BuildSpec: |
version: 0.2
phases:
pre_build:
commands:
- echo "Logging in to Amazon ECR..."
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
build:
commands:
- echo "Retrieving Docker image tags..."
- TAGS=$(curl -L -s https://registry.hub.docker.com/v2/repositories/${IMAGE_REPO_NAME}/tags | jq '."results"[]["name"]' | head -n${IMAGE_TAG_COUNT} | sed s'/"//g')
- for TAG in $TAGS; do docker pull $IMAGE_REPO_NAME:$TAG;done
- for TAG in $TAGS; do docker tag $IMAGE_REPO_NAME:$TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$TAG;done
post_build:
commands:
- echo "Pushing image tags to ECR..."
- for TAG in $TAGS; do docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$TAG;done
Environment:
ComputeType: "BUILD_GENERAL1_SMALL"
Image: "aws/codebuild/standard:5.0"
Type: "LINUX_CONTAINER"
PrivilegedMode: true
EnvironmentVariables:
- Name: AWS_DEFAULT_REGION
Type: PLAINTEXT
Value: "ap-southeast-2"
- Name: AWS_ACCOUNT_ID
Type: PLAINTEXT
Value: !Ref AWS::AccountId
- Name: IMAGE_TAG_COUNT
Type: PLAINTEXT
Value: !Ref ImageTagCount
- Name: IMAGE_REPO_NAME
Type: PLAINTEXT
Value: !Ref ImageRepoName
Description: !Sub 'Run ${ImageRepoName} image tags repo sync from Dockerhub to local ECR repo'
ServiceRole: !GetAtt CodeBuild.Arn
TimeoutInMinutes: 300
LogGroup:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: !Sub '/aws/codebuild/${DockerHubSync}-${ImageRepoName}'
RetentionInDays: 3
EventRole:
Type: AWS::IAM::Role
Properties:
Description: IAM role to allow Amazon CloudWatch Events to trigger AWS CodeBuild build
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: events.amazonaws.com
Policies:
- PolicyDocument:
Statement:
- Action: codebuild:StartBuild
Effect: Allow
Resource: !GetAtt 'DockerHubSync.Arn'
PolicyName: !Join
- '-'
- - !Ref 'AWS::StackName'
- CloudWatchEventPolicy
RoleName: !Join
- '-'
- - !Ref 'AWS::StackName'
- CloudWatchEventRule
NightlyEvent:
Type: AWS::Events::Rule
Properties:
Description: Rule for Amazon CloudWatch Events to trigger a build every night
ScheduleExpression: "cron(0 0 * * ? *)"
Name: !Join
- '-'
- - !Ref 'AWS::StackName'
- NightlyBuild
State: ENABLED
Targets:
- Arn: !GetAtt 'DockerHubSync.Arn'
Id: NightlyCheck
RoleArn: !GetAtt 'EventRole.Arn'
Once the stack has been created, the codebuild job will kick off on the schedule and perform the sync.
The output will look something like this.
[Container] 2022/06/01 00:01:30 Running command echo "Retrieving Docker image tags..."
Retrieving Docker image tags...
[Container] 2022/06/01 00:01:30 Running command TAGS=$(curl -L -s https://registry.hub.docker.com/v2/repositories/${IMAGE_REPO_NAME}/tags | jq '."results"[]["name"]' | head -n${IMAGE_TAG_COUNT} | sed s'/"//g')
[Container] 2022/06/01 00:01:32 Running command for TAG in $TAGS; do docker pull $IMAGE_REPO_NAME:$TAG;done
latest: Pulling from hashicorp/terraform
2408cc74d12b: Pulling fs layer
86c08b1682e5: Pulling fs layer
89232a3d66c3: Pulling fs layer
2408cc74d12b: Verifying Checksum
2408cc74d12b: Download complete
86c08b1682e5: Verifying Checksum
86c08b1682e5: Download complete
89232a3d66c3: Verifying Checksum
89232a3d66c3: Download complete
2408cc74d12b: Pull complete
86c08b1682e5: Pull complete
89232a3d66c3: Pull complete
Digest: sha256:8aecb79b6197269722e2e3fba5040756135d20427da395a0f9883bb0927e16d1
Status: Downloaded newer image for hashicorp/terraform:latest
docker.io/hashicorp/terraform:latest
light: Pulling from hashicorp/terraform
Digest: sha256:8aecb79b6197269722e2e3fba5040756135d20427da395a0f9883bb0927e16d1
Status: Downloaded newer image for hashicorp/terraform:light
docker.io/hashicorp/terraform:light
And here are our containers, in our private repo for consumption
Hope this helps someone else
Cheers!
For more articles on ECS click here!](https://sjramblings.io/tag/ecs)