Skip to content

VOL 00 / CH 07 / LESSON 01

7.1 Images, Containers, and Runtime Boundaries ​

Prerequisites: Chapter 2, Terminal Basics; Chapter 6, Errors and Logs

Estimated time: 15 minutes

Exercise environment: Bash, curl 7.71+, Docker Engine 28+, and the default bridge/NAT network; access to a sample image registry is required on first use

You are ready to continue when: you can distinguish between images, containers, and repositories, and safely run, observe, and clean up a container

"It works on my machine" usually proves that your machine is feeling cooperative. Operating systems, CPU architectures, runtimes, system libraries, dependencies, and configurations can all vary. A container does not erase those differences, but it can package a set of runtime conditions into a repeatable image.

Four Concepts Separated ​

ConceptMeaning
RegistryA service for storing and distributing images; Docker Hub is an example
ImageA template composed of a read-only image layer, configuration, and metadata
ContainerA process started from an image, along with its own writable layer and runtime settings
LayerA read-only filesystem layer in an image that is reusable and content-addressable

An image is immutable input; a container is one running instance started from it. The same image can start multiple containers, each with its own writable layer and runtime settings. At its core, a container is still a process on the host, not a complete virtual machine.

What Containers Do Not Package ​

  • Linux containers share the Linux kernel running on the host machine; they don't come with their own separate kernel.
  • On Windows and macOS, Docker Desktop typically runs Linux containers via a Linux virtual machine.
  • Images are still constrained by CPU architecture and target platform, and cannot guarantee to run exactly the same on any machine.
  • Passwords, deployment addresses, and environment-specific configurations are usually injected at runtime and should not be baked into the image entirely.
  • Container isolation depends on mechanisms such as namespace, cgroup, capability, and seccomp; it is not an unconditional security boundary.

Do a Read-Only Check ​

bash
docker version
docker compose version
docker image ls
docker container ls --all

docker version checks both the client and server. If only the client version is present and the server reports an error, it typically means that the Docker daemon or Docker Desktop is not yet available.

Running the First Web Container ​

The following example uses a native random free port and binds only to the loopback address to prevent exposing the practice service to the local network:

bash
(
set -e
container_id=$(docker run --detach --rm \
  --publish 127.0.0.1::80 nginx:latest)
trap 'docker stop "$container_id" >/dev/null 2>&1 || true' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
published=$(docker port "$container_id" 80/tcp)
printf 'published=%s\n' "$published"
host_port=${published##*:}
curl --fail --silent --show-error --retry 10 --retry-all-errors \
  --retry-delay 1 --max-time 2 "http://127.0.0.1:$host_port/"
docker logs "$container_id"
)

The parentheses create a subshell. After startup, it records only the container ID returned by this run and cleans that container up on exit, avoiding conflicts with a fixed name. Bounded curl retries allow Nginx time to start. The output of docker port is the actual port on the host machine. The script does not guess a fixed value. --rm indicates that the container is automatically deleted after stopping, while the image is not deleted.

This example requires Engine 28+. Older releases had a localhost-publishing issue that allowed access from the same layer-2 network, so the loopback access guarantee here does not apply to them. --publish 127.0.0.1::80 is responsible for port publishing. The EXPOSE 80 in the Dockerfile is just metadata and does not automatically open host ports. Omitting the host IP in -p 8080:80 may default to listening on all host addresses. During practice, it is advisable to avoid expanding the exposure surface.

Container and Virtual Machine Boundaries ​

Linux containers typically don't require a full guest kernel for each instance, so they tend to start faster and have lower overhead in typical scenarios. However, image sizes can range from a few MBs to several GBs, and startup times are influenced by application initialization, storage, and networking, so they can't be reliably described as "milliseconds" or "only a few MBs."

Virtual machines provide an independent guest kernel and offer a different level of isolation. In practice, containers are often run within virtual machines, and the two approaches are not mutually exclusive.

Before Continuing ​

  • Can explain the differences between registry, image, container, and layer;
  • Can explain how Linux containers share the kernel and Docker Desktop's virtual machine boundaries;
  • Can identify randomly published ports, read logs, and stop only the containers you created;
  • Knows that EXPOSE is not equal to --publish.

You have safely run and removed a container from an existing image. Next, use a Dockerfile to define your own files, runtime, and startup command. Verify the security boundaries of port publishing in the Docker documentation.

→ Next Step: Write a Dockerfile

Built with VitePress | Software Systems Atlas