关于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/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。