5

systemd tmpfiles相关的服务

 2 years ago
source link: http://bean-li.github.io/systemd-tmpfiles/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

systemd tmpfiles相关的服务

首页 分类 标签 留言 关于 订阅

2022-03-18

|

分类 Linux 

|

标签 systmed 

前些日子在排查一个httpd session的问题,发现虚机尽管重启了,但是Firefox浏览器并不logout,机器重启后,Firefox的发送的请求,httpd后台依然会处理。

一般来讲,httpd请求会为每一个client维护一个session,session相关的信息存放位置

  • CentOS:/tmp/systemd-private-5257097ec71448b0aac566695b533a84-httpd.service-dMlTTI/sessions 这种类似的目录
CentOS 版本:
---------------
[root@node-a tmp]# tree systemd-private-5257097ec71448b0aac566695b533a84-httpd.service-dMlTTI
systemd-private-5257097ec71448b0aac566695b533a84-httpd.service-dMlTTI
└── tmp
    └── sessions
        └── 6d474c39c1606792c92f72973c0f135dc07b6682
2 directories, 1 file

注意为什么CentOS版本的session存放在一个systemd-priviate-开头的奇怪目录下。原因是写在httpd的systemd启动脚本中:

[root@node-a system]# cat httpd.service 
[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=man:httpd(8)
Documentation=man:apachectl(8)

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
# We want systemd to give httpd some time to finish gracefully, but still want
# it to kill httpd after TimeoutStopSec if something went wrong during the
# graceful stop. Normally, Systemd sends SIGTERM signal right after the
# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give
# httpd time to finish.
KillSignal=SIGCONT
PrivateTmp=true

[Install]
WantedBy=multi-user.target

注意上面的PrivateTmp=true,这个选项是一个systemd选项,表示该服务会有一个独立的/tmp目录作为自己的/tmp目录,对于httpd而言:

drwx------  3 root root    4096 Mar 18 13:22 systemd-private-5257097ec71448b0aac566695b533a84-httpd.service-dMlTTI
drwx------  3 root root    4096 Mar 18 12:44 systemd-private-5257097ec71448b0aac566695b533a84-ntpd.service-YDlnOF

很多服务都有类似的行为,比如上面的ntpd的service,毫不意外,ntpd的service脚本中也有:

[Unit]
Description=Network Time Service
After=syslog.target ntpdate.service sntp.service

[Service]
Type=forking
EnvironmentFile=-/etc/sysconfig/ntpd
ExecStart=/usr/sbin/ntpd -u ntp:ntp $OPTIONS
PrivateTmp=true

[Install]
WantedBy=multi-user.target

很奇怪的现象是,CentOS的session文件,有以下行为模式:

  • reboot -f时,sessoin并不会被清理 。reboot -f,然后重建集群,发现很多很奇怪的请求到来,并且被后端正常处理。
  • reboot的时候,本次的session文件会被清理,但是历史垃圾的session信息不会被清理。

systemd-tmpfiles 相关的服务

Linux操作系统,会有一些临时存放文件的区域,最典型的就应该是/tmp/目录下,该目录存放的文件,一般为临时存放区,不重要,可损失的文件,正式因为这个区域不那么严肃,所以很多进程或者人,会堆放一些文件在该目录下,如果没有任何服务负责管理,很可能会累积非常多的垃圾文件。

Linux的systemd提供了tmpfiles相关的服务:

[root@node-a system]# systemctl status systemd-tmpfiles-*
● systemd-tmpfiles-clean.service - Cleanup of Temporary Directories
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.service; static; vendor preset: disabled)
   Active: inactive (dead) since Fri 2022-03-18 13:00:01 CST; 1h 14min ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)
  Process: 12340 ExecStart=/usr/bin/systemd-tmpfiles --clean (code=exited, status=0/SUCCESS)
 Main PID: 12340 (code=exited, status=0/SUCCESS)

Mar 18 13:00:01 node-a systemd[1]: Starting Cleanup of Temporary Directories...
Mar 18 13:00:01 node-a systemd[1]: Started Cleanup of Temporary Directories.

● systemd-tmpfiles-clean.timer - Daily Cleanup of Temporary Directories
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.timer; static; vendor preset: disabled)
   Active: active (waiting) since Fri 2022-03-18 12:44:40 CST; 1h 29min ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)

Mar 18 12:44:40 node-a systemd[1]: Started Daily Cleanup of Temporary Directories.

● systemd-tmpfiles-setup-dev.service - Create Static Device Nodes in /dev
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-setup-dev.service; static; vendor preset: disabled)
   Active: active (exited) since Fri 2022-03-18 12:44:35 CST; 1h 29min ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)
  Process: 556 ExecStart=/usr/bin/systemd-tmpfiles --prefix=/dev --create --boot (code=exited, status=0/SUCCESS)
 Main PID: 556 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/systemd-tmpfiles-setup-dev.service

Mar 18 12:44:35 node-a systemd[1]: Starting Create Static Device Nodes in /dev...
Mar 18 12:44:35 node-a systemd[1]: Started Create Static Device Nodes in /dev.

● systemd-tmpfiles-setup.service - Create Volatile Files and Directories
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-setup.service; static; vendor preset: disabled)
   Active: active (exited) since Fri 2022-03-18 12:44:38 CST; 1h 29min ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)
  Process: 805 ExecStart=/usr/bin/systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev (code=exited, status=0/SUCCESS)
 Main PID: 805 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/systemd-tmpfiles-setup.service

Mar 18 12:44:38 node-a systemd[1]: Starting Create Volatile Files and Directories...
Mar 18 12:44:38 node-a systemd[1]: Started Create Volatile Files and Directories.
[root@node-a system]# vim systemd-tmpfiles-clean.service 

清理工作一般分成两类:

  • 开机启动时的清理
    • systemd-tmpfiles-setup.service
    • systemd-tmpfiles-setup-dev.service
  • Linux正常运行期间的清理
    • systemd-tmpfiles-clean.timer

开机清理,这个是比较容易理解,开机的时候,可能所有服务都没有启动,上一轮机器运行阶段,可能产生了不少垃圾文件,或者没来得及清理的文件(比如异常掉电或者reboot -f),需要对具体的目录做一些清理动作。

另外一个就是长时间运行状态下,也要有服务负责清理,因为Linux服务器一般不喜欢关机,我们也有很多机器线上运行时间1000天以上,完全指望开机清理,可能势必垃圾文件堆积成山。

我们一起看下sytemd-tmpfiles-setup.service配置文件的内容:

[Unit]
Description=Create Volatile Files and Directories
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
DefaultDependencies=no
Conflicts=shutdown.target
After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target systemd-sysusers.service
Before=sysinit.target shutdown.target
RefuseManualStop=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev

该文件可以看到,主要是调用一个名称为/usr/bin/systemd-tmpfiles的可执行文件,传了一些参数。sytemd-tmpfiles有一些参数值得我们注意:

  • create:

    • If this option is passed, all files and directories marked with f, F, w, d, D, v, p, L, c, b, m in the configuration files are created
                 or written to. Files and directories marked with z, Z, t, T, a, and A have their ownership, access mode and security labels set.
      
  • remove

    • If this option is passed, the contents of directories marked with D or R, and files or directories themselves marked with r or R are removed.
      
  • clean

    • If this option is passed, all files and directories with an age parameter configured will be cleaned up.
      
    • Also execute lines with an exclamation mark. (带感叹号的行, --boot才会执行)
      

boot最好理解,正常运行期间和重启刚开机是又分别的,有些目录,开机阶段可以粗暴删除,但是正常运行期间不能太粗暴,因为你可能没有办法确定,该文件或者目录是否还在被使用。因此后面配置文件会有区分的手段,剧透一下就是 action后面加感叹号,就是只有boot阶段才应该执行,正常运行期间,本条配置可以忽略。

systemd-tmpfiles 的可配置性

我们讲了很多了,但是到底如何告知systemd那些文件可以被清理,可被清理的文件又遵循什么样的策略呢?这个地方就到了配置文件部分了。

配置文件的名称必须符合 package.confpackage-part.conf格式。 当需要明确的将某部分(part)配置提取出来,以方便用户专门针对这部分进行修改的时候, 应该使用第二种命名格式。

对于不同目录下的同名配置文件,仅以优先级最高的目录中的那一个为准。具体说来就是: /etc/tmpfiles.d 的优先级最高、 /run/tmpfiles.d 的优先级居中、 /usr/lib/tmpfiles.d 的优先级最低。 软件包应该将自带的配置文件安装在 /usr/lib/tmpfiles.d 目录中, 而 /etc/tmpfiles.d 目录仅供系统管理员使用。 所有的配置文件,无论其位于哪个目录中,都统一按照文件名的字典顺序处理。 如果在多个配置文件中设置了同一个路径(文件或目录),那么仅以文件名最靠前(字典顺序)的那一个为准, 其他针对同一个路径的配置项将会作为警告信息记录到错误日志中。 如果有两行的路径互为前后缀,那么始终是先创建前缀行、再创建后缀行, 如果还需要删除,那么顺序正好相反,始终是先删除后缀行、再删除前缀行。 所有带有shell风格通配符的行,都在所有不带通配符的行之后处理。如果有多个操作符应用于同一个文件(例如 ACL, xattr, 文件属性调整),那么将始终按固定的顺序操作。除上述清空之外,对于其他情况, 文件与目录总是按照它们在配置文件中出现的顺序处理。

[root@node-a system]# cd /usr/lib/tmpfiles.d/
[root@node-a tmpfiles.d]# ll
total 132
-rw-r--r--. 1 root root   29 Mar 16 04:33 ceph-common.conf
-rw-r--r--. 1 root root   35 Apr  1  2020 cryptsetup.conf
-rw-r--r--. 1 root root   26 Mar 16 05:02 ctdb.conf
-rw-r--r--. 1 root root   67 Dec 11 08:32 elasticsearch.conf
-rw-r--r--. 1 root root  464 Nov 17  2020 etc.conf
-rw-r--r--. 1 root root   77 Nov 16  2020 httpd.conf
-rw-r--r--. 1 root root   39 Nov 17  2020 initscripts.conf
-rw-r--r--. 1 root root   75 Dec 15  2020 iscsi.conf
-rw-r--r--. 1 root root 1181 Nov 17  2020 legacy.conf
-rw-r--r--. 1 root root   34 Apr  1  2020 libselinux.conf
-r--r--r--. 1 root root   61 Dec 16  2020 lvm2.conf
-rw-r--r--. 1 root root   34 Oct  1  2020 mdadm.conf
-rw-r--r--. 1 root root   35 Jan 22  2021 net-snmp.conf
-rw-r--r--. 1 root root   27 Sep 30  2020 nscd.conf
-rw-r--r--. 1 root root  104 Sep 30  2020 nss-pam-ldapd.conf
-rw-r--r--. 1 root root   85 Oct  1  2020 openldap.conf
-rw-r--r--. 1 root root  110 Apr  1  2020 pam.conf
-rw-r--r--. 1 root root   15 Apr 10  2017 proftpd.conf
-rw-r--r--. 1 root root   16 Nov 17  2020 python.conf
-rw-r--r--. 1 root root   42 Nov 17  2020 resource-agents.conf
-rw-r--r--. 1 root root   87 Apr  1  2020 rpcbind.conf
-rw-r--r--. 1 root root   22 Oct  1  2020 rpm.conf
-rw-r--r--. 1 root root   60 Mar 16 05:02 samba.conf
-rw-r--r--. 1 root root  228 Nov 17  2020 sap.conf
-rw-r--r--. 1 root root   72 Oct  1  2020 screen.conf
-rw-r--r--. 1 root root  137 Nov 17  2020 selinux-policy.conf
-rw-r--r--. 1 root root  305 Jan 27  2021 sudo.conf
-rw-r--r--. 1 root root 1662 Nov 17  2020 systemd.conf
-rw-r--r--. 1 root root  496 Nov 17  2020 systemd-nologin.conf
-rw-r--r--. 1 root root  638 Nov 17  2020 tmp.conf
-rw-r--r--. 1 root root   56 Mar 22  2019 tuned.conf
-rw-r--r--. 1 root root  563 Nov 17  2020 var.conf
-rw-r--r--. 1 root root  623 Nov 17  2020 x11.conf
[root@node-a tmpfiles.d]# 
[root@node-a tmpfiles.d]# cd /etc/tmpfiles.d/
[root@node-a tmpfiles.d]# ll
total 0
[root@node-a tmpfiles.d]# 

主要的配置文件都被存放在/etc/tmpfiles.d和 /usr/lib/tmpfiles.d/下。其中/usr/lib/tmpfiles.d下可以看到有形形色色的配置文件。Ubuntu版本的产品比较神器,可以自动清理/tmp/sessions下的文件,甚至整个/tmp/sessions都被删除,我们看下配置文件:

root@CVM01:/usr/lib/tmpfiles.d# cat tmp.conf 
D /tmp 1777 root root -
#q /var/tmp 1777 root root 30d

# Exclude namespace mountpoints created with PrivateTmp=yes
x /tmp/systemd-private-%b-*
X /tmp/systemd-private-%b-*/tmp
x /var/tmp/systemd-private-%b-*
X /var/tmp/systemd-private-%b-*/tmp

这里除了我们比较熟悉的路径意外,有写D x X之类的奇奇怪怪的字母,这些何意?

systemd-tmpfiles 配置语法

tmpfiles.d 配置文件定义了一套临时文件管理机制: 创建 文件、目录、管道、设备节点, 调整访问模式、所有者、属性、限额、内容, 删除过期文件。 主要用于管理易变的临时文件与目录,例如 /run, /tmp, /var/tmp, /sys, /proc, 以及 /var 下面的某些目录

配置文件的格式是每行对应一个路径,包含如下字段: 类型, 路径, 权限, 属主, 属组, 寿命, 参数

#Type Path        Mode User Group Age Argument
d     /run/user   0755 root root  10d -
L     /tmp/foobar -    -    -     -   /dev/null

字段值可以用引号界定,并可以包含C风格的转义字符

然后就到了奇奇怪怪的字母部分了,因为它支持的Type太多了,我就一一罗列的,否则也记不住,我重点介绍常用的,如果需要了解细节的,可以阅读 金步国的文章

  • d 创建指定的目录并赋于指定的User/Group与权限。如果指定的目录已经存在,那么仅调整User/Group与权限。 如果指定了”寿命”字段,那么该目录中的内容将遵守基于时间的清理策略。
  • D 与 d 类似, 但是如果使用了 --remove 选项,那么将会清空目录中的所有内容。

注意此处, 我们看下Ubuntu的tmp.conf配置文件里面的一行:

D /tmp 1777 root root -

这一行毁天灭地,如果有印象的话,systemd-tmpfiles-setup.service执行的是:

ExecStart=/usr/bin/systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev

这会将/tmp/下的所有东西一扫而空。但是Ubuntu版本有些人会说,没有,启动之后/tmp/目录下还有文件。这些文件是重启之后创建出来的。因此我们就明白了为什么Ubuntu下,/tmp/sessions会被清理,因为实时上不仅它会被清理,整个/tmp/都会被清理。

  • x 根据”寿命”字段清理过期文件时, 忽略指定的路径及该路径下的所有内容。 可以在”路径”字段中使用shell风格的通配符。 注意, 这个保护措施对 rR 无效。
  • R 在根据”寿命”字段清理过期文件时, 仅忽略指定的路径自身而不包括该路径下的其他内容。 可以在”路径”字段中使用shell风格的通配符。 注意, 这个保护措施对 rR 无效。

这两个是额外的保护,即按照时间线来清理的时候,免死金牌,不被清理。但是这个保护措施对后面提到的r和R无效

  • r 若指定的文件或目录存在, 则删除它。 不可用于非空目录。 可以在”路径”字段中使用shell风格的通配符。 不追踪软连接。
  • R 若指定的文件或目录存在,则递归的删除它。 可用于非空目录。 可以在”路径”字段中使用shell风格的通配符。 不追踪软连接。

这两个删除指令,R可递归,r不可。支持通配符。我们欣赏下Ubuntu 20.04版本里的systemd-tmp.conf

# Exclude namespace mountpoints created with PrivateTmp=yes
x /tmp/systemd-private-%b-*
X /tmp/systemd-private-%b-*/tmp
x /var/tmp/systemd-private-%b-*
X /var/tmp/systemd-private-%b-*/tmp

# Remove top-level private temporary directories on each boot
R! /tmp/systemd-private-*
R! /var/tmp/systemd-private-*

上面赦免不用说了,正常清理过程中,不要按照时间清理/tmp/systemd-private/打头的文件。但是后面R!表示机器重启期间,要将上述文件彻底删除,防止留下垃圾。

使用了感叹号(!)标记的行,仅可在系统启动过程中执行, 而不能用于运行中的系统(会破坏系统的正常运行)。 未使用感叹号(!)标记的行, 可以在任意时间安全的执行(例如升级软件包的时候)。 systemd-tmpfiles 仅在明确使用了 --boot 选项的时候 才会执行使用了感叹号(!)标记的行。

分析CentOS版本的行为

# Clear tmp directories separately, to make them easier to override
v /tmp 1777 root root 10d
v /var/tmp 1777 root root 30d

# Exclude namespace mountpoints created with PrivateTmp=yes
x /tmp/systemd-private-%b-*
X /tmp/systemd-private-%b-*/tmp
x /var/tmp/systemd-private-%b-*
X /var/tmp/systemd-private-%b-*/tmp

啥也不说了。根本就不清理 /tmp/system-private-文件。

如何调试systemd-tmpfiles

env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --clean

这种方式比较详细,会把中间的判断过程也打印出来,如果清理行为不理解的话,可以用这个方法,看下为什么行为和自己理解的不一样。

[root@node-a tmpfiles.d]# env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --clean
Reading config file "/usr/lib/tmpfiles.d/ceph-common.conf".
Reading config file "/usr/lib/tmpfiles.d/cryptsetup.conf".
Reading config file "/usr/lib/tmpfiles.d/ctdb.conf".
Reading config file "/usr/lib/tmpfiles.d/elasticsearch.conf".
Reading config file "/usr/lib/tmpfiles.d/etc.conf".
Reading config file "/usr/lib/tmpfiles.d/httpd.conf".
Reading config file "/usr/lib/tmpfiles.d/initscripts.conf".
Reading config file "/usr/lib/tmpfiles.d/iscsi.conf".
Reading config file "/run/tmpfiles.d/kmod.conf".
Ignoring entry c! "/dev/fuse" because --boot is not specified.
Ignoring entry c! "/dev/cuse" because --boot is not specified.
Ignoring entry c! "/dev/btrfs-control" because --boot is not specified.
Ignoring entry c! "/dev/loop-control" because --boot is not specified.
Ignoring entry c! "/dev/net/tun" because --boot is not specified.
Ignoring entry c! "/dev/ppp" because --boot is not specified.
Ignoring entry c! "/dev/uinput" because --boot is not specified.
Ignoring entry c! "/dev/mapper/control" because --boot is not specified.
Ignoring entry c! "/dev/uhid" because --boot is not specified.
Ignoring entry c! "/dev/vfio/vfio" because --boot is not specified.
Ignoring entry c! "/dev/vhci" because --boot is not specified.
Ignoring entry c! "/dev/vhost-net" because --boot is not specified.
....

如果带上参数 –boot 和–remove,模拟的基本就是开机启动时的清理逻辑:

env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --clean

参考文献:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK