deployment-automation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDeployment Automation
部署自动化
When to use this skill
何时使用此技能
- 신규 프로젝트: 처음부터 자동 배포 설정
- 수동 배포 개선: 반복적인 수동 작업 자동화
- 멀티 환경: dev, staging, production 환경 분리
- 스케일링: 트래픽 증가 대비 Kubernetes 도입
- 新项目:从0开始配置自动部署
- 手动部署优化:将重复性手动工作自动化
- 多环境:分离dev、staging、production环境
- 扩容:应对流量增长引入Kubernetes
Instructions
操作指南
Step 1: Docker 컨테이너화
步骤1:Docker容器化
애플리케이션을 Docker 이미지로 패키징합니다.
Dockerfile (Node.js 앱):
dockerfile
undefined将应用程序打包为Docker镜像。
Dockerfile(Node.js应用):
dockerfile
undefinedMulti-stage build for smaller image size
Multi-stage build for smaller image size
FROM node:18-alpine AS builder
WORKDIR /app
FROM node:18-alpine AS builder
WORKDIR /app
Copy package files and install dependencies
Copy package files and install dependencies
COPY package*.json ./
RUN npm ci --only=production
COPY package*.json ./
RUN npm ci --only=production
Copy source code
Copy source code
COPY . .
COPY . .
Build application (if needed)
Build application (if needed)
RUN npm run build
RUN npm run build
Production stage
Production stage
FROM node:18-alpine
WORKDIR /app
FROM node:18-alpine
WORKDIR /app
Copy only necessary files from builder
Copy only necessary files from builder
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
Create non-root user for security
Create non-root user for security
RUN addgroup -g 1001 -S nodejs &&
adduser -S nodejs -u 1001 USER nodejs
adduser -S nodejs -u 1001 USER nodejs
RUN addgroup -g 1001 -S nodejs &&
adduser -S nodejs -u 1001 USER nodejs
adduser -S nodejs -u 1001 USER nodejs
Expose port
Expose port
EXPOSE 3000
EXPOSE 3000
Health check
Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD node healthcheck.js
CMD node healthcheck.js
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD node healthcheck.js
CMD node healthcheck.js
Start application
Start application
CMD ["node", "dist/index.js"]
**.dockerignore**:node_modules
npm-debug.log
.git
.env
.env.local
dist
build
coverage
.DS_Store
**빌드 및 실행**:
```bashCMD ["node", "dist/index.js"]
**.dockerignore**:node_modules
npm-debug.log
.git
.env
.env.local
dist
build
coverage
.DS_Store
**构建与运行**:
```bashBuild image
Build image
docker build -t myapp:latest .
docker build -t myapp:latest .
Run container
Run container
docker run -d -p 3000:3000 --name myapp-container myapp:latest
docker run -d -p 3000:3000 --name myapp-container myapp:latest
Check logs
Check logs
docker logs myapp-container
docker logs myapp-container
Stop and remove
Stop and remove
docker stop myapp-container
docker rm myapp-container
undefineddocker stop myapp-container
docker rm myapp-container
undefinedStep 2: GitHub Actions CI/CD
步骤2:GitHub Actions CI/CD
코드 푸시 시 자동으로 테스트 및 배포합니다.
.github/workflows/deploy.yml:
yaml
name: CI/CD Pipeline
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: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test -- --coverage
- name: Upload coverage
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: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
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: Build and push Docker image
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: Deploy to production
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代码推送时自动执行测试与部署。
.github/workflows/deploy.yml:
yaml
name: CI/CD Pipeline
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: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test -- --coverage
- name: Upload coverage
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: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
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: Build and push Docker image
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: Deploy to production
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 -fStep 3: Kubernetes 배포
步骤3:Kubernetes部署
확장 가능한 컨테이너 오케스트레이션을 구현합니다.
k8s/deployment.yaml:
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):
bash
#!/bin/bash
set -e实现可扩展的容器编排。
k8s/deployment.yaml:
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):
bash
#!/bin/bash
set -eVariables
Variables
NAMESPACE="production"
IMAGE_TAG="${1:-latest}"
echo "Deploying myapp:${IMAGE_TAG} to ${NAMESPACE}..."
NAMESPACE="production"
IMAGE_TAG="${1:-latest}"
echo "Deploying myapp:${IMAGE_TAG} to ${NAMESPACE}..."
Apply Kubernetes manifests
Apply Kubernetes manifests
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 apply -f k8s/namespace.yaml
kubectl apply -f k8s/secrets.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
Update image
Update image
kubectl set image deployment/myapp myapp=ghcr.io/username/myapp:${IMAGE_TAG} -n ${NAMESPACE}
kubectl set image deployment/myapp myapp=ghcr.io/username/myapp:${IMAGE_TAG} -n ${NAMESPACE}
Wait for rollout
Wait for rollout
kubectl rollout status deployment/myapp -n ${NAMESPACE} --timeout=5m
kubectl rollout status deployment/myapp -n ${NAMESPACE} --timeout=5m
Verify
Verify
kubectl get pods -n ${NAMESPACE} -l app=myapp
echo "Deployment completed successfully!"
undefinedkubectl get pods -n ${NAMESPACE} -l app=myapp
echo "Deployment completed successfully!"
undefinedStep 4: Vercel/Netlify (프론트엔드)
步骤4:Vercel/Netlify(前端)
정적 사이트 및 Next.js 앱을 간단히 배포합니다.
vercel.json:
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 배포:
bash
undefined轻松部署静态网站与Next.js应用。
vercel.json:
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部署:
bash
undefinedInstall Vercel CLI
Install Vercel CLI
npm i -g vercel
npm i -g vercel
Login
Login
vercel login
vercel login
Deploy to preview
Deploy to preview
vercel
vercel
Deploy to production
Deploy to production
vercel --prod
vercel --prod
Set environment variable
Set environment variable
vercel env add DATABASE_URL
undefinedvercel env add DATABASE_URL
undefinedStep 5: 무중단 배포 전략
步骤5:无缝部署策略
서비스 중단 없이 새 버전을 배포합니다.
Blue-Green 배포 (docker-compose):
yaml
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=greenswitch.sh (Blue/Green 전환):
bash
#!/bin/bash
CURRENT_COLOR=$(cat current_color.txt)
NEW_COLOR=$([[ "$CURRENT_COLOR" == "blue" ]] && echo "green" || echo "blue")在不中断服务的情况下部署新版本。
蓝绿部署 (docker-compose):
yaml
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=greenswitch.sh(蓝绿切换):
bash
#!/bin/bash
CURRENT_COLOR=$(cat current_color.txt)
NEW_COLOR=$([[ "$CURRENT_COLOR" == "blue" ]] && echo "green" || echo "blue")Deploy new version to inactive environment
Deploy new version to inactive environment
docker-compose up -d app-${NEW_COLOR}
docker-compose up -d app-${NEW_COLOR}
Wait for health check
Wait for health check
sleep 10
sleep 10
Health check
Health check
if curl -f http://localhost:8080/health; then
Update nginx to point to new environment
sed -i "s/${CURRENT_COLOR}/${NEW_COLOR}/g" nginx.conf
docker-compose exec nginx nginx -s reload
Update current color
echo ${NEW_COLOR} > current_color.txt
Stop old environment after 5 minutes (rollback window)
sleep 300
docker-compose stop app-${CURRENT_COLOR}
echo "Deployment successful! Switched to ${NEW_COLOR}"
else
echo "Health check failed! Keeping ${CURRENT_COLOR}"
docker-compose stop app-${NEW_COLOR}
exit 1
fi
undefinedif curl -f http://localhost:8080/health; then
Update nginx to point to new environment
sed -i "s/${CURRENT_COLOR}/${NEW_COLOR}/g" nginx.conf
docker-compose exec nginx nginx -s reload
Update current color
echo ${NEW_COLOR} > current_color.txt
Stop old environment after 5 minutes (rollback window)
sleep 300
docker-compose stop app-${CURRENT_COLOR}
echo "Deployment successful! Switched to ${NEW_COLOR}"
else
echo "Health check failed! Keeping ${CURRENT_COLOR}"
docker-compose stop app-${NEW_COLOR}
exit 1
fi
undefinedOutput format
输出格式
배포 체크리스트
部署检查表
markdown
undefinedmarkdown
undefinedDeployment Checklist
Deployment Checklist
Pre-Deployment
Pre-Deployment
- All tests passing (unit, integration, E2E)
- Code review approved
- Environment variables configured
- Database migrations ready
- Rollback plan documented
- All tests passing (unit, integration, E2E)
- Code review approved
- Environment variables configured
- Database migrations ready
- Rollback plan documented
Deployment
Deployment
- Docker image built and tagged
- Image pushed to container registry
- Kubernetes manifests applied
- Rolling update started
- Pods healthy and ready
- Docker image built and tagged
- Image pushed to container registry
- Kubernetes manifests applied
- Rolling update started
- Pods healthy and ready
Post-Deployment
Post-Deployment
- Health check endpoint responding
- Metrics/logs monitoring active
- Performance baseline established
- Old pods terminated (after grace period)
- Deployment documented in changelog
undefined- Health check endpoint responding
- Metrics/logs monitoring active
- Performance baseline established
- Old pods terminated (after grace period)
- Deployment documented in changelog
undefinedConstraints
约束条件
필수 규칙 (MUST)
必须遵守的规则(MUST)
-
Health Checks: 모든 서비스에 health check 엔드포인트typescript
app.get('/health', (req, res) => { res.status(200).json({ status: 'ok' }); }); -
Graceful Shutdown: SIGTERM 신호 처리javascript
process.on('SIGTERM', async () => { console.log('SIGTERM received, shutting down gracefully'); await server.close(); await db.close(); process.exit(0); }); -
환경변수 분리: 하드코딩 금지, .env 사용
-
健康检查:所有服务都需配置health check端点typescript
app.get('/health', (req, res) => { res.status(200).json({ status: 'ok' }); }); -
优雅停机:处理SIGTERM信号javascript
process.on('SIGTERM', async () => { console.log('SIGTERM received, shutting down gracefully'); await server.close(); await db.close(); process.exit(0); }); -
环境变量分离:禁止硬编码,使用.env文件
금지 사항 (MUST NOT)
禁止事项(MUST NOT)
- Secrets 커밋 금지: API 키, 비밀번호를 Git에 절대 커밋하지 않음
- 프로덕션에서 디버그 모드: 필수
NODE_ENV=production - latest 태그만 사용: 버전 태그 사용 (v1.0.0, sha-abc123)
- 禁止提交密钥:绝对不要将API密钥、密码提交到Git
- 生产环境禁用调试模式:必须设置
NODE_ENV=production - 禁止仅使用latest标签:使用版本标签(如v1.0.0、sha-abc123)
Best practices
最佳实践
- Multi-stage Docker builds: 이미지 크기 최소화
- Immutable infrastructure: 서버 수정 대신 새로 배포
- Blue-Green deployment: 무중단 배포 및 쉬운 롤백
- Monitoring 필수: Prometheus, Grafana, Datadog
- 多阶段Docker构建:最小化镜像体积
- 不可变基础设施:不修改服务器,而是重新部署
- 蓝绿部署:实现无缝部署与快速回滚
- 必须监控:使用Prometheus、Grafana、Datadog
References
参考资料
Metadata
元数据
버전
版本
- 현재 버전: 1.0.0
- 최종 업데이트: 2025-01-01
- 호환 플랫폼: Claude, ChatGPT, Gemini
- 当前版本:1.0.0
- 最后更新:2025-01-01
- 兼容平台:Claude、ChatGPT、Gemini
관련 스킬
相关技能
- monitoring: 배포 후 모니터링
- security: 배포 보안
- monitoring:部署后监控
- security:部署安全
태그
标签
#deployment#CI/CD#Docker#Kubernetes#automation#infrastructure#deployment#CI/CD#Docker#Kubernetes#automation#infrastructureExamples
示例
Example 1: Basic usage
示例1:基础用法
<!-- Add example content here -->
<!-- Add example content here -->
Example 2: Advanced usage
示例2:进阶用法
<!-- Add advanced example content here -->
<!-- Add advanced example content here -->