Installing Docker and Your First Container
Getting Docker is two different stories depending on the host. On a Linux machine you install Docker Engine — the daemon, the CLI, and containerd — and containers run directly on that machine's kernel. On macOS and Windows you install Docker Desktop, which runs a lightweight Linux VM behind the same CLI, because Linux containers need a Linux kernel to share and your laptop does not have one.
Once it is running, a single command proves the whole client → daemon → runtime chain from topic 05 works end to end. docker run hello-world pulls an image, the daemon creates a container, runc starts the process, it prints a message and exits — the full round trip in one line.
Engine vs Desktop
Docker Engine is the daemon-on-the-host install: dockerd, containerd, and the docker CLI running directly on Linux, with containers on the machine's own kernel. It is what runs in production and CI, and it is free. Docker Desktop wraps a managed Linux VM, a GUI, Kubernetes, and assorted extras behind the same CLI on macOS, Windows, and optionally Linux — a developer convenience, not a server runtime.
dockerd, containerd, and the CLI installed directly on Linux, with containers on the machine's own kernel. The production and CI runtime, and free.The split matters for two reasons. On a Linux server, installing Desktop instead of Engine adds a VM and a GUI you neither need nor want under a production workload. And Docker Desktop carries licensing terms — it is not free for larger companies above a headcount and revenue threshold — that Engine does not. Check the current terms against your company's size before rolling Desktop out broadly.
The First Run, Step by Step
docker run hello-world does more than print a greeting. The daemon checks the local image store, finds nothing, and pulls the hello-world image from Docker Hub; it then creates a container from that image, runc starts the process, the process writes its message to stdout and exits, and the container stops. That one command exercises the registry round-trip, the pull, the create, and the start — the entire chain in a single invocation.
If hello-world prints its message, the install is sound: the CLI reached the daemon, the daemon reached the registry and containerd, and runc started a process. It proves the plumbing works — and nothing more. It says nothing about whether your storage, networking, or security are configured for real workloads, so treat a clean run as a smoke test, not a green light for production.
An Interactive Container
docker run -it ubuntu bash is where topic 03 becomes visible. The -it flags attach an interactive terminal, and instead of exiting, the container drops you into a Bash shell inside it. Run ps aux there and you will see two or three processes, not the host's hundreds, because the PID namespace hides them. Run hostname and you get a random twelve-character ID, the container's own.
# the shell is now inside the container root@3f2a1b9c4d5e:/# ps aux USER PID COMMAND root 1 bash # the app is PID 1 — the PID namespace root 10 ps aux root@3f2a1b9c4d5e:/# hostname 3f2a1b9c4d5e # a random container ID, not the host's name
Everything topic 03 described is now in front of you: Bash is PID 1, the process list is nearly empty, and the hostname is the container's own. Type exit and the shell's process ends, which ends PID 1, which stops the container — proof one more time that a container is a process, and that killing its main process kills the container.
Images Are Cached Locally
Run the same image a second time and the pull is gone — the container starts immediately. The daemon already has the image's layers in its local store, so there is nothing to download; this is your first sight of the local image cache that Chapter 2 covers in depth. docker images lists what is cached, with each image's repository, tag, digest, and size.
Rootless and Sudo
On Linux, the CLI talks to the daemon over a socket that only root and the docker group can reach, so a bare docker run as a normal user fails with a permission error. The two fixes are to prefix every command with sudo, or to add your user to the docker group so the socket is reachable without it. The second is more convenient and exactly as privileged — group membership grants root-equivalent access, as topic 05 spelled out.
When neither a root daemon nor a root-equivalent group is acceptable — a shared build host, a hardened CI runner — rootless Docker runs the daemon as an unprivileged user instead. Chapter 10 covers it in full; here it is enough to know the option exists and is the answer when "just add yourself to the docker group" is too much authority to hand out.
- Installing Docker Desktop on a production Linux server when Docker Engine is the correct install — Desktop is a developer tool with a VM, a GUI, and licensing implications, not a server runtime, and it wastes resources on a host.
- Running every
dockercommand withsudoout of habit while not realizing thedockergroup grants the same root-equivalent access more conveniently — same authority, just less typing, and the same risk either way. - Assuming a clean
docker run hello-worldmeans Docker is production-ready — it proves the chain works end to end and nothing about storage, networking, or security being configured for real workloads. - On macOS or Windows, being surprised that containers cannot see host processes or that bind-mount I/O is slower — there is a Linux VM in between, and file I/O crossing that VM boundary is an expected, not anomalous, cost.
- Install Docker Engine on Linux servers and CI runners, and reserve Docker Desktop for developer laptops where the managed VM and GUI actually earn their keep.
- Add your user to the
dockergroup on a development machine for convenience, but treat that membership as granting root and restrict who gets it accordingly. - Verify a new install with
docker run hello-worldand then an interactiveubuntushell, so you confirm both the registry round-trip and the namespace isolation in one sitting. - Check Docker Desktop's licensing terms against your company's size before deploying it broadly, since it is not free for all commercial use above its headcount and revenue threshold.
Knowledge Check
When should you install Docker Engine rather than Docker Desktop?
- On Linux servers and CI runners, where you want the daemon on the host without a VM, GUI, or Desktop licensing
- On macOS and Windows developer laptops alike, where the bundled lightweight Linux VM is what is required to run any containers at all
- Whenever you want a built-in graphical dashboard to browse and manage your containers and images visually
- Whenever you need a one-click local single-node Kubernetes cluster bundled directly with the install
What does a successful docker run hello-world actually confirm?
- That the pull, daemon, and runtime chain works end to end — not that storage, networking, or security are configured
- That Docker is now fully configured, hardened, and ready to take on real production workloads at scale
- That your user account has now been granted privileged kernel access for every container you run from this point on
- That your custom container networks, bridges, and named volumes are all correctly wired up and working as configured
Inside docker run -it ubuntu bash, ps shows only two or three processes. Why?
- The PID namespace gives the container its own process tree, so it sees only its own processes, not the host's
- Docker pauses all the host's other processes while an interactive container is attached
- The ubuntu container boots its own minimal stripped-down guest operating system with its own separate kernel, and that pared-back guest simply has almost no background processes to start
- The
pscommand is broken inside containers and truncates its output to a few lines
Why is adding your user to the docker group equivalent to granting root on the host?
- The group grants access to the root-owned daemon socket, and through it you can run a container that edits any host file
- Joining the group silently rewrites your own user ID to 0 for every single command you go on to run on the host
- It directly exposes the hashed login passwords of every other user account that is also a member of the same docker group on the host
- It only lets you skip typing
sudoin front of one single one-offdockercommand at a time, and nothing more
You got correct