Docker
Google Container Engine
Private Container Images
Kubernetes
Cloud Computing

How do I run private docker images on Google Container Engine

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Running Private Docker Images on Google Kubernetes Engine (GKE)

Deploying applications from private Docker images on GKE requires configuring authentication between your Kubernetes cluster and the container registry where the images are stored. The process varies depending on whether you use Google Artifact Registry (the recommended option), the older Google Container Registry, or a third-party registry like Docker Hub or AWS ECR.

This article walks through each scenario with working configuration examples and troubleshooting guidance.

Prerequisites

Before you begin, ensure you have the following in place:

  1. An active Google Cloud project with billing enabled.
  2. The gcloud CLI installed and authenticated (gcloud auth login).
  3. A running GKE cluster (gcloud container clusters list to verify).
  4. A private Docker image pushed to your chosen registry.
  5. kubectl configured to point at your cluster (gcloud container clusters get-credentials CLUSTER_NAME --zone ZONE).

Google Artifact Registry is the successor to Container Registry and supports Docker, Maven, npm, and other package formats. GKE clusters authenticate to Artifact Registry automatically when the node service account has the correct IAM role.

Grant Access to the Service Account

By default, GKE nodes use the Compute Engine default service account. Grant it the Artifact Registry Reader role:

bash
1# Get the default service account email
2PROJECT_ID=$(gcloud config get-value project)
3SA_EMAIL="${PROJECT_ID}[email protected]"
4
5# Grant Artifact Registry Reader
6gcloud projects add-iam-policy-binding $PROJECT_ID \
7    --member="serviceAccount:${SA_EMAIL}" \
8    --role="roles/artifactregistry.reader"

Push Your Image

Tag and push your Docker image to Artifact Registry:

bash
1# Configure Docker to authenticate with Artifact Registry
2gcloud auth configure-docker us-central1-docker.pkg.dev
3
4# Tag the image
5docker tag my-app:latest us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:latest
6
7# Push
8docker push us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:latest

Deploy to GKE

Create a Kubernetes deployment that references the Artifact Registry image. No image pull secret is needed because the node service account handles authentication:

yaml
1# deployment.yaml
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5  name: my-app
6spec:
7  replicas: 2
8  selector:
9    matchLabels:
10      app: my-app
11  template:
12    metadata:
13      labels:
14        app: my-app
15    spec:
16      containers:
17        - name: my-app
18          image: us-central1-docker.pkg.dev/my-project/my-repo/my-app:latest
19          ports:
20            - containerPort: 8080
bash
kubectl apply -f deployment.yaml
kubectl get pods -w

Option 2: Third-Party Registries (Docker Hub, ECR, etc.)

For images stored outside Google Cloud, you need to create a Kubernetes imagePullSecret that contains the registry credentials.

Create the Secret

bash
1kubectl create secret docker-registry my-registry-secret \
2    --docker-server=https://index.docker.io/v1/ \
3    --docker-username=YOUR_USERNAME \
4    --docker-password=YOUR_PASSWORD \
5    --docker-email=YOUR_EMAIL

For AWS ECR, the server URL has a different format:

bash
1# Get the ECR login token (valid for 12 hours)
2aws ecr get-login-password --region us-east-1 | \
3    kubectl create secret docker-registry ecr-secret \
4    --docker-server=123456789.dkr.ecr.us-east-1.amazonaws.com \
5    --docker-username=AWS \
6    --docker-password-stdin

Reference the Secret in Your Deployment

Add the imagePullSecrets field to the pod spec:

yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: my-app
5spec:
6  replicas: 2
7  selector:
8    matchLabels:
9      app: my-app
10  template:
11    metadata:
12      labels:
13        app: my-app
14    spec:
15      imagePullSecrets:
16        - name: my-registry-secret
17      containers:
18        - name: my-app
19          image: docker.io/myorg/my-app:latest
20          ports:
21            - containerPort: 8080

Attach the Secret to a Service Account

To avoid specifying imagePullSecrets in every deployment, attach the secret to the default service account in the namespace:

bash
kubectl patch serviceaccount default \
    -p '{"imagePullSecrets": [{"name": "my-registry-secret"}]}'

After this, all pods in the namespace that use the default service account will automatically use the secret for image pulls.

Option 3: Workload Identity (Production Best Practice)

For production environments, Workload Identity is the recommended way to authenticate GKE workloads to Google Cloud services, including Artifact Registry. It avoids using node-level service accounts, which grant access to all pods on the node.

bash
1# Enable Workload Identity on the cluster
2gcloud container clusters update CLUSTER_NAME \
3    --zone ZONE \
4    --workload-pool=${PROJECT_ID}.svc.id.goog
5
6# Create a Kubernetes service account
7kubectl create serviceaccount my-app-sa
8
9# Create a Google Cloud service account
10gcloud iam service-accounts create my-app-gsa
11
12# Grant Artifact Registry access
13gcloud projects add-iam-policy-binding $PROJECT_ID \
14    --member="serviceAccount:my-app-gsa@${PROJECT_ID}.iam.gserviceaccount.com" \
15    --role="roles/artifactregistry.reader"
16
17# Bind the Kubernetes SA to the Google Cloud SA
18gcloud iam service-accounts add-iam-policy-binding \
19    my-app-gsa@${PROJECT_ID}.iam.gserviceaccount.com \
20    --role="roles/iam.workloadIdentityUser" \
21    --member="serviceAccount:${PROJECT_ID}.svc.id.goog[default/my-app-sa]"
22
23# Annotate the Kubernetes SA
24kubectl annotate serviceaccount my-app-sa \
25    iam.gke.io/gcp-service-account=my-app-gsa@${PROJECT_ID}.iam.gserviceaccount.com

Then reference serviceAccountName: my-app-sa in your pod spec.

Troubleshooting Image Pull Errors

If pods show ImagePullBackOff or ErrImagePull, use these commands to diagnose:

bash
1# Check pod events for error details
2kubectl describe pod POD_NAME
3
4# Verify the secret exists and is correctly formatted
5kubectl get secret my-registry-secret -o yaml
6
7# Test the image pull manually on a node (for debugging only)
8docker pull us-central1-docker.pkg.dev/my-project/my-repo/my-app:latest

Common Pitfalls

  • Insufficient IAM permissions. The most common cause of image pull failures on Artifact Registry is the node service account missing the roles/artifactregistry.reader role. Double-check with gcloud projects get-iam-policy.
  • Expired credentials for third-party registries. AWS ECR tokens expire after 12 hours. Automate token refresh using a CronJob or an external secrets operator like external-secrets.
  • Wrong registry URL. Docker Hub's registry URL is https://index.docker.io/v1/, not docker.io. Using the wrong URL in the secret will cause silent authentication failures.
  • Secret in the wrong namespace. Kubernetes secrets are namespace-scoped. The imagePullSecret must exist in the same namespace as the pod that references it.
  • Using default compute credentials in Autopilot. GKE Autopilot clusters manage node service accounts differently. Use Workload Identity instead of relying on the node service account.

Summary

Running private Docker images on GKE requires properly configured authentication between the cluster and your registry. For Google Artifact Registry, grant the node service account the reader role and no additional secrets are needed. For third-party registries, create a docker-registry secret and reference it in your pod spec or attach it to the namespace service account. In production, use Workload Identity for fine-grained access control. When pods fail to pull images, check IAM permissions, secret configuration, and the registry URL format.


Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.