Comprehensive Practical Training

This is the final project for this course—it brings together the knowledge from all 23 lessons to deploy a full-stack microservice from scratch to a production environment.

1. What You'll Learn


2. A Story of a 3-Day Delivery

(1) Challenge: Moving from local to production within 3 days

Charlie was assigned a task: to deploy an e-commerce platform from local development to a production environment within three days. The architecture consisted of a React front end, a Go API, PostgreSQL, Redis, and RabbitMQ—five services and zero automated processes.

(2) A Solution for the Docker Full-Stack Toolchain

Charlie used the full-stack Docker toolchain to complete the project in two days: writing the Dockerfile → orchestrating with Compose → automated CI/CD deployment → monitoring and alerts.

(3) Benefit: Completed and delivered in 2 days

From manual deployment to full automation, we completed architecture design, containerization, orchestration, CI/CD, and monitoring in just two days—that’s the value of mastering full-stack Docker skills.


3. Full-Stack Architecture Design

(1) Architecture Overview

100%
graph TB
    USER["Browser"] --> ING["Nginx<br/>:80<br/>React SPA + API Proxy"]
    ING -->|"api/"| API1["Go API #1<br/>:8080"]
    ING -->|"api/"| API2["Go API #2<br/>:8080"]
    ING -->|"api/"| API3["Go API #3<br/>:8080"]
    API1 --> PG["PostgreSQL<br/>:5432<br/>Primary DB"]
    API2 --> PG
    API3 --> PG
    API1 --> REDIS["Redis<br/>:6379<br/>Cache"]
    API2 --> REDIS
    API3 --> MQ["RabbitMQ<br/>:5672<br/>Message Queue"]
    MQ --> WRK["Worker<br/>Background Jobs"]
    PROM["Prometheus<br/>:9090<br/>Metrics"] --> GRAF["Grafana<br/>:3000<br/>Dashboards"]
    PROM --> API1
    PROM --> PG
    PROM --> REDIS

(2) List of Services

Services Tech Stack Images Ports
Nginx Reverse proxy + static files Self-hosted (multi-stage) 80
Go API REST API Self-hosted (multi-stage) 8080
PostgreSQL Relational Database postgres:15-alpine 5432
Redis Cache + Session redis:7-alpine 6379
RabbitMQ Message Queue rabbitmq:3-management 5672/15672
Worker Background task processing Self-hosted (same as API image) -
Prometheus Metrics Collection prom/prometheus 9090
Grafana Visualization Dashboard grafana/grafana 3000

  1. Frontend Dockerfile (React + Nginx)

▶ Example: Multi-stage Build for a Frontend Dockerfile (Difficulty: ⭐⭐⭐)

DOCKERFILE
# ============================================
# Stage 1: Build React application
# ============================================
FROM node:20-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# ============================================
# Stage 2: Serve with Nginx
# ============================================
FROM nginx:1.25-alpine

# Copy built assets
COPY --from=builder /app/dist /usr/share/nginx/html

# Copy Nginx config for SPA routing
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Security: non-root user
RUN chown -R nginx:nginx /usr/share/nginx/html && \
    chown -R nginx:nginx /var/cache/nginx && \
    chown -R nginx:nginx /var/log/nginx

EXPOSE 80
HEALTHCHECK --interval=30s --timeout=5s \
  CMD wget -qO- http://localhost/ || exit 1

CMD ["nginx", "-g", "daemon off;"]

5. Backend Dockerfile (Go multi-stage)

▶ Example: Multi-stage Build in a Backend Dockerfile (Difficulty: ⭐⭐⭐)

DOCKERFILE
# ============================================
# Stage 1: Build Go binary
# ============================================
FROM golang:1.22-alpine AS builder

RUN apk add --no-cache git

WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /app/server

# ============================================
# Stage 2: Minimal runtime
# ============================================
FROM alpine:3.19

RUN apk --no-cache add ca-certificates tzdata curl && \
    adduser -D -u 1000 appuser

WORKDIR /app
COPY --from=builder /app/server .

RUN chown -R appuser:appuser /app
USER appuser

EXPOSE 8080

HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

CMD ["/app/server"]

6. Docker Compose Orchestration

▶ Example: Complete docker-compose.prod.yml (Difficulty: ⭐⭐⭐)

YAML
# ============================================
# docker-compose.prod.yml - Full stack
# ============================================
services:
  nginx:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "80:80"
    depends_on:
      api:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - frontend
      - backend
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"

  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    environment:
      DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/${DB_NAME}
      REDIS_URL: redis://redis:6379
      RABBITMQ_URL: amqp://guest:${MQ_PASSWORD}@rabbitmq:5672
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - backend
      - db-net
      - cache-net
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 15s
      timeout: 5s
      retries: 3
      start_period: 10s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"

  worker:
    build:
      context: ./api
      dockerfile: Dockerfile
    command: ["/app/server", "worker"]
    environment:
      DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/${DB_NAME}
      RABBITMQ_URL: amqp://guest:${MQ_PASSWORD}@rabbitmq:5672
    depends_on:
      postgres:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - backend
      - db-net

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser"]
      interval: 5s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - db-net

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 5s
    restart: unless-stopped
    networks:
      - cache-net

  rabbitmq:
    image: rabbitmq:3-management-alpine
    environment:
      RABBITMQ_DEFAULT_PASS: ${MQ_PASSWORD}
    ports:
      - "15672:15672"
    volumes:
      - mq-data:/var/lib/rabbitmq
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
      interval: 15s
      timeout: 10s
    restart: unless-stopped
    networks:
      - backend

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    ports:
      - "9090:9090"
    restart: unless-stopped
    networks:
      - backend
      - db-net
      - cache-net

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
    volumes:
      - grafana-data:/var/lib/grafana
    depends_on:
      - prometheus
    restart: unless-stopped
    networks:
      - backend

volumes:
  pg-data:
  redis-data:
  mq-data:
  prometheus-data:
  grafana-data:

networks:
  frontend:
  backend:
  db-net:
    internal: true
  cache-net:
    internal: true

  1. CI/CD Configuration

(1) GitHub Actions End-to-End

YAML
# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ${{ secrets.REGISTRY }}
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_PASS }}

      - name: Build and push API
        uses: docker/build-push-action@v5
        with:
          context: ./api
          push: true
          tags: ${{ secrets.REGISTRY }}/api:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Build and push Frontend
        uses: docker/build-push-action@v5
        with:
          context: ./frontend
          push: true
          tags: ${{ secrets.REGISTRY }}/frontend:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Deploy to production
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /opt/ecommerce
            export API_TAG=${{ github.sha }}
            export FRONTEND_TAG=${{ github.sha }}
            docker compose -f docker-compose.prod.yml pull
            docker compose -f docker-compose.prod.yml up -d --remove-orphans
            docker image prune -f

8. Monitoring Configuration

(1) Prometheus Configuration

YAML
# monitoring/prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'api'
    static_configs:
      - targets: ['api:8080']
    metrics_path: /metrics

  - job_name: 'postgres'
    static_configs:
      - targets: ['postgres-exporter:9187']

  - job_name: 'redis'
    static_configs:
      - targets: ['redis-exporter:9121']

  - job_name: 'rabbitmq'
    static_configs:
      - targets: ['rabbitmq:15692']

9. Deployment and Validation

(1) Deployment Checklist

Step Action Verification
1 docker compose -f docker-compose.prod.yml up -d --build docker compose ps All Up
2 Visit http://localhost React page displays correctly
3 curl http://localhost/api/health {"status":"ok"}
4 Visit http://localhost:3000 Grafana Login Page
5 Visit http://localhost:15672 RabbitMQ Management Page
6 docker compose logs api No errors in API logs

(2) Comparison Table: Bare Metal vs. Docker vs. K8s

Dimension Bare-metal deployment Docker Compose Kubernetes
Deployment Time 1–2 days 30 minutes 1–2 days (initial setup)
Repeatability
Automatic Scaling ✅ HPA
Self-healing restart policy ✅ Automatic rebuild
Zero-downtime updates Difficult Compose restart ✅ Rolling updates
Monitoring Manual Prometheus+Grafana Built-in + Prometheus
Complexity Low Medium High

10. Complete Example: One-Click Deployment of a Full-Stack Application

BASH
# ============================================
# Complete walkthrough: Full-stack deployment
# ============================================

# 1. Create .env file (NEVER commit this)
cat > .env << 'EOF'
DB_PASSWORD=secure_db_pass_2024
DB_NAME=ecommerce
REDIS_PASSWORD=secure_redis_pass
MQ_PASSWORD=secure_mq_pass
GRAFANA_PASSWORD=admin123
EOF

# 2. Build and start all services
docker compose -f docker-compose.prod.yml up -d --build

# 3. Wait for services to initialize
sleep 30

# 4. Verify all services
docker compose -f docker-compose.prod.yml ps
echo "=== Health Checks ==="
docker compose -f docker-compose.prod.yml ps --format "table {{.Name}}\t{{.Status}}"

# 5. Test the API
curl -s http://localhost/api/health

# 6. Check database connectivity
docker compose -f docker-compose.prod.yml exec postgres pg_isready -U appuser

# 7. Access monitoring
echo "Grafana: http://localhost:3000 (admin/${GRAFANA_PASSWORD})"
echo "RabbitMQ: http://localhost:15672 (guest/${MQ_PASSWORD})"
echo "Prometheus: http://localhost:9090"

# 8. View aggregated logs
docker compose -f docker-compose.prod.yml logs --tail 50 api

# 9. Scale API if needed
docker compose -f docker-compose.prod.yml up -d --scale api=5

# 10. Clean up
docker compose -f docker-compose.prod.yml down

❓ FAQ

Q How much more complex are microservices compared to a monolithic architecture?
A Operational complexity increases significantly—network configuration, service discovery, log aggregation, and distributed tracing all present new challenges. However, the benefits include independent deployment, independent scaling, and fault isolation. Recommendation: Small teams (<5 people) should use a modular monolithic architecture, while larger teams should use microservices. Don’t adopt microservices just for the sake of it.
Q How do you perform database migrations in CI/CD?
A Add migration steps before the deployment steps: ① Build the migration image; ② docker run --rm migrate:latest alembic upgrade head; ③ Deploy the new version. Key point: Migrations must be backward-compatible—the new code must support both the old and new table structures.
Q How can logs from multiple services be consolidated?
A There are three approaches: ① ELK Stack (Elasticsearch + Logstash + Kibana) — the industry standard; ② Loki + Grafana (lightweight, recommended for cloud-native environments); ③ Cloud service provider logging services (AWS CloudWatch / Alibaba Cloud SLS). All container stdout → collector → centralized storage → search dashboard.
Q How do I configure HTTPS in a production environment?
A Configure TLS in the Nginx container: ① Free Let's Encrypt certificate + automatic renewal via Certbot; ② Reverse proxy mode: Nginx handles TLS, while internal communication uses HTTP; ③ The cloud provider's load balancer handles TLS (ALB/SLB), so the container does not need a certificate.
Q How do you monitor the health of the entire microservices stack?
A The golden combination of Prometheus and Grafana: ① Prometheus collects data from the /metrics endpoints of each service; ② Grafana displays dashboards and alert rules; ③ Key metrics: API latency (P50/P95/P99), error rate, CPU/memory usage, and number of database connections. Monitor first, then optimize.

📖 Summary


📝 Exercises

  1. Basic Question (Difficulty: ⭐): Design a microservices architecture diagram for a blog system (Nginx + API + DB + Cache), and list the image and port for each service.
  2. Advanced Exercise (Difficulty: ⭐⭐): Deploy this architecture using full-stack Docker technology, write the docker-compose.prod.yml file, and successfully start the application.
  3. Challenge (Difficulty: ⭐⭐⭐): Set up a Prometheus + Grafana monitoring dashboard, add dashboards for API latency and error rates, and configure email alert rules.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏