Skip to main content

Overview

ECR (Elastic Container Registry) stores your Docker container images for ECS deployments. Fjall automatically creates and manages ECR repositories when you use ComputeFactory with type: "ecs" - you typically don’t need to create them manually.

Automatic Management

When you deploy ECS containers with Fjall, ECR repositories are automatically:
  • Created with your application name
  • Configured with image scanning
  • Set up with lifecycle policies
  • Granted access to your ECS tasks
// Fjall handles ECR automatically
const api = app.addCompute(
  ComputeFactory.build("API", {
    type: "ecs",
    ecsType: "fargate",
    // ECR repository created automatically
  })
);

Pushing Images

Using Docker CLI

# Login to ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin \
  123456789012.dkr.ecr.us-east-1.amazonaws.com

# Build and tag image
docker build -t myapp .
docker tag myapp:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# Push to ECR
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

In CI/CD Pipeline

# GitHub Actions example
- name: Login to Amazon ECR
  uses: aws-actions/amazon-ecr-login@v1

- name: Build and push
  env:
    ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
    ECR_REPOSITORY: myapp
    IMAGE_TAG: ${{ github.sha }}
  run: |
    docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
    docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

Manual Repository Creation

Only create explicit ECR repositories if you need:
  • Shared repositories across multiple applications
  • Custom lifecycle or scanning policies
  • Cross-account repository access
import { Repository } from "aws-cdk-lib/aws-ecr";

const sharedRepo = new Repository(this, "SharedImages", {
  repositoryName: "shared-base-images",
  imageScanOnPush: true,
  lifecycleRules: [
    {
      maxImageCount: 10,
      description: "Keep only 10 images",
    },
  ],
});

Using Custom Repositories

Specify Repository in ComputeFactory

import { Repository } from "aws-cdk-lib/aws-ecr";

const customRepo = Repository.fromRepositoryName(
  this,
  "CustomRepo",
  "my-custom-repo"
);

const api = app.addCompute(
  ComputeFactory.build("API", {
    type: "ecs",
    ecsType: "fargate",
    ecrRepository: customRepo,
  })
);

Use Specific Image Tag

import { RepositoryImage } from "aws-cdk-lib/aws-ecs";

const api = app.addCompute(
  ComputeFactory.build("API", {
    type: "ecs",
    ecrRepository: RepositoryImage.fromEcrRepository(
      Repository.fromRepositoryName(this, "Repo", "myapp"),
      "v1.2.3"
    ),
  })
);

Lifecycle Policies

Keep recent images, remove old ones:
const repo = new Repository(this, "Repo", {
  lifecycleRules: [
    {
      description: "Keep last 5 production images",
      tagPrefixList: ["prod"],
      maxImageCount: 5,
    },
    {
      description: "Expire untagged images after 7 days",
      maxImageAge: Duration.days(7),
      tagStatus: TagStatus.UNTAGGED,
    },
  ],
});

Image Scanning

Automatically scan for vulnerabilities:
const repo = new Repository(this, "Repo", {
  imageScanOnPush: true, // Scan every pushed image
});

Lambda Container Images

Use ECR for Lambda container images:
import { Repository } from "aws-cdk-lib/aws-ecr";
import { Runtime, Code } from "aws-cdk-lib/aws-lambda";

const lambdaRepo = Repository.fromRepositoryName(
  this,
  "LambdaImages",
  "lambda-containers"
);

const containerLambda = app.addCompute(
  ComputeFactory.build("Worker", {
    type: "lambda",
    code: Code.fromEcrImage(lambdaRepo, {
      tagOrDigest: "latest",
    }),
    handler: Handler.FROM_IMAGE,
    runtime: Runtime.FROM_IMAGE,
  })
);

Cross-Account Access

Share images with other AWS accounts:
import { AccountPrincipal } from "aws-cdk-lib/aws-iam";

repo.grantPull(new AccountPrincipal("123456789012"));

Repository URLs

Get repository information:
// Repository ARN
console.log(repo.repositoryArn);
// arn:aws:ecr:us-east-1:123456789012:repository/myapp

// Repository URI
console.log(repo.repositoryUri);
// 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp

// Use in environment variables
const api = app.addCompute(
  ComputeFactory.build("API", {
    type: "ecs",
    containerEnvironment: {
      IMAGE_REPO: repo.repositoryUri,
    },
  })
);

Best Practices

  • Let Fjall manage ECR for standard ECS deployments
  • Enable image scanning to detect vulnerabilities
  • Use lifecycle policies to limit storage costs
  • Tag images with version numbers (e.g., v1.2.3, git SHA)
  • Use separate repos for different applications
  • Implement CI/CD for automated image builds
  • Monitor scan results and update base images regularly

Common Issues

Image Pull Errors

If ECS can’t pull images:
  • Verify ECR repository exists in the same region
  • Check ECS task role has ECR pull permissions (Fjall handles this automatically)
  • Ensure image tag exists in repository
  • Confirm repository name matches configuration

Large Image Sizes

Optimize image size:
  • Use multi-stage Docker builds
  • Choose minimal base images (alpine, distroless)
  • Remove unnecessary files and dependencies
  • Combine RUN commands to reduce layers

See Also