Understand the nouns
Dockerfile, image, registry, container, port mapping, bind mount, and volume should all feel distinct.
Learn Docker and containers from first principles: image versus container, Dockerfile, layers, ports, volumes, logs, debugging, cleanup, and the exact reason containers fix the classic “works on my machine” problem.
build instructions
read only
runtime
Docker gets much easier when you learn the runtime story first, then the Dockerfile, then the day-to-day commands. The goal is to build confidence without filling your machine with mystery containers.
Dockerfile, image, registry, container, port mapping, bind mount, and volume should all feel distinct.
Write a tiny Dockerfile, build the image, and inspect the result before running it.
Learn docker run, ps, logs, and exec until they feel normal.
Use ports, environment variables, bind mounts, and named volumes without guessing.
Stop and remove containers, prune safely, and leave your machine in a known-good state.
The shortest useful definition of a container is: a running process packaged with the filesystem and defaults it needs, isolated from other processes by the host OS.
That is why Docker is so practical. You stop depending on the host machine being set up “just right” and instead ship the runtime with the app.
Use Docker when you need consistent runtimes across machines, fast onboarding, reproducible builds, or a clean way to package an app for CI and production.
Most Docker confusion disappears once you can picture the full lifecycle from source code to running container. That flow is what the CLI is helping you control.
Describe the base image, dependencies, files, environment variables, and startup command.
Docker executes the steps and creates reusable image layers.
Optionally tag the image and push it to a registry for reuse elsewhere.
Docker launches a process from the image and adds a small writable runtime layer.
Use logs, exec, inspect, and port mapping to understand what the container is doing.
Remove containers, images, and unused resources when you are finished.
A VM includes a whole guest operating system. A container shares the host kernel and packages only the app, dependencies, and runtime surface it needs.
Great when you need a full guest OS, but slower to boot and heavier on resources.
Excellent for consistent app packaging because you avoid shipping a full guest OS every time.
A Dockerfile is the recipe that becomes an image. Each instruction adds a layer or changes how the image will behave at runtime.
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
ENV PORT=8000
EXPOSE 8000
CMD ["python", "app.py"]
FROM
Picks the base image you are building on top of. This is the runtime starting point.
WORKDIR
Sets the working directory for later instructions and the default runtime location.
COPY + RUN
Bring files into the image and install dependencies during the build.
ENV / EXPOSE / CMD
Define runtime defaults, document network intent, and set the default startup command.
Search or filter the command atlas below. The goal is not only to list commands, but to make it obvious which one to reach for during build, run, inspect, data handling, or cleanup.
| Command | What it does | When to use it |
|---|---|---|
docker version |
Shows Docker client and server version details. | Run it first when you want to confirm Docker is installed and reachable. |
docker run --rm hello-world |
Runs a tiny test container and removes it afterward. | Great quick proof that your Docker runtime works. |
docker build -t my-app:dev . |
Builds an image from the Dockerfile in the current directory and tags it. | Use it after changing app code or Dockerfile instructions. |
docker images |
Lists local images. | Use it to confirm the image exists and to inspect tags and sizes. |
docker pull nginx:alpine |
Downloads an image from a registry. | Use it when you want to run or inspect an image without building one yourself. |
docker run -d --name web -p 8080:80 nginx |
Runs the nginx image in detached mode and maps container port 80 to local port 8080. | Use it for services you want to keep running in the background. |
docker ps |
Lists running containers. | Use it to verify that a container is still up and what ports are exposed. |
docker ps -a |
Lists all containers, including stopped ones. | Useful when a container exits too quickly and disappears from normal ps. |
docker logs -f web |
Streams logs from the web container. |
Use it when the app starts but you need runtime clues. |
docker exec -it web sh |
Starts an interactive shell inside the running container. | Helpful for checking files, environment variables, and in-container behavior. |
docker inspect web |
Shows detailed JSON metadata for the container. | Use it when you need exact mounts, env vars, IPs, or port bindings. |
docker stop web |
Stops a running container. | Use it when you want the container shut down cleanly. |
docker start web |
Starts a previously stopped container. | Useful when you want to reuse an existing container instead of creating a new one. |
docker rm web |
Removes a stopped container. | Use it after stopping a container that you no longer need. |
docker rmi my-app:dev |
Deletes a local image by tag. | Use it when you want to reclaim space or reset a local image build. |
docker tag my-app:dev myrepo/my-app:dev |
Creates another tag pointing to the same image. | Common before pushing to a remote registry. |
docker push myrepo/my-app:dev |
Uploads an image tag to a registry. | Use it when you want other machines or CI systems to pull the image. |
docker run --rm -e APP_MODE=demo my-app:dev |
Runs a container with an environment variable override. | Use it for runtime config that should not be baked into the image. |
docker run --rm -v "$PWD":/app -w /app node:20 npm test |
Mounts the current directory into the container and runs a command there. | Useful for ad hoc tooling or local dev workflows. |
docker volume create app-data |
Creates a named volume for persistent container data. | Use it when data should survive container replacement. |
docker volume ls |
Lists named volumes. | Use it to see what persistent local data Docker is managing. |
docker run -d --name db -v app-data:/var/lib/postgresql/data postgres:16 |
Runs a database container with its data stored in a named volume. | Good basic example of durable data outside the container filesystem. |
docker network ls |
Lists Docker networks on the host. | Helpful when you are debugging connectivity between containers. |
docker system df |
Shows disk usage for images, containers, and volumes. | Use it before cleanup if Docker is consuming more space than expected. |
docker container prune -f |
Deletes all stopped containers. | Fast cleanup for old lab containers you forgot to remove individually. |
docker image prune -f |
Deletes dangling images. | Useful after repeated rebuilds that leave untagged layers behind. |
docker system prune -f |
Removes unused containers, networks, and dangling images. | Use it carefully when you want an aggressive cleanup of unused Docker state. |
Tip: pair docker ps -a, docker logs, and docker inspect before rebuilding. Many container problems are runtime configuration issues, not build issues.
These labs are intentionally simple and local. The point is to make images, containers, ports, logs, mounts, and cleanup feel normal rather than mysterious.
Confirm the runtime works before you do anything more complicated.
Practice detached containers, port mapping, logs, and browser testing.
Write a tiny Dockerfile and turn code into a repeatable runnable package.
Stop, remove, prune, and leave your machine predictable for the next lab.
Confirm the Docker client can talk to the runtime and run a disposable test container.
docker version
docker run --rm hello-world
Practice detached mode, naming, port mapping, and container logs with a tiny nginx container.
docker run -d --name web -p 8080:80 nginx
docker ps
docker logs web
Take a tiny app or static site and turn it into a reusable image.
docker build -t my-app:dev .
docker images
docker run --rm my-app:dev
See how runtime configuration changes behavior without rebuilding the image.
docker run --rm -e APP_MODE=demo my-app:dev
docker logs -f <container-name>
Mount your local project into a container so the container sees live files from your machine.
docker run --rm -v "$PWD":/app -w /app node:20 npm test
See how data survives container replacement when it lives in a Docker volume instead of the container filesystem.
docker volume create app-data
docker run -d --name db -v app-data:/var/lib/postgresql/data postgres:16
docker volume ls
With Docker, the fastest path is usually: check whether the container is still running, read the logs, inspect the config, and only then rebuild if you truly need to.
Use docker ps or docker ps -a first.
state
Use docker logs before rebuilding. Startup errors often explain themselves.
logs
Use docker inspect for ports, mounts, env vars, and entrypoint details.
inspect
Use docker exec when you need to inspect files or runtime environment from inside.
exec
| Signal | Likely meaning | First move |
|---|---|---|
| Container exits immediately | The main process finished, crashed, or the startup command is wrong. | docker ps -a then docker logs |
| Port already allocated | Something else on your host is already using that port. | Pick another host port or stop the conflicting process |
| Image builds but app still fails | The problem is likely runtime config, startup logic, or environment, not the build itself. | docker logs and docker inspect |
| Data disappeared after restart | The data lived inside the container filesystem, not a named volume. | Move state into a volume |
| App cannot reach localhost | Inside a container, localhost means the container itself, not your laptop. |
Recheck networking assumptions and host mapping |
| Permission denied | File permissions, user IDs, or mount ownership may not match what the container expects. | Inspect mounts and the container user |
This simulator keeps the core idea simple: raw code fails on a mismatched production host, while a container succeeds because it brings the runtime with it.
Docker is easiest to trust when you know exactly how to stop, remove, and prune what you created. Cleanup is part of the skill, not an afterthought.
docker stop ....docker rm ... or docker container prune -f.docker rmi ....docker system prune -f is aggressive. Use it only when you understand what is considered unused.Once Docker feels predictable, the natural progression is learning how to manage many containers at once and how to package those deployments cleanly.
Containers are the foundation layer. The pages below show what comes next.