Artifact Registry
Artifact Registry is GCP's fully managed package and container registry. It replaces Container Registry (GCR) and adds vulnerability scanning, IAM-based access control, and native integration with Cloud Build and Cloud Run. For ML workloads, it's where you store the Docker images that power your model servers.
Why Artifact Registry?
| Feature | Artifact Registry | Docker Hub | GCR (Legacy) |
|---|---|---|---|
| Vulnerability scanning | Built-in | Limited | Basic |
| IAM access control | Yes | No | Limited |
| Regional replication | Yes | No | No |
| Multiple formats | Docker, Maven, npm, Python | Docker only | Docker only |
| CI/CD integration | Native GCP | Manual | Native GCP |
| Pricing | 0.50 USD/GB/month | Free (public) | Same |
1. Create a Docker Repository
# Set variables
export PROJECT_ID="your-project-id"
export REGION="us-central1"
export REPO_NAME="ml-images"
# Create a Docker-format repository
gcloud artifacts repositories create ${REPO_NAME} \
--repository-format=docker \
--location=${REGION} \
--description="Docker images for ML model servers" \
--project=${PROJECT_ID}
# Verify the repository
gcloud artifacts repositories describe ${REPO_NAME} \
--location=${REGION}
# List all repositories
gcloud artifacts repositories list --location=${REGION}
2. Authenticate Docker
Before pushing or pulling, configure Docker to authenticate with Artifact Registry:
# One-time auth setup (valid for 4 hours)
gcloud auth configure-docker ${REGION}-docker.pkg.dev
# Verify auth
docker login ${REGION}-docker.pkg.dev
3. Push Docker Images
Build your ML container and push it to Artifact Registry:
# Build and tag the image
export IMAGE_TAG="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ml-predictor:v1.0.0"
docker build -t ${IMAGE_TAG} .
# Push the image
docker push ${IMAGE_TAG}
# List images in the repository
gcloud artifacts docker images list \
${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME} \
--include-tags
Tagging conventions
Use a consistent tagging strategy for ML images:
# Semantic versioning for releases
docker tag ml-predictor:latest ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ml-predictor:1.2.0
# Git SHA for traceability
docker tag ml-predictor:latest ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ml-predictor:sha-abc1234
# Environment tags
docker tag ml-predictor:latest ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ml-predictor:staging
docker tag ml-predictor:latest ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ml-predictor:production
| Tag Type | Format | Use Case |
|---|---|---|
| SemVer | 1.2.0 | Production releases |
| Git SHA | sha-abc1234 | Traceability, rollback |
| Environment | staging, production | Deployment targets |
| Latest | latest | Development only (never in prod) |
4. Pushing from CI/CD (Cloud Build)
Automate image builds and pushes with Cloud Build:
# cloudbuild.yaml
steps:
# Step 1: Build the Docker image
- name: "gcr.io/cloud-builders/docker"
args:
[
"build",
"-t",
"${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_REPO}/ml-predictor:${SHORT_SHA}",
"-t",
"${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_REPO}/ml-predictor:latest",
".",
]
# Step 2: Push the image (both tags)
- name: "gcr.io/cloud-builders/docker"
args: ["push", "--all-tags", "${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_REPO}/ml-predictor"]
# Step 3: Deploy to Cloud Run
- name: "gcr.io/cloud-builders/gcloud"
args:
[
"run",
"deploy",
"ml-predictor",
"--image=${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_REPO}/ml-predictor:${SHORT_SHA}",
"--region=${_REGION}",
"--platform=managed",
]
substitutions:
_REGION: us-central1
_REPO: ml-images
images:
- "${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_REPO}/ml-predictor:${SHORT_SHA}"
- "${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_REPO}/ml-predictor:latest"
# Trigger the build manually
gcloud builds submit --config=cloudbuild.yaml \
--substitutions=_REGION=us-central1,_REPO=ml-images
# Or set up a trigger from GitHub
gcloud builds triggers create github \
--repo-name=your-repo \
--repo-owner=your-org \
--branch-pattern="^main$" \
--build-config=cloudbuild.yaml
5. Vulnerability Scanning
Artifact Registry can automatically scan images for known security vulnerabilities (CVEs):
# Enable vulnerability scanning on the repository
gcloud artifacts repositories update ${REPO_NAME} \
--location=${REGION} \
--enable-vulnerability-scanning
# Scan a specific image
gcloud artifacts docker images scan \
${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ml-predictor:v1.0.0
# Get scan results
gcloud artifacts docker images list-vulnerabilities \
${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ml-predictor@sha256:abc123...
Vulnerability severity levels
| Level | Action |
|---|---|
| CRITICAL | Must fix before deploying. Block in CI/CD. |
| HIGH | Fix within 24 hours. Alert the team. |
| MEDIUM | Fix within 1 week. Track in backlog. |
| LOW | Fix opportunistically. |
CI/CD vulnerability gate
# Add to cloudbuild.yaml — block deployment on critical vulnerabilities
steps:
- name: "gcr.io/cloud-builders/gcloud"
entrypoint: "bash"
args:
- "-c"
- |
SCAN_RESULT=$(gcloud artifacts docker images scan \
${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_REPO}/ml-predictor:${SHORT_SHA} \
--format="value(response.vulnerabilityCount)")
if [ "$SCAN_RESULT" -gt 0 ]; then
echo "Vulnerabilities found! Check scan results."
exit 1
fi
6. Image Versioning and Cleanup
Over time, old images accumulate and consume storage. Set up cleanup policies:
# List all versions of an image
gcloud artifacts docker images list \
${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ml-predictor \
--include-tags \
--format="table(version,metadata.tag,metadata.uploadTime)"
# Delete a specific version
gcloud artifacts docker images delete \
${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ml-predictor@sha256:abc123... \
--delete-tags \
--quiet
# Set a cleanup policy (keep last 10 versions)
gcloud artifacts repositories set-cleanup-policies ${REPO_NAME} \
--location=${REGION} \
--policy=cleanup-policy.json
// cleanup-policy.json
[
{
"name": "keep-last-10",
"action": { "type": "KEEP", "mostRecentVersions": { "keepCount": 10 } },
"condition": { "packageName": "ml-predictor" }
},
{
"name": "delete-untagged-older-than-30d",
"action": { "type": "DELETE" },
"condition": {
"packageName": "ml-predictor",
"olderThan": "2592000s",
"tagState": "UNTAGGED"
}
}
]
7. IAM Access Control
Control who can push and pull images:
# Grant read access to all developers
gcloud artifacts repositories add-iam-policy-binding ${REPO_NAME} \
--location=${REGION} \
--member="group:developers@company.com" \
--role="roles/artifactregistry.reader"
# Grant write access to CI/CD service account
gcloud artifacts repositories add-iam-policy-binding ${REPO_NAME} \
--location=${REGION} \
--member="serviceAccount:cloudbuild@your-project-id.iam.gserviceaccount.com" \
--role="roles/artifactregistry.writer"
# Grant admin access to ML platform team
gcloud artifacts repositories add-iam-policy-binding ${REPO_NAME} \
--location=${REGION} \
--member="group:ml-platform@company.com" \
--role="roles/artifactregistry.admin"
Artifact Registry Checklist
- Create regional Docker repository for ML images
- Use semantic versioning + git SHA tags
- Enable vulnerability scanning on the repository
- Set up CI/CD pipeline with Cloud Build
- Add vulnerability gate to block critical CVEs
- Configure cleanup policies to manage storage costs
- Restrict push access to CI/CD service accounts only
- Never use
latesttag in production deployments