Ansibleを用いたWindows版Zabbixエージェントの自動バージョンアップ MSIファイル編
こんにちは!プラットフォーム技術部の小羽根陸です。
前回の記事では、Linux版Zabbixエージェントの自動バージョンアップ方法を紹介しましたので、今回はWindows版Zabbixエージェントの自動バージョンアップ方法を紹介します!
Windows版Zabbixエージェントは、msiファイルを用いたインストール方法とZIPアーカイブファイルを用いたインストール方法の2種類ありますが、今回紹介する内容はmsiファイルを使用した方法です。
※本記事はある程度Ansibleの知識がある方向けになっています
Ansibleとは
Ansibleについては、Linux版Zabbixエージェントの自動バージョンアップ方法で説明しているため、そちらをご確認ください。
Ansible Collectionsとは
Ansible Collectionsとは、Playbookやモジュールなどをパッケージ化して配布されているものです。
もともとはAnsible本体に含まれていましたがモジュール数が多くなったため、Ansible 2.10からはユーザーが必要なCollectionをインストールして使用する形になりました。
今回はコミュニティが配布しているWindowsモジュールを使用するため、Ansibleホストで以下のコマンドを使用してCollectionをインストールします。
# ansible-galaxy collection install community.windows
Ansibleの使用方法
ここからは実際にAnsibleを用いてZabbixエージェントのバージョンアップをおこなっていきます。
環境情報
ホスト情報
本記事ではAnsibleホストとリモートホストを2台用意してPlaybookを実行してみます。
- Ansibleホスト (OS:RHEL9.1)
- リモートホスト1 (OS:Windows Server2022)
- リモートホスト2 (OS:Windows Server2022)
今回作成したPlaybookはZabbixエージェントのバージョンアップ用ですが、Zabbixエージェントがインストールされていない場合は新規インストールをおこなうように作成しています。
リモートホスト1には、バージョンアップ用としてZabbixエージェント 4.0をインストールしておきました。リモートホスト2は、新規インストール用にZabbixエージェントをインストールしていない状態にしています。
前提条件
Ansibleを実行する時の前提条件として以下のものがあります。
Ansibleホスト
- Ansibleがインストールされており、動作確認ができていること
- pywinrmがインストールされていること
- WinRMで使用するポート(5986)のアウトバウンド通信が許可されていること
- Ansible実行ユーザーが作成済みであること
- Pythonがインストールされていること(RHEL9.1はデフォルトでインストール済み)
- Ansible Collections(community.windows)がインストールされていること
リモートホスト
- WinRMがBasic認証を許可し、HTTPSトランスポートで構成されていること
- WinRM接続で使用するポート(5986)のインバウンド通信が許可されていること
- Administrator権限が付与されたAnsible実行ユーザーが作成済みであること
AnsibleはWindows Serverと通信する際にWinRM(Windows Remote Manager)を使用します。
WinRMはWindowsが別のサーバーとリモート通信するために使用する管理プロトコルです。
Ansibleのディレクトリ構成
ディレクトリ構成は公式ページにある「Sample directory layout」を参考に以下のようにしました。
/etc/ansible
├── group_vars
│ └── zabbix_agent_windows
│ ├── general.yml # 一般的な変数を定義
│ └── login.yml # リモートホスト接続に必要な変数を定義
├── roles
│ └── zabbix_agent_windows
│ ├── files # リモートホストに配布するファイルを配置
│ │ └── zabbix_agent-6.0.13-windows-amd64-openssl.msi # ZabbixAgentのパッケージ
│ └── tasks
│ └── main.yml # Zabbix Agentのバージョンアップ用のPlaybook
├── site.yml # メインの Playbook
└── hosts # リモートホスト情報を記載
/etc/ansible/roles/zabbix_agent_windows/filesには、バージョンアップ用のmsiファイルをZabbix公式ページから事前にダウンロードして配置します。
本記事ではZabbixエージェント 6.0.13にバージョンアップを想定してパッケージを配置しています。必要に応じて配置するパッケージのバージョンは変更してください。
各種ファイルの説明
では1つずつファイルを見ていきましょう。
hosts
hostsファイルには対象のリモートホスト名とIPアドレスを記載しています。Playbookを実行する際にhostsファイルを参照して、リモートホストに接続しています。
hostsファイルはINI形式、またはYAML形式で記載ができます。本記事ではYAML形式で記載しています。
今回はリモートホストが2台あるため、2台分の情報を記載しています。
- /etc/ansible/hosts
--- # YAML形式の1行目は「---」で開始する
all:
children:
zabbix_agent_windows: # グループ名を指定
hosts:
ansible_remote-devlog1: # リモートホスト1のホスト名
ansible_host: 172.31.10.1 # リモートホスト1のIPアドレス
ansible_remote-devlog2: # リモートホスト2のホスト名
ansible_host: 172.31.10.2 # リモートホスト2のIPアドレス
login.yml
login.ymlではWinRMを用いたリモート操作するために必要な変数を定義しています。
本記事ではリモートホスト上にAnsible実行ユーザーとして「ansibleuser」を作成しています。
変数ansible_passwordはパスワードを平文で記載する必要があります。セキュリティ上問題がある場合は、Ansible Vault機能を使用することでパスワードを記載したファイルを暗号化することが可能です。Ansible Vault機能について詳しく知りたい方は公式ページをご確認ください。
WinRMはHTTP通信に5985ポートを使用し、HTTPS通信に5986ポートを使用します。
今回は5986ポート(HTTPS通信)を使用しているため、ネットワーク上にパスワードが平文で流れる心配もありません。
また本記事では認証オプションに一番安全性が低いBasicを使用しています。認証オプションについても詳しく知りたい方は公式ページをご確認ください。
- /etc/ansible/group_vars/zabbix_agent_windows/login.yml
---
ansible_user: ansibleuser # 認証に使用するユーザー
ansible_password: xxx # 認証に使用するユーザーのログインパスワード
ansible_connection: winrm # 通信プロトコルを指定
ansible_port: 5986 # 使用ポートを指定
ansible_winrm_transport: basic #認証オプションを指定
ansible_winrm_server_cert_validation: ignore # 今回は証明書を構成しないため、サーバー証明書の検証モードをignoreに設定
general.yml
general.ymlではmain.ymlで使用する変数を定義しています。状況に応じて変数は修正してください。
- /etc/ansible/group_vars/zabbix_agent_windows/general.yml
---
zabbix_agent_package: "zabbix_agent-6.0.13-windows-amd64-openssl" # インストールするパッケージを記載
files_directory: "/etc/ansible/roles/zabbix_agent_windows/files/" # リモートホストに配布するファイルの配置場所
work_directory: "C:\\" # パッケージを配布するフォルダ
zabbix_directory: "C:\\Program Files\\Zabbix Agent" # Zabbixの設定ファイル保存場所
zabbix_agent_command: "C:\"\\Program Files\\Zabbix Agent\"\\zabbix_agentd.exe -V | %{ $_.Split( )[4] }" # 現在のZabbixエージェントバージョンを出力するコマンド
zabbix_server_ip: "xx.xx.xx.xx" # ZabbixサーバーのIPアドレスを記載
Playbookの説明
ここからはPlaybookの設定を確認していきます。
site.yml
site.ymlはシステム全体でどのPlaybookを利用するかを制御します。site.ymlはシンプルにしておき、他のPlaybookを読み込むようにしておきます。roles:でzabbix_agent_windowsを指定しておくことで、/etc/ansible/roles/zabbix_agent_windows/task/main.ymlを読み込みます。
- /etc/ansible/site.yml
---
- name: Upgrade or fresh install Zabbix Agent on Windows # nameはPlayの説明を記載する
hosts: zabbix_agent_windows # hostsファイルのzabbix_agent_windowsグループのホストに対して実行
roles:
- zabbix_agent_windows
main.yml
main.ymlでは具体的に実行する内容を記載しています。変数はgeneral.ymlに記載したものを呼び出しています。
以下の手順でPlaybookを作成しています。
- Zabbixエージェントがインストールされているか確認 ※1
- Zabbixエージェントのバージョンを確認
- Zabbixフォルダのバックアップを作成
- Ansibleホストのfiles配下にあるmsiファイルをリモート先の資材ディレクトリ配下にコピー
- Zabbixエージェントを停止
- Zabbixエージェントのバージョンアップ(新規インストール)
- Zabbixエージェント起動 自動起動(遅延実行)設定
※1 Zabbixエージェントがインストールされていない場合は、手順2,3,5をスキップする
- /etc/ansible/roles/zabbix_agent_windows/tasks/main.yml
---
- name: Check if Zabbix Agent is installed
ansible.windows.win_command: sc query "Zabbix Agent"
changed_when: false
register: zabbix_installed # 実行結果を変数[zabbix_installed]に格納する
ignore_errors: yes # Zabbixエージェントがインストールされていない場合でも次のTaskを実行する
- name: Check Zabbix Agent version
ansible.windows.win_shell: '{{ zabbix_agent_command }}'
changed_when: false # ansible.builtin.shellモジュールは常に「changed」になるが、構成変更は行われていないため「ok」と表示する
register: zabbix_version # 実行結果を変数[zabbix_version]に格納する
when: zabbix_installed.rc == 0 # 「Check if Zabbix Agent is installed」Taskが失敗した場合、本Taskはskipされる
- name: Backup Zabbix directory
ansible.windows.win_copy:
src: "{{ zabbix_directory }}"
dest: "{{ zabbix_directory }}_{{ zabbix_version.stdout_lines[0] }}"
remote_src: yes # リモートホスト内のsrcフォルダからdestフォルダにコピーする
when:
- zabbix_installed.rc == 0
- zabbix_agent_package is not search(zabbix_version.stdout_lines[0]) # インストールされているバージョンと、今回インストールするバージョンが同じ場合、本Taskをskipする
- name: Copy Zabbix Agent package
ansible.windows.win_copy:
src: "{{ files_directory }}/{{ zabbix_agent_package }}.msi"
dest: "{{ work_directory }}"
- name: Stop Zabbix Agent
ansible.windows.win_service:
name: "Zabbix Agent"
state: stopped
when:
- zabbix_installed.rc == 0
- zabbix_agent_package is not search(zabbix_version.stdout_lines[0])
- name: Upgrade or fresh install Zabbix Agent
ansible.windows.win_package:
path: "{{ work_directory }}\\{{ zabbix_agent_package }}.msi"
state: present
arguments: /qn SERVER={{ zabbix_server_ip }} SERVERACTIVE={{ zabbix_server_ip }} HOSTNAME={{ inventory_hostname }}
- name: Start Zabbix Agent
ansible.windows.win_service:
name: "Zabbix Agent"
start_mode: delayed
state: started
Linux版の記事で冪等性を説明しましたが、Windows用モジュールにも一部冪等性が担保されないものがあります。ansible.windows.win_command、ansible.windows.win_shellなどコマンドが直接記載できるモジュールは、Taskで何か変化が起きた時のステータスである「changed」を常に返すため、冪等性が担保されません。
そんな時は「changed_when: false」と記載することで、強制的に「ok」ステータスを返します。
今回作成したPlaybookでは、3行目でansible.windows.win_commandを使用して以下のコマンドを実行しています。
sc query "Zabbix Agent"
また9行目ではansible.windows.win_shellを使用して以下のコマンドを実行しています。
C:"\Program Files\Zabbix Agent\zabbix_agentd.exe" -V | %{ $_.Split( )[4] }
このコマンドはZabbixエージェントのステータス確認とZabbixエージェントのバージョンを取得しているだけで構成の変化はないため、「changed_when: false」を記載して冪等性を担保するようにしています。
また今回作成したPlaybookでは「Upgrade or fresh install Zabbix Agent」Taskでzabbix_agentd.confの以下3つの設定のみ変更するようになっています。
- Server
- ServerActive
- Hostname
msiファイルでバージョンアップまたはインストールする際は、エージェントのパラメーターをargumentsに記載して設定しています。こちらは必要に応じて追加してください。
zabbix_agentd.confの設定がリモートホストごとに変更する設定内容が異なる場合は、Playbook内で個別に設定変更するのは難しいです。
個別に設定する時は事前に全リモートホスト分、[リモートホスト名]_zabbix_agentd.confを作成しておきます。作成したファイルを/etc/roles/zabbix_agent_windows/files配下に配置し、main.ymlの42行目に以下のTaskを追記することで、それぞれのリモートホストにzabbix_agentd.confを配置してくれます。
- name: Copy Zabbix Agent config file
ansible.windows.win_copy:
src: "{{ files_directory }}/{{ inventory_hostname }}_zabbix_agentd.conf"
dest: "{{ zabbix_directory }}\\zabbix_agentd.conf"
Playbook実行
1回目の実行
Ansible実行ユーザーにスイッチして、以下のコマンドでPlaybookを実行します。
$ ansible-playbook /etc/ansible/site.yml
Taskは以下のステータスで表示されます。
- ok : Taskが成功した時のステータス
- changed : Taskで何か変化が起きた時のステータス
- failed : Taskが失敗した時のステータス
- skipping : Taskをスキップする。(何も行わない)
PLAY [Upgrade or fresh install Zabbix Agent on Windows] ***************************
TASK [Gathering Facts] ************************************************************
ok: [ansible_remote-devlog1]
ok: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Check if Zabbix Agent is installed] ******************
ok: [ansible_remote-devlog1]
fatal: [ansible_remote-devlog2]: FAILED! => {"changed": false, "cmd": "sc query \"Zabbix Agent\"", "delta": "0:00:00.093755", "end": "2024-02-19 14:12:38.332137", "msg": "non-zero return code", "rc": 1060, "start": "2024-02-19 14:12:38.238381", "stderr": "", "stderr_lines": [], "stdout": "[SC] EnumQueryServicesStatus:OpenService FAILED 1060:\r\n\r\nThe specified service does not exist as an installed service.\r\n\r\n", "stdout_lines": ["[SC] EnumQueryServicesStatus:OpenService FAILED 1060:", "", "The specified service does not exist as an installed service.", ""]}
...ignoring
TASK [zabbix_agent_windows : Check Zabbix Agent version] **************************
ok: [ansible_remote-devlog1]
skipping: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Backup Zabbix directory] *****************************
changed: [ansible_remote-devlog1]
skipping: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Copy Zabbix Agent package] ***************************
changed: [ansible_remote-devlog1]
changed: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Stop Zabbix Agent] ***********************************
changed: [ansible_remote-devlog1]
skipping: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Upgrade or fresh install Zabbix Agent] ***************
changed: [ansible_remote-devlog1]
changed: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Start Zabbix Agent] **********************************
changed: [ansible_remote-devlog1]
changed: [ansible_remote-devlog2]
PLAY RECAP ************************************************************************
ansible_remote-devlog1 : ok=3 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible_remote-devlog2 : ok=1 changed=3 unreachable=0 failed=0 skipped=3 rescued=0 ignored=1
ansible_remote-devlog2では、Zabbixエージェントがインストールされていないため「Check if Zabbix Agent is installed」Taskが失敗しています。Taskが失敗した場合はrcに0が代入されます。
後続の「Check Zabbix Agent version」「Backup Zabbix directory」「Stop Zabbix Agent」Taskでは、when: zabbix_installed.rc == 0の条件をつけており、この条件を満たしているとTaskはskipされます。
「Upgrade or Fresh Install Zabbix Agent」Taskでは、ansible_remote-devlog1とansible_remote-devlog2ともに、Zabbix エージェントの新規インストール/バージョンアップに成功しています。
2回目の実行(冪等性の確認)
冪等性が担保されているか確認するためにPlaybookをもう一度実行します。
$ ansible-playbook /etc/ansible/site.yml
PLAY [Upgrade or Fresh Install Zabbix Agent on Windows] ***************************
TASK [Gathering Facts] ************************************************************
ok: [ansible_remote-devlog1]
ok: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Check if Zabbix Agent is installed] ******************
ok: [ansible_remote-devlog1]
ok: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Check Zabbix Agent version] **************************
ok: [ansible_remote-devlog1]
ok: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Backup Zabbix directory] *****************************
skipping: [ansible_remote-devlog1]
skipping: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Copy Zabbix Agent package] ***************************
ok: [ansible_remote-devlog1]
ok: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Stop Zabbix Agent] ***********************************
skipping: [ansible_remote-devlog1]
skipping: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Upgrade or fresh install Zabbix Agent] ***************
ok: [ansible_remote-devlog1]
ok: [ansible_remote-devlog2]
TASK [zabbix_agent_windows : Start Zabbix Agent] **********************************
ok: [ansible_remote-devlog1]
ok: [ansible_remote-devlog2]
PLAY RECAP ************************************************************************
ansible_remote-devlog1 : ok=6 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
ansible_remote-devlog2 : ok=6 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
changedが0となっているため、構成の変更は発生しませんでした。そのためPlaybookを実行した1回目と2回目で状態が同じになっており、冪等性が担保されていることが確認できました。
まとめ
前回の記事ではLinux版Zabbixエージェントの自動バージョンアップ紹介だったため、今回はWindows版msiファイルを用いたバージョンアップ方法を紹介しました。
次の記事ではZIPアーカイブファイルを用いた自動バージョンアップ方法を試してみたいと思います!
ぜひ興味を持たれた方は、Ansibleを使用した自動化を試してみてください。
Zabbixに関するお問い合わせはこちらからお願いいたします。