MonkeyCode容器化摆设实战:从Dockerfile到Kubernetes上云

[复制链接]
发表于 昨天 19:02 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
容器化是今世摆设的标配

还在用scp把jar包传到服务器上?还在手动配情况?容器化让摆设变得可重复、可回滚、可扩展。但Dockerfile写欠好,镜像1GB+;K8s设置不对,服务天天重启。
这篇文章用MonkeyCode天生完备的容器化摆设方案,从Dockerfile优化到K8s上云。
给MonkeyCode的同一Prompt
  1. 为Python Web应用生成完整的容器化部署方案,要求:
  2. 1. 多阶段构建Dockerfile(最小镜像)
  3. 2. Docker Compose本地开发环境
  4. 3. Kubernetes部署YAML(Deployment + Service + Ingress)
  5. 4. 健康检查和就绪探针
  6. 5. 资源限制(CPU/内存)
  7. 6. 水平自动扩缩容(HPA)
  8. 7. ConfigMap和Secret管理
  9. 8. 滚动更新策略
  10. 9. 日志日志收集配置
  11. 应用:FastAPI后端 + Celery异步任务 + Redis + PostgreSQL
复制代码
1. 多阶段构建Dockerfile
  1. # Dockerfile - MonkeyCode生成
  2. # ===== 阶段1:构建依赖 =====
  3. FROM python:3.11-slim AS builder
  4. WORKDIR /build
  5. # 先复制依赖文件(利用Docker缓存层)
  6. COPY requirements.txt .
  7. # 安装依赖到虚拟环境
  8. RUN python -m venv /opt/venv
  9. ENV PATH="/opt/venv/bin:$PATH"
  10. RUN pip install --no-cache-dir --upgrade pip && \
  11.     pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
  12. # ===== 阶段2:运行时镜像 =====
  13. FROM python:3.11-slim AS runtime
  14. # 安装系统运行时依赖(仅必需)
  15. RUN apt-get update && \
  16.     apt-get install -y --no-install-recommends \
  17.     libpq5 \
  18.     curl && \
  19.     rm -rf /var/lib/apt/lists/*
  20. # 从builder复制虚拟环境
  21. COPY --from=builder /opt/venv /opt/venv
  22. ENV PATH="/opt/venv/bin:$PATH"
  23. # 创建非root用户
  24. RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser
  25. WORKDIR /app
  26. # 复制应用代码
  27. COPY --chown=appuser:appuser . .
  28. # 切换到非root用户
  29. USER appuser
  30. # 健康检查
  31. HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  32.     CMD curl -f http://localhost:8000/health || exit 1
  33. # 暴露端口
  34. EXPOSE 8000
  35. # 启动命令
  36. CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
复制代码
Dockerfile优化对比

优化项优化前优化后效果根本镜像python:3.11 (1.02GB)python:3.11-slim (150MB)-85%多阶段构建无builder + runtime去除编译工具链pip缓存保存--no-cache-dir-200MBapt缓存保存rm -rf-50MB运行用户rootappuser安全提升终极镜像1.2GB180MB-85%2. Docker Compose本地开发
  1. # docker-compose.yml - MonkeyCode生成
  2. version: '3.8'
  3. services:
  4.   # PostgreSQL数据库
  5.   postgres:
  6.     image: postgres:16-alpine
  7.     environment:
  8.       POSTGRES_DB: myapp
  9.       POSTGRES_USER: appuser
  10.       POSTGRES_PASSWORD: ${DB_PASSWORD:-devpassword}
  11.     ports:
  12.       - "5432:5432"
  13.     volumes:
  14.       - postgres-data:/var/lib/postgresql/data
  15.       - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql
  16.     healthcheck:
  17.       test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]
  18.       interval: 5s
  19.       timeout: 5s
  20.       retries: 5
  21.   # Redis缓存
  22.   redis:
  23.     image: redis:7-alpine
  24.     command: redis-server --requirepass ${REDIS_PASSWORD:-devpassword} --maxmemory 256mb --maxmemory-policy allkeys-lru
  25.     ports:
  26.       - "6379:6379"
  27.     volumes:
  28.       - redis-data:/data
  29.     healthcheck:
  30.       test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-devpassword}", "ping"]
  31.       interval: 5s
  32.       timeout: 3s
  33.       retries: 5
  34.   # FastAPI后端
  35.   api:
  36.     build:
  37.       context: .
  38.       dockerfile: Dockerfile
  39.     ports:
  40.       - "8000:8000"
  41.     environment:
  42.       - DATABASE_URL=postgresql+asyncpg://appuser:${DB_PASSWORD:-devpassword}@postgres:5432/myapp
  43.       - REDIS_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/0
  44.       - CELERY_BROKER_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/1
  45.       - ENVIRONMENT=development
  46.     depends_on:
  47.       postgres:
  48.         condition: service_healthy
  49.       redis:
  50.         condition: service_healthy
  51.     volumes:
  52.       - ./app:/app/app  # 开发时热重载
  53.     command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
  54.   # Celery Worker
  55.   celery-worker:
  56.     build:
  57.       context: .
  58.       dockerfile: Dockerfile
  59.     environment:
  60.       - DATABASE_URL=postgresql+asyncpg://appuser:${DB_PASSWORD:-devpassword}@postgres:5432/myapp
  61.       - REDIS_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/0
  62.       - CELERY_BROKER_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/1
  63.     depends_on:
  64.       redis:
  65.         condition: service_healthy
  66.       postgres:
  67.         condition: service_healthy
  68.     command: celery -A app.celery_app worker --loglevel=info --concurrency=4
  69.   # Celery Beat(定时任务)
  70.   celery-beat:
  71.     build:
  72.       context: .
  73.       dockerfile: Dockerfile
  74.     environment:
  75.       - CELERY_BROKER_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/1
  76.     depends_on:
  77.       redis:
  78.         condition: service_healthy
  79.     command: celery -A app.celery_app beat --loglevel=info
  80.   # Flower(Celery监控监控
  81.   flower:
  82.     build:
  83.       context: .
  84.       dockerfile: Dockerfile
  85.     ports:
  86.       - "5555:5555"
  87.     environment:
  88.       - CELERY_BROKER_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/1
  89.     depends_on:
  90.       redis:
  91.         condition: service_healthy
  92.     command: celery -A app.celery_app flower --port=5555
  93. volumes:
  94.   postgres-data:
  95.   redis-data:
复制代码
3. Kubernetes摆设
  1. # k8s/namespace.yaml
  2. apiVersion: v1
  3. kind: Namespace
  4. metadata:
  5.   name: myapp-production
  6.   labels:
  7.     environment: production
复制代码
  1. # k8s/configmap.yaml
  2. apiVersion: v1
  3. kind: ConfigMap
  4. metadata:
  5.   name: myapp-config
  6.   namespace: myapp-production
  7. data:
  8.   ENVIRONMENT: "production"
  9.   LOG_LEVEL: "info"
  10.   DATABASE_HOST: "postgres-service"
  11.   DATABASE_PORT: "5432"
  12.   DATABASE_NAME: "myapp"
  13.   REDIS_HOST: "redis-service"
  14.   REDIS_PORT: "6379"
  15.   REDIS_DB: "0"
  16.   CELERY_BROKER_DB: "1"
  17.   UVICORN_WORKERS: "4"
  18. ---
  19. apiVersion: v1
  20. kind: Secret
  21. metadata:
  22.   name: myapp-secrets
  23.   namespace: myapp-production
  24. type: Opaque
  25. stringData:
  26.   DATABASE_URL: "postgresql+asyncpg://appuser:CHANGE_ME@postgres-service:5432/myapp"
  27.   REDIS_URL: "redis://:CHANGE_ME@redis-service:6379/0"
  28.   CELERY_BROKER_URL: "redis://:CHANGE_ME@redis-service:6379/1"
  29.   SECRET_KEY: "CHANGE_ME_TO_RANDOM_STRING"
复制代码
  1. # k8s/api-deployment.yaml - MonkeyCode生成
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5.   name: myapp-api
  6.   namespace: myapp-production
  7.   labels:
  8.     app: myapp
  9.     component: api
  10. spec:
  11.   replicas: 3
  12.   selector:
  13.     matchLabels:
  14.       app: myapp
  15.       component: api
  16.   strategy:
  17.     type: RollingUpdate
  18.     rollingUpdate:
  19.       maxSurge: 1        # 滚动更新时最多多出1个Pod
  20.       maxUnavailable: 0   # 更新期间不允许有Pod不可用
  21.   template:
  22.     metadata:
  23.       labels:
  24.         app: myapp
  25.         component: api
  26.     spec:
  27.       containers:
  28.         - name: api
  29.           image: registry.example.com/myapp-api:latest
  30.           ports:
  31.             - containerPort: 8000
  32.               protocol: TCP
  33.           envFrom:
  34.             - configMapRef:
  35.                 name: myapp-config
  36.             - secretRef:
  37.                 name: myapp-secrets
  38.           resources:
  39.             requests:
  40.               cpu: "250m"    # 0.25核
  41.               memory: "256Mi"
  42.             limits:
  43.               cpu: "1000m"   # 1核
  44.               memory: "512Mi"
  45.           livenessProbe:
  46.             httpGet:
  47.               path: /health
  48.               port: 8000
  49.             initialDelaySeconds: 15
  50.             periodSeconds: 20
  51.             timeoutSeconds: 5
  52.             failureThreshold: 3
  53.           readinessProbe:
  54.             httpGet:
  55.               path: /health/ready
  56.               port: 8000
  57.             initialDelaySeconds: 5
  58.             periodSeconds: 10
  59.             timeoutSeconds: 3
  60.             failureThreshold: 3
  61.           volumeMounts:
  62.             - name: tmp
  63.               mountPath: /tmp
  64.       volumes:
  65.         - name: tmp
  66.           emptyDir: {}
  67.       terminationGracePeriodSeconds: 30
复制代码
  1. # k8s/api-service.yaml
  2. apiVersion: v1
  3. kind: Service
  4. metadata:
  5.   name: myapp-api-service
  6.   namespace: myapp-production
  7. spec:
  8.   selector:
  9.     app: myapp
  10.     component: api
  11.   ports:
  12.     - port: 80
  13.       targetPort: 8000
  14.       protocol: TCP
  15.   type: ClusterIP
  16. ---
  17. # Ingress(Nginx Ingress Controller)
  18. apiVersion: networking.k8s.io/v1
  19. kind: Ingress
  20. metadata:
  21.   name: myapp-ingress
  22.   namespace: myapp-production
  23.   annotations:
  24.     nginx.ingress.kubernetes.io/rewrite-target: /
  25.     nginx.ingress.kubernetes.io/ssl-redirect: "true"
  26.     nginx.ingress.kubernetes.io/proxy-body-size: "50m"
  27.     nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
  28.     nginx.ingress.kubernetes.io/rate-limit: "100"
  29.     cert-manager.io/cluster-issuer: letsencrypt-prod
  30. spec:
  31.   ingressClassName: nginx
  32.   tls:
  33.     - hosts:
  34.         - api.myapp.com
  35.       secretName: myapp-tls
  36.   rules:
  37.     - host: api.myapp.com
  38.       http:
  39.         paths:
  40.           - path: /
  41.             pathType: Prefix
  42.             backend:
  43.               service:
  44.                 name: myapp-api-service
  45.                 port:
  46.                   number: 80
复制代码
4. 水平主动扩缩容(HPA)
  1. # k8s/hpa.yaml - MonkeyCode生成
  2. apiVersion: autoscaling/v2
  3. kind: HorizontalPodAutoscaler
  4. metadata:
  5.   name: myapp-api-hpa
  6.   namespace: myapp-production
  7. spec:
  8.   scaleTargetRef:
  9.     apiVersion: apps/v1
  10.     kind: Deployment
  11.     name: myapp-api
  12.   minReplicas: 3
  13.   maxReplicas: 20
  14.   metrics:
  15.     # CPU使用率超过70%时扩容
  16.     - type: Resource
  17.       resource:
  18.         name: cpu
  19.         target:
  20.           type: Utilization
  21.           averageUtilization: 70
  22.     # 内存使用率超过80%时扩容
  23.     - type: Resource
  24.       resource:
  25.         name: memory
  26.         target:
  27.           type: Utilization
  28.           averageUtilization: 80
  29.     # 基于QPS自定义指标(需安装Prometheus Adapter)
  30.     - type: Pods
  31.       pods:
  32.         metric:
  33.           name: http_requests_per_second
  34.         target:
  35.           type: AverageValue
  36.           averageValue: "1000"
  37.   behavior:
  38.     scaleUp:
  39.       stabilizationWindowSeconds: 60
  40.       policies:
  41.         - type: Pods
  42.           value: 2
  43.           periodSeconds: 60
  44.     scaleDown:
  45.       stabilizationWindowSeconds: 300  # 缩容冷却5分钟
  46.       policies:
  47.         - type: Percent
  48.           value: 10
  49.           periodSeconds: 60
复制代码
5. Celery Worker摆设
  1. # k8s/celery-deployment.yaml - MonkeyCode生成
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5.   name: myapp-celery-worker
  6.   namespace: myapp-production
  7.   labels:
  8.     app: myapp
  9.     component: celery-worker
  10. spec:
  11.   replicas: 2
  12.   selector:
  13.     matchLabels:
  14.       app: myapp
  15.       component: celery-worker
  16.   template:
  17.     metadata:
  18.       labels:
  19.         app: myapp
  20.         component: celery-worker
  21.     spec:
  22.       containers:
  23.         - name: celery-worker
  24.           image: registry.example.com/myapp-api:latest
  25.           command: ["celery", "-A", "app.celery_app", "worker", "--loglevel=info", "--concurrency=4"]
  26.           envFrom:
  27.             - configMapRef:
  28.                 name: myapp-config
  29.             - secretRef:
  30.                 name: myapp-secrets
  31.           resources:
  32.             requests:
  33.               cpu: "500m"
  34.               memory: "512Mi"
  35.             limits:
  36.               cpu: "2000m"
  37.               memory: "1Gi"
  38. ---
  39. apiVersion: apps/v1
  40. kind: Deployment
  41. metadata:
  42.   name: myapp-celery-beat
  43.   namespace: myapp-production
  44.   labels:
  45.     app: myapp
  46.     component: celery-beat
  47. spec:
  48.   replicas: 1  # Beat只能运行1个副本
  49.   selector:
  50.     matchLabels:
  51.       app: myapp
  52.       component: celery-beat
  53.   template:
  54.     metadata:
  55.       labels:
  56.         app: myapp
  57.         component: celery-beat
  58.     spec:
  59.       containers:
  60.         - name: celery-beat
  61.           image: registry.example.com/myapp-api:latest
  62.           command: ["celery", "-A", "app.celery_app", "beat", "--loglevel=info"]
  63.           envFrom:
  64.             - configMapRef:
  65.                 name: myapp-config
  66.             - secretRef:
  67.                 name: myapp-secrets
复制代码
6. 数据库摆设(StatefulSet)
  1. # k8s/postgres-statefulset.yaml - MonkeyCode生成
  2. apiVersion: apps/v1
  3. kind: StatefulSet
  4. metadata:
  5.   name: postgres
  6.   namespace: myapp-production
  7. spec:
  8.   serviceName: postgres-service
  9.   replicas: 1  # 生产环境建议用云RDS
  10.   selector:
  11.     matchLabels:
  12.       app: myapp
  13.       component: postgres
  14.   template:
  15.     metadata:
  16.       labels:
  17.         app: myapp
  18.         component: postgres
  19.     spec:
  20.       containers:
  21.         - name: postgres
  22.           image: postgres:16-alpine
  23.           ports:
  24.             - containerPort: 5432
  25.           env:
  26.             - name: POSTGRES_DB
  27.               value: myapp
  28.             - name: POSTGRES_USER
  29.               value: appuser
  30.             - name: POSTGRES_PASSWORD
  31.               valueFrom:
  32.                 secretKeyRef:
  33.                   name: myapp-secrets
  34.                   key: DB_PASSWORD
  35.             - name: PGDATA
  36.               value: /var/lib/postgresql/data/pgdata
  37.           resources:
  38.             requests:
  39.               cpu: "500m"
  40.               memory: "1Gi"
  41.             limits:
  42.               cpu: "2000m"
  43.               memory: "4Gi"
  44.           volumeMounts:
  45.             - name: postgres-data
  46.               mountPath: /var/lib/postgresql/data
  47.           livenessProbe:
  48.             exec:
  49.               command: ["pg_isready", "-U", "appuser", "-d", "myapp"]
  50.             initialDelaySeconds: 30
  51.             periodSeconds: 10
  52.           readinessProbe:
  53.             exec:
  54.               command: ["pg_isready", "-U", "appuser", "-d", "myapp"]
  55.             initialDelaySeconds: 5
  56.             periodSeconds: 5
  57.   volumeClaimTemplates:
  58.     - metadata:
  59.         name: postgres-data
  60.       spec:
  61.         accessModes: ["ReadWriteOnce"]
  62.         resources:
  63.           requests:
  64.             storage: 50Gi
  65. ---
  66. apiVersion: v1
  67. kind: Service
  68. metadata:
  69.   name: postgres-service
  70.   namespace: myapp-production
  71. spec:
  72.   selector:
  73.     app: myapp
  74.     component: postgres
  75.   ports:
  76.     - port: 5432
  77.       targetPort: 5432
  78.   clusterIP: None  # Headless Service(StatefulSet用)
复制代码
7. CI/CD流水线(GitHub Actions → K8s)
  1. # .github/workflows/deploy.yml - MonkeyCode生成
  2. name: Build and Deploy
  3. on:
  4.   push:
  5.     branches: [main]
  6. env:
  7.   REGISTRY: registry.example.com
  8.   IMAGE_NAME: myapp-api
  9. jobs:
  10.   test:
  11.     runs-on: ubuntu-latest
  12.     steps:
  13.       - uses: actions/checkout@v4
  14.       - uses: actions/setup-python@v5
  15.         with:
  16.           python-version: '3.11'
  17.       - run: pip install -r requirements.txt
  18.       - run: pytest tests/ -v --cov=app --cov-report=xml
  19.       - uses: codecov/codecov-action@v3
  20.   build:
  21.     needs: test
  22.     runs-on: ubuntu-latest
  23.     steps:
  24.       - uses: actions/checkout@v4
  25.       
  26.       - name: Login to Registry
  27.         uses: docker/login-action@v3
  28.         with:
  29.           registry: ${{ env.REGISTRY }}
  30.           username: ${{ secrets.REGISTRY_USERNAME }}
  31.           password: ${{ secrets.REGISTRY_PASSWORD }}
  32.       
  33.       - name: Build and Push
  34.         uses: docker/build-push-action@v5
  35.         with:
  36.           context: .
  37.           push: true
  38.           tags: |
  39.             ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
  40.             ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
  41.           cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
  42.           cache-to: type=inline
  43.   deploy:
  44.     needs: build
  45.     runs-on: ubuntu-latest
  46.     environment: production
  47.     steps:
  48.       - uses: actions/checkout@v4
  49.       
  50.       - name: Deploy to K8s
  51.         uses: steebchen/kubectl@v2.1.1
  52.         with:
  53.           config: ${{ secrets.KUBE_CONFIG }}
  54.           command: set image deployment/myapp-api api=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} -n myapp-production
  55.       
  56.       - name: Verify Deployment
  57.         run: |
  58.           kubectl rollout status deployment/myapp-api -n myapp-production --timeout=300s
  59.           kubectl get pods -n myapp-production -l app=myapp,component=api
复制代码
8. 一键摆设脚本
  1. #!/bin/bash
  2. # scripts/deploy.sh - MonkeyCode生成
  3. set -euo pipefail
  4. ENV=${1:-production}
  5. IMAGE_TAG=${2:-latest}
  6. echo "🚀 Deploying myapp to $ENV (tag: $IMAGE_TAG)"
  7. # 创建命名空间
  8. kubectl apply -f k8s/namespace.yaml
  9. # 应用配置
  10. kubectl apply -f k8s/configmap.yaml
  11. # 应用数据库
  12. kubectl apply -f k8s/postgres-statefulset.yaml
  13. # 等待数据库就绪
  14. echo "⏳ Waiting for PostgreSQL..."
  15. kubectl wait --for=condition=ready pod -l app=myapp,component=postgres -n myapp-$ENV --timeout=120s
  16. # 应用API
  17. kubectl set image deployment/myapp-api api=registry.example.com/myapp-api:$IMAGE_TAG -n myapp-$ENV
  18. kubectl rollout status deployment/myapp-api -n myapp-$ENV --timeout=300s
  19. # 应用Celery
  20. kubectl set image deployment/myapp-celery-worker celery-worker=registry.example.com/myapp-api:$IMAGE_TAG -n myapp-$ENV
  21. # 应用HPA
  22. kubectl apply -f k8s/hpa.yaml
  23. echo "✅ Deployment complete!"
  24. kubectl get all -n myapp-$ENV
复制代码
容器化摆设的关键是分层筹划:Dockerfile多阶段构建减小镜像,K8s分层设置(ConfigMap/Secret分离),HPA主动扩缩容应对流量。MonkeyCode能天生完备的K8s YAML模板,但资源限定和HPA阈值必要根据实际负载调优。

免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表