Migrate
This commit is contained in:
401
microservices/.agent/skills/docker-traefik/SKILL.md
Normal file
401
microservices/.agent/skills/docker-traefik/SKILL.md
Normal file
@@ -0,0 +1,401 @@
|
||||
---
|
||||
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
|
||||
Reference in New Issue
Block a user