Skip to main content
This guide walks through setting up an Amazon ECR mirror cache for images from cr.root.io. Once configured, your workloads pull Root images from your own ECR — reducing external network dependency, enabling lifecycle policies, and keeping image access within your AWS account.

What You’ll Achieve

  • Store cr.root.io images in your AWS account’s ECR
  • Reduce repeated external pulls with local caching
  • Handle mutable tags (:latest, :prod) with automatic change detection
  • Optionally pin to specific architectures (e.g., linux/amd64)

Prerequisites

  • AWS account ID and target region
  • Root registry credentials (cr.root.io)
  • A scheduler to run the mirroring job (cron, CI system, or Kubernetes CronJob)
  • Docker installed on the machine running the mirror script

Step 1: Authenticate to AWS

Choose one method:
# Option A: named profile
export AWS_PROFILE="your-profile-name"

# Option B: access keys
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."

# Required in both cases
export AWS_REGION="us-east-1"

Step 2: Choose Your ECR Naming Convention

Map Root image paths to ECR repository names. A consistent prefix keeps things organized:
SourceDestination
cr.root.io/python:3.12<ACCOUNT>.dkr.ecr.<REGION>.amazonaws.com/root-mirror/python:3.12
cr.root.io/node:20-slim<ACCOUNT>.dkr.ecr.<REGION>.amazonaws.com/root-mirror/node:20-slim

Step 3: Create ECR Repositories

aws ecr create-repository \
  --region $AWS_REGION \
  --repository-name root-mirror/python
Add a lifecycle policy to limit storage (retains the last 30 images):
aws ecr put-lifecycle-policy \
  --region $AWS_REGION \
  --repository-name root-mirror/python \
  --lifecycle-policy-text '{
    "rules": [{
      "rulePriority": 1,
      "selection": {
        "tagStatus": "any",
        "countType": "imageCountMoreThan",
        "countNumber": 30
      },
      "action": { "type": "expire" }
    }]
  }'
Alternatively, set AUTO_CREATE_REPOS=true in the mirror script to create repositories automatically (requires additional IAM permissions).

Step 4: IAM Permissions

Your IAM role or user needs:
{
  "Effect": "Allow",
  "Action": [
    "ecr:GetAuthorizationToken",
    "ecr:BatchCheckLayerAvailability",
    "ecr:InitiateLayerUpload",
    "ecr:UploadLayerPart",
    "ecr:CompleteLayerUpload",
    "ecr:PutImage"
  ],
  "Resource": "arn:aws:ecr:<REGION>:<ACCOUNT>:repository/root-mirror/*"
}
If using AUTO_CREATE_REPOS=true, also add ecr:CreateRepository and ecr:DescribeRepositories.

Step 5: Define Images to Mirror

Create images.txt. Each line specifies an image and optional architecture:
cr.root.io/python:3.12 amd64
cr.root.io/node:20-slim amd64
cr.root.io/nginx:1.25 amd64
cr.root.io/python:3.11
The optional architecture column prevents pulling the wrong platform variant, which is especially important when running the mirror job on macOS or ARM hosts.

Step 6: Run the Mirror Script

Set environment variables and run:
export AWS_REGION="us-east-1"
export AWS_ACCOUNT_ID="123456789012"
export ROOT_USER="root"
export ROOT_PASS="your-root-token"
export AUTO_CREATE_REPOS=true
export IMAGES_FILE=images.txt

chmod +x mirror_to_ecr.sh
./mirror_to_ecr.sh
The script:
  1. Resolves the source config digest from cr.root.io
  2. Resolves the destination config digest from ECR
  3. Skips images where digests match (already cached and current)
  4. Pulls, retags, and pushes only when the image has changed

Step 7: Update Workload References

# Before
spec:
  containers:
    - name: app
      image: cr.root.io/python:3.12

# After
spec:
  containers:
    - name: app
      image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/root-mirror/python:3.12
Create an ImagePullSecret if required:
kubectl create secret docker-registry ecr-pull-secret \
  --docker-server=123456789012.dkr.ecr.us-east-1.amazonaws.com \
  --docker-username=AWS \
  --docker-password=$(aws ecr get-login-password --region us-east-1) \
  --namespace=your-namespace

Step 8: Schedule the Mirror Job

Run the script regularly to pick up new Root Patches:
# Cron — every 30 minutes
*/30 * * * * /path/to/mirror_to_ecr.sh >> /var/log/root-mirror.log 2>&1
Or as a Kubernetes CronJob — package the script and images.txt into a container image and schedule it. For frequently-changing production tags, run every 15–30 minutes. For pinned versions, less often.

Networking

For workloads in private subnets, configure an ECR VPC endpoint to keep pulls entirely within your AWS network:
aws ec2 create-vpc-endpoint \
  --vpc-id vpc-xxx \
  --service-name com.amazonaws.us-east-1.ecr.dkr \
  --vpc-endpoint-type Interface

Troubleshooting

IssueSolution
401 from cr.root.ioVerify ROOT_PASS token hasn’t expired
Access Denied pushing to ECRCheck IAM permissions include ecr:PutImage and upload permissions
Repository not foundPre-create repos or set AUTO_CREATE_REPOS=true
Wrong architecture pulledAdd architecture column (amd64/arm64) to images.txt
Slow initial pullsFirst pull fetches from Root; subsequent pulls serve from ECR cache
For Root credential issues: support@root.io