AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

systemctl —— systemd 服务管理的总入口

一句话定义

systemctl 是和 systemd 进程管理器对话的命令行工具。Ubuntu 16.04+ / CentOS 7+ / RHEL 7+ 几乎所有发行版都用 systemd 替代了 init(SysV)。systemctl 管的不只是"启动停止服务"——它管理 unit:服务(service)、socket、定时器(timer)、挂载(mount)、target(运行级别)等。

典型场景

  • 启停服务:systemctl start/stop/restart sshd
  • 改完配置重载:systemctl reload nginx
  • 开机自启:systemctl enable kubelet
  • 看状态:systemctl status sshd
  • 排查"哪些服务开着启动?是不是 IDC 塞了 agent?":systemctl list-unit-files --state=enabled
  • 写自定义 unit:/etc/systemd/system/myapp.service + systemctl daemon-reload

核心 8 个动作

按使用频率排序:

动作作用立刻生效?重启后还在?
status <unit>查看状态——
start <unit>启动✅❌
stop <unit>停止✅❌
restart <unit>重启(先停后起)✅❌
reload <unit>重载配置(不重启进程)✅❌
enable <unit>设为开机自启❌✅
disable <unit>取消开机自启❌✅
enable --now <unit>开机自启 + 立即启动✅✅

注意:start 和 enable 是两件事:

  • start 只在这次开机内起服务
  • enable 只在下次开机生效,这次开机内不会启动它
  • 通常你想要的是 systemctl enable --now <unit>(两件事一起做)

status —— 第一个该跑的诊断命令

$ systemctl status sshd
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2026-05-27 10:23:45 UTC; 3h 12min ago
   Main PID: 1234 (sshd)
      Tasks: 1 (limit: 4915)
     Memory: 5.5M
        CPU: 23ms
     CGroup: /system.slice/ssh.service
             └─1234 sshd: /usr/sbin/sshd -D

May 27 13:35:12 m1 sshd[5678]: Accepted publickey for root from 192.168.1.5
May 27 13:35:12 m1 sshd[5678]: pam_unix(sshd:session): session opened

读法(按行):

  1. Loaded: 配置文件路径 + enabled/disabled 状态 + vendor preset
  2. Active: 当前状态 + 多久了。active (running) 是好的;failed / inactive (dead) 要查
  3. Main PID: 主进程 PID
  4. CGroup: 这个服务下属的所有进程(systemd 按 cgroup 分组)
  5. 最近 10 行日志(journalctl 的尾巴)

status 自动带最近日志——这是它最方便的地方,不用单独再 journalctl。

Active 的可能取值

取值含义
active (running)正在跑
active (exited)跑过然后正常退出(典型:oneshot 服务)
active (waiting)等触发(典型:socket、timer)
inactive (dead)没在跑(手动停了 / 没启用)
failed启动失败 / 跑挂了
activating / deactivating启停中间态

restart vs reload 的本质区别

动作行为副作用
restart杀进程 → 重新拉起断所有现有连接 / 状态
reload给进程发 SIGHUP(或 unit 里指定的 reload 命令)不断连接,但只有支持的服务能这么做

不是所有服务都支持 reload。看 unit 里有没有 ExecReload=:

systemctl cat sshd | grep ExecReload
# ExecReload=/usr/sbin/sshd -t
# ExecReload=/bin/kill -HUP $MAINPID

有 → 可以 reload。没有 → 只能 restart。

养成肌肉记忆:

  • nginx / sshd / haproxy → reload(配置改了不断连接)
  • 应用类(你自己写的服务)→ 通常 restart(一般没实现 SIGHUP)
  • 系统配置类(sysctl、netfilter)→ 通常没办法 reload,只能 restart 或 daemon-reload

enable / disable —— 开机自启

systemctl enable kubelet         # 标记为开机自启
systemctl disable kubelet        # 取消
systemctl is-enabled kubelet     # 查看(脚本里常用)
# enabled / disabled / static / masked

enable 实质:在 /etc/systemd/system/<某 target>.wants/<service> 创建一个 symlink,下次启动到该 target 时这个服务被拉起。

--now 一步到位

systemctl enable --now kubelet   # 等价于 enable + start
systemctl disable --now kubelet  # 等价于 disable + stop

强烈推荐 --now —— 否则你 enable 了一个服务、却发现现在没跑,必须再手动 start。

is-enabled 的几种取值

取值含义
enabled标记为开机自启
disabled没标记
static没有 install 段,不能被 enable(其它服务依赖它时被拉起)
masked被屏蔽(见下面)
alias是别名

mask —— 比 disable 更狠

systemctl mask cups              # 完全屏蔽(连依赖触发都拉不起来)
systemctl unmask cups

mask 把 unit 链接到 /dev/null,相当于让 systemd 完全不认识这个服务。区别:

  • disable —— 不会自启,但 systemctl start 还能起、依赖触发也能起
  • mask —— 彻底封禁,任何方式都启不起来

用场景:

  • 不想要的服务被某个依赖反复拉起(典型:apache、cups、avahi)
  • IDC 模板里塞了你不要的 agent

不要随意 mask 系统关键服务,否则系统启动可能进 emergency。


list-units / list-unit-files

systemctl list-units                          # 当前已加载的所有 unit
systemctl list-units --type=service           # 只看 service
systemctl list-units --state=failed           # 看挂掉的
systemctl list-units --type=service --state=running  # 跑着的服务

systemctl list-unit-files                     # 看所有"已安装"的 unit(含没运行的)
systemctl list-unit-files --state=enabled     # 看开机自启的

装机审计常用:

systemctl list-unit-files --state=enabled | grep -iE 'agent|aliyun|aegis|nezha|monitor'

排查 IDC 塞的"agent 类"服务(typhoon agent、阿里云盾、监控蜘蛛等),有则查清楚是什么 → 决定保留 / disable / mask。


看 unit 文件本身

systemctl cat sshd               # 显示完整 unit 配置(含所有 drop-in override)
systemctl show sshd              # 显示所有属性(含 systemd 内部解析后的值)
systemctl show sshd -p ExecStart # 看特定属性

cat 显示文件原文,show 显示 systemd 实际生效的解析后属性。排查"为什么这个服务用了某参数"用 cat。


改 unit 配置:drop-in 而不是改原文件

发行版自带的 unit 文件在 /lib/systemd/system/(或 /usr/lib/systemd/system/)。不要直接改——apt upgrade 会覆盖。

正确做法:drop-in(覆盖片段)。

systemctl edit sshd              # 自动开个空 drop-in 文件让你编辑
# 写入要 override 的部分:
[Service]
Environment="SSHD_OPTS=-d"

这会在 /etc/systemd/system/ssh.service.d/override.conf 创建一个片段。systemd 把原文件 + 这个片段合并使用,apt 升级不会动它。

完成后:

systemctl daemon-reload          # 必须做:让 systemd 重读 unit 文件
systemctl restart sshd

daemon-reload 时机

任何时候改了 unit 文件 / drop-in / 新增自定义 unit → 必须 systemctl daemon-reload。否则 systemd 用的还是旧配置。

Warning: The unit file, source configuration file or drop-ins of sshd.service changed on disk.
Run 'systemctl daemon-reload' to reload units.

看到这个 warning 就 daemon-reload 一下。


写一个最小自定义服务

cat > /etc/systemd/system/myapp.service <<'EOF'
[Unit]
Description=My App
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --config /etc/myapp.conf
Restart=on-failure
RestartSec=5s
User=myapp

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now myapp
systemctl status myapp

三个段:

  • [Unit] —— 元信息、依赖关系(After、Requires、Wants)
  • [Service] —— 进程行为(ExecStart、Type、Restart、User)
  • [Install] —— enable 时挂哪个 target(通常 multi-user.target)

Type=simple 是最常用的(ExecStart 不 daemonize、systemd 直接 fork 跑)。其它常见:

  • Type=forking —— ExecStart 会自己 daemonize(老式 daemon)
  • Type=oneshot —— 跑完就退(一次性脚本)
  • Type=notify —— 进程会主动通知 systemd ready(高级用法)

target —— 系统的"运行级别"

systemd 的 target 类似 SysV 的 runlevel:

target含义旧 runlevel
poweroff.target关机0
rescue.target单用户1
multi-user.target多用户文字模式(服务器默认)3
graphical.target图形界面5
reboot.target重启6
systemctl get-default            # 看当前默认 target
systemctl set-default multi-user.target   # 改默认(服务器不要图形)
systemctl isolate rescue.target  # 立即切到 rescue(小心)

常见踩坑

坑 1:start 之后没 enable,重启后服务没了

systemctl start kubelet          # 这次开机内跑着
reboot                            # 重启
systemctl status kubelet          # inactive (dead)

start 只管这次开机。重启后要靠 enable 的 symlink 来拉起。永远用 enable --now。

坑 2:改了 unit 文件但不 daemon-reload

systemd 把 unit 文件解析后缓存在内存。改文件后必须 systemctl daemon-reload。不做的话:

vim /etc/systemd/system/myapp.service    # 改了
systemctl restart myapp                  # 重启了
systemctl show myapp -p ExecStart        # ExecStart 还是旧值!

坑 3:改了 /lib/systemd/system/... 被 apt 覆盖

vim /lib/systemd/system/ssh.service      # ❌ 不要改这里

正确:systemctl edit ssh 用 drop-in。

坑 4:status 显示 failed,不知道为啥

systemctl status myapp
# Active: failed (Result: exit-code)

直接跟 journalctl(详见 journalctl.md):

journalctl -u myapp -n 100 --no-pager
journalctl -u myapp --since "10 min ago"

或者用 --full 看完整错误:

systemctl status myapp -l        # -l 不截断长行

坑 5:服务自动 restart 把日志刷爆

[Service]
Restart=always                   # 任何退出都重启
RestartSec=1s                    # 1 秒间隔

挂了 → 1 秒后重启 → 又挂 → 又重启 ... 日志爆炸。

防御:

Restart=on-failure               # 只有失败才重启(exit 0 不重启)
RestartSec=10s                   # 间隔大点
StartLimitInterval=60s           # 60 秒内
StartLimitBurst=3                # 最多 3 次,再失败就不重启了

坑 6:reload 当 restart 用,对不支持 reload 的服务无效果

systemctl reload myapp           # 静默"成功",但啥都没做

如果 unit 里没定义 ExecReload,systemctl reload 通常报错 / 没动作。改用 restart,或在 unit 里加 ExecReload=/bin/kill -HUP $MAINPID(如果你的应用响应 HUP)。

坑 7:用 kill 干进程,被 systemd 自动拉起

kill 1234                        # 杀了 myapp
ps aux | grep myapp              # 还在跑(PID 变了)

Restart= 让 systemd 监控进程退出并重启。要真停:systemctl stop myapp。


关联命令

  • journalctl —— 看日志(status 给你尾巴,journalctl 给你全部)
  • systemd-cgls / systemd-cgtop —— cgroup 视角看服务资源占用
  • loginctl —— 登录会话管理
  • hostnamectl —— hostname 设置
  • timedatectl —— 时区 / NTP 设置
在 GitHub 上编辑此页