Ansibleを用いたWindows版Zabbixエージェントの自動バージョンアップ MSIファイル編

Ansible,Infrastructure as Code,Zabbix

こんにちは!プラットフォーム技術部の小羽根陸です。

前回の記事では、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を作成しています。

  1. Zabbixエージェントがインストールされているか確認 ※1
  2. Zabbixエージェントのバージョンを確認
  3. Zabbixフォルダのバックアップを作成
  4. Ansibleホストのfiles配下にあるmsiファイルをリモート先の資材ディレクトリ配下にコピー
  5. Zabbixエージェントを停止
  6. Zabbixエージェントのバージョンアップ(新規インストール)
  7. 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_commandansible.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 Japan LLC の認定パートナー企業です。 当社はZabbixバージョン1.1の時代から監視ソリューションの活用を進め、Zabbixに関する製品・サービスの販売に加え、Zabbix関連サービスの提供を行っています。

Zabbixに関するお問い合わせはこちらからお願いいたします。
  • 株式会社アークシステムの予約・来訪管理システム BRoomHubs
  • 低コスト・短納期で提供するまるごとおまかせZabbix