今天在拜讀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的配置文件Vagrantfile的配置格式如下

1
2
3
4
5
6
7
8
9
10
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目錄下,順序執行如下命令

1
2
vagrant up
vagrant provision

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

Experiment

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

Preparation

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

1
2
3
4
5
6
[[email protected] 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
[[email protected] ansible]$

此處配置3臺Vagrant虛擬機

  • Vagrantfile內容
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    # -*- 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內容
    1
    2
    3
    4
    5
    6
    7
    8
    ---
    - 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
[[email protected] ansible]$ pwd
/home/flying/vagrant/ansible
[[email protected] 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.
[[email protected] ansible]$

Vagrant provision

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
[[email protected] 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

[[email protected] ansible]$

Verification

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[[email protected] 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

[[email protected] 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

[[email protected] 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

[[email protected] ansible]$

Unsolved Problem

Parallel Multi-machine Provisioning

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

參閱

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

層級結構

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.
├── 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    # -*- 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    - 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