Skip to main content
Docker · lesson 1 of 9
Docker beginner Lesson 1 of 9

Also part of: DevOps FastAPI

Introduction to Docker

Run your first Docker containers and see what they are: ordinary Linux processes sharing the host kernel, started from an image in well under a second.

By SkillByExample · Updated

Docker packages an application and everything it needs into an image, and runs that image as an isolated container. Every example below was run against Docker Engine 29 on Linux; on macOS or Windows, install Docker Desktop and the commands are identical.

Check the client and the daemon

The docker command is a client that talks to a background daemon (dockerd), which does the real work. docker version shows both halves.

docker version --format 'client {{.Client.Version}}, server {{.Server.Version}} ({{.Server.Os}}/{{.Server.Arch}})'
$ docker version --format 'client {{.Client.Version}}, server {{.Server.Version}} ({{.Server.Os}}/{{.Server.Arch}})'
client 29.8.2, server 29.8.2 (linux/amd64)

If the server half is missing and you see Cannot connect to the Docker daemon, the client is installed but the daemon is not running — start Docker Desktop, or sudo systemctl start docker on Linux.

Your first container

docker run --rm hello-world:linux
$ docker run --rm hello-world:linux
Unable to find image 'hello-world:linux' locally
linux: Pulling from library/hello-world
4f55086f7dd0: Pulling fs layer
d5e71e642bf5: Download complete
4f55086f7dd0: Download complete
4f55086f7dd0: Pull complete
Digest: sha256:5e22040d441e5fb3aed38368acbe8486b575d7018df38dbdfbc7311fbb2ef3a9
Status: Downloaded newer image for hello-world:linux

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

docker run did three things: it found no local image, pulled it from Docker Hub, then created and started a container from it. The digest pins the exact image content; the tag (linux) is just a movable label. --rm deletes the container once it exits. Run the command again and the pull lines disappear, because the image is now cached.

A container shares the host kernel

uname -r
docker run --rm alpine:3.20 sh -c 'uname -r; grep PRETTY /etc/os-release'
$ uname -r
6.18.44-fc-v77
$ docker run --rm alpine:3.20 sh -c 'uname -r; grep PRETTY /etc/os-release'
Unable to find image 'alpine:3.20' locally
3.20: Pulling from library/alpine
25f1d6b1951a: Pulling fs layer
...
Status: Downloaded newer image for alpine:3.20
6.18.44-fc-v77
PRETTY_NAME="Alpine Linux v3.20"

The container reports Alpine Linux as its operating system but the same kernel version as the host. That is the difference from a virtual machine: the image supplies the userland (files, libraries, shell), and the host supplies the kernel. Nothing boots, so there is no OS start-up cost.

A container is just a process

docker run -d --name sleeper alpine:3.20 sleep 300
docker top sleeper
ps -eo pid,comm | grep -w sleep
docker exec sleeper ps
docker rm -f sleeper
$ docker run -d --name sleeper alpine:3.20 sleep 300
016183fe1a4279219b0a07b3d75d90750f19900d8bfcf3bc89e7cfd0042fb905
$ docker top sleeper
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                1933                1908                20                  23:32               ?                   00:00:00            sleep 300
$ ps -eo pid,comm | grep -w sleep
 1933 sleep
$ docker exec sleeper ps
PID   USER     TIME  COMMAND
    1 root      0:00 sleep 300
    7 root      0:00 ps
$ docker rm -f sleeper
sleeper

From the host, the container’s sleep is plain PID 1933 in the normal process list. Inside the container, the same process is PID 1, and it can only see its own processes. That narrowed view is a Linux PID namespace; Docker adds similar namespaces for the network, mounts and hostname, plus cgroups to cap CPU and memory. Isolation is a set of kernel features applied to a process, not a separate machine.

Containers start fast

time docker run --rm alpine:3.20 echo hi
$ time docker run --rm alpine:3.20 echo hi
hi

real	0m0.285s
user	0m0.000s
sys	0m0.039s

Creating a container, running a command in it and removing it took under a third of a second, most of it client/daemon round trips. A VM boot is measured in tens of seconds. This is why containers are used for throwaway jobs like CI steps and one-off tools.

Images versus containers

docker image ls --format '{{.Repository}}:{{.Tag}} {{.Size}}'
$ docker image ls --format '{{.Repository}}:{{.Tag}} {{.Size}}'
alpine:3.20 12.2MB
hello-world:linux 25.9kB

An image is a read-only template — a stack of filesystem layers plus metadata like the default command. A container is an instance of an image with a thin writable layer on top. Every docker run above created a new container from the same cached alpine:3.20 image, which is only 12 MB on disk. A Dockerfile is the recipe that builds an image, and a registry (Docker Hub by default) is where images are pushed and pulled. The next lessons cover each in turn.

Practice

  1. Print the exact Alpine release inside the alpine:3.20 image (it is stored in /etc/alpine-release).
Solution
docker run --rm alpine:3.20 cat /etc/alpine-release
$ docker run --rm alpine:3.20 cat /etc/alpine-release
3.20.10

The tag 3.20 is a moving label for the latest 3.20.x patch release.

  1. Start a detached container named napper that sleeps for 60 seconds, and print its host PID and status with docker inspect. Remove it afterwards.
Solution
docker run -d --name napper alpine:3.20 sleep 60
docker inspect --format '{{.State.Pid}} {{.State.Status}}' napper
docker rm -f napper
$ docker run -d --name napper alpine:3.20 sleep 60
a53b9d8cc41e5ddf58538976f3cf58c5751be1309052b5cf1f655b03f0bc4dec
$ docker inspect --format '{{.State.Pid}} {{.State.Status}}' napper
1626 running
$ docker rm -f napper
napper

-d prints the full container ID and returns immediately. The PID is the process’s ID on the host.

  1. Run uname -r in a debian:12-slim container. Is the kernel version different from the one Alpine reported?
Solution
docker run --rm debian:12-slim uname -r
$ docker run --rm debian:12-slim uname -r
Unable to find image 'debian:12-slim' locally
12-slim: Pulling from library/debian
...
Status: Downloaded newer image for debian:12-slim
6.18.44-fc-v77

Same kernel. Debian and Alpine supply different userlands; every container on the host shares one kernel.

  1. Run alpine:3.20 echo done without --rm and a --name of once. Show that the stopped container still exists, then remove it.
Solution
docker run --name once alpine:3.20 echo done
docker ps -a --filter name=once --format '{{.Names}} {{.Status}}'
docker rm once
$ docker run --name once alpine:3.20 echo done
done
$ docker ps -a --filter name=once --format '{{.Names}} {{.Status}}'
once Exited (0) Less than a second ago
$ docker rm once
once

A container that exits is stopped, not deleted. Without --rm, stopped containers accumulate until you remove them.

Frequently Asked Questions

What problem does Docker solve?
Docker packages an application with everything it needs, such as the runtime, libraries and configuration, into an image. A container started from that image behaves the same on a laptop, a CI runner or a production server, which removes the 'it works on my machine' class of bugs.
Is a Docker container the same as a virtual machine?
No. A virtual machine boots its own kernel on emulated hardware. A container is an ordinary process on the host that shares the host's kernel, isolated with Linux namespaces and cgroups. That is why containers start in a fraction of a second and an Alpine image is about 12 MB.
What is the difference between a Docker image and a container?
An image is a read-only template made of stacked filesystem layers. A container is a running (or stopped) instance of an image with its own thin writable layer on top. You can start many containers from one image, the way you create many objects from one class.
Do I need Linux to run Docker?
Linux containers need a Linux kernel. On Linux, Docker Engine uses the host kernel directly. On macOS and Windows, Docker Desktop runs a small Linux virtual machine for you, so the commands in this course work the same way everywhere.