准备使用Ansible控制Windows操作系统
首先
由于Ansible 1.7版本开始可以操作Windows系统,现在我将写出执行所需的准备工作。
(2015-01-18:根据现状进行大幅修改)
(2015-03-27:添加了“使用Ansible 1.9.0.1时需要的额外工作”)
(2015-04-29:由于1.9.1解决了“使用Ansible 1.9.0.1时需要的额外工作”,所以进行了修正)
(2016-02-27:终于有时间了,虽然有些晚了,但是对文章进行了2.0版本的适配)
(2016-04-17:网络配置文件即使是公共的也可以使用,并且ansible_winrm_*已经回溯到了1.9.5版本)
(2017-06-03:在2.3.1版本中也可以在Python 3上运行)
这次的环境
首先进行了如下的尝试阶段:
被操作的Windows正在使用8.1更新版和Windows Server 2012 R2。
进行操作的一方正在使用CentOS 7.0.1406,并在Ansible 1.7.1及以后版本上确认过。
Windows端的准备
Ansible使用Windows远程管理(WinRM)来操作Windows系统。
因此,需要对Windows进行设置和配置以启用WinRM。
首先以管理员身份运行PowerShell。
值得一提的是,Ansible要求Windows系统使用PowerShell 3.0或更高版本,但Windows 8.1和Windows Server 2012 R2已经预装了PowerShell 4.0,所以没有问题。
有关可以使用PowerShell 3.0或更高版本的Windows版本,请参考下文中的“附注:可用于Ansible操作的Windows版本”。
因为官方提供了能够帮助进行Windows端准备的脚本,所以需要下载该脚本。
(以下、将PowerShell控制台提示符表示为“PS >”)
PS > mkdir C:\work
PS > cd C:\work
PS > Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile ConfigureRemotingForAnsible.ps1
如果网络配置文件不是公共网络,那么运行下载的ConfigureRemotingForAnsible.ps1文件。可以在Windows 8/2012或更新版本上使用PowerShell运行Get-NetConnectionProfile -IPv4Connectivity Internet命令来获取NetworkCategory的值来查看网络配置文件。在Windows 7上可以通过网络共享中心等方式进行确认。
PS > powershell -ExecutionPolicy RemoteSigned .\ConfigureRemotingForAnsible.ps1
如果网络配置文件是公共的,请添加-SkipNetworkProfileCheck选项后执行。
PS > powershell -ExecutionPolicy RemoteSigned .\ConfigureRemotingForAnsible.ps1 -SkipNetworkProfileCheck
备注:适用于Ansible操作的Windows版本
可以将可通过Ansible操作的Windows版本总结如下。
从Windows 8或Windows Server 2012起,PowerShell 3.0以上版本已经预装。
最初已预装的是PowerShell 2.0以前的版本,但可以安装PowerShell 3.0
→可以在Windows 7和Windows Server 2008 R2上安装。
中就没有预装PowerShell,但可以安装PowerShell 3.0。
尽管Windows Vista与Windows Server 2008具有相同的代码基础,但没有提供PowerShell 3.0版本。
以下的页面按表格形式整理在此链接中:
http://ja.wikipedia.org/wiki/Windows_PowerShell
以下链接是从官方文档中链接的一个脚本,用于在Windows 7、Windows Server 2008 (R2)上安装PowerShell 3.0。然而,需要手动安装.NET Framework 4或更高版本才能安装PowerShell 3.0,因为该部分已被注释掉。
https://github.com/cchurch/ansible/blob/devel/examples/scripts/upgrade_to_ps3.ps1
然而,该脚本的功能只是下载并安装安装程序,所以您也可以随意通过Web浏览器下载并安装,没有问题。
Ansible方面的准备工作
对于Ansible来说,还需要准备与WinRM通信的环境。
安装pip并使用pip安装pywinrm。
# curl -sL https://bootstrap.pypa.io/get-pip.py | python
# pip install pywinrm
Ansible 1.9.x以前,创建以下样式的主机清单文件。
如果在Windows端指定的用户不属于Administrators组,则无法使用WinRM连接,并在执行ansible命令时会出错。
如果用户属于域,则可以属于Domain Admins组或Enterprise Admins组。
只有在Python 2.7.9或更高版本中才需要使用ansible_winrm_server_cert_validation=ignore。这个参数仅在Ansible 2.0/1.9.5或更高版本以及pywinrm 0.1.1或更高版本时才会被使用,但即使不满足这些条件,写出它也是无害的。(→从Python 2.7.9开始,进行了进行HTTPS证书验证的规范更改)
[windows]
<Windowsの解決可能なホスト名かIPアドレス>
[windows:vars]
ansible_ssh_user=<Windows側のユーザ名>
ansible_ssh_pass=<Windows側ユーザのパスワード>
ansible_ssh_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
在Ansible 2.0版本中,以ansible_ssh_开头的参数名称将被废弃掉。
目前在2.0版本中仍然可以使用上述的写法,但将来将会变成以下的形式。
[windows]
<Windowsの解決可能なホスト名かIPアドレス>
[windows:vars]
ansible_user=<Windows側のユーザ名>
ansible_password=<Windows側ユーザのパスワード>
ansible_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
如果你不喜欢将密码以明文形式保存,可以选择将其放入Ansible Vault中,或在执行时使用-k选项进行输入。
确认行动。
# ansible windows -i hosts -m win_ping -vvvv
从Ansible 2.3.1开始,它也支持Python 3运行。
在旧版本中的错误。
WinRM连接插件的错误(1.7.0 – 1.7.2)
由于Ansible 1.7.0至1.7.2版本在WinRM连接中失败并报错,所以需要在Ansible源代码中进行一处修正。
https://github.com/ansible/ansible/issues/8720(标题中提到https或http都会普遍发生该问题)
该问题已在1.8.0版本中修复,所以在以后的版本中不需要进行此操作。
# sed -i.bak '90s/exc\.args\[0\]/exc/' /usr/lib/python2.7/site-packages/ansible/runner/connection_plugins/winrm.py
在Windows系统模块中缺失 (1.8.0 – 1.8.1)。
在Ansible 1.8.0和1.8.1版本中,Windows模块文件中扩展名为ps1的文件丢失了。因此,在执行win_ping模块之前,请执行以下操作进行下载。
在1.7.x版本或1.8.2之后,此步骤无需进行。
# for x in {setup,slurp,win_feature,win_get_url,win_group,win_msi,win_ping,win_service,win_stat,win_user}; do wget https://raw.githubusercontent.com/ansible/ansible-modules-core/release1.8.0/windows/${x}.ps1 -P /usr/lib/python2.7/site-packages/ansible/modules/core/windows/; done
如果不执行此操作,则会输出以下错误消息。
FAILED => module win_ping not found in configured module paths. Additionally, core modules are missing. If this is a checkout, run 'git submodule update --init --recursive' to correct this problem.
这个错误的原因是在打包时使用的 https://github.com/ansible/ansible/blob/devel/setup.py 中的package_data参数指定不足。
当执行策略为”Restricted”时的错误 (1.9.0.1)
如果在Ansible 1.9.0.1版本中,Windows系统下的Powershell执行策略为Restricted,则Ansible在WinRM连接时执行会失败。在此情况下,错误消息的一部分会显示为“<模块名称>.ps1不能加载,因为运行脚本”。(在Windows 8.1更新版中验证过)
只需要一个选项。在Windows端,如果将Execution Policy例如更改为RemoteSigned,就可以运行。
此更改在重新启动操作系统后仍然有效。
PS > Set-ExecutionPolicy RemoteSigned -Force
只要「Ansible側の準備」完成,即使处于Restricted状态,也可以使用raw模块。从Ansible端执行以下操作即可将其更改为RemoteSigned。
# ansible windows -i hosts -m raw -a 'powershell Set-ExecutionPolicy RemoteSigned -Force'
这个现象仅在1.9.0.1版本中发生。
(虽然理论上也应该在1.9.0版本中发生,但由于这个版本很快被更新,所以没有特别确认)
允许使用HTTP协议进行连接。
当在Windows系统上运行ConfigureRemotingForAnsible.ps1脚本时,将允许使用HTTPS协议进行WinRM连接。尽管在WinRM连接中可以使用HTTP协议,但ConfigureRemotingForAnsible.ps1脚本不允许使用HTTP协议。
如果只允许HTTPS协议,那么使用Ansible操作Windows就足够了。但如果因某种原因还想允许HTTP协议的连接,只需执行以下附加命令即可。
PS > winrm set winrm/config/service '@{AllowUnencrypted="true"}'
这是一个用于更改WinRM配置的命令。
可以通过运行winrm get winrm/config来查看当前的配置内容。
如果在Windows端允许HTTP协议,除了使用5986端口进行HTTPS连接外,还可以通过5985端口进行连接。
因此,只要将Ansible的清单文件设置为以下方式,就可以进行连接。
[windows]
<Windowsの解決可能なホスト名かIPアドレス>
[windows:vars]
ansible_user=<Windows側のユーザ名>
ansible_password=<Windows側ユーザのパスワード>
ansible_port=5985
ansible_connection=winrm
Ansible 2.0/1.9.5之后设置名为ansible_winrm_(key)的参数会将键和值传递给pywinrm。因此,2.0/1.9.5之后可以使用ansible_winrm_scheme参数来指定协议。ansible_winrm_scheme的初始值为http,仅当ansible_port的值为5985时,否则为https。
[windows]
<Windowsの解決可能なホスト名かIPアドレス>
[windows:vars]
ansible_user=<Windows側のユーザ名>
ansible_password=<Windows側ユーザのパスワード>
ansible_port=80
ansible_connection=winrm
ansible_winrm_scheme=http
Ansible 1.9.4之前无法指定协议,当使用5985端口时会自动选择HTTP,当使用5986端口时会自动选择HTTPS。
关于使用HTTPS协议的备注
自己签署的证明书有效期限
通过ConfigureRemotingForAnsible.ps1在Windows端创建了一个自签名证书(也称为自制证书),其有效期为一年。然而,即使在Windows端将时钟往前调了五年并运行了ConfigureRemotingForAnsible.ps1,然后将时钟恢复到正确的时间,也可以正常操作而不会出现任何错误。
Python 2.7.9版本或后续版本已进行了对HTTPS证书进行验证的规范更改。
2014年12月10日,Python 2.7.9版本发布了,但是在Ansible中使用Python 2.7.9版本并尝试使用HTTPS协议进行WinRM连接时,会出现以下错误:
WINRM连接错误:500 WinRMTransport。[SSL:CERTIFICATE_VERIFY_FAILED]证书验证失败(_ssl.c:581)。
由于这不是针对自签名证书的错误,而是一个规范更改,所以在Python 2.7.10及更高版本中也会出现相同的情况。
如果Ansible的版本是2.0/1.9.5或之后,且pywinrm的版本是0.1.1或之后,则可以通过设置ansible_winrm_server_cert_validation=ignore来避免对Python 2.7.9或之后版本的HTTPS证书进行验证,以避免错误。即使对于2.7.8或之前的版本,此选项也是无害的。
[windows]
<Windowsの解決可能なホスト名かIPアドレス>
[windows:vars]
ansible_user=<Windows側のユーザ名>
ansible_password=<Windows側ユーザのパスワード>
ansible_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
只需要添加以下内容到 Ansible 1.9.4 的 ansible/runner/connection_plugins/winrm.py 文件中的 _winrm_connect 方法的开头,问题就能暂时解决。
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
情报来源:链接地址为https://github.com/ansible/ansible/pull/10132
实战篇
-
- 使用Ansible通过Chocolatey在Windows上安装应用程序
-
- 使用Ansible在Windows服务器上配置Active Directory
- 使用Ansible将Windows设备转为SSH服务器
在PowerShell 4.0及更高版本中,可以使用wget或curl作为Invoke-WebRequest的别名来下载脚本文件(-Uri也可以省略)。因此,可以按照以下方式进行下载:wget https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile ConfigureRemotingForAnsible.ps1。
如果执行Get-ExecutionPolicy发现比RemoteSigned更宽松的设置,那么只需要执行.\ConfigureRemotingForAnsible.ps1即可。如果没有特别更改的话,执行策略默认为Restricted除了Windows 2012 R2为RemoteSigned。关于ExecutionPolicy的详细信息可以参考http://qiita.com/kikuchi/items/59f219eae2a172880ba6。
对于Windows 8/2012及更高版本,可以通过Set-NetConnectionProfile -InterfaceAlias (Get-NetConnectionProfile -IPv4Connectivity Internet).InterfaceAlias -NetworkCategory Private来将网络配置修改为私有。如果要在GUI界面操作,将鼠标移动到右下角,然后点击“Settings>Change PC settings>Network”,点击“Connected”状态的网络,如果设备和内容搜索已关闭,则为公共网络,需要修改为私有。在Windows 7中,可以在网络共享中心等地方进行修改。
在正文中,为安装pip指定了通用命令curl -sL https://bootstrap.pypa.io/get-pip.py | python,但是在CentOS中可以通过EPEL安装python-pip,所以也可以使用yum install python-pip。Ubuntu等系统中也有python-pip可用。
准确来说,在端口5985的情况下,首先尝试使用HTTP连接,如果无法连接,则尝试使用HTTPS连接。而对于其他端口号,首先尝试使用HTTPS连接,如果无法连接,则尝试使用HTTP连接(但从1.9版本开始,尝试使用HTTPS连接并无法连接则停止)。