Building Images
By the end of this lesson
Build and tag images, and read the build output.
Building an image needs two inputs: a Dockerfile, and a build context. The context is the folder you point the build at. Its contents are sent to the builder before the first instruction runs, and COPY can only take files from inside it — which is why a Dockerfile cannot reach up into a parent directory for files.
The output is an image on your machine, usually with a name and tag you chose. From there it either runs locally or gets pushed to a registry so other machines can pull it.
# Build using ./Dockerfile, with this folder as the context
docker build -t anvi/employees-api:1.4.0 .
# A Dockerfile stored elsewhere, context still the repository root
docker build -f deploy/api.Dockerfile -t anvi/employees-api:1.4.0 .
# Add a second name for the image that was just built
docker tag anvi/employees-api:1.4.0 anvi/employees-api:1.4
# Both names, one image — compare the IMAGE ID column
docker images anvi/employees-api
# Publish so another machine can pull it
docker push anvi/employees-api:1.4.0- The trailing dot is the build context, not the Dockerfile. Pointing it at a folder full of unrelated material makes every build slower, which is what .dockerignore is for.
- -t sets name:tag. Skip it and the image still exists, listed with <none> for both columns, findable only by its identifier.
- -f names a different Dockerfile. The context is still whatever path you gave, so paths inside COPY do not change.
- docker tag adds a label to an existing image. Nothing is copied and nothing is rebuilt — you can confirm that because both entries share one image identifier.
- docker push requires you to be signed in and the image name to match the account or registry you are pushing to.
The build output is a progress report, and reading it saves time when something goes wrong:
The context is transferred
The first lines cover loading the Dockerfile and sending the context. A long pause here is a context problem, not a build problem — check .dockerignore.
Each instruction becomes a numbered step
Steps appear in Dockerfile order with their own timings. The numbering is how you map a failure back to a line.
CACHED means no work was done
A step marked CACHED reused a layer from a previous build. On a second build of unchanged source, most steps should say this. If they do not, the next lesson explains why.
A failure stops the build at that step
Everything before it is already cached, so fixing the problem and rebuilding resumes from roughly where it stopped rather than starting over.
The final lines report the result
You get the image digest and the names that were applied. That digest is the only identifier guaranteed to refer to this exact content forever.
Four ways to refer to an image, in increasing order of precision:
- Repository
- The name without a tag, such as anvi/employees-api. A repository holds many images over time.
- Tag
- A label attached to one image in a repository, such as 1.4.0. Readable, convenient, and movable.
- Image ID
- A local identifier for the image on your machine. Precise, but meaningless to anyone else.
- Digest
- A hash of the image content, written as anvi/employees-api@sha256:... — the same content always produces the same digest, and it cannot be moved to different content.
A tag is a movable label, not a version. Nothing about the tag 1.4.0 forces it to keep pointing at the image you built today. Run docker tag again, or push the same tag from another build, and it points somewhere else. The name did not change; the content under it did.
The digest is the part that cannot move, because it is derived from the content itself. When a deployment has to be certain about what it is running — a production release, a reproducible investigation into a bug — reference the digest and record it. Tags stay useful for people; digests are what you rely on.
Summary
- A build takes a Dockerfile and a context; only files in the context can be copied
- -t names the image, -f selects a different Dockerfile, and docker tag adds a name without rebuilding
- CACHED steps in the output mean a previous layer was reused
- A tag is a movable label; only the digest is tied to specific content
- latest carries no guarantee, so production deployments need explicit immutable tags
Practice
Attempt each one before opening the solution. Getting it wrong first is how the idea sticks.
Try it yourself
Build twice, then tag twice
Build an image with a version tag and note how long it takes. Build it again without changing anything and compare.
Then add a second tag to the same image and list both. What do you notice about the image identifier?
Show solution
The second build is far quicker, and most steps report CACHED. Nothing changed, so there was nothing to redo.
Both tags show the same image identifier, because tagging attaches a name rather than producing a new image. This is the clearest demonstration that a tag is a label on content, not a property of it — and that two names can refer to one thing, which is exactly why the name alone never proves what you are running.
docker build -t anvi/employees-api:1.4.0 .
docker build -t anvi/employees-api:1.4.0 .
docker tag anvi/employees-api:1.4.0 anvi/employees-api:stable
docker images anvi/employees-apiThink about it
Think about it
A test environment and a production environment both deploy anvi/employees-api:latest. Testing passes, production fails on the same feature.
List the things you cannot establish from that setup, and what you would change.
Show solution
You cannot establish whether the two environments are running the same image at all, which image passed the tests, or which image is currently failing. The evidence that would answer all three was never recorded.
The change is to tag each build immutably — the commit identifier works well — promote that exact tag from testing to production, and record the digest each environment is running.
The trade-off is honest: you now have more tags to manage and a promotion step to automate. In exchange, "what is running?" becomes a question with an answer.
Knowledge check
Nothing is recorded and there is no score. The explanation appears either way.
Saved in this browser only.