こんにちは。Red Hatの呉と申します。普段はAnsible Automation Platform製品のテクニカルサポートエンジニアをしております。
今回は題名の通り、Ansible Event-DrivenとPerformance Co-Pilot(PCP)を使ったファイルシステム管理について紹介したいと思います。
Linuxサーバーを使っていたら、いつのまにかファイルシステムがいっぱいになっていたという状況は誰しも一度は経験したことがあるかと思います(私だけでしょうか笑)。 検証の最中にサーバーがフリーズしたりして面倒ですし、それだけならまだしも本番環境で発生したら、面倒では済まない事もあるかと思います。 そこで、ファイルシステムがいっぱいになるのを未然に防ぐ方法は無いかと思い今回の方法を思いつきました。
Performance Co-Pilot(PCP)の設定
Performance Co-Pilot (PCP)は、システムレベルのパフォーマンス測定を監視、視覚化、保存、および分析するためのオープンソースソフトウェアです。RHEL9以降、PCPではWebhookを利用できるようになりました。これにより、「システムがあるパフォーマンスルールに該当する状況になったら、Webhookを発行する」という事ができるようになりました。
まずは参考までに、監視対象のLinuxサーバーにPCPをセットアップする手順を記載します。せっかくなのでAnsibleでセットアップします。
- インベントリファイルを作成
まずはインベントリファイルを作成します。IPアドレスやsudoパスワード等は管理対象サーバーのログイン情報に合わせて適宜変更してください。 参考:インベントリファイルを構築する方法
inventory.yaml
--- all: children: pcp_servers: hosts: 192.168.57.10: ansible_become_pass: password 192.168.57.11: ansible_become_pass: password
2. Playbookの作成
次に、以下のコードを使用してプレイブックを作成します。CHANGEME
の部分は、ルールブックを実行するサーバーのIPアドレスもしくはFQDNに置き換えてください。
pre_setup.yaml
--- - hosts: pcp_servers become: true gather_facts: no vars: webhook_endpoint: "http://CHANGEME:5000/endpoint" tasks: - name: Install pcp packages on the managed nodes ansible.builtin.dnf: name: "{{ item }}" state: latest loop: - pcp - name: Install additional packages for stress test and analyze performance ansible.builtin.dnf: name: "{{ item }}" state: latest loop: - sysstat - stress-ng - name: Start and enable pmcd service ansible.builtin.systemd_service: name: pmcd state: started enabled: true - name: Start and enable pmcd service ansible.builtin.systemd_service: name: pmie state: started enabled: true - name: Start and enable pmcd service ansible.builtin.systemd_service: name: pmlogger state: started enabled: true - name: Configure global webhook_action as "yes" command: "pmieconf -f /var/lib/pcp/config/pmie/config.default modify global webhook_action yes" - name: Configure webhook endpoint command: "pmieconf -f /var/lib/pcp/config/pmie/config.default modify global webhook_endpoint {{ webhook_endpoint }}" loop: "{{ groups['pcp_servers'] }}" notify: Restart pmie handlers: - name: Restart pmie ansible.builtin.systemd_service: name: pmie state: restarted enabled: true
3. プレイブックの実行
以下のコマンドでプレイブックを実行してください:
$ ansible-playbook -i inventory.yaml pre_setup.yaml
以上で、PCPサービスを実行するための初期セットアップが完了しました。
Ansible Rulebookの実行環境を用意する
ルールブックを実行するために、まずはルールブックの実行に必要となる環境を用意する必要があります。ルールブックの実行環境としては以下2パターンが考えられます。
1. ルールブックの実行環境を含んだコンテナをダウンロードして、コンテナで実行する。
2. ansible-rulebookおよびJavaなど、必要なパッケージをサーバーにインストールする。
今回は簡単に実行環境を用意したいので、コンテナを利用する方法を記載したいと思います。2をご希望の場合は、公式サイトをご参考ください。
それでは実行環境を構築していきます。
まずは、Red Hat quay.io registryレジストリーから配布されているansible-rulebookコンテナイメージをダウンロードします。
$ podman pull quay.io/ansible/ansible-rulebook
次に、以下のルールブックを用意します。各ルールの解説については、ファイル内のコメントをご参考ください。
pcpEventRules.yaml
--- - name: Listen for RHEL Performance Co-Pilot events hosts: all sources: - ansible.eda.webhook: host: 0.0.0.0 port: 5000 rules: - name: Respond to PMIE rule filesys.filling #ファイルシステムが100%フルの場合、Ansibleは管理対象ノードにログインできません。 #このため、ファイルシステムが100%でない場合のみこのルールを起動します。 condition: "event.payload.pcp.pmie.message is not match('100%',ignorecase=true) and event.payload.pcp.pmie.rule == 'File system is filling up'" action: run_playbook: name: /work/filesys.filling.yaml # 100%フルの場合は、監視対象ノードにログインせず、ファイルシステムがいっぱいになっていることを通知するだけにします。 #通知用プレイブックの実装は今回はスキップします。 #- name: Launch PMIE rule filesys.filling when the managed node file system is 100% full # condition: "event.payload.pcp.pmie.message is match('100%',ignorecase=true) and event.payload.pcp.pmie.rule == 'File system is filling up'" # action: # run_playbook: # name: playbooks/manage_filesystems/notify_filesystem_usage.yaml #デバッグ用 - name: Display any contents of event.payload variable condition: event.payload is defined action: debug: msg: "Received: {{ event.payload }}"
ちなみに、PCPが送ってくるWebhookの中身はこんな感じになっています。
"pcp": { "pmie": { "rule": "File system is filling up", "hostname": "192.168.122.182", "message": "99%used[/dev/mapper/rhel-root]@192.168.122.182" } } }
ルールブックが起動するプレイブックも実装しましょう。なお、このプレイブックでは実装例として「/tmpディレクトリ配下で7日間利用が無かったファイルを削除する」というタスクを実装していますが、もしサイズの大きなファイルやディレクトリがあらかじめわかっている場合はそれらをピンポイントで削除するといったタスクなども実装すると役に立つかと思います。ここはそれぞれご利用の環境や運用状況に合わせて実装してください :)
filesys.filling.yaml
--- - name: EDA response to PMIE rule file.filling hosts: "{{ ansible_eda.event.payload.pcp.pmie.hostname }}" #Webhookを送信してきたホストに対してプレイブックを実行したいので、受信したWebhookからホスト名を取り出します。 become: true gather_facts: false #<---管理対象ノードは現在パフォーマンスが低下しているため、不要な負荷をかけるタスクは避けます。 tasks: - name: Display ansible_eda.event.payload.pcp.pmie.message variable debug: msg: "ansible_eda.event.payload.pcp.pmie.message value: {{ ansible_eda.event.payload.pcp.pmie.message }}" - name: Display ansible_eda.event.payload.pcp.pmie.rule variable debug: msg: "ansible_eda.event.payload.pcp.pmie.rule value: {{ ansible_eda.event.payload.pcp.pmie.rule }}" #7日間利用がなかったファイルを見つける - name: Find files unused for 7 days command: find /tmp -type f -atime +7 register: unused_files #7日間利用がなかったファイルを削除する - name: Delete unused files for 7 days ansible.builtin.file: path: "{{ unused_files.stdout }}" state: absent register: deleted_files #削除したファイルを表示する - name: Showing the deleted files debug: var=deleted_files #削除されたファイルをチャットツールに送信するタスク。これはCiscoのWebexに送信しています。実装はお好みで。 #- name: Cisco Webex Teams - Text Message to a Room # community.general.cisco_webex: # recipient_type: roomId # recipient_id: "{{ room_id }}" # msg_type: markdown # personal_token: "{{ token }}" # msg: "{{ lookup('ansible.builtin.template', './templates/chatMsg.j2') }}"
次に、コンテナを起動します。以下の例では、quay.io/ansible/ansible-rulebook イメージを使用してコンテナを起動し、プロジェクトディレクトリをマウントしてポート5000をリッスンします。/home/vagrant/work/project を実際のプロジェクトディレクトリに置き換えてください。
$ sudo podman run -p 5000:5000 -v /home/vagrant/work/project:/work:z quay.io/ansible/ansible-rulebook ansible-rulebook --rulebook /work/pcpEventRules.yaml -i /work/inventory.yaml --verbose
監視対象ノードでターミナルを開き、curl コマンドを実行して、リクエストがAnsible Event-Drivenサーバーに到達するか確認してください。これにより、PCPからのWebhookがEvent-Drivenサーバーに到達できるか確認できます。IPアドレス192.168.122.11は実際のAnsible Event-Drivenサーバーのホストアドレスに置き換えてください。
$ curl -H 'Content-Type: application/json' -d "{\"message\": \"Ansible is super cool\"}" 192.168.122.11:5000
リクエストが実行中のAnsible Event-Drivenサーバーに到達すると、次のようなログ出力が表示されます:
** 2024-12-19 06:45:46.221739 [debug] ****************************************** Received: {'message': 'Ansible is super cool'} ********************************************************************************
動作テスト
それでは、管理対象サーバーに巨大なファイルを作成して、動作テストをしてみましょう。
ルールブックを起動したまま、以下のようなコマンドを管理対象サーバーで実行します。
たとえば、5GBのダミーファイルを作成する場合:
dd if=/dev/zero of=/tmp/testfile bs=1M count=5120
ファイルサイズを調整しながら、使用率が 95% 程度になるまでファイルを追加してください。
ファイル使用率の確認コマンド:
df -h
筆者の監視対象ノードでは、こんな感じでファイルシステムをいっぱいにしました。この状態でしばらく待ってみましょう。
$ df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 4.0M 0 4.0M 0% /dev tmpfs 3.8G 0 3.8G 0% /dev/shm tmpfs 1.5G 9.4M 1.5G 1% /run /dev/mapper/rhel-root 35G 34G 1.4G 97% / #<---here /dev/vda1 1014M 397M 618M 40% /boot tmpfs 768M 36K 768M 1% /run/user/976 tmpfs 768M 100K 768M 1% /run/user/1000
筆者の環境では3分ほど待つと、先ほど作成した、ファイルを削除するプレイブックfile.filling.yaml
が実行されるのを確認できました。
なお、うまく再現できない場合や待っていられない場合は、PCPが送信するWebhookの中身を監視対象ノードからCurlで飛ばしてテストする手段もあります。
例えばこちらのように実行できます。endpointのIPは、ルールブックを実行中のサーバーのものに置き換えてください。
$ curl -X POST http://192.168.122.11:5000/endpoint -H "Content-Type: application/json" -d '{ "pcp": { "pmie": { "rule": "File system is filling up", "hostname": "192.168.122.183", "message": "99%used[/dev/mapper/rhel-root]@192.168.122.183" } } }'
まとめ
いかがでしたでしょうか。PCPにはファイルシステムの監視ルール「filling.filesystem」の他にも、現時点で32個ほどルールがありますので、この仕組みはシステムのパフォーマンス監視に役立てると思います。
※PCPのルールについてはpmieconf rules
コマンドでご確認できます。
このクリスマスや年末年始を平和に過ごすための1つの手段として、ぜひご検討ください。