2019年7月27日土曜日

RHEL8 の sysstat の採取周期を 1 分毎に変更

RHEL8/CentOS8 では、sysstat のデフォルト採取周期を 10分 から 1分 に変更する方法が変更になっています。RHEL7 以下では cron を利用していたものが、systemd.timer ベースに変更されてしまったためです。RHEL7 以下のように簡単ではないので、備忘録として書いておこうと思います。

sysstat-collect.timer に修正を加えるのですが、sysstat パッケージの更新のことを考えると /var/lib/systemd/system 下のファイルを直接書き換えるのではなくて、systemctl edit を使ったほうが良いものと思います。
[root@hoge ~]# EDITOR=vim systemctl edit sysstat-collect.timer
[Unit]
Description=Run system activity accounting tool every 1 minutes

[Timer]
OnCalendar=  ※必要
OnCalendar=*:*:01
AccuracySec=0
上記のように入力して書き込みます。デフォルトのエディタは vim にしてくれって思いますが、いたしかたない。
[root@hoge ~]# systemctl cat sysstat-collect.timer
# /usr/lib/systemd/system/sysstat-collect.timer
# /usr/lib/systemd/system/sysstat-collect.timer
# (C) 2014 Tomasz Torcz 
#
# sysstat-11.7.3 systemd unit file:
#        Activates activity collector every 10 minutes

[Unit]
Description=Run system activity accounting tool every 10 minutes

[Timer]
OnCalendar=*:00/10

[Install]
WantedBy=sysstat.service

# /etc/systemd/system/sysstat-collect.timer.d/override.conf
[Unit]
Description=Run system activity accounting tool every 1 minutes

[Timer]
OnCalendar=
OnCalendar=*:*:01
AccuracySec=0
[root@hoge ~]# systemctl status sysstat-collect.timer
* sysstat-collect.timer - Run system activity accounting tool every 1 minutes
   Loaded: loaded (/usr/lib/systemd/system/sysstat-collect.timer; enabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/sysstat-collect.timer.d
           `-override.conf
   Active: active (waiting) since Sat 2019-07-27 21:19:18 JST; 14min ago
  Trigger: Sat 2019-07-27 21:35:00 JST; 41s left

Jul 27 21:19:18 hoge systemd[1]: Started Run system activity accounting tool every 1 minutes.
[root@hoge ~]# sar
Linux 4.18.0-80.el8.x86_64 (hoge)  07/27/19  _x86_64_ (2 CPU)

21:19:18     LINUX RESTART (2 CPU)

21:20:01        CPU     %user     %nice   %system   %iowait    %steal     %idle
21:21:01        all      0.08      0.00      0.14      0.04      0.00     99.73
21:22:01        all      0.03      0.00      0.09      0.02      0.00     99.86
21:23:01        all      0.05      0.00      0.09      0.04      0.00     99.82
21:24:01        all      0.03      0.00      0.12      0.03      0.00     99.82
21:25:01        all      0.21      1.54      0.83      0.35      0.02     97.05
21:26:01        all      0.03      0.00      0.08      0.04      0.00     99.84
21:27:01        all      0.03      0.00      0.08      0.01      0.00     99.87
21:28:01        all      0.03      0.00      0.08      0.00      0.00     99.88
21:29:01        all      0.03      0.00      0.08      0.05      0.00     99.84
21:30:01        all      0.10      0.30      0.18      0.18      0.00     99.24
21:31:01        all      0.03      0.00      0.07      0.01      0.00     99.90
21:32:01        all      0.03      0.00      0.08      0.03      0.01     99.85
21:33:01        all      0.14      0.00      0.17      0.03      0.01     99.65
21:34:01        all      0.03      0.00      0.09      0.03      0.00     99.85
Average:        all      0.06      0.13      0.16      0.06      0.00     99.59
なんだかなあ。cron で ええやんか と思うのですがねえ、messages にも余計なメッセージが大量に出てしまうし。
[root@hoge ~]# less /var/log/messages
...
Jul 27 21:33:01 hoge systemd[1]: Starting system activity accounting tool...
Jul 27 21:33:01 hoge systemd[1]: Started system activity accounting tool.
Jul 27 21:34:01 hoge systemd[1]: Starting system activity accounting tool...
Jul 27 21:34:01 hoge systemd[1]: Started system activity accounting tool.
...
これらが不要(要るっていう人は居るの?)なら、以前書いた記事を応用して rsyslog でフィルタすれば良いものと思いますが、あーめんどくさい。rsyslog なんてやめて journal で運用すればいいって、開発者の人は思ってるのでしょうけれど、世の中そう急には変わらない。/var/log/messages は必要とされているだろうと思います。きっと。

2019-09-18追記
1点間違えていましたので、訂正しました。
override.confの[timer]セクションで、OnCalendar=*:*:01 の前には、もう一つ OnCalendar= が必要でした。そうしないと、デフォルトの OnCalendar=*:00/10 も有効として扱われるようです。風変わりな書き方ですが、実装を想像するとそうなるか、という記法だと思いました。

2019年7月22日月曜日

CentOS 7 の root ファイルシステムに ZFS を使う

3年ほど前に、CentOS 6 の root ファイルシステムに ZFS を使う方法について書きました。
CentOS 6 の root ファイルシステムに ZFS を使う
当時設定したサーバは、最新の v0.8.1 にアップデートして、今も動かしています。3年間の運用中、カーネルアップデートや ZFS のアップデートの際、何回か起動できなくなり snapshot から rollback したことがありましたが、ZFS の高い信頼性(格納データに対するチェックサム、mirror構成による自己修復)を活用できたと思っています。
しかし、CentOS 7 については Btrfs raid1 が使えたので、そちらを使って構築していました。カーネルアップデートが ZFS よりは容易であるという利点があります。信頼性はおそらく ZFS のほうが上かも。

さて、Red Hat が Btrfs を見限った(フルサポート開始をあきらめて RHEL8 から削除)ということもあり、最近になって CentOS 7 の root ファイルシステムに ZFS を使うようになりました。ところが、、、最新の zfs-dracut には問題があるようです。v0.7.13 で動作していた環境を v0.8.1 にアップデートしたら起動できなくなってしまいました。
https://github.com/zfsonlinux/zfs/issues/8913
たぶんこれが、対応していると思われます。まもなく直るでしょう。
zfs-dracut っていうのは、要するに dracut のフレームワークに乗っかって、ZFS root をマウントしてくれるだけだし、最新のスクリプトでなくてもよいと思えるので、snapshot 中の古い /usr/lib/dracut/modules.d/90zfs/ をコピーして、initramfs を再作成したら起動できました。rd.break=pre-mount で、起動を中断させてシェルに落し、次のような手順で initramfs を再作成しました。応急処置です。
# zpool import rpool
# mkdir /mnt_temp
# mount -t zfs rpool/ROOT /mnt_temp
# mkdir /mnt_temp2
# mount -t zfs -o ro rpool/ROOT@2019-04-23-0312 /mnt_temp2
# cp -rp /mnt_temp2/usr/lib/dracut/modules.d/90zfs/ /mnt_temp/usr/lib/dracut/modules.d/
# mount -t proc proc /mnt_temp/proc
# mount -t devtmpfs devtmpfs /mnt_temp/dev
# mount -t devpts devpts /mnt_temp/dev/pts
# mount -t sysfs sysfs /mnt_temp/sys
# chroot /mnt_temp
# dracut -f /boot/initramfs-3.10.0-957.21.3.el7.x86_64.img 3.10.0-957.21.3.el7.x86_64
次は、現在の稼動状態です。ThinkPad 25 の NVMe から UEFI ブートしています。
[root@hoge ~]# df -hT /
ファイルシス   タイプ サイズ  使用  残り 使用% マウント位置
rpool/ROOT     zfs       26G  7.7G   18G   31% /
[root@hoge ~]# cat /proc/cmdline 
BOOT_IMAGE=/ROOT@/boot/vmlinuz-3.10.0-957.21.3.el7.x86_64 root=ZFS=rpool/ROOT ro crashkernel=auto elevator=deadline vconsole.keymap=jp106 int_pln_enable=1 efi=old_map
[root@hoge ~]# grep linuxefi /boot/efi/EFI/centos/grub.cfg
 linuxefi /ROOT@/boot/vmlinuz-3.10.0-957.21.3.el7.x86_64 root=ZFS=rpool/ROOT ro crashkernel=auto elevator=deadline vconsole.keymap=jp106 int_pln_enable=1 efi=old_map 
 linuxefi /ROOT@/boot/vmlinuz-0-rescue-27a0bb3862794c69a2c05249c5e54c36 root=ZFS=rpool/ROOT ro crashkernel=auto elevator=deadline vconsole.keymap=jp106 int_pln_enable=1 efi=old_map 
[root@hoge ~]# grep ^GRUB_CMD /etc/default/grub 
GRUB_CMDLINE_LINUX="crashkernel=auto elevator=deadline vconsole.keymap=jp106 int_pln_enable=1 efi=old_map"
[root@hoge ~]# zpool status
  pool: rpool
 state: ONLINE
status: Some supported features are not enabled on the pool. The pool can
 still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
 the pool may no longer be accessible by software that does not support
 the features. See zpool-features(5) for details.
  scan: scrub repaired 0B in 0 days 00:00:20 with 0 errors on Sat Jul 20 00:58:48 2019
config:

 NAME         STATE     READ WRITE CKSUM
 rpool        ONLINE       0     0     0
   nvme0n1p5  ONLINE       0     0     0

errors: No known data errors
[root@hoge ~]# zfs get all -s local
NAME                        PROPERTY              VALUE                    SOURCE
rpool                       compression           lz4                      local
rpool                       relatime              on                       local
rpool/ROOT                  mountpoint            legacy                   local
rpool/ROOT                  compression           lz4                      local
rpool/ROOT                  acltype               posixacl                 local
これは、実験的な環境ですが、この他にサーバを1台 ZFS mirror で動かしています。

CentOS 7 で ZFS root 環境を作る手順については、こちら にまとめられています。thanks

2019-11-27追記
書き忘れていましたが、カーネルをアップデートした場合に、grub.cfg の自動更新が失敗するので、手動で grub2-mkconfig を行う必要があります。
  インストール中          : kernel-3.10.0-1062.4.3.el7.x86_64
grubby fatal error: unable to find a suitable template
  更新します              : sudo-1.8.23-4.el7_7.1.x86_64
というメッセージが出て、grub.cfg に新しいエントリーが追加されません。
[root@hoge ~]# grep 3.10.0 /boot/efi/EFI/centos/grub.cfg
menuentry 'CentOS Linux (3.10.0-1062.4.1.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-1062.4.1.el7.x86_64-advanced-8c823f06e4556631' {
        linuxefi /ROOT@/boot/vmlinuz-3.10.0-1062.4.1.el7.x86_64 root=ZFS=rpool/ROOT ro crashkernel=auto elevator=deadline vconsole.keymap=jp106 int_pln_enable=1 psmouse.synaptics_intertouch=1
        initrdefi /ROOT@/boot/initramfs-3.10.0-1062.4.1.el7.x86_64.img
[root@hoge ~]# grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
Generating grub configuration file ...
Linux イメージを見つけました: /boot/vmlinuz-3.10.0-1062.4.3.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1062.4.3.el7.x86_64.img
Linux イメージを見つけました: /boot/vmlinuz-3.10.0-1062.4.1.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1062.4.1.el7.x86_64.img
Linux イメージを見つけました: /boot/vmlinuz-0-rescue-27a0bb3862794c69a2c05249c5e54c36
Found initrd image: /boot/initramfs-0-rescue-27a0bb3862794c69a2c05249c5e54c36.img
完了
[root@hoge ~]# grep 3.10.0 /boot/efi/EFI/centos/grub.cfg
menuentry 'CentOS Linux (3.10.0-1062.4.3.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-1062.4.3.el7.x86_64-advanced-8c823f06e4556631' {
        linuxefi /ROOT@/boot/vmlinuz-3.10.0-1062.4.3.el7.x86_64 root=ZFS=rpool/ROOT ro crashkernel=auto elevator=deadline vconsole.keymap=jp106 int_pln_enable=1 psmouse.synaptics_intertouch=1
        initrdefi /ROOT@/boot/initramfs-3.10.0-1062.4.3.el7.x86_64.img
menuentry 'CentOS Linux (3.10.0-1062.4.1.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-1062.4.1.el7.x86_64-advanced-8c823f06e4556631' {
        linuxefi /ROOT@/boot/vmlinuz-3.10.0-1062.4.1.el7.x86_64 root=ZFS=rpool/ROOT ro crashkernel=auto elevator=deadline vconsole.keymap=jp106 int_pln_enable=1 psmouse.synaptics_intertouch=1
        initrdefi /ROOT@/boot/initramfs-3.10.0-1062.4.1.el7.x86_64.img
if [ "x$default" = 'CentOS Linux (3.10.0-1062.4.1.el7.x86_64) 7 (Core)' ]; then default='Advanced options for CentOS Linux>CentOS Linux (3.10.0-1062.4.1.el7.x86_64) 7 (Core)'; fi;
[root@hoge ~]# 

2019-12-25追記
前述の grubby のエラーについて探究していませんでしたが、調べてみると単純な話しでした。まず、/var/log/grubby というログファイルが存在することがわかったので見てみたら、次のような出力になっていました。
[root@hoge ~]# cat /var/log/grubby
...
DBG: 1894: Wed Dec 25 04:39:43 2019: command line: --grub2 -c /boot/efi/EFI/centos/grub.cfg --efi --add-kernel=/boot/vmlinuz-3.10.0-1062.9.1.el7.x86_64 --copy-default --title CentOS Linux (3.10.0-1062.9.1.el7.x86_64) 7 (Core) --args=root=ZFS=rpool/ROOT  --remove-kernel=TITLE=CentOS Linux (3.10.0-1062.9.1.el7.x86_64) 7 (Core) --make-default
DBG: Image entry failed: access to /ROOT@/boot/vmlinuz-3.10.0-1062.4.3.el7.x86_64 failed
DBG: menuentry 'CentOS Linux (3.10.0-1062.4.3.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-1062.4.3.el7.x86_64-advanced-8c823f06e4556631' { 
DBG:  load_video
DBG:  set gfxpayload=keep
DBG:  insmod gzio
DBG:  insmod part_gpt
DBG:  insmod zfs
DBG:  if [ x$feature_platform_search_hint = xy ]; then
DBG:    search --no-floppy --fs-uuid --set=root  8c823f06e4556631
DBG:  else
DBG:    search --no-floppy --fs-uuid --set=root 8c823f06e4556631
DBG:  fi
DBG:  linuxefi /ROOT@/boot/vmlinuz-3.10.0-1062.4.3.el7.x86_64 root=ZFS=rpool/ROOT ro crashkernel=auto elevator=deadline vconsole.keymap=jp106 int_pln_enable=1 psmouse.synaptics_intertouch=1 
DBG:  initrdefi /ROOT@/boot/initramfs-3.10.0-1062.4.3.el7.x86_64.img
DBG: }
DBG: Image entry failed: access to /ROOT@/boot/vmlinuz-0-rescue-27a0bb3862794c69a2c05249c5e54c36 failed
DBG: menuentry 'CentOS Linux (0-rescue-27a0bb3862794c69a2c05249c5e54c36) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-27a0bb3862794c69a2c05249c5e54c36-advanced-8c823f06e4556631' { 
DBG:  load_video
...
ZFS 特有の /ROOT@/boot という記法を解釈できないために、vmlinuz のパスを正しく認識できず、エラーになるようです。つまり、安直にはシンボリックリンクでも張ればよいと思われます。
[root@hoge ~]# ln -s / /ROOT\@
[root@hoge ~]# ls -l / | grep ROOT
lrwxrwxrwx    1 root root    1 12月 25 06:00 ROOT@ -> /
[root@hoge ~]# ls -l /ROOT@/boot/vmlinuz-3.10.0-1062.9.1.el7.x86_64 
-rwxr-xr-x 1 root root 6734016 12月  7 00:53 /ROOT@/boot/vmlinuz-3.10.0-1062.9.1.el7.x86_64
[root@hoge ~]# 
これでうまくいくかどうかは、次回のアップデートカーネルが出て来たときに確認しようと思います。
思わず grubby のソースまで見てしまいましたが、ZFS の場合だけ特別に扱うようなコードは受け入れられそうにないかなと思いました。

2019年7月21日日曜日

bash でシグナル trap 中に更にシグナルを受けたらどうなるか?

bash でシグナル trap 中に更にシグナルを受けたらどうなるか? を確認したいと思い、実験してみました。
#!/bin/bash

SELF_PID=$$

sig_HUP_handler() {
        echo caught SIGHUP
        kill -TERM $SELF_PID
}

trap "echo caught SIGTERM ; exit 1" SIGTERM
trap "sig_HUP_handler     ; exit 2" SIGHUP

kill -HUP $SELF_PID

exit 0
このスクリプトを実行して確認してみたら、終了コードが 2 でした。つまり、SIGTERM に対する trap は実行されませんでした。
[root@hoge ~]# ./trap_test.bash 
caught SIGHUP
[root@hoge ~]# echo $?
2
[root@hoge ~]# strace ./trap_test.bash 
...
kill(9607, SIGHUP)                      = 0
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=9607, si_uid=0} ---
rt_sigreturn({mask=[]})                 = 0
rt_sigprocmask(SIG_BLOCK, [HUP], [], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP], 8) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0264e7a000
write(1, "caught SIGHUP\n", 14caught SIGHUP
)         = 14
kill(9607, SIGTERM)                     = 0
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=9607, si_uid=0} ---
rt_sigreturn({mask=[HUP]})              = 0
rt_sigprocmask(SIG_SETMASK, [HUP], NULL, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
exit_group(2)                           = ?
+++ exited with 2 +++
[root@hoge ~]# 
strace をかけてみると、このように SIGTERM は確かに割り込んでいます。次に、exit 2 を行わないようにして、実験してみました。
[root@hoge ~]# diff trap_test.bash trap_test2.bash 
11c11
< trap "sig_HUP_handler     ; exit 2" SIGHUP
---
> trap "sig_HUP_handler     # exit 2" SIGHUP
[root@hoge ~]# ./trap_test2.bash 
caught SIGHUP
caught SIGTERM
[root@hoge ~]# echo $?
1
終了コードは 1 になりました。つまり、SIGHUP に対する trap 完了後に、SIGTERM に対する trap が実行されました。
なお、上記の実験環境は、CentOS7 bash-4.2.46-31.el7.x86_64 です。同じスクリプトを RHEL4 より古い環境で動かすと bash が segfault してしまいます。当時は、想定されていなかったのでしょうね。 シグナルには気をつけよう!
人気ブログランキングへ にほんブログ村 IT技術ブログへ