feat: initial Claude Code configuration scaffold
Comprehensive Claude Code guidance system with: - 5 agents: tdd-guardian, code-reviewer, security-scanner, refactor-scan, dependency-audit - 18 skills covering languages (Python, TypeScript, Rust, Go, Java, C#), infrastructure (AWS, Azure, GCP, Terraform, Ansible, Docker/K8s, Database, CI/CD), testing (TDD, UI, Browser), and patterns (Monorepo, API Design, Observability) - 3 hooks: secret detection, auto-formatting, TDD git pre-commit - Strict TDD enforcement with 80%+ coverage requirements - Multi-model strategy: Opus for planning, Sonnet for execution (opusplan) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
459
.claude/skills/infrastructure/docker-kubernetes/SKILL.md
Normal file
459
.claude/skills/infrastructure/docker-kubernetes/SKILL.md
Normal file
@@ -0,0 +1,459 @@
|
||||
---
|
||||
name: docker-kubernetes
|
||||
description: Docker containerization and Kubernetes orchestration patterns. Use when building containers, writing Dockerfiles, or deploying to Kubernetes.
|
||||
---
|
||||
|
||||
# Docker & Kubernetes Skill
|
||||
|
||||
## Dockerfile Best Practices
|
||||
|
||||
### Multi-Stage Build (Python)
|
||||
```dockerfile
|
||||
# Build stage
|
||||
FROM python:3.12-slim as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install build dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Python dependencies
|
||||
COPY pyproject.toml uv.lock ./
|
||||
RUN pip install uv && uv sync --frozen --no-dev
|
||||
|
||||
# Production stage
|
||||
FROM python:3.12-slim as production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Create non-root user
|
||||
RUN groupadd -r appuser && useradd -r -g appuser appuser
|
||||
|
||||
# Copy only necessary files from builder
|
||||
COPY --from=builder /app/.venv /app/.venv
|
||||
COPY src/ ./src/
|
||||
|
||||
# Set environment
|
||||
ENV PATH="/app/.venv/bin:$PATH"
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Switch to non-root user
|
||||
USER appuser
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"
|
||||
|
||||
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
```
|
||||
|
||||
### Multi-Stage Build (Node.js)
|
||||
```dockerfile
|
||||
# Build stage
|
||||
FROM node:22-alpine as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies first (layer caching)
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
# Build application
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM node:22-alpine as production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -S appuser && adduser -S appuser -G appuser
|
||||
|
||||
# Copy only production dependencies and built files
|
||||
COPY --from=builder /app/package*.json ./
|
||||
RUN npm ci --only=production && npm cache clean --force
|
||||
|
||||
COPY --from=builder /app/dist ./dist
|
||||
|
||||
USER appuser
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
|
||||
|
||||
CMD ["node", "dist/main.js"]
|
||||
```
|
||||
|
||||
### Multi-Stage Build (Rust)
|
||||
```dockerfile
|
||||
# Build stage
|
||||
FROM rust:1.75-slim as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Create a dummy project for dependency caching
|
||||
RUN cargo new --bin app
|
||||
WORKDIR /app/app
|
||||
|
||||
# Copy manifests and build dependencies
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
RUN cargo build --release && rm -rf src
|
||||
|
||||
# Copy source and build
|
||||
COPY src ./src
|
||||
RUN touch src/main.rs && cargo build --release
|
||||
|
||||
# Production stage
|
||||
FROM debian:bookworm-slim as production
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create non-root user
|
||||
RUN groupadd -r appuser && useradd -r -g appuser appuser
|
||||
|
||||
COPY --from=builder /app/app/target/release/app /usr/local/bin/app
|
||||
|
||||
USER appuser
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD ["/usr/local/bin/app", "health"]
|
||||
|
||||
CMD ["/usr/local/bin/app"]
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
|
||||
### Development Setup
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
target: development
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- .:/app
|
||||
- /app/.venv # Exclude venv from mount
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://user:pass@db:5432/myapp
|
||||
- REDIS_URL=redis://redis:6379/0
|
||||
- DEBUG=true
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_USER: user
|
||||
POSTGRES_PASSWORD: pass
|
||||
POSTGRES_DB: myapp
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
```
|
||||
|
||||
### Production Setup
|
||||
```yaml
|
||||
# docker-compose.prod.yml
|
||||
services:
|
||||
app:
|
||||
image: ${REGISTRY}/myapp:${VERSION}
|
||||
deploy:
|
||||
replicas: 3
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
environment:
|
||||
- DATABASE_URL_FILE=/run/secrets/db_url
|
||||
secrets:
|
||||
- db_url
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
secrets:
|
||||
db_url:
|
||||
external: true
|
||||
```
|
||||
|
||||
## Kubernetes Manifests
|
||||
|
||||
### Deployment
|
||||
```yaml
|
||||
# k8s/deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myapp
|
||||
labels:
|
||||
app: myapp
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: myapp
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: myapp
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: myapp
|
||||
image: myregistry/myapp:v1.0.0
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
resources:
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: "128Mi"
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: "512Mi"
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: myapp-secrets
|
||||
key: database-url
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8000
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /ready
|
||||
port: 8000
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
```
|
||||
|
||||
### Service
|
||||
```yaml
|
||||
# k8s/service.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
selector:
|
||||
app: myapp
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8000
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: myapp
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- myapp.example.com
|
||||
secretName: myapp-tls
|
||||
rules:
|
||||
- host: myapp.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: myapp
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
### ConfigMap and Secrets
|
||||
```yaml
|
||||
# k8s/config.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: myapp-config
|
||||
data:
|
||||
LOG_LEVEL: "info"
|
||||
CACHE_TTL: "3600"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: myapp-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
database-url: postgresql://user:pass@db:5432/myapp # Use sealed-secrets in production
|
||||
```
|
||||
|
||||
### Horizontal Pod Autoscaler
|
||||
```yaml
|
||||
# k8s/hpa.yaml
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: myapp
|
||||
minReplicas: 2
|
||||
maxReplicas: 10
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 70
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 80
|
||||
```
|
||||
|
||||
## Helm Chart Structure
|
||||
|
||||
```
|
||||
myapp-chart/
|
||||
├── Chart.yaml
|
||||
├── values.yaml
|
||||
├── values-prod.yaml
|
||||
├── templates/
|
||||
│ ├── _helpers.tpl
|
||||
│ ├── deployment.yaml
|
||||
│ ├── service.yaml
|
||||
│ ├── ingress.yaml
|
||||
│ ├── configmap.yaml
|
||||
│ ├── secret.yaml
|
||||
│ └── hpa.yaml
|
||||
└── charts/
|
||||
```
|
||||
|
||||
### values.yaml
|
||||
```yaml
|
||||
replicaCount: 2
|
||||
|
||||
image:
|
||||
repository: myregistry/myapp
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
host: myapp.example.com
|
||||
tls: true
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 2
|
||||
maxReplicas: 10
|
||||
targetCPUUtilization: 70
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Docker
|
||||
docker build -t myapp:latest .
|
||||
docker build --target development -t myapp:dev .
|
||||
docker run -p 8000:8000 myapp:latest
|
||||
docker compose up -d
|
||||
docker compose logs -f app
|
||||
docker compose down -v
|
||||
|
||||
# Kubernetes
|
||||
kubectl apply -f k8s/
|
||||
kubectl get pods -l app=myapp
|
||||
kubectl logs -f deployment/myapp
|
||||
kubectl rollout status deployment/myapp
|
||||
kubectl rollout undo deployment/myapp
|
||||
kubectl port-forward svc/myapp 8000:80
|
||||
|
||||
# Helm
|
||||
helm install myapp ./myapp-chart
|
||||
helm upgrade myapp ./myapp-chart -f values-prod.yaml
|
||||
helm rollback myapp 1
|
||||
helm uninstall myapp
|
||||
```
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- [ ] Run as non-root user
|
||||
- [ ] Use multi-stage builds (minimal final image)
|
||||
- [ ] Pin base image versions
|
||||
- [ ] Scan images for vulnerabilities (Trivy, Snyk)
|
||||
- [ ] No secrets in images or environment variables
|
||||
- [ ] Read-only root filesystem where possible
|
||||
- [ ] Drop all capabilities, add only needed ones
|
||||
- [ ] Set resource limits
|
||||
- [ ] Use network policies
|
||||
- [ ] Enable Pod Security Standards
|
||||
Reference in New Issue
Block a user