使用Vagrant的配置工具,将Ansible用作Provisioner(在Windows上使用Cygwin作为Control Machine)

目前(版本1.8.4),Ansible尚不支持Windows作为控制机,但可以参考博客《在Windows上使用Vagrant与Ansible进行配置》等设置的步骤进行设置。

以上的一半可純粹使用Windows(Cygwin)來設置Ansible,與Vagrant無關而獨立使用。

此外,在最后一个避免措施中提到了一个未解决的问题(被认为是由于秘密密钥的权限过于宽松而被拒绝访问),为了回避此问题,部分情况下我们强行修改了Ansible源代码。

环境

    • Windows 8.1 Pro

 

    • Cygwin

 

    • Vagrant 1.7.2

 

    Ansible 1.8.4

配置Cygwin环境

使用传统的Cygwin安装程序,添加以下的Cygwin软件包。

    • python

 

    • python-paramiko

 

    • python-crypto

 

    • python-setuptools

 

    • gcc-core

 

    • gcc-g++

 

    • make

 

    • wget

 

    • openssh

 

    libyaml-devel

安装pip

为了安装Ansible,需要先安装pip(Python的包管理系统)(在此操作时,Cygwin的Python版本为2.7.8,因此默认不附带pip)。

$ python /usr/lib/python2.7/site-packages/easy_install.py pip
...
...
Installed /usr/lib/python2.7/site-packages/pip-6.0.8-py2.7.egg
Processing dependencies for pip
Finished processing dependencies for pip

安装Ansible

$ pip install ansible
Collecting ansible
  Downloading ansible-1.9.0.1.tar.gz (916kB)
...
...
Successfully installed PyYAML-3.11 ansible-1.9.0.1 ecdsa-0.13 jinja2-2.7.3 markupsafe-0.23

如果在执行命令”python setup.py egg_info”时出现错误代码1,那么请升级setuptools以解决安装问题。
$ pip install –upgrade setuptools

准备进行Ansible独立运行的测试。

在使用Ansible作为Vagrant的Provisioner之前,请先确认Ansible本身的正常运行。

准备管理节点

作为被Ansible控制的受管节点,需要预先使用vagrant up或其他方法来创建适当的虚拟机,并记下其IP地址(以下暂定为两个节点,分别为192.168.30.11和192.168.30.12)。

准备库存文件

mkdir /etc/ansible
chmod 755 /etc/ansible
192.168.30.11
192.168.30.12

SSH的安装设置

创建密钥对。

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/XXXX/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/XXXX/.ssh/id_rsa.
Your public key has been saved in /home/XXXX/.ssh/id_rsa.pub.
The key fingerprint is:

给Managed Node分配一个用于ssh连接的主机名(可选)

Host node01
  HostName 192.168.30.11
Host node02
  HostName 192.168.30.12

如果进行了这个设置,库存文件可以使用以下选项。

node01
node02

将公钥分发给托管节点。

$ ssh-copy-id vagrant@node01`
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
vagrant@192.168.30.11's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'vagrant@node01'"
and check to make sure that only the key(s) you wanted were added.

$ ssh-copy-id vagrant@node02
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
vagrant@192.168.30.11's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'vagrant@node02'"
and check to make sure that only the key(s) you wanted were added.

在这里,@前面的“vagrant”是登录到node01、node02的用户名。

控制主端设置

据称,Ansible与SSH的控制主机之间存在通信问题,因此需要进行以下修正。

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
control_path = /tmp

顺便提一下,如果不进行这个设定的话

fatal: [node01] => SSH Error: Failed to connect to new control master
    while connecting to 192.168.30.11:22

变成这样。

启动SSH身份验证代理

为了省去输入密码的步骤,可以使用认证代理程序。

$ eval `ssh-agent`
Agent pid 9148

(ssh-agent)您需要用单引号将其括起来。

顺便提一下,如果不使用认证代理,不仅需要多次输入密码短语,而且由于需要同时处理到多个节点的SSH连接请求,使得输入密码短语的要求混乱在一起,无法顺利输入。在这种情况下,可以在启动ansible-playbook时添加“-f 1”参数,以便一次只处理一个节点,从而可以输入密码短语。

让认证代理记住私钥

$ ssh-add .ssh/id_rsa
Enter passphrase for .ssh/id_rsa:
Identity added: .ssh/id_rsa (.ssh/id_rsa)

验证Ansible的独立操作

自定义命令

尝试执行Ad-hoc命令来验证Ansible在独立运行时的工作情况,并从两个被管理的节点中获取/etc/redhat-release文件的命令来尝试执行。

$ ansible all -a "cat /etc/redhat-release" -u vagrant
192.168.30.12 | success | rc=0 >>
CentOS Linux release 7.1.1503 (Core)

192.168.30.11 | success | rc=0 >>
CentOS Linux release 7.1.1503 (Core)

顺利无故事的获得成功。

剧本 (jù

準備一份Playbook來確認簡單的操作。
在兩個節點上,準備一個名為”kuroneko”的使用者註冊Playbook。

$ cat <<EOF > add_user.yml
> - hosts: all
>   sudo: yes
>   remote_user: vagrant
>   vars:
>     username: kuroneko
>   tasks:
>     - name: add user
>       user: name={{ username }} group=wheel shell=/usr/bin/bash
> EOF

试着运行ansible-playbook。

$ ansible-playbook add_user.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.30.11]
ok: [192.168.30.12]

TASK: [add user] **************************************************************
changed: [192.168.30.11]
changed: [192.168.30.12]

PLAY RECAP ********************************************************************
192.168.30.11              : ok=2    changed=1    unreachable=0    failed=0
192.168.30.12              : ok=2    changed=1    unreachable=0    failed=0

经过努力,一切顺利。为了确认kuroneko已经创建成功,还是再次确认一下。

$ ansible all -a "grep kuroneko /etc/passwd" -u vagrant
192.168.30.12 | success | rc=0 >>
kuroneko:x:1002:10::/home/kuroneko:/usr/bin/bash

192.168.30.11 | success | rc=0 >>
kuroneko:x:1002:10::/home/kuroneko:/usr/bin/bash

确认到用户”kuroneko”已经成功添加并且playbook成功执行。

将ansible-playbook配置为可以从vagrant中调用

准备ansible-playbook.bat文件

要从Vagrant中调用ansible-playbook,可以进行以下操作:

    • Windows PATHの中に ansible-playerを配置する

 

    ansible-playerがCygwinのPaythonを使用できる

这是必要的。
因此,请将以下的bat文件放置在C:\HashiCorp\Vagrant\bin目录下。

@echo off

set CYGWIN=C:\cygwin64

set SH=%CYGWIN%\bin\bash.exe

"%SH%" -c "/bin/ansible-playbook %*"

在这里,CYGWIN=C:\cygwin64是Cygwin安装目录。请根据实际环境进行设置。另外,放置bat文件的目录不一定要是C:\HashiCorp\Vagrant\bin。可以放在Windows的PATH路径下。

我会执行ansible-playbook.bat进行确认。

$ ansible-playbook.bat add_user.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [node01]
ok: [node02]

TASK: [add user] **************************************************************
ok: [node01]
ok: [node02]

PLAY RECAP ********************************************************************
node01                     : ok=2    changed=0    unreachable=0    failed=0
node02                     : ok=2    changed=0    unreachable=0    failed=0

bat文件调用了ansible-playbook,成功执行了add_user.yml。

对于Ansible作为Vagrant的Provisioner的运行验证,请确认。

准备Vasgrantfile

准备一个Vagrantfile以创建两个运行CentOS 7 (1503)操作系统的虚拟服务器,并进行Apache provisioning。

Vagrant.configure(2) do |config|

  if Vagrant.has_plugin?("vagrant-cachier")
    config.cache.scope = :box
  end
  if Vagrant.has_plugin?("vagrant-vbguest")
    config.vbguest.auto_update = false
  end
  config.vm.define "web02" do |web|
    web.vm.box = "centos7-1503-01-min"
    web.vm.hostname = "web02"
    web.vm.network "private_network", ip: "192.168.40.12"
    web.vm.provision "shell",
      inline: "nmcli connection reload;systemctl restart network.service"
    web.vm.provision "ansible" do |ansible|
      ansible.playbook = "ensure-apache-latest.yml"
    end
  end
  config.vm.define "web01" do |web|
    web.vm.box = "centos7-1503-01-min"
    web.vm.hostname = "web01"
    web.vm.network "private_network", ip: "192.168.40.11"
    web.vm.provision "shell",
      inline: "nmcli connection reload;systemctl restart network.service"
    web.vm.provision "ansible" do |ansible|
      ansible.playbook = "ensure-apache-latest.yml"
    end
  end

end

被呼唤的Playbook如下所示。

- hosts: all
  sudo: yes
  remote_user: vagrant
  tasks:
    - name: ensure apache is at the latest version
      yum: pkg=httpd state=latest
      notify:
      - stop firewalld
      - restart httpd
  handlers:
    - name: stop firewalld
      service: name=firewalld state=stopped enabled=no
    - name: restart httpd
      service: name=httpd state=restarted enabled=yes

确认动作(失败)

当在上述的Vagrantfile中执行vagrant up时,会显示以下错误消息,导致无法启动Playbook。

fatal: [web01] => private_key_file (D:/Vagrant/projects/ansible-windows/.vagrant/machines/web01/virtualbox/private_key) is group-readable or world-readable and thus insecure - you will probably get an SSH failure

看起来私的密钥文件的权限设置太宽松了,即使使用chmod 600或者通过setfacl严格设置了ACL,问题仍无法解决。
在这篇文章的开头,我使用了~/.ssh/id_rsa进行Playbook的操作确认,所以我尝试设置相同的权限,例如:设置同样的权限~/.ssh/id_rsa或尝试getfacl ~/.ssh/id_rsa | setfacl -f – private_key等,但奇怪的是问题依然无法解决。通过执行stat private_key等命令,看起来并没有什么异常。我可能在Cygwin和Windows的权限相关问题上漏掉了一些东西,但我不知道是什么。因此,我选择了下一个应急措施。

避免策略

上面的错误信息是由/usr/lib/python2.7/site-packages/ansible/runner/connection.py输出的。

if st is not None and st.st_mode & (stat.S_IRGRP | stat.S_IROTH):
  raise AnsibleError("private_key_file (%s) is group-readable or world-readable and thus insecure - "
    "you will probably get an SSH failure"
    % (private_key_file,))

我试验性地使用”#”将此部分注释掉,然后执行了vagrant destroy;vagrant up。成功地进行了配置操作。

$ vagrant up
Bringing machine 'web02' up with 'virtualbox' provider...
Bringing machine 'web01' up with 'virtualbox' provider...
...
...
...
==> web02: Running provisioner: ansible...
...
...
...
PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [web02]

TASK: [ensure apache is at the latest version] ********************************
changed: [web02]

NOTIFIED: [stop firewalld] ****************************************************
changed: [web02]

NOTIFIED: [restart httpd] *****************************************************
changed: [web02]

PLAY RECAP ********************************************************************
web02                      : ok=4    changed=3    unreachable=0    failed=0
==> web02: Configuring cache buckets...
==> web01: Importing base box 'centos7-1503-01-min'...
...
...
...
==> web01: Running provisioner: ansible...
...
...
...
PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [web01]

TASK: [ensure apache is at the latest version] ********************************
changed: [web01]

NOTIFIED: [stop firewalld] ****************************************************
changed: [web01]

NOTIFIED: [restart httpd] *****************************************************
changed: [web01]

PLAY RECAP ********************************************************************
web01                      : ok=4    changed=3    unreachable=0    failed=0
==> web01: Configuring cache buckets...

顺便提一下

如果按照上述Vagrantfile中的ansible playbook的调用方式,只是单调地顺序执行创建虚拟服务器、配置和创建虚拟服务器、配置,这样很无聊。Vagrant文档中的Ansible的小技巧中有一条名为”ANSIBLE PARALLEL EXECUTION”的记录。我尝试在下面的Vagrantfile中模仿这个方法,进行并行执行配置。

Vagrant.configure(2) do |config|

  if Vagrant.has_plugin?("vagrant-cachier")
    config.cache.scope = :box
  end
  if Vagrant.has_plugin?("vagrant-vbguest")
    config.vbguest.auto_update = false
  end
  config.ssh.insert_key = false
  config.vm.define "web02" do |web|
    web.vm.box = "centos7-1503-01-min"
    web.vm.hostname = "web02"
    web.vm.network "private_network", ip: "192.168.40.12"
    web.vm.provision "shell",
      inline: "nmcli connection reload;systemctl restart network.service"
  end
  config.vm.define "web01" do |web|
    web.vm.box = "centos7-1503-01-min"
    web.vm.hostname = "web01"
    web.vm.network "private_network", ip: "192.168.40.11"
    web.vm.provision "shell",
      inline: "nmcli connection reload;systemctl restart network.service"
    web.vm.provision "ansible" do |ansible|
      ansible.playbook = "ensure-apache-latest.yml"
      ansible.limit = 'all'
    end
  end

end

如果忘记将config.ssh.insert_key = false设置为true,则除了一个虚拟服务器外,不能使用同一个密钥进行ssh,并且这会导致部署失败,所以请注意。

看起来似乎可以使用,但之后必须更换不安全的传统密钥。

广告
将在 10 秒后关闭
bannerAds