ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Jetson黑屏故障排查:rc.local、SSH与systemd启动链深度解析

Jetson黑屏故障排查:rc.local、SSH与systemd启动链深度解析 1. 项目概述这不是“黑屏”是系统启动链的无声断点Jetson设备开机后屏幕一片漆黑连光标都不闪一下——这种故障在Jetson Nano、Orin NX、Orin AGX这些边缘AI开发板上太常见了。我去年帮三个实验室处理过类似问题其中两个团队卡在“能ping通但SSH连不上”一个直接卡在“HDMI无信号串口无日志”。别急着重刷镜像这90%不是硬件损坏而是系统启动流程中某个环节静默失败了。核心关键词就三个rc.local、SSH、systemd——它们不是孤立配置项而是Ubuntu启动生命周期里三道关键闸门rc.local是传统SysV时代的“最后遗嘱”SSH服务是远程访问的生命线而systemd则是整个启动过程的总调度员。当Jetson黑屏时你真正要排查的不是“显示器坏了”而是“系统到底卡在哪一步没走出来”。比如rc.local里一句sudo nvidia-smi没加-c 0参数就会让GPU初始化阻塞整个启动又比如SSH服务被systemd标记为failed却没报错到控制台因为串口日志被默认关闭了。这篇文章不讲泛泛而谈的“重启试试”而是带你用串口线systemctljournalctl三件套像拆解一台精密钟表一样逐级定位启动链上的断裂点。适合刚拿到Jetson Nano想跑YOLOv5却连不上SSH的新手也适合部署AirSLAM后突然黑屏的老手——所有操作都在终端完成不需要显示器、不需要GUI环境一根USB转TTL线就是你的听诊器。2. 启动机制深度拆解为什么rc.local和systemd会打架2.1 Ubuntu on Jetson的启动四阶段模型Jetson设备运行的是定制化Ubuntu系统通常是20.04 LTS或22.04 LTS其启动流程远比普通x86服务器复杂。它不是简单的BIOS→GRUB→Kernel→Init而是嵌入了NVIDIA特有的BootROM→CBoot→U-Boot→Kernel→Userspace五层引导链。我们关心的“黑屏”问题95%发生在Userspace阶段也就是内核加载完驱动、挂载完根文件系统之后。这个阶段又可细分为四个逻辑阶段Early Userspace早期用户空间由initramfs提供只包含最精简的工具集如modprobe、udevadm负责加载GPU、PCIe、CSI摄像头等关键驱动模块。如果这里出错你会看到串口输出卡在“Loading modules...”Systemd Init Phasesystemd初始化期systemd作为PID 1进程接管系统启动basic.target加载/etc/systemd/system.conf中的基础配置此时rc-local.service才被首次识别Multi-User Target Phase多用户目标期systemd启动multi-user.target依次激活网络、SSH、显示管理器gdm3等服务。注意Jetson默认不启用图形界面gdm3是可选服务黑屏往往意味着它根本没启动或者启动失败后systemd没做错误回滚rc.local执行期传统脚本兜底期rc-local.service是一个兼容性服务它会在multi-user.target就绪后按顺序执行/etc/rc.local里的命令。但关键在于——它没有超时机制、没有错误捕获、没有依赖声明。一行sleep 10就能让整个启动卡住10秒而systemd只会默默等待。提示Jetson官方镜像中rc-local.service默认是disabled状态。如果你手动启用了它sudo systemctl enable rc-local就必须承担它带来的不可控风险。很多“黑屏”案例根源就是某位开发者在rc.local里加了一行./my_ai_app.sh 结果该脚本因缺少CUDA环境变量而无限报错又没加后台运行直接阻塞了后续所有服务。2.2 rc.local与systemd的冲突本质时间窗口与权限鸿沟rc.local和systemd的矛盾不是“谁对谁错”而是两种哲学的碰撞。rc.local代表“我写什么系统就执行什么”systemd代表“我按依赖图谱精确调度每一步”。这种冲突在Jetson上被放大原因有三GPU初始化时机错位Jetson的NVIDIA驱动nvidia-firmware、nvidia-kernel-dkms必须在nvidia-persistenced.service启动后才能安全调用nvidia-smi。而rc.local默认在nvidia-persistenced.service之前执行。我见过最典型的错误是rc.local里写nvidia-smi -i 0 -r重置GPU结果systemd还没来得及启动persistenced命令就卡死整个启动流程停滞文件系统挂载顺序混乱Jetson Nano的eMMC和Orin的NVMe SSD可能被配置为不同挂载点如/mnt/data。rc.local里若直接访问/mnt/data/model.bin而该分区的systemd-mount服务尚未激活就会触发No such file or directory错误并静默失败环境变量继承失效rc.local运行在/bin/sh环境下PATH极短通常只有/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin不包含/usr/lib/nvidia或/opt/jetpack路径。这意味着你在.bashrc里设置的export CUDA_HOME/usr/local/cuda在rc.local里完全不可见。很多用户抱怨“明明装了CUDArc.local里nvcc却找不到”根源就在这里。2.3 SSH服务失效的三大隐藏陷阱SSH连不上表面看是端口不通深层原因往往藏在启动链的缝隙里sshd_config的PermitRootLogin陷阱Jetson默认镜像中/etc/ssh/sshd_config的PermitRootLogin默认是prohibit-password即禁止root密码登录只允许密钥。但如果你用sudo passwd root设置了root密码却没生成root的SSH密钥就会出现“能ping通但ssh rootjetson拒绝连接”的假象SELinux/AppArmor策略拦截Ubuntu 22.04在Jetson上默认启用AppArmor其/etc/apparmor.d/usr.sbin.sshd配置文件会限制sshd对/run/systemd/journal/socket的访问。如果rc.local里修改了/run目录权限AppArmor可能直接阻止sshd启动journalctl里只显示apparmorDENIED毫无SSH相关日志NetworkManager与systemd-networkd共存冲突Jetson官方镜像默认使用systemd-networkd管理网络但很多教程教用户安装network-manager并启用它。两者同时运行会导致eth0接口被重复配置DHCP获取IP失败SSH自然连不上。systemctl status systemd-networkd显示active (exited)而systemctl status NetworkManager显示active (running)这就是典型冲突信号。3. 实战排查四步法从串口日志到SSH恢复3.1 第一步用串口线捕获真实启动日志绕过黑屏没有串口线一切排查都是空中楼阁。Jetson Nano/NX/AGX的调试串口是4针UARTTX、RX、GND、VCC但切记不要接VCC——Jetson的UART是3.3V电平接5V VCC会烧毁芯片。你需要一条CH340或CP2102芯片的USB转TTL线淘宝搜“Jetson串口线”即可约15元。接线方式以Jetson Nano为例TTL线的GND → Jetson Nano的J48排针第6脚GNDTTL线的TX → Jetson Nano的J48第8脚GPIO 10 / UART0_RXTTL线的RX → Jetson Nano的J48第10脚GPIO 8 / UART0_TX注意Jetson Orin系列的调试串口位置不同Orin NX在J21Orin AGX在J24务必查阅对应型号的Hardware Design Guide文档别凭Nano经验乱接。连接后在Ubuntu主机上执行ls /dev/ttyUSB* # 通常显示 /dev/ttyUSB0 sudo apt install screen screen /dev/ttyUSB0 115200按下Jetson电源键你会看到完整的启动日志流。重点观察三处Starting kernel...之后是否出现Booting Linux on physical CPU确认内核加载成功systemd[1]: Started User Manager for UID 1000.之后是否出现systemd[1]: Starting OpenBSD Secure Shell server...确认SSH服务已触发最后一行是否停在Started GNOME Display Manager.如果有GUI或Reached target Multi-User System.无GUI这是启动完成的标志。如果日志卡在Starting NVIDIA Persistence Daemon...说明GPU固件加载失败需检查/lib/firmware/nvidia/下是否有对应版本的firmware文件如果卡在Starting LSB: Start NTP daemon...则可能是ntpdate服务因网络未就绪而超时。3.2 第二步用systemctl精准定位失败服务替代rc.local盲猜一旦确认串口日志能输出下一步就是找出哪个服务拖垮了整个启动。在串口终端或通过其他已连通的设备SSH进去执行# 查看所有failed状态的服务 systemctl list-units --statefailed # 查看SSH服务的详细状态关键 systemctl status ssh # 查看rc-local服务是否被激活及状态 systemctl status rc-local # 查看启动耗时最长的10个服务找瓶颈 systemd-analyze blame | head -10 # 查看完整启动流程时间线 systemd-analyze plot boot-time.svg # 需在有GUI的机器上用浏览器打开svg常见失败服务解读ssh.servicefailed withcodeexited, status255通常是/etc/ssh/sshd_config语法错误用sudo sshd -t验证rc-local.servicefailed withcodeexited, status1rc.local脚本里有命令返回非零值需检查脚本末尾是否加了exit 0nvidia-persistenced.servicefailed withFailed to connect to NVIDIA driverGPU驱动未正确安装需重新运行sudo /opt/jetpack/install.shsystemd-networkd-wait-online.servicetimeout网络配置有问题检查/etc/systemd/network/下的.network文件。实操心得我曾遇到一个案例systemctl status ssh显示active (running)但实际无法连接。用sudo ss -tlnp | grep :22发现sshd监听的是127.0.0.1:22而非0.0.0.0:22。根源是/etc/ssh/sshd_config里ListenAddress被误设为127.0.0.1。这种细节仅靠systemctl status是看不到的必须结合ss命令交叉验证。3.3 第三步安全修复rc.local保留功能消除隐患如果确认rc.local是罪魁祸首不要直接删掉它——很多AI应用依赖它启动。正确的做法是重构它让它符合systemd规范原危险写法/etc/rc.local#!/bin/sh -e # rc.local echo Starting AI service... cd /home/user/my_project ./start_server.sh exit 0安全重构写法创建systemd服务# 创建服务文件 sudo nano /etc/systemd/system/ai-server.service内容如下[Unit] DescriptionAI Server Service Afternvidia-persistenced.service network.target Wantsnvidia-persistenced.service [Service] Typesimple Useruser WorkingDirectory/home/user/my_project EnvironmentPATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/nvidia:/usr/local/cuda/bin EnvironmentCUDA_HOME/usr/local/cuda ExecStart/home/user/my_project/start_server.sh Restarton-failure RestartSec10 [Install] WantedBymulti-user.target然后启用服务sudo systemctl daemon-reload sudo systemctl enable ai-server.service sudo systemctl start ai-server.service这样做的好处After确保在GPU持久化服务和网络就绪后再启动Environment显式注入CUDA路径避免环境变量丢失Restarton-failure让服务崩溃后自动重启比rc.local更健壮systemctl status ai-server可实时监控日志统一归档到journalctl。注意Jetson Nano的内存有限4GBRestartSec10要谨慎设置。如果start_server.sh启动耗时超过10秒systemd会误判为失败并反复重启导致CPU满载。实测建议设为RestartSec30并在脚本开头加sleep 5给GPU留足初始化时间。3.4 第四步SSH服务深度诊断与一键修复当确定SSH服务本身失败时按以下顺序排查1. 验证sshd配置语法sudo sshd -t # 若输出Syntax OK配置无误若报错按提示修改/etc/ssh/sshd_config2. 检查SSH密钥权限高频坑# /etc/ssh/目录下密钥必须是root:root且600权限 sudo chown root:root /etc/ssh/ssh_host_* sudo chmod 600 /etc/ssh/ssh_host_* # 用户家目录的.ssh权限必须是700私钥600 sudo chmod 700 /home/user/.ssh sudo chmod 600 /home/user/.ssh/id_rsa3. 强制重生成SSH主机密钥终极手段sudo rm /etc/ssh/ssh_host_* sudo dpkg-reconfigure openssh-server # 此命令会重新生成所有密钥并重启sshd4. 检查防火墙规则# Jetson默认不启用ufw但若有人启用过需放行22端口 sudo ufw status verbose sudo ufw allow 225. 一键修复脚本保存为fix-ssh.sh#!/bin/bash echo Starting SSH Repair sudo systemctl stop ssh sudo sshd -t echo ✓ sshd config OK || { echo ✗ sshd config error; exit 1; } sudo chown root:root /etc/ssh/ssh_host_* 2/dev/null sudo chmod 600 /etc/ssh/ssh_host_* 2/dev/null sudo systemctl restart ssh sleep 2 if sudo ss -tlnp | grep :22 | grep -q sshd; then echo ✓ SSH is listening on port 22 echo Test with: ssh user$(hostname -I | awk {print $1}) else echo ✗ SSH failed to start sudo journalctl -u ssh -n 20 --no-pager fi赋予执行权限并运行chmod x fix-ssh.sh sudo ./fix-ssh.sh4. 常见问题速查表与独家避坑指南4.1 黑屏问题速查表按现象分类现象可能原因快速验证命令修复方案串口无任何输出电源不足或UART硬件损坏用万用表测J48第1脚3.3V电压更换电源适配器推荐12V/3A或更换TTL线串口有输出卡在Booting Linux...eMMC/NVMe固件损坏sudo fdisk -l查看磁盘是否识别用JetPack SDK重刷整个系统镜像串口显示Started GNOME Display Manager.后黑屏GPU驱动与Xorg不兼容sudo journalctl -u gdm3 -n 50编辑/etc/gdm3/custom.conf取消#WaylandEnablefalse注释能ping通但ssh连接超时SSH服务未监听0.0.0.0sudo ss -tlnp | grep :22修改/etc/ssh/sshd_config确保ListenAddress 0.0.0.0ssh连接被拒绝Connection refusedsshd服务未启动sudo systemctl status sshsudo systemctl start ssh并enable它ssh登录后立即退出用户shell被设为/bin/falsegetent passwd usersudo usermod -s /bin/bash user4.2 rc.local相关致命错误与修复错误1/etc/rc.local里调用nvidia-smi导致卡死根源nvidia-smi需要GPU驱动完全加载而rc.local执行过早。修复删除rc.local中所有nvidia-smi命令改用systemd服务Afternvidia-persistenced.service。错误2rc.local里cd /some/path后执行命令但路径不存在根源rc.local在/目录下执行cd失败不会终止脚本后续命令在/下执行必然失败。修复所有路径用绝对路径或在命令前加cd /some/path 并检查cd返回值if cd /home/user/project; then ./start.sh else echo Project dir not found 2 exit 1 fi错误3rc.local里nohup python3 app.py 启动后台进程但app.py依赖GPU根源后台运行后进程脱离systemd管理GPU上下文可能被释放。修复改用systemd服务Typesimple并添加EnvironmentCUDA_VISIBLE_DEVICES0。4.3 SSH连接失败的隐蔽原因DNS解析失败导致连接慢sshd默认启用UseDNS yes会反向解析客户端IP。若Jetson无法访问DNS服务器会卡顿30秒。修复sudo nano /etc/ssh/sshd_config设UseDNS no然后sudo systemctl restart ssh。SSH密钥格式不兼容新版本OpenSSH8.8默认禁用RSA-SHA1签名算法。若你用旧版密钥ssh-keygen -t rsa生成可能被拒绝。修复生成新密钥ssh-keygen -t ed25519或在sshd_config中加PubkeyAcceptedAlgorithms ssh-rsa。SELinux/AppArmor阻止sshd读取密钥/var/log/audit/audit.log里有avc: denied记录。修复临时禁用测试sudo setenforce 0SELinux或sudo aa-disable /usr/sbin/sshdAppArmor确认后调整策略。4.4 Jetson特定硬件陷阱Jetson Orin NX的PCIe带宽限制Orin NX的PCIe x4通道实际带宽只有x2若rc.local里启动的AI服务试图占用全部带宽会导致USB 3.0设备如串口线失联。修复在/boot/extlinux/extlinux.conf中添加pcinomsi内核参数降低中断请求频率。Jetson AGX Orin的散热 throttlingAGX在无散热器情况下CPU/GPU会降频至500MHz导致systemd-analyze显示启动耗时异常长2分钟。修复强制设置性能模式sudo nvpmodel -m 0并确保散热风扇正常工作。Jetson Nano的microSD卡寿命耗尽频繁写入日志会使廉价SD卡坏块/var/log/journal/目录损坏会导致journalctl崩溃进而影响systemd服务状态查询。修复将日志重定向到RAMsudo mkdir /var/log/journal; sudo systemd-tmpfiles --create或更换工业级SD卡。5. 预防性加固让Jetson启动坚如磐石5.1 启动日志永久化配置默认journal日志只保存在内存中重启后丢失。要永久保存编辑/etc/systemd/journald.confStoragepersistent Compressyes MaxRetentionSec1month SystemMaxUse500M然后重启journaldsudo systemctl restart systemd-journald这样即使黑屏你也能用journalctl --since 2 hours ago找回最近的日志。5.2 创建启动健康检查服务新建/etc/systemd/system/boot-healthcheck.service[Unit] DescriptionBoot Health Check Aftermulti-user.target [Service] Typeoneshot ExecStart/usr/local/bin/boot-check.sh RemainAfterExityes [Install] WantedBymulti-user.target对应的/usr/local/bin/boot-check.sh#!/bin/bash # 检查GPU if ! nvidia-smi -i 0 --query-gpuname --formatcsv,noheader | grep -q Orin; then logger ERROR: GPU not detected exit 1 fi # 检查网络 if ! ping -c 1 -W 1 google.com /dev/null; then logger WARN: Network unreachable fi # 检查SSH if ! ss -tlnp | grep -q :22; then logger ERROR: SSH not listening systemctl restart ssh fi赋予权限并启用sudo chmod x /usr/local/bin/boot-check.sh sudo systemctl daemon-reload sudo systemctl enable boot-healthcheck.service5.3 开发者必备的启动调试清单每次部署新模型或更新JetPack后务必执行sudo systemctl list-dependencies --after multi-user.target—— 查看服务依赖树确认AI服务在GPU和网络之后sudo systemd-analyze critical-chain ssh.service—— 查看SSH启动的关键路径定位瓶颈服务sudo journalctl -b -p 3—— 查看本次启动的所有警告和错误priority 3errsudo lsof -i :22—— 确认sshd进程绑定的IP和端口cat /proc/sys/kernel/random/entropy_avail—— 检查熵池低于100可能导致SSH密钥生成卡顿。我个人在实际操作中的体会是Jetson黑屏问题80%源于“想当然”的配置。比如把x86服务器上的rc.local脚本原样复制到Jetson忽略了GPU初始化时序或者用VS Code Remote-SSH连接时没意识到Jetson的/home/user目录默认是ext4格式而某些AI框架要求XFS。真正的稳定不是靠运气重启而是靠对启动链每个环节的敬畏——把systemd当交响乐指挥而不是执行批处理的DOS。最后分享一个小技巧在/etc/default/grub里把GRUB_CMDLINE_LINUX_DEFAULT改成quiet splash loglevel3 rd.systemd.show_status1重启后GRUB菜单按e键末尾加systemd.log_leveldebug就能看到systemd启动的每一帧日志比串口还详细。
返回列表