Skip to content

DevOps 从零到精通验收清单

这一页不是命令速查,而是 DevOps 的学习验收表。目标是让零基础同学能沿着“代码如何变成线上服务”这条主线,把 Docker、Nginx、Jenkins、Kubernetes、配置、密钥、发布、回滚、监控和排障串起来。

DevOps 真正要解决的问题不是“会不会敲 docker 命令”,而是:

  1. 代码能不能稳定构建。
  2. 制品能不能追踪来源。
  3. 环境能不能一致复现。
  4. 配置和密钥能不能隔离。
  5. 发布能不能灰度、观察和回滚。
  6. 出故障能不能快速知道坏在哪一层。

最终学习目标

学完 DevOps 模块,至少要能做到:

能力合格标准不合格表现
交付链路能画出 Git 到用户访问的全过程只知道把 jar 复制到服务器
Docker能解释镜像、容器、层、网络、数据卷、日志把容器当虚拟机
Nginx能解释反向代理、负载均衡、限流、HTTPS、真实 IP502/504 分不清
Jenkins能写 Pipeline,知道凭据、制品、镜像 tag、健康检查只会点构建按钮
Kubernetes能解释 Pod、Deployment、Service、Ingress、ConfigMap、Secret、Probe、VolumePod 访问不了只会看应用日志
发布回滚能设计滚动发布、灰度、停止放量、回滚和数据库兼容以为回滚只是重启旧代码
可观测性能用日志、指标、链路追踪定位问题用户说慢只能猜
生产排查能按入口、网络、服务、容器、应用、依赖、资源逐层查一上来乱改配置

总学习路线

mermaid
flowchart TD
    A["理解交付链路"] --> B["Docker 镜像和容器"]
    B --> C["Dockerfile 和 Compose"]
    C --> D["Nginx 入口代理"]
    D --> E["Jenkins Pipeline"]
    E --> F["Kubernetes 工作负载"]
    F --> G["配置、密钥、存储、探针"]
    G --> H["灰度、回滚、扩缩容"]
    H --> I["日志、指标、链路追踪"]
    I --> J["生产故障排查"]

学习时不要把工具割裂开。Docker 解决“应用和运行环境一起交付”,Nginx 解决“入口流量如何进入服务”,Jenkins 解决“构建和发布流程自动化”,Kubernetes 解决“多个容器如何在集群中稳定运行”,监控告警解决“上线后怎么知道系统是否健康”。

阶段一:DevOps 到底解决什么

是什么

DevOps 是把开发、测试、构建、制品、部署、运行、监控、告警、回滚和复盘连成闭环的工程体系。

为什么需要

传统人工发布常见问题:

问题例子后果
环境漂移开发机 JDK8,服务器 JDK17本地正常,线上启动失败
人工操作手动上传 jar、手动改配置容易漏步骤、难审计
制品不可追踪不知道线上 jar 来自哪个 commit出事故无法定位版本
配置混乱测试库地址发布到生产数据污染或服务不可用
无回滚能力只有当前版本,没有旧镜像故障恢复慢
无观测能力没有日志聚合、指标、告警用户反馈后才知道坏了

全过程原理

mermaid
flowchart TD
    A["开发提交代码"] --> B["Git 保存 commit"]
    B --> C["CI 拉取指定版本"]
    C --> D["编译、测试、质量检查"]
    D --> E["生成可运行产物"]
    E --> F["构建不可变镜像"]
    F --> G["推送镜像仓库"]
    G --> H["CD 更新目标环境"]
    H --> I["实例启动并健康检查"]
    I --> J["入口接入流量"]
    J --> K["持续观察日志和指标"]
    K --> L{"是否异常"}
    L -- "正常" --> M["完成发布"]
    L -- "异常" --> N["停止放量或回滚"]

这条链路的关键是“可重复、可追踪、可回滚”。如果同一个 commit 每次构建出的东西不同,或者线上运行的镜像不知道来自哪里,就无法保证生产稳定。

阶段二:Docker 镜像和容器

零基础第一次操作前,先完成 Docker第一次运行:从CLI到容器生命周期 的整套实验。要求不是“命令执行成功”,而是能解释每一步由CLI、daemon、Registry、镜像、容器主进程、端口发布、日志驱动、可写层和Volume中的哪个对象完成。

在学习镜像和容器前,必须先通过 Docker安装、权限与升级 建立可验证运行环境:

  • 解释 CLI、dockerd、containerd、shim、runc、Buildx、Compose 的安装来源和职责。
  • 识别 OS、Kernel、CPU 架构、cgroup、文件系统、空间、inode、DNS、时间和代理。
  • 说明 APT/RPM 仓库签名、keyring、signed-by 和发行版代号为什么不能跳过。
  • 使用 systemd 检查 service、socket、unit参数和journal,区分 daemon-reload 与 restart。
  • 解释 rootful socket、docker组近似root权限和普通业务容器挂载socket的风险。
  • 说明 rootless 的User Namespace、用户级systemd、网络、端口、cgroup和存储边界。
  • 规划 data-root、overlay2、日志轮转、地址池、代理、Registry与私有CA。
  • 通过 Docker daemon配置原理、安全变更与故障回滚 区分CLI配置、daemon配置和容器HostConfig,证明systemd unit、drop-in、flags和daemon.json的加载关系。
  • 解释daemon-reload与restart的区别,使用JSON解析、目标版本dockerd --validate、status和journal定位语法错误与重复参数。
  • 证明daemon日志默认值只影响新建容器,设计data-root迁移、地址池冲突治理、代理NO_PROXY、Registry CA和live-restore演练。
  • 在不删除Docker Root Dir的前提下制造一次daemon启动失败,完成金丝雀、分层验证和配置回滚。
  • 分别验证 hello-world、端口发布、自定义网络DNS、Volume持久化、资源限制、Buildx和Compose。
  • 写出Docker Engine金丝雀升级、回滚和卸载保留数据的方案。

核心概念

概念通俗理解原理重点
Image应用运行模板只读分层文件系统
Container镜像运行后的实例宿主机上的隔离进程
Layer镜像的一层构建缓存和复用单位
Registry镜像仓库保存和分发镜像
Volume数据卷容器外持久化数据
Network容器网络容器之间和外部通信

镜像和容器怎么工作

mermaid
flowchart TD
    A["Dockerfile"] --> B["docker build"]
    B --> C["镜像层"]
    C --> D["只读 image"]
    D --> E["docker run"]
    E --> F["可写容器层"]
    F --> G["容器进程"]
    G --> H["namespace 隔离"]
    G --> I["cgroup 限制资源"]

容器不是一台完整虚拟机。容器里的 Java 进程本质上仍运行在宿主机内核上,只是 Docker 使用 namespace 隔离进程、网络、挂载点等视图,使用 cgroup 限制 CPU 和内存。

不这样会怎样

如果不用镜像而是在服务器手动安装环境:

  1. 每台服务器安装步骤可能不一致。
  2. JDK、字体、时区、系统库版本可能漂移。
  3. 回滚时不知道旧环境是什么样。
  4. 扩容新机器时重复手工操作,错误概率高。

Demo:Spring Boot JDK8 镜像

dockerfile
FROM eclipse-temurin:8-jre

WORKDIR /app

COPY target/order-api.jar /app/order-api.jar

ENV JAVA_OPTS="-Xms512m -Xmx512m -XX:+UseG1GC"
ENV SPRING_PROFILES_ACTIVE="prod"

EXPOSE 8080

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/order-api.jar"]

解释:

配置为什么
固定基础镜像避免 latest 漂移
WORKDIR统一应用目录
JAVA_OPTSJVM 参数由环境控制
SPRING_PROFILES_ACTIVE区分环境配置
日志输出标准输出方便容器日志采集

常见坑

现象原因排查
容器立刻退出启动命令错误或应用启动失败docker logs
访问不到端口没有 -p 映射或应用没监听docker psnetstat
容器内连不上 MySQL写了 localhost,实际指向容器自己改成服务名或真实地址
数据丢失没有挂载 volumedocker inspect
磁盘打满日志、镜像、临时文件堆积docker system df

容器信息不能停在记住命令名。必须能够从 Docker容器信息与生产诊断 完成这些验收:

  • docker ps -a 区分 Created、Running、Restarting、Exited 和健康状态。
  • inspect 的 State、Config、HostConfig、NetworkSettings、Mounts 解释最终运行配置。
  • 证明端口是 EXPOSE 还是实际 PortBindings,并确认应用监听地址。
  • 区分 stdout/stderr 日志与容器内文件日志,说明日志驱动和轮转。
  • 区分退出码137、OOMKilled、Java Heap OOM和容器总内存超限。
  • 用 stats、top、events 和历史监控组成事故时间线。

Docker 命令不能靠复制速查表。必须通过 Docker命令从对象模型到生产操作 完成这些验收:

  • 解释 context、image、container、network、volume、builder 和 Compose project 分别是什么对象。
  • 从参数位置拆解 docker run,说明镜像名前后的选项为什么语义不同。
  • 区分 Tag、Digest、Image ID,证明 restart 不会自动切换到本地新镜像。
  • 分别演示 create/start/run、stop/kill/restart、exec/attach 的状态和进程差异。
  • 使用 filter、format、label 精确定位目标,避免依赖截断 ID 或无条件批量操作。
  • 使用 inspect、logs、stats、top、exec、cp、port、diff 和 events,并说明每条命令的证据边界。
  • 区分 save/load 与 export/import,解释为什么后者不是完整镜像或数据库备份。
  • 创建并检查自定义网络和命名卷,说明删除容器、镜像和 Volume 各自影响什么。
  • 使用 system df -v 分类空间,在清理前确认对象引用、业务归属、备份与恢复,不执行无条件全局 prune。

还必须通过 Docker容器运行底层原理 解释:

  • Docker CLI、daemon、containerd、shim、runc 和 Linux 内核的调用链。
  • namespace 负责隔离视图,cgroup 负责资源限制与统计。
  • 镜像只读层、容器可写层、OverlayFS、Copy-on-Write 和 whiteout。
  • docker run 从镜像解析到 Entrypoint 进程启动的完整步骤。
  • PID 1、Shell form、Exec form、SIGTERM、SIGKILL 和优雅停机。
  • Capabilities、seccomp、非root、rootless、privileged 和 Docker Socket 风险。
  • 老版本 JDK 8 与现代 JDK 对容器 CPU/内存感知的差异。

Java服务还必须通过 Spring Boot容器化运行原理 完成这些验收:

  • 画出源码、Jar、镜像、容器、JVM、Spring ApplicationContext、内嵌Tomcat和流量接入全过程。
  • 区分Spring Boot 2.7/JDK 8和Spring Boot 3/JDK 17版本边界,不能只替换基础镜像。
  • 证明Exec form下JVM成为PID 1,并观察SIGTERM、Shutdown Hook和Spring优雅停机。
  • 为容器总内存分别预算Heap、Metaspace、Direct Memory、线程栈、Code Cache和native,并解释Xmx为何不能等于限制。
  • 在目标JDK 8镜像中检查完整8u版本、UseContainerSupport、Heap最终值和availableProcessors。
  • 从Docker Env、Profile、外部配置、命令行参数和配置中心追踪Spring最终PropertySource。
  • 区分liveness、readiness、startup和Docker health,说明错误探针如何制造重启风暴。
  • 以非root运行,并验证日志、临时目录、外部配置、TrustStore和Dump挂载权限。
  • 从容器、JVM、Tomcat、连接池和业务指标完成生产观测与故障定位。
  • 完成先摘流、SIGTERM、等待在途请求、关闭消费者和容器退出的发布实验。

阶段三:Dockerfile 构建和优化

构建过程

mermaid
flowchart TD
    A["读取 Dockerfile"] --> B["拉取基础镜像"]
    B --> C["执行指令生成层"]
    C --> D["命中缓存则复用"]
    D --> E["生成 image id"]
    E --> F["打 tag"]
    F --> G["推送 registry"]

Dockerfile 的顺序会影响缓存。变化少的步骤放前面,变化多的代码复制放后面,可以减少重复构建。

生产写法原则

原则原因
基础镜像固定版本构建结果可复现
不把密码打进镜像镜像可能被多人拉取
不使用 root 运行应用降低容器逃逸后的风险
使用 .dockerignore减少上下文体积
镜像 tag 包含版本或 commit方便回滚和审计
设置 JVM 容器参数避免容器内存限制下 OOM

Demo:带非 root 用户的镜像

dockerfile
FROM eclipse-temurin:8-jre

RUN addgroup --system app && adduser --system --ingroup app app
WORKDIR /app
COPY target/order-api.jar /app/order-api.jar
RUN chown -R app:app /app

USER app
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/order-api.jar"]

如果容器使用 root 运行,一旦应用存在文件写入漏洞或远程命令执行漏洞,攻击面会明显变大。

仅能写出上面的最小示例还不算掌握 Dockerfile。必须通过 Dockerfile 从构建原理到生产镜像 完成这些验收:

  • 解释构建上下文为什么是构建输入边界,以及 .dockerignore 如何同时影响性能、缓存和敏感信息风险。
  • 区分文件系统层与镜像配置,说明内容摘要、父步骤和输入变化如何决定缓存命中。
  • 从源码逐步推导 ENTRYPOINTCMDdocker run 参数的最终合并结果。
  • 解释 Shell form、Exec form、PID 1、SIGTERM 和 exec 入口脚本之间的关系。
  • 使用多阶段构建分别生成 JDK 8 与 JDK 17 的运行镜像,说明为什么不能只考虑最终镜像体积。
  • 解释为什么 ARGENV 和“先复制后删除”都不能安全保存密码,并能使用 BuildKit Secret Mount。
  • 以固定 UID/GID 的非 root 用户运行应用,并定位 COPY --chown、Volume 和宿主机权限问题。
  • 验证具体 JDK 8 更新版本是否识别 cgroup 限制,说明为什么 Xmx 不能等于容器内存上限。
  • docker historyimage inspect、构建日志和运行时 inspect 定位镜像过大、缓存失效和启动失败。
  • 说明镜像 tag、digest、commit 标签、SBOM、漏洞扫描和同一制品跨环境晋级的关系。

阶段四:Compose、网络、数据卷、日志

Compose 适合本地开发、联调、测试环境或者小规模单机环境。它能把 MySQL、Redis、应用服务放在同一个声明式文件里启动。

mermaid
flowchart TD
    A["Compose Project"] --> B["order-api服务"]
    A --> C["mysql服务"]
    A --> D["redis服务"]
    B --> E["通过服务名mysql和redis访问"]
    C --> F["Named Volume保存数据库数据"]
    C --> G["Secret文件提供初始化密码"]
    C --> H["Healthcheck表达初始化状态"]

完整可运行示例不要使用明文root密码,也不要默认把数据库端口暴露到所有宿主机接口。请直接完成 Compose商业栈DemoMySQL容器化Demo,其中包含Secret、健康检查、命名卷、资源限制和日志轮转。

关键原理:

  1. 同一个 Compose 网络中,服务名可以作为 DNS 名称。
  2. depends_on 只控制启动顺序,不保证依赖已经可用。
  3. 数据库必须挂 volume,否则删除容器就会丢数据。
  4. 容器日志默认写到 Docker 管理的日志文件,需要设置日志轮转。

Compose 不能只会 up -ddown。必须通过 Docker Compose 从项目模型到商业编排 完成这些验收:

  • 解释 Compose CLI 如何把变量插值、文件合并后的项目模型转换为 Docker Engine 的容器、网络和 Volume。
  • 区分 Project、Service、Container、服务名 DNS 和项目资源前缀,说明改变项目名为什么会出现另一组数据卷。
  • 分别演示 upcreatestartrestartrunexecstopdown 对对象和配置的影响。
  • 区分项目 .env 的 Compose 插值和 service env_file 的容器环境注入,并用 configinspect 证明最终值。
  • 使用 healthcheck 与 service_healthy 控制初始依赖,同时解释应用为什么仍需连接超时、退避重试、熔断和降级。
  • 解释 portsexpose、容器端口、宿主机端口以及服务内访问之间的关系。
  • 使用命名卷、Bind Mount、external volume,并说明 downdown -v、项目名变化和挂载覆盖的后果。
  • 使用多文件覆盖、Profile 和 Secret,解释最终配置合并与本地 Secret 的安全边界。
  • configpslogstopinspectnetwork inspectvolume inspect 定位完整故障链路。
  • 根据单机故障域、跨节点调度、滚动发布和存储需求判断 Compose 与 Kubernetes 的选型边界。

MySQL 作为有状态服务还必须通过 MySQL容器化与数据安全 完成这些验收:

  • 画出Entrypoint对空数据目录的初始化、临时mysqld、账号创建、init脚本和正式mysqld过程。
  • 证明MYSQL_ROOT_PASSWORD、MYSQL_DATABASE和init脚本不会对已有Volume重新执行。
  • 使用Secret文件、普通业务账号、只读配置、命名卷和最小网络暴露,禁止privileged与明文弱密码。
  • 从Buffer Pool、连接线程、sort/join Buffer、临时表和全局结构预算cgroup总内存。
  • 解释Volume独立生命周期与备份的区别,以及为什么不能tar运行中的数据目录。
  • 完成mysqldump一致性备份、隔离Volume恢复、校验、加密、保留和恢复耗时记录。
  • 说明全量备份、binlog、PITR、RPO和RTO之间的关系。
  • 制定MySQL补丁和大版本升级、兼容验证、未升级副本及失败回退方案。
  • 定位Restarting、Access denied、Too many connections、OOMKilled、磁盘满和崩溃恢复慢。

Redis 作为内存型有状态服务还必须通过 Redis容器化与持久化安全 完成这些验收:

  • 画出镜像Entrypoint、redis-serverredis.conf、ACL文件、PID 1和Docker停止信号之间的启动与停止链路。
  • 保持protected mode,通过内部网络和Redis 6+ ACL限制用户、Key Pattern及命令权限;密码使用Secret,不公开宿主机6379。
  • /data 挂到命名卷,分别说明RDB、AOF everysec、混合持久化的数据丢失窗口、恢复过程和文件布局。
  • 解释BGSAVE与AOF rewrite为什么需要fork,页表复制、Copy-on-Write、写入速率和磁盘IO如何造成内存峰值及延迟抖动。
  • 区分used_memoryused_memory_rssmaxmemory和cgroup内存上限,为allocator碎片、客户端/复制Buffer、Module和fork峰值预留空间。
  • 检查宿主机overcommit、THP、文件描述符、磁盘空间和IO;说明哪些配置是宿主机全局配置,为什么不能靠privileged容器随意修改。
  • 完成RDB/AOF一致备份、校验、加密、保留和空Volume隔离恢复,说明Volume为什么不等于备份。
  • 比较单容器restart、主从、Sentinel和Cluster在副本、自动切换、分片、客户端和跨故障域方面的边界。
  • 使用INFOSLOWLOGLATENCYcommandstats、Docker stats/logs/inspect定位NOAUTH、NOPERM、OOM、持久化失败、数据丢失和延迟抖动。

Nginx作为容器入口还必须通过 Nginx容器化、反向代理与生产安全 完成这些验收:

  • 画出Entrypoint、daemon off、master/worker、PID 1、停止信号和Docker端口发布的完整链路。
  • 使用只读配置和证书挂载,并用inspect Mounts、nginx -tnginx -T证明容器最终读取的内容。
  • 解释localhost、Compose服务名、容器IP、宿主机端口和Docker DNS的边界,禁止写死后端容器IP。
  • 证明proxy_pass尾部斜杠对上游URI的影响,并正确传递Host、真实IP、协议和WebSocket Upgrade头。
  • 区分reload、restart和recreate,验证新旧worker平滑过渡、长连接与优雅退出。
  • 让access/error log进入stdout/stderr并配置日志轮转,说明挂载日志目录为什么可能遮住官方镜像符号链接。
  • 设计非root、只读根文件系统、tmpfs和最小Capability方案,不使用privileged或chmod 777掩盖权限错误。
  • 按DNS、端口发布、Nginx监听、服务名解析、上游TCP、应用与依赖逐层定位403、404、502、504和TLS错误。

网络不能只会执行 docker network create。必须通过 Docker 网络底层原理 完成这些验收:

  • 画出 Network Namespace、容器 eth0、veth pair、Linux bridge 和宿主机物理网卡的关系。
  • 解释同网络服务名为什么能解析,以及默认 bridge 和自定义 bridge 在 DNS 方面的区别。
  • 分别画出容器访问外网的 SNAT 路径和外部访问 -p 发布端口的 DNAT 路径。
  • 区分 Connection refused、超时、DNS 失败、TLS/HTTP 错误,说明每类错误处在哪一层。
  • 解释 localhost0.0.0.0、容器 IP、宿主机 IP、服务名各自表示什么。
  • 能说明 MTU、iptables/nftables、host、macvlan、overlay 的适用边界,并完成最小抓包定位。

数据卷不能只记住 -v。必须通过 Docker 存储挂载与数据生命周期 完成这些验收:

  • 区分镜像只读层、容器可写层、Named Volume、Bind Mount 和 tmpfs 的生命周期。
  • 解释 OverlayFS 可写层为什么不适合持久数据库,以及挂载为什么会遮住镜像内原文件。
  • 能定位 UID/GID、只读挂载、SELinux 标签和 Docker Desktop 路径造成的权限问题。
  • 解释 docker compose downdown -vvolume rmvolume prune 对数据的不同影响。
  • 说明 Volume 为什么不是备份,为什么不能随意复制运行中数据库数据目录。
  • 根据 RPO/RTO 设计逻辑备份、独立副本、保留策略、校验和恢复演练。

阶段五:Nginx 入口层

在学习配置指令前,必须先完成 Nginx进程模型、事件循环与高并发原理:能够解释Master与Worker、非阻塞socket、epoll就绪事件、连接状态机、客户端与upstream双连接、FD限制、keep-alive、Buffer和reload。只会背“异步非阻塞”不算通过。

配置阶段必须完成 Nginx配置解析、虚拟主机与请求匹配全过程:能够从listen、SNI、Host、server_name一路推导到规范化URI和location,分别验证rewrite last/break、root/alias、try_files内部重定向、proxy_pass URI替换、可信代理Header和404/403/502/504排查。

负载均衡阶段必须完成 Nginx负载均衡、健康判断与重试全过程:能够比较加权轮询、least_conn、ip_hash和consistent hash,区分被动失败与主动健康,解释proxy_next_upstream、非幂等重复执行、每Worker keepalive、DNS更新、慢节点P99和重试风暴。

限流阶段必须完成 Nginx限流、排队与拒绝全过程:能够逐请求推导rate、burst、nodelay和delay时间线,区分limit_req与limit_conn,解释可信真实IP、NAT误伤、zone容量、多个Nginx实例额度放大、全局限流和登录/短信/搜索/上传策略。

可观测性阶段必须完成 Nginx日志、分段耗时与生产故障取证:能够用Request ID和多值upstream变量还原重试链,区分request/connect/header/response时间,定位499/502/504、CPU、连接、FD、磁盘和TLS问题。

缓存阶段必须完成 Nginx代理缓存、过期与一致性全过程:能够设计安全cache key,区分TTL与inactive、HIT/MISS/STALE/BYPASS,解释cache lock、stale、多实例冷缓存、磁盘容量和用户数据串读风险。

Nginx 做什么

Nginx 常见职责:

  1. 反向代理:隐藏后端真实地址。
  2. 负载均衡:把流量分给多个实例。
  3. 静态资源:直接返回 HTML、JS、CSS、图片。
  4. HTTPS 终止:处理证书和 TLS 握手。
  5. 限流:保护后端服务。
  6. 缓存:降低后端压力。
  7. 真实 IP 透传:让后端知道客户端来源。

请求转发流程

mermaid
flowchart TD
    A["用户请求域名"] --> B["DNS 解析到入口 IP"]
    B --> C["Nginx 接收连接"]
    C --> D["匹配 server_name"]
    D --> E["匹配 location"]
    E --> F{"静态还是代理"}
    F -- "静态资源" --> G["读取本地文件"]
    F -- "API" --> H["选择 upstream"]
    H --> I["转发后端服务"]
    I --> J["返回响应给用户"]

Demo:反向代理和负载均衡

nginx
upstream order_api {
    least_conn;
    server 10.0.0.11:8080 max_fails=3 fail_timeout=10s;
    server 10.0.0.12:8080 max_fails=3 fail_timeout=10s;
}

server {
    listen 80;
    server_name api.example.com;

    location /api/ {
        proxy_pass http://order_api/;
        proxy_connect_timeout 3s;
        proxy_read_timeout 30s;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Request-Id $request_id;
    }
}

502 和 504 怎么区分

状态含义常见原因
502Nginx 无法从后端拿到正常响应后端挂了、端口不通、协议错误、连接被拒绝
504Nginx 等后端响应超时后端慢 SQL、线程池满、外部接口慢、超时配置太短

排查时先看 Nginx error log,再 curl upstream 地址,再看后端日志和依赖。

阶段六:Jenkins Pipeline

在编写Jenkinsfile前,先完成 Jenkins Controller、Agent与构建执行全过程:能够从Webhook推导到Queue、Label、Node、Agent、Executor和Workspace,解释workspace@2、JDK运行时与构建工具链、stash/archive/制品仓库、JENKINS_HOME和安全隔离。

Pipeline阶段必须完成 Jenkins Pipeline CPS、并发与可靠发布全过程:能够解释CPS、Continuation、暂停点、Controller重启恢复、@NonCPS与序列化,正确使用agent none、input、timeout、retry、parallel、matrix、milestone、lock和Credentials,并推广同一镜像Digest。

生产发布阶段必须完成 Jenkins商业发布、灰度与回滚全过程:能够追踪Commit、Digest、配置和数据库版本,使用Expand/Migrate/Contract和消息兼容支持回滚,设计滚动/蓝绿/金丝雀、版本技术与业务指标、自动停止、多对象回滚、前滚和副作用补偿。

共享库阶段必须完成 Jenkins Shared Library加载、信任与版本治理:能够解释 varssrcresources 的加载边界,区分 @Library 与运行期 library,说明 Trusted/Untrusted、CPS、无状态API和Shell注入原理,并能设计语义版本、测试金字塔、金丝雀升级与回退流程。

Jenkins 解决什么

Jenkins 把发布步骤从“人工点击和手工命令”变成“代码化流水线”。流水线的价值不只是自动化,更重要的是可审计、可重复、可回滚。

Pipeline 执行流程

mermaid
flowchart TD
    A["触发构建"] --> B["拉取代码"]
    B --> C["编译"]
    C --> D["单元测试"]
    D --> E["打包制品"]
    E --> F["构建镜像"]
    F --> G["推送镜像仓库"]
    G --> H["部署目标环境"]
    H --> I["健康检查"]
    I --> J{"是否成功"}
    J -- "成功" --> K["通知完成"]
    J -- "失败" --> L["停止发布或回滚"]

Demo:Jenkinsfile

groovy
pipeline {
  agent any

  environment {
    APP_NAME = 'order-api'
    REGISTRY = 'registry.example.com/backend'
    IMAGE_TAG = "${env.BUILD_NUMBER}-${env.GIT_COMMIT.take(8)}"
  }

  stages {
    stage('Checkout') {
      steps {
        checkout scm
      }
    }

    stage('Test') {
      steps {
        sh 'mvn clean test'
      }
    }

    stage('Package') {
      steps {
        sh 'mvn package -DskipTests'
        archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
      }
    }

    stage('Build Image') {
      steps {
        sh 'docker build -t $REGISTRY/$APP_NAME:$IMAGE_TAG .'
      }
    }

    stage('Push Image') {
      steps {
        sh 'docker push $REGISTRY/$APP_NAME:$IMAGE_TAG'
      }
    }

    stage('Deploy') {
      steps {
        sh 'kubectl set image deployment/order-api order-api=$REGISTRY/$APP_NAME:$IMAGE_TAG -n prod'
        sh 'kubectl rollout status deployment/order-api -n prod --timeout=180s'
      }
    }
  }
}

凭据和制品

内容正确做法错误做法
镜像仓库密码Jenkins Credentials写在 Jenkinsfile
SSH 私钥凭据绑定放代码仓库
jar 包archiveArtifacts 归档构建完就丢
镜像 tag构建号 + commit永远 latest
发布日志保留流水线日志人工命令无记录

阶段七:Kubernetes 核心对象

零基础学习者应先完成 Kubernetes从零学习路线与第一个应用:能够从镜像、容器、Pod一路解释到Deployment、Service和Ingress;能够部署最小应用,沿着API Server、Controller、Scheduler、kubelet、CRI和CNI说明创建过程;能够用OwnerReference、EndpointSlice、Condition、Event和日志证明每个环节,而不是只看到Running就认定上线成功。

工作负载阶段必须完成 Kubernetes工作负载、滚动更新与任务调度:能够从Deployment追踪到新旧ReplicaSet和Pod,计算maxSurge/maxUnavailable,解释Readiness、minReadySeconds、ProgressDeadline和优雅终止;能够区分StatefulSet、DaemonSet、Job、CronJob的控制语义,并设计批任务幂等、重试、Deadline与错过调度处理。

网络阶段必须完成 Kubernetes Pod网络、Service、DNS与NetworkPolicy:能够解释CNI如何建立Pod网络,追踪Selector到EndpointSlice,区分port/targetPort/nodePort,说明ClusterIP、iptables/IPVS/eBPF、Conntrack和长连接负载边界;能够排查CoreDNS/ndots/缓存,设计双向最小NetworkPolicy并定位同节点、跨节点和MTU故障。

七层入口阶段必须完成 Kubernetes Ingress、TLS与七层流量排障:能够区分Ingress、IngressClass、Controller、Controller Service和外部LB,解释Reconcile、Host/SNI/PathType、Rewrite和TLS终止;能够从真实握手、Controller上游日志、EndpointSlice和Trace区分404、502、503、504,并治理可信源IP、危险Annotation和多租户Host冲突。

配置与密钥阶段必须完成 Kubernetes ConfigMap、Secret与配置轮换全过程:能够解释API到etcd、kubelet和容器的注入链路,区分env快照、Atomic Writer投射卷和subPath,设计版本化配置与Checksum发布;能够说明Base64/静态加密/KMS边界、审计间接Secret权限,并完成数据库凭据和TLS证书零停机轮换。

探针阶段必须完成 Kubernetes Startup、Readiness、Liveness探针全过程:能够解释kubelet执行和阈值状态机,说明Startup门控、Readiness到EndpointSlice传播和Liveness容器重启;能够比较HTTP/TCP/gRPC/Exec边界,为Spring Boot设计不依赖共享数据库的健康契约,并排查误杀、重启风暴、全部摘流和假健康。

存储阶段必须完成 Kubernetes PV、PVC、StorageClass与CSI存储全过程:能够解释静态/动态供应、Immediate/WFFC拓扑调度和CSI Create/Attach/Stage/Publish,准确区分RWO/RWX/RWOP与Filesystem/Block;能够治理Reclaim、扩容、快照/备份/PITR,并排查PVC Pending、Multi-Attach、FailedAttach、FailedMount和Node故障恢复。

Helm阶段必须完成 Helm Chart、模板渲染与生产发布全过程:能够解释Chart/Release/Revision、Values优先级与Map/List合并、Go Template作用域和Release Secret;能够区分wait/atomic/cleanup/force,治理Hook数据库迁移、CRD特殊生命周期、依赖锁和OCI供应链,并排查pending、ownership、Hook和Rollback失败。

对象关系

mermaid
flowchart TD
    A["Deployment"] --> B["ReplicaSet"]
    B --> C["Pod 副本"]
    D["Service"] --> C
    E["Ingress"] --> D
    F["ConfigMap"] --> C
    G["Secret"] --> C
    H["Volume"] --> C
    I["Probe"] --> C

每个对象解决什么

对象作用不理解会怎样
Pod最小调度单位误以为容器直接被 Service 管
Deployment声明期望副本和发布策略手动创建 Pod 无法滚动发布
ReplicaSet维持某版本副本数不知道旧版本为什么还存在
Service稳定服务发现和负载均衡Pod IP 变化后调用失败
Ingress集群外 HTTP 入口外部流量不知道怎么进集群
ConfigMap普通配置配置硬编码进镜像
Secret敏感配置密码散落在代码和镜像
Probe健康检查不健康实例继续接流量
Volume持久化或共享文件Pod 重建后数据丢失

Demo:Deployment + Service

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-api
  namespace: prod
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: order-api
  template:
    metadata:
      labels:
        app: order-api
    spec:
      containers:
        - name: order-api
          image: registry.example.com/backend/order-api:1.0.0
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: order-api-config
            - secretRef:
                name: order-api-secret
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 20
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 60
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: order-api
  namespace: prod
spec:
  selector:
    app: order-api
  ports:
    - port: 80
      targetPort: 8080

阶段八:配置、密钥、存储、探针

ConfigMap 和 Secret

ConfigMap 保存普通配置,Secret 保存敏感配置。Secret 默认只是 base64 编码,不等于绝对安全,生产还要结合 RBAC、etcd 加密、密钥轮换和审计。

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-api-config
data:
  SPRING_PROFILES_ACTIVE: "prod"
  LOG_LEVEL: "INFO"
---
apiVersion: v1
kind: Secret
metadata:
  name: order-api-secret
type: Opaque
stringData:
  SPRING_DATASOURCE_PASSWORD: "change-me"

readiness 和 liveness

mermaid
flowchart TD
    A["Pod 启动"] --> B["容器进程启动"]
    B --> C["liveness 检查"]
    B --> D["readiness 检查"]
    C -- "失败" --> E["重启容器"]
    D -- "失败" --> F["从 Service endpoints 移除"]
    D -- "成功" --> G["接收流量"]
探针代表什么失败后果
readinessProbe是否准备好接流量Service 不转发给它
livenessProbe进程是否还活着kubelet 重启容器
startupProbe慢启动保护成功前不执行其他探针

慢启动服务应该使用 startupProbe 或把 liveness 初始延迟调大,否则应用还在初始化就会被反复杀掉。

阶段九:灰度发布、回滚、扩缩容

滚动发布流程

mermaid
flowchart TD
    A["创建新 ReplicaSet"] --> B["启动少量新 Pod"]
    B --> C["新 Pod readiness 通过"]
    C --> D["减少旧 Pod"]
    D --> E["继续替换"]
    E --> F{"全部完成"}
    F -- "是" --> G["发布成功"]
    F -- "异常" --> H["暂停或回滚"]

回滚为什么不是万能的

代码能回滚,不代表系统一定能回滚。真正的回滚条件包括:

  1. 旧镜像仍在镜像仓库。
  2. 旧配置仍可用。
  3. 数据库表结构兼容旧代码。
  4. MQ 消息格式兼容旧消费者。
  5. 前端静态资源和后端接口兼容。
  6. 外部接口协议没有单向变更。

扩缩容不是万能药

接口慢时不能立刻扩容,要先判断瓶颈:

瓶颈盲目扩容后果
数据库慢 SQL更多实例产生更多 DB 压力
Redis 热 key更多实例同时打同一个 key
MQ 消费慢消费者扩容受分区数或顺序性限制
外部接口慢更多并发打爆外部接口
线程池配置小实例增多前单实例仍卡住

阶段十:可观测性和生产排查

三类证据

类型回答什么问题典型工具
日志某次请求具体发生了什么ELK、Loki
指标系统整体是否健康Prometheus、Grafana
链路追踪请求经过哪些服务SkyWalking、Jaeger、Zipkin
mermaid
flowchart TD
    A["用户请求"] --> B["网关生成 traceId"]
    B --> C["订单服务"]
    C --> D["库存服务"]
    C --> E["支付服务"]
    C --> F["日志、指标、链路上报"]
    F --> G["告警和看板"]

故障排查总流程

mermaid
flowchart TD
    A["线上异常"] --> B{"表现是什么"}
    B -- "访问不了" --> C["DNS、Nginx、Ingress"]
    B -- "接口 5xx" --> D["应用日志、异常栈"]
    B -- "变慢" --> E["P99、线程池、DB、Redis、MQ"]
    B -- "Pod 异常" --> F["describe、events、logs"]
    B -- "发布失败" --> G["流水线、镜像、权限、探针"]
    C --> H["确认请求到达哪一层"]
    D --> I["用 traceId 串完整链路"]
    E --> J["定位瓶颈再决定扩容或回滚"]
    F --> K["区分调度、拉镜像、启动、探针"]
    G --> L["停止发布并保留现场"]

常用命令

bash
kubectl get pod -n prod
kubectl describe pod order-api-xxx -n prod
kubectl logs order-api-xxx -n prod --tail=200
kubectl get events -n prod --sort-by=.metadata.creationTimestamp
kubectl get endpoints order-api -n prod
kubectl rollout status deployment/order-api -n prod
kubectl rollout history deployment/order-api -n prod
kubectl rollout undo deployment/order-api -n prod
kubectl top pod -n prod
bash
docker ps -a
docker logs order-api --tail=200
docker inspect order-api
docker exec -it order-api sh
docker system df

Docker 排障不能停在记住以上命令。必须通过 Docker生产故障排查Runbook 完成这些验收:

  • 先区分容器运行中、已退出/重启中、已删除/宿主机失联,说明每种现场还能获得哪些证据。
  • 在任何重启、重建和清理前,保存容器State、时间戳日志、events、镜像身份、端口、网络、Mounts和资源限制。
  • 从Docker context、daemon、镜像、创建、主进程、网络、存储、应用到依赖逐层缩小故障域。
  • 对Created、Running、Restarting、Exited、Unhealthy分别给出下一步检查和判定依据。
  • 从客户端、宿主机防火墙、端口发布、容器IP、监听地址到HTTP业务完成访问失败定位。
  • 按目标配置、服务名DNS、共同网络、TCP、TLS、认证和协议完成依赖连接失败定位。
  • 区分Exit 137、OOMKilled、Java Heap OOM、容器总内存OOM和宿主机OOM,并说明信息从哪里获取。
  • 从CPU quota/throttling、JVM线程、GC、流量和重试风暴定位CPU高与接口慢。
  • 使用df -hdf -isystem df -v、LogConfig和deleted-open文件定位磁盘占满,禁止盲目全局prune。
  • 从最终Mounts、数字UID/GID、只读rootfs、SELinux和项目名变化定位权限与数据问题。
  • 写出包含业务影响、时间线、直接原因、根因、触发条件、扩大因素、长期修复和验证的事故复盘,不能以“重启恢复”结案。
bash
nginx -t
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
curl -H "Host: api.example.com" http://127.0.0.1/api/health

商业常用场景

场景一:订单系统发布

订单系统要关注下单、库存、支付、MQ 和状态机。

发布前:

  1. 检查数据库变更是否兼容旧代码。
  2. 检查 MQ 消息字段是否兼容旧消费者。
  3. 检查支付回调地址是否保持稳定。
  4. 确认限流、熔断、线程池、连接池配置。
  5. 准备下单成功率、支付成功率、订单卡状态数量看板。

发布后:

  1. 观察接口错误率和 P99。
  2. 观察 MQ 堆积和消费失败。
  3. 观察数据库慢 SQL。
  4. 观察支付回调失败率。
  5. 异常时停止放量或回滚。

场景二:医疗数据采集平台发布

医疗数据采集平台常见链路是设备接入、数据清洗、异步入库、文件归档、ES 检索、资产管理。

发布策略:

  1. 采集网关滚动发布,避免所有设备同时断连。
  2. 正在执行的采集任务要能恢复或补偿。
  3. 采集配置变更必须审计。
  4. MQ 堆积、失败批次、ES 同步延迟要告警。
  5. 原始报文和清洗结果要能追踪。

场景三:搜索服务发布

搜索服务通常涉及 MySQL、MQ、ES、缓存。

重点:

  1. 索引 Mapping 变更要用新索引和别名切换。
  2. ES 同步失败要有补偿任务。
  3. 查询接口要观察 P99 和慢查询。
  4. 发布前要确认新旧索引兼容。
  5. 回滚时要确认别名指向和代码版本一致。

面试标准回答

DevOps 是什么

text
DevOps 是把开发、测试、构建、制品、部署、运行、监控、告警和反馈连接起来的工程体系。它的目标不是单纯自动发布,而是让软件交付可重复、可追踪、可回滚、可观测,减少环境差异和人工操作风险。

代码到上线全过程

text
开发提交代码到 Git 后,CI 流水线拉取指定 commit,执行编译、测试和打包,生成 jar 或 dist。然后构建 Docker 镜像并打上构建号和 commit tag,推送到镜像仓库。CD 阶段更新 Kubernetes Deployment,新 Pod 拉取镜像启动,通过 readinessProbe 后加入 Service,再由 Ingress 或 Nginx 对外暴露。上线后观察日志、指标、链路追踪和业务指标,异常时停止放量或回滚。

Docker 镜像和容器区别

text
镜像是只读模板,由多层文件系统组成;容器是镜像运行后的进程实例,会在只读镜像层之上增加可写层。一个镜像可以启动多个容器。容器不是完整虚拟机,它共享宿主机内核,通过 namespace 做隔离,通过 cgroup 做资源限制。

Nginx 502 和 504 区别

text
502 通常表示 Nginx 连接后端失败或后端返回了异常网关响应,常见原因是后端挂了、端口不通、upstream 配错。504 表示 Nginx 等待后端响应超时,常见原因是后端慢 SQL、线程池耗尽、外部接口慢或超时配置不合理。排查时先看 Nginx error log,再验证 upstream,再看后端日志和依赖。

Kubernetes 中 Pod、Deployment、Service、Ingress 的关系

text
Pod 是最小调度单位,应用容器运行在 Pod 中;Deployment 声明期望副本数和发布策略,通过 ReplicaSet 维持 Pod 副本;Service 通过标签选择一组 Pod,提供稳定访问入口和负载均衡;Ingress 把集群外 HTTP 请求路由到 Service。用户请求通常经过 Ingress,再到 Service,最后转发到 Ready 的 Pod。

readinessProbe 和 livenessProbe 区别

text
readinessProbe 表示实例是否准备好接流量,失败时 Service 不再把请求转发给它;livenessProbe 表示进程是否还活着,失败时 kubelet 会重启容器。慢启动服务如果 liveness 配太激进,会出现还没启动完成就被反复杀掉的 CrashLoopBackOff。

学懂验收问题

如果下面问题答不上来,说明还没有真正学懂:

  1. 为什么生产发布不能只上传 jar?
  2. 镜像为什么要固定 tag,不能一直用 latest?
  3. 容器为什么不是虚拟机?
  4. 为什么容器内访问宿主机的 localhost 经常不对?
  5. Nginx 502 和 504 分别从哪几层排查?
  6. Jenkins Credentials 为什么不能用环境变量明文替代?
  7. Pod Ready 但服务仍访问失败有哪些原因?
  8. readinessProbe 和 livenessProbe 配错会造成什么事故?
  9. 为什么数据库变更可能让代码回滚失效?
  10. 接口变慢时为什么不能立刻扩容?

关联知识点跳转

主题继续学习
DevOps 总览运维工具
生产路线DevOps 从零到生产级掌握
商业场景DevOps 商业场景训练营
Docker 入门Docker 入门路线
Docker第一次运行hello-world、Nginx、端口、日志、状态、可写层与Volume
Docker daemon配置配置来源、systemd、data-root、日志、网络、代理与回滚
DockerfileDockerfile
Docker ComposeDocker Compose
Docker 排障Docker 排障
Docker容器信息诊断容器状态、inspect与OOM
Docker容器底层原理namespace、cgroup、OverlayFS与runtime
Docker网络底层原理namespace、veth、bridge、DNS与NAT
Docker存储生命周期可写层、Volume、Bind、权限与备份恢复
Redis容器化ACL、RDB/AOF、fork/COW、内存预算、备份恢复与高可用边界
Nginx容器化启动链、配置挂载、Docker DNS、TLS、reload与502/504排障
Nginx 总览Nginx 总览
Nginx事件模型Master、Worker、epoll、连接状态机、FD与reload
Nginx配置匹配listen、server_name、location、rewrite、root/alias、try_files与proxy_pass
Nginx 负载均衡算法、健康、重试、幂等、Keep-Alive、动态服务发现与排障
Nginx 限流rate、burst、delay、连接、真实IP、全局额度与商业策略
Nginx日志排障Request ID、upstream分段耗时、状态码、轮转与Runbook
Nginx代理缓存Key、磁盘、TTL、击穿、stale和一致性
Jenkins PipelineCPS、恢复、并发、凭据、制品、审批与可靠发布
Jenkins执行架构Controller、Agent、Queue、Executor、Workspace与制品
Jenkins商业发布制品准入、数据库兼容、灰度、指标、回滚、前滚与补偿
Jenkins Shared Library加载、信任、版本、API、测试、金丝雀升级与回退
K8s 从零入口对象关系、首个应用、API执行链、观察证据和故障实验
K8s 架构API请求、etcd、Informer控制循环、调度与Pod创建全过程
K8s 工作负载滚动更新、终止、状态身份、节点Agent与任务调度全过程
K8s 网络Pod IP、Service数据面、DNS、TrafficPolicy和NetworkPolicy全过程
K8s 配置与密钥注入、热更新、版本发布、加密、权限、外部Secret与轮换
K8s IngressController Reconcile、Host/Path、TLS、代理语义与七层Runbook
K8s 存储供应、拓扑、CSI挂载、访问模式、扩容、快照、备份与恢复
K8s 探针执行机制、时间窗口、流量准入、重启、Spring Boot与误杀Runbook
K8s HelmChart、Values、模板、Release、Hook、CRD、供应链与发布Runbook
K8s 可观测性六类证据、Metrics数据源、故障场景与生产Runbook
DevOps 面试DevOps 面试题