关于DevOps 自动化部署的几点记录

这次做 DevOps 自动化改造,从脚本到基础设施即代码,。

最初的问题

手动部署

# 登录服务器
ssh server

# 拉取代码
cd /var/www/myapp
git pull

# 安装依赖
npm install

# 构建项目
npm run build

# 重启服务
pm2 restart myapp

问题

  • 容易出错
  • 没有版本控制
  • 无法回滚
  • 效率低

Shell 脚本

简单的部署脚本

#!/bin/bash
# deploy.sh

set -e

APP_DIR="/var/www/myapp"
APP_NAME="myapp"

echo "开始部署 ${APP_NAME}"

# 拉取代码
cd ${APP_DIR}
git pull origin main

# 安装依赖
npm ci

# 构建项目
npm run build

# 重启服务
pm2 restart ${APP_NAME}

echo "部署完成"

使用 Ansible

# deploy.yml
- hosts: servers
  become: yes
  tasks:
    - name: Update code
      git:
        repo: https://github.com/example/myapp.git
        dest: /var/www/myapp
        version: main
    
    - name: Install dependencies
      npm:
        path: /var/www/myapp
    
    - name: Build project
      command: npm run build
      args:
        chdir: /var/www/myapp
    
    - name: Restart service
      command: pm2 restart myapp

基础设施即代码

Terraform 部署

# main.tf
provider "aws" {
  region = "us-west-1"
}

# 创建 EC2 实例
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  
  tags = {
    Name = "web-server"
  }
}

# 创建安全组
resource "aws_security_group" "web" {
  name        = "web-sg"
  description = "Allow HTTP traffic"
  
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# 输出实例 IP
output "instance_ip" {
  value = aws_instance.web.public_ip
}

Kubernetes 部署

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 80
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 80
  type: LoadBalancer

Helm Charts

创建 Helm Chart

# 创建 Chart
helm create myapp
cd myapp

values.yaml

# values.yaml
replicaCount: 3

image:
  repository: myapp
  pullPolicy: IfNotPresent
  tag: "1.0.0"

service:
  type: LoadBalancer
  port: 80

resources:
  limits:
    cpu: 200m
    memory: 256Mi
  requests:
    cpu: 100m
    memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

部署应用

# 部署
helm install myapp ./myapp

# 升级
helm upgrade myapp ./myapp --set image.tag=2.0.0

# 回滚
helm rollback myapp

ArgoCD

安装 ArgoCD

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

创建 Application

# myapp.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/example/myapp.git
    targetRevision: HEAD
    path: k8s
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

自动化流程

GitOps 流程

graph TB A[开发者提交代码] --> B[Git 仓库] B --> C[CI/CD 流水线] C --> D[构建镜像] D --> E[推送镜像] E --> F[更新 GitOps 配置] F --> G[ArgoCD 检测到变化] G --> H[自动同步到集群] style A fill:#FFD700 style C fill:#90EE90 style H fill:#FFB6C1

GitHub Actions

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      
      - name: Build Docker image
        run: |
          docker build -t myapp:${{ github.sha }} .
          docker tag myapp:${{ github.sha }} myapp:latest
      
      - name: Push to registry
        run: |
          docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
          docker push myapp:${{ github.sha }}
          docker push myapp:latest
  
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to Kubernetes
        run: |
          kubectl set image deployment/myapp myapp=myapp:${{ github.sha }}
          kubectl rollout status deployment/myapp

灰度发布

Kubernetes 灰度发布

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: myapp
spec:
  replicas: 3
  strategy:
    canary:
      steps:
      - setWeight: 10
      - pause: { duration: 1h }
      - setWeight: 30
      - pause: { duration: 1h }
      - setWeight: 50
      - pause: { duration: 1h }
      - setWeight: 100
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        ports:
        - containerPort: 80

踩过的坑

坑一:部署失败没有回滚

新版本有 bug,但没有回滚机制。

解决:实现自动回滚。

# Helm Chart
annotations:
  "helm.sh/hook": post-upgrade
  "helm.sh/hook-delete-policy": before-hook-creation

# 或者在部署脚本中
if ! kubectl rollout status deployment/myapp --timeout=5m; then
  kubectl rollout undo deployment/myapp
  exit 1
fi

坑二:配置管理混乱

配置分散在各个地方,难以管理。

解决:统一配置管理。

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
data:
  DATABASE_URL: "postgres://db:5432/myapp"
  REDIS_URL: "redis://redis:6379"

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secret
type: Opaque
stringData:
  API_KEY: "your-api-key"

坑三:资源泄漏

部署后没清理旧资源,导致资源泄漏。

解决:配置资源限制和清理策略。

# deployment.yaml
resources:
  requests:
    memory: "128Mi"
    cpu: "100m"
  limits:
    memory: "256Mi"
    cpu: "200m"

# 清理策略
revisionHistoryLimit: 10

部署检查清单

部署前

  • 代码 review 完成
  • 测试通过
  • 配置文件正确
  • 数据库迁移准备

部署中

  • 监控部署进度
  • 检查日志
  • 验证健康检查
  • 准备回滚

部署后

  • 功能验证
  • 性能验证
  • 监控告警
  • 用户反馈

写在最后

DevOps 自动化部署这东西,不只是工具问题,是文化问题。

解决了

  • 手动操作风险
  • 部署效率
  • 回滚能力
  • 版本管理

带来了

  • 学习成本
  • 维护成本
  • 复杂度增加

实施之前先评估:

  • 团队能力
  • 项目规模
  • 业务需求
  • 预算

不是所有场景都需要完整的 DevOps 流程,有时候简单的脚本就够了。


这次 DevOps 自动化改造花了一个月,从脚本到基础设施即代码。改造完成后,部署时间从 30 分钟降到 5 分钟,部署成功率从 80% 提升到 99%。

版权声明: 本文首发于 指尖魔法屋-关于DevOps 自动化部署的几点记录https://blog.thinkmoon.cn/post/72-devops-automation-iac-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!