Appearance
系统初始化基线
新服务器投入使用前,基础状态得先统一——主机身份、名称解析、时间同步、软件源、基础工具、登录方式、防火墙策略、系统参数、资源限制,这些都得过一遍。基线配置不等于完整安全加固,它更接近机器交付前的"最低可用状态"。后续排查日志时间对不上、证书校验失败、Kubernetes 节点异常、数据库复制延迟、监控采集报错的时候,根因经常落在这些基础项上——所以基线没做好,后面会一直还债。
一、基线项清单
系统初始化可以按下面几类整理。不同公司会把安全审计、账号管理、监控 Agent 也纳入基线,这里记录的是操作系统层面最常见的一组:
| 分类 | 配置项 | 干什么用 |
|---|---|---|
| 主机身份 | hostname、/etc/hosts | 批量管理、日志识别、集群节点互相解析 |
| 网络解析 | DNS、NSS 顺序 | 软件安装、域名访问、内网服务解析 |
| 时间同步 | 时区、chrony、硬件时钟 | 日志排序、证书校验、集群一致性 |
| 软件环境 | 软件源、EPEL、基础工具 | 后续安装和排障命令能用 |
| 登录访问 | SSH、sudo、密钥 | 远程管理入口 |
| 网络策略 | firewalld / iptables | 控制端口暴露范围 |
| 系统参数 | sysctl、limits、systemd limit | 网络连接、文件句柄、进程资源 |
| 存储基础 | swap、fstab、挂载检查 | 避免重启后挂载丢失或启动失败 |
| 日志审计 | journald、rsyslog、logrotate | 保留操作和故障现场 |
二、主机名和本机解析
主机名是机器身份的一部分。批量执行命令、监控告警、日志检索的时候,如果所有机器都叫 localhost,根本判断不了告警来自哪台服务器——这种痛,运维过的人都懂。
bash
hostnamectl status
hostnamectl set-hostname k3s-server-01
hostnamectl statushostnamectl set-hostname 会写入系统的静态主机名,重启后保留。虚拟机模板批量克隆的时候,主机名尤其容易重复,初始化阶段一定要改掉,不然一套环境里冒出三个 localhost,排查时全是糊涂账。
本机名解析通常写在 /etc/hosts。小规模实验环境没有内部 DNS 时,/etc/hosts 很常用;生产环境如果有统一 DNS,/etc/hosts 只保留必要的本机解析和临时兜底记录:
bash
cat >> /etc/hosts <<'EOF'
# 集群节点解析;小规模环境可直接用 hosts 管理
192.168.10.11 k3s-server-01
192.168.10.12 k3s-server-02
192.168.10.13 k3s-server-03
EOF
getent hosts k3s-server-01getent hosts 会按系统的名称解析顺序查询,结果比单独 cat /etc/hosts 更接近应用实际看到的解析结果。解析顺序由 /etc/nsswitch.conf 控制:
bash
grep '^hosts:' /etc/nsswitch.conf常见输出:
text
hosts: files dnsfiles dns 表示先查 /etc/hosts,再查 DNS。排查"能 ping 通 IP,但服务名解析失败"的时候,这一项经常要看——顺序错了或者 hosts 里没配,都会导致解析异常。
三、DNS 和软件源
DNS 配置影响一大片——软件安装、镜像拉取、证书申请、访问外部 API,全依赖 DNS。不同发行版和网络管理工具写法不一样,systemd-resolved、NetworkManager、传统网卡配置文件都可能接管 DNS。
基础检查从解析文件和实际结果开始:
bash
cat /etc/resolv.conf
getent hosts mirrors.aliyun.com
curl -I https://mirrors.aliyun.com/ 2>/dev/null | head/etc/resolv.conf 里能看到当前 nameserver,但它不一定是最终配置源。有些系统里这个文件是软链接,由 NetworkManager 或 systemd-resolved 生成——你直接编辑,会被上层服务重新生成时覆盖。这也是为什么"改了 DNS 重启又变回去"的常见原因。
RHEL 系装基础工具:
bash
yum install -y epel-release
yum install -y vim curl wget tar unzip lsof net-tools bind-utils bash-completionUbuntu / Debian:
bash
apt update
apt install -y vim curl wget tar unzip lsof net-tools dnsutils bash-completionbind-utils/dnsutils 提供 dig、nslookup 这些命令。网络排障时这些工具太基础了,初始化阶段装好,现场排查就少一层阻塞——不然真出问题的时候,想 dig 一下发现命令没有,还得先装,黄花菜都凉了。
四、时区和时间同步
系统时间是很多问题的共同前提。日志时间错乱、TLS 证书还没生效或已过期、定时任务提前执行、Kubernetes 节点证书校验异常、数据库主从复制延迟判断不准——这些都可能跟时间有关。
时区设置:
bash
timedatectl status
timedatectl set-timezone Asia/Shanghai
timedatectl statustimedatectl status 里重点看 Time zone、System clock synchronized、NTP service。时区只是显示规则,真正决定各节点时间是否一致的是 NTP 同步——时区对了但时间没同步,照样一堆问题。
chrony 是现在 Linux 服务器最常用的时间同步服务。RHEL 系服务名一般是 chronyd,Debian/Ubuntu 上包名是 chrony,服务名也常见 chrony。
RHEL 系:
bash
yum install -y chrony
# enable 保证开机自启,--now 立即启动
systemctl enable --now chronyd
systemctl is-enabled chronyd
systemctl is-active chronydUbuntu / Debian:
bash
apt update
apt install -y chrony
# Ubuntu/Debian 上服务名常见是 chrony
systemctl enable --now chrony
systemctl is-enabled chrony
systemctl is-active chronychrony 配置文件在 /etc/chrony.conf 或 /etc/chrony/chrony.conf。时间源按内网优先,内网没有 NTP 再用公网源:
conf
# 内网 NTP;生产环境通常用公司统一时间源
server 192.168.10.1 iburst
# 公网 NTP;实验环境按网络情况选择
server ntp.aliyun.com iburst
server time1.cloud.tencent.com iburst
# 启动初期时间偏差超过 1 秒时允许直接校正,后续通过微调修正
makestep 1.0 3
# 同步系统时间到硬件时钟,减少重启后的初始偏差
rtcsync几个参数解释一下:iburst 在服务启动初期快速发几次请求,让首次同步更快;makestep 1.0 3 表示启动后前 3 次同步里,如果时间偏差超过 1 秒,允许直接跳变校正——服务稳定后 chrony 倾向于微调慢慢修正,避免运行中的系统时间频繁跳变影响业务。
改完配置重启并检查:
bash
systemctl restart chronyd
timedatectl status --no-pager
chronyc sources -v
chronyc trackingchronyc sources -v 输出里的符号要看懂:
| 符号 | 含义 |
|---|---|
^* | 当前正在使用的时间源 |
^+ | 可用候选时间源 |
^- | 可用但未被选中 |
^? | 暂时无法访问或状态未知 |
全是 ^? 说明一个 NTP 源都没连上,时间还在裸奔——这种状态下日志时间不可信,集群组件也可能因为时钟偏差告警。
测试环境如果频繁恢复虚拟机快照,系统时间可能跟真实时间差很多,恢复后用 timedatectl 和 chronyc tracking 复查一遍同步状态;生产基线按固定 NTP 源 + 开机自启 + 启动初期校正来处理。
五、SSH 和 sudo 基础
SSH 是远程运维入口,完整安全加固在 系统安全加固 里展开。初始化阶段至少要确认服务状态、登录方式、sudo 权限:
bash
systemctl status sshd --no-pager
ss -lntp | grep ':22'
grep -E '^(PermitRootLogin|PasswordAuthentication|PubkeyAuthentication)' /etc/ssh/sshd_config生产环境通常会逐步收敛到"普通用户 + sudo + 密钥登录"。实验环境可能临时用 root 密码,后续接入堡垒机或自动化工具时,再统一管账号、密钥和审计。
创建普通运维用户:
bash
useradd ops
passwd ops
# wheel 组在 RHEL 系通常有 sudo 权限
usermod -aG wheel ops
id opsUbuntu/Debian 上 sudo 组是 sudo:
bash
usermod -aG sudo ops
id ops改完 SSH 配置,用服务自带的语法检查:
bash
sshd -t
systemctl reload sshdreload 重新加载配置,不断开已有连接。改 SSH 登录策略的时候,保留一个当前会话,另开一个新会话验证登录——比直接断开重连稳妥,改错了旧会话还能救。
六、防火墙和 SELinux 状态
防火墙基线不是简单开或关,而是确认当前由谁管理规则,以及哪些端口该暴露。
bash
systemctl is-active firewalld || true
firewall-cmd --state 2>/dev/null || true
iptables -S 2>/dev/null | head
ss -lntupRHEL 系常见 firewalld,底层可能用 iptables 或 nftables。系统里同时出现 firewalld、iptables 脚本、云安全组的时候,排查端口不通要把这几层都列出来——任何一层拦了都不通,不知道是哪层拦的最难排查。
开放服务端口示例:
bash
# 添加 HTTP 端口到 public zone,写入永久配置
firewall-cmd --permanent --zone=public --add-service=http
# 重新加载永久规则
firewall-cmd --reload
# 查看当前 zone 的生效规则
firewall-cmd --list-allSELinux 是强制访问控制,它和传统文件权限是两套系统——文件权限允许,不代表 SELinux 一定允许。Web 服务访问新目录、数据库写新路径、容器挂载宿主机目录,经常碰 SELinux 上下文问题。
bash
getenforce 2>/dev/null || true
sestatus 2>/dev/null || true三种状态:Enforcing 策略生效并拦截违规、Permissive 只记录不拦截(排查用)、Disabled 关闭。
排查访问被拒绝时:
bash
ausearch -m avc -ts recent 2>/dev/null | tail -n 20
ls -Z /var/www/html 2>/dev/null || true初始化时记录 SELinux 状态,比出故障后临时猜测可靠得多。是关闭、宽松还是保持强制,通常由业务软件兼容性和团队安全要求决定——别一刀切地全关。
七、swap、fstab 和挂载检查
swap 是磁盘上的交换空间,内存不够时内核把不活跃内存页换到 swap。它不能替代真实内存,性能远低于内存,但能降低小内存机器因为瞬时内存压力直接 OOM 的概率。
查看当前 swap:
bash
swapon --show
free -h创建 2G swap 文件:
bash
fallocate -l 2G /swapfile
chmod 600 /swapfile # swap 文件不能给其他用户读写
mkswap /swapfile
swapon /swapfile
swapon --show持久化到 /etc/fstab:
bash
cp -a /etc/fstab "/etc/fstab.$(date +%F-%H%M%S).bak"
echo '/swapfile none swap sw 0 0' >> /etc/fstab
mount -a # 检查 fstab 语法和可挂载性/etc/fstab 写错可能导致系统启动卡住——所以改完一定执行 mount -a,能在当前会话里提前暴露多数格式或路径错误,别等重启才发现。
Kubernetes 节点通常会关掉 swap(K8s 默认要求),普通 Linux 主机是否启用看业务类型和内存规模。数据库服务器更关注稳定延迟,swap 策略会比普通 Web 服务器谨慎——频繁 swap 会让数据库性能断崖式下跌。
八、sysctl 和内核模块
sysctl 用来调整内核运行参数——网络转发、连接跟踪、TCP 队列、文件句柄都可能在这配。初始化阶段不要盲目套一堆"万能优化参数",更适合按实际用途记录必需项,那些抄来的优化参数很多时候对你这个场景根本没用,反而引入问题。
查看当前参数:
bash
sysctl net.ipv4.ip_forward
sysctl fs.file-max
sysctl vm.swappiness写入持久配置:
bash
cat >/etc/sysctl.d/99-base.conf <<'EOF'
# 开启 IPv4 转发;LVS、容器网络、路由转发场景会用到
net.ipv4.ip_forward = 1
# 降低系统主动使用 swap 的倾向;内存长期吃紧不能只靠这个值解决
vm.swappiness = 10
EOF
sysctl --system/etc/sysctl.d/*.conf 比直接改 /etc/sysctl.conf 方便分组管理——基础参数放 99-base.conf,Kubernetes 节点参数放 99-kubernetes.conf,互不干扰。
加载内核模块:
bash
modprobe br_netfilter
modprobe overlay
cat >/etc/modules-load.d/container.conf <<'EOF'
# 容器网络常用模块
br_netfilter
overlay
EOF
lsmod | grep -E 'br_netfilter|overlay'容器和 Kubernetes 环境经常用到 br_netfilter 和 overlay。模块没加载,网络转发和容器存储相关功能会表现异常——这种问题排查起来特别绕,因为报错往往指向别的地方,不会直接告诉你"缺内核模块"。
九、limits 和 systemd 限制
ulimit 控制单个进程能用的资源,比如最大打开文件数、最大进程数。高并发服务、数据库、代理服务经常会碰到 too many open files,就是文件句柄上限不够。
查看当前限制:
bash
ulimit -n
ulimit -u通过 /etc/security/limits.d/ 配置登录会话限制:
conf
# /etc/security/limits.d/99-ops.conf
# nofile 是最大打开文件数,nproc 是最大进程数
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535这个配置主要影响 PAM 登录会话,systemd 管理的服务还得看 unit 自己的限制:
bash
systemctl show nginx -p LimitNOFILE
systemctl cat nginx给某个服务单独设文件句柄:
bash
systemctl edit nginx写入 override:
ini
[Service]
# Nginx worker 打开大量连接时需要更高的文件句柄上限
LimitNOFILE=65535重新加载并重启:
bash
systemctl daemon-reload
systemctl restart nginx
systemctl show nginx -p LimitNOFILE排查 too many open files 时,只改 /etc/security/limits.conf 可能对 systemd 服务完全无效——这是经典踩坑点。比如 systemctl show nginx -p LimitNOFILE 还是 1024,cat /proc/<pid>/limits 里 Max open files 也是 1024,基本能确定这个服务没吃到 limits.conf 的配置,得改 systemd unit 或 drop-in 才行。
十、日志和轮转
初始化阶段至少确认系统日志服务和日志轮转可用:
bash
systemctl is-active rsyslog || true
systemctl is-active systemd-journald || true
journalctl -n 20 --no-pager
logrotate --versionjournald 管 systemd 日志,rsyslog 常用于把系统日志写到 /var/log/messages 或 /var/log/syslog,不同发行版默认组合不同。
查看 journald 磁盘占用:
bash
journalctl --disk-usage限制 journald 空间,写入 /etc/systemd/journald.conf:
ini
[Journal]
# 限制 journald 最多用 1G 磁盘
SystemMaxUse=1G
# 单个日志文件最大 100M,便于轮转和清理
SystemMaxFileSize=100M改完重启:
bash
systemctl restart systemd-journald
journalctl --disk-usage应用日志通常还需要 logrotate。没有轮转的访问日志、错误日志、任务日志,很容易把 /var 撑满——磁盘满了服务直接挂,这种事故见得太多了。
十一、基线检查脚本片段
初始化完成之后,可以跑一段只读检查,确认关键项是否生效:
bash
#!/usr/bin/env bash
set -euo pipefail
echo "== system =="
cat /etc/os-release | grep -E '^(NAME|VERSION)='
uname -r
hostnamectl --static
echo
echo "== time =="
timedatectl status --no-pager | grep -E 'Time zone|System clock synchronized|NTP service'
chronyc tracking 2>/dev/null | grep -E 'Reference ID|Leap status' || true
echo
echo "== network =="
ip -brief addr
ip route | head -n 5
getent hosts "$(hostname)" || true
echo
echo "== storage =="
df -h
swapon --show || true
echo
echo "== security =="
ss -lntup
getenforce 2>/dev/null || true
systemctl is-active firewalld 2>/dev/null || true
echo
echo "== limits =="
ulimit -n
sysctl net.ipv4.ip_forward vm.swappiness 2>/dev/null || true这段脚本只读取信息,不修改系统,交接机器、批量扩容节点、变更后复查的时候,都可以用它确认基线还在不在。更完整的初始化脚本可以参考 服务器初始化脚本。