task(1)の実行結果を保持してtask(2)の入力にする、であればregister
を使って可能だけど、play(A)の実行結果を保持してplay(B)の入力にするには、、、(←この認識は誤り)で、環境変数なんかはAnsibleから更新する方法がよくわからなかったけど、処理を行うホストを変更するregister
で保持できる変数のスコープはplay内delegate_to
とfact変数を使って結果を持ち越せたので、そのやり方について。
※ 4/16 訂正記事作成: [Ansible] registerでセットされる値は実行時のターゲットノードに紐づき寿命はplaybook全体 (play終了で消えない) - zaki work log
※ 4/15 22:30 delegate_to
とfact変数を使わない方法について追記
[zaki@manager-dev initialize-kubeadm-ansible]$ 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)]
やりたいこと
kubeadmを使ったKubernetes環境でworkerノード追加するとき
- masterノードで
kubeadm token list
等を使ってトークンを取得 - 追加したいworkerノード上で↑の情報を引数に
kubeadm join
実行
というのを、Ansibleを使ってやりたい。
うまくいかなかったやり方
1の処理はmasterノード1台でやるので、master[0]
をhosts
に指定したplayを作成。
2の処理は追加したいworkerノード上で行うのでworker
(追加対象のworkerを指定したホストグループ)をhosts
に指定したplayを作成。
すると、playをまたがった変数保持が必要になるんだけど、単純に1のplay内でregister
を使っても、2のplayに変数を引き継げない。
環境変数も、1のplay内で更新してもやっぱり2には引き継げない。(←追記: 異なるターゲットノード間で引き継げない、が"おそらく"正解)
fact変数にセットしても、1のplay内のfact変数セットはターゲットノードであるmaster[0]ノードが対象となり、2のplayのターゲットノードであるworkerのfact変数には影響しない。
shell
でssh
使うのはさすがに却下。笑
playをまたいだ変数保持の仕方
ベストプラクティスはあるのかもしれないけどよくわからなかった。。
トライアルアンドエラーと検索の末たどり着いたのがdelegate_to
。
delegate_to
を使うことで、一時的に処理対象をターゲットホストでなくdelegate_to
で指定したホストに変更することができる。
概要としてはこんな感じ
--- - hosts: master[0] gather_facts: false become: true tasks: - name: check exists token shell: kubeadm token list check_mode: false changed_when: false register: token_exists - name: create token shell: kubeadm token create --print-join-command when: token_exists.stdout == '' register: create_token_result - set_fact: kubeadm_token: "{{create_token_result.stdout}}" delegate_to: localhost # set_factの実行ホストをlocalhostに移譲 delegate_facts: true # delegate_toで実行ホストを変更したfact更新を許可 # ↑の結果を # ↓に持ち越すのが今回のテーマ - hosts: localhost gather_facts: false tasks: - name: test debug: msg: "{{kubeadm_token}}"
まず出力を取り出したい最初のplayの以下のtask
- name: create token shell: kubeadm token create --print-join-command when: token_exists.stdout == '' register: create_token_result
shell
を使ってkubeadm token create --print-join-command
というコマンドを実行し、その結果をcreate_token_result
という変数にセット。
ここまでは普通。
そして次のtask。
- set_fact: kubeadm_token: "{{create_token_result.stdout}}" delegate_to: localhost # set_factの実行ホストをlocalhostに移譲 delegate_facts: true # delegate_toで実行ホストを変更したfact更新を許可
delegate_to: localhost
を指定して、処理の対象(この場合set_fact
モジュールを実行するターゲット)をlocalhost
に変更している。
その際、前のtaskでregister
を使って保持したcreate_token_result
へのスコープは生きているので、「localhostのfact変数kubeadm_token
にcreate_token_result.stdout
をセット」ができる。
なお、ターゲットノードを変更するだけであればdelegate_to
で対象指定するだけで良いが、fact変数の更新は更にdelegate_facts
でtrue
を指定する必要もある。
これで、以降localhost
にfact変数としてkubeadm_token
を参照できるようになる。
そして次のplay、前のplayとtaskでセットしたkubeadm_token
に参照している。
- hosts: localhost gather_facts: false tasks: - name: test debug: msg: "{{kubeadm_token}}"
最終的に(完成はしてない)こんな感じ。
(上の例ではlocalhost
でset_fact
してるけど、実際にやりたいのは全worker
ノードなので、loop
で繰り返し処理してる)
手順そのものはこちら
kubeadmでworkerノードの追加
ということで、うまくいきました。
[zaki@k8s-master01 ~]$ kubectl get node NAME STATUS ROLES AGE VERSION k8s-master01.esxi.jp-z.jp Ready master 8d v1.18.0 k8s-master02.esxi.jp-z.jp Ready master 8d v1.18.0 k8s-master03.esxi.jp-z.jp Ready master 8d v1.18.0 k8s-worker01.esxi.jp-z.jp Ready <none> 8d v1.18.0 k8s-worker02.esxi.jp-z.jp Ready <none> 37s v1.18.0
参考
「そういう処理なら〇〇使う方がいいよー」とか「delegate_toは□□みたいなとき使えないよー」とかいうのがあったら教えてください。。
(追記) delegate_*とfactを使わないやり方
よこちさん( id:akira6592 )が検証してくださった結果、「register
でセットした変数は"playまたぎできない"ではなく、(set_fact
の通常動作と同様に)セットしたときのホストに紐づく」という動作だったらしい。
delegate_* なにして、localhsot 側のPlayの debug の msg で
— よこち(yokochi) (@akira6592) 2020年4月15日
"{{ hostvars[master[0]].kubeadm_token }}"
とやったときに表示できる気がします!
簡単なサンプルなのですが、この画像の例だと、localhost から他のホストが前のPlayでregisterした値が表示できました。 pic.twitter.com/Nnc5iqooHd
言い換えると、Ansible実行中の変数は、ホストという名前空間で区切られており、ホスト名省略時は自ホストで持っている変数しか参照できないが、(FQDN的に)ホスト名を指定すれば別ホストでセットした値も見える、という感じかな?
というわけで「やりたいこと」についてはfact変数を使わなくてもクリアできそう。感謝!!