Claude-skill-registry docker-devops
Docker orchestration and CI/CD for IntelliFill. Use when configuring containers, writing workflows, or setting up environments.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/docker-devops" ~/.claude/skills/majiayu000-claude-skill-registry-docker-devops && rm -rf "$T"
manifest:
skills/data/docker-devops/SKILL.mdsource content
Docker & DevOps Skill
This skill provides comprehensive guidance for Docker orchestration, CI/CD pipelines, and deployment strategies in IntelliFill.
Table of Contents
- Docker Architecture
- Dockerfile Patterns
- Docker Compose
- GitHub Actions
- Environment Management
- Health Checks
- Deployment Strategies
Docker Architecture
IntelliFill uses a multi-container architecture with Docker Compose.
Container Structure
IntelliFill/ ├── quikadmin/ # Backend API container │ ├── Dockerfile.dev # Development build │ ├── Dockerfile.prod # Production build │ └── Dockerfile.test # Testing build ├── quikadmin-web/ # Frontend UI container │ ├── Dockerfile.dev │ └── Dockerfile.prod ├── docker-compose.yml # Development orchestration └── docker-compose.e2e.yml # E2E testing orchestration
Service Overview
# Services in docker-compose.yml services: postgres: # PostgreSQL database redis: # Redis cache & queues backend: # Express API frontend: # React UI nginx: # Reverse proxy (production)
Dockerfile Patterns
IntelliFill uses multi-stage builds for optimization.
Backend Dockerfile (Development)
# quikadmin/Dockerfile.dev FROM node:18-alpine AS base # Install dependencies for native modules RUN apk add --no-cache \ python3 \ make \ g++ \ cairo-dev \ jpeg-dev \ pango-dev \ giflib-dev WORKDIR /app # Copy package files COPY package*.json ./ COPY prisma ./prisma/ # Install dependencies RUN npm ci # Copy source code COPY . . # Generate Prisma Client RUN npx prisma generate # Expose port EXPOSE 3002 # Development command with hot reload CMD ["npm", "run", "dev"]
Backend Dockerfile (Production)
# quikadmin/Dockerfile.prod FROM node:18-alpine AS builder # Install build dependencies RUN apk add --no-cache \ python3 \ make \ g++ \ cairo-dev \ jpeg-dev \ pango-dev WORKDIR /app # Copy package files COPY package*.json ./ COPY prisma ./prisma/ # Install dependencies (production only) RUN npm ci --only=production # Copy source COPY . . # Generate Prisma Client RUN npx prisma generate # Build TypeScript RUN npm run build # Production stage FROM node:18-alpine AS production WORKDIR /app # Copy from builder COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist COPY --from=builder /app/prisma ./prisma COPY --from=builder /app/package*.json ./ # Create non-root user RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 USER nodejs EXPOSE 3002 # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD node -e "require('http').get('http://localhost:3002/api/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1); });" CMD ["node", "dist/index.js"]
Frontend Dockerfile (Development)
# quikadmin-web/Dockerfile.dev FROM oven/bun:1 AS base WORKDIR /app # Copy package files COPY package.json bun.lock ./ # Install dependencies RUN bun install # Copy source COPY . . EXPOSE 8080 # Development server with hot reload CMD ["bun", "run", "dev", "--host", "0.0.0.0"]
Frontend Dockerfile (Production)
# quikadmin-web/Dockerfile.prod FROM oven/bun:1 AS builder WORKDIR /app # Copy package files COPY package.json bun.lock ./ # Install dependencies RUN bun install # Copy source COPY . . # Build production bundle RUN bun run build # Production stage with nginx FROM nginx:alpine AS production # Copy nginx config COPY nginx.conf /etc/nginx/conf.d/default.conf # Copy built files COPY --from=builder /app/dist /usr/share/nginx/html EXPOSE 80 # Health check HEALTHCHECK --interval=30s --timeout=3s \ CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1 CMD ["nginx", "-g", "daemon off;"]
Testing Dockerfile
# quikadmin/Dockerfile.test FROM node:18-alpine WORKDIR /app # Install dependencies RUN apk add --no-cache \ python3 \ make \ g++ # Copy package files COPY package*.json ./ COPY prisma ./prisma/ # Install all dependencies (including devDependencies) RUN npm ci # Copy source COPY . . # Generate Prisma Client RUN npx prisma generate # Run tests CMD ["npm", "run", "test:ci"]
Docker Compose
IntelliFill uses Docker Compose for local development and E2E testing.
Development Compose
# docker-compose.yml version: '3.8' services: postgres: image: postgres:15-alpine container_name: intellifill-postgres environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: intellifill ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine container_name: intellifill-redis ports: - "6379:6379" volumes: - redis_data:/data command: redis-server --appendonly yes healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 backend: build: context: ./quikadmin dockerfile: Dockerfile.dev container_name: intellifill-backend environment: NODE_ENV: development PORT: 3002 DATABASE_URL: postgresql://postgres:postgres@postgres:5432/intellifill REDIS_URL: redis://redis:6379 ports: - "3002:3002" volumes: - ./quikadmin:/app - /app/node_modules - backend_uploads:/app/uploads depends_on: postgres: condition: service_healthy redis: condition: service_healthy command: sh -c "npx prisma migrate deploy && npm run dev" frontend: build: context: ./quikadmin-web dockerfile: Dockerfile.dev container_name: intellifill-frontend environment: VITE_API_URL: http://localhost:3002/api ports: - "8080:8080" volumes: - ./quikadmin-web:/app - /app/node_modules depends_on: - backend volumes: postgres_data: redis_data: backend_uploads:
E2E Testing Compose
# docker-compose.e2e.yml version: '3.8' services: postgres-test: image: postgres:15-alpine environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: intellifill_test healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 3s retries: 5 redis-test: image: redis:7-alpine healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 backend-test: build: context: ./quikadmin dockerfile: Dockerfile.dev environment: NODE_ENV: test PORT: 3002 DATABASE_URL: postgresql://postgres:postgres@postgres-test:5432/intellifill_test REDIS_URL: redis://redis-test:6379 ports: - "3002:3002" depends_on: postgres-test: condition: service_healthy redis-test: condition: service_healthy command: sh -c "npx prisma migrate deploy && npm run dev" frontend-test: build: context: ./quikadmin-web dockerfile: Dockerfile.dev environment: VITE_API_URL: http://backend-test:3002/api ports: - "8080:8080" depends_on: - backend-test e2e-runner: build: context: ./e2e dockerfile: Dockerfile environment: BASE_URL: http://frontend-test:8080 API_URL: http://backend-test:3002/api depends_on: - frontend-test - backend-test command: npm run test:e2e
Production Compose (Example)
# docker-compose.prod.yml version: '3.8' services: postgres: image: postgres:15-alpine environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - postgres_data:/var/lib/postgresql/data restart: unless-stopped redis: image: redis:7-alpine volumes: - redis_data:/data restart: unless-stopped backend: build: context: ./quikadmin dockerfile: Dockerfile.prod environment: NODE_ENV: production PORT: 3002 DATABASE_URL: ${DATABASE_URL} REDIS_URL: redis://redis:6379 depends_on: - postgres - redis restart: unless-stopped frontend: build: context: ./quikadmin-web dockerfile: Dockerfile.prod depends_on: - backend restart: unless-stopped nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/ssl:/etc/nginx/ssl depends_on: - backend - frontend restart: unless-stopped volumes: postgres_data: redis_data:
GitHub Actions
IntelliFill uses GitHub Actions for CI/CD.
Test Workflow
# .github/workflows/test.yml name: Tests on: push: branches: [main, develop] pull_request: branches: [main, develop] jobs: backend-tests: name: Backend Tests runs-on: ubuntu-latest services: postgres: image: postgres:15-alpine env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: intellifill_test options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 5432:5432 redis: image: redis:7-alpine options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 6379:6379 steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm' cache-dependency-path: quikadmin/package-lock.json - name: Install dependencies working-directory: quikadmin run: npm ci - name: Generate Prisma Client working-directory: quikadmin run: npx prisma generate - name: Run migrations working-directory: quikadmin env: DATABASE_URL: postgresql://postgres:postgres@localhost:5432/intellifill_test run: npx prisma migrate deploy - name: Run tests working-directory: quikadmin env: DATABASE_URL: postgresql://postgres:postgres@localhost:5432/intellifill_test REDIS_URL: redis://localhost:6379 run: npm run test:coverage - name: Upload coverage uses: codecov/codecov-action@v3 with: files: ./quikadmin/coverage/lcov.info flags: backend frontend-tests: name: Frontend Tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v1 - name: Install dependencies working-directory: quikadmin-web run: bun install - name: Run tests working-directory: quikadmin-web run: bun run test:coverage - name: Upload coverage uses: codecov/codecov-action@v3 with: files: ./quikadmin-web/coverage/lcov.info flags: frontend e2e-tests: name: E2E Tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build and run E2E tests run: | docker-compose -f docker-compose.e2e.yml up --abort-on-container-exit --exit-code-from e2e-runner - name: Upload test results if: always() uses: actions/upload-artifact@v3 with: name: e2e-results path: e2e/test-results/
Build and Deploy Workflow
# .github/workflows/deploy.yml name: Deploy on: push: branches: [main] jobs: build: name: Build and Push Docker Images runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push backend uses: docker/build-push-action@v5 with: context: ./quikadmin file: ./quikadmin/Dockerfile.prod push: true tags: | ${{ secrets.DOCKER_USERNAME }}/intellifill-backend:latest ${{ secrets.DOCKER_USERNAME }}/intellifill-backend:${{ 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: ./quikadmin-web file: ./quikadmin-web/Dockerfile.prod push: true tags: | ${{ secrets.DOCKER_USERNAME }}/intellifill-frontend:latest ${{ secrets.DOCKER_USERNAME }}/intellifill-frontend:${{ github.sha }} cache-from: type=gha cache-to: type=gha,mode=max deploy: name: Deploy to Production runs-on: ubuntu-latest needs: build steps: - name: Deploy to server uses: appleboy/ssh-action@master with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /app/intellifill docker-compose pull docker-compose up -d docker system prune -f
Environment Management
Environment Files
# .env.example (template) NODE_ENV=development PORT=3002 # Database DATABASE_URL=postgresql://user:password@localhost:5432/intellifill DIRECT_URL=postgresql://user:password@localhost:5432/intellifill # Redis REDIS_URL=redis://localhost:6379 # Supabase SUPABASE_URL=https://xxx.supabase.co SUPABASE_ANON_KEY=xxx SUPABASE_SERVICE_ROLE_KEY=xxx # JWT JWT_SECRET=your-secret-key
Docker Environment Variables
# docker-compose.yml services: backend: env_file: - ./quikadmin/.env environment: # Override specific variables DATABASE_URL: postgresql://postgres:postgres@postgres:5432/intellifill
Build Arguments
# Dockerfile with build args FROM node:18-alpine ARG NODE_ENV=production ENV NODE_ENV=$NODE_ENV ARG API_URL ENV VITE_API_URL=$API_URL WORKDIR /app # ...
# docker-compose.yml with build args services: frontend: build: context: ./quikadmin-web args: NODE_ENV: development API_URL: http://localhost:3002/api
Health Checks
Application Health Endpoint
// quikadmin/src/api/health.routes.ts import { Router } from 'express'; import prisma from '../utils/prisma'; import redis from '../utils/redis'; const router = Router(); router.get('/health', async (req, res) => { try { // Check database await prisma.$queryRaw`SELECT 1`; // Check Redis await redis.ping(); res.status(200).json({ status: 'healthy', timestamp: new Date().toISOString(), services: { database: 'up', redis: 'up', }, }); } catch (error) { res.status(503).json({ status: 'unhealthy', timestamp: new Date().toISOString(), error: error.message, }); } }); export default router;
Docker Health Checks
# Dockerfile with health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD node -e "require('http').get('http://localhost:3002/api/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1); });"
# docker-compose.yml with health checks services: backend: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3002/api/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s
Deployment Strategies
Zero-Downtime Deployment
#!/bin/bash # deploy.sh # Pull latest images docker-compose pull # Start new containers docker-compose up -d --no-deps --scale backend=2 backend # Wait for health check sleep 10 # Stop old containers docker-compose up -d --no-deps --scale backend=1 backend # Clean up docker system prune -f
Blue-Green Deployment
# docker-compose.blue-green.yml services: backend-blue: # Current production backend-green: # New version nginx: # Switch between blue/green
Rolling Updates
# Update one container at a time for service in backend-1 backend-2 backend-3; do docker-compose up -d $service sleep 30 # Wait for health check done
Best Practices
- Multi-stage builds - Separate build and production stages
- Layer caching - Order Dockerfile commands for optimal caching
- Non-root user - Run containers as non-root
- Health checks - Implement health checks for all services
- Resource limits - Set memory and CPU limits
- Secrets management - Use Docker secrets or external secret managers
- Volume mounts - Use named volumes for persistence
- Network isolation - Use custom networks
- Graceful shutdown - Handle SIGTERM signals
- Logging - Configure proper log drivers