TT Lab
开始
学习 学习路径 课程

LFCS — Linux 基金会认证系统管理员

enable 与 start 是两个问题 — systemd、nginx、iptables、bond、chrony、podman

在 TT Lab 中继续学习

一句话总结

Linux 管理有一半的工作,是把“现在能用吗”和“下次也能用吗”分开来问。systemctl start 与 enable、sysctl -w 与 /etc/sysctl.d、iptables -A 与 iptables-save、ip link 与 netplan——每一对中,前者管现在,后者管下次启动。LFCS 两者都要求,本模块的实验也两者都评分。

为什么需要它

前面的模块(lfcs-operating-systems、lfcs-networking)在 Pod 中运行,只能做到编写单元文件并用 systemd-analyze verify 验证。定时器是否真的在运行、nginx 是否真的把请求转给后端、iptables 规则是否真的丢弃数据包,这些都看不到。本模块在 Ubuntu 24.04 VM 中以 root 运行。评分器会用 systemctl is-active、curl、iptables -S、/sys/class/net、sysctl -n、podman inspect 查看系统当前的状态。

有一条边界需要注意。VM 对外只开放了 DNS 和公网的 80/443,UDP 123 是被屏蔽的。因此 chrony 即使知道服务器也无法同步,这一步按配置、服务状态和输出文件评分。另外,评分代理通过 8899/tcp 进入,所以一旦把 iptables 的 INPUT 默认策略改成 DROP,或者封掉 8899、22,评分从那一刻起就无法到达 VM。

工作原理

定时器是调用服务的单元。 按 systemd.timer(5) 的说明,省略 Unit= 时,.timer 单元会激活同名的 .service。OnBootSec= 指定开机后第一次是什么时候,OnUnitActiveSec= 指定该服务上一次被激活之后每隔多久再次执行。被调用的一方必须是 systemd.service(5) 中的 Type=oneshot,才会被视为“运行一次就结束的任务”。此外,enable 是根据 [Install] 节中的 WantedBy=timers.target 创建符号链接,start 则是立即启动。--now 会一次完成这两件事。is-enabled 与 is-active 可能给出不同的答案,这就是这一步的全部要点。

反向代理在前端接收请求,再转发给后端。 ngx_http_proxy_module 的 proxy_pass 就是那关键的一行。Ubuntu 软件包把配置放在 sites-available 中,再通过 sites-enabled 里的符号链接来启用。默认站点也通过 default_server 占用了 80 端口,所以不删除它的话,nginx -t 会拒绝重复的配置。后端用 python3 -m http.server 就足够了,但如果手动用 & 启动,会话断开时它也会随之退出。应把它做成单元,由 systemd 来接管。

Netfilter 由表和链构成。 iptables(8) 的 nat 表负责修改地址,filter 表负责决定放行或拦截。PREROUTING 是数据包刚进来时(路由之前),INPUT 是发往本机的数据包,OUTPUT 是本机产生的数据包。因此,发给自己的数据包不会经过 PREROUTING——用 curl localhost:8080 是看不到 DNAT 效果的。iptables-extensions(8) 中的 DNAT 用 --to-destination 修改目标地址,REDIRECT 是它的特殊形式。DROP 不作任何响应就直接丢弃,所以客户端看到的不是拒绝,而是超时。规则重启后会消失,iptables-save 的输出是下次启动时恢复规则的素材。还要知道,Ubuntu 24.04 的 iptables 运行在 nf_tables 后端之上。

桥接与 bond。 桥接是软件交换机,bond 把多条链路合并为一条。用 ip-link(8) 创建 type dummy|bridge|bond,再用 master 加入成员。内核 bonding 文档中的 active-backup 是只使用一条链路、它故障后再切换到另一条的模式,所以不需要交换机配置,而且从属接口在加入之前必须处于 down 状态。在只有一块真实 NIC 的 VM 中,成员用 dummy 接口来创建——在内核看来,它就是真正的接口。以声明式方式描述同样配置的,是 netplan YAML 的 bridges 和 bonds 节,本实验把它放在 /etc/netplan 之外,不予应用。因为一旦失去真实的 NIC,就没有退路了。

时刻与时区是两回事。 内核时钟始终是 UTC,时区只是显示规则。timedatectl 的 set-timezone 修改后者,chrony.conf 的 server … iburst 校准前者。iburst 是在启动之后立即连续发送数据包,以加快首次同步的选项。chronyc 的 sources 第一列若为 ?,说明还没有收到响应,在这台 VM 上这是正常的。

容器镜像就是 tar。 podman-import(1) 会把一个 tarball 变成只有一层的镜像。亲手验证一下——不需要 Dockerfile,也不需要注册表,仅凭一个 /bin/busybox 就能变成镜像,这样就能明白镜像究竟是什么。本实验中的 podman 以 root 运行,并通过 podman-run(1) 的 --network none 在不配置网络的情况下运行。

sysctl 要做两次。 sysctl(8) 的 -w 会立即修改当前内核,而 sysctl.d(5) 的文件在启动时读取。sysctl --system 会按顺序应用标准目录,所以写完文件后运行它,现在和下次启动就会同时生效。平均负载正如 proc_loadavg(5) 所说,是正在运行或等待运行(以及等待磁盘 I/O)的任务数的平均值,必须与 CPU 数量对比才有意义。

在现场相遇的样子

“放进 cron 了却不运行”的 systemd 版本,就是“只对定时器执行了 start”。重启后如果 systemctl list-timers 中没有它,首先查看 is-enabled。反过来,如果只执行了 enable 而没有执行 start,到下次启动之前什么都不会运行。

“加了防火墙规则,重启后却消失了”是 iptables 的经典问题。规则在内核内存中,而在启动时恢复已保存文件的,是另外的服务(Ubuntu 是 iptables-persistent 的 rules.v4)的职责。这就是实验最后要把 iptables-save 保存成文件的原因。

收到“节点很慢”的反馈时,用 uptime 中的平均负载除以 nproc。4 核上的 4.0 表示已满载,1 核上的 4.0 表示有三个任务在排队。top 中的 wa 偏大说明是磁盘问题,st 偏大则说明是 hypervisor 上的邻居占用了 CPU。

下一项实验要做什么

oneshot 服务 + 1 分钟定时器(enable、start、日志)→ python 后端单元 + nginx 代理(停用默认站点)→ DNAT 8080→80 与 9999 DROP(8899、22 保持不变)+ iptables-save → dummy 之上的 br0、bond0 与 netplan 文档 → chrony 服务器、时区、输出文件 → git init、branch、--no-ff 合并 → 用 podman import 导入 busybox tar 并运行 → sysctl 文件 + --system → uptime、top、NPROC。每一步都要同时兼顾“现在”和“下次启动”,评分器两者都会检查。