てんこ

ブログ名は愛猫(てん)の愛称です。中身は個人のIT系学習記録です。

AnsibleでWindowsUpdateをやってみた。

Ansible解禁して一発目はこれ、と決めていたので、WindowsUpdateをやってみたお話を書きます。

Ansible関連の実践記事一覧はこちら。

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

両方とも、評価版でISOから手動でポチポチとインストール。

接続方法

今回は、実績も文献も多いWinRMを選択しています。

Windowsを操作するための初期設定

Ansible側

セットアップは以下のサイト(以下公式ガイド)を参照しながら実施。

Windows Remote Management — Ansible Documentation

WinRMのPython用のモジュールの導入

公式ガイド通り、pipにてpywinrmをインストール。

pip install "pywinrm>=0.3.0"

関連モジュールがいろいろと入りましたが、モジュールそのものはpywinrm-0.3.0が入りました。

f:id:tatematsu_san:20191014203136p:plain

インベントリの定義

過去のもくもく会や書籍などの情報から、インベントリはシンプルに、というのは理解していますが、まず動かしたかったのでインベントリに認証情報などを入力。

[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なるものがあるのを見つけました。

モジュール一覧から、目的のもの見つけ出すのは楽しいですね。

win_ping.yaml

---
- 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走らせてみたら、問題なく動きました。

ログインが功を奏したのか、時間が解決したのか、一体何なんだ…

またログなど確認して原因分かれば調べてみたいと思います。