Skip to content
AyoKoding

Quick Start

Want to containerize applications and achieve consistent deployments? This quick start introduces essential Docker concepts through practical examples. You'll build from simple containers to multi-container networked applications.

This tutorial provides 5-30% coverage using the touchpoints approach - 10 core concepts with runnable examples. After completing this guide, continue to By Example - Beginner for comprehensive 0-40% coverage.

Prerequisites

Before starting, ensure you have completed Initial Setup. You should have:

  • Docker installed and running
  • Experience running basic containers
  • Understanding of container lifecycle
  • A terminal and text editor ready

Learning Path

This quick start covers 10 essential Docker touchpoints:

%% Color Palette: Blue #0173B2, Orange #DE8F05, Teal #029E73, Purple #CC78BC
graph TD
    A["1. Container Basics"] --> B["2. Dockerfile"]
    B --> C["3. Image Building"]
    C --> D["4. Port Mapping"]
    D --> E["5. Volumes"]
    E --> F["6. Networks"]
    F --> G["7. Environment Variables"]
    G --> H["8. Docker Compose"]
    H --> I["9. Multi-Stage Builds"]
    I --> J["10. Health Checks"]
 
    style A fill:#0173B2,color:#fff
    style B fill:#0173B2,color:#fff
    style C fill:#029E73,color:#fff
    style D fill:#029E73,color:#fff
    style E fill:#DE8F05,color:#fff
    style F fill:#DE8F05,color:#fff
    style G fill:#CC78BC,color:#fff
    style H fill:#CC78BC,color:#fff
    style I fill:#0173B2,color:#fff
    style J fill:#DE8F05,color:#fff

Concept 1: Container Basics

What: Isolated, lightweight runtime environments from images.

Why: Consistent application deployment across development, testing, production.

Example: Interactive Container Management

docker run -it --name myubuntu ubuntu:22.04 bash
 
apt update
apt install curl -y
curl --version
exit
 
docker ps -a
 
docker start myubuntu
 
docker exec myubuntu curl --version
 
docker attach myubuntu
 
docker stop myubuntu
 
docker rm myubuntu

Key points:

  • -it: Interactive terminal
  • --name: Custom container name
  • docker exec: Run commands without attaching
  • docker attach: Connect to container's main process
  • Containers are ephemeral - state lost when removed

Concept 2: Dockerfile

What: Text file with instructions to build Docker images.

Why: Automate image creation with version-controlled configuration.

Example: Simple Web Application

Create app.py:

from http.server import HTTPServer, BaseHTTPRequestHandler
 
class SimpleHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(b'<h1>Hello from Docker!</h1>')
 
if __name__ == '__main__':
    server = HTTPServer(('0.0.0.0', 8000), SimpleHandler)
    print('Server running on port 8000')
    server.serve_forever()

Create Dockerfile:

FROM python:3.11-slim
 
WORKDIR /app
 
COPY app.py .
 
EXPOSE 8000
 
CMD ["python", "app.py"]

Build and run:

docker build -t mywebapp:1.0 .
 
docker run -d -p 8000:8000 --name webapp mywebapp:1.0
 
curl http://localhost:8000
 
docker logs webapp
 
docker stop webapp
docker rm webapp

Key points:

  • FROM: Base image
  • WORKDIR: Set working directory
  • COPY: Copy files into image
  • EXPOSE: Document port (informational)
  • CMD: Default command to run
  • -d: Detached mode (background)

Concept 3: Image Building

What: Create custom images from Dockerfile with layers and caching.

Why: Package applications with dependencies for portable deployment.

Example: Multi-Layer Image

Create requirements.txt:

flask==3.0.0
requests==2.31.0

Create server.py:

from flask import Flask
import os
 
app = Flask(__name__)
 
@app.route('/')
def hello():
    version = os.getenv('APP_VERSION', 'unknown')
    return f'<h1>Flask App v{version}</h1>'
 
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Create Dockerfile:

FROM python:3.11-slim
 
WORKDIR /app
 
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
 
COPY server.py .
 
EXPOSE 5000
 
CMD ["python", "server.py"]

Build with tags:

docker build -t flaskapp:1.0 -t flaskapp:latest .
 
docker history flaskapp:1.0
 
docker inspect flaskapp:1.0
 
docker run -d -p 5000:5000 -e APP_VERSION=1.0.0 --name flask flaskapp:1.0
 
curl http://localhost:5000
 
docker stop flask
docker rm flask

Key points:

  • Each Dockerfile instruction creates a layer
  • Layers are cached for faster rebuilds
  • Order matters - put changing files last
  • Multiple tags point to same image
  • docker history shows layer size and commands

Concept 4: Port Mapping

What: Map container ports to host ports for external access.

Why: Enable communication between containers and external clients.

Example: Multiple Port Mappings

Create multiport.py:

from http.server import HTTPServer, BaseHTTPRequestHandler
import threading
 
class Handler8000(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(b'<h1>Service on port 8000</h1>')
 
class Handler9000(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(b'<h1>Service on port 9000</h1>')
 
def run_server(port, handler):
    server = HTTPServer(('0.0.0.0', port), handler)
    print(f'Server running on port {port}')
    server.serve_forever()
 
if __name__ == '__main__':
    t1 = threading.Thread(target=run_server, args=(8000, Handler8000))
    t2 = threading.Thread(target=run_server, args=(9000, Handler9000))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

Create Dockerfile:

FROM python:3.11-slim
WORKDIR /app
COPY multiport.py .
EXPOSE 8000 9000
CMD ["python", "multiport.py"]

Run with multiple ports:

docker build -t multiport .
 
docker run -d -p 8000:8000 -p 9000:9000 --name multi multiport
 
curl http://localhost:8000
curl http://localhost:9000
 
docker stop multi
docker rm multi
docker run -d -p 3000:8000 -p 3001:9000 --name multi multiport
 
curl http://localhost:3000
curl http://localhost:3001
 
docker stop multi
docker rm multi

Key points:

  • -p host:container maps ports
  • Can map same container port to different host ports
  • Host port must be unique across containers
  • EXPOSE in Dockerfile is documentation only
  • -P publishes all exposed ports to random host ports

Concept 5: Volumes

What: Persistent data storage outside container filesystem.

Why: Preserve data when containers are removed or upgraded.

Example: Named Volumes and Bind Mounts

docker volume create mydata
 
docker run -d --name db1 \
  -v mydata:/data \
  alpine sh -c "echo 'Data from db1' > /data/info.txt && tail -f /dev/null"
 
docker exec db1 cat /data/info.txt
 
docker stop db1
docker rm db1
 
docker run -d --name db2 \
  -v mydata:/data \
  alpine tail -f /dev/null
 
docker exec db2 cat /data/info.txt
 
mkdir -p /tmp/docker-data
echo "Host file" > /tmp/docker-data/host.txt
 
docker run --rm -v /tmp/docker-data:/app alpine cat /app/host.txt
 
docker volume ls
 
docker volume inspect mydata
 
docker stop db2
docker rm db2
docker volume rm mydata
rm -rf /tmp/docker-data

Key points:

  • Named volumes: managed by Docker, portable
  • Bind mounts: direct host directory mapping
  • Volumes persist after container deletion
  • Multiple containers can share volumes
  • Use volumes for databases, uploads, logs
  • docker volume prune removes unused volumes

Concept 6: Networks

What: Isolated virtual networks for container communication.

Why: Enable multi-container applications with service discovery.

Example: Custom Bridge Network

docker network create mynet
 
docker run -d --name web --network mynet nginx:alpine
 
docker run -it --rm --network mynet alpine sh
 
apk add curl
curl http://web  # Works! DNS resolution by container name
exit
 
docker network inspect mynet
 
docker run -d --name isolated nginx:alpine
 
docker exec isolated ping -c 1 web  # Fails
 
docker network connect mynet isolated
docker exec isolated ping -c 1 web  # Now works!
 
docker network disconnect mynet isolated
 
docker stop web isolated
docker rm web isolated
docker network rm mynet

Key points:

  • Custom networks enable DNS-based service discovery
  • Containers on same network communicate by name
  • Default bridge network requires --link (deprecated)
  • docker network create creates isolated networks
  • Containers can connect to multiple networks
  • Network drivers: bridge, host, overlay, macvlan

Concept 7: Environment Variables

What: Pass configuration to containers at runtime.

Why: Configure containers without rebuilding images.

Example: Configuration via Environment

Create config-app.py:

import os
 
db_host = os.getenv('DB_HOST', 'localhost')
db_port = os.getenv('DB_PORT', '5432')
db_user = os.getenv('DB_USER', 'admin')
db_password = os.getenv('DB_PASSWORD', '')
debug = os.getenv('DEBUG', 'false').lower() == 'true'
 
print(f'Database: {db_user}@{db_host}:{db_port}')
print(f'Debug mode: {debug}')
print(f'Password set: {"yes" if db_password else "no"}')

Create Dockerfile:

FROM python:3.11-slim
WORKDIR /app
COPY config-app.py .
ENV DEBUG=false
ENV DB_PORT=5432
CMD ["python", "config-app.py"]

Run with different configurations:

docker build -t configapp .
 
docker run --rm configapp
 
docker run --rm \
  -e DB_HOST=prod-db.example.com \
  -e DB_USER=produser \
  -e DB_PASSWORD=secret123 \
  -e DEBUG=true \
  configapp
 
cat > .env <<EOF
DB_HOST=staging-db.example.com
DB_USER=staginguser
DB_PASSWORD=staging-password
DEBUG=false
EOF
 
docker run --rm --env-file .env configapp
 
rm .env

Key points:

  • ENV in Dockerfile sets default values
  • -e flag sets or overrides variables
  • --env-file loads variables from file
  • Environment variables configure without rebuilding
  • Use for database URLs, API keys, feature flags
  • Never commit sensitive .env files

Concept 8: Docker Compose

What: Define and run multi-container applications with YAML.

Why: Orchestrate complex applications with single command.

Example: Web Application with Database

Create app.py:

from flask import Flask
import os
import time
 
app = Flask(__name__)
 
@app.route('/')
def hello():
    db_host = os.getenv('DATABASE_HOST', 'unknown')
    return f'<h1>Web App</h1><p>Database: {db_host}</p>'
 
@app.route('/health')
def health():
    return 'OK', 200
 
if __name__ == '__main__':
    time.sleep(5)  # Wait for database
    app.run(host='0.0.0.0', port=5000)

Create requirements.txt:

flask==3.0.0

Create Dockerfile:

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]

Create compose.yaml:

services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      - DATABASE_HOST=db
    depends_on:
      - db
    networks:
      - app-network
 
  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_PASSWORD=secret
      - POSTGRES_USER=appuser
      - POSTGRES_DB=appdb
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - app-network
 
networks:
  app-network:
 
volumes:
  db-data:

Run multi-container application:

docker compose up -d
 
docker compose logs
 
curl http://localhost:5000
 
docker compose ps
 
docker compose up -d --scale web=3
 
docker compose down
 
docker compose down -v

Key points:

  • compose.yaml defines complete application
  • services: containers to run
  • networks: automatic service discovery
  • volumes: persistent data storage
  • depends_on: startup order
  • docker compose up: start all services
  • docker compose down: stop and remove

Concept 9: Multi-Stage Builds

What: Use multiple FROM statements to create optimized images.

Why: Reduce final image size by excluding build tools.

Example: Go Application Build

Create main.go:

package main
 
import (
    "fmt"
    "net/http"
)
 
func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Go Application</h1>")
}
 
func main() {
    http.HandleFunc("/", handler)
    fmt.Println("Server running on port 8080")
    http.ListenAndServe(":8080", nil)
}

Create Dockerfile (single-stage - large):

FROM golang:1.21
WORKDIR /app
COPY main.go .
RUN go build -o server main.go
CMD ["./server"]

Create Dockerfile.multistage (multi-stage - small):

FROM golang:1.21 AS builder
WORKDIR /app
COPY main.go .
RUN go build -o server main.go
 
FROM alpine:latest
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]

Compare image sizes:

docker build -t goapp-large -f Dockerfile .
 
docker build -t goapp-small -f Dockerfile.multistage .
 
docker images | grep goapp
 
docker run -d -p 8080:8080 --name goapp goapp-small
 
curl http://localhost:8080
 
docker stop goapp
docker rm goapp

Key points:

  • Multiple FROM statements create stages
  • AS builder names build stage
  • COPY --from=builder copies artifacts between stages
  • Final stage only includes runtime dependencies
  • Dramatically reduces image size (1GB+ to 10MB)
  • Faster pulls, less attack surface

Concept 10: Health Checks

What: Define commands to check container health status.

Why: Enable automatic recovery and load balancer integration.

Example: Application with Health Check

Create health-app.py:

from http.server import HTTPServer, BaseHTTPRequestHandler
import time
import random
 
start_time = time.time()
 
class HealthHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        # Healthy after 10 seconds
        uptime = time.time() - start_time
 
        if self.path == '/health':
            if uptime < 10:
                self.send_response(503)  # Service Unavailable
                self.end_headers()
                self.wfile.write(b'Starting up...')
            else:
                self.send_response(200)
                self.end_headers()
                self.wfile.write(b'Healthy')
        else:
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            self.wfile.write(b'<h1>Application Running</h1>')
 
if __name__ == '__main__':
    server = HTTPServer(('0.0.0.0', 8000), HealthHandler)
    print('Server starting...')
    server.serve_forever()

Create Dockerfile:

FROM python:3.11-slim
WORKDIR /app
COPY health-app.py .
EXPOSE 8000
 
HEALTHCHECK --interval=5s --timeout=3s --start-period=15s --retries=3 \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"
 
CMD ["python", "health-app.py"]

Run and monitor health:

docker build -t healthapp .
 
docker run -d -p 8000:8000 --name health healthapp
 
watch -n 1 'docker ps --filter name=health --format "table {{.Names}}\t{{.Status}}"'
 
docker inspect health --format='{{json .State.Health}}' | python -m json.tool
 
docker exec health pkill python
 
docker ps -a
 
docker stop health
docker rm health

Key points:

  • HEALTHCHECK instruction defines health check
  • --interval: Time between checks
  • --timeout: Maximum check duration
  • --start-period: Initialization grace period
  • --retries: Failures before unhealthy
  • Exit code 0: healthy, 1: unhealthy
  • Orchestrators can restart unhealthy containers

Learning Path Summary

You've completed 10 essential Docker touchpoints:

%% Color Palette: Blue #0173B2, Orange #DE8F05, Teal #029E73, Purple #CC78BC
graph TD
    A["Containers &<br/>Dockerfiles"] --> B["Images &<br/>Ports"]
    B --> C["Volumes &<br/>Networks"]
    C --> D["Env Vars &<br/>Compose"]
    D --> E["Multi-Stage &<br/>Health"]
 
    style A fill:#0173B2,color:#fff
    style B fill:#029E73,color:#fff
    style C fill:#DE8F05,color:#fff
    style D fill:#CC78BC,color:#fff
    style E fill:#0173B2,color:#fff

Next Steps

Now that you understand core Docker concepts:

  1. By Example - Beginner: Deep dive into 0-40% coverage with 25+ annotated examples
  2. By Example - Intermediate: Advance to 40-75% coverage with orchestration
  3. By Example - Advanced: Master 75-95% coverage with production patterns

Further Resources

Official Documentation:

Key Concepts:

  • Containers: Isolated runtime environments
  • Images: Template for containers with layers
  • Dockerfile: Automated image build instructions
  • Volumes: Persistent data storage
  • Networks: Container communication
  • Compose: Multi-container orchestration
  • Multi-stage: Optimized image building
  • Health checks: Container health monitoring

Summary

You've completed the Docker Quick Start with 5-30% coverage! You now understand:

  • Container lifecycle and management
  • Dockerfile syntax and image building
  • Layer caching and optimization
  • Port mapping for external access
  • Volume types and data persistence
  • Custom networks and service discovery
  • Environment variable configuration
  • Docker Compose for multi-container apps
  • Multi-stage builds for small images
  • Health checks for reliability

Continue your journey with comprehensive By Example tutorials for deeper mastery of Docker containerization.

Last updated January 28, 2025

Command Palette

Search for a command to run...