You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

自定义systemd服务手动启动正常,EC2实例重启后启动失败(状态码255)原因排查咨询

手动启动正常但EC2开机自启失败的systemd服务排查思路

这种情况我之前在EC2上部署定时任务服务时也遇到过——手动跑完全没问题,一重启就掉链子。status=255只是个通用退出码,结合你的场景(要下载数据集、EventBridge触发实例启动),背后大概率是启动时机、环境/路径、权限这几类问题,给你梳理几个核心排查方向:

1. 服务启动太早,依赖的系统资源还没就绪

EC2实例启动时,网络、cloud-init初始化、甚至SSM Agent这些组件都需要一点时间才能完全就绪。你手动启动时,这些资源都已经跑起来了,但开机自启时systemd可能在这些依赖项就绪前就启动了你的服务,导致脚本拿不到密钥、连不上网络。

排查方法:

用journalctl看本次启动的服务日志,找具体错误:

sudo journalctl -u service-name.service -b

如果日志里出现“网络不可达”“无法获取密钥”这类提示,基本就是时机问题。

解决办法:

修改你的systemd服务文件(通常在/etc/systemd/system/下),添加依赖项,让服务在必要的系统组件就绪后再启动:

[Unit]
Description=Your Python Dataset Download Service
After=network-online.target cloud-init.target ssm-agent.target
Wants=network-online.target
  • network-online.target:确保网络完全就绪(不是仅仅启动网络服务)
  • cloud-init.target:等待EC2的初始化脚本执行完毕(比如挂载EBS、设置环境变量)
  • ssm-agent.target:如果你的密钥存在SSM Parameter Store里,确保Agent就绪

修改后记得重载systemd配置并重启服务:

sudo systemctl daemon-reload
sudo systemctl enable --now service-name.service

2. 环境变量或路径不匹配

手动启动时,你当前shell的环境变量(比如密钥所在的变量)、工作目录都是正确的,但systemd服务默认运行在干净的系统环境里,没有用户shell的环境变量,工作目录默认是/,这会导致脚本找不到依赖文件或者密钥。

排查方法:

检查日志里有没有“找不到文件”“未定义变量”的错误;或者临时修改ExecStart打印环境变量,对比手动启动时的环境:

ExecStart=/bin/bash -c "env > /tmp/service-env.log && /usr/bin/python3 /path/to/script.py --key $KEY"

重启实例后查看/tmp/service-env.log就能发现差异。

解决办法:

  • 绝对路径优先:把脚本里的所有相对路径改成绝对路径(比如数据集下载路径、依赖模块路径),ExecStart里也要用Python和脚本的绝对路径,比如/usr/bin/python3 /home/ec2-user/scripts/download.py
  • 显式设置环境变量:如果密钥是通过环境变量传递的,在服务文件里用Environment字段定义,或者引用外部环境文件:
    [Service]
    Environment="DATASET_KEY=your-secret-key"
    # 或者引用外部环境文件
    EnvironmentFile=/etc/dataset-service.env
    
  • 设置工作目录:在服务文件里添加WorkingDirectory,指定脚本所在的目录:
    [Service]
    WorkingDirectory=/home/ec2-user/scripts
    

3. 权限不足

手动启动时你用sudo是以root身份运行,但systemd服务默认可能用nobody或者其他低权限用户,导致脚本无法读取密钥文件、写入下载目录,或者无法执行某些系统操作。另外,如果你的脚本需要访问挂载的EBS卷,开机时卷的权限可能还没正确设置。

排查方法:

看journalctl日志里有没有Permission denied的关键词;检查服务文件的User/Group配置,确认该用户有脚本执行权限、密钥文件读取权限、下载目录写入权限。

解决办法:

  • 指定运行用户:如果不需要低权限运行,直接在服务文件里设置User=root
    [Service]
    User=root
    
  • 调整文件权限:给脚本和密钥文件设置严格的权限(避免泄露):
    sudo chmod 700 /path/to/script.py
    sudo chmod 600 /path/to/key-file
    
  • 依赖存储挂载:如果用了EBS卷,在服务文件里添加After=remote-fs.target,确保卷挂载完成后再启动服务。

4. 添加自动重试机制

有时候启动失败只是临时的(比如网络波动、SSM Agent还在初始化),给服务加上自动重试配置,能大大提高开机自启的成功率:

[Service]
Restart=on-failure
RestartSec=5
StartLimitInterval=300
StartLimitBurst=5
  • Restart=on-failure:服务失败时自动重启
  • RestartSec=5:失败后5秒重试
  • StartLimitInterval/StartLimitBurst:限制5分钟内最多重试5次,避免无限循环

最后提醒:每次修改服务文件后,一定要执行sudo systemctl daemon-reload重载配置,然后用sudo systemctl enable service-name.service确保服务被设置为开机自启。

内容的提问来源于stack exchange,提问作者Danny

火山引擎 最新活动