本文来自依云's Blog,转载请注明。
前几日群里又有人提到使用 systemd 管理用户的守护进程。早些时候我就知道有设计这么个功能,然调用systemctl --user
时却总是跑去执行/bin/false
,然后告诉我执行失败 QAQ
既然提到,就再试试呗。没想到这次systemctl --user
列出一大堆 unit!还没弄明白它是哪里来的,不过至少说明systemctl --user
已经可以用了!于是尝试性地把几个不依赖 X 的服务改成 systemd 服务了。至于依赖 X 的就不要 systemd 管了,我自己写在 Awesome 配置里,毕竟它们属于这个 X 会话,独立性没那么强,也免得纠结 DISPLAY 环境变量的问题。
我的 systemd 版本是 208。大概以前的版本确实有些问题,现在已经弄好了。
systemd 的用户配置位于~/.config/systemd/user
、/lib/systemd/user
和/etc/systemd/user
下。我当然是用「家」里的那个了。
我改写的这些服务之前大部分是在 tmux 里跑的,除了占用 tmux 窗口外还占用个 zsh。现在全部改写成 systemd 服务了,于是 tmux 那边干净了不少 =w=
比如这个:
[Unit] Description=Privoxy Web Proxy With Advanced Filtering Capabilities ConditionPathIsDirectory=%h/.privoxy [Service] Type=simple PIDFile=/run/user/%U/privoxy.pid SyslogFacility=local0 ExecStart=/usr/bin/privoxy --pidfile /run/user/%U/privoxy.pid --no-daemon %h/.privoxy/config [Install] WantedBy=default.target
可以看到,systemd 里写起要执行什么命令还是挺简陋的。毕竟它不调用 shell 的,于是环境变量都用不了,家目录的位置也要写成%h
,%U
则是用户 ID。令我不解的是,执行的命令和#!
里的一样,必须使用绝对路径,而不能只写个名字,依赖 $PATH 环境变量去寻找。于是就有这样丑陋的ExecStart
了——
ExecStart=/bin/zsh -c "exec sslocal -s HOST -p PORT -l LOCALPORT -k PASSWORD -m METHOD -c <(echo {})"
至于那个SyslogFacility
,是为了在 syslog-ng 的日志中不显示出来而定义的,这样就可以根据 facility 来过滤掉这些用户级服务的日志了。
还有个SyslogIdentifier
也挺好用的。systemd 默认使用ExecStart
里第一个字的文件名部分来作为日志的标识,于是在系统日志(syslog 和 journald)中就看到一堆 sh 以及一些 zsh 和 socat,没区分度了……于是写明 SyslogFacility 来赋予其一个更合理的名字。
systemd 用户级服务使用systemctl --user
来管理,其它的和系统级的差不多,也是 enable / start / disable / stop / status 这些。当然 daemon-reload 命令会频繁地使用啦 :-)
查看 journald 日志却有些不同,也是加--user
,但是查看某个服务的日志输出却不是-u SERVICE
了。有个--user-unit NAME
参数,但是它会只显示 systemd 启动的进程的日志,而没有 systemd 自己处理该服务时的日志了……通过阅读日志的 JSON 格式输出(-o json-pretty
),终于弄了个比较理想的方案。以下是我在 zshrc 里的相关配置(zsh only 哦):
alias sysuser="systemctl --user" function juser () { # sadly, this won't have nice completion typeset -a args integer nextIsService=0 for i; do if [[ $i == -u ]]; then nextIsService=1 args=($args _SYSTEMD_CGROUP=/user.slice/user-$UID.slice/user@$UID.service/) else if [[ $nextIsService -eq 1 ]]; then nextIsService=0 args[$#args]="${args[$#args]}$i.service" else args=($args $i) fi fi done journalctl -n --user ${^args} }
加-n
是因为默认全部输出,一下子跳到后边的日志时就太卡了,但是只输出最后一部分日志就挺快的。默认是十行,也可以接数字来指定数量。指定多次时最后一次生效,所以我问题把它写进去也不怎么影响手动指定的情况。
于是管理用户级服务时我就用sysuser ...
,而要看某个服务的日志时就用juser -u xxx
。
因为我使用 eCryptfs 加密了主目录,所以还遇到一个问题:用户级的 systemd 进程是通过 PAM 启动的,而这启动的时候我的主目录还没解密呢。于是 systemd 没有读取到我的配置,没有自动启动任何服务……于是只好在~/.profile
里加两行,在挂载之后告诉 systemd 一声:
if [ -r "$HOME/.ecryptfs/auto-mount" ]; then grep -qs "$HOME ecryptfs" /proc/mounts if [ $? -ne 0 ]; then mv $HOME/.Xauthority /tmp 2>/dev/null mount -i "$HOME" cd "$HOME" mv /tmp/.Xauthority $HOME 2>/dev/null systemctl --user daemon-reload systemctl --user default fi fi
Feb 03, 2014 08:44:00 AM
早期 arch 刚转到 systemd 的时候,systemctl networkmanager 起不来后,我就放弃 arch 了,现在是什么情况了?
Feb 04, 2014 08:45:07 PM
我不用 NetworkManager。我还没遇到起不来的服务。
Feb 09, 2014 11:15:26 AM
当时 systemctl networkmanager 提示 networkmanager 不存在,去看一下,真的是空的。模仿写了一个结果不能用,遂放弃。
Feb 10, 2014 04:55:31 PM
查了一下,那个叫 NetworkManager 啊……
Feb 12, 2014 05:02:42 PM
我都去目录看了整个是空的。也不知道是我当时安装哪里有问题了,总之结果就是那样,所以放弃了。
Feb 12, 2014 08:31:09 PM
目录? /lib/systemd/system 么?怎么可能是空的……
Feb 17, 2014 01:19:58 PM
很久的事情了。我也忘了具体是什么目录,结局就是那样。
Jun 11, 2023 08:44:43 PM
>systemd 的用户配置位于~/.confg/systemd/user
s/.confg/.config/g
Jun 12, 2023 11:28:25 AM
已修正,喵~