传统手工运维模式存在三大痛点:
全栈自动化的目标:
本文以一套 Spring Boot 微服务应用 为例,展示完整的自动化闭环。
┌─────────────────────────────────────────────────────────────────┐
│ 开发者 Git Push │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ GitHub Actions (CI) │
│ - 代码检出 │
│ - 静态代码扫描 (SonarQube) │
│ - 单元测试 + 覆盖率报告 │
│ - 构建 Docker 镜像 │
│ - 镜像安全扫描 (Trivy) │
│ - 推送到 Harbor 镜像仓库 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Terraform (基础设施即代码) │
│ - 创建/更新 Kubernetes 集群 (若需要) │
│ - 创建 Namespace、ServiceAccount、Secret │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Argo CD / kubectl (持续部署) │
│ - 应用 Kubernetes 清单 (Deployment, Service, Ingress) │
│ - 滚动更新 (maxSurge, maxUnavailable) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Kubernetes 集群 (生产环境) │
│ - 多个 Pod 运行应用 │
│ - 健康检查 (Readiness/Liveness) │
│ - 服务发现与负载均衡 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Prometheus + Alertmanager │
│ - 采集应用指标 (错误率、响应时间) │
│ - 触发告警 (如错误率 > 5%) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 自动化回滚 (Python 脚本) │
│ - 接收到告警 Webhook │
│ - 执行 `kubectl rollout undo` │
│ - 发送回滚通知到钉钉/企业微信 │
└─────────────────────────────────────────────────────────────────┘我们准备一个极简 REST API,用于演示:
src/main/java/com/example/DemoController.java:
package com.example;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@RestController
public class DemoController {
@GetMapping("/health")
public String health() {
return "OK";
}
@GetMapping("/greet")
public String greet(String name) {
return "Hello, " + name + "! Time: " + LocalDateTime.now();
}
}application.yml:
server:
port: 8080
management:
endpoints:
web:
exposure:
include: health, metrics, prometheusDockerfile:
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]在项目根目录创建 .github/workflows/ci.yml:
name: Full CI Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
REGISTRY: harbor.example.com
IMAGE_NAME: myapp
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'
- name: Run unit tests with coverage
run: mvn test jacoco:report
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@v3
with:
projectBaseDir: .
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
- name: Build Docker image
run: docker build -t $REGISTRY/$IMAGE_NAME:${{ github.sha }} .
- name: Security scan with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
- name: Log in to Harbor
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.HARBOR_USER }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Push image
run: docker push $REGISTRY/$IMAGE_NAME:${{ github.sha }}
- name: Tag as latest (if main branch)
if: github.ref == 'refs/heads/main'
run: |
docker tag $REGISTRY/$IMAGE_NAME:${{ github.sha }} $REGISTRY/$IMAGE_NAME:latest
docker push $REGISTRY/$IMAGE_NAME:latest
- name: Update Kubernetes manifest (GitOps)
if: github.ref == 'refs/heads/main'
run: |
# 使用 yq 更新 deployment.yaml 中的镜像 tag
apt-get update && apt-get install -y yq
yq eval -i '.spec.template.spec.containers[0].image = "'$REGISTRY/$IMAGE_NAME:${{ github.sha }}'"' k8s/deployment.yaml
git config user.name "github-actions"
git config user.email "actions@github.com"
git add k8s/deployment.yaml
git commit -m "Update image to ${{ github.sha }} [skip ci]"
git push https://${{ secrets.GH_PAT }}@github.com/${{ github.repository }}.git如果集群需要动态创建,我们使用 Terraform 管理 Kubernetes 基础资源。
terraform/main.tf:
provider "kubernetes" {
config_path = "~/.kube/config"
}
resource "kubernetes_namespace" "app" {
metadata {
name = "myapp-prod"
}
}
resource "kubernetes_secret" "docker_registry" {
metadata {
name = "harbor-registry"
namespace = kubernetes_namespace.app.metadata.name
}
type = "kubernetes.io/dockerconfigjson"
data = {
".dockerconfigjson" = jsonencode({
auths = {
"harbor.example.com" = {
auth = base64encode("${var.harbor_user}:${var.harbor_password}")
}
}
})
}
}
variable "harbor_user" {
sensitive = true
}
variable "harbor_password" {
sensitive = true
}执行:
terraform init
terraform apply -var="harbor_user=xxx" -var="harbor_password=xxx"k8s/deployment.yaml(自动更新镜像 tag):aml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: myapp-prod
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
imagePullSecrets:
- name: harbor-registry
containers:
- name: myapp
image: harbor.example.com/myapp:latest # 将被CI更新为具体SHA
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"k8s/service.yaml:
apiVersion: v1
kind: Service
metadata:
name: myapp-service
namespace: myapp-prod
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIPk8s/ingress.yaml(假设使用 nginx-ingress):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
namespace: myapp-prod
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-service
port:
number: 80在 CI 的最终步骤,我们通过 GitOps 方式触发部署(上面的 workflow 已更新 manifest 并 push)。Argo CD 监控 Git 仓库变化,自动同步。
或者,我们也可以直接使用 kubectl apply 在 CI 中部署(但建议 GitOps 方式)。为了完整性,额外添加一个部署 Job:
# .github/workflows/deploy.yml (独立或合并)
deploy:
runs-on: ubuntu-latest
needs: build-and-test
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v4
with:
version: 'latest'
- name: Configure kubeconfig
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config
- name: Apply manifests
run: |
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml
kubectl rollout status deployment/myapp -n myapp-prod --timeout=5m使用 Prometheus Operator 或 Helm 快速部署:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring --create-namespace配置 ServiceMonitor 采集应用指标:
k8s/servicemonitor.yaml:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: myapp-monitor
namespace: myapp-prod
spec:
selector:
matchLabels:
app: myapp
endpoints:
- port: http
path: /actuator/prometheus
interval: 30sprometheus-rules.yaml(添加到 Prometheus):
groups:
- name: myapp
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_server_requests_seconds_count{status=~"5.."}[2m]))
/ sum(rate(http_server_requests_seconds_count[2m])) > 0.05
for: 1m
labels:
severity: critical
annotations:
summary: "应用错误率过高"
description: "错误率 {{ $value }} 超过 5%,触发自动回滚"当 Alertmanager 发送告警,我们通过 Webhook 接收并执行回滚。
rollback_server.py:
from flask import Flask, request, jsonify
import subprocess
import json
import os
app = Flask(__name__)
ROLLBACK_THRESHOLD = 0.05 # 可配置
@app.route('/webhook', methods=['POST'])
def webhook():
data = request.json
# 解析告警内容
alerts = data.get('alerts', [])
for alert in alerts:
if alert.get('labels', {}).get('alertname') == 'HighErrorRate':
# 确认错误率超过阈值
annotations = alert.get('annotations', {})
# 可以解析 value,此处简化
print(f"收到告警: {annotations}")
# 执行回滚
result = rollback_deployment()
# 发送通知
send_notification(result)
return jsonify({"status": "ok"}), 200
def rollback_deployment():
cmd = "kubectl rollout undo deployment/myapp -n myapp-prod"
try:
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, text=True)
return f"回滚成功: {output}"
except subprocess.CalledProcessError as e:
return f"回滚失败: {e.output}"
def send_notification(msg):
# 发送到钉钉/企业微信
import requests
webhook_url = os.getenv("DINGTALK_WEBHOOK", "")
if webhook_url:
payload = {
"msgtype": "text",
"text": {"content": f"[自动回滚] {msg}"}
}
requests.post(webhook_url, json=payload)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)将此服务部署为 Kubernetes Deployment,并暴露 Service,在 Alertmanager 中配置 Webhook receiver。
Alertmanager 配置片段:
receivers:
- name: 'webhook'
webhook_configs:
- url: 'http://rollback-service.default.svc.cluster.local:5000/webhook'修改代码(例如引入错误逻辑)并 push,观察 CI 是否构建、部署,以及 Prometheus 检测到错误率升高后触发回滚。
# 模拟错误注入
kubectl exec -it deployment/myapp -n myapp-prod -- /bin/sh -c "echo 'error' > /tmp/error"
# 观察 Prometheus 是否告警,回滚服务是否执行本文完整实现了从代码提交到自动化回滚的全栈自动化闭环,涉及:
可进一步扩展的方向:
全栈自动化不仅是技术堆砌,更是 DevOps 文化的落地。通过代码定义一切,我们让发布变得可重复、可审计、可恢复。希望本文的代码能成为你构建自动化体系的基础素材。
免责声明:本文示例代码仅供学习参考,生产环境需结合安全策略、备份恢复、熔断机制等完善。
关于作者:DevOps 架构师,专注云原生与自动化运维实践。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。