AnsibleでWindowsUpdateをやってみた。
Ansible解禁して一発目はこれ、と決めていたので、WindowsUpdateをやってみたお話を書きます。
Ansible関連の実践記事一覧はこちら。
目的
Windowsのセットアップや運用で必ず通る、アップデートをAnsibleで実施する方法を理解するため
環境
共通
下記のホストはすべてVirtual Box上の仮想マシンで実施。
Ansible側
項目 | 値 |
---|---|
OS | CentOS Linux release 7.6.1810 (Core) |
ansible | 2.8.5 |
python | 2.7.5 |
Pythonのサポートの話は認識はしてますが、とりあえず手元にあった環境で実験。
Ansibleのインストールは、まずはyumで導入しました。
ansible.cfgについては、-vを付けた時の出力形式が好みだったので、以下の設定だけ実施しています。
stdout_callback = unixy
操作対象側Windows
- Windows Server 2012 R2
- Windows Server 2016
両方とも、評価版でISOから手動でポチポチとインストール。
接続方法
今回は、実績も文献も多いWinRMを選択しています。
Windowsを操作するための初期設定
Ansible側
セットアップは以下のサイト(以下公式ガイド)を参照しながら実施。
Windows Remote Management — Ansible Documentation
WinRMのPython用のモジュールの導入
公式ガイド通り、pipにてpywinrmをインストール。
pip install "pywinrm>=0.3.0"
関連モジュールがいろいろと入りましたが、モジュールそのものはpywinrm-0.3.0が入りました。
インベントリの定義
過去のもくもく会や書籍などの情報から、インベントリはシンプルに、というのは理解していますが、まず動かしたかったのでインベントリに認証情報などを入力。
[win_2016] 192.168.10.233 [win_2012] 192.168.10.248 [windows:children] win_2016 win_2012 [windows:vars] ansible_user=Administrator ansible_password=P@ssw0rd ansible_connection=winrm ansible_winrm_transport=basic ansible_winrm_server_cert_validation=ignore
実際には、最後の1行(cert_validation)は後から付け足しました。
この手順通りに実行した場合、操作対象のWindowsには自己証明書が導入されるのですが、そのままだと接続のときに証明書の確認エラーで弾かれてしまいました。(以下ログ)
Gathering Facts... 192.168.10.233 unreachable: { "changed": false, "msg": "basic: HTTPSConnectionPool(host='192.168.10.233', port=5986): Max retries exceeded with url: /wsman (Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:618)'),))", "unreachable": true }
そのため、もう一度公式ガイドを確認したら、cert_validationについて、しっかり書いてありました。ちゃんと読め自分。
Windows側
インストール時のパラメータ
基本的に、Administratorのパスワードをインベントリに合わせたくらいです。
WinRMの設定
公式ガイドに、PowerShellでセットアップできる方法が記載があったため、そのまま実施。
Windows PowerShell Copyright (C) 2016 Microsoft Corporation. All rights reserved. PS C:\Users\Administrator> PS C:\Users\Administrator> $url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1" PS C:\Users\Administrator> $file = "$env:temp\ConfigureRemotingForAnsible.ps1" PS C:\Users\Administrator> PS C:\Users\Administrator> (New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file) PS C:\Users\Administrator> powershell.exe -ExecutionPolicy ByPass -File $file Self-signed SSL certificate generated; thumbprint: 804F14E0FFED613185E8049AEF5AB79E578DC775 wxf : http://schemas.xmlsoap.org/ws/2004/09/transfer a : http://schemas.xmlsoap.org/ws/2004/08/addressing w : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd lang : ja-JP Address : http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous ReferenceParameters : ReferenceParameters OK
設定されているかどうかの確認
こちらも、公式ガイドにあったとおりのコマンドでListenerの状態を確認。(ログはWin2016側のもの)
PS C:\Users\Administrator> winrm enumerate winrm/config/Listener Listener Address = * Transport = HTTP Port = 5985 Hostname Enabled = true URLPrefix = wsman CertificateThumbprint ListeningOn = 127.0.0.1, 192.168.10.233, ::1, 2001:0:348b:fb58:28d8:154a:3f57:f516, fe80::28d8:154a:3f57:f516%4, fe8 0::e572:d2e2:836a:bafe%3 Listener Address = * Transport = HTTPS Port = 5986 Hostname = WIN-KPFBQSB4964 Enabled = true URLPrefix = wsman CertificateThumbprint = 804F14E0FFED613185E8049AEF5AB79E578DC775 ListeningOn = 127.0.0.1, 192.168.10.233, ::1, 2001:0:348b:fb58:28d8:154a:3f57:f516, fe80::28d8:154a:3f57:f516%4, fe8 0::e572:d2e2:836a:bafe%3
よくあるハマりで、Windows Firewallの設定があるなあと思ってそちらも確認してみたのですが、自動で接続許可設定が入っていました。(Win2016/Win2012いずれも)
行き届いている…
またPowerShellの中身そのものは確認しておきたいところです。
両方完了後の疎通試験
win_pingモジュールを使いました。
もくもく会では、sshでの疎通試験だったなあと思いつつ、WinRMではどうやってやるんだ?と思い、Windowsのモジュール一覧を確認していたら、win_pingなるものがあるのを見つけました。
モジュール一覧から、目的のもの見つけ出すのは楽しいですね。
--- - name: Windows WinRM Ansible hosts: windows gather_facts: no tasks: - name: ping win_ping:
実行結果
ping... 192.168.10.233 ok 192.168.10.248 ok
Windows Updateの実施
まだやってる最中ですが、Win2012/Win2016いずれも1回は成功しました。
こんな感じのPlaybookにしています。
--- - name: Windows WinRM Ansible hosts: windows - name: Do Windows Update win_updates: category_names: - CriticalUpdates - SecurityUpdates - UpdateRollups state: installed # reboot: yes # reboot_timeout: 1800 register: update_result - name: debug debug: var: update_result verbosity: 0 - name: reboot if needed win_reboot: when: update_result.reboot_required
最初はwin_updatesの中でリブートという流れにしていたんですが、初回Update後のリブート→再起動後のパッチ適用でreboot_timeoutの初期値1200秒を超えてしまい、最終結果がfailedになることがわかりました。 Timeout値を長くしようか悩んだ挙句、まずは結果の出力を優先し、アップデートを切り離すことに。
やってみて
とっかかりこそ苦労したものの、2台目のホスト(Windows2012 R2)のセットアップはとても簡単でした。
今まで業務でPoC環境作るのに手動でぽちぽちやってたのがウソみたいです。
まずは取り急ぎ動かしてみただけなので、実運用を考えた場合に修正すべき点はたくさんあると思いますが、便利さが実感できただけでもとても満足できました。
今後もこんな風に、小さな成功体験を積み上げていきたいと思います。
ただ、動かしている最中に、どの程度作業が進行しているのかがわからないのが、ドキドキしてしまいます。(%表示とかが出ないので)
この辺は何かうまい方法があるのか、また探してみたいなと思います。
追伸
(現在、Win2012の2回目で絶賛ハマり中です…)
Do Windows Update... 192.168.10.248 failed: { "changed": false, "filtered_updates": {}, "msg": "Failed to search for updates: \"1\" 個の引数を指定して \"Search\" を呼び出し中に例外が発生しました: \"HRESULT からの例外:0x80072EFE\"", "updates": {} }
追伸の追伸
上記エラーは2回試して2回とも発生しました。
大型アップデートとかの初期処理がログイン後に走るのかな?と思ってコンソールでログインしてみましたが、特に動きはなく。
ただ、その後何もいじらずに再度WindowsaUpdateのPlaybook走らせてみたら、問題なく動きました。
ログインが功を奏したのか、時間が解決したのか、一体何なんだ…
またログなど確認して原因分かれば調べてみたいと思います。