GKE Image Streaming lets your pods start up to 10x faster by streaming container images directly to the node’s local disk instead of pulling the entire image before starting.

Here’s how it looks in action. Imagine you have a pod definition like this:

apiVersion: v1
kind: Pod
metadata:
  name: my-streaming-app
spec:
  containers:
  - name: app-container
    image: us-central1-docker.pkg.dev/my-project/my-repo/my-app:latest
    ports:
    - containerPort: 8080

When GKE is configured for Image Streaming, and you run kubectl apply -f pod.yaml, the kubelet on the node doesn’t wait for us-central1-docker.pkg.dev/my-project/my-repo/my-app:latest to fully download. Instead, it starts the container using the streamed image layers. The initial layers needed to boot the application are fetched first, allowing the container to start executing much sooner. Subsequent layers are streamed in the background as needed.

This is fundamentally different from the traditional imagePullPolicy: IfNotPresent or Always. In those scenarios, the entire image must be downloaded and stored on the node’s local disk before the container can start. For large images, this pull operation can take minutes, significantly increasing pod startup latency.

Image Streaming tackles this by using a user-space proxy that runs on the node. This proxy intercepts image pull requests. It doesn’t download the whole image; instead, it streams only the required image layers to a local cache. When the container runtime requests an image, the kubelet’s containerd (or Docker) runtime communicates with this proxy. The proxy then provides the image layers on demand. This means the container can begin its execution with just the essential layers, and the rest are fetched as the application actually accesses them.

To enable this, you need to configure your GKE node pools. During node pool creation or update, you specify the Image Streaming settings.

Here’s a gcloud command to create a new node pool with Image Streaming enabled:

gcloud container node-pools create streaming-pool \
  --cluster=my-gke-cluster \
  --num-nodes=3 \
  --machine-type=e2-medium \
  --node-locations=us-central1-a \
  --enable-image-streaming \
  --image-streaming-installation-bucket=gs://my-streaming-bucket-12345

The --enable-image-streaming flag is the key. You also need to specify a Cloud Storage bucket (--image-streaming-installation-bucket) where the necessary proxy components will be installed. This bucket must be in the same region as your GKE cluster.

The primary benefit is drastically reduced pod startup times. This is particularly impactful for:

  • Scalability: When GKE scales up your deployments (e.g., due to increased traffic), new pods can become ready and start serving requests much faster.
  • Self-healing: If a pod crashes and needs to be restarted, the time to get a new instance up and running is significantly reduced.
  • Batch Jobs: Jobs that spin up and down frequently can complete their work quicker.

The underlying mechanism involves a daemonset that deploys the Image Streaming proxy to each node. This proxy then interacts with containerd, the container runtime, via a plugin. When containerd needs an image layer, it queries the proxy, which fetches it from the container registry and serves it to containerd. This is all transparent to your Kubernetes workload definitions. You don’t need to change your Pod or Deployment YAMLs to use Image Streaming; just enabling it on the node pool is sufficient.

A common misconception is that Image Streaming requires specific image formats or changes to your CI/CD pipeline. This is not true. It works with standard OCI-compliant container images. The streaming happens at the node level, abstracting away the complexity from your image building process.

The next logical step after optimizing pod startup with Image Streaming is to explore how to manage and optimize your container images themselves for even faster pulls and reduced storage footprints.

Want structured learning?

Take the full Gke course →