Patching containers: rebuild images, don't patch in place

Updated November 2026

You patch a container by building a new image from an updated base and replacing the running containers with it. Don't run apt upgrade inside a running container: the fix vanishes the next time it starts. And patch the host too, because every container uses the host's kernel.

Why patching in place fails

Docker's documentation puts it plainly: images are immutable, and a build is a snapshot taken at that moment. A container started from an image gets a thin writable layer on top. If you run a package update inside it:

So the unit you patch is the image. The steps are always the same: rebuild, scan, push, redeploy, and check that the old containers are gone.

Rebuild from an updated base

Most fixes reach you through the base image (the FROM line). Docker Official Images and other maintained base images are updated regularly with fixes. Your build only picks those up if it pulls the new base and doesn't reuse old cached layers:

docker build --pull --no-cache -t registry.example.com/myapp:2026-11-03 .
docker push registry.example.com/myapp:2026-11-03

--pull makes Docker check for and download a newer base image. --no-cache rebuilds every layer, so a cached RUN apt-get install step can't keep old packages. Docker recommends rebuilding regularly, not only when a scanner complains. A weekly scheduled build in CI plus an on-demand build for urgent advisories works for most teams.

If the base publisher hasn't shipped a fixed image yet, you can upgrade packages during the build. The fix then lives in your image:

# Debian/Ubuntu base
RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*

# Alpine base
RUN apk upgrade --no-cache

Remove the line once the base image catches up, so your images stay close to what the publisher tests.

Application dependencies are separate. npm, pip, Composer, Maven and Go modules don't change when the base image changes. Update your lock files and rebuild. See Node.js and PHP.

Pin base images, then refresh the pins

Tags are mutable: debian:13 or alpine:3.22 points to a new image every time the publisher rebuilds. A digest is fixed. Docker shows this form:

FROM alpine:3.21@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c

Pinning makes builds repeatable, but a pinned digest never gets fixes on its own. Use pins only together with a process that updates them, such as a dependency bot that opens pull requests for new digests, or a scheduled job. In that setup --pull doesn't change anything; the pin update is the patch. docker scout recommendations also shows newer base image versions for an image.

Avoid latest in production. Kubernetes' documentation warns that it makes it hard to track which version runs and to roll back. Use a specific tag and/or a digest.

Scan before and after

Scanners list the packages in an image and match them against vulnerability data. Three common free command-line options:

# Trivy: show only HIGH and CRITICAL issues that have a fix
trivy image --severity HIGH,CRITICAL --ignore-unfixed registry.example.com/myapp:2026-11-03

# Grype: update its database, then fail (exit code 2) on high or worse, fixed issues only
grype db update
grype registry.example.com/myapp:2026-11-03 --only-fixed --fail-on high

# Docker Scout: fixable critical and high CVEs
docker scout cves --only-fixed --only-severity critical,high registry.example.com/myapp:2026-11-03

All three can fail a CI job: Trivy with --exit-code 1, Grype with --fail-on, Docker Scout with --exit-code. Filtering to fixed issues keeps the list actionable. A CVE with no fix yet can't be patched by rebuilding, so track it and decide whether a workaround is needed. Results differ between tools because they use different data sources, so pick one and use it consistently. More on scanners is in vulnerability scanning.

Scan what runs, not just what you build. Scan images in your registry on a schedule. New CVEs appear against images that were clean when you built them.

Roll out on Kubernetes

Point the workload at the new image. A new tag or digest triggers a rolling update:

kubectl set image deployment/myapp myapp=registry.example.com/myapp:2026-11-03
kubectl rollout status deployment/myapp

Better still, change the tag or digest in your manifests or Helm values in Git and let your deployment pipeline apply it. That way the next apply doesn't put the old image back.

If you reuse the same tag, existing pods keep the old image. For any tag other than latest, the default pull policy is IfNotPresent, so a node that already has the tag won't pull again. kubectl rollout restart deployment/myapp restarts all pods of the deployment, but nodes that already have the tag reuse their old copy unless the pull policy is Always. That's another reason to use unique tags or digests.

For plain Docker or Compose hosts, pull and recreate the containers. This restarts the services:

docker compose pull
docker compose up -d

Then check what actually runs: docker ps on hosts, or kubectl get pods -o jsonpath='{..image}' on clusters.

Distroless and Alpine notes

Distroless
Google's distroless images hold only your app and its runtime dependencies. There is no shell and no package manager, so you can't patch inside them even if you wanted to. Rebuild is the only path. Current images are based on Debian 13 and have names like gcr.io/distroless/static-debian13. Fewer packages means fewer CVEs to patch. A :debug tag adds a busybox shell for troubleshooting; don't run it in production.
Alpine
Alpine images are very small (under 6 MB), so they have little to patch. Alpine uses apk and the musl C library instead of glibc, so some binaries built for glibc won't run. Each Alpine branch has its own support period; rebuild onto a supported branch before yours ends. See Alpine Linux.

The host kernel is shared

Containers are not virtual machines. Docker's documentation says that all containers on a host share the same kernel. A kernel flaw, such as a privilege escalation, can let code in any container affect the host and every other container. Rebuilding images does not fix it; patching the host does.

Sources