今天在拜讀Jeff Geerling撰寫的Ansible for DevOps一書 (ISBN 978-0-9863934-0-2),寫得很不錯,值得好好研讀。文中介紹了很多其他方面的知識,如第10章Server Security and Ansible部分對SSH的歷史、特性、優化做了詳細介紹,本人已將新獲取的知識整合進 SSH Configurations And Usages

文中的實驗環境使用VagrantVirtualBox搭建,第3章Local Infrastructure Development: Ansible and Vagrant部分介紹了如何使用ansible配置vagrant guest matchine。本人是剛知曉Vagrant有該功能,查閱其官方文檔Vagrant有一個Provisioner功能,支持安裝軟件、調整配置,是vagrant up進程的一部分(第一次執行時)。也可執行vagrant up後,再執行vagrant provision。文檔頁PROVISIONING

Provisioners in Vagrant allow you to automatically install software, alter configurations, and more on the machine as part of the vagrant up process.

Introduction

關於AnsibleVagrant支持兩種 * ANSIBLE PROVISIONER:調用宿主機或Vagrant host中的ansible執行playbook * ANSIBLE LOCAL PROVISIONER:調用Vagrant虛擬機中的ansible執行playbook

此處只介紹ANSIBLE PROVISIONER,其在Vagrant的配置文件Vagrantfile的配置格式如下

Vagrant.configure("2") do |config|

  #
  # Run Ansible from the Vagrant Host
  #
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "playbook.yml"
  end

end

Ansibleplaybook.yml直接創建在vagrant目錄下,順序執行如下命令

vagrant up
vagrant provision

即可自動執行playbook中定義的task

Experiment

以下是實驗過程,使用Ansible安裝Apache Web Server

Preparation

本文使用此前自己創建的box CentOS7Minimal (virtualbox, 0)進行vagrant init初始化安裝。

[flying@lemp ansible]$ ls -lhA
total 8.0K
-rw-rw-r-- 1 flying flying 199 Mar 24 23:17 playbook.yml
drwxrwxr-x 4 flying flying  40 Mar 24 22:29 .vagrant
-rw-rw-r-- 1 flying flying 602 Mar 24 23:13 Vagrantfile
[flying@lemp ansible]$

此處配置3臺Vagrant虛擬機

  • Vagrantfile內容 ```

    -- mode: ruby --

    vi: set ft=ruby :

boxes = [ { :name => :slave1, :ip => ‘192.168.0.50’ }, { :name => :slave2, :ip => ‘192.168.0.51’ }, { :name => :slave3, :ip => ‘192.168.0.52’ }, ]

Vagrant.configure(2) do |config| config.vm.box = “CentOS7Minimal”

boxes.each do |opts|
    config.vm.define opts[:name] do |config|
        config.vm.network "public_network",ip: opts[:ip],bridge: "wlp3s0"
        config.vm.host_name = "%s.vm" % opts[:name].to_s
        config.vm.provision "ansible" do |ansible|                
            #ansible.inventory_path = "hosts" #inventory路徑
            ansible.playbook = "playbook.yml"
        end
    end
end

end


安裝Apache Web Server

* `playbook.yml`內容

  • hosts: all sudo: yes tasks:
    • name: Install Apache Web Server yum: name=httpd state=present
    • name: Start and Enable Httpd Service service: name=httpd state=started enabled=yes ```

Vagrant up

[flying@lemp ansible]$ pwd
/home/flying/vagrant/ansible
[flying@lemp ansible]$ vagrant up
Bringing machine 'slave1' up with 'virtualbox' provider...
Bringing machine 'slave2' up with 'virtualbox' provider...
Bringing machine 'slave3' up with 'virtualbox' provider...
==> slave1: Clearing any previously set forwarded ports...
==> slave1: Clearing any previously set network interfaces...
==> slave1: Preparing network interfaces based on configuration...
    slave1: Adapter 1: nat
    slave1: Adapter 2: bridged
==> slave1: Forwarding ports...
    slave1: 22 (guest) => 2222 (host) (adapter 1)
==> slave1: Booting VM...
==> slave1: Waiting for machine to boot. This may take a few minutes...
    slave1: SSH address: 127.0.0.1:2222
    slave1: SSH username: vagrant
    slave1: SSH auth method: private key
    slave1: Warning: Remote connection disconnect. Retrying...
==> slave1: Machine booted and ready!
GuestAdditions 5.0.16 running --- OK.
==> slave1: Checking for guest additions in VM...
==> slave1: Setting hostname...
==> slave1: Configuring and enabling network interfaces...
==> slave1: Mounting shared folders...
    slave1: /vagrant => /home/flying/vagrant/ansible
==> slave1: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> slave1: flag to force provisioning. Provisioners marked to run always will still run.
==> slave2: Clearing any previously set forwarded ports...
==> slave2: Fixed port collision for 22 => 2222. Now on port 2200.
==> slave2: Clearing any previously set network interfaces...
==> slave2: Preparing network interfaces based on configuration...
    slave2: Adapter 1: nat
    slave2: Adapter 2: bridged
==> slave2: Forwarding ports...
    slave2: 22 (guest) => 2200 (host) (adapter 1)
==> slave2: Booting VM...
==> slave2: Waiting for machine to boot. This may take a few minutes...
    slave2: SSH address: 127.0.0.1:2200
    slave2: SSH username: vagrant
    slave2: SSH auth method: private key
    slave2: Warning: Remote connection disconnect. Retrying...
==> slave2: Machine booted and ready!
GuestAdditions 5.0.16 running --- OK.
==> slave2: Checking for guest additions in VM...
==> slave2: Setting hostname...
==> slave2: Configuring and enabling network interfaces...
==> slave2: Mounting shared folders...
    slave2: /vagrant => /home/flying/vagrant/ansible
==> slave2: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> slave2: flag to force provisioning. Provisioners marked to run always will still run.
==> slave3: Clearing any previously set forwarded ports...
==> slave3: Fixed port collision for 22 => 2222. Now on port 2201.
==> slave3: Clearing any previously set network interfaces...
==> slave3: Preparing network interfaces based on configuration...
    slave3: Adapter 1: nat
    slave3: Adapter 2: bridged
==> slave3: Forwarding ports...
    slave3: 22 (guest) => 2201 (host) (adapter 1)
==> slave3: Booting VM...
==> slave3: Waiting for machine to boot. This may take a few minutes...
    slave3: SSH address: 127.0.0.1:2201
    slave3: SSH username: vagrant
    slave3: SSH auth method: private key
    slave3: Warning: Remote connection disconnect. Retrying...
==> slave3: Machine booted and ready!
GuestAdditions 5.0.16 running --- OK.
==> slave3: Checking for guest additions in VM...
==> slave3: Setting hostname...
==> slave3: Configuring and enabling network interfaces...
==> slave3: Mounting shared folders...
    slave3: /vagrant => /home/flying/vagrant/ansible
==> slave3: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> slave3: flag to force provisioning. Provisioners marked to run always will still run.
[flying@lemp ansible]$

Vagrant provision

[flying@lemp ansible]$ vagrant provision
==> slave1: Running provisioner: ansible...
    slave1: Running ansible-playbook...

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

GATHERING FACTS ***************************************************************
ok: [slave1]

TASK: [Install Apache Web Server] *********************************************
changed: [slave1]

TASK: [Start and Enable Httpd Service] ****************************************
changed: [slave1]

PLAY RECAP ********************************************************************
slave1                     : ok=3    changed=2    unreachable=0    failed=0   

==> slave2: Running provisioner: ansible...
    slave2: Running ansible-playbook...

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

GATHERING FACTS ***************************************************************
ok: [slave2]

TASK: [Install Apache Web Server] *********************************************
changed: [slave2]

TASK: [Start and Enable Httpd Service] ****************************************
changed: [slave2]

PLAY RECAP ********************************************************************
slave2                     : ok=3    changed=2    unreachable=0    failed=0   

==> slave3: Running provisioner: ansible...
    slave3: Running ansible-playbook...

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

GATHERING FACTS ***************************************************************
ok: [slave3]

TASK: [Install Apache Web Server] *********************************************
changed: [slave3]

TASK: [Start and Enable Httpd Service] ****************************************
changed: [slave3]

PLAY RECAP ********************************************************************
slave3                     : ok=3    changed=2    unreachable=0    failed=0   

[flying@lemp ansible]$

Verification

使用curl --head獲取各虛擬主機HTTP響應header信息,用以證明成功安裝了httpd

[flying@lemp ansible]$ curl --head http://192.168.0.50
HTTP/1.1 403 Forbidden
Date: Thu, 24 Mar 2016 15:48:28 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Thu, 16 Oct 2014 13:20:58 GMT
ETag: "1321-5058a1e728280"
Accept-Ranges: bytes
Content-Length: 4897
Content-Type: text/html; charset=UTF-8

[flying@lemp ansible]$ curl --head http://192.168.0.51
HTTP/1.1 403 Forbidden
Date: Thu, 24 Mar 2016 15:48:37 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Thu, 16 Oct 2014 13:20:58 GMT
ETag: "1321-5058a1e728280"
Accept-Ranges: bytes
Content-Length: 4897
Content-Type: text/html; charset=UTF-8

[flying@lemp ansible]$ curl --head http://192.168.0.52
HTTP/1.1 403 Forbidden
Date: Thu, 24 Mar 2016 15:48:40 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Thu, 16 Oct 2014 13:20:58 GMT
ETag: "1321-5058a1e728280"
Accept-Ranges: bytes
Content-Length: 4897
Content-Type: text/html; charset=UTF-8

[flying@lemp ansible]$

Unsolved Problem

Parallel Multi-machine Provisioning

使用ansible中的hostsplaybook.yum進行多主機並行操作時,出現問題,只執行一臺主機操作便停止。

參閱 * ANSIBLE PROVISIONER * Ansible parallel race * Support parallel multi-machine provisioning using Ansible

文檔說是要等所有主機都啓動後再執行ansible provision,但仍未能找到解決方案。

層級結構

.
├── hosts
├── MariaDB
│   ├── jemalloc-3.6.0-1.el7.x86_64.rpm
│   ├── jemalloc-devel-3.6.0-1.el7.x86_64.rpm
│   ├── MariaDB-10.1.13-centos7-x86_64-client.rpm
│   ├── MariaDB-10.1.13-centos7-x86_64-common.rpm
│   ├── MariaDB-10.1.13-centos7-x86_64-devel.rpm
│   ├── MariaDB-10.1.13-centos7-x86_64-server.rpm
│   └── MariaDB-10.1.13-centos7-x86_64-shared.rpm
├── playbook.retry
├── playbook.yml
└── Vagrantfile

1 directory, 11 files
  • Vagrantfile ```

    -- mode: ruby --

    vi: set ft=ruby :

boxes = [ { :name => :loadbalancer, :role => ‘lb’, :ip => ‘192.168.0.30’, :last => ‘no’ }, # load balancer { :name => :master, :role => ‘db’, :ip => ‘192.168.0.31’, :last => ‘no’ }, # master node { :name => :slave1, :role => ‘db’, :ip => ‘192.168.0.32’, :last => ‘no’ }, # classical replication node { :name => :slave2, :role => ‘db’, :ip => ‘192.168.0.33’, :last => ‘yes’ }, # gtid replication node ]

$install_common = <<SCRIPT sudo yum install -y chrony sudo systemctl start chronyd sudo systemctl enable chronyd SCRIPT

Vagrant.configure(2) do |config| config.vm.box = “CentOS7Minimal”

boxes.each do |opts|
    config.vm.define opts[:name] do |config|
        #config.ssh.username = 'vagrant'
        #config.ssh.password = 'vagrant'
        # config.ssh.insert_key = false
        # config.vm.network "public_network", bridge: "wlp3s0"
        config.vm.network "public_network",ip: opts[:ip],bridge: "wlp3s0"
        config.vm.host_name = "%s.vm" % opts[:name].to_s
        config.vm.provision "shell", inline: $install_common
        if opts[:role] == 'lb'
            config.vm.provision "shell", inline: <<-SHELL
                sudo yum install -y haproxy
            SHELL
        end
        if opts[:last] == 'yes'
            config.vm.provision "ansible" do |ansible|
                ansible.limit = "all"
                ansible.inventory_path = "hosts"
                ansible.playbook = "playbook.yml"
            end
        end
    end
end

end


* hosts

[db] 192.168.0.[31:33]

[lb] 192.168.0.30

[db:vars] ansible_ssh_user=vagrant

[lb:vars] ansible_ssh_user=vagrant


* playbook.yml
  • hosts: db become: yes tasks:
    • name: Copy MariaDB Packages to VM copy: src=./MariaDB/ dest=/tmp
    • name: Install MariaDB Server yum: name=/tmp/{{ item }} state=present with_items:
      • MariaDB-10.1.13-centos7-x86_64-client.rpm
      • MariaDB-10.1.13-centos7-x86_64-server.rpm
      • jemalloc-3.6.0-1.el7.x86_64.rpm
      • jemalloc-devel-3.6.0-1.el7.x86_64.rpm
      • MariaDB-10.1.13-centos7-x86_64-common.rpm
      • MariaDB-10.1.13-centos7-x86_64-devel.rpm
      • MariaDB-10.1.13-centos7-x86_64-shared.rpm ```

References

Change Logs

  • 2016.03.24 23:51 Thu Asia/Beijing
    • 初稿完成
  • 2016.04.16 08:33 Sat Asia/Beijing
    • 添加Unsolved Problem

  • Note Time: 2016.03.24 23:51 Thu
  • Note Location: Asia/Beijing
  • Writer: lempstacker