容器化是现代部署的标配还在用scp把jar包传到服务器上还在手动配环境容器化让部署变得可重复、可回滚、可扩展。但Dockerfile写不好镜像1GBK8s配置不对服务天天重启。这篇文章用MonkeyCode生成完整的容器化部署方案从Dockerfile优化到K8s上云。给MonkeyCode的统一Prompt为Python Web应用生成完整的容器化部署方案要求 1. 多阶段构建Dockerfile最小镜像 2. Docker Compose本地开发环境 3. Kubernetes部署YAMLDeployment Service Ingress 4. 健康检查和就绪探针 5. 资源限制CPU/内存 6. 水平自动扩缩容HPA 7. ConfigMap和Secret管理 8. 滚动更新策略 9. 日志收集配置 应用FastAPI后端 Celery异步任务 Redis PostgreSQL1. 多阶段构建Dockerfile# Dockerfile - MonkeyCode生成 # 阶段1构建依赖 FROM python:3.11-slim AS builder WORKDIR /build # 先复制依赖文件利用Docker缓存层 COPY requirements.txt . # 安装依赖到虚拟环境 RUN python -m venv /opt/venv ENV PATH/opt/venv/bin:$PATH RUN pip install --no-cache-dir --upgrade pip \ pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 阶段2运行时镜像 FROM python:3.11-slim AS runtime # 安装系统运行时依赖仅必需 RUN apt-get update \ apt-get install -y --no-install-recommends \ libpq5 \ curl \ rm -rf /var/lib/apt/lists/* # 从builder复制虚拟环境 COPY --frombuilder /opt/venv /opt/venv ENV PATH/opt/venv/bin:$PATH # 创建非root用户 RUN groupadd -r appuser useradd -r -g appuser -d /app -s /sbin/nologin appuser WORKDIR /app # 复制应用代码 COPY --chownappuser:appuser . . # 切换到非root用户 USER appuser # 健康检查 HEALTHCHECK --interval30s --timeout5s --start-period10s --retries3 \ CMD curl -f http://localhost:8000/health || exit 1 # 暴露端口 EXPOSE 8000 # 启动命令 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本地开发# docker-compose.yml - MonkeyCode生成 version: 3.8 services: # PostgreSQL数据库 postgres: image: postgres:16-alpine environment: POSTGRES_DB: myapp POSTGRES_USER: appuser POSTGRES_PASSWORD: ${DB_PASSWORD:-devpassword} ports: - 5432:5432 volumes: - postgres-data:/var/lib/postgresql/data - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: [CMD-SHELL, pg_isready -U appuser -d myapp] interval: 5s timeout: 5s retries: 5 # Redis缓存 redis: image: redis:7-alpine command: redis-server --requirepass ${REDIS_PASSWORD:-devpassword} --maxmemory 256mb --maxmemory-policy allkeys-lru ports: - 6379:6379 volumes: - redis-data:/data healthcheck: test: [CMD, redis-cli, -a, ${REDIS_PASSWORD:-devpassword}, ping] interval: 5s timeout: 3s retries: 5 # FastAPI后端 api: build: context: . dockerfile: Dockerfile ports: - 8000:8000 environment: - DATABASE_URLpostgresqlasyncpg://appuser:${DB_PASSWORD:-devpassword}postgres:5432/myapp - REDIS_URLredis://:${REDIS_PASSWORD:-devpassword}redis:6379/0 - CELERY_BROKER_URLredis://:${REDIS_PASSWORD:-devpassword}redis:6379/1 - ENVIRONMENTdevelopment depends_on: postgres: condition: service_healthy redis: condition: service_healthy volumes: - ./app:/app/app # 开发时热重载 command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload # Celery Worker celery-worker: build: context: . dockerfile: Dockerfile environment: - DATABASE_URLpostgresqlasyncpg://appuser:${DB_PASSWORD:-devpassword}postgres:5432/myapp - REDIS_URLredis://:${REDIS_PASSWORD:-devpassword}redis:6379/0 - CELERY_BROKER_URLredis://:${REDIS_PASSWORD:-devpassword}redis:6379/1 depends_on: redis: condition: service_healthy postgres: condition: service_healthy command: celery -A app.celery_app worker --loglevelinfo --concurrency4 # Celery Beat定时任务 celery-beat: build: context: . dockerfile: Dockerfile environment: - CELERY_BROKER_URLredis://:${REDIS_PASSWORD:-devpassword}redis:6379/1 depends_on: redis: condition: service_healthy command: celery -A app.celery_app beat --loglevelinfo # FlowerCelery监控 flower: build: context: . dockerfile: Dockerfile ports: - 5555:5555 environment: - CELERY_BROKER_URLredis://:${REDIS_PASSWORD:-devpassword}redis:6379/1 depends_on: redis: condition: service_healthy command: celery -A app.celery_app flower --port5555 volumes: postgres-data: redis-data:3. Kubernetes部署# k8s/namespace.yaml apiVersion: v1 kind: Namespace metadata: name: myapp-production labels: environment: production# k8s/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: myapp-config namespace: myapp-production data: ENVIRONMENT: production LOG_LEVEL: info DATABASE_HOST: postgres-service DATABASE_PORT: 5432 DATABASE_NAME: myapp REDIS_HOST: redis-service REDIS_PORT: 6379 REDIS_DB: 0 CELERY_BROKER_DB: 1 UVICORN_WORKERS: 4 --- apiVersion: v1 kind: Secret metadata: name: myapp-secrets namespace: myapp-production type: Opaque stringData: DATABASE_URL: postgresqlasyncpg://appuser:CHANGE_MEpostgres-service:5432/myapp REDIS_URL: redis://:CHANGE_MEredis-service:6379/0 CELERY_BROKER_URL: redis://:CHANGE_MEredis-service:6379/1 SECRET_KEY: CHANGE_ME_TO_RANDOM_STRING# k8s/api-deployment.yaml - MonkeyCode生成 apiVersion: apps/v1 kind: Deployment metadata: name: myapp-api namespace: myapp-production labels: app: myapp component: api spec: replicas: 3 selector: matchLabels: app: myapp component: api strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # 滚动更新时最多多出1个Pod maxUnavailable: 0 # 更新期间不允许有Pod不可用 template: metadata: labels: app: myapp component: api spec: containers: - name: api image: registry.example.com/myapp-api:latest ports: - containerPort: 8000 protocol: TCP envFrom: - configMapRef: name: myapp-config - secretRef: name: myapp-secrets resources: requests: cpu: 250m # 0.25核 memory: 256Mi limits: cpu: 1000m # 1核 memory: 512Mi livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 15 periodSeconds: 20 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /health/ready port: 8000 initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 volumeMounts: - name: tmp mountPath: /tmp volumes: - name: tmp emptyDir: {} terminationGracePeriodSeconds: 30# k8s/api-service.yaml apiVersion: v1 kind: Service metadata: name: myapp-api-service namespace: myapp-production spec: selector: app: myapp component: api ports: - port: 80 targetPort: 8000 protocol: TCP type: ClusterIP --- # IngressNginx Ingress Controller apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-ingress namespace: myapp-production annotations: nginx.ingress.kubernetes.io/rewrite-target: / nginx.ingress.kubernetes.io/ssl-redirect: true nginx.ingress.kubernetes.io/proxy-body-size: 50m nginx.ingress.kubernetes.io/proxy-read-timeout: 300 nginx.ingress.kubernetes.io/rate-limit: 100 cert-manager.io/cluster-issuer: letsencrypt-prod spec: ingressClassName: nginx tls: - hosts: - api.myapp.com secretName: myapp-tls rules: - host: api.myapp.com http: paths: - path: / pathType: Prefix backend: service: name: myapp-api-service port: number: 804. 水平自动扩缩容HPA# k8s/hpa.yaml - MonkeyCode生成 apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: myapp-api-hpa namespace: myapp-production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: myapp-api minReplicas: 3 maxReplicas: 20 metrics: # CPU使用率超过70%时扩容 - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 # 内存使用率超过80%时扩容 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 # 基于QPS自定义指标需安装Prometheus Adapter - type: Pods pods: metric: name: http_requests_per_second target: type: AverageValue averageValue: 1000 behavior: scaleUp: stabilizationWindowSeconds: 60 policies: - type: Pods value: 2 periodSeconds: 60 scaleDown: stabilizationWindowSeconds: 300 # 缩容冷却5分钟 policies: - type: Percent value: 10 periodSeconds: 605. Celery Worker部署