当前位置: 首页 > news >正文

MonkeyCode容器化部署实战:从Dockerfile到Kubernetes上云

容器化是现代部署的标配

还在用scp把jar包传到服务器上?还在手动配环境?容器化让部署变得可重复、可回滚、可扩展。但Dockerfile写不好,镜像1GB+;K8s配置不对,服务天天重启。

这篇文章用MonkeyCode生成完整的容器化部署方案,从Dockerfile优化到K8s上云。

给MonkeyCode的统一Prompt

为Python Web应用生成完整的容器化部署方案,要求: 1. 多阶段构建Dockerfile(最小镜像) 2. Docker Compose本地开发环境 3. Kubernetes部署YAML(Deployment + Service + Ingress) 4. 健康检查和就绪探针 5. 资源限制(CPU/内存) 6. 水平自动扩缩容(HPA) 7. ConfigMap和Secret管理 8. 滚动更新策略 9. 日志收集配置 应用:FastAPI后端 + Celery异步任务 + Redis + PostgreSQL

1. 多阶段构建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 --from=builder /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 --chown=appuser:appuser . . # 切换到非root用户 USER appuser # 健康检查 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ 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-200MB
apt缓存保留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_URL=postgresql+asyncpg://appuser:${DB_PASSWORD:-devpassword}@postgres:5432/myapp - REDIS_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/0 - CELERY_BROKER_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/1 - ENVIRONMENT=development 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_URL=postgresql+asyncpg://appuser:${DB_PASSWORD:-devpassword}@postgres:5432/myapp - REDIS_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/0 - CELERY_BROKER_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/1 depends_on: redis: condition: service_healthy postgres: condition: service_healthy command: celery -A app.celery_app worker --loglevel=info --concurrency=4 # Celery Beat(定时任务) celery-beat: build: context: . dockerfile: Dockerfile environment: - CELERY_BROKER_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/1 depends_on: redis: condition: service_healthy command: celery -A app.celery_app beat --loglevel=info # Flower(Celery监控) flower: build: context: . dockerfile: Dockerfile ports: - "5555:5555" environment: - CELERY_BROKER_URL=redis://:${REDIS_PASSWORD:-devpassword}@redis:6379/1 depends_on: redis: condition: service_healthy command: celery -A app.celery_app flower --port=5555 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: "postgresql+asyncpg://appuser:CHANGE_ME@postgres-service:5432/myapp" REDIS_URL: "redis://:CHANGE_ME@redis-service:6379/0" CELERY_BROKER_URL: "redis://:CHANGE_ME@redis-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 --- # Ingress(Nginx 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: 80

4. 水平自动扩缩容(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: 60

5. Celery Worker部署

http://www.jsqmd.com/news/1094250/

相关文章:

  • 二十年保险法律执业三段履历完整客观梳理
  • 计算机毕业设计之基于深度学习的商品结算系统的设计与实现
  • 痛点场景还原:一个具体的例子
  • DeepPCB:1500对图像数据集,开启PCB缺陷检测的AI时代
  • 嵌入式事件驱动架构:硬件自动化如何解放CPU并提升实时性
  • 【计算机毕业设计】Harcend学习网站的设计与实现
  • 计算机毕业设计之东北特产网上商城的设计与实现
  • 把 Agent 效果从 “感觉” 变成 “可验证”
  • GPT-4稀疏激活原理:MoE架构与动态路由技术解析
  • 告别低效手工:Nimble Document如何激活企业文档数据价值
  • Redis Key 空间事件通知机制
  • 计算机毕业设计之基于SSM框架的运动康复医疗管理系统
  • 怎样永久激活IDM下载工具:3步实用教程告别试用限制
  • 攻克eNSP AR1启动难题:从错误代码40到兼容性版本精准匹配
  • Agent 核心原理:用小项目验证核心能力
  • 为什么方向看准了,还是拿不住单子
  • AES加密在图片处理中的实战应用:原理、实现与安全考量
  • Win11Debloat终极指南:3分钟彻底优化你的Windows 11系统
  • 从 ReAct 到 Planning:从走一步看一步到先拆解再推进
  • 【交流纪实】现在的PCIe 6.0协议分析仪和训练器都进化到什么程度了?
  • Java集成MQTT协议对接第三方设备实战————从参数配置到业务落地的避坑指南
  • 【独家首发】ChatGPT Plus额度重置周期漏洞利用指南(非越狱,纯合规,已通过2024.06灰度测试)
  • 2026生成式引擎优化(GEO)行业观察:合肥本地AI搜索优化现状与落地逻辑
  • 告别传统:2026智能试剂柜行业智能化、物联化发展新趋势!
  • 2026顶流!5款AI论文工具实测,治愈文献焦虑,初稿撰写快人一步
  • ProperTree跨平台plist编辑器终极指南:如何高效管理macOS配置文件
  • 阿里云PolarDB(兼容Oracle)从入门到精通:部署、连接与SQL语法全解
  • 软件空对象管理化的空值默认处理
  • 如何使用 Python 设置 Excel 单元格数字格式
  • 基于双阀值区间扰动观察法与带预测模型模糊PID控制法的光伏MPPT控制仿真模型研究(Simulink仿真实现)