zaki work log

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

[Ansible] registerでセットされる値は実行時のターゲットノードに紐づき寿命はplaybook全体 (play終了で消えない)

昨日のこの「playまたぎの変数保持」についての記事、記事への補足訂正は追記済みですが、致命的に認識誤りしてました💦

zaki-hmkc.hatenablog.com

記事作成当時の認識の「playをまたいで変数を持ち越せない」は、

  1. masterノードでkubeadm token list等を使ってトークンを取得
  2. 追加したいworkerノード上で↑の情報を引数にkubeadm join実行

という処理を実現したいのがベースにあり、

  1. 「masterノード」をターゲットノードにしたplayでトークン取得処理を作成
  2. 「追加したいworkerノード」をターゲットノードにしたplayでkubeadm joinを実行

と、二つのplayでターゲットノードが異なるため 1の結果をregister使って保持しても2のplay実行時に持ち越せないのが本当の原因だったのですが、これを「play間で変数を持ち越せない」と問題を誤認していました。

コメントくださったみなさんありがとうございました!

ちなみに変数管理周りはVariableManagerなので、この辺から攻めるとよいとのこと。勉強になるなぁ。


というわけで、動作確認してみました。
Ansibleの実装を追って行った方が確実だし面白そうなんだけど、ひとまず動きを確認してみたい。

検証: registerの値をplayをまたいで参照してみる

パターン1: ターゲットノードが同じ

---
- hosts: master[0]
  gather_facts: false
  become: true
  tasks:
    - name: exec ls
      shell: ls /root
      register: shell_result

# ↑の結果を
# ↓で参照する

- hosts: master[0]
  gather_facts: false
  tasks:
    - name: echo "ls /root"
      debug:
        msg: "{{shell_result.stdout}}"

結果

[zaki@manager-dev test-ansible]$ ansible-playbook -i inventory.ini other_host.yaml -K
BECOME password: 

PLAY [master[0]] ***************************************************************

TASK [exec ls] *****************************************************************
changed: [master01]

PLAY [master[0]] ***************************************************************

TASK [echo "ls /root"] *********************************************************
ok: [master01] => 
  msg: |-
    anaconda-ks.cfg
    original-ks.cfg

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

[zaki@manager-dev test-ansible]$ 

なるほど、問題無い。
(ちなみに1つ目のplayはbecome: trueでroot実行して、2つ目のplayは通常ユーザー権限で動かしてるので、特権動作の結果を通常権限で参照するという動作でも問題無い)

パターン2: ターゲットノードが異なる場合

---
- hosts: master[0]
  gather_facts: false
  become: true
  tasks:
    - name: exec ls
      shell: ls /root
      register: shell_result

# ↑の結果を
# ↓で参照する

- hosts: master[1]
  gather_facts: false
  tasks:
    - name: echo "ls /root"
      debug:
        msg: "{{shell_result.stdout}}"

結果

[zaki@manager-dev test-ansible]$ ansible-playbook -i inventory.ini other_host.yaml -K
BECOME password: 

PLAY [master[0]] ***************************************************************

TASK [exec ls] *****************************************************************
changed: [master01]

PLAY [master[1]] ***************************************************************

TASK [echo "ls /root"] *********************************************************
fatal: [master02]: FAILED! => 
  msg: |-
    The task includes an option with an undefined variable. The error was: 'shell_result' is undefined
  
    The error appears to be in '/home/zaki/ansible/test-ansible/other_host.yaml': line 16, column 7, but may
    be elsewhere in the file depending on the exact syntax problem.
  
    The offending line appears to be:
  
      tasks:
        - name: echo "ls /root"
          ^ here

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

[zaki@manager-dev test-ansible]$ 

register使ってセットしたshell_resultは未定義とエラーになった。

パターン3: ターゲットノードは異なるがhostvarsでregisterを使ったノードを指定

hostvarsは、対象ノードのfact変数や定義済み変数などにアクセスする際に使用します。

---
- hosts: master[0]
  gather_facts: false
  become: true
  tasks:
    - name: exec ls
      shell: ls /root
      register: shell_result

# ↑の結果を
# ↓で参照する

- hosts: master[1]
  gather_facts: false
  tasks:
    - name: echo "ls /root"
      debug:
        msg: "{{ hostvars[groups.master[0]] }}"

結果

[zaki@manager-dev test-ansible]$ ansible-playbook -i inventory.ini other_host.yaml -K
BECOME password: 

PLAY [master[0]] ***************************************************************

TASK [exec ls] *****************************************************************
changed: [master01]

PLAY [master[1]] ***************************************************************

TASK [echo "ls /root"] *********************************************************
ok: [master02] => 
  msg:
    ansible_check_mode: false
    ansible_diff_mode: false
    ansible_facts:
      discovered_interpreter_python: /usr/bin/python
    ansible_forks: 5
    ansible_host: 192.168.0.121
    ansible_inventory_sources:
    - /home/zaki/ansible/test-ansible/inventory.ini
    ansible_playbook_python: /usr/bin/python2
    ansible_run_tags:
    - all
    ansible_skip_tags: []
    ansible_verbosity: 0
    ansible_version:
      full: 2.9.6
      major: 2
      minor: 9
      revision: 6
      string: 2.9.6
    discovered_interpreter_python: /usr/bin/python
    group_names:
    - master
    groups:
      all:
      - worker01
      - worker02
      - worker03
      - master01
      - master02
      master:
      - master01
      - master02
      ungrouped: []
      worker:
      - worker01
      - worker02
      - worker03
    inventory_dir: /home/zaki/ansible/test-ansible
    inventory_file: /home/zaki/ansible/test-ansible/inventory.ini
    inventory_hostname: master01
    inventory_hostname_short: master01
    playbook_dir: /home/zaki/ansible/test-ansible
    shell_result:
      ansible_facts:
        discovered_interpreter_python: /usr/bin/python
      changed: true
      cmd: ls /root
      delta: '0:00:00.003252'
      end: '2020-04-16 19:50:33.655705'
      failed: false
      rc: 0
      start: '2020-04-16 19:50:33.652453'
      stderr: ''
      stderr_lines: []
      stdout: |-
        anaconda-ks.cfg
        original-ks.cfg
      stdout_lines:
      - anaconda-ks.cfg
      - original-ks.cfg

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

[zaki@manager-dev test-ansible]$ 

gather_fact: falseにしているのでfact変数はセットされていないですが、Ansible環境情報やインベントリ変数などに加えて、registerでセットしたshell_resultが含まれているのが確認できます。

追試

パターン4: あらかじめall:varsでホスト変数をセットしておきplay内で1ノードだけ変数更新してみる

インベントリファイル

[master]
master01 ansible_host=192.168.0.121
master02 ansible_host=192.168.0.122
master03 ansible_host=192.168.0.123

[all:vars]
sample_host_val = "curry"

プレイブック

---
- hosts: master
  gather_facts: false
  tasks:
    - name: print host value
      debug:
        msg: "{{ sample_host_val }}"

- hosts: master[2]
  gather_facts: false
  tasks:
    - shell: echo "tabetai"
      register: sample_host_val
    - name: print host value
      debug:
        msg: "{{ sample_host_val.stdout }}"

- hosts: master
  gather_facts: false
  tasks:
    - name: print host value
      debug:
        msg: "{{ sample_host_val }}"

実行結果

[zaki@manager-dev test-ansible]$ ansible-playbook -i inventory.ini host_vars.yaml 

PLAY [master] ******************************************************************

TASK [print host value] ********************************************************
ok: [master01] => 
  msg: curry
ok: [master02] => 
  msg: curry
ok: [master03] => 
  msg: curry

PLAY [master[2]] ***************************************************************

TASK [shell] *******************************************************************
changed: [master03]

TASK [print host value] ********************************************************
ok: [master03] => 
  msg: tabetai

PLAY [master] ******************************************************************

TASK [print host value] ********************************************************
ok: [master03] => 
  msg:
    ansible_facts:
      discovered_interpreter_python: /usr/bin/python
    changed: true
    cmd: echo "tabetai"
    delta: '0:00:00.002291'
    end: '2020-04-16 20:09:34.678726'
    failed: false
    rc: 0
    start: '2020-04-16 20:09:34.676435'
    stderr: ''
    stderr_lines: []
    stdout: tabetai
    stdout_lines:
    - tabetai
ok: [master01] => 
  msg: curry
ok: [master02] => 
  msg: curry

PLAY RECAP *********************************************************************
master01                   : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
master02                   : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
master03                   : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[zaki@manager-dev test-ansible]$ 

master03(master[2])でのみregisterを使ってshellの実行結果をセットしたみたけど、その次のplayではmaster03のみ値が更新されている。

なので、registerを使うと、ホスト変数を上書きするみたい。

ちなみに

- hosts: master[0]
  gather_facts: false
  vars:
    sample_host_val: "tabetai"
  tasks:
    - name: print host value
      debug:
        msg: "{{ sample_host_val }}"

というplayの場合は、varsで値をセットしたplay内ではsample_host_valtabetaiで上書きされて実行されるけど、次のplayではリセットされる。


というわけで、hostvars使った版のworkerノード追加のplaybookはこの通り。(set_factしてたtaskが1個減った)

結果

[zaki@k8s-master01 ~]$ kubectl get node 
NAME                        STATUS   ROLES    AGE   VERSION
k8s-master01.esxi.jp-z.jp   Ready    master   9d    v1.18.0
k8s-master02.esxi.jp-z.jp   Ready    master   9d    v1.18.0
k8s-master03.esxi.jp-z.jp   Ready    master   9d    v1.18.0
k8s-worker01.esxi.jp-z.jp   Ready    <none>   9d    v1.18.0
k8s-worker02.esxi.jp-z.jp   Ready    <none>   38h   v1.18.0
k8s-worker03.esxi.jp-z.jp   Ready    <none>   33s   v1.18.0

うむ。


よこちさん( id:akira6592 )が関連記事を作成してくださいました。ありがとうございます!

tekunabe.hatenablog.jp