DevOps & 工程化
难度等级:⭐⭐⭐ 前置知识:Web 后端开发 后续衔接:微服务架构、云原生
学习路径
- 入门阶段:掌握 Git 基础,理解 CI/CD 流程
- 进阶阶段:能够编写 Dockerfile、配置 CI/CD Pipeline
- 精通阶段:能够搭建完整的可观测性体系
一、CI/CD 持续集成与交付
1.1 CI/CD 概念
CI/CD 是现代软件工程中不可或缺的核心实践,它将传统的”开发完成后一次性交付”模式转变为高频、小批量的持续交付模式。
持续集成(Continuous Integration, CI) 是指开发人员频繁地将代码变更合并到主干分支,每次合并都会触发自动化构建和测试流程。其核心目标是尽早发现集成错误,避免”集成地狱”。典型的 CI 流程包括:代码提交 → 触发构建 → 编译打包 → 运行单元测试 → 运行集成测试 → 生成构建报告。
持续交付(Continuous Delivery, CD) 在 CI 的基础上,确保代码在任何时候都可以安全地部署到生产环境。它强调自动化部署流程,但最终是否上线由人工决定。持续交付的关键环节包括:自动化部署到预发环境 → 运行验收测试 → 性能测试 → 安全扫描 → 等待人工审批。
持续部署(Continuous Deployment) 是持续交付的更进一步,所有通过自动化测试的变更都会自动部署到生产环境,无需人工干预。这需要极高的测试覆盖率和成熟的监控体系作为保障。
三者关系可以用一句话概括:持续集成是基础,持续交付是保障,持续部署是目标。
| 实践 | 自动化测试 | 人工审批 | 生产部署 |
|---|---|---|---|
| 持续集成 | ✅ | ❌ | ❌ |
| 持续交付 | ✅ | ✅ | 手动触发 |
| 持续部署 | ✅ | ❌ | 自动触发 |
1.2 Jenkins
Jenkins 是最流行的开源 CI/CD 工具,拥有超过 1800 个插件,支持几乎任何构建、测试和部署场景。
Pipeline 语法:Jenkins Pipeline 使用 Groovy 语言定义,分为声明式(Declarative)和脚本式(Scripted)两种。推荐使用声明式,结构更清晰:
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'registry.example.com'
}
stages {
stage('Checkout') {
steps { checkout scm }
}
stage('Build') {
steps { sh './gradlew build' }
}
stage('Test') {
parallel {
stage('Unit Tests') { steps { sh './gradlew test' } }
stage('Integration Tests') { steps { sh './gradlew integrationTest' } }
}
}
stage('Deploy') {
when { branch 'main' }
steps { sh './deploy.sh' }
}
}
post {
success { echo 'Pipeline succeeded!' }
failure { mail to: 'team@example.com', subject: 'Pipeline Failed' }
}
}
Jenkinsfile 应该与源代码一起提交到版本控制系统中,实现 Pipeline as Code。这样既便于版本管理,也方便团队协作。
分布式构建:Jenkins 支持 Master-Agent 架构,可以将构建任务分发到多个 Agent 节点,提高并发构建能力。配置 Agent 时需要指定标签(label),Pipeline 中通过 agent { label 'linux' } 指定运行节点。
插件生态:常用插件包括 Git Plugin、Docker Plugin、Kubernetes Plugin、SonarQube Scanner、Blue Ocean(可视化 Pipeline)等。插件过多会影响 Jenkins 性能,建议只安装必要的插件。
1.3 GitLab CI
GitLab CI 与 GitLab 代码仓库深度集成,无需额外部署独立服务,配置简洁。
核心概念:
- Pipeline:一次完整的 CI/CD 执行流程
- Stage:Pipeline 中的阶段,如 build、test、deploy
- Job:Stage 中的具体任务
- Runner:执行 Job 的执行器
- Artifact:Job 产生的构建产物,可在后续 Stage 中使用
.gitlab-ci.yml 示例:
stages:
- build
- test
- deploy
variables:
MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
cache:
paths:
- .m2/repository/
build-job:
stage: build
image: maven:3.9-eclipse-temurin-17
script:
- mvn clean package -DskipTests
artifacts:
paths:
- target/*.jar
expire_in: 1 week
test-job:
stage: test
image: maven:3.9-eclipse-temurin-17
script:
- mvn test
coverage: '/Coverage: \d+\.\d+%/'
deploy-job:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/app app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
only:
- main
Runner 类型:Shared Runner(所有项目共享)、Group Runner(组内共享)、Specific Runner(绑定特定项目)。Runner 执行器支持 Docker、Shell、Kubernetes 等多种模式。
优化技巧:
- 使用
cache缓存依赖,避免每次构建都重新下载 - 使用
artifacts传递构建产物 - 使用
rules或only/except控制 Job 执行条件 - 使用
needs实现 DAG 有向无环图执行,跳过不必要的等待
1.4 GitHub Actions
GitHub Actions 是 GitHub 内置的 CI/CD 工具,与 GitHub 生态无缝集成,拥有庞大的 Action 市场。
核心概念:
- Workflow:定义在
.github/workflows/目录下的 YAML 文件 - Event:触发 Workflow 的事件,如 push、pull_request、schedule
- Job:Workflow 中的执行单元,每个 Job 运行在独立的 Runner 上
- Step:Job 中的具体步骤
- Action:可复用的任务单元
Workflow 示例:
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
strategy:
matrix:
java: ['17', '21']
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
cache: 'gradle'
- name: Build
run: ./gradlew build
- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-java-${{ matrix.java }}
path: build/reports/tests/
docker-build:
needs: build-and-test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
Matrix 构建 允许在多个维度上并行执行任务,如不同操作系统、不同语言版本、不同数据库版本等,非常适合兼容性测试。
Secrets 管理:敏感信息(如 API Key、Docker 密码)应存储在 Repository Settings → Secrets 中,通过 ${{ secrets.NAME }} 在 Workflow 中引用。
1.5 自动化测试
自动化测试是 CI/CD 的基石,没有可靠的测试体系,持续集成就失去了意义。
测试金字塔(Test Pyramid)由 Mike Cohn 提出,建议测试分为三层:
/\
/ \ E2E Tests(端到端测试)- 少量
/____\
/ \ Integration Tests(集成测试)- 适量
/________\
/ \ Unit Tests(单元测试)- 大量
/____________\
- 单元测试(Unit Tests):测试单个函数或方法,运行速度快,数量最多。使用 Mock 隔离外部依赖。目标覆盖率 80%+。
- 集成测试(Integration Tests):测试多个组件的协作,如数据库操作、HTTP 调用、消息队列等。需要真实或模拟的外部服务。
- 端到端测试(E2E Tests):从用户视角测试完整流程,如通过浏览器自动化测试 Web 应用。运行慢、维护成本高,应精简关键路径。
测试策略建议:
- 单元测试运行时间控制在秒级,每次提交必须执行
- 集成测试可在 PR 合并到主干时执行
- E2E 测试可在每日定时任务或发布前执行
- 使用测试覆盖率工具(如 JaCoCo、Istanbul)监控质量底线
常见测试框架:
- Java:JUnit 5 + Mockito + Testcontainers
- JavaScript/TypeScript:Jest + Testing Library + Playwright
- Python:pytest + unittest.mock
- Go:testing 包 + testify + gock
1.6 代码质量
代码质量是软件可维护性的保障,需要通过工具化手段在 CI/CD 流程中自动检查。
SonarQube 是最流行的代码质量管理平台,支持 30+ 编程语言。它能检测:
- Bug:潜在的空指针、资源泄漏、并发问题
- 漏洞:SQL 注入、XSS、硬编码密码
- 代码异味(Code Smell):过长方法、重复代码、过高圈复杂度
- 测试覆盖率:单元测试覆盖情况
SonarQube 集成示例:
# GitLab CI 中集成 SonarQube
sonarqube-check:
stage: test
image: sonarsource/sonar-scanner-cli:latest
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
GIT_DEPTH: "0"
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- sonar-scanner
-Dsonar.projectKey=${CI_PROJECT_NAME}
-Dsonar.qualitygate.wait=true
allow_failure: true
only:
- merge_requests
- main
代码规范检查:
- Java:Checkstyle(代码风格)、PMD(潜在问题)、SpotBugs(字节码分析)
- JavaScript:ESLint + Prettier
- Python:flake8 + black + mypy
- 建议将规范检查配置为 CI 的 Gate,不通过则阻止合并
质量门禁(Quality Gate) 建议配置:
- 新增代码覆盖率不低于 80%
- 新增代码不得引入 Blocker/Critical 级别问题
- 重复代码率不超过 3%
- 圈复杂度不超过 15
二、容器化
2.1 Docker 基础
Docker 通过容器技术实现了应用的标准化打包和隔离运行,是云原生时代的基石。
镜像(Image)与容器(Container):镜像是只读的模板,包含运行应用所需的代码、运行时、库和配置。容器是镜像的运行实例,具有独立的文件系统、网络命名空间和进程空间。可以把镜像理解为”类”,容器理解为”对象”。
Dockerfile 常用指令:
# 基础镜像
FROM eclipse-temurin:17-jre-alpine
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV JAVA_OPTS="-Xmx512m -Xms256m"
# 复制文件
COPY target/app.jar app.jar
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -qO- http://localhost:8080/actuator/health || exit 1
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
Dockerfile 指令说明:
FROM:指定基础镜像,每个 Dockerfile 必须以 FROM 开头RUN:在构建时执行命令,每条 RUN 会创建一个新的镜像层COPY/ADD:将文件复制到镜像中,ADD 还支持 URL 和自动解压 tarCMD/ENTRYPOINT:定义容器启动时的默认命令,ENTRYPOINT 更适合作为固定入口EXPOSE:声明容器监听的端口(仅文档作用,实际映射需通过 -p 参数)ENV:设置环境变量,可在运行时通过 -e 覆盖
层(Layer)与缓存:Docker 镜像由多个只读层叠加而成。每条指令创建一个层。Docker 会缓存已构建的层,如果某层内容未变,则复用缓存。因此应将变化频率低的指令(如安装依赖)放在前面,变化频率高的指令(如复制源码)放在后面,以充分利用缓存加速构建。
2.2 Docker Compose
Docker Compose 用于定义和运行多容器应用,通过一个 YAML 文件管理所有容器的生命周期。
docker-compose.yml 示例:
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- DB_HOST=db
- REDIS_HOST=redis
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app-network
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: appdb
volumes:
- db-data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
volumes:
db-data:
redis-data:
networks:
app-network:
driver: bridge
核心概念:
- Service:一个容器的抽象定义,可以指定镜像、端口、环境变量等
- Network:容器间的通信网络,默认创建 bridge 网络,同一网络内的容器可通过服务名互相访问
- Volume:持久化存储,分为命名卷(managed volume)和绑定挂载(bind mount)
- depends_on:定义服务启动顺序,可配合 healthcheck 实现”等依赖就绪后再启动”
常用命令:
docker-compose up -d:后台启动所有服务docker-compose logs -f app:查看指定服务的日志docker-compose down -v:停止并删除所有容器、网络和卷docker-compose exec app bash:进入容器内部
2.3 镜像优化
镜像优化直接影响构建速度、传输效率和运行时安全性。
多阶段构建(Multi-stage Build) 是最有效的优化手段,将构建环境和运行环境分离:
# 构建阶段
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /build
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests -q
# 运行阶段
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# 仅复制构建产物,不包含源码和 Maven
COPY --from=builder /build/target/*.jar app.jar
USER appuser
ENTRYPOINT ["java", "-jar", "app.jar"]
优化策略:
- 选择精简基础镜像:优先使用 Alpine 或 Distroless 镜像。Alpine 基于 musl libc,体积仅 5MB;Distroless 仅包含运行时依赖,无 shell 和包管理器。
- 合并 RUN 指令:将多个 apt-get 命令合并为一条,减少镜像层数。
- 使用 .dockerignore:排除不必要的文件(如 .git、node_modules、target),减小构建上下文。
- 利用构建缓存:将变化少的层(如依赖安装)放在前面,变化多的层(如源码复制)放在后面。
- 清理临时文件:在同一层中安装依赖后立即清理缓存,如
apt-get clean && rm -rf /var/lib/apt/lists/*。
.dockerignore 示例:
.git
.gitignore
.idea
*.md
target/
build/
node_modules/
.env
.dockerignore
Dockerfile
docker-compose*.yml
镜像大小对比:
- 标准 Ubuntu + JDK:~400MB
- Alpine + JRE:~100MB
- Distroless JRE:~80MB
2.4 容器安全
容器安全是生产环境中不可忽视的环节。
以非 root 用户运行:默认情况下,容器内的进程以 root 身份运行,一旦被攻破,攻击者可能获得宿主机权限。
# 创建非 root 用户
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
# 设置文件权限
RUN chown -R appuser:appgroup /app
# 切换用户
USER appuser
镜像扫描:定期扫描镜像中的已知漏洞(CVE)。常用工具包括 Trivy、Grype、Snyk、Docker Scout。
# 使用 Trivy 扫描镜像
trivy image --severity HIGH,CRITICAL myapp:latest
Secret 管理:
- 不要将密码、Token 等敏感信息写入镜像或 Dockerfile
- 使用 Docker Secrets 或外部密钥管理服务(如 HashiCorp Vault、AWS Secrets Manager)
- 运行时通过环境变量或挂载文件注入 Secret
其他安全最佳实践:
- 固定基础镜像版本,避免使用
latest标签 - 使用只读文件系统(
--read-only),仅挂载必要的可写目录 - 限制容器资源(
--memory、--cpus),防止资源耗尽 - 删除不必要的工具和包(如 curl、wget、apt),减少攻击面
- 定期更新基础镜像,修复已知漏洞
三、Kubernetes
3.1 K8s 架构
Kubernetes(简称 K8s)是 Google 开源的容器编排平台,已成为云原生时代的事实标准。
控制平面(Control Plane / Master 节点):
- API Server:K8s 的唯一入口,所有操作都通过 REST API 进行。负责验证、处理请求并更新 etcd。
- etcd:分布式键值存储,保存集群的所有状态和配置。是 K8s 的”单一数据源”,需要定期备份。
- Scheduler:负责将 Pod 调度到合适的 Node 上,考虑资源需求、亲和性、污点等约束。
- Controller Manager:运行各种控制器(如 ReplicaSet、Node、Endpoint 控制器),确保实际状态与期望状态一致。
工作节点(Worker Node / Node):
- kubelet:Node 上的 Agent,负责与 API Server 通信,管理 Pod 的生命周期。
- kube-proxy:负责 Service 的网络代理,实现负载均衡和服务发现。
- Container Runtime:运行容器的软件,如 containerd、CRI-O。
架构特点:声明式 API(用户声明期望状态,控制器自动趋近目标)、自愈能力(自动重启、替换失败的 Pod)、水平扩展(通过增加 Node 提升集群容量)。
3.2 核心资源
Pod:K8s 最小的部署单元,包含一个或多个容器。同一 Pod 内的容器共享网络命名空间(同一个 IP)和存储卷。
apiVersion: v1
kind: Pod
metadata:
name: app-pod
labels:
app: myapp
version: v1
spec:
containers:
- name: app
image: myapp:1.0.0
ports:
- containerPort: 8080
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
Deployment:管理 Pod 的副本数量,支持滚动更新和回滚。
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-deployment
spec:
replicas: 3
selector:
matchLabels:
app: myapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
spec:
containers:
- name: app
image: myapp:1.0.0
Service:为一组 Pod 提供稳定的网络访问入口,通过 Label Selector 关联 Pod。
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
ConfigMap 和 Secret:
- ConfigMap:存储非敏感配置(如配置文件、环境变量)
- Secret:存储敏感信息(如密码、Token),数据以 Base64 编码存储
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
application.yml: |
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://db:3306/appdb
---
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
db-password: cm9vdDEyMw== # base64 encoded
3.3 服务暴露
K8s 提供了多种服务暴露方式,适用于不同场景。
| 类型 | 说明 | 使用场景 |
|---|---|---|
| ClusterIP | 集群内部可访问的虚拟 IP(默认) | 内部服务间通信 |
| NodePort | 在每个 Node 上开放指定端口 | 开发测试、简单外部访问 |
| LoadBalancer | 调用云提供商创建外部负载均衡器 | 生产环境,云部署 |
| Ingress | 七层 HTTP/HTTPS 路由,基于域名和路径转发 | 多域名、多路径路由 |
Ingress 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: tls-secret
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: app-v1-service
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: app-v2-service
port:
number: 80
Ingress 需要配合 Ingress Controller(如 Nginx Ingress、Traefik、Istio Gateway)才能工作。
3.4 存储
K8s 的存储体系分为三层抽象:
PersistentVolume(PV):集群级别的存储资源,由管理员预先创建或由 StorageClass 动态创建。
PersistentVolumeClaim(PVC):用户对存储的请求,类似于 Pod 对 Node 资源的请求。系统会将 PVC 与合适的 PV 绑定。
StorageClass:定义存储的”类型”,支持动态供应(Dynamic Provisioning)。
# StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: io1
iopsPerGB: "50"
---
# PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 50Gi
---
# Pod 中使用 PVC
# 在 Pod spec 中:
volumes:
- name: db-storage
persistentVolumeClaim:
claimName: db-pvc
访问模式:
- ReadWriteOnce(RWO):单节点读写(最常用)
- ReadOnlyMany(ROX):多节点只读
- ReadWriteMany(RWX):多节点读写(需要 NFS、Ceph 等支持)
3.5 自动扩缩容
K8s 提供了多层次的自动扩缩容能力。
HPA(Horizontal Pod Autoscaler):根据 CPU、内存或自定义指标自动调整 Pod 副本数。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: app-deployment
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
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
VPA(Vertical Pod Autoscaler):自动调整 Pod 的 CPU 和内存请求/限制。适合无法水平扩展的有状态应用。
Cluster Autoscaler:当 Pod 因资源不足无法调度时,自动增加 Node 数量;当 Node 利用率过低时,自动缩减 Node。需要云提供商支持。
KEDA(Kubernetes Event-driven Autoscaling):基于外部事件源(如消息队列长度、HTTP 请求数)驱动扩缩容,适合事件驱动架构。
3.6 Helm
Helm 是 K8s 的包管理工具,通过模板化方式管理复杂的 K8s 资源。
Chart 结构:
mychart/
├── Chart.yaml # Chart 元数据(名称、版本、描述)
├── values.yaml # 默认配置值
├── values-prod.yaml # 环境特定配置
├── charts/ # 依赖的子 Chart
└── templates/ # K8s 资源模板
├── deployment.yaml
├── service.yaml
├── configmap.yaml
└── ingress.yaml
模板中使用 Values:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include "mychart.name" . }}
template:
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
ports:
- containerPort: {{ .Values.service.port }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
常用命令:
helm install my-release ./mychart:安装 Charthelm upgrade my-release ./mychart -f values-prod.yaml:升级 Releasehelm rollback my-release 1:回滚到指定版本helm list:列出所有 Releasehelm repo add stable https://charts.helm.sh/stable:添加 Chart 仓库
四、监控与日志
4.1 Prometheus
Prometheus 是云原生时代最流行的监控系统,采用拉模式(Pull)采集指标。
数据模型:Prometheus 将所有数据存储为时间序列(Time Series),由指标名称和键值对标签组成。例如:http_requests_total{method="POST", handler="/api/users", status="200"}。
四种指标类型:
- Counter:只增不减的计数器,如请求总数、错误数
- Gauge:可增可减的仪表盘值,如内存使用量、队列长度
- Histogram:直方图,用于统计分布(如请求延迟的 P99、P95)
- Summary:类似 Histogram,在客户端计算分位数
Exporter:将非 Prometheus 格式的数据转换为 Prometheus 格式。常用 Exporter 包括:
- Node Exporter:主机指标(CPU、内存、磁盘、网络)
- MySQL Exporter:数据库指标
- JMX Exporter:Java 应用指标
- Blackbox Exporter:黑盒探测(HTTP、TCP、DNS)
PromQL 示例:
# 过去 5 分钟的 HTTP 请求速率(每秒)
rate(http_requests_total[5m])
# P99 请求延迟
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
# 错误率(5xx 响应占比)
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
# 内存使用率
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
AlertManager:负责处理 Prometheus 产生的告警,支持分组、抑制、静默和多渠道通知(邮件、Slack、钉钉、企业微信、PagerDuty)。
4.2 Grafana
Grafana 是最流行的可视化仪表盘工具,支持多种数据源。
核心功能:
- Dashboard:将多个 Panel 组合为一个可视化页面,每个 Panel 可以展示不同数据源的指标
- 数据源:支持 Prometheus、Elasticsearch、MySQL、Loki、Tempo、Jaeger 等
- 告警规则:在 Grafana 中定义告警条件,通过 Notification Channel 发送通知
- 变量:支持 Dashboard 级别的变量(如环境、服务名),实现动态过滤
典型 Dashboard 布局:
- 顶部:关键指标概览(QPS、错误率、延迟、饱和度)
- 中部:各服务的详细指标(请求量、响应时间、资源使用)
- 底部:基础设施指标(CPU、内存、磁盘、网络)
Grafana + Prometheus 告警规则示例:
# prometheus-rule.yml
groups:
- name: app-alerts
rules:
- alert: HighErrorRate
expr: sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "高错误率:{{ $value | humanizePercentage }}"
description: "服务 {{ $labels.job }} 的 5xx 错误率超过 5%"
4.3 ELK 日志栈
ELK(Elasticsearch + Logstash + Kibana)是经典的日志管理方案,现在常与 Filebeat 配合使用,称为 Elastic Stack。
架构组件:
应用 → Filebeat → Logstash → Elasticsearch → Kibana
(采集) (处理) (存储) (展示)
Filebeat:轻量级日志采集器,部署在每台主机上,负责读取日志文件并发送到 Logstash 或 Elasticsearch。
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
fields:
service: myapp
env: production
multiline:
pattern: '^\d{4}-\d{2}-\d{2}'
negate: true
match: after
output.logstash:
hosts: ["logstash:5044"]
Logstash:日志处理管道,支持过滤、转换、丰富日志数据。
# logstash.conf
input {
beats { port => 5044 }
}
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{LOGLEVEL:level}\] %{DATA:logger} - %{GREEDYDATA:msg}" }
}
date {
match => ["timestamp", "yyyy-MM-dd HH:mm:ss.SSS"]
}
mutate {
remove_field => ["timestamp"]
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "app-logs-%{+YYYY.MM.dd}"
}
}
Elasticsearch:分布式搜索引擎,负责存储和索引日志数据。需要关注索引生命周期管理(ILM),定期滚动索引以控制存储成本。
Kibana:日志可视化工具,支持搜索、过滤、聚合分析和创建 Dashboard。
4.4 链路追踪
链路追踪用于追踪请求在分布式系统中的完整调用路径,帮助定位性能瓶颈和故障根因。
核心概念:
- Trace:一次完整的请求链路,由唯一的 Trace ID 标识
- Span:链路中的一个操作单元(如一次 RPC 调用、一次数据库查询),由 Span ID 标识
- Parent/Child:Span 之间的层级关系,形成调用树
- Context Propagation:在微服务之间传递 Trace 信息(通常通过 HTTP Header)
OpenTelemetry:CNCF 的观测性标准,统一了链路追踪、指标和日志的采集方式。
# OpenTelemetry Collector 配置示例
receivers:
otlp:
protocols:
grpc:
http:
processors:
batch:
exporters:
jaeger:
endpoint: jaeger:14250
tls:
insecure: true
logging:
loglevel: debug
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [jaeger, logging]
主流追踪后端:
- Jaeger:Uber 开源的分布式追踪系统,支持多种存储后端
- Zipkin:Twitter 开源的追踪系统,生态成熟
- SkyWalking:Apache 项目,对 Java 生态支持优秀,适合微服务架构
链路追踪的价值:
- 可视化服务依赖关系
- 定位慢请求根因
- 分析请求在各服务间的流转路径
- 结合日志和指标,形成完整的可观测性体系
4.5 可观测性三位一体
现代云原生系统的可观测性建立在三个支柱之上:
Metrics(指标):聚合的数值数据,如 CPU 使用率、QPS、错误率。特点是存储效率高,适合趋势分析和告警,但无法提供单个请求的详细信息。
Logs(日志):离散的事件记录,包含时间戳、级别、消息等。特点是信息丰富、可搜索,但存储成本高,难以直接关联。
Traces(链路追踪):请求级别的调用路径记录。特点是能完整还原请求生命周期,但采样率高时可能遗漏问题。
三者的关系:
用户请求 → [Trace] 完整调用链路
↓
每个 Span 关联 → [Logs] 该步骤的详细日志
↓
每个服务暴露 → [Metrics] 聚合指标
整合实践:
- 使用 OpenTelemetry SDK 同时采集 Traces 和 Metrics
- 在日志中注入 Trace ID,实现日志与链路的关联
- 在 Grafana 中统一展示三类数据,形成完整的观测视图
- 告警基于 Metrics,根因分析基于 Traces,详细排查基于 Logs
五、版本控制与协作
5.1 Git 工作流
Git 工作流定义了团队协作开发时的分支策略和代码合并规范。
Git Flow:经典的双主干模型,适合有固定发布周期的项目。
main (生产) ──────────────────────────────────────
↑ ↑ ↑
release/1.0 release/1.1 release/2.0
↑ ↑ ↑
develop ──────────────────────────────────────────
↑ ↑ ↑
│ └─ feature/B
└─ feature/A
- main:只接受来自 release 和 hotfix 的合并,始终可发布
- develop:集成开发分支,包含最新开发中的代码
- feature/:从 develop 创建,完成后合并回 develop
- release/:从 develop 创建,修复 bug 后合并到 main 和 develop
- hotfix/:从 main 创建,修复后合并回 main 和 develop
GitHub Flow:简化的单主干模型,适合持续部署。
main ───┬────────────────────────────────────────
│ ┌─ feature/A (PR) ──┐
│ │ │
└────┴───────────────────┘── deploy
- main:始终可部署
- 从 main 创建功能分支,完成后通过 PR 合并回 main
- 合并后立即部署到生产
Trunk Based Development:所有开发者直接向主干提交代码(或小批量短分支),配合功能开关(Feature Flags)控制功能可见性。适合高频发布的团队。
5.2 分支策略
分支策略的选择取决于团队的发布频率和质量要求。
保护分支(Protected Branches):
- 禁止直接 push 到 main/develop
- 要求 PR 至少一个 reviewer 批准
- 要求 CI 全部通过才能合并
- 禁止 force push
分支命名规范:
feature/描述:新功能bugfix/描述:bug 修复hotfix/描述:紧急修复release/版本号:发布准备
合并策略:
- Merge Commit:保留完整历史,但会产生额外的合并提交
- Squash and Merge:将多个提交压缩为一个,保持历史简洁
- Rebase and Merge:将提交线性化,避免合并提交
5.3 Code Review
Code Review 是保证代码质量、知识共享和团队一致性的重要实践。
Review 清单:
- 代码是否正确实现了需求
- 是否有潜在的安全问题
- 错误处理是否完善
- 是否有充分的测试
- 代码是否可读、可维护
- 命名是否清晰、一致
- 是否有不必要的复杂度
- 性能是否合理
Review 最佳实践:
- 小批量提交:每个 PR 控制在 200-400 行以内
- 及时响应:尽量在 24 小时内完成 review
- 建设性反馈:指出问题并提供改进建议
- 使用自动化工具:让 CI 处理格式、风格等机械检查
- 尊重作者:评论针对代码而非人
5.4 语义化提交
Conventional Commits 规范了提交信息的格式,使提交历史更具可读性和可自动化处理。
格式:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
常用 type:
feat:新功能fix:bug 修复docs:文档更新style:代码格式(不影响代码逻辑)refactor:重构perf:性能优化test:测试相关chore:构建/工具相关
示例:
feat(auth): add JWT token refresh endpoint
Implements token refresh to allow users to extend
their session without re-authentication.
Closes #123
自动化工具:
- commitlint:校验提交信息格式
- husky:Git hooks 管理
- semantic-release:自动生成版本号、CHANGELOG
六、学习资源推荐
CI/CD
- 《Continuous Delivery》- Jez Humble, David Farley(持续交付经典著作)
- Jenkins 官方文档:https://www.jenkins.io/doc/
- GitHub Actions 文档:https://docs.github.com/en/actions
- GitLab CI/CD 文档:https://docs.gitlab.com/ee/ci/
容器化
- 《Docker Deep Dive》- Nigel Poulton
- Docker 官方文档:https://docs.docker.com/
- Docker Bench for Security:https://github.com/docker/docker-bench-security
Kubernetes
- 《Kubernetes in Action》- Marko Luksa
- Kubernetes 官方文档:https://kubernetes.io/docs/
- Helm 文档:https://helm.sh/docs/
- KEDA:https://keda.sh/
监控与日志
- Prometheus 官方文档:https://prometheus.io/docs/
- Grafana 文档:https://grafana.com/docs/
- OpenTelemetry 文档:https://opentelemetry.io/docs/
- ELK Stack 文档:https://www.elastic.co/guide/
版本控制
- Pro Git(免费在线阅读):https://git-scm.com/book/
- Conventional Commits:https://www.conventionalcommits.org/
- 《Git Flow》- Vincent Driessen:https://nvie.com/posts/a-successful-git-branching-model/