Docker lets you run applications in containers: isolated, reproducible environments, perfect for avoiding the classic “it works on my machine”.
Below you’ll find a practical list (cheatsheet style) of the most useful commands, your first Dockerfile and a small real-world workflow to get started right away.
1. Images#
docker pull nginx:latest - download an image from Docker Hub
docker images (or docker image ls) - list local images
docker rmi nginx:latest - remove an image
docker image prune - delete “dangling” images (with no tag)
docker image prune -a - delete every image not used by any container (careful)
2. Containers: Start, Stop, Inspect#
docker run hello-world - run a test container
docker ps - show running containers
docker ps -a - show all containers (including stopped ones)
docker stop <container> - stop a container
docker start <container> - start a stopped container again
docker restart <container> - restart a container
docker rm <container> - delete a container (it must be stopped, or use -f)
3. Running It Properly: Ports, Name, Background#
docker run -d --name web -p 8080:80 nginx:latest - start Nginx in the background and map port 8080 on your machine to port 80 in the container
-d= detached (in the background)--name= a friendlier name than the ID-p host:container= port mapping--rm= delete the container when it stops (handy for tests)
Now open http://localhost:8080 in your browser and you’ll see the Nginx welcome page.
4. Logs and Quick Debugging#
docker logs web - show the logs
docker logs -f web - follow the logs in real time
docker exec -it web /bin/sh - open a shell inside the container
docker inspect web - show every detail of the container (network, volumes, variables…)
Tip: some images ship
/bin/bash, but Alpine images only havesh.
5. Copying Files to/from a Container#
docker cp web:/etc/nginx/nginx.conf ./nginx.conf - copy from the container to your machine
docker cp ./index.html web:/usr/share/nginx/html/index.html - copy from your machine to the container
6. Volumes: Data Persistence (Essential)#
Without volumes, data written inside a container disappears when the container is deleted. Volumes make it persistent.
docker volume ls - list volumes
docker volume create mydata - create a volume
docker run -d --name db -e POSTGRES_PASSWORD=pass -v mydata:/var/lib/postgresql/data postgres:16 - Postgres with persistent data
docker run -d -p 8080:80 -v "$(pwd)/site":/usr/share/nginx/html nginx - “bind mount”: mount a folder from your machine into the container (great for development)
docker volume rm mydata - delete a volume (careful: you lose the data)
7. Networks: Letting Containers Talk to Each Other#
docker network ls - list networks
docker network create app-net - create a network
docker run -d --name db --network app-net -e POSTGRES_PASSWORD=pass postgres:16 - DB on the network
docker run -d --name api --network app-net my-api:latest - API on the same network
This way api can reach db using db as the hostname.
8. Cleanup: Free Up Space Without Breaking Things#
docker system df - show how much space images, containers and volumes are using
docker container prune - delete stopped containers
docker image prune - delete dangling images
docker system prune - more aggressive cleanup: stopped containers, unused networks, dangling images and build cache (volumes are kept unless you add --volumes)
9. Build: Creating Your Own Image#
A Dockerfile is the “recipe” for your image. Here is a minimal example for a Node.js app:
# Base image
FROM node:22-alpine
# Working directory inside the container
WORKDIR /app
# Dependency files first: Docker reuses the cache if they don't change
COPY package*.json ./
RUN npm ci --omit=dev
# Then the rest of the code
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]docker build -t myapp:1.0 . - build the image from the Dockerfile in the current folder
docker run -p 3000:3000 myapp:1.0 - run the image you just built
Tip: add a
.dockerignorefile listingnode_modulesand.gitto make builds faster and images smaller.
10. Real Mini Workflow (Copy-Paste): Database + Admin Panel with Docker Compose#
Example docker-compose.yml (Postgres + pgAdmin):
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: pass
POSTGRES_USER: user
POSTGRES_DB: appdb
ports:
- "5432:5432"
volumes:
- dbdata:/var/lib/postgresql/data
pgadmin:
image: dpage/pgadmin4
environment:
PGADMIN_DEFAULT_EMAIL: [email protected]
PGADMIN_DEFAULT_PASSWORD: pass
ports:
- "5050:80"
depends_on:
- db
volumes:
dbdata:Commands:
docker compose up -d - start everything in the background
docker compose ps - status of the services
docker compose logs -f - real-time logs
docker compose down - stop and remove the containers (volumes are kept)
docker compose down -v - stop everything and delete the volumes too (careful: you lose the data)
Open http://localhost:5050, log in to pgAdmin and connect to the server using db as the host.
Security: passwords written in the file are fine only locally. In real projects move them to a
.envfile (never commit it to Git) or use secrets.
Bonus: 5 Concepts That Explain Docker in 30 Seconds#
- Image = the app’s “template” (immutable)
- Container = a running instance of an image
- Volume = persistent storage for data
- Network = virtual network for communication between containers
- Compose = a simple way to manage multiple containers together
Learn 2-3 commands a week and Docker will stop looking like “black magic”.




