Linux、容器与部署
部署不是把代码上传到服务器。它要把一个确定的构建产物放进受控运行环境,配置好网络、权限、资源和数据迁移,验证它真的可用,并保留回滚路径。
Linux、容器和编排系统解决的,是同一组问题的不同层次:进程怎样运行,资源怎样隔离和限制,多个实例怎样调度,发布怎样可重复。
1. Linux 的四个核心对象
跳转到“1. Linux 的四个核心对象”1.1 文件与挂载
跳转到“1.1 文件与挂载”Linux 把设备和目录组织成一棵树,常见目录各有职责:
| 目录 | 内容 |
|---|---|
/bin、/usr/bin |
基础可执行文件 |
/etc |
系统与应用配置 |
/var |
日志、缓存、数据库等可变数据 |
/home |
用户目录 |
/tmp |
临时文件,可能被清理 |
/proc、/sys |
内核暴露的运行状态 |
/dev |
设备文件 |
生产应用的数据不应只放在容器可写层或临时目录。日志、数据库和上传文件要挂载到持久卷或对象存储。
1.2 权限
跳转到“1.2 权限”文件权限通常由所有者、所属组和其他人的读/写/执行位组成。chmod 改权限,chown 改所有者。目录的执行位表示能否进入或遍历。
ls -lchmod 640 .envchown app:app /srv/app/config.yml不要用 chmod 777 解决权限问题。它让所有用户都能写,可能扩大攻击面。服务应以最小权限用户运行,而不是默认 root。
1.3 进程
跳转到“1.3 进程”每个进程有 PID、父进程、用户、打开的文件、环境变量和资源限制。常用观察命令:
ps auxtopss -ltnplsof -p <pid>进程收到 SIGTERM 应优雅退出;SIGKILL 无法被捕获,只能强制结束。容器停止时也遵循类似信号机制,应用要正确处理终止并完成清理。
1.4 systemd 与服务
跳转到“1.4 systemd 与服务”systemd 管理服务启动、依赖、重启和日志。一个服务单元通常声明:
[Unit]Description=Example APIAfter=network.target
[Service]User=appWorkingDirectory=/srv/appExecStart=/srv/app/serverRestart=on-failure
[Install]WantedBy=multi-user.target排查服务时先看:
systemctl status examplejournalctl -u example -n 100 --no-pager退出码、启动参数、工作目录、用户权限和日志通常比“服务没起来”这句话更有用。
2. 容器不是轻量虚拟机
跳转到“2. 容器不是轻量虚拟机”容器共享宿主机内核,通过 namespace 隔离进程、网络、挂载点、主机名和用户,通过 cgroup 限制 CPU、内存和 I/O。它不像虚拟机那样启动完整客户机操作系统,因此更轻,但隔离边界也更依赖内核配置。
2.1 镜像与层
跳转到“2.1 镜像与层”镜像由只读层组成,容器在镜像之上增加可写层。Dockerfile 的每条指令通常形成一层,构建缓存会复用未变化的层。
FROM node:22-alpineWORKDIR /appCOPY package.json pnpm-lock.yaml ./RUN corepack enable && pnpm install --frozen-lockfileCOPY . .RUN pnpm buildUSER nodeEXPOSE 3000CMD ["node", "dist/server.js"]先把依赖文件复制并安装,再复制源码,可以更好利用缓存。生产镜像应尽量:
- 使用明确版本的基础镜像,而不是永远
latest。 - 安装锁文件中的依赖。
- 使用非 root 用户运行。
- 清理构建工具和缓存。
- 只复制运行所需文件。
- 记录镜像 digest,确保部署的产物可追溯。
2.2 容器网络
跳转到“2.2 容器网络”容器内的 localhost 指容器自身,不是宿主机。容器之间通常通过同一网络中的服务名访问。端口映射把宿主机端口转发到容器端口,但“容器没起来”“端口没映射”“应用只监听回环地址”是不同问题。
容器编排中的服务发现通常使用 DNS 名称,例如 db:5432。服务名解析失败时,先检查网络、DNS 和服务是否注册。
2.3 数据与生命周期
跳转到“2.3 数据与生命周期”容器可写层随容器删除而消失。持久数据应放在:
- 数据卷。
- 宿主机绑定目录。
- 对象存储。
- 托管数据库。
不要把数据库文件放在容器临时层,也不要在生产依赖“容器重启后数据还在”。
2.4 Docker Compose
跳转到“2.4 Docker Compose”Compose 适合本地开发和单机多服务编排:
services: api: build: . ports: ["3000:3000"] environment: DATABASE_URL: postgres://app:secret@db:5432/app depends_on: - db db: image: postgres:17 volumes: - pgdata:/var/lib/postgresql/datavolumes: pgdata:depends_on 只保证启动顺序,不保证数据库已经接受连接。应用需要重试连接或健康检查。Compose 不是生产高可用平台,多实例调度、滚动发布和故障转移要交给编排系统或托管服务。
3. Kubernetes 的核心模型
跳转到“3. Kubernetes 的核心模型”Kubernetes 把“运行什么、需要多少副本、怎样访问”声明为对象,由控制平面持续把实际状态调整到期望状态。
3.1 主要对象
跳转到“3.1 主要对象”| 对象 | 作用 |
|---|---|
| Pod | 最小部署单元,包含一个或多个容器 |
| Deployment | 管理无状态副本和滚动更新 |
| Service | 为一组 Pod 提供稳定访问入口 |
| Ingress/Gateway | 把外部 HTTP 路由到服务 |
| ConfigMap | 非敏感配置 |
| Secret | 敏感配置的封装,仍需配合加密与权限 |
| StatefulSet | 有稳定身份和存储需求的实例 |
| Job/CronJob | 一次性或定时任务 |
3.2 控制平面
跳转到“3.2 控制平面”控制平面包括 API Server、调度器、控制器和状态存储。调度器选择节点,控制器比较期望状态与实际状态,etcd 保存集群状态。工作节点运行容器运行时和 kubelet。
集群失去多数控制平面节点时,已有 Pod 可能继续运行,但无法可靠调度和更新。托管 Kubernetes 会替你管理部分控制平面,但工作节点、网络、存储和应用配置仍由你负责。
3.3 调度与资源
跳转到“3.3 调度与资源”resources: requests: cpu: "250m" memory: "256Mi" limits: cpu: "1" memory: "512Mi"requests 用于调度和保障资源,limits 用于限制上限。内存超过 limit 可能被杀,CPU 超过 limit 会被限流。设得太低会频繁重启,太高会浪费容量。需要根据实际指标调整。
3.4 健康检查
跳转到“3.4 健康检查”- liveness:进程卡死时重启。
- readiness:准备好接收流量时加入 Service。
- startup:慢启动应用在初始化阶段避免被误杀。
健康检查只应验证“本实例能否工作”,不要把它做成完整业务链路监控。依赖数据库短暂波动时,把所有实例同时标记不健康会造成更大故障。
3.5 发布
跳转到“3.5 发布”Deployment 默认支持滚动更新。关键参数:
- 最大不可用副本数。
- 最大超额副本数。
- 新版本就绪后多久接收流量。
- 失败后是否自动回滚。
发布前应保证数据库迁移向后兼容,因为新旧 Pod 会短暂并存。
4. CI/CD
跳转到“4. CI/CD”持续集成(CI)在代码变化后自动构建和验证。持续交付/部署(CD)把通过验证的产物送到环境。
4.1 流水线阶段
跳转到“4.1 流水线阶段”拉取代码 → 格式/静态检查 → 单元测试 → 构建产物/镜像 → 扫描依赖与镜像 → 部署测试环境 → 集成/端到端测试 → 生成变更记录 → 人工或自动审批 → 部署生产 → 健康检查/验证每个阶段应输出可定位的结果。只显示“pipeline failed”而不保留日志、测试报告和失败产物,会拖慢排查。
4.2 构建一次,部署同一个产物
跳转到“4.2 构建一次,部署同一个产物”开发、测试、生产应尽量使用同一个构建产物,只改变配置和密钥。若每个环境重新构建,代码、依赖和构建工具差异会让“测试通过”失去意义。
镜像或产物应带版本、提交哈希和构建时间。部署时记录实际 digest,而不是只看可变标签。
4.3 数据库迁移
跳转到“4.3 数据库迁移”部署顺序要明确:
- 先执行向后兼容的 schema 迁移。
- 再部署兼容新旧 schema 的应用。
- 回填或双写。
- 切换读取。
- 最后移除旧字段。
回滚应用不等于回滚数据库。删除列和改变类型要格外谨慎,通常需要多阶段迁移。
4.4 Secrets
跳转到“4.4 Secrets”CI/CD 中的密钥应存放在受控密钥管理系统,按环境和用途隔离。日志中不能打印 token;构建产物不能包含生产密钥;临时凭据应短期有效。
5. 部署策略
跳转到“5. 部署策略”| 策略 | 做法 | 风险 |
|---|---|---|
| 滚动发布 | 逐步替换旧实例 | 新旧版本并存,需兼容 |
| 蓝绿 | 两套环境切换流量 | 资源成本高,数据仍需兼容 |
| 金丝雀 | 先给小比例用户 | 需要流量分流和指标比较 |
| 功能开关 | 代码上线但功能关闭 | 开关累积、状态组合复杂 |
| 影子流量 | 复制请求到新版本但不影响用户 | 写操作和外部副作用要隔离 |
无论哪种,都需要验证指标:错误率、延迟、关键业务成功率和资源使用。发布完成不等于健康,必须观察一段时间。
6. 回滚
跳转到“6. 回滚”可回滚部署要满足:
- 旧镜像/产物仍可用。
- 配置和密钥有版本。
- 数据库变更兼容旧版本。
- 回滚不需要手工改多台机器。
- 回滚后核心指标能验证。
“把新版本删掉再重新部署旧版本”可能太慢。蓝绿切换、流量回切或保留上一版副本能缩短恢复时间。
7. 运行中的常见故障
跳转到“7. 运行中的常见故障”| 现象 | 优先检查 |
|---|---|
| 容器启动即退出 | 启动命令、配置、权限、依赖 |
| 服务重启循环 | 内存 limit、liveness、启动时间 |
| 外部访问 502 | Service、Ingress、容器端口和应用监听 |
| 某实例无流量 | readiness、标签选择器、网络策略 |
| 发布后错误上升 | 新旧版本、数据库迁移、配置差异 |
| 节点磁盘满 | 日志轮转、镜像缓存、卷容量 |
| 延迟突然升高 | 节点资源、依赖、连接池、网络 |
检查清单
跳转到“检查清单”- 应用是否以最小权限用户运行。
- 数据、日志和临时文件是否存储在正确位置。
- 镜像是否锁定版本,是否只包含运行所需内容。
- 容器是否监听正确地址和端口。
- Kubernetes 的 requests/limits、probe 和副本数是否有依据。
- 配置与密钥是否分离,是否支持版本和审计。
- CI 是否包含检查、测试、构建、扫描和产物记录。
- 部署是否构建一次并复用同一产物。
- 数据库迁移是否兼容滚动发布与回滚。
- 是否有灰度、验证指标和明确回滚路径。