Overview
Docker solves a classic problem: “It works on my machine, but not on yours.” This tutorial explains the core concepts, shows the most useful commands, and walks through containerizing a Python Flask application.
What Docker Solves
- Environment inconsistency between development, testing, and production
- Slow and error-prone manual server setup
- Virtual machines waste resources because each one needs a full OS
Docker packages an application and all its dependencies into a standard container that runs consistently anywhere Docker is installed.
Core Concepts
| Concept | Description | Analogy |
|---|---|---|
| Image | A read-only template containing everything needed to run an app | Like an ISO installer |
| Container | A running instance of an image with its own filesystem, network, and process space | Like a very lightweight VM |
| Dockerfile | A text file that defines how to build an image | Like a Makefile |
| Registry | A service for storing and distributing images | Like GitHub for images |
Install Docker
Ubuntu
sudo apt update
sudo apt install docker.io
sudo systemctl enable --now docker
CentOS
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
macOS and Windows
Download Docker Desktop from the Docker Desktop official site. Windows users should enable WSL2.
Verify Installation
docker --version
docker run hello-world
Essential Docker Commands
Image Commands
| Command | Purpose |
|---|---|
docker pull nginx:latest | Pull an image |
docker images | List local images |
docker rmi image_id | Remove an image |
docker build -t myapp:v1 . | Build an image |
Container Commands
| Command | Purpose |
|---|---|
docker run -d -p 8080:80 nginx | Run a container in the background with port mapping |
docker ps | List running containers |
docker ps -a | List all containers, including stopped ones |
docker stop container_id | Stop a container |
docker rm container_id | Remove a container |
docker logs container_id | View container logs |
docker exec -it container_id bash | Open a shell inside a container |
Build a Flask App with Docker
Step 1: Create the Application
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello from Docker!"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Step 2: Create a Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
Step 3: Create requirements.txt
flask==3.0.0
Step 4: Build the Image
docker build -t my-flask-app:v1 .
Step 5: Run the Container
docker run -d -p 5000:5000 --name myapp my-flask-app:v1
Visit http://localhost:5000 to see “Hello from Docker!”
Docker Compose Overview
When an app needs multiple services, Docker Compose defines them in a YAML file:
version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
Start all services with docker compose up -d and stop them with docker compose down.
Common Beginner Problems
| Problem | Solution |
|---|---|
Need sudo for every Docker command | sudo usermod -aG docker $USER && newgrp docker |
| Data disappears after container stops | Use a volume with -v |
| Code changes not reflected in image | Reorder COPY steps in the Dockerfile or build with --no-cache |
| Port already in use | Change the host port, for example -p 8080:5000 |
