8.5K Views
November 22, 23
スライド概要
「8a1」APC勉強会 #40 の発表資料です。
https://8a1-apc.connpass.com/event/301686/
ansible
#apc8a1 Ansibleにおける「冪等性がない」 の解像度を上げたい 2023/11/22 「8a1」APC勉強会 #40 株式会社エーピーコミュニケーションズ 横地 晃 (@akira6592) 1
#apc8a1 はじめに ◼ 冪等性とは AnsibleとしてはPlaybook を 1 回実行しても、複数回実行しても、結果 は同じになることを示します。 ◼ 「冪等性がない」は、どのような状況を連想されますでしょうか。いくつか分類でき るように思います。 ◼ 今回は「冪等性がない」の解像度を上げるために、いくつかの観点で整理したいと 思います。 まだ頭の整理中のものも含まれます ※ 数学的な言及はしません(できません) 2
#apc8a1 自己紹介 横地 晃 @akira6592 てくなべ(ブログ) 所属 (株)エーピーコミュニケーションズ 業務 ネットワーク自動化のご支援 https://tekunabe.hatenablog.jp/ コミュニ Ansible ユーザー会、JANOG ティ 共著 Ansible クックブック Ansible 実践ガイド 第4版[基礎編]、他 https://book.impress.co.jp/books/1120101163 https://book.impress.co.jp/books/1122101189 3
#apc8a1 冪等性とは 4
#apc8a1 Ansible における冪等性とは ◼ Playbook を 1 回実行しても、複数回実行しても、結果が同じになること 1回目の実行 2回目の実行 正常終了 処理 正常終了 処理 同じ結果 5
#apc8a1 公式ドキュメント上の説明 ほとんどの Ansible モジュールは、目的の最終状態がすでに達成されているかどうかを確 認し、その状態が達成されている場合は何も実行せずに終了するため、タスクを繰り返して も最終状態は変わりません。 このような動作をするモジュールは、しばしば「冪等性」と呼ばれます。 Playbook を 1 回だけ実行しても、複数回実行しても、結果は同じになるはずです。 ※ 引用元 https://docs.ansible.com/ansible-core/2.15_ja/playbook_guide/playbooks_intro.html#desired-state-and-idempotency 6
#apc8a1 事前アンケート 1.Playbookの処理について「冪等性がな い」と表現したことはありますか? 2.「冪等性がない」処理とはどのような処 理のイメージでしょうか? ◼ シェルモジュール固有 ◼ ◼ ◼ ファイルの扱い、 API ◼ ◼ ◼ ◼ ◼ Ansibleでは、モジュールやアクションプラグインの中で、マネージドノードのス テートをチェックせずに、指定されたバラメータにしたがって、ステートを変更 させる可能性がある操作を実行することです。 Playbookである状態にしたい処理が既に実行されていた場合は処理を実行 しないみたいな感じです その他 ◼ 50名お申し込み時点 二回目以降の実行で差分が毎回出る 1回実行した後の状態と 2回以上実行した後の状態で差異があるような処 理。 2回実行できない 内部処理 ◼ ◼ ファイルの編集、更新系 Web APIの呼び出し 行挿入等で複数回実行して同じ状態にならない処理 実行回数 ◼ ◼ ◼ モジュールを使用せずにシェルスクリプトで実行したプログラムのイメージ シェルモジュール実行 失敗して再実行する際、手作業でリカバリが必要である 7
#apc8a1 考えていたこと 「冪等性がある」は暗黙的に正常終了することも含まれている エラーが起きたり、他のいろいろな現象は「冪等性がない」 🤔 「冪等性がない」には対処の優先度がいろいろありそうだ わからない、わかりたい 8
#apc8a1 分ければわかるかも “「わかる」ことは「分ける」こと” 「記録・情報・知識」の世界 ―オントロジ・アルゴリズムの研究 「はじめに」より 9
#apc8a1 「冪等性がない」の分類 10
#apc8a1 分類の概要 ◼ エラーになるか、ならないか ◼ エラーになる ◼ エラーにならない 結果による分類 ◼ 副作用がある ◼ 副作用がない ◼ 原因 ◼ モジュールの使い方起因 ◼ しょうがない 原因による分類 ※ここでは副作用 = タスク単体で見た時の実害のようなもの 11
#apc8a1 エラーの有無 ◼ エラーになる ◼ 例: 2回実行したら、そのタスクがエラーになってPlaybookがの処理が止まってしまう ◼ 対処優先度は高い ◼ エラーにならない ◼ (後述の)副作用の有無によって対処優先度が異なる 12
#apc8a1 副作用の有無 ◼ 副作用がある ◼ 例: 2回実行したら設定ファイルが壊れる ◼ 対処優先度は高い ◼ 副作用がない ◼ 例: 毎回 changed になるが、実際は2回目以降は変更が発生しない 13
#apc8a1 原因の所在 ◼ モジュールの使い方起因 ◼ ◼ 使い方の変更で対処できるなら対処したい しょうがない ◼ モジュールの仕様上しょうがないのはしょうがない 14
#apc8a1 分類・優先度・対処方針まとめ 結果による分類 原因による分類 エラーの有無 副作用の有無 使い方起因 しょうがない エラーになる - 優先度: 高 優先度: 高 副作用がある 優先度: 高 優先度: 高 【対処方針】 ● モジュールやタスクの使 い方を変更 ● 他のモジュールを検討 【対処方針】 ● 他タスクとの組み合わせ ● 他のモジュールを検討 エラーにならない 副作用がない 15
#apc8a1 「冪等性がない」の具体例 16
#apc8a1
例1: ansible.builtin.uri モジュール(Playbook)
◼
エラーになる
エラーにならい
副作用あり
副作用なし
使い方起因
しょうがない
あるファイアウォールのルールを追加するPOST
--- name: Test uri
gather_facts: false
hosts: localhost
2回目の実行で
エラー 「HTTP Error 409: Conflict」
tasks:
- name: Add a firewall rule
ansible.builtin.uri:
url: https://example.com/gateway/rules
method: POST
body_format: json
body: "{{ lookup('ansible.builtin.file','payload.json') }}"
headers: "{{ headers }}"
17
#apc8a1 例1: ansible.builtin.uri モジュールの例(対処案) ◼ エラーにならい 副作用あり 副作用なし 使い方起因 しょうがない 案1: ansible.builtin.uri モジュールの status_code オプションで 200 と 409 を指定する ◼ ◼ エラーになる デフォルトは 200 のみ。どういうコードになるかはAPI仕様を要調査 案2: failed_when ディレクティブで調整 # ...(略)... register: result failed_when: - result.status not in [200, 409] ◼ ◼ 案3: 対象オブジェクトの有無をGETで調べるタスクを事前に仕込み、 ない場合だけPOSTする ◼ ◼ 4xx を ok するのは直感に反するか・・? 専用モジュールがあれば、この手の処理はモジュール内部で行われる その他、API仕様次第ではもっと良い方法があるかも 18
#apc8a1 例2: cisco.ios.ios_config モジュール(Playbook) ◼ エラーになる エラーにならい 副作用あり 副作用なし 使い方起因 しょうがない Cisco IOS 機器への設定投入 --- hosts: ios01 gather_facts: false 毎回 changed tasks: - name: Configure a interface cisco.ios.ios_config: lines: running-config 上は interface GigabitEthernet0/1 - no ip redirects という表記のため差分とみなされる parents: - int Gi0/1 * 公式 FAQ あり https://docs.ansible.com/ansible/latest/network/user_guide/faq.html#why-do-the-config-modules-always-return-changed-true-with-abbreviated-commands * 参考記事 https://tekunabe.hatenablog.jp/entry/2022/07/09/222546 19
#apc8a1 例2: cisco.ios.ios_config モジュール(対処案) ◼ エラーになる エラーにならい 副作用あり 副作用なし 使い方起因 しょうがない 案1: モジュールに指定するコマンドを running-config 上の表記に合わせる --- hosts: ios01 gather_facts: false tasks: - name: Configure a interface cisco.ios.ios_config: lines: - no ip redirects running-config 上の表記に合わせる parents: - interface GigabitEthernet0/1 20
#apc8a1 Playbook 単位での「冪等性がない」? 21
#apc8a1 Playbook単位で考えられる・・? ◼ ◼ これまでは話を単純化するために、タスク単位にスコープを絞っていました 拡大解釈するとPlaybook単位での冪等性という見方もあるのではと思いました タスク単位の冪等性 冪等性ある? タスク1 Playbook単位の冪等性? タスク1 冪等性ある? タスク2 タスク2 冪等性ある? タスク3 タスク3 冪等性ある? 22
#apc8a1 Playbook単位の例1: 事前確認を入れると2回目の実行でエラー ◼ 何かを追加する前に、ないことを事前確認(ここではassertモジュール)する場合、2 回目の実行の事前確認でエラーになる 【1回目】 【2回目】 エラー タスク1 事前確認: A がないこと タスク1 事前確認: A がないこと タスク2 設定: A を追加 タスク2 設定: A を追加 ※ 2回実行されること自体が、何かしらの想定外をはらんでいる可能性がある場合は、あえてこれで良しとする考え方も 23
#apc8a1 Playbook単位の例2: 意図したパッケージのバージョンにならない ◼ ◼ あるパッケージをインストールする前に、全パッケージをアップデートし、 その後に、あるパッケージの過去バージョンをインストールする 2回実行すると意図したバージョンにならない # ...(略)... 1回目実行後結果 2回目実行後結果 - name: Update all packages ansible.builtin.yum: name: '*' state: latest package1 最新 package2 最新 ansible-core なし package1 最新 package2 最新 ansible-core 2.14 - name: Install ansible-core 2.13 ansible.builtin.yum: name: ansible-core-2.13.3-2.el8_7.x86_64 package1 最新 package2 最新 ansible-core 2.13 package1 最新 package2 最新 ansible-core 2.14 ※yum モジュールの allow_downgrade: true で強制ダウングレードできる 24
#apc8a1 おまけ 25
#apc8a1 (おまけ)今回整理できなかった他の分類 ◼ 原因による分類にもう一点 ◼ 時間や外界の影響 ◼ 例: 2回連続で実行すると冪等性はあるが、1年後に実行すると changed になる ◼ どの時間の範囲で冪等性ありなしとするか 26
#apc8a1 まとめ 27
#apc8a1 まとめ ◼ 今回整理してみた分類 ◼ エラーの有無、副作用の有無、原因の所在 ◼ 分類することで対処の優先度が見えてきた ◼ 拡大解釈すると、タスク単位だけではなくPlaybook単位の冪等性 という考え方もあるかもしれない(考慮単位による分類) ◼ 他の切り口、考え方があればコメントいただけると幸いです 28