本章核心:环境准备不是“有手就行”。 我见过太多团队在环境这一步翻车——缺一个依赖、版本不对、端口被占用,最后排查两小时白费。这篇内容,就是让你在动手部署前,把“坑”先填上。

环境准备与依赖检查

做部署验证这些年,我踩过最深的一个坑是什么?
——不是配置写错了,而是环境没准备好。你想想看,辛辛苦苦写好的部署脚本,跑起来报个“command not found”,或者“port already in use”,是不是特别让人崩溃?

说白了,环境准备就是部署的“地基”。地基不稳,上层建筑再漂亮也没用。我个人习惯,在每次部署之前,都会先花15分钟把环境从头到尾捋一遍。这叫“磨刀不误砍柴工”。

2.1 操作系统与内核参数核对

不同发行版、不同内核版本,行为差异很大。我建议你先把这几项确认死:

  • 操作系统版本:CentOS 7 和 Ubuntu 20.04 的包管理器、默认防火墙规则完全不同。
  • 内核版本:至少 3.10 以上(CentOS 7 默认就是这个),如果需要跑容器或高并发,建议 4.18+。
  • 文件描述符限制:ulimit -n 默认 1024,对生产服务器来说太低了。我一般会改成 65535 或更高。
  • 时间同步:NTP 或 chronyd 必须成功运行。证书校验、日志审计都依赖准确的时间。

我个人习惯:写一个 env_check.sh 脚本,把这些检查项做成自动化。每到一个新环境,先跑一遍,心里就踏实了。


#!/bin/bash
# 简化版环境预检脚本
echo "=== 操作系统 ==="
cat /etc/os-release | head -2
echo "=== 内核版本 ==="
uname -r
echo "=== 文件描述符限制 ==="
ulimit -n
echo "=== 时间同步状态 ==="
timedatectl status | grep "NTP synchronized"

我曾经遇到过一次:客户的环境是 CentOS 6,内核 2.6.32。部署容器时发现 Docker 根本跑不起来。后来查了才知道,Docker 要求内核至少 3.10。所以,版本核对真的不能偷懒。

2.2 网络连通性与端口检查

部署过程中,很多问题都出在网络层。
你可能会问:不就是 ping 通就行吗?
嗯,这里要注意:ping 通只代表 ICMP 通,不代表应用层通。

我建议按下面这个顺序检查:

  1. 基础连通性:用 ping 确认目标 IP 可达。
  2. 端口可达性:用 telnet 或 nc -zv 测试指定端口。
  3. DNS 解析:nslookup 确认域名能正确解析。
  4. 路由与防火墙:traceroute 看路径,iptables -L -n 看规则是否放行了必要端口。
检查项 命令示例 预期结果
端口监听 ss -tlnp 看到服务已监听在 0.0.0.0:8080
端口可达 nc -zv 10.0.0.1 8080 返回 "succeeded"
DNS 解析 nslookup api.example.com 返回正确 IP
防火墙规则 iptables -L INPUT -n --line-numbers 没有误拦

实战技巧:如果 nc 不通,别忘了检查 selinux 和 firewalld。getenforce 返回 Enforcing 时,很多端口会被默认拒绝。

2.3 依赖库与组件版本核对

依赖管理,是让我又爱又恨的一环。爱的是包管理工具让安装变简单,恨的是版本冲突一旦出现,排查起来特别麻烦。

常见的依赖检查清单:

  • 编程语言运行时:Java、Python、Node、Go 等,版本必须精确匹配。Java 8 和 Java 11 的某些 API 都不兼容。
  • 系统库:比如 openssl、libcurl、zlib。用 ldd 检查二进制文件的依赖。
  • 容器基础镜像:如果使用 Docker,确认基础镜像的 OS 版本和打包的库版本是否一致。
  • 数据库驱动:比如 Java 应用需要特定版本的 MySQL Connector。

避坑指南: 我习惯把依赖写成 requirements.txt(Python)或 package.json(Node),并且锁死主版本号。千万别用 latest——生产环境里最怕“意外升级”。


# requirements.txt 示例(Python)
flask==2.2.3
gunicorn==20.1.0
requests==2.28.1
# 不要写成 flask>=2.2.0,不指定主版本号就是给自己埋雷

2.4 容器 Runtime 与编排工具校验

现代部署基本离不开容器。但容器环境本身也需要验证:

  1. Docker/containerd 是否运行:systemctl status docker,docker info。
  2. 镜像拉取权限:docker pull 测试私有仓库是否可以认证。
  3. 容器网络:docker network ls 确认 overlay 网络正常。
  4. 资源限制:cgroup 版本、swap 是否禁用、CPU/memory 限制是否生效。
  5. Kubernetes 集群:kubectl get nodes 所有节点 Ready,kubectl cluster-info 正常。
组件 检查命令 关键输出
Docker Engine docker version Server 版本 ≥ 20.10
Kubernetes kubectl version Server version 与 Client version 差异 ≤ 1 个小版本
镜像仓库 docker login xxx.com Login Succeeded

我曾经遇到过最头疼的一个问题:有个项目同时用到 Docker 和 Containerd,但两个 runtime 的配置里都用了同一个端口映射,导致容器启动失败。排查了好久才发现。所以,不同容器 runtime 之间的端口和资源冲突,一定要在部署前检查清楚。

2.5 云平台配置一致性

如果你在云上部署,环境准备的维度就更多了。我个人习惯做一张“配置核对表”:

  • 安全组/ACL:出入站规则是否放行了应用端口?有没有误屏蔽了健康检查 IP?
  • 负载均衡:健康检查路径、间隔、超时时间是否与应用一致?
  • IAM 权限:应用使用的服务账号是否有权限访问对象存储、数据库?
  • 环境变量:.env 或配置中心的变量值是否与目标环境匹配(开发/测试/生产)?

一个真实的教训: 有一次我们部署一个 Java 应用,在测试环境一切正常,但上了生产就报 403。最后发现是生产环境的 IAM 策略里,没有允许该服务读取 S3 的 Action。从那以后,我每次部署前都会让人工走一遍“最小权限原则”检查。

2.6 环境预检的整体流程

说了这么多,我们来把整个流程串一下。我个人习惯按照“从下到上”的原则检查:
先底层(OS、网络),再中间层(部署工具、运行时),最后应用层(配置、依赖)。

下面这张图,是我自己项目里一直在用的依赖检查总览:

环境预检与依赖检查总览 环境基础层 OS/内核版本核对 内核参数优化 时间同步检查 网络与端口层 端口可达性 防火墙/DNS/路由 安全组/ACL 应用依赖层 运行时/库版本 容器Runtime/K8S 配置/密钥/IAM 顺序:从下到上检查,每一层的错误都会导致部署失败

图里这个顺序是按照依赖关系画的:
环境基础层 错了,后面网络和依赖都没意义;
网络与端口层 不通,应用根本连不上;
应用依赖层 有问题,服务就跑不起来或者运行不稳定。

我的一个习惯: 每次做环境预检,我都会把发现的问题记在一个小本本上(其实是个 Markdown 文件)。比如“某环境的 openssl 版本太旧”、“某台机器缺 libffi”。时间长了,就能总结出一套“常见环境问题模式”,直接写到自动化脚本里,一劳永逸。

好了,环境准备部分就是这些。
记住一句话:花15分钟做预检,能省下2小时的排查时间。 这笔账,怎么算都划算。