agentleFS
geoffsdeskgeoffsdesk/portage/skills/registry-migration/SKILL.md

registry-migration

Skill0 starsChanged 6 months agoApache-2.0View on GitHub

Migrate container images from Amazon ECR to Google Artifact Registry. Plans the AR repo layout, mirrors images (skopeo or pull-through), updates build pipelines, sets up vulnerability scanning, and produces an image-map.json mapping every old image reference to its new one. Use when "migrate ECR to Artifact Registry", "set up image registries on GCP", or as Phase 3 of a Portage migration.

1 other project uses a version of this, 1 of them edited.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

7 rules. About 0 are common, 5 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Every container image referenced from any Kubernetes workload has to be reachable from GKE — preferably from a regional Artifact Registry — …

    line 12
  2. Very specific:

    GitHub Actions: add a google-github-actions/auth@v2 step (using Workload Identity Federation), then google-github-actions/setup-gcloud@v2, …

    line 130
  3. Distinctive:

    CodeBuild / CodePipeline: add a parallel push step that pushes to AR using a service account key OR (preferred) federated identity into GCP.

    line 131
  4. Very specific:

    Tekton: add a second image-push task targeting AR.

    line 133
  5. Distinctive:

    After cutover and soak, EKS push step retired, then ECR repos retired (separate decommission).

    line 175
  6. Distinctive:

    Every image referenced by any translated workload exists in AR with matching digest.

    line 213
  7. Distinctive:

    Pipelines that hardcode AWS region in image refs: When the dual-push goes live, those pipelines break in non-obvious ways.

    line 230

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Registry Migration

You move container images from ECR to Artifact Registry, set up vulnerability scanning, update build pipelines, and produce a mapping file the rest of Portage uses to rewrite image references.

Purpose

Every container image referenced from any Kubernetes workload has to be reachable from GKE — preferably from a regional Artifact Registry — at low latency, with vulnerability scanning, and (when in scope) with Binary Authorization attestations.

When to use this skill

  • Phase 3 of a Portage migration.
  • The user asks to "set up Artifact Registry", "mirror ECR to GCP", "migrate images".

Prerequisites

  • 01-discovery/inventory.json ECR section.
  • 03-landing-zone/plan.md with the artifact-registry shared project provisioned.
  • gcloud, aws, skopeo CLIs.
  • Either skopeo with credentials for both registries OR a CI/CD runner with both credentials.

Procedure

Step 1 — Plan the AR repo layout

Default layout:

projects/artifact-registry/locations/<region>/repositories/<repo-name>

Naming: one AR repository per ECR repository, same name. Multi-region repos for global distribution if cross-region pulls matter.

Decide repo format:

  • Standard repository: contains images directly. One per (env × team) is the typical shape, OR mirror ECR's existing per-app structure 1:1 to keep image references close to identical.
  • Virtual repository: aggregates upstream registries (Docker Hub, public ECR Public). Use to standardize where pull-through caching is needed.
  • Remote repository: mirrors a single upstream (Docker Hub, NPM). Use for bringing public images on-cluster without depending on Docker Hub directly.

For this migration:

  • Plan a standard AR repo per ECR repo, in the user's primary region (e.g., us-central1).
  • For repos with very high cross-region pull rates, plan an additional repo in the second region with replication.
  • Plan a remote repo for docker.io and quay.io if the workloads pull public images directly.

Step 2 — Provision AR repos

Terraform per repo:

resource "google_artifact_registry_repository" "payments_api" {
  project       = var.ar_project
  location      = var.region
  repository_id = "payments-api"
  format        = "DOCKER"

  docker_config { immutable_tags = false }   # tighten later if desired

  cleanup_policies {
    id     = "keep-recent-100"
    action = "KEEP"
    most_recent_versions { keep_count = 100 }
  }
  cleanup_policies {
    id     = "delete-untagged-after-30d"
    action = "DELETE"
    condition {
      tag_state  = "UNTAGGED"
      older_than = "2592000s"
    }
  }

  cleanup_policy_dry_run = true   # flip to false after one cleanup cycle of review
}

For pull-through cache:

resource "google_artifact_registry_repository" "docker_hub_remote" {
  project       = var.ar_project
  location      = var.region
  repository_id = "docker-hub"
  format        = "DOCKER"
  mode          = "REMOTE_REPOSITORY"
  remote_repository_config {
    docker_repository { public_repository = "DOCKER_HUB" }
  }
}

Step 3 — Mirror images

For each ECR repo + tag/digest in scope:

SRC=123456789012.dkr.ecr.us-east-1.amazonaws.com/payments/api:1.4.2
DST=us-central1-docker.pkg.dev/artifact-registry-prod/payments-api:1.4.2

aws ecr get-login-password --region us-east-1 \
  | skopeo login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com

gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
gcloud auth print-access-token \
  | skopeo login --username oauth2accesstoken --password-stdin us-central1-docker.pkg.dev

skopeo copy --multi-arch=all --preserve-digests \
  docker://${SRC} \
  docker://${DST}

For the bulk move, drive a parallel job:

jq -r '.[] | select(.kind=="image") | "\(.src)|\(.dst)"' image-plan.json \
  | xargs -P 8 -I{} bash -c 'IFS="|" read SRC DST <<< "$1"; \
     skopeo copy --multi-arch=all --preserve-digests docker://$SRC docker://$DST' _ {}

--preserve-digests ensures digests survive the copy, which is critical if any deployment pins by digest (it should).

Step 4 — Update build pipelines

For each upstream pipeline:

  • GitHub Actions: add a google-github-actions/auth@v2 step (using Workload Identity Federation), then google-github-actions/setup-gcloud@v2, then push to *.pkg.dev/.... Keep ECR push for a co-existence period.
  • CodeBuild / CodePipeline: add a parallel push step that pushes to AR using a service account key OR (preferred) federated identity into GCP.
  • Cloud Build / Cloud Deploy: native push to AR.
  • Tekton: add a second image-push task targeting AR.

Produce a checklist 08-registry-migration/pipelines.md listing every pipeline, the change to make, and the verification step.

Step 5 — Build the image-map

Produce 08-registry-migration/image-map.json:

[
  {
    "src": "123456789012.dkr.ecr.us-east-1.amazonaws.com/payments/api:1.4.2",
    "dst": "us-central1-docker.pkg.dev/artifact-registry-prod/payments-api:1.4.2",
    "src_digest": "sha256:abc...",
    "dst_digest": "sha256:abc...",
    "consumed_by": ["payments/payments-api"]
  }
]

workload-translation consumes this to rewrite image refs.

Step 6 — Vulnerability scanning + Binary Authorization

Enable Artifact Analysis (formerly Container Analysis) on the AR project. New images push automatically scan. Surface findings in 08-registry-migration/vuln-baseline.md so the team has a starting state.

For Binary Authorization (when in scope):

  1. Plan an attestor: gcloud container binauthz attestors create ….
  2. Plan an attestation policy on the cluster (start in EVALUATION mode, switch to ENFORCE after a review window).
  3. Wire CI to attest on push (Cloud Build has built-in support; for GitHub Actions, use google-github-actions/attest-build-provenance or cosign sign).

Step 7 — Cutover plan for image references

The image references in workloads should be rewritten in the same change that deploys to GKE. Until cutover, EKS continues to pull from ECR.

Sequence:

  1. AR repos exist.
  2. Initial mirror done; ongoing mirror automated (a Cloud Scheduler + Cloud Run job, or CI step).
  3. Pipelines push to both ECR and AR.
  4. GKE workloads reference AR.
  5. After cutover and soak, EKS push step retired, then ECR repos retired (separate decommission).

Step 8 — Decommission plan for ECR

Produce 08-registry-migration/ecr-decommission.md:

  • Per-repo decommission date (default: 30 days post final cutover for that workload).
  • Final image archive: tag archive-YYYYMMDD and copy to a long-term Cloud Storage bucket if compliance requires.
  • IAM cleanup: scoped IAM roles, lifecycle policies.

Decision points

DecisionDefaultWhen to deviate
AR repo structureOne AR repo per ECR repo, same nameRestructure if ECR layout was historically painful
RegionSame region as primary GKE clusterMulti-region replication for >2 regions
Pull-through cachesOne for docker.io, one for quay.io (if used)Skip if you mirror everything explicitly
Cleanup policyKeep 100 most recent + delete untagged > 30dTighter (10 most recent) for non-prod
Binary AuthorizationEnabled in EVALUATION mode initiallyENFORCE mode only after attestation pipeline runs cleanly for >2 weeks

Outputs / Deliverables

08-registry-migration/
├── repos.md                  # Per-AR-repo plan
├── terraform/
│   └── artifact-registry.tf
├── mirror-plan.json          # Source images, target images, mirror command
├── image-map.json            # Used by workload-translation
├── pipelines.md              # Per-pipeline change list
├── vuln-baseline.md          # Initial Artifact Analysis findings
├── binauthz/                 # Attestor + policy YAMLs (optional)
├── ecr-decommission.md
└── escalations.md

Validation

  • Every image referenced by any translated workload exists in AR with matching digest.
  • gcloud container images describe <full-ref> succeeds for every image in image-map.json.
  • A test pod on GKE successfully pulls a representative image without auth issues (KSA → GSA with roles/artifactregistry.reader on the AR project).
  • New CI runs push to AR and the image appears with the new tag within 5 minutes.
  • (If BinAuthz enabled) EVALUATION mode logs show every push attestation event.

Escalation triggers

  • ECR images in repos using lifecycle rules whose retention exceeds AR cleanup policies the user is willing to set. Surface for re-decision.
  • Images larger than AR's per-image / per-layer limits (rare). Surface and discuss split.
  • Cross-cloud egress costs from initial mirror exceed the user's per-month tolerance. Surface plan: throttled mirror, region-by-region.
  • ECR repos referenced by workloads in another AWS account (cross-account pulls). Discovery should have flagged; if not, surface here.

Common pitfalls

  • Pushing without --preserve-digests. Re-built images get new digests and break digest-pinned deployments.
  • Forgetting Workload Identity → AR reader. GSAs that pull from AR need roles/artifactregistry.reader on the AR project, not just on the cluster project.
  • Pipelines that hardcode AWS region in image refs. When the dual-push goes live, those pipelines break in non-obvious ways.
  • Pull-through caches that tag-pin. A pull-through cache pinning latest from Docker Hub returns whatever the cache last fetched, not the real latest.
  • Not seeding the cache. The first cluster pull of every cached upstream image is slow. Pre-warm before cutover.

References

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.