关于 systemd-services
systemd-services 是面向 Linux 系统管理员的 systemd 服务管理技能,说明如何配置服务、定时器和套接字激活,并涵盖依赖、资源限制与日志分析。
主要功能
- 01编写和管理服务单元
- 02配置 systemd 定时器
- 03设置套接字激活
- 04管理依赖与资源限制
- 05使用 journalctl 分析日志
适用场景
- 01将应用部署为后台服务
- 02用定时器替代 cron 任务
- 03排查服务启动或运行故障
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill systemd-services安装后在 Claude Code 中输入/systemd-services确认已加载。
详细介绍
Systemd 服务
创建、管理和监控 systemd 服务与定时器。涵盖单元文件编写、依赖管理、套接字激活、资源限制、journalctl 日志分析和生产环境加固。
适用场景
- 将应用部署为受管理的后台服务
- 用 systemd 定时器替代 cron 作业,以便更好地记录日志和控制依赖关系
- 设置套接字激活,实现按需启动服务
- 为服务配置资源限制(CPU、内存、I/O)
- 调试服务启动失败和运行时崩溃
- 管理服务依赖关系和启动顺序
前置条件
- 运行 systemd 的 Linux 系统(大多数现代发行版均符合)
- 创建系统级单元文件所需的 root 或 sudo 权限
- 要作为服务运行的应用二进制文件或脚本
- 了解应用的启动/停止生命周期
服务单元文件——完整示例
# /etc/systemd/system/myapp.service
[Unit]
Description=MyApp Production Server
Documentation=https://docs.example.com/myapp
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service
[Service]
Type=notify
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
# Environment configuration
EnvironmentFile=/etc/myapp/env
Environment=NODE_ENV=production
Environment=PORT=8080
# Execution
ExecStartPre=/opt/myapp/bin/migrate --check
ExecStart=/opt/myapp/bin/server --config /etc/myapp/config.yaml
ExecStartPost=/opt/myapp/bin/healthcheck.sh
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/opt/myapp/bin/graceful-stop.sh
# Restart behavior
Restart=on-failure
RestartSec=5
StartLimitIntervalSec=300
StartLimitBurst=5
# Timeouts
TimeoutStartSec=30
TimeoutStopSec=30
WatchdogSec=60
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/myapp /var/log/myapp
CapabilityBoundingSet=
AmbientCapabilities=
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp
[Install]
WantedBy=multi-user.target
服务管理命令
# Reload systemd after creating or modifying unit files
systemctl daemon-reload
# Start, stop, restart a service
systemctl start myapp
systemctl stop myapp
systemctl restart myapp
# Reload service configuration without restart (if supported)
systemctl reload myapp
# Enable service to start on boot
systemctl enable myapp
# Enable and start in one command
systemctl enable --now myapp
# Disable and stop
systemctl disable --now myapp
# Check service status
systemctl status myapp
# Check if a service is active, enabled, or failed
systemctl is-active myapp
systemctl is-enabled myapp
systemctl is-failed myapp
# List all running services
systemctl list-units --type=service --state=running
# List all failed services
systemctl list-units --type=service --state=failed
# Show all properties of a service
systemctl show myapp
# Show specific property values
systemctl show myapp -p MainPID,MemoryCurrent,CPUUsageNSec
# Mask a service (prevent it from being started at all)
systemctl mask myapp
# Unmask
systemctl unmask myapp
# Reset a failed service state
systemctl reset-failed myapp
定时器单元(替代 Cron)
定时器文件
# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup timer
[Timer]
# Run daily at 2:30 AM
OnCalendar=*-*-* 02:30:00
# If the system was off at the scheduled time, run when it boots
Persistent=true
# Add random delay up to 15 minutes to avoid thundering herd
RandomizedDelaySec=900
# Associate with a specific service (defaults to same name .service)
Unit=backup.service
[Install]
WantedBy=timers.target
对应的服务文件
# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup job
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/run-backup.sh
StandardOutput=journal
StandardError=journal
定时器管理
# Common OnCalendar expressions:
# minutely, hourly, daily, weekly, monthly
# *-*-* 06:00:00 Daily at 6 AM
# Mon..Fri *-*-* 09:00 Weekdays at 9 AM
# *:0/15 Every 15 minutes
# Validate calendar expressions
systemd-analyze calendar "Mon..Fri *-*-* 09:00"
# List all active timers
systemctl list-timers --all
# Enable and start a timer
systemctl enable --now backup.timer
# Run the associated service immediately (for testing)
systemctl start backup.service
套接字激活
# /etc/systemd/system/myapp.socket
[Unit]
Description=MyApp Socket
[Socket]
ListenStream=8080
Accept=no
# Optionally bind to a specific IP
# ListenStream=10.0.1.10:8080
[Install]
WantedBy=sockets.target
# /etc/systemd/system/myapp.service
[Unit]
Description=MyApp Server
Requires=myapp.socket
[Service]
Type=notify
User=myapp
ExecStart=/opt/myapp/bin/server
# Service receives the socket file descriptor from systemd
[Install]
WantedBy=multi-user.target
# Enable the socket (service starts on first connection)
systemctl enable --now myapp.socket
# Check socket status
systemctl status myapp.socket
# List all listening sockets
systemctl list-sockets
依赖管理
# Key [Unit] directives for ordering and dependencies:
# After= Start after these units (ordering only)
# Requires= Hard dependency -- fail if this unit cannot start
# Wants= Soft dependency -- try to start, don't fail if unavailable
# PartOf= Stop this unit when the parent stops
# Conflicts= Cannot run alongside this unit
# Visualize the dependency tree for a service
systemctl list-dependencies myapp
# Show reverse dependencies (who depends on this unit)
systemctl list-dependencies myapp --reverse
# Analyze boot order for a service
systemd-analyze critical-chain myapp.service
资源限制(cgroups v2)
# /etc/systemd/system/myapp.service.d/limits.conf
# (drop-in override file)
[Service]
# Memory limits
MemoryMax=1G
MemoryHigh=768M
# CPU limits
CPUQuota=200% # Up to 2 full CPU cores
CPUWeight=100 # Relative weight (default=100)
# I/O limits
IOWeight=50
IOReadBandwidthMax=/dev/sda 100M
IOWriteBandwidthMax=/dev/sda 50M
# Process limits
LimitNOFILE=65535
LimitNPROC=4096
TasksMax=512
# Disable OOM killer (let the app handle it)
OOMPolicy=continue
# Apply drop-in overrides without editing the main unit file
mkdir -p /etc/systemd/system/myapp.service.d/
cat <<'EOF' > /etc/systemd/system/myapp.service.d/limits.conf
[Service]
MemoryMax=1G
CPUQuota=200%
EOF
systemctl daemon-reload
systemctl restart myapp
# View current resource usage for a service
systemctl status myapp # Shows Memory and CPU
systemd-cgtop # Real-time cgroup resource usage
# Edit a service's overrides interactively
systemctl edit myapp
# This creates a drop-in file automatically
Journalctl 日志分析
# Follow logs for a service in real time
journalctl -u myapp -f
# Show logs since last boot
journalctl -u myapp -b
# Show logs for a specific time range
journalctl -u myapp --since "2025-01-15 08:00" --until "2025-01-15 12:00"
# Show only error and above
journalctl -u myapp -p err
# Show the last 100 lines with full messages (no truncation)
journalctl -u myapp -n 100 --no-pager -l
# Show logs in JSON format (for parsing)
journalctl -u myapp -o json-pretty --no-pager | head -50
# Check journal disk usage and vacuum old entries
journalctl --disk-usage
journalctl --rotate
journalctl --vacuum-time=7d
journalctl --vacuum-size=500M
故障排查
| 症状 | 诊断命令 | 常见修复方法 |
|---|---|---|
| 服务无法启动 | systemctl status myapp、journalctl -u myapp -n 50 | 检查 ExecStart 路径、权限和配置语法 |
| 服务不断重启 | journalctl -u myapp --since "5 min ago" | 检查 StartLimitBurst;在日志中查找崩溃信息 |
| "Main process exited, code=exited, status=217" | journalctl -u myapp | 单元文件中的用户或组不存在 |
| "Failed to set up mount namespacing" | 检查 ProtectSystem/PrivateTmp | 内核版本过旧或 SELinux 阻止了操作;放宽相关指令 |
| 定时器未触发 | systemctl list-timers、systemctl status backup.timer | 确保定时器已启用;验证 OnCalendar 表达式 |
| 服务在依赖项之前启动 | 检查 After= 和 Requires= | 添加 After=dependency.service 来指定顺序 |
| 被 OOM 杀死 | journalctl -k | grep oom、dmesg | 增大 MemoryMax 或优化应用内存使用 |
| 无法绑定到端口 80 | 检查 AmbientCapabilities | 添加 CAP_NET_BIND_SERVICE 或使用更高的端口 |
相关技能
linux-administration-- 通用系统管理背景知识performance-tuning-- 内核调优和资源优化user-management-- 服务账户和权限backup-recovery-- 使用 systemd 定时器安排备份
评论
支持 Markdown