はじめに
先日 Ansible の公式ブログで、Event-Driven Ansible という言葉が含まれるブログが次々と投稿されました。
- Introducing the Event-Driven Ansible developer preview | Ansible Collaborative
- Getting Started with Event-Driven Ansible | Ansible Collaborative
- It takes a community: how partners play a key role in event driven automation
また、AnsibleFest 2022 の 10/19 の Key Note でも Event-Driven Ansible が紹介されていました。
動画 (40:13 ころから)
また、個人的には GitHub の Ansible Organizationをフォローしてるのですが、たしかに最近それっぽいリポジトリがいくつかパブリックになりました。なのでそのうち何か発表があるかなと楽しみにしていました。
Event-Driven Ansible というのは、外部からのイベントを検出し、条件にあえば特定のアクションを実行する仕組みのようです。これまでは基本的に人がPlaybookをキックしますが、それとはまた別で、人が介在しないアプローチ。まっさきに IFTTT や StackStorm を連想しました。
Event-Driven Ansible を実現するツールとして ansible-rulebookがあります。まだ developer preview という扱いのようです。
まだあまり情報が多くないですが、簡単なものでためしてみたのでまとめます。まだまだ、環境含めて全体的に手探りです・・。
- 環境
Event-Driven Ansible を実現する要素
Event-Driven Ansible を理解するために重要そうな4つの要素があります。
1. Rulebook: どういうときに何をさせたいかの定義ファイル
検出したいイベントの発生源、条件、実行したいアクションを YAML で定義するファイルです。遠目で見ると Playbook のように見えます。
以降紹介する、 source、condition(rule)、action の定義を含みます。以下の関係です。
- rulebook
- source
- condition (rule)
- action
2. source: イベントの発生源
イベントの発生源です。例えば Webhook や Kafka、Azure Event Bus などです。
拡張性のためか、ansible collection によって追加できる仕組みのようです。
現状、イベントソースを含むコレクションとしては ansible.eda
(eda は Event-Driven Ansible の略)があるようです。後でこのコレクションを利用して試します。
ansible.eda
コレクション 0.9.4 には、例えばイベントソースが含まれています(詳細はこちら)。
- webhook
- alertmanager
- file
- kafka
- azure_service_bus
- url_check
これらを見ると、他システムとの連携イメージが湧きそうです。また、「ansible-rulebook は何に対応しているか?」という問いには「どのイベントソースがあるか」という調べ方になるケースが多そうです。
StackStorm でいうと Sensor のようなものかなと思います。
3. condition(rule): 条件
何かを実行するための条件です。主に source からのイベントに含まれる情報を元にします。例えば「飛んできた Webhook に含まれるペイロード内の message
が sakana
だったら」のような条件です。
condition の例(Rulebook 抜粋)
condition: event.payload.message == "sakana"
複数の条件も指定できます。
AND 条件:
condition: all: - event.payload.message == "sakana" - event.payload.user == "taro"
OR 条件:
condition: any: - event.payload.message == "sakana" - event.payload.message == "fish"
なお、Rulebook の書式上は conditions
という書式を利用しますが、仕組みの説明上は rule と表現されることもあるようです。
4. ction: 実行させたい処理
condition にマッチしたときに実行させたい処理です。以下は一例です。
run_playbook
: 指定した Playbook を実行する (あとで扱う)run_module
: 指定した モジュールのを実行するdebug
: デバッグ情報を表示する
すべての action 一覧はこちらです。
ここまでの source と condition と action をとても雑に表現すると、以下のようなイメージでしょうか。
# 雑なイメージ if (sourceを元にしたcondition): action
環境の準備
ここから、ansible-rulebook を試すための環境を準備します。
インストール・設定
インストール方法に関する公式ドキュメントはこちらです。
ここでは私の環境で私が試した方法を掲載します。上記ドキュメントは後で見つけたため、方法が微妙に異なるのでご了承ください。一次ソースとしてはドキュメントを参照してください。
本体
本体を pip でインストールします。
pip install ansible-rulebook
この時点で ansible-runner
も入りました(ansible-core
はない)。
環境変数
JAVA_HOME` が必要なので、設定します。私の環境の場合は以下の通り。
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-17.0.5.0.8-2.el8_6.x86_64
JAVA_HOME
を設定しないと ansible-rulebook --version
すらエラーになります。
関連パッケージなど
後で分かったのですが、別途 Ansible 環境が必要だったので ansible-core
もインストールします。
pip install ansible-core
今回使うイベントソースが入っている ansible.eda
コレクションをインストールします。
ansible-galaxy collection install ansible.eda
ほか、これも後でエラーが起きてから気づいたのですが、今回使う ansible.eda
コレクション内の webhook
イベントソースが aiohttp
を使うのでインストールします。
pip install aiohttp
何が必要になるかは、利用するイベントソースによって異なります。
おためし
環境ができたので試します。手軽さを重視して、すべてローカルホストで完結する内容です。
Rulebook の準備
お手軽にそれらしことを体験できそうな Webhook をイベントソースとする Rulebook を試してみます。
test-rulebook.yml
--- - name: Hello Events hosts: localhost sources: - ansible.eda.webhook: host: 0.0.0.0 port: 5000 rules: - name: Say Hello condition: event.payload.message == "sakana" action: run_playbook: name: test_playbook.yml
この Rulebook の定義内容は以下の通りです。
- Sensor: Webhook の受け口として、Web サーバー を起動してポート番号
5000
(デフォルト通り)で待ち受ける - Condition: こに対して
message
がsakana
というペイロードの Webhook が飛んできたら・・ - Action:
test_playbook.yml
(あとでrulebookと同じディレクトリに作成)という Playbook を実行する
インベントリファイルの準備
ansible-rulebook
の実行にはインベントリが必要です。
今回は必要最低限の以下のファイルを用意しました。
inventory.yml
--- all: hosts: localhost:
Playbook の準備
Rulebook 内の条件がマッチしたときに実行する Playbook を準備します。
test_playbook.yml
--- - name: debug msg play hosts: localhost connection: local gather_facts: false tasks: - name: debug msg ansible.builtin.debug: msg: HELLO!!
実行
まず待受側として Rulebook を実行します。コマンドは ansible-rulebook
です。
ansible-rulebook -i inventory.yml --rulebook test_rulebook.yml --verbose
ここで指定している ansible-rulebook
コマンドの主なオプションは以下のとおりです。
-i
: インベントリファイル名を指定。--inventory
でも可--rulebook
: Rulebook ファイル名、またはコレクション内の Rulebook を指定。単にファイル名だけ指定するのも可--verbose
: 詳細なログを画面上に表示する(任意)。-v
のように省略できないので注意
ansible-rulebook
側はフォアグラウンドで待ち受け状態になります(--verbose
付きなのでログが多めです)。
$ ansible-rulebook -i inventory.yml --rulebook test_rulebook.yml --verbose INFO:ansible_rulebook.app:Starting sources INFO:ansible_rulebook.app:Starting rules INFO:ansible_rulebook.engine:run_ruleset INFO:ansible_rulebook.engine:ruleset define: {"name": "Hello Events", "hosts": ["localhost"], "sources": [{"EventSource": {"name": "ansible.eda.webhook", "source_name": "ansible.eda.webhook", "source_args": {"host": "0.0.0.0", "port": 5000}, "source_filters": []}}], "rules": [{"Rule": {"name": "Say Hello", "condition": {"AllCondition": [{"EqualsExpression": {"lhs": {"Event": "payload.message"}, "rhs": {"String": "sakana"}}}]}, "action": {"Action": {"action": "run_playbook", "action_args": {"name": "test_playbook.yml"}}}, "enabled": true}}]} INFO:ansible_rulebook.engine:load source INFO:ansible_rulebook.engine:load source filters INFO:ansible_rulebook.engine:Calling main in ansible.eda.webhook INFO:ansible_rulebook.engine:Waiting for event from Hello Events (ここで待機)
条件にマッチする Webhook リクエスト
続いて、Webhook を再現するために、同じホストから以下の curl
を叩きます。条件にマッチするように message
が sakana
のペイロードを仕込んでいます。endpoint
は ansible-rulebook
側の仕様で、固定のようです。
curl -H 'Content-Type: application/json' -d "{\"message\": \"sakana\"}" 127.0.0.1:5000/endpoint
すると、待ち受け状態の ansible-rilebook
側で、以下のログが続きました。
INFO:aiohttp.access:127.0.0.1 [21/10月/2022:06:21:57 +0000] "POST /endpoint HTTP/1.1" 200 158 "-" "curl/7.61.1" INFO:ansible_rulebook.rule_generator:calling Say Hello INFO:ansible_rulebook.engine:call_action run_playbook INFO:ansible_rulebook.engine:substitute_variables [{'name': 'test_playbook.yml'}] [{'event': {'payload': {'message': 'sakana'}, 'meta': {'headers': {'Accept': '*/*', 'User-Agent': 'curl/7.61.1', 'Host': '127.0.0.1:5000', 'Content-Length': '21', 'Content-Type': 'application/json'}, 'endpoint': 'endpoint'}}, 'fact': {'payload': {'message': 'sakana'}, 'meta': {'headers': {'Accept': '*/*', 'User-Agent': 'curl/7.61.1', 'Host': '127.0.0.1:5000', 'Content-Length': '21', 'Content-Type': 'application/json'}, 'endpoint': 'endpoint'}}}] INFO:ansible_rulebook.engine:action args: {'name': 'test_playbook.yml'} INFO:ansible_rulebook.builtin:running Ansible playbook: test_playbook.yml INFO:ansible_rulebook.builtin:ruleset: Hello Events, rule: Say Hello INFO:ansible_rulebook.builtin:Calling Ansible runner PLAY [debug msg play] ********************************************************** TASK [debug msg] *************************************************************** ok: [localhost] => { "msg": "HELLO!!" } PLAY RECAP ********************************************************************* localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
無事に条件にマッチし、run_playbook
で指定した Playbook が実行されました。
動画です(次に説明するマッチしないパターンも含みます)。
(アップし直し) pic.twitter.com/mlwGlExQg2
— よこち (@akira6592) 2022年10月21日
条件にマッチしない Webhook リクエスト
条件にマッチしない以下のリクエストの場合は、Playbook は実行されませんでした。
$ curl -H 'Content-Type: application/json' -d "{\"message: \"fish\"}" 127.0.0.1:5000/endpoint
来たリクエストの概要だけログに表示されました。--verbose
による挙動です。
INFO:aiohttp.access:127.0.0.1 [21/10月/2022:06:22:49 +0000] "POST /endpoint HTTP/1.1" 200 158 "-" "curl/7.61.1"
なるほどなるほど。
Webhook (イベントソース)の内容を Playbook 内で参照する
先ほどの Playbook は、べた書きの文字列を表示するだけでした。せっかくなので、イベントソースの内容、今回では飛んできた Webhook のペイロードの値も扱いたいと思って調べました。
action として debug
を指定すると、イベントソースの色々な情報が表示されました。
Rulebook は以下の通りです。
- name: Hello Events hosts: localhost sources: - ansible.eda.webhook: host: 0.0.0.0 port: 5000 rules: - name: Say Hello condition: event.payload.message == "sakana" action: debug: # デバッグの指定
上記 Rulebook を実行中に、条件にマッチする Webhook をリクスエストをすると、以下のようにイベントソースの内容が色々表示されました。
INFO:ansible_rulebook.engine:call_action debug INFO:ansible_rulebook.engine:substitute_variables [{}] [{'event': {'payload': {'message': 'sakana'}, 'meta': {'headers': {'Accept': '*/*', 'User-Agent': 'curl/7.61.1', 'Host': '127.0.0.1:5000', 'Content-Length': '21', 'Content-Type': 'application/json'}, 'endpoint': 'endpoint'}}, 'fact': {'payload': {'message': 'sakana'}, 'meta': {'headers': {'Accept': '*/*', 'User-Agent': 'curl/7.61.1', 'Host': '127.0.0.1:5000', 'Content-Length': '21', 'Content-Type': 'application/json'}, 'endpoint': 'endpoint'}}}] INFO:ansible_rulebook.engine:action args: {} ============================================================================================= kwargs: {'facts': {}, 'hosts': ['localhost'], 'inventory': {'all': {'hosts': {'localhost': None}}}, 'project_data_file': None, 'ruleset': 'Hello Events', 'source_rule_name': 'Say Hello', 'source_ruleset_name': 'Hello Events', 'variables': {'event': {'meta': {'endpoint': 'endpoint', 'headers': {'Accept': '*/*', 'Content-Length': '21', 'Content-Type': 'application/json', 'Host': '127.0.0.1:5000', 'User-Agent': 'curl/7.61.1'}}, 'payload': {'message': 'sakana'}}, 'fact': {'meta': {'endpoint': 'endpoint', 'headers': {'Accept': '*/*', 'Content-Length': '21', 'Content-Type': 'application/json', 'Host': '127.0.0.1:5000', 'User-Agent': 'curl/7.61.1'}}, 'payload': {'message': 'sakana'}}}} ===================
上記の内容のうち、event.payload.message
を Playbook に埋め込んでみます。
--- - name: debug msg play hosts: localhost connection: local gather_facts: false tasks: - name: debug msg ansible.builtin.debug: msg: "{{ event.payload.message }}" # イベントソースの情報を利用
Rulebook 内の action を debug
から run_playbook
に戻します。
# ...(略)... action: run_playbook: name: test_playbook.yml
上記 Rulebook を実行中に、条件にマッチする Webhook をリクスエストをすると、以下のように event.payload.message
の値(sakana
)が表示されました。
INFO:aiohttp.access:127.0.0.1 [21/10月/2022:06:33:42 +0000] "POST /endpoint HTTP/1.1" 200 158 "-" "curl/7.61.1" INFO:ansible_rulebook.rule_generator:calling Say Hello INFO:ansible_rulebook.engine:call_action run_playbook INFO:ansible_rulebook.engine:substitute_variables [{'name': 'test_playbook.yml'}] [{'event': {'payload': {'message': 'sakana'}, 'meta': {'headers': {'Accept': '*/*', 'User-Agent': 'curl/7.61.1', 'Host': '127.0.0.1:5000', 'Content-Length': '21', 'Content-Type': 'application/json'}, 'endpoint': 'endpoint'}}, 'fact': {'payload': {'message': 'sakana'}, 'meta': {'headers': {'Accept': '*/*', 'User-Agent': 'curl/7.61.1', 'Host': '127.0.0.1:5000', 'Content-Length': '21', 'Content-Type': 'application/json'}, 'endpoint': 'endpoint'}}}] INFO:ansible_rulebook.engine:action args: {'name': 'test_playbook.yml'} INFO:ansible_rulebook.builtin:running Ansible playbook: test_playbook.yml INFO:ansible_rulebook.builtin:ruleset: Hello Events, rule: Say Hello INFO:ansible_rulebook.builtin:Calling Ansible runner PLAY [debug msg play] ********************************************************** TASK [debug msg] *************************************************************** ok: [localhost] => { "msg": "sakana" } PLAY RECAP ********************************************************************* localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
無事に、実行された Playbook 内でイベントソースの内容を扱えました。
おわりに
Event-Driven Ansible の中心となるツール ansible-rulebook
を試してみました。
今後は対応するイベントソースが増えていくと更に可能性が広がりそうです。 イベントソースは collection に含められるようなので、すでに配布やインストールの仕組みがすでに整ってるのは良い条件に思います。
また、こちらの記事によると、AAP のコンポーネントになることが計画されているそうです。
Event-Driven Ansible is planned to become a component of Red Hat Ansible Automation Platform.
今回は、ローカルホストで完結するよう簡単なサンプルでした。まだ、分かっていない仕組み、扱っていないイベントソースや action が色々あります。
今後の動向もチェックしていきたいと思います。
まだ理解していないこと
現時点ではまだ以下の点がまだ理解しきれていません。またあとで調べたいと思います。まだ少し触っただけですので、そもそも認識が及んでいない領域もあります。
ansible-rulebook
と一緒にインストールされるansible-runner
の使われ方- docker を止めてる状態でも正常に Playbook が実行した(明示的にインストールした
ansible-core
によるものの模様)
- docker を止めてる状態でも正常に Playbook が実行した(明示的にインストールした
- インベントリと 各
hosts:
の関係- 今回はすべて
lcoalhost
で完結する内容だったが、ansible-rulebook
の-i
で指定したイベントリファイルと Rulebook 冒頭のhosts:
、Playbook 冒頭のhosts:
がどういう関係なのか
- 今回はすべて
- 内部で Drools がどのように使わているか
参考
Event-Driven Ansible 総合情報
https://www.ansible.com/event-driven
Event-Driven Ansible 関連の公式ブログの記事たち
https://www.ansible.com/blog/topic/event-driven-automation
Event-Driven Ansible を含むハンズオンのラボ環境
https://www.ansible.com/products/ansible-training
ansible-rulebook リポジトリ
https://github.com/ansible/ansible-rulebook
ansible-rulebook ドキュメント
https://ansible-rulebook.readthedocs.io/en/latest/
直近の関連ウェビナー
https://www.redhat.com/en/events/webinar/event-driven-ansible-office-hours-november
https://www.redhat.com/en/events/webinar/event-driven-ansible-office-hours-december
関連動画
雰囲気がわかりやすいです
Git Ops とからめる