
systemctl 让你用一行配置替代 200 行 shell 脚本
在 CentOS 6 及之前的版本中,服务管理依赖 SysV init 系统,每个服务都需要编写一个 200 多行的 shell 脚本,手动实现 start、stop、restart、status 等逻辑。这不仅繁琐,而且脚本质量参差不齐。
CentOS 7 引入的 systemd 彻底改变了这一局面。它通过结构化的 .service 文件管理服务,配置清晰、功能强大、自动处理依赖关系。这一篇我们系统介绍 systemctl 的常用操作和 .service 文件的编写方法。
一、service vs systemctl
| | |
|---|
| /etc/init.d/ | /usr/lib/systemd/system/ |
| | |
| | |
| service | systemctl |
| | .target |
运行级别映射:
| |
|---|
| poweroff.target |
| rescue.target |
| multi-user.target |
| graphical.target |
| reboot.target |
二、systemctl 常用操作
2.1 服务控制
systemctl start sshd # 启动服务systemctl stop sshd # 停止服务systemctl restart sshd # 重启服务(完全重启)systemctl reload sshd # 重载配置(不中断服务)systemctl status sshd # 查看详细状态
restart vs reload:
- •
restart:完全停止再启动,会中断连接,适合重大变更 - •
reload:向进程发送 SIGHUP 信号,进程重新加载配置,不中断服务,适合配置文件修改
2.2 开机自启管理
systemctl enable sshd # 启用开机自启systemctl disable sshd # 禁用开机自启systemctl is-enabled sshd # 查看是否启用自启
2.3 状态查看
systemctl status sshd # 详细状态(含最近日志)systemctl is-active sshd # 仅返回 active/inactivesystemctl list-unit-files # 查看所有服务及自启状态systemctl list-dependencies # 查看服务依赖关系
status 输出解读:
● sshd.service - OpenBSD Secure Shell server Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled) Active: active (running) since Tue 2025-07-01 10:00:00 CST Main PID: 1234 (sshd) CGroup: /system.slice/sshd.service └─1234 /usr/sbin/sshd -D
- •
Loaded:是否加载,enabled/disabled 表示开机自启状态 - •
Active:运行状态(active/inactive/failed)
2.4 运行级别管理
systemctl get-default # 查看当前默认运行级别systemctl set-default multi-user.target # 设置为字符界面(重启生效)
三、服务配置 service 文件
我们以 sshd.service 为例,解剖一个典型的服务单元文件。
[Unit]Description=OpenBSD Secure Shell serverDocumentation=man:sshd(8) man:sshd_config(5)After=network.target auditd.serviceConditionPathExists=!/etc/ssh/sshd_not_to_be_run[Service]EnvironmentFile=-/etc/default/sshExecStartPre=/usr/sbin/sshd -tExecStart=/usr/sbin/sshd $SSHD_OPTSExecReload=/bin/kill -HUP $MAINPIDKillMode=processRestart=on-failureRestartPreventExitStatus=255Type=notifyRuntimeDirectory=sshdRuntimeDirectoryMode=0755[Install]WantedBy=multi-user.targetAlias=sshd.service
3.1 [Unit] 部分——描述与依赖
| |
|---|
Description | 服务描述(显示在 systemctl status 中) |
Documentation | |
After | |
Wants | 弱依赖关系,被依赖的服务启动失败不影响本服务。 |
Requires | 强依赖(可选),依赖服务启动失败则本服务不启动。可用systemctl list-dependencies查看依赖关系。 |
ConditionPathExists | |
3.2 [Service] 部分——启动与运行
| |
|---|
EnvironmentFile | |
ExecStartPre | |
ExecStart | |
ExecReload | |
KillMode | process |
Restart | 失败时自动重启策略(on-failure、always、no) |
Type | notify:通知 systemd 已就绪;simple:默认;forking:进程 fork 后退出 |
RuntimeDirectory | |
RuntimeDirectoryMode | 为新创建的 /run/sshd/ 子目录设置权限 |
3.3 [Install] 部分——安装信息
| |
|---|
WantedBy | 在哪个 target 下启用自启(通常为 multi-user.target) |
Alias | |
四、自定义服务示例
假设我们要为 /usr/local/bin/myapp 创建一个后台服务,具体步骤如下。
4.1 创建 service 文件
sudo vi /usr/lib/systemd/system/myapp.service
4.2 写入配置
[Unit]Description=My Custom Application Service # 服务描述,systemctl status 时会显示。Documentation=https://example.com/docs # 文档链接,支持 http://、man: 等格式。After=network.target # 服务在哪些服务之后启动(确保网络已就绪)。Wants=network.target # 弱依赖关系,被依赖的服务启动失败不影响本服务。[Service]Type=simple # simple(默认):ExecStart为主进程;forking:主进程会fork子进程后退出;oneshot:一次性任务。User=myappuser # 生产环境必须指定,不要用root运行业务服务。Group=myappgroup # 生产环境必须指定,不要用root运行业务服务。WorkingDirectory=/opt/myapp # 服务的工作目录。ExecStart=/opt/myapp/bin/myapp --config /etc/myapp/config.yaml # 启动命令(必需)。使用绝对路径,不依赖PATH。ExecReload=/bin/kill -HUP $MAINPID # 重载配置的命令(如发送HUP信号)。ExecStop=/bin/kill -TERM $MAINPID # 停止服务的命令,不配则systemd会用SIGTERM。Restart=on-failure # on-failure:仅非正常退出时重启;always:总是重启(适合守护类服务)。RestartSec=10 # 重启前的等待时间。StandardOutput=journalStandardError=journalEnvironment="APP_ENV=production" # 注入环境变量,可写多行。Environment="LOG_LEVEL=info"LimitNOFILE=65536 # 文件描述符上限,防止“too many open files”。MemoryLimit=2G # 内存软限制,达到时会触发OOM Killer(谨慎使用)。[Install]WantedBy=multi-user.target # multi-user.target 表示在多用户模式下启动(即开机自启)。
4.3 启用并启动
sudo systemctl daemon-reload # 重新加载所有 unit 文件sudo systemctl enable myapp # 启用开机自启sudo systemctl start myapp # 立即启动sudo systemctl status myapp # 检查状态sudo journalctl -u myapp -f # 查看实时日志
4.4 几个实用Tips
- 1. 日志管理:默认输出到
journald,用journalctl查看。生产环境建议配合logrotate或转发到ELK等日志中心。 - 2. 环境变量文件:变量较多时,可用
EnvironmentFile=/etc/myapp/env.conf引用外部文件,避免 service 文件过长。
# -r 创建系统用户(system account),执行id myappuser输出的uid值<1000说明是系统用户。# -s /bin/false 指定用户的登录Shell为 /bin/false,禁止交互式登录sudo useradd -r -s /bin/false myappuser
-r :创建系统用户。系统用户(UID范围通常 1-999)与普通用户(UID ≥ 1000)的区别:
- • 系统用户没有家目录(默认不创建
/home/myappuser) - • 系统用户主要用于运行守护进程(daemon)和服务,而非给人使用
- • 系统用户的密码默认被锁定(
!!),无法通过密码登录
-s /bin/false:禁止登录。
- •
/bin/false 是一个什么都不做、直接返回非零退出码的小程序 - • 当用户尝试登录时,Shell 被设置为
/bin/false,系统会立即拒绝登录并退出 - • 安全目的:即使攻击者获得了该账户的密码或SSH密钥,也无法通过SSH或控制台登录系统
- •
/sbin/nologin:类似,但会显示一条友好提示信息 "This account is currently not available"。 - •
/bin/bash:正常登录Shell(生产环境绝对不要给服务账户配置这个)
- 4. 生产环境禁止使用
Type=simple + ExecStop发送kill信号:systemd默认会根据Type启动方式决定停止逻辑,对于Type=simple,systemd会向整个进程组发送SIGTERM,通常无需自定义ExecStop。如需自定义,确保信号正确。
systemd-analyze verify /etc/systemd/system/myapp.service
五、常见问题与踩坑
问题1:修改 service 文件后不生效
systemctl daemon-reload
修改 unit 文件后必须执行此命令,systemd 才会重新加载。
问题2:服务启动失败,日志在哪里看?
journalctl -u myapp.service # 查看服务日志journalctl -u myapp.service -f # 实时追踪
问题3:云主机操作 sshd 的风险
systemctl stop sshd # !远程连接会立即断开
千万注意:停止 sshd 服务会使当前 SSH 连接断开,且无法重新连接。有云主机 VNC 控制台时可以通过控制台恢复,否则需要谨慎操作。正确的做法是先启动一个新的 SSH 会话(不关闭当前会话),再执行重启操作。
六、systemctl 命令速查
| |
|---|
systemctl start NAME | |
systemctl stop NAME | |
systemctl restart NAME | |
systemctl reload NAME | |
systemctl status NAME | |
systemctl enable NAME | |
systemctl disable NAME | |
systemctl is-active NAME | |
systemctl is-enabled NAME | |
systemctl daemon-reload | |
systemctl list-unit-files | |
systemctl get-default | |
systemctl set-default TARGET | |
journalctl -u NAME | |