zaki work log

作業ログやら生活ログやらなんやら

[Ansible / Linux] sysctlコマンドとAnsibleモジュールについてメモ (sysctl_set未解決)

kernelパラメタを更新するのに使用するsysctlとAnsibleのsysctlモジュールについて、設定ファイルと読み込みの動作について備忘録。

sysctl_setパラメタについては不明点あり。

docs.ansible.com

実行環境

$ ansible --version
ansible 2.9.6
  config file = /home/zaki/ansible/initialize-kubeadm-ansible/ansible.cfg
  configured module search path = [u'/home/zaki/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Aug  7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
$ cat /etc/redhat-release 
CentOS Linux release 7.7.1908 (Core)

sysctl CLIコマンドについて

値の適用について使用するのは主に以下

sysctl -w について

引数無しで実行すると

# sysctl -w
sysctl: no variables specified
Try `sysctl --help' for more information.

これは引数に適用したい設定値を与えてコマンドラインでパラメタ設定を行うオプション。

# cat /proc/sys/net/ipv4/ip_forward
0
# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
# cat /proc/sys/net/ipv4/ip_forward
1

この通り。
つまり、rebootすれば消えてしまう状態。

sysctl -p について

引数無しで実行すると

# grep -v "^#" /etc/sysctl.conf 
net.ipv4.ip_forward = 1
# cat /proc/sys/net/ipv4/ip_forward
0
# sysctl -p
net.ipv4.ip_forward = 1
# cat /proc/sys/net/ipv4/ip_forward
1

この通り、引数無しだとデフォルトで/etc/sysctl.confが読み込まれる。
引数を指定することで、任意のファイルでパラメタの設定が可能。

# cat /proc/sys/net/bridge/bridge-nf-call-iptables 
0
# cat /proc/sys/net/bridge/bridge-nf-call-ip6tables 
0
# cat /etc/sysctl.d/k8s.conf 
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
# sysctl -p /etc/sysctl.d/k8s.conf 
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
# cat /proc/sys/net/bridge/bridge-nf-call-iptables 
1
# cat /proc/sys/net/bridge/bridge-nf-call-ip6tables 
1

sysctl --system について

システム上の全設定ファイルが適用される。

manから引用

       --system
              Load settings from all system  configuration  files.  Files  are
              read  from directories in the following list in given order from
              top to bottom. Once a file of a given filename  is  loaded,  any
              file of the same name in subsequent directories is ignored.
              /run/sysctl.d/*.conf
              /etc/sysctl.d/*.conf
              /usr/local/lib/sysctl.d/*.conf
              /usr/lib/sysctl.d/*.conf
              /lib/sysctl.d/*.conf
              /etc/sysctl.conf

Ansibleのsysctlモジュールについて

以上のsysctlコマンドの読み込み動作を踏まえて

保存先のファイル

sysctl_fileで指定できる。

デフォルトの/etc/sysctl.confに保存したい

  sysctl:
    sysctl_file: /etc/sysctl.conf

で指定できる。
ただしこのパラメタのデフォルト値なので省略可能。

任意の設定ファイルに保存したい

例えば/etc/sysctl.d/k8s.confに設定を保存したい場合は

  sysctl:
    sysctl_file: /etc/sysctl.d/k8s.conf

と書けばOK

値の即時適用

reloadで指定する。

  • true: 設定ファイルに設定値が保存され、設定も反映されて/proc/sys以下の値が更新
  • false: 設定ファイルに設定値が保存されるが、設定は適用されず/proc/sys以下の値は変更されない

なので基本はtrue/yesで良いし、デフォルトはそうなっている。

(未解決)sysctl_set って何

で実はこれが分からなく、デフォルトはoffだしパラメタの説明を見ても

Verify token value with the sysctl command and set with -w if necessary

の意味がピンと来なかった。

で、結局ソースを見たんだけど、v2.9ベースだとset_procというフラグがonになっている
更に読んでいくと、この_set_token_value()関数をコールしていることが分かる。

内容をよく見ると、sysctl -w key=valueを実行している。
が、つまりどういうことだってばよ?

reload:falseでキー誤りの場合

結局よくわからず、パラメタの説明の "Verify token value" と勘を頼りに「誤ったカーネルパラメタを指定」して、かつreload: falseで即時適用をオフにしてみるとエラーで停止する動作をするものだった。

つまり

  tasks:
  - sysctl:
      name: net.ipv4.ip_forwar
      value: '1'
      state: present
      sysctl_set: false
      reload: false

という誤ったキー(forwardでなくdが抜けてforwarになってる)にすると、sysctl_set: false(デフォルト)の場合は誤ったキー設定で/etc/sysctl.confが作成されるてエラーにもならずに処理が行われる。

  tasks:
  - sysctl:
      name: net.ipv4.ip_forwar
      value: '1'
      state: present
      sysctl_set: true
      reload: false

と、sysctl_settrueにすると、

TASK [sysctl] ******************************************************************
fatal: [master02]: FAILED! => changed=false 
  ansible_facts:
    discovered_interpreter_python: /usr/bin/python
  msg: |-
    setting net.ipv4.ip_forwar failed: sysctl: cannot stat /proc/sys/net/ipv4/ip_forwar: No such file or directory

PLAY RECAP *********************************************************************
master02                   : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

という風にエラーでAnsibleが止まるようになる。

ただし、一見便利そうに見えて、誤ったキー文字列のまま設定ファイルへは出力されてしまう。
前述dが抜けたip_forwaの例であれば

net.ipv4.ip_forwar=1

/etc/sysctl.confに書き込まれる。

reload:falseでキーも正しい場合

キーが間違ってる場合の動作を踏まえると、reload:falseで即時反映をオフにしてるつもりでもsysctl_set:trueにすれば(内部のsysctl -wの動作で)即時反映されるのでは?と思い確認。

  tasks:
  - sysctl:
      name: net.ipv4.ip_forward
      value: '1'
      state: present
      sysctl_set: true
      reload: false

上記のタスク設定であれば、予想通り/proc/sys/net/ipv4/ip_forwardの値は1になる。

そもそもreload:trueでキー誤りの場合

sysctl_set:falsereload:trueの場合(どちらもデフォルト)

  tasks:
  - sysctl:
      name: net.ipv4.ip_forwar
      value: '1'
      state: present
      sysctl_set: false
      reload: true

このタスク(dが抜けてforwarになってる)を動かすと、

TASK [sysctl] ******************************************************************
fatal: [master02]: FAILED! => changed=false 
  ansible_facts:
    discovered_interpreter_python: /usr/bin/python
  msg: |-
    Failed to reload sysctl: sysctl: cannot stat /proc/sys/net/ipv4/ip_forwar: No such file or directory

PLAY RECAP *********************************************************************
master02                   : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

結局キー誤りでエラーになる。

なるほどわからん。。

set_token_value()のコールが設定ファイル書き込み処理より先に実行されれば事前チェックになりそうではあるけど、このパラメタの本来の主旨を把握できてないので何とも。 (そもそもAnsibleでカーネルパラメタの設定が妥当かチェックする機能が必要かどうかという話もあるし)


調査の発端

なんでこんなの調べてるかというと、kubeadmを使ったKubernetes環境構築の事前設定

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

という手順があり、Ansible対応しようとした際にsysctlモジュールを正しく使うにはどうすればいいのかなと調べてたらパラメタの機能がわからなかったので調べてみた、という話。

github.com

やりたいことを実現するだけなら、とりあえずsysctl_setはデフォルトのオフで大丈夫そうだけどね。