Dockerfile check · medium

apt-get update in a separate RUN from apt-get install

Docker caches each RUN instruction separately. When apt-get update sits in its own RUN, its cached layer is reused on later builds, so a changed apt-get install line runs against an old package index. That can install outdated, vulnerable package versions or fail when the old index points at files the mirror no longer has. Run update and install in the same RUN.

$ explain Dockerfile
! apt-get update is in a separate RUN from install medium
line 2
fix: see below
$ 

What the free Dockerfile explainer reports on the risky example below.

Why it matters

The build cache matches RUN instructions by their text. apt-get update never changes, so once cached it is never re-run, however old the index becomes.

When the install line changes (a new package, say), Docker re-runs only that step, against the stale index, which can pin you to old versions or cause 404 errors from the mirror.

The explainer flags an apt or apt-get update in a RUN that doesn't install, when a later RUN in the same stage does.

Risky and safer Dockerfile

RiskyDockerfile
FROM debian:12-slim
RUN apt-get update
RUN apt-get install -y --no-install-recommends ca-certificates
COPY app /usr/local/bin/app
USER 10001
HEALTHCHECK CMD ["/usr/local/bin/app", "health"]
CMD ["/usr/local/bin/app"]
SaferDockerfile
FROM debian:12-slim
RUN apt-get update \
 && apt-get install -y --no-install-recommends ca-certificates \
 && rm -rf /var/lib/apt/lists/*
COPY app /usr/local/bin/app
USER 10001
HEALTHCHECK CMD ["/usr/local/bin/app", "health"]
CMD ["/usr/local/bin/app"]

How to fix it

  • Put apt-get update and apt-get install in the same RUN, joined with &&.
  • Use --no-install-recommends to avoid pulling in packages you didn't ask for.
  • Remove the package lists in that same RUN (rm -rf /var/lib/apt/lists/*) so they don't add size to the layer.

When it's acceptable

  • Rarely. If you rebuild with --no-cache every time, the split doesn't go stale, but combining the steps costs nothing and keeps the image smaller.

Check your own Dockerfile

The risky example is loaded below. Paste your own file to check it for this and every other Dockerfile rule. It runs in your browser; nothing is uploaded.

Dockerfile

Parsed in your browser. Nothing is uploaded.

Explanation

1 stage7 instructions1 medium1 low

Stage 0debian:12-slim

  • Docs for FROM (opens in a new tab)

    Starts from the base image debian, tag 12-slim.

    A version tag can be re-pushed to different content; only a digest is immutable. This applies to every tagged FROM in the file.

    Safer: Pin the digest as well (image:tag@sha256:<digest>) and let a bot open pull requests when it changes.

  • Docs for RUN (opens in a new tab)

    Runs apt-get update while building the image and saves the result as a new layer.

    Docker caches each instruction separately. Once the update layer is cached, later builds install from an old package index, which can mean old, vulnerable packages.

    Safer: Run apt-get update, apt-get install --no-install-recommends and rm -rf /var/lib/apt/lists/* in a single RUN.

  • Docs for RUN (opens in a new tab)

    Runs apt-get install -y --no-install-recommends ca-certificates while building the image and saves the result as a new layer.

  • Docs for COPY (opens in a new tab)

    Copies app from your build context to /usr/local/bin/app in the image.

  • Docs for USER (opens in a new tab)

    Runs later instructions and the container's process as user 10001.

  • Docs for HEALTHCHECK (opens in a new tab)

    Runs /usr/local/bin/app health to check the container is healthy.

  • Docs for CMD (opens in a new tab)

    Sets the default command to /usr/local/bin/app. It runs when the container starts, and anything passed to docker run replaces it.

Questions

Why should apt-get update and install be in the same RUN?

So they are cached together. If update is a separate cached step, later builds install from an old package index.

Should I delete /var/lib/apt/lists in a Dockerfile?

Yes, in the same RUN as the install. The lists are only needed during installation, and removing them in a later RUN would not shrink the earlier layer.

Does this apply to apt as well as apt-get?

Yes. The explainer checks both apt update and apt-get update followed by an install in a later RUN of the same stage.