CrackOps
Interview PrepTracksLinuxAWS LabSoonInterview RoomSoon
Sign inStart free
CrackOps

Interview prep for the people who keep production up.

[email protected]
ProductInterview PrepTracksDashboardInterview Room
RolesDevOpsSREPlatformCloud
CompanyAboutContactPrivacyTerms
© CrackOps
Linux / Docker / docker build

docker build

Build an image from a Dockerfile

Intermediateimagesdockerfileci-cd

docker build turns a Dockerfile and a build context (usually the current directory) into an image: a stack of cached, content-addressed layers plus a config that says what to run. Getting the layer order and .dockerignore right is the difference between 2-second and 2-minute builds.

Syntaxdocker build [OPTIONS] PATH | URL | -

Watch it run

You have a Node API with a Dockerfile and need an image tagged with the release version.

devops@devops-lab: ~/app — zsh — 96×28
➜ ~/app
Step 1 of 3
cat Dockerfile

Dependencies are copied and installed before the source code. Source changes on every commit, package.json rarely, so this order keeps the slow npm ci step cached.

Anatomy of a command

$
commanddocker build

Run a build with BuildKit (through the buildx plugin) and load the result into the local image store.

How it works

The CLI hands the build to BuildKit (via buildx) and streams the build context to it, skipping anything in .dockerignore. BuildKit parses the Dockerfile into a dependency graph, so independent stages build in parallel and unused stages are skipped. FROM resolves the base image to a digest. For every instruction it computes a cache key from the parent layer, the instruction text and, for COPY and ADD, a checksum of the copied files. On a hit it reuses the stored layer (CACHED); on a miss it runs the step, RUN in a temporary container, and snapshots the filesystem diff as a new layer identified by its sha256. One miss invalidates every step after it. Finally it writes the image config (ENV, USER, CMD...) and a manifest listing the layers, and tags it.

Each Dockerfile step becomes a cached layer keyed by its parent and inputs; one cache miss rebuilds everything after it.

build requestsend contextFROM digestkey lookuprun stepmanifestYoudocker build .Build contextyour filesBuildKitvia buildxRegistrynode:22-alpineLayer cacheby cache keyNew layerssha256 diffsImageshop-api:1.4.0
1/7
docker build hands the job to BuildKit

The CLI (through the buildx plugin) opens a session with BuildKit and passes the Dockerfile, tags and build args.

← → to step

Options you'll actually use

-t, --tag NAME:TAGName the image; repeat to add several tags
-f, --file PATHUse a Dockerfile other than ./Dockerfile
--target STAGEBuild only up to a named stage of a multi-stage file
--build-arg KEY=VALSet a build-time ARG (not for secrets)
--no-cacheIgnore the layer cache and run every step
--pullAlways check the registry for a newer base image
--platform linux/arm64Build for another CPU architecture (Graviton, Apple silicon)
--progress plainPrint full, uncollapsed step output (best in CI logs)
--secret id=npm,src=.npmrcMount a secret into one RUN step without baking it into a layer
--pushPush to the registry straight after building (buildx)
--cache-from / --cache-toImport or export the layer cache, for CI runners with empty disks
--label KEY=VALAdd metadata, such as the git commit, to the image

Common mistakes

COPY . . before RUN npm ci (or pip install)

Any source change alters the COPY checksum, so the dependency install misses the cache on every build.

COPY package*.json ./ then RUN npm ci, then COPY . .
No .dockerignore in a repo with node_modules, .git and .env

The context is huge and slow to send, and COPY . . bakes secrets and local junk into the image.

Add .dockerignore with node_modules, .git, .env*, *.log
--build-arg NPM_TOKEN=... or ENV API_KEY=... to get a secret into the build

Build args and ENV are stored in the image config and history, so anyone who can pull the image can read them.

RUN --mount=type=secret,id=npm ... with docker build --secret id=npm,src=.npmrc
Only ever tagging :latest

You can't tell which code is running, and rollbacks to 'the previous latest' are impossible.

docker build -t shop-api:1.4.0 -t shop-api:$(git rev-parse --short HEAD) .

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    ~/app has a real Dockerfile. Read it and build it as orders-api, then edit src/server.js and build again: which steps run again, and can ~/app/.env end up in the image?

  2. 2

    Now protect it anyway: write ~/app/.dockerignore excluding node_modules, .git, all .log files and any .env file, then check it.

  3. 3

    Write the build command that uses Dockerfile.prod, builds only the runtime stage, and tags the image both shop-api:2.0.0 and shop-api:latest.

  4. 4

    This Dockerfile reinstalls dependencies on every code change: FROM python:3.12-slim / WORKDIR /app / COPY . . / RUN pip install -r requirements.txt / CMD ["python","app.py"]. Rewrite it into ~/app/Dockerfile with the cache in mind.

  5. 5

    Build and push a real image in the CrackOps AWS Lab: build for linux/amd64 and tag it for your ECR repository.

Related commands

docker imagesList, filter and clean up local imagesdocker pushUpload an image to a registrydocker runCreate and start a container from an imagedocker system pruneReclaim disk space from unused Docker data
Previousdocker runNextdocker ps
Linux / Docker / docker build

docker build

Build an image from a Dockerfile

Intermediateimagesdockerfileci-cd

docker build turns a Dockerfile and a build context (usually the current directory) into an image: a stack of cached, content-addressed layers plus a config that says what to run. Getting the layer order and .dockerignore right is the difference between 2-second and 2-minute builds.

Syntaxdocker build [OPTIONS] PATH | URL | -

Watch it run

You have a Node API with a Dockerfile and need an image tagged with the release version.

devops@devops-lab: ~/app — zsh — 96×28
➜ ~/app
Step 1 of 3
cat Dockerfile

Dependencies are copied and installed before the source code. Source changes on every commit, package.json rarely, so this order keeps the slow npm ci step cached.

Anatomy of a command

$
commanddocker build

Run a build with BuildKit (through the buildx plugin) and load the result into the local image store.

How it works

The CLI hands the build to BuildKit (via buildx) and streams the build context to it, skipping anything in .dockerignore. BuildKit parses the Dockerfile into a dependency graph, so independent stages build in parallel and unused stages are skipped. FROM resolves the base image to a digest. For every instruction it computes a cache key from the parent layer, the instruction text and, for COPY and ADD, a checksum of the copied files. On a hit it reuses the stored layer (CACHED); on a miss it runs the step, RUN in a temporary container, and snapshots the filesystem diff as a new layer identified by its sha256. One miss invalidates every step after it. Finally it writes the image config (ENV, USER, CMD...) and a manifest listing the layers, and tags it.

Each Dockerfile step becomes a cached layer keyed by its parent and inputs; one cache miss rebuilds everything after it.

build requestsend contextFROM digestkey lookuprun stepmanifestYoudocker build .Build contextyour filesBuildKitvia buildxRegistrynode:22-alpineLayer cacheby cache keyNew layerssha256 diffsImageshop-api:1.4.0
1/7
docker build hands the job to BuildKit

The CLI (through the buildx plugin) opens a session with BuildKit and passes the Dockerfile, tags and build args.

← → to step

Options you'll actually use

-t, --tag NAME:TAGName the image; repeat to add several tags
-f, --file PATHUse a Dockerfile other than ./Dockerfile
--target STAGEBuild only up to a named stage of a multi-stage file
--build-arg KEY=VALSet a build-time ARG (not for secrets)
--no-cacheIgnore the layer cache and run every step
--pullAlways check the registry for a newer base image
--platform linux/arm64Build for another CPU architecture (Graviton, Apple silicon)
--progress plainPrint full, uncollapsed step output (best in CI logs)
--secret id=npm,src=.npmrcMount a secret into one RUN step without baking it into a layer
--pushPush to the registry straight after building (buildx)
--cache-from / --cache-toImport or export the layer cache, for CI runners with empty disks
--label KEY=VALAdd metadata, such as the git commit, to the image

Common mistakes

COPY . . before RUN npm ci (or pip install)

Any source change alters the COPY checksum, so the dependency install misses the cache on every build.

COPY package*.json ./ then RUN npm ci, then COPY . .
No .dockerignore in a repo with node_modules, .git and .env

The context is huge and slow to send, and COPY . . bakes secrets and local junk into the image.

Add .dockerignore with node_modules, .git, .env*, *.log
--build-arg NPM_TOKEN=... or ENV API_KEY=... to get a secret into the build

Build args and ENV are stored in the image config and history, so anyone who can pull the image can read them.

RUN --mount=type=secret,id=npm ... with docker build --secret id=npm,src=.npmrc
Only ever tagging :latest

You can't tell which code is running, and rollbacks to 'the previous latest' are impossible.

docker build -t shop-api:1.4.0 -t shop-api:$(git rev-parse --short HEAD) .

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    ~/app has a real Dockerfile. Read it and build it as orders-api, then edit src/server.js and build again: which steps run again, and can ~/app/.env end up in the image?

  2. 2

    Now protect it anyway: write ~/app/.dockerignore excluding node_modules, .git, all .log files and any .env file, then check it.

  3. 3

    Write the build command that uses Dockerfile.prod, builds only the runtime stage, and tags the image both shop-api:2.0.0 and shop-api:latest.

  4. 4

    This Dockerfile reinstalls dependencies on every code change: FROM python:3.12-slim / WORKDIR /app / COPY . . / RUN pip install -r requirements.txt / CMD ["python","app.py"]. Rewrite it into ~/app/Dockerfile with the cache in mind.

  5. 5

    Build and push a real image in the CrackOps AWS Lab: build for linux/amd64 and tag it for your ECR repository.

Related commands

docker imagesList, filter and clean up local imagesdocker pushUpload an image to a registrydocker runCreate and start a container from an imagedocker system pruneReclaim disk space from unused Docker data
Previousdocker runNextdocker ps