🚀 快速安装

复制以下命令并运行,立即安装此 Skill:

npx @anthropic-ai/skills install supercent-io/skills-template/deployment-automation

💡 提示:需要 Node.js 和 NPM

部署自动化

何时使用此技能

  • 新项目:从零开始设置自动化部署
  • 改进手动部署:自动化重复的手动任务
  • 多环境:分离开发、预发布和生产环境
  • 扩展:引入 Kubernetes 以应对流量增长

指示

步骤 1:Docker 容器化

将应用程序打包为 Docker 镜像。

Dockerfile(Node.js 应用):

# 多阶段构建以减小镜像大小
FROM node:18-alpine AS builder

WORKDIR /app

# 复制包文件并安装依赖
COPY package*.json ./
RUN npm ci --only=production

# 复制源代码
COPY . .

# 构建应用程序(如果需要)
RUN npm run build

# 生产阶段
FROM node:18-alpine

WORKDIR /app

# 仅从构建阶段复制必要文件
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./

# 为了安全,创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001
USER nodejs

# 暴露端口
EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node healthcheck.js

# 启动应用程序
CMD ["node", "dist/index.js"]

.dockerignore

node_modules
npm-debug.log
.git
.env
.env.local
dist
build
coverage
.DS_Store

构建和运行

# 构建镜像
docker build -t myapp:latest .

# 运行容器
docker run -d -p 3000:3000 --name myapp-container myapp:latest

# 查看日志
docker logs myapp-container

# 停止并移除
docker stop myapp-container
docker rm myapp-container

步骤 2:GitHub Actions CI/CD

在代码推送时自动运行测试和部署。

.github/workflows/deploy.yml

name: CI/CD 流水线

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  NODE_VERSION: '18'
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: 设置 Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - name: 安装依赖
        run: npm ci

      - name: 运行代码检查器
        run: npm run lint

      - name: 运行测试
        run: npm test -- --coverage

      - name: 上传覆盖率报告
        uses: codecov/codecov-action@v3
        with:
          files: ./coverage/coverage-final.json

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

      - name: 设置 Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: 登录容器注册表
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: 提取元数据
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=sha,prefix={{branch}}-
            type=semver,pattern={{version}}
            latest

      - name: 构建并推送 Docker 镜像
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment: production

    steps:
      - name: 部署到生产环境
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.PROD_HOST }}
          username: ${{ secrets.PROD_USER }}
          key: ${{ secrets.PROD_SSH_KEY }}
          script: |
            cd /app
            docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
            docker-compose up -d --no-deps --build web
            docker image prune -f

步骤 3:Kubernetes 部署

实现可扩展的容器编排。

k8s/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: production
  labels:
    app: myapp
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: ghcr.io/username/myapp:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 3000
        env:
        - name: NODE_ENV
          value: "production"
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: myapp-secrets
              key: database-url
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: production
spec:
  selector:
    app: myapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
  type: LoadBalancer

---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

部署脚本(deploy.sh):

#!/bin/bash
set -e

# 变量
NAMESPACE="production"
IMAGE_TAG="${1:-latest}"

echo "正在将 myapp:${IMAGE_TAG} 部署到 ${NAMESPACE}..."

# 应用 Kubernetes 清单
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/secrets.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml

# 更新镜像
kubectl set image deployment/myapp myapp=ghcr.io/username/myapp:${IMAGE_TAG} -n ${NAMESPACE}

# 等待滚动更新完成
kubectl rollout status deployment/myapp -n ${NAMESPACE} --timeout=5m

# 验证
kubectl get pods -n ${NAMESPACE} -l app=myapp

echo "部署成功完成!"

步骤 4:Vercel/Netlify(前端)

简单部署静态站点和 Next.js 应用。

vercel.json

{
  "version": 2,
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/next"
    }
  ],
  "env": {
    "DATABASE_URL": "@database-url",
    "API_KEY": "@api-key"
  },
  "regions": ["sin1", "icn1"],
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "X-Frame-Options",
          "value": "DENY"
        },
        {
          "key": "X-Content-Type-Options",
          "value": "nosniff"
        }
      ]
    }
  ],
  "redirects": [
    {
      "source": "/old-path",
      "destination": "/new-path",
      "permanent": true
    }
  ]
}

CLI 部署

# 安装 Vercel CLI
npm i -g vercel

# 登录
vercel login

# 部署到预览环境
vercel

# 部署到生产环境
vercel --prod

# 设置环境变量
vercel env add DATABASE_URL

步骤 5:零停机部署策略

在不中断服务的情况下部署新版本。

蓝绿部署(docker-compose):

version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - app-blue
      - app-green

  app-blue:
    image: myapp:blue
    environment:
      - NODE_ENV=production
      - COLOR=blue

  app-green:
    image: myapp:green
    environment:
      - NODE_ENV=production
      - COLOR=green

switch.sh(蓝绿切换):

#!/bin/bash

CURRENT_COLOR=$(cat current_color.txt)
NEW_COLOR=$([[ "$CURRENT_COLOR" == "blue" ]] && echo "green" || echo "blue")

# 将新版本部署到非活跃环境
docker-compose up -d app-${NEW_COLOR}

# 等待健康检查
sleep 10

# 健康检查
if curl -f http://localhost:8080/health; then
  # 更新 nginx 以指向新环境
  sed -i "s/${CURRENT_COLOR}/${NEW_COLOR}/g" nginx.conf
  docker-compose exec nginx nginx -s reload

  # 更新当前颜色
  echo ${NEW_COLOR} > current_color.txt

  # 5 分钟后停止旧环境(回滚窗口期)
  sleep 300
  docker-compose stop app-${CURRENT_COLOR}

  echo "部署成功!已切换到 ${NEW_COLOR}"
else
  echo "健康检查失败!保持 ${CURRENT_COLOR}"
  docker-compose stop app-${NEW_COLOR}
  exit 1
fi

输出格式

部署清单

## 部署清单

### 部署前
- [ ] 所有测试通过(单元、集成、端到端)
- [ ] 代码审查已批准
- [ ] 环境变量已配置
- [ ] 数据库迁移已就绪
- [ ] 回滚计划已记录

### 部署中
- [ ] Docker 镜像已构建并打标签
- [ ] 镜像已推送到容器注册表
- [ ] Kubernetes 清单已应用
- [ ] 滚动更新已启动
- [ ] Pod 健康且就绪

### 部署后
- [ ] 健康检查端点响应正常
- [ ] 指标/日志监控已激活
- [ ] 性能基线已建立
- [ ] 旧 Pod 已终止(宽限期后)
- [ ] 部署已记录在更新日志中

约束条件

必需规则(必须遵守)

  1. 健康检查:所有服务必须有健康检查端点
    app.get('/health', (req, res) => {
      res.status(200).json({ status: 'ok' });
    });
    
  2. 优雅关闭:处理 SIGTERM 信号
    process.on('SIGTERM', async () => {
      console.log('收到 SIGTERM 信号,正在优雅关闭');
      await server.close();
      await db.close();
      process.exit(0);
    });
    
  3. 环境变量分离:无硬编码;使用 .env 文件

禁止规则(不得违反)

  1. 不提交密钥:切勿将 API 密钥或密码提交到 Git
  2. 生产环境不使用调试模式:必须设置 NODE_ENV=production
  3. 避免仅使用 latest 标签:使用版本标签(v1.0.0, sha-abc123)

最佳实践

  1. 多阶段 Docker 构建:最小化镜像大小
  2. 不可变基础设施:重新部署而非修改服务器
  3. 蓝绿部署:零停机部署和轻松回滚
  4. 需要监控:Prometheus、Grafana、Datadog

参考资料

元数据

版本

  • 当前版本:1.0.0
  • 最后更新:2025-01-01
  • 兼容平台:Claude, ChatGPT, Gemini

相关技能

标签

#部署 #CI/CD #Docker #Kubernetes #自动化 #基础设施

示例

示例 1:基本用法

示例 2:高级用法

📄 原始文档

完整文档(英文):

https://skills.sh/supercent-io/skills-template/deployment-automation

💡 提示:点击上方链接查看 skills.sh 原始英文文档,方便对照翻译。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。