2
2
2014
7

玩转 systemd 之用户级服务管理

本文来自依云's Blog,转载请注明。

前几日群里又有人提到使用 systemd 管理用户的守护进程。早些时候我就知道有设计这么个功能,然调用systemctl --user时却总是跑去执行/bin/false,然后告诉我执行失败 QAQ

既然提到,就再试试呗。没想到这次systemctl --user列出一大堆 unit!还没弄明白它是哪里来的,不过至少说明systemctl --user已经可以用了!于是尝试性地把几个不依赖 X 的服务改成 systemd 服务了。至于依赖 X 的就不要 systemd 管了,我自己写在 Awesome 配置里,毕竟它们属于这个 X 会话,独立性没那么强,也免得纠结 DISPLAY 环境变量的问题。

我的 systemd 版本是 208。大概以前的版本确实有些问题,现在已经弄好了。

systemd 的用户配置位于~/.confg/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
Category: Linux | Tags: systemd linux | Read Count: 12335
Avatar_small
views63 说:
Feb 03, 2014 08:44:00 AM

早期 arch 刚转到 systemd 的时候,systemctl networkmanager 起不来后,我就放弃 arch 了,现在是什么情况了?

Avatar_small
依云 说:
Feb 04, 2014 08:45:07 PM

我不用 NetworkManager。我还没遇到起不来的服务。

Avatar_small
views63 说:
Feb 09, 2014 11:15:26 AM

当时 systemctl networkmanager 提示 networkmanager 不存在,去看一下,真的是空的。模仿写了一个结果不能用,遂放弃。

Avatar_small
依云 说:
Feb 10, 2014 04:55:31 PM

查了一下,那个叫 NetworkManager 啊……

Avatar_small
views63 说:
Feb 12, 2014 05:02:42 PM

我都去目录看了整个是空的。也不知道是我当时安装哪里有问题了,总之结果就是那样,所以放弃了。

Avatar_small
依云 说:
Feb 12, 2014 08:31:09 PM

目录? /lib/systemd/system 么?怎么可能是空的……

Avatar_small
views63 说:
Feb 17, 2014 01:19:58 PM

很久的事情了。我也忘了具体是什么目录,结局就是那样。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

部分静态文件存储由又拍云存储提供。 | Theme: Aeros 2.0 by TheBuckmaker.com