扫码加入

  • 正文
  • 相关推荐
申请入驻 产业图谱

基于 systemd 的 Linux 启动初始化全解析:配置与实战应用

1小时前
158
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

systemd 作为目前主流 Linux 发行版的系统和服务管理器,取代了传统的 SysV init,以并行启动、集中管理、配置简洁的特性成为 Linux 启动初始化的标准方案。它不仅负责系统引导阶段的用户空间初始化,还统一管理进程、守护进程、网络、挂载点等核心功能,基于纯文本的单元文件实现服务配置,大幅简化了自定义启动脚本、自动服务的开发与维护。本文以 NXP i.MX93EVK(Linux 6.1.36+)为例,详解 systemd 核心原理、常用操作及两个典型实战场景(自动登录、自定义启动脚本),实现系统启动的自动化定制。

资料获取:基于systemd的启动初始化

1. systemd 核心基础:组件与核心特性

1.1 systemd 的核心定位

systemd 是 Linux 的系统和服务管理器,作为系统启动后的第一个进程(PID=1),替代传统 /sbin/init,核心职责包括:
  • 引导用户空间初始化,并行启动各类系统服务,大幅缩短启动时间;
  • 集中管理进程、守护进程、设备、挂载点、网络连接、日志等;
  • 为登录用户启动独立的服务实例,实现用户级服务管理;
  • 提供统一的配置方式和命令行工具,简化服务的启动、停止、自启配置。
在系统中,/sbin/init 为 systemd 的符号链接,可通过以下命令验证:
ls /sbin/init -al
# 输出:lrwxrwxrwx 1 root root 20 Sep 20 01:57 /sbin/init -> /lib/systemd/systemd

1.2 三大核心操作工具

systemd 提供了一套简洁的命令行工具,覆盖服务管理、启动性能分析、单元查询等所有场景,核心工具如下:

(1)systemctl:核心服务管理工具

用于控制 systemd 的状态,管理所有服务单元(.service),常用命令:
# 重新加载systemd守护进程(修改配置后必执行)
sudo systemctl daemon-reload
# 查看服务状态(关键:查看是否运行、是否自启、错误日志)
sudo systemctl status [服务名]
# 启动/停止/重启服务
sudo systemctl start/stop/restart [服务名]
# 设置服务开机自启/关闭自启
sudo systemctl enable/disable [服务名]
# 查看所有已加载的单元
systemctl list-units
# 查看指定类型的单元(如target、service)
systemctl list-units --type=[类型]

(2)systemd-analyze:启动性能分析工具

用于分析系统启动耗时,定位启动缓慢的服务,优化启动性能,常用命令:
# 查看启动总耗时(内核+用户空间)
systemd-analyze
# 示例输出:Startup finished in 2.649s (kernel) + 7.091s (userspace) = 9.740s
# 查看各服务启动耗时,按耗时从长到短排序
systemd-analyze blame
# 查看启动关键链,定位核心耗时节点
systemd-analyze critical-chain

(3)单元文件:systemd 的配置核心

systemd 摒弃了传统的 shell 启动脚本,通过纯文本单元文件定义服务的初始化规则,单元文件存放在/etc/systemd/system/(自定义)和/usr/lib/systemd/system/(系统默认),支持多种类型,核心类型包括:
单元类型 后缀 用途
service .service 系统服务 / 守护进程管理
target .target 启动目标(如多用户、图形)
socket .socket 套接字管理
timer .timer 定时任务
mount .mount 文件系统挂载
所有单元文件均由[Unit][Service][Install]三大段构成,各段职责明确,配置语法简洁。

1.3 systemd 的核心优势

相比传统 SysV init,systemd 的核心优势体现在:
  • 并行启动:同时启动多个无依赖的服务,大幅缩短系统启动时间;
  • 集中管理:统一管理进程、网络、设备、日志等,替代多个独立工具;
  • 按需启动:通过 socket/timer 实现服务的按需启动,减少系统资源占用;
  • 配置简洁:基于声明式单元文件,无需编写复杂的 shell 脚本;
  • 状态监控:实时监控服务状态,服务异常时可自动重启(配置后);
  • 兼容性:向下兼容 SysV init 的启动脚本,平滑迁移。

2. systemd 核心单元文件解析

所有自定义启动服务均需通过编写单元文件实现,单元文件的三大段为固定格式,各段核心配置项如下,是实现所有自定义功能的基础:

2.1 [Unit] 段:定义单元的元信息与依赖关系

用于描述服务名称、说明,配置服务的启动依赖(如在某个服务 / 目标之后启动),核心配置项:
  • Description:服务的简短描述,便于识别;
  • After:指定本服务在哪些服务 / 目标之后启动(如 network.target,网络启动后);
  • Before:指定本服务在哪些服务 / 目标之前启动;
  • Requires:强依赖,依赖的服务启动失败,本服务也会启动失败;
  • Wants:弱依赖,依赖的服务启动失败,本服务仍可正常启动(推荐使用)。

2.2 [Service] 段:定义服务的运行规则

核心段,指定服务的执行命令、运行模式、重启策略等,核心配置项:
  • ExecStart:服务启动时执行的命令 / 脚本路径(必配);
  • ExecStop:服务停止时执行的命令;
  • ExecReload:服务重新加载时执行的命令;
  • Type:服务运行模式,常用simple(默认,立即启动)、idle(等待系统空闲后启动);
  • Restart:重启策略,常用always(服务异常退出时自动重启)、on-failure(仅失败时重启);
  • Environment:设置服务运行的环境变量;
  • TTYPath:指定服务使用的终端设备(如串口登录服务)。

2.3 [Install] 段:定义服务的安装规则

用于配置服务的自启目标,即服务开机自启时归属的启动目标,核心配置项:
  • WantedBy:指定服务被哪个目标所需要,配置后可通过systemctl enable设置自启;
    • 常用目标:multi-user.target(多用户命令行目标,最常用)、default.target(系统默认目标)、graphical.target(图形界面目标);
  • RequiredBy:强依赖目标,目标启动时必须启动本服务。

2.4 通用单元文件模板

基于以上配置项,自定义启动脚本的通用单元文件模板如下(保存为/etc/systemd/system/[服务名].service):
[Unit]
Description=My Custom Startup Service  # 自定义服务描述
After=network.target  # 网络启动后再执行本服务

[Service]
Type=simple  # 运行模式
ExecStart=/path/to/your/script.sh  # 自定义脚本的绝对路径
Restart=on-failure  # 脚本执行失败时自动重启

[Install]
WantedBy=multi-user.target  # 多用户目标下自启

3. 实战场景 1:实现系统串口自动登录

NXP i.MX93EVK 等嵌入式 Linux 设备,默认串口登录需要手动输入用户名和密码,在工业现场、无人值守场景下,自动登录是刚需。该功能通过修改 systemd 的串口登录服务单元文件实现,核心是修改agetty的启动参数,添加自动登录选项。

3.1 找到串口登录的服务单元文件

嵌入式 Linux 中,串口登录服务通常为serial-getty@ttyLP0.service(ttyLP0 为串口设备名,可根据实际修改),文件位于:
/etc/systemd/system/getty.target.wants/serial-getty@ttyLP0.service

3.2 修改单元文件的 [Service] 段

原文件的ExecStart配置为:
[Service]
Environment="TERM=linux"
ExecStart=-/sbin/agetty -8 -L %I 115200 $TERM
Type=idle
Restart=always
# 其他配置...
agetty命令中添加--autologin root(自动登录 root 用户),修改后:
ExecStart=-/sbin/agetty -8 -L %I --autologin root 115200 $TERM
  • %I:自动替换为串口设备名(如 ttyLP0);
  • 115200:串口波特率,根据实际配置修改。

3.3 生效配置并验证

无需重新加载 systemd,直接重启系统即可生效:
reboot
重启后,串口将直接自动登录 root 用户,无需要求输入用户名和密码,示例输出:
OK] Reached target Graphical Interface.
NXP i.MX Release Distro6.1-mickledore imx93evk ttyLP0
imx93evk login:root(automatic login)
root@imx93evk:~#

4. 实战场景 2:通过 profile.d 实现自定义脚本自动执行

除了编写 systemd service 单元文件,嵌入式 Linux 中还可通过 **/etc/profile.d/目录实现自定义脚本的自动执行,该方式更轻量,适合环境变量配置、简单驱动加载、基础服务启动 ** 等场景,无需编写复杂的单元文件。

4.1 profile.d 的核心原理

  • /etc/profile是 Linux 系统为 Bash shell 配置的全局初始化脚本,系统启动或用户登录时会自动执行;
  • /etc/profile.d//etc/profile的扩展目录,该目录下所有以.sh 结尾的脚本会被自动执行,执行顺序按脚本名称字典序;
  • 适用于所有登录方式(串口、SSH、图形界面),脚本执行完成后才会进入用户终端;
  • 推荐将脚本按数字命名(如 01-wifi.sh、02-bt.sh),实现按顺序执行。

4.2 实战:实现 WiFi-BT 驱动自动加载与 IP 自动获取

以 NXP i.MX93EVK 为例,编写脚本实现系统启动时自动加载 WiFi-BT 驱动、固件,并自动连接 WiFi 获取 IP 地址,步骤如下:

(1)在 /etc/profile.d/ 创建自定义脚本

创建脚本/etc/profile.d/01-wifi-bt.sh,赋予可执行权限:
touch /etc/profile.d/01-wifi-bt.sh
chmod +x /etc/profile.d/01-wifi-bt.sh

(2)编写脚本内容

脚本实现驱动加载、WiFi 使能、自动连接 WiFi、DHCP 获取 IP,核心代码:
#!/bin/sh
# 加载WiFi驱动
modprobe moal mod_para=nxp/wifi_mod_para.conf
echo "wifi driver load successfully" > /dev/kmesg
# 加载BT驱动
modprobe btnxpuart
echo "bt driver load successfully" > /dev/kmesg

# 检查WiFi网卡mlan0是否存在
ifconfig -a | awk '{print $1}' | grep mlan0
if [ $? -eq 0 ]
then
    # 使能WiFi网卡
    ifconfig mlan0 up
    # 添加WiFi密码到配置文件(替换SSID和PASSWORD为实际WiFi信息)
    wpa_passphrase SSID PASSWORD >> /etc/wpa_supplicant.conf
    # 关闭以太网(可选)
    ifconfig eth0 down
    # 后台启动wpa_supplicant,连接WiFi
    wpa_supplicant -d -B -i mlan0 -c /etc/wpa_supplicant.conf -Dnl80211
    # DHCP自动获取IP
    udhcpc -i mlan0
else
    echo "wifi module loaded failure!" > /dev/kmesg
fi

(3)重启系统验证效果

重启系统后,脚本会自动执行,通过dmesg或串口日志可查看执行过程,最终 WiFi 会自动连接并获取 IP,通过ifconfig mlan0验证:

ifconfig mlan0
# 示例输出:
mlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
        inet 192.168.0.221  netmask 255.255.255.0  broadcast 192.168.0.255
        ether d0:17:69:ee:6b:08  txqueuelen 1000 (Ethernet)
        RX packets 33  bytes 7000 (6.8 KiB)
        TX packets 48  bytes 6906 (6.7 KiB)

4.3 profile.d 的优缺点

优点

  • 配置简单:无需编写 systemd 单元文件,仅需创建.sh 脚本并赋予执行权限;
  • 按序执行:通过数字命名实现脚本的顺序执行,满足依赖需求;
  • 全局生效:适用于所有登录方式,一次配置全局有效;
  • 易于维护:单独的脚本文件,修改、删除方便,不影响其他系统配置。

缺点

  • 无状态监控:systemd 不会监控脚本执行状态,执行失败无自动重启机制;
  • 阻塞登录:脚本执行完成后才会进入用户终端,脚本耗时过长会导致登录延迟;
  • 仅适用于简单场景:不适合复杂的守护进程、需要后台运行的服务(此类场景推荐使用 systemd service)。

5. systemd 服务的完整配置流程(自定义 service 方式)

对于需要后台运行、状态监控、自动重启的复杂服务(如自定义应用、守护进程),推荐使用 systemd service 单元文件的方式,完整配置流程如下,以自定义myapp.service为例:

5.1 编写自定义执行脚本

创建脚本/usr/local/bin/myapp.sh,实现业务逻辑,赋予可执行权限:
#!/bin/sh
# 自定义业务逻辑,如启动后台应用
nohup /usr/local/bin/myapp > /var/log/myapp.log 2>&1 &
chmod +x /usr/local/bin/myapp.sh

5.2 编写 systemd 单元文件

创建单元文件/etc/systemd/system/myapp.service,内容如下:
[Unit]
Description=My Custom Application Service
After=network.target syslog.target  # 网络和日志服务启动后执行

[Service]
Type=forking  # 后台运行模式(对应nohup)
ExecStart=/usr/local/bin/myapp.sh  # 启动脚本
ExecStop=/usr/bin/pkill -9 myapp  # 停止命令
Restart=always  # 任何情况都自动重启
RestartSec=3  # 重启间隔3秒

[Install]
WantedBy=multi-user.target

5.3 加载配置并设置自启

# 重新加载systemd守护进程,使新配置生效
sudo systemctl daemon-reload
# 设置服务开机自启
sudo systemctl enable myapp.service
# 启动服务
sudo systemctl start myapp.service
# 查看服务状态
sudo systemctl status myapp.service

5.4 服务的日常管理

# 停止服务
sudo systemctl stop myapp.service
# 重启服务
sudo systemctl restart myapp.service
# 查看服务日志(定位错误)
journalctl -u myapp.service -f

6. 常见问题排查与避坑指南

6.1 自定义 service 启动失败,提示 "ExecStart path is not absolute"

  • 原因ExecStart配置的脚本 / 命令路径为相对路径,systemd 要求必须使用绝对路径
  • 解决:修改为绝对路径,如/usr/local/bin/script.sh,而非./script.sh

6.2 profile.d 中的脚本未执行

  • 原因 1:脚本未赋予可执行权限(缺少 x 权限);
  • 原因 2:脚本后缀不是.sh,systemd 仅执行.sh 结尾的脚本;
  • 原因 3:脚本存在语法错误,导致执行中断;
  • 解决:执行chmod +x 脚本.sh,检查脚本后缀和语法,通过sh 脚本.sh手动执行测试。

6.3 服务设置自启后,重启系统仍未自动启动

  • 原因 1:未执行sudo systemctl daemon-reload,配置未生效;
  • 原因 2[Install]段的WantedBy配置的目标不存在,或目标未启动;
  • 原因 3:服务存在依赖错误,通过systemctl status 服务名查看具体错误;
  • 解决:重新执行daemon-reload,核对WantedBy配置为multi-user.target(通用),排查依赖错误。

6.4 自动登录配置后,串口无输出

  • 原因:串口设备名配置错误(如 ttyLP0 改为 ttyS0),或波特率不匹配;
  • 解决:通过dmesg | grep tty查看实际串口设备名,修改单元文件中的波特率和设备名。

6.5 服务重启策略不生效(Restart=always)

  • 原因Type配置的运行模式与服务实际运行方式不匹配(如后台运行的服务配置为simple);
  • 解决:后台运行的服务(如 nohup、&)配置Type=forking,前台运行的服务配置Type=simple

7. 两种自动启动方式的选型建议

systemd service 和 profile.d 是嵌入式 Linux 中最常用的两种自动启动方式,需根据实际场景选择,核心选型原则如下:

推荐使用 systemd service 的场景

  1. 自定义应用、守护进程,需要后台运行、状态监控、自动重启
  2. 服务有明确的依赖关系(如需要在网络 / 数据库启动后执行);
  3. 需要对服务进行启动、停止、重启的日常管理;
  4. 无人值守场景,要求服务异常时自动恢复。

推荐使用 profile.d 的场景

  1. 简单的初始化操作,如环境变量配置、驱动加载、临时文件清理;
  2. 无需状态监控,执行一次即可,无需后台运行;
  3. 希望快速配置,无需编写复杂的单元文件;
  4. 多个简单脚本需要按顺序执行。
systemd 作为 Linux 启动初始化的标准方案,通过单元文件实现了服务配置的标准化和简洁化,相比传统 SysV init 大幅提升了启动效率和管理便捷性。本文讲解的串口自动登录profile.d 自定义脚本是嵌入式 Linux 中最典型的实战场景,而自定义 systemd service 则适用于更复杂的后台服务管理。

核心使用要点:

  1. 所有 systemd 配置修改后,需执行systemctl daemon-reload生效;
  2. 单元文件的ExecStart必须使用绝对路径,依赖关系优先使用AfterWants
  3. 简单场景用 profile.d,复杂场景用 systemd service,兼顾效率和可维护性;
  4. 利用systemctl statusjournalctl排查服务问题,利用systemd-analyze优化启动性能。
基于 systemd 的启动初始化配置,可灵活实现嵌入式 Linux 设备的自动化定制,满足工业现场、无人值守、消费电子等各类场景的需求,是嵌入式 Linux 开发工程师的必备技能。

相关推荐