--- 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