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
- Full-Stack Microservices Architecture Design
- Hands-On, End-to-End Multi-Stage Development
- Multi-service Compose orchestration
- CI/CD Automated Deployment
- Setting Up a Monitoring and Alerting System
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
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 |
- Frontend Dockerfile (React + Nginx)
▶ Example: Multi-stage Build for a Frontend Dockerfile (Difficulty: ⭐⭐⭐)
# ============================================
# 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: ⭐⭐⭐)
# ============================================
# 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: ⭐⭐⭐)
# ============================================
# 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
- CI/CD Configuration
(1) GitHub Actions End-to-End
# .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
# 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
# ============================================
# 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
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.📖 Summary
- Full-stack microservices = Frontend + API + DB + Cache + MQ + Monitoring + CI/CD
- Multi-stage frontend: Node build → Nginx runtime; image size reduced from 1 GB to 25 MB
- Backend multi-stage: Go compilation → Alpine execution; image size reduced from 780 MB to 15 MB
- Compose: Network isolation (db-net internal) + health checks + resource limits + log rotation
- CI/CD: push → build → push → SSH deployment—fully automated with zero manual intervention
- Prometheus + Grafana: Metrics Collection + Visualization + Alerts—Essential for Operations
📝 Exercises
- 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.
- Advanced Exercise (Difficulty: ⭐⭐): Deploy this architecture using full-stack Docker technology, write the
docker-compose.prod.ymlfile, and successfully start the application. - Challenge (Difficulty: ⭐⭐⭐): Set up a Prometheus + Grafana monitoring dashboard, add dashboards for API latency and error rates, and configure email alert rules.



