马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
容器化是今世摆设的标配
还在用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-200MBapt缓存保存rm -rf-50MB运行用户rootappuser安全提升终极镜像1.2GB180MB-85%2. Docker Compose本地开发
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摆设
- # k8s/celery-deployment.yaml - MonkeyCode生成
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: myapp-celery-worker
- namespace: myapp-production
- labels:
- app: myapp
- component: celery-worker
- spec:
- replicas: 2
- selector:
- matchLabels:
- app: myapp
- component: celery-worker
- template:
- metadata:
- labels:
- app: myapp
- component: celery-worker
- spec:
- containers:
- - name: celery-worker
- image: registry.example.com/myapp-api:latest
- command: ["celery", "-A", "app.celery_app", "worker", "--loglevel=info", "--concurrency=4"]
- envFrom:
- - configMapRef:
- name: myapp-config
- - secretRef:
- name: myapp-secrets
- resources:
- requests:
- cpu: "500m"
- memory: "512Mi"
- limits:
- cpu: "2000m"
- memory: "1Gi"
- ---
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: myapp-celery-beat
- namespace: myapp-production
- labels:
- app: myapp
- component: celery-beat
- spec:
- replicas: 1 # Beat只能运行1个副本
- selector:
- matchLabels:
- app: myapp
- component: celery-beat
- template:
- metadata:
- labels:
- app: myapp
- component: celery-beat
- spec:
- containers:
- - name: celery-beat
- image: registry.example.com/myapp-api:latest
- command: ["celery", "-A", "app.celery_app", "beat", "--loglevel=info"]
- envFrom:
- - configMapRef:
- name: myapp-config
- - secretRef:
- name: myapp-secrets
复制代码 6. 数据库摆设(StatefulSet)
- # k8s/postgres-statefulset.yaml - MonkeyCode生成
- apiVersion: apps/v1
- kind: StatefulSet
- metadata:
- name: postgres
- namespace: myapp-production
- spec:
- serviceName: postgres-service
- replicas: 1 # 生产环境建议用云RDS
- selector:
- matchLabels:
- app: myapp
- component: postgres
- template:
- metadata:
- labels:
- app: myapp
- component: postgres
- spec:
- containers:
- - name: postgres
- image: postgres:16-alpine
- ports:
- - containerPort: 5432
- env:
- - name: POSTGRES_DB
- value: myapp
- - name: POSTGRES_USER
- value: appuser
- - name: POSTGRES_PASSWORD
- valueFrom:
- secretKeyRef:
- name: myapp-secrets
- key: DB_PASSWORD
- - name: PGDATA
- value: /var/lib/postgresql/data/pgdata
- resources:
- requests:
- cpu: "500m"
- memory: "1Gi"
- limits:
- cpu: "2000m"
- memory: "4Gi"
- volumeMounts:
- - name: postgres-data
- mountPath: /var/lib/postgresql/data
- livenessProbe:
- exec:
- command: ["pg_isready", "-U", "appuser", "-d", "myapp"]
- initialDelaySeconds: 30
- periodSeconds: 10
- readinessProbe:
- exec:
- command: ["pg_isready", "-U", "appuser", "-d", "myapp"]
- initialDelaySeconds: 5
- periodSeconds: 5
- volumeClaimTemplates:
- - metadata:
- name: postgres-data
- spec:
- accessModes: ["ReadWriteOnce"]
- resources:
- requests:
- storage: 50Gi
- ---
- apiVersion: v1
- kind: Service
- metadata:
- name: postgres-service
- namespace: myapp-production
- spec:
- selector:
- app: myapp
- component: postgres
- ports:
- - port: 5432
- targetPort: 5432
- clusterIP: None # Headless Service(StatefulSet用)
复制代码 7. CI/CD流水线(GitHub Actions → K8s)
- # .github/workflows/deploy.yml - MonkeyCode生成
- name: Build and Deploy
- on:
- push:
- branches: [main]
- env:
- REGISTRY: registry.example.com
- IMAGE_NAME: myapp-api
- jobs:
- test:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-python@v5
- with:
- python-version: '3.11'
- - run: pip install -r requirements.txt
- - run: pytest tests/ -v --cov=app --cov-report=xml
- - uses: codecov/codecov-action@v3
- build:
- needs: test
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to Registry
- uses: docker/login-action@v3
- with:
- registry: ${{ env.REGISTRY }}
- username: ${{ secrets.REGISTRY_USERNAME }}
- password: ${{ secrets.REGISTRY_PASSWORD }}
-
- - name: Build and Push
- uses: docker/build-push-action@v5
- with:
- context: .
- push: true
- tags: |
- ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
- ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- cache-to: type=inline
- deploy:
- needs: build
- runs-on: ubuntu-latest
- environment: production
- steps:
- - uses: actions/checkout@v4
-
- - name: Deploy to K8s
- uses: steebchen/kubectl@v2.1.1
- with:
- config: ${{ secrets.KUBE_CONFIG }}
- command: set image deployment/myapp-api api=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} -n myapp-production
-
- - name: Verify Deployment
- run: |
- kubectl rollout status deployment/myapp-api -n myapp-production --timeout=300s
- kubectl get pods -n myapp-production -l app=myapp,component=api
复制代码 8. 一键摆设脚本
- #!/bin/bash
- # scripts/deploy.sh - MonkeyCode生成
- set -euo pipefail
- ENV=${1:-production}
- IMAGE_TAG=${2:-latest}
- echo "🚀 Deploying myapp to $ENV (tag: $IMAGE_TAG)"
- # 创建命名空间
- kubectl apply -f k8s/namespace.yaml
- # 应用配置
- kubectl apply -f k8s/configmap.yaml
- # 应用数据库
- kubectl apply -f k8s/postgres-statefulset.yaml
- # 等待数据库就绪
- echo "⏳ Waiting for PostgreSQL..."
- kubectl wait --for=condition=ready pod -l app=myapp,component=postgres -n myapp-$ENV --timeout=120s
- # 应用API
- kubectl set image deployment/myapp-api api=registry.example.com/myapp-api:$IMAGE_TAG -n myapp-$ENV
- kubectl rollout status deployment/myapp-api -n myapp-$ENV --timeout=300s
- # 应用Celery
- kubectl set image deployment/myapp-celery-worker celery-worker=registry.example.com/myapp-api:$IMAGE_TAG -n myapp-$ENV
- # 应用HPA
- kubectl apply -f k8s/hpa.yaml
- echo "✅ Deployment complete!"
- kubectl get all -n myapp-$ENV
复制代码 容器化摆设的关键是分层筹划:Dockerfile多阶段构建减小镜像,K8s分层设置(ConfigMap/Secret分离),HPA主动扩缩容应对流量。MonkeyCode能天生完备的K8s YAML模板,但资源限定和HPA阈值必要根据实际负载调优。
免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金. |