Ansible 筆記
Ansible 是屬於 push-based 的自動部署工具,我們不需要在遠端機器上安裝任何 client 端的程式或是 agent, 只要確定好有安裝 python 2.6 以上的版本就可以了. Ansible 主要是經由 SSH 來進行控制及設定遠端的機器,經由這樣子的設計,我們在使用 ansible 時,所需要的前置作業就會少很多.
安裝 Ansible
Ansible 預設是經由 SSH protocol 來管理其它的遠端機器。因此,需要一台機器作為中央控管來操作 Ansible 的所有指令,Ansible 稱為 ** Control Machine **, 而其它的遠端機器則稱為 ** Managed Node **. 這些機器都需要安裝 Python 2.6 以上的版本.
使用 YUM 安裝
這裡使用的是 CentOS7 的版本,如果需要知道其它作業系統的安裝,可以參照 Ansible Installation
在安裝 Ansible 之前,先安裝 EPEL 這個擴充資源庫
1
2sudo rpm -Uhv https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
sudo yum -y update
然後再安裝 Ansible
1
sudo yum -y install ansible
開始使用 Ansible
設定 SSH 公開金鑰認證
在開始使用 Ansible 之前,我們可以設定 SSH 公開金鑰認證 (Public Key Authentication), 來讓我們不用每次都要打密碼才能執行 Ansible 指令.
首先,先確定 ~/.ssh
是否存在且目錄的權限是否正確
1
2mkdir -p ~/.ssh
chmod 700 ~/.ssh
接下來産生 SSH 金鑰
1
ssh-keygen -t rsa
在産生的過程中,會詢問一些問題,如果沒有什麼要修改就直接使用預設值.
最後,會詢問是要不要設定金鑰保護密碼
1
Enter passphrase (empty for no passphrase):
如果有設密碼,就會在每次使用時,都會詢問密碼。如果不要設定密碼的話就直接按下 Enter 鍵即可.
這時我們可以在 ~/.ssh
下看到這二個新産生檔案:
- id_ras.pub: 公開金鑰 (public key), 可以對外開放,可以放在遠端機器上.
- id_rsa: 私密金鑰 (private key), 不可以對外開放,需放在本機上.
接下來,就要把所産生的公開金鑰放到遠端機器上.
1
ssh-copy-id -i ~/.ssh/id_rsa.pub username@host
完成 SSH 的設定,我們可以開始進入 ansible 的世界.
設定 Ansible Invetory File
Ansible 如何知道有那些遠端的主機需要被管理呢?Ansible 有一個主機的管理設定檔,稱為 Invetory File
. 用來管理遠端主機的資訊。這個檔案預設是放在 /etc/ansible/hosts
假設我們有二台 web server 的 IP 分別是 10.0.15.11 及 10.0.15.12, 我們可以直接寫入檔案中.
1
210.0.15.11
10.0.15.12
這樣子就完成一個最簡單的 Invetory File
. 除了使用 IP 外,也可以使用 hostname.
1
2web01
web02
也可以為它加上群組,讓我們可以對整個群組內的機器下達的相同指令。只要使用中括號把群組名括起來:
1
2
3
4# 我們定義一個叫webservers 的群組
[webservers]
10.0.15.11
10.0.15.12
有時,我們使用 vm 或 container 之類的技術,在同一台機器上跑多個 nodes. 這時我們就不能使用 SSH port 的預設值 22 來溝通.
Ansible 有提供 ansible_host
, ansible_port
這二個參數來讓我們對預設值進行修改:
1
2
3
4# 假設我們在192.168.10.10這台機器上開二個vm, 其ssh port 分別為 2201, 2202
[webservers]
web01 ansible_host=192.168.10.10 ansible_port=2201
web02 ansible_host=192.168.10.10 ansible_port=2202
Ansible 的第一次體驗
完成 Inventory File
的設定後,在命令列下達以下指令,測試 Ansible 是否可以連到我們的遠端主機
1
2
3
4
5
6
7
8
9
10
11# all 是告訴 ansible 測試所有的遠端主機
$ ansible all -m ping
web01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web02 | SUCCESS => {
"changed": false,
"ping": "pong"
}
看到遠端主機有回應,就代表我們的設置是正確.
接著我們來查看所有遠端主機的時間,我們可以用以下指令
1
2
3
4
5
6
7
8
9
10
11
12# -m: 是指定 ansible 模組的名稱, 我們這裡使用 command 模組
# -a: 是模組的參數
$ ansible all -m "command" -a "date"
web01 | SUCCESS | rc=0 >>
Wed Apr 19 08:42:35 UTC 2017
web02 | SUCCESS | rc=0 >>
Wed Apr 19 08:42:35 UTC 2017
# 如果 Inventory File 是放在其它的位置可以加上 -i 的參數來指定
$ ansible all -i hosts -m "command" -a "date"
Ansible 稱這種使用方式為 ad-hoc
, 可以提供我們快速地對遠端主機下一些指令,或是我們可以經由 ad-hoc 來學習或測試 Ansible 的模組。不過這種使用方式,是一種臨時的作法。在實務上,仍是建議要把執行的指令寫成 playbook.
有關 ad-hoc 可以參照 官方的說明
關於 playbook
什麼是 playbook
呢?Playbook 是 ansible 用來描述有關遠端主機的參數配置,系統部署以及服務管理的一種描述語言。而 playbook 內則是由許多的 tasks 所組成。經由這些描述,ansible 可以讓遠端的主機一歩一歩地完成我們所想要的配罝或部署。也可以這樣子理解,playbook 就像是電影所使用的劇本,裡面會描述電影的一切細節。而演員就會按照劇本來進行表演,只是現在演員的角色被替換成遠端主機。遠端主機會依照 playbook 的描述一歩一歩地完成,我們所交付的任務.
從一個簡單的 playbook 開始
我們先來看一個簡單的 playbook 範例,在這個範例中,遠端主機 (web01) 是安裝好 Centos 7 而我們會使用 YUM 來安裝 Nginx.
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---
- name: Install nginx server
hosts: web01
become: yes
gather_facts: true
vars:
http_port: 80
tasks:
- name: NGINX | Installing NGINX repo rpm
yum:
name: http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
- name: NGINX | Installing NGINX
yum:
name: nginx
state: present
- name: NGINX | Coping default configaration file
template:
src: "{{ playbook_dir }}/conf/default.conf.j2"
dest: /etc/nginx/conf.d/default.conf
notify: NGINX | Restart
handlers:
- name: NGINX | Restart
systemd:
name: nginx
state: restarted
enabled: true
Playbook 是使用 YAML 來編寫,YAML 相較於其它比較通用的格式,例如 XML 或 JSON, 是一種有利於人們閱讀及編寫的語法。有關 YAML 的詳細語法可以參照 YAML Syntax
一份 playbook 文件可以包含一個或多個 play
. 一個 play
則是一組包含著主機資訊,使用者權限以及所要執行的任務描述。簡單來說,在整份 playbook 文件中,可以分成以下這幾個部份:
- Hosts 和 Users
- Tasks list
- Handlers
- 變數
Hosts 和 Users
Hosts: 指示 ansible 要到那些遠端主機去執行 Tasks. 主機或主機群組則是被定義在 Invetory File
中。每個 play
都必須指定 hosts
.
Hosts 有一些特別的表示法可以參照 Patterns
Users: 如果我們所執行的 Tasks 需要特別的權限,如 root
, 則可以用 become
, become_user
來指定使用者的權限.
例如,需要用 root 權限來進行安裝 nginx
1
2
3
4- name: Install nginx server
hosts: web01
become: yes
become
語法是告訴 ansible 要開啟使用者權限,如果我們不使用 become_user
來指定使用者時,ansible 則會預設為 root 的權限。如果要指定特別的使用者權限來進行操作,則需要加上 becomde_user
1
2
3
4
5- name: Install nginx server as nginx user
hosts: web01
become: yes
# ansible 會換轉使用者為 nginx, 來執行指令
become_user: nginx
有關使用者權限的詳細說明,可以參照 Become
Tasks list
每一組 play
會包含一組 tasks, 這些 tasks 會依照撰寫的順序來執行. Task 的內容基本上就是 ansible 的模組及其參數.
Ansible 提供很多模組,這裡是有關 ansible 的 模組列表
以下就是一個基本的 task 範例,我們使用 YUM 模組來安裝 nginx.
1
2
3
4
5tasks:
- name: NGINX | Installing NGINX
yum:
name: nginx
state: present
我們也可以使用 key=value
的格式,來表示參數
1
2
3tasks:
- name: NGINX | Installing NGINX
yum: name=nginx state=present
Handlers
在一些埸景中,我們會希望在執行完 task 時,可以觸發其它的額外的工作項目。比較常見的例子是,當我們改變一個服務的設定時,會想要重啓服務來讓設定生效.
這時,我們就可以使用 notify
這個關鍵字在 task 中,來呼叫要觸發的工作任務 (handlers). Handlers 是 task 的一種,寫法也是一樣,差別是在 handlers 會監聽 notify, 如果發現有被呼叫才會執行,不然是不會被執行的.
以下是 handlers 的一個範例,我們更改 nginx 的設定檔並重新啓動 nginx 服務:
1
2
3
4
5
6
7
8
9
10
11
12
13tasks:
- name: NGINX | Coping default configaration file
template:
src: "{{ playbook_dir }}/conf/default.conf.j2"
dest: /etc/nginx/conf.d/default.conf
notify: NGINX | Restart
handlers:
- name: NGINX | Restart
systemd:
name: nginx
state: restarted
enabled: true
變數
在 play
中,我們可以增加 vars
區塊,來指定變數。例如:
1
2
3
4- name: Install nginx server
hosts: web01
vars:
http_port: 80
在這裡,我們指定一個變數名稱 http_port
, 如果我們要在 playbook 中使用時,則在前後各加上二個大括號. Ansible 在解析這些字符時,就會置換此變數名稱為變數的值。不過在 ansible 中,變數的使用方式有分二種:
在 Template 中使用時,可以直接使用,例如:
1
listen {{ http_port }};
在 YAML 中使用時,則需要在字串前後加上雙引號 "
, 例如:
1
src: "{{ playbook_dir }}/conf/default.conf.j2"
有關 ansible 的變數詳細說明可以參照 Variables
內建變數
Ansible 本身也會提供一些內建的變數 (ansible 稱為 Magic Variables), 以方便我們取得 Ansible 本身的一些資訊,例如 變數 playbook_dir
是放置 playbook 文件的根目錄路徑,而其它有關內建變數的資訊,可以參照 Magic Variables, and How To Access Information About Other Hosts
Facts
Ansible 還有另外一種變數是用來放置遠端系統資訊,稱為 Facts
. 我們可以先在命令列中輸入以下指令:
1
2# 假設遠端主機的名稱為 web01
$ ansible web01 -m setup
則可以看到回傳的結果如下:
1
2
3
4
5
6
7
8
9
10
11
12web01 | SUCCESS => {
"ansible_facts": {
....
....(省略)
"ansible_distribution": "CentOS",
"ansible_distribution_major_version": "7",
....
....(省略)
},
"changed": false
}
這個表示,當我們在 playbook 或 template 中,使用 {{ansible_distribution}}
, 就可以取到遠端主機的作業系統的發佈套件資訊為 CentOS
.
關閉 Facts
在 playbook 中,Facts 是預設開啟的,如果確定不會使用到 Facts 的變數,則可以選擇關掉。只要在 play
中,增加 gather_facts
指令,例如:
1
2
3- name: Install nginx server
hosts: web01
gather_facts: false
Template
Ansible 使用 Jinja2 作為 template engine. 我們可以使用 template
模組及變數來完成各式的文件檔。例如 nginx 的設定檔:
1
2
3
4
5
6
7
8
9
10
11
12
13
14server {
listen {{ http_port }};
server_name {{ansible_hostname}};
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
其它有關 Template 的部分可以參照 Templating (Jinja2)
開始執行 Playbook
在了解 playbook 的組成要素之後,就是要如何來讓 playbook 開始執行。我們可以在命令列下以下指令
1
2# 假設我們的 playbook 文件是 webservers.yml
$ ansible-playbook webservers.yml
接著我們可以查看輸出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PLAY [install web] *************************************************************
TASK [setup] *******************************************************************
ok: [web01]
TASK [NGINX | Installing NGINX repo rpm] ***************************************
changed: [web01]
TASK [NGINX | Installing NGINX] ************************************************
changed: [web01]
TASK [NGINX | Coping default configaration file] *******************************
changed: [web01]
RUNNING HANDLER [NGINX | Restart] **********************************************
changed: [web02]
PLAY RECAP *********************************************************************
web01 : ok=5 changed=4 unreachable=0 failed=0
這樣子我們就完成了 nginx 的部署。而在輸出訊息上,可以看到每個 Task 的執行結果, PLAY RECAP
這個區塊則是會總結所有 task 的結果.