---
name: docker-traefik
description: Docker containerization và Traefik reverse proxy. Use for Dockerfile, docker-compose, routing rules, SSL termination, và load balancing.
compatibility: "Docker 24+, Docker Compose v2+, Traefik v3+"
metadata:
  author: Velik Ho
  version: "1.0"
---

# Docker & Traefik Patterns / Mẫu Docker & Traefik

Docker containerization và Traefik reverse proxy cho GoodGo microservices.

## When to Use This Skill / Khi Nào Sử Dụng

Use this skill when:
- Creating Dockerfiles for .NET services / Tạo Dockerfiles cho services .NET
- Configuring docker-compose for local dev / Cấu hình docker-compose cho dev local
- Setting up Traefik routing / Cài đặt Traefik routing
- Configuring SSL/TLS termination / Cấu hình SSL/TLS termination
- Implementing load balancing / Triển khai load balancing
- Managing service discovery / Quản lý service discovery

## Core Concepts / Khái Niệm Cốt Lõi

### Architecture Overview / Tổng Quan Kiến Trúc

```
Internet
    │
    ▼
┌─────────────────────────────────────────────────────┐
│                   Traefik (Gateway)                  │
│   - SSL Termination   - Rate Limiting               │
│   - Load Balancing    - Path Routing                │
└───────┬────────────────────────────────┬────────────┘
        │                                │
        ▼                                ▼
┌───────────────┐              ┌───────────────┐
│ iam-service   │              │ storage-svc   │
│ :8080         │              │ :8080         │
└───────────────┘              └───────────────┘
```

### Traefik Concepts / Các Khái Niệm Traefik

| Concept | Description | Example |
|---------|-------------|---------|
| **EntryPoints** | Network ports | `web:80`, `websecure:443` |
| **Routers** | Match requests to services | `PathPrefix(\`/api/v1/iam\`)` |
| **Services** | Backend targets | `loadbalancer.server.port=8080` |
| **Middlewares** | Request/Response modifiers | `stripprefix`, `ratelimit` |

### Docker Best Practices / Best Practices Docker

1. **Multi-stage builds** - Separate build and runtime
2. **Non-root user** - Security best practice
3. **Alpine images** - Smaller image size
4. **.dockerignore** - Exclude unnecessary files
5. **Layer caching** - Optimize build time

## Key Patterns / Mẫu Chính

### Dockerfile for .NET Service

```dockerfile
# ===================================
# EN: Build stage / VI: Stage build
# ===================================
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
WORKDIR /src

# EN: Copy solution and restore dependencies
# VI: Copy solution và restore dependencies
COPY *.slnx ./
COPY src/MyService.API/*.csproj src/MyService.API/
COPY src/MyService.Domain/*.csproj src/MyService.Domain/
COPY src/MyService.Infrastructure/*.csproj src/MyService.Infrastructure/
RUN dotnet restore

# EN: Copy source code and build
# VI: Copy source code và build
COPY src/ src/
RUN dotnet publish src/MyService.API -c Release -o /app --no-restore

# ===================================
# EN: Runtime stage / VI: Stage runtime
# ===================================
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS runtime
WORKDIR /app

# EN: Install additional packages if needed
# VI: Cài đặt packages bổ sung nếu cần
RUN apk add --no-cache icu-libs

# EN: Create non-root user for security
# VI: Tạo user không phải root để bảo mật
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

# EN: Copy published files
# VI: Copy files đã publish
COPY --from=build --chown=appuser:appgroup /app .

# EN: Configure environment
# VI: Cấu hình môi trường
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production
ENV DOTNET_RUNNING_IN_CONTAINER=true

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health/live || exit 1

ENTRYPOINT ["dotnet", "MyService.API.dll"]
```

### Docker Compose với Traefik

```yaml
# docker-compose.yml
version: "3.8"

services:
  # ===================================
  # Traefik - API Gateway
  # ===================================
  traefik:
    image: traefik:v3.0
    container_name: traefik
    command:
      # EN: Enable API and Dashboard
      # VI: Bật API và Dashboard
      - "--api.dashboard=true"
      - "--api.insecure=true"
      
      # EN: Docker provider configuration
      # VI: Cấu hình Docker provider
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.network=goodgo-network"
      
      # EN: Entrypoints
      # VI: Các điểm vào
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      
      # EN: Access logs
      # VI: Logs truy cập
      - "--accesslog=true"
      - "--accesslog.format=json"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"  # Dashboard
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - goodgo-network
    labels:
      # EN: Enable Traefik dashboard
      # VI: Bật Traefik dashboard
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.localhost`)"
      - "traefik.http.routers.dashboard.service=api@internal"

  # ===================================
  # IAM Service
  # ===================================
  iam-service-net:
    build:
      context: ../..
      dockerfile: services/iam-service-net/Dockerfile
    container_name: iam-service-net
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ConnectionStrings__DefaultConnection=${IAM_DATABASE_URL}
    labels:
      - "traefik.enable=true"
      # EN: Router configuration / VI: Cấu hình router
      - "traefik.http.routers.iam-service-net.rule=PathPrefix(`/api/v1/iam`)"
      - "traefik.http.routers.iam-service-net.entrypoints=web"
      # EN: Service configuration / VI: Cấu hình service
      - "traefik.http.services.iam-service-net.loadbalancer.server.port=8080"
      # EN: Health check / VI: Kiểm tra sức khỏe
      - "traefik.http.services.iam-service-net.loadbalancer.healthcheck.path=/health/live"
      - "traefik.http.services.iam-service-net.loadbalancer.healthcheck.interval=10s"
    networks:
      - goodgo-network
    depends_on:
      - postgres

  # ===================================
  # Storage Service
  # ===================================
  storage-service-net:
    build:
      context: ../..
      dockerfile: services/storage-service-net/Dockerfile
    container_name: storage-service-net
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ConnectionStrings__DefaultConnection=${STORAGE_DATABASE_URL}
      - MinIO__Endpoint=${MINIO_ENDPOINT}
      - MinIO__AccessKey=${MINIO_ACCESS_KEY}
      - MinIO__SecretKey=${MINIO_SECRET_KEY}
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.storage-service-net.rule=PathPrefix(`/api/v1/storage`)"
      - "traefik.http.routers.storage-service-net.entrypoints=web"
      - "traefik.http.services.storage-service-net.loadbalancer.server.port=8080"
    networks:
      - goodgo-network
    depends_on:
      - postgres
      - minio

  # ===================================
  # PostgreSQL
  # ===================================
  postgres:
    image: postgres:15-alpine
    container_name: postgres
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - goodgo-network

  # ===================================
  # MinIO (S3-compatible storage)
  # ===================================
  minio:
    image: minio/minio:latest
    container_name: minio
    command: server /data --console-address ":9001"
    environment:
      - MINIO_ROOT_USER=minioadmin
      - MINIO_ROOT_PASSWORD=minioadmin
    volumes:
      - minio_data:/data
    ports:
      - "9000:9000"
      - "9001:9001"
    networks:
      - goodgo-network

networks:
  goodgo-network:
    driver: bridge

volumes:
  postgres_data:
  minio_data:
```

### Traefik Middlewares

```yaml
# EN: Strip path prefix middleware
# VI: Middleware bỏ prefix path
services:
  iam-service-net:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.iam-service-net.rule=PathPrefix(`/api/v1/iam`)"
      - "traefik.http.routers.iam-service-net.entrypoints=web"
      # EN: Apply middleware to strip prefix
      # VI: Áp dụng middleware để bỏ prefix
      - "traefik.http.routers.iam-service-net.middlewares=iam-stripprefix"
      - "traefik.http.middlewares.iam-stripprefix.stripprefix.prefixes=/api/v1/iam"
      - "traefik.http.services.iam-service-net.loadbalancer.server.port=8080"
```

### Rate Limiting Middleware

```yaml
services:
  api-service:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=PathPrefix(`/api`)"
      # EN: Rate limiting middleware
      # VI: Middleware giới hạn rate
      - "traefik.http.routers.api.middlewares=api-ratelimit"
      - "traefik.http.middlewares.api-ratelimit.ratelimit.average=100"
      - "traefik.http.middlewares.api-ratelimit.ratelimit.burst=50"
      - "traefik.http.middlewares.api-ratelimit.ratelimit.period=1m"
```

## Common Mistakes / Lỗi Thường Gặp

### 1. Running as Root

```dockerfile
# ❌ BAD: Running as root
FROM mcr.microsoft.com/dotnet/aspnet:8.0
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyService.dll"]

# ✅ GOOD: Non-root user
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
RUN adduser -D appuser
USER appuser
COPY --from=build --chown=appuser /app .
ENTRYPOINT ["dotnet", "MyService.dll"]
```

### 2. No Health Checks

```yaml
# ❌ BAD: No health check
services:
  my-service:
    build: .
    labels:
      - "traefik.enable=true"

# ✅ GOOD: With health check
services:
  my-service:
    build: .
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.my-service.loadbalancer.healthcheck.path=/health/live"
      - "traefik.http.services.my-service.loadbalancer.healthcheck.interval=10s"
```

### 3. Exposing Internal Ports

```yaml
# ❌ BAD: Exposing all ports
services:
  my-service:
    ports:
      - "8080:8080"  # Direct access bypasses Traefik

# ✅ GOOD: Only expose through Traefik
services:
  my-service:
    # No ports exposed directly
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.my-service.loadbalancer.server.port=8080"
```

## Quick Reference / Tham Chiếu Nhanh

### Docker Commands

```bash
# EN: Build and start / VI: Build và start
docker-compose -f deployments/local/docker-compose.yml up -d --build

# EN: View logs / VI: Xem logs
docker-compose logs -f iam-service-net

# EN: Restart service / VI: Restart service
docker-compose restart iam-service-net

# EN: Stop all / VI: Dừng tất cả
docker-compose down

# EN: Clean rebuild / VI: Rebuild sạch
docker-compose down -v && docker-compose up -d --build
```

### Traefik Router Rules

| Rule | Example | Description |
|------|---------|-------------|
| `Host` | ``Host(`api.example.com`)`` | Match by hostname |
| `PathPrefix` | ``PathPrefix(`/api`)`` | Match by path prefix |
| `Path` | ``Path(`/api/health`)`` | Match exact path |
| `Method` | ``Method(`GET`, `POST`)`` | Match by HTTP method |
| `Headers` | ``Headers(`X-Custom`, `value`)`` | Match by header |

### Common Labels

```yaml
# EN: Basic routing / VI: Routing cơ bản
- "traefik.enable=true"
- "traefik.http.routers.{name}.rule=PathPrefix(`/path`)"
- "traefik.http.routers.{name}.entrypoints=web"
- "traefik.http.services.{name}.loadbalancer.server.port=8080"

# EN: With HTTPS / VI: Với HTTPS
- "traefik.http.routers.{name}-secure.rule=PathPrefix(`/path`)"
- "traefik.http.routers.{name}-secure.entrypoints=websecure"
- "traefik.http.routers.{name}-secure.tls=true"
```

## Resources / Tài Nguyên

- [Detailed Examples](./references/REFERENCE.md) - Full configurations
- [Project Rules](../project-rules/SKILL.md) - Docker naming conventions
- [Observability](../observability/SKILL.md) - Container monitoring
- [Error Handling](../error-handling-patterns/SKILL.md) - Health checks
