Docker is an open-source platform for building, shipping, and running applications in containers. A container packages an application together with everything it needs to run — the runtime, system libraries, dependencies, and configuration — so the application behaves identically on a laptop, a CI server, or production. It solves the classic "it works on my machine" problem: the machine is the container.
Key benefits:
Both provide isolation, but at different levels. A virtual machine virtualizes hardware and runs a full guest operating system. A container virtualizes at the operating system level and shares the host kernel.
| Aspect | Virtual Machine | Container |
|---|---|---|
| Guest OS | Full OS per VM (Windows, Linux...) | None — shares the host kernel |
| Size | Gigabytes | Megabytes |
| Boot time | Minutes | Milliseconds |
| Isolation | Strong (hardware level) | Process-level (namespaces, cgroups) |
| Overhead | High (hypervisor + OS) | Very low |
| Density per host | Tens | Hundreds |
They are complements, not rivals: containers frequently run inside VMs in cloud environments.
docker CLI. You type commands; it talks to the daemon via a REST API (Unix socket or TCP).dockerd) — the server that builds images, runs containers, and manages volumes and networks. It uses containerd underneath to actually manage container processes.An image is an immutable template: a packaged filesystem (application + dependencies) plus metadata such as the default command and exposed ports. A container is a running (or stopped) instance of that image with a thin writable layer on top.
A useful analogy: the image is the class, containers are object instances. You can run many containers from one image, and deleting containers never modifies the image.
docker images # list local images
docker run -d --name web1 nginx # container 1 from the nginx image
docker run -d --name web2 nginx # container 2 from the same image
docker ps # see both containers running
Every instruction in a Dockerfile creates a layer: a filesystem diff stacked on top of the previous ones using a union filesystem. Layers matter because they are:
node:20 base store that base only once on disk, and pulls transfer only missing layers.A registry is a service that stores and serves images. Docker Hub is the default. An image reference has the form [registry/][namespace/]name[:tag]:
docker pull nginx # nginx:latest from Docker Hub (implicit tag)
docker pull nginx:1.27-alpine # specific version + variant
docker pull myregistry.corp.com/team/api:1.4.2 # private registry
Watch out for latest: it is just the default tag, not "newest version", and it is not guaranteed to be stable. Pin explicit versions in real projects.
# Images
docker pull nginx:1.27 # download an image
docker images # list local images
docker rmi nginx:1.27 # remove an image
# Containers
docker run -d --name web -p 8080:80 nginx # create + start
docker ps # running containers
docker ps -a # all containers (including stopped)
docker stop web # graceful stop (SIGTERM, then SIGKILL)
docker start web # start a stopped container
docker restart web
docker rm web # delete a stopped container
docker rm -f web # force-delete a running one
docker run actually do, and what are its most common flags?docker run creates a container from an image and starts it. If the image is not local, it is pulled first. The flags you will use daily:
docker run \
--name my-api \ # human-readable container name
-d \ # detached: run in the background
-p 8080:8000 \ # publish: host port 8080 -> container port 8000
-e APP_ENV=prod \ # environment variable
-v mydata:/var/lib/data \# named volume for persistence
--rm \ # auto-remove when it stops (great for one-offs)
-it \ # interactive + TTY (for shells and CLIs)
my-api-image:1.0
A quick interactive example — a throwaway Ubuntu shell:
docker run --rm -it ubuntu:24.04 bash
docker logs -f web # follow stdout/stderr output
docker logs --tail 100 web # last 100 lines
docker exec -it web bash # open a shell inside the running container
docker exec web ls /app # run a one-off command inside it
docker inspect web # full JSON: IP, mounts, env, restart policy...
docker stats # live CPU/memory per container
docker cp web:/app/log.txt . # copy files in/out of a container
Remember: applications should log to stdout/stderr (not files inside the container) so docker logs works.
A Dockerfile is a text file named Dockerfile with one instruction per line. A minimal Python web app:
FROM python:3.12-slim # base image: official Python, slim variant
WORKDIR /app # set the working directory inside the image
COPY requirements.txt . # copy dependency list first (cache trick)
RUN pip install --no-cache-dir -r requirements.txt
COPY . . # now copy the rest of the source code
EXPOSE 8000 # document the port the app listens on
CMD ["python", "app.py"] # default command when the container starts
Instruction meanings:
FROM — the base image everything builds on. Always start from an official, small image.WORKDIR — creates and switches to the directory for subsequent instructions.COPY — copies files from your machine (the build context) into the image.RUN — executes a command at build time (installing dependencies, compiling).EXPOSE — documentation only; it does not publish ports (that is -p at runtime).CMD — the default command at run time. Only one per image (the last wins).docker build -t my-api:1.0 .
docker run -d --name api -p 8080:8000 my-api:1.0
curl http://localhost:8080/
The trailing . is the build context — the folder Docker sends to the daemon (and where it looks for the Dockerfile). Use -f if the Dockerfile has another name/location: docker build -f deploy/Dockerfile .. The -t name:tag flags name the resulting image.
Container filesystems are ephemeral: when the container is removed, its writable layer is deleted too. Any data written inside the container (e.g., a database file) is lost. Volumes are Docker-managed storage that lives outside the container lifecycle:
docker volume create appdata
docker run -d --name db -v appdata:/var/lib/postgresql/data postgres:16
docker volume ls
docker volume inspect appdata
Even if the db container is deleted and recreated, the appdata volume persists. Volumes are covered in more depth (volumes vs. bind mounts) in the Intermediate level.
Docker accumulates stopped containers, dangling images, unused volumes, and build cache. Periodic cleanup:
docker container prune # remove all stopped containers
docker image prune # remove dangling (untagged) images
docker image prune -a # remove ALL images not used by a container
docker volume prune # remove unused volumes (data loss risk!)
docker system prune # everything above + unused networks
docker system prune -a --volumes # nuclear option: also unused images/volumes
docker system df # show disk usage by images/containers/volumes
Be careful with volume pruning — it deletes data that is not currently attached to a container.
← Back to IT Knowledge Base