Skip to main content
Cloud DevOps Solutions
Get a quote Talk to an engineer

Docker & Containerization

Private Container Registry Setup on ECR, ACR and Artifact Registry

A private container registry stores your images under your own access control. We set up ECR, ACR or Google Artifact Registry (the successor to GCR) with least-privilege access, immutable tags, lifecycle policies, scanning and CI push permissions, then connect it to your clusters.

Key takeaways

  • Use the registry native to your cloud: it integrates with IAM, networking and your clusters.
  • Immutable tags and digest-based deploys prevent a tag from silently changing underneath production.
  • Lifecycle policies control storage cost without deleting images that are still running.
  • CI pushes and clusters pull using short-lived, scoped identities, not shared passwords.
  • Google Container Registry has been superseded by Artifact Registry, so new setups should use the latter.

Why a private registry deserves attention

Many teams start by pushing images to a personal Docker Hub account and pulling them onto servers. It works until a rate limit blocks a production deploy, an engineer leaves with the only credentials, or someone discovers that an internal image with embedded configuration was public. A private registry in your own cloud account solves these problems, but only if access, retention and networking are designed rather than left at defaults.

This is part of our Docker containerisation service, and it usually sits beside work on Kubernetes on EKS or other clusters.

What good looks like

  • One repository per deployable service, with a consistent naming convention.
  • CI is the only identity that pushes to production repositories.
  • Clusters pull using cloud identity, not static passwords.
  • Tags are immutable, and deployments reference a version or digest.
  • Images are scanned on push, and old images expire automatically.
  • Everything is defined as code and reviewable.

Choosing the registry

CloudRegistryNotes
AWSAmazon ECRTight IAM integration, repository policies, lifecycle policies, pull-through cache
AzureAzure Container RegistryIntegrates with Microsoft Entra ID and AKS, tiers differ in features
Google CloudArtifact RegistryReplaces Container Registry (GCR), supports multiple package formats
Multi-cloud or self-hostedHarborOpen source, more control, more to operate

If you are on one cloud, use its registry. The integrations with IAM, private networking and the managed Kubernetes service save real effort.

An ECR example

This Terraform sketch creates a repository with immutable tags, scan on push, encryption and a lifecycle rule:

resource "aws_ecr_repository" "api" {
  name                 = "platform/api"
  image_tag_mutability = "IMMUTABLE"

  image_scanning_configuration {
    scan_on_push = true
  }

  encryption_configuration {
    encryption_type = "KMS"
  }
}

resource "aws_ecr_lifecycle_policy" "api" {
  repository = aws_ecr_repository.api.name
  policy = jsonencode({
    rules = [{
      rulePriority = 1
      description  = "Expire untagged images after 14 days"
      selection = {
        tagStatus   = "untagged"
        countType   = "sinceImagePushed"
        countUnit   = "days"
        countNumber = 14
      }
      action = { type = "expire" }
    }]
  })
}

For release tags we add a second rule that keeps the last N tagged images, sized to your rollback window. The exact tagPrefixList or tagPatternList depends on how you name versions, so we set it after reviewing your release process.

Access: who pushes and who pulls

Push. Your pipeline authenticates through OIDC federation to a role allowed to push to specific repositories only. No long-lived access keys sit in CI variables. Developers can push to a sandbox repository but not to production ones.

Pull. Clusters pull through node roles or workload identity. Production nodes get read-only access to production repositories. Cross-account pulls are granted explicitly with repository policies.

Network. For stricter environments, we add private endpoints so image pulls never traverse the public internet, which also reduces NAT gateway data charges in some AWS designs.

Repository layout and naming

Layout decisions are cheap on day one and expensive later, because every manifest, pipeline and policy refers to the names. We usually recommend one repository per deployable service, grouped by team or product with a path prefix such as platform/api, and a separate prefix for mirrored third-party images. Environments should not get their own repositories: you promote the same image by digest or tag, and the environments differ only in configuration. Keeping a clear boundary between “built by us”, “mirrored from upstream” and “scratch or sandbox” also makes access policy simpler, because each group has different rules about who may push.

Day-two operations

A registry needs a little ongoing care. Someone should review who can push, check that lifecycle rules still match the release cadence, and watch for repositories that nobody owns. Scan findings on stored images should flow into a backlog, since an image that was clean at push time can acquire a new advisory later, as covered in scanning in CI/CD. We also test the unhappy paths once: a pull with an expired credential, a pull from a node without access, and a push to a repository the pipeline should not reach. Each should fail clearly, with an error message your on-call engineer can act on.

Cross-account and multi-environment access

Many organisations separate production into its own cloud account. The registry then lives in a shared account or in the production account, and other accounts need explicit permission to pull. We define this with repository policies and roles in code, test the pull from each environment, and avoid broad organisation-wide grants. The same discipline applies on Azure and Google Cloud, with role assignments instead of policies. When this is set up as Terraform, an access change becomes a reviewed pull request rather than a console click that nobody remembers.

Decisions and trade-offs

Pull-through caches for public images (ECR supports this for several upstream registries) remove Docker Hub rate limit failures and give you a place to scan third-party images. They add configuration, but for any team with frequent node churn it is worth it.

Replication. Multi-region ECR replication or ACR geo-replication shortens pulls and improves resilience for multi-region deployments. It also increases storage cost, so we enable it only where there is a real need.

Harbor or a cloud registry? Harbor gives you features like project-level policies and proxy caching in one place, but you run it. Most startups should not.

Migrating from GCR. Container Registry has been superseded by Artifact Registry. We map repositories, copy images, update references in manifests and pipelines, and switch over in stages.

Common failure modes

  • Lifecycle rules deleting images that are still deployed, causing pull failures when a pod reschedules. We protect tags that production references.
  • Mutable latest tags deployed to production. We forbid it by policy.
  • Overly broad access, such as ecr:* on all repositories. We scope by repository.
  • Forgotten cross-region pulls, causing slow deploys and transfer cost.

Registries also anchor your supply chain: scanning is described in Trivy scanning in CI/CD, and signatures are stored alongside images as covered in image signing with Cosign.

Delivery and handover

We deliver the registry as Terraform in your repository, CI push configuration, cluster pull configuration and a short access runbook. Costs and ownership of each repository are documented. If you want help planning the layout, book a consultation.

How to tell it is working

Deploys never fail on image pull rate limits or expired credentials, no human credentials can push to production, storage cost stays flat as releases accumulate, and every running image can be traced back to a build in your CI.

References

How we deliver it

  1. 01

    Choose the registry model

    We select ECR, ACR or Artifact Registry to match your cloud, and decide repository layout and naming.

  2. 02

    Define access

    Separate push identities for CI and pull identities for clusters, with least-privilege policies and no human push to production repositories.

  3. 03

    Protect the images

    Immutable tags, encryption, scan on push and, where needed, private networking endpoints.

  4. 04

    Control cost and clutter

    Lifecycle rules expire untagged and old images, with protection for tags in use.

  5. 05

    Wire up CI and clusters

    Pipelines authenticate with OIDC, and clusters pull through node roles, workload identity or pull secrets.

  6. 06

    Codify and document

    Everything is defined in Terraform, with a short runbook for access requests and common errors.

Tools and technologies

Amazon ECRAzure Container RegistryGoogle Artifact RegistryTerraformAWS IAMAzure RBACOIDCTrivyHarborGitHub ActionsGitLab CI

Frequently asked questions

Which registry should we choose, ECR, ACR or Artifact Registry?
Use the one in the cloud where your workloads run. Each integrates natively with that cloud's identity, networking and Kubernetes service, which avoids credential handling and cross-cloud egress. Multi-cloud teams can use one per cloud or a neutral option such as Harbor, accepting the extra operations.
What happened to Google Container Registry (GCR)?
Google has superseded Container Registry with Artifact Registry, which supports container images plus other package formats and finer access control. New projects should use Artifact Registry, and existing GCR users should plan a migration. We handle that move as part of registry setup when needed.
Why use immutable tags?
With mutable tags, pushing myapp:1.4 twice replaces the first image, so two environments can believe they run the same version while running different code. Immutable tags make that impossible. For the strongest guarantee, deploy by digest, which identifies the exact image content.
How do we stop the registry becoming expensive?
Add lifecycle policies that expire untagged images and keep only a defined number of recent tags per repository, while protecting release tags. Reduce image sizes too, since storage and transfer scale with size. We tune the rules to your release cadence and rollback needs.
Can Kubernetes pull from a private registry without storing passwords?
Yes. On EKS, node IAM roles or IAM Roles for Service Accounts grant ECR pull access. On AKS, the cluster identity is attached to ACR. On GKE, the service account is granted Artifact Registry reader. These avoid long-lived image pull secrets entirely.

Talk to an engineer about private container registry

Book a free 30-minute call. We review your current setup and tell you honestly whether and how we can help.

Written by Saddique Khan, DevOps / SRE / Cloud Consultant Engineer. Last updated 2026-10-08.