Skip to content

Docker & Containers: Practical Reference

This is your hands-on companion to Docker fundamentals. Pick the core concepts you’ll see in interviews, nail the commands you’ll use daily, and avoid the gotchas that burn everyone once.

Containerization is a lightweight virtualization method that packages an application, its runtime, libraries, and dependencies into a single, self-contained environment called a container. Containers isolate your app from the host system and other containers, ensuring consistency across development, testing, and production.

FeatureContainersVMs
OSShare host OS kernelFull OS stack per instance
StartupSecondsMinutes
SizeMBGB
IsolationProcess-levelFull OS-level

Docker is a platform that builds, ships, and runs containers. It provides a standardized way to package your application into a Docker image that can run identically on any system with Docker installed — your laptop, a colleague’s machine, or production servers.

Docker Image vs Container: What’s the Difference?

Section titled “Docker Image vs Container: What’s the Difference?”
  • Image = read-only template (a layered blueprint of code + dependencies). Think of it as a class definition.
  • Container = running instance of an image. Think of it as an object created from that class.

You build an image once; you can run many containers from it. Each container gets its own isolated filesystem, network interface, and process space.

Docker Hub is the default cloud registry (like GitHub for Docker images). You pull public images (docker pull nginx), push your own, and manage versions with tags. Private registries (Azure Container Registry, Docker Registry, AWS ECR) store proprietary images securely.

Volumes are how containers persist data beyond their lifetime. Two types:

  • Named volumes: Docker-managed storage (recommended for production — survives container deletion).
  • Bind mounts: Direct folder mapping from host to container (convenient for dev, but host-dependent).

Without volumes, all data dies when the container is removed. In production, always use named volumes.

Docker Compose: Multi-Container Local Development

Section titled “Docker Compose: Multi-Container Local Development”

Docker Compose is a YAML tool that defines, builds, and runs multi-container applications locally. One file describes all services, networks, and volumes; one command brings them all up: docker-compose up -d.

Container orchestration is the automated management of container deployment, scaling, health checks, and networking across a cluster of machines. Kubernetes and Docker Swarm are the main players — Kubernetes is industry standard for production.

Containers run as root by default — a serious security risk. Always run containers as non-root users by adding USER instruction to your Dockerfile. Regularly update base images, scan for vulnerabilities, and isolate containers with network policies.

Terminal window
docker --version
docker [command] --help # help for any docker command
docker info # docker system info
Terminal window
docker images # list local images
docker pull nginx:latest # download image from registry
docker pull myregistry.azurecr.io/myapp # pull from private registry
docker build -t myapp:1.0 . # build image from Dockerfile in current dir
docker build -t myapp:latest --no-cache . # build without cache (forces fresh layers)
docker rmi myapp:1.0 # remove image (fails if container is running)
docker rmi -f myapp:1.0 # force remove (use with caution)
docker tag myapp:1.0 myapp:latest # create new tag pointing to same image
docker push myregistry.azurecr.io/myapp:1.0 # push to registry
docker inspect myapp:1.0 # detailed image metadata (layers, config, env)
Terminal window
docker create myapp:1.0 # create container (don't start)
docker run -d -p 8080:8080 --name myapi myapp:1.0 # run detached, port map, name it
docker run -it ubuntu /bin/bash # run interactive (stay attached)
docker run -e DEBUG=true myapp:1.0 # pass environment variables
docker ps # list running containers
docker ps -a # list all containers (running + stopped)
docker ps -aq # quiet mode — only IDs (useful for scripting)
docker stop myapi # graceful stop (SIGTERM)
docker kill myapi # hard stop (SIGKILL)
docker start myapi # restart stopped container
docker restart myapi # stop then start
docker rm myapi # remove stopped container
docker rm -f myapi # force remove (running or stopped)
Terminal window
docker logs myapi # print container logs
docker logs -f myapi # follow logs (like tail -f)
docker logs --tail 50 myapi # last 50 lines
docker logs --since 2h myapi # logs from last 2 hours
docker exec -it myapi /bin/sh # interactive shell inside container
docker exec myapi printenv # run command and exit (non-interactive)
docker top myapi # list processes inside container
docker inspect myapi # detailed container metadata, config, mounts
docker stats myapi # real-time CPU/memory usage
Terminal window
docker network ls # list networks
docker network create mynet # create custom network
docker network connect mynet myapi # attach running container to network
docker network disconnect mynet myapi # detach from network
docker network inspect mynet # detailed network info (connected containers, driver)
docker run --network mynet myapp:1.0 # run container on specific network
Terminal window
docker volume ls # list named volumes
docker volume create mydata # create named volume
docker volume inspect mydata # volume metadata and mount point
docker volume rm mydata # remove volume
docker run -v mydata:/data myapp:1.0 # attach named volume to container
docker run -v /host/path:/container/path myapp:1.0 # bind mount host directory
docker run --mount type=volume,source=mydata,target=/data myapp:1.0 # explicit mount syntax
docker rm -v myapi # remove container AND its volumes (use with care)
Terminal window
docker-compose up -d # start services (detached)
docker-compose down # stop and remove containers/networks (not volumes)
docker-compose up --build # rebuild images before starting
docker-compose ps # list compose services and status
docker-compose logs -f myapi # follow logs for specific service
docker-compose exec myapi /bin/sh # shell into running service
docker-compose restart myapi # restart single service
docker-compose build # rebuild images only (don't start)
docker-compose pull # pull fresh images before starting
Terminal window
docker system prune # remove stopped containers, unused networks, dangling images
docker system prune -a # remove ALL unused images (including tagged ones not in use)
docker image prune # remove dangling images only
docker container prune # remove stopped containers
docker volume prune # remove unused volumes
  • Use specific base image tags — not node:latest, use node:20-alpine.
  • Multi-stage builds — build stage for compilation, runtime stage for just the artifacts (shrinks final image).
  • Minimize layers — combine commands with && to reduce layer count.
  • Order commands by change frequency — base images first, source code last (Docker layer caching).
  • .dockerignore — exclude development artifacts, version control, logs, test files.

Master these commands and concepts and you’ll handle 95% of your Docker day-to-day work. The rest is orchestration (Kubernetes) and registry management (deployment pipelines).