Ansible是當下比較流行的自動化運維工具,可通過SSH協議對遠端伺服器進行集中化的配置管理、應用部署等,常結合Jenkins來實現自動化部署。
除了Ansible,還有像SaltStack、Fabric(曾經管理100多臺伺服器上的應用時也曾受益於它)、Puppet等自動化工具。相比之下,Ansible最大的優勢就是無需在被管理主機端部署任何客戶端代理程式,通過SSH通道就可以進行遠端命令的執行或配置的下發,足夠輕量級,但同時功能非常強大,且各項功能通過模組來實現,具備良好的擴充套件性。不足之處是Ansible只支援在Linux系統上安裝,不支援Windows。
如果你需要在多於一臺伺服器上做相同的操作,那麼建議你使用Ansible之類的自動化工具,這將極大提高你的操作效率。
環境搭建
1.找一臺主機用於做管理伺服器,在其上安裝Ansible
yum -y install ansible
Ansible基於Python實現,一般Linux系統都自帶Python,所以可以直接使用yum安裝或pip安裝。
安裝完後,在/etc/ansible/目錄下生成三個主要的檔案或目錄,
[root@tool-server ~]# ll /etc/ansible/
total 24
-rw-r--r--. 1 root root 19179 Jan 30 2018 ansible.cfg
-rw-r--r--. 1 root root 1136 Apr 17 15:17 hosts
drwxr-xr-x. 2 root root 6 Jan 30 2018 roles
- ansible.cfg: Ansible的配置檔案
- hosts:登記被管理的主機
- roles:角色專案定義目錄,主要用於程式碼複用
2.在/etc/ansible/hosts檔案中新增需要被管理的伺服器節點
[root@tool-server ~]# vim /etc/ansible/hosts
[k8s]
192.168.40.201
192.168.40.202
192.168.40.205
192.168.40.206
[k8s]
表示將下面的伺服器節點分到k8s的組中,後面執行命令時可指定針對某個組執行。
3.生成SSH KEY,並copy到被管理節點上,實現免密SSH訪問
在管理節點執行 ssh-keygen
生成SSH KEY,然後copy到各被管理節點上
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.40.201
上面命令將~/.ssh/id_rsa.pub
檔案內容新增到被管理節點的/root/.ssh/authorized_keys檔案中,實現管理節點到被管理節點的免密SSH訪問。
4.除錯Ansible
針對k8s伺服器組執行ping,驗證Ansible到各被管理節點的連通性
[root@tool-server ~]# ansible k8s -m ping
192.168.40.201 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.40.205 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.40.202 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.40.206 | SUCCESS => {
"changed": false,
"ping": "pong"
}
Ansible只需要在管理主機上安裝,然後打通管理主機到各被管理主機的SSH免密訪問即可進行集中化的管理控制,不需在被管理主機安裝任何代理程式。
Ansible命令
Ansible的命令格式為, ansible 主機群組名 -m 命令模組名 -a "批量執行的操作"
其中-m不是必須的,預設為command模組,-a也不是必須的,表示命令模組的引數,比如前面的ping模組就沒有引數。
可以使用 ansible-doc -l
列出所有可用的命令模組, ansible-doc -s 模組名
檢視指定模組的引數資訊
常用命令模組
1.command
command是Ansible的預設模組,不指定-m引數時預設使用command。command可以執行遠端主機許可權範圍內的所有shell命令,但不支援管道操作
# 檢視k8s分組主機記憶體使用情況
ansible k8s -m command -a "free -g"
2.shell
shell基本與command相同,但shell支援管道操作
#shell支援管道操作 |grep Mem
ansible k8s -m shell -a "free -g|grep Mem"
3.script
script就是在遠端主機上執行管理端儲存的shell指令碼檔案,相當於scp+shell
# /root/echo.sh為管理端本地shell指令碼
ansible k8s -m script -a "/root/echo.sh"
4.copy
copy實現管理端到遠端主機的檔案拷貝,相當於scp
#拷貝本地echo.sh檔案到k8s組中遠端主機的/tmp目錄下,所屬使用者、組為 root ,許可權為 0755
ansible k8s -m copy -a "src=/root/echo.sh dest=/tmp/ owner=root group=root mode=0755"
5.yum
軟體包安裝或刪除
ansible k8s -m yum -a "name=wget state=latest"
其中state有如下取值:
- 針對安裝,可取值“present,installed,latest”,present,installed即普通安裝,兩者無區別,latest是使用yum mirror上最新的版本進行安裝
- 針對刪除,可取值“absent,removed”,兩者無差別
6.service
對遠端主機的服務進行管理
ansible k8s -m service -a "name=nginx state=stoped"
state可取值“started/stopped/restarted/reloaded”。
7.get_url
在遠端主機上下載指定URL到本地
ansible k8s -m get_url -a "url=http://www.baidu.com dest=/tmp/index.html mode=0440 force=yes"
8.setup
獲取遠端主機的資訊
ansible k8s -m setup
9.file
管理遠端主機的檔案或目錄
ansible k8s -m file -a "dest=/opt/test state=touch"
state可取值
- directory:建立目錄
- file:如果檔案不存在,則建立
- link:建立symbolic link
- absent:刪除檔案或目錄
- touch: 建立一個不存在的空檔案
10.cron
管理遠端主機的crontab定時任務
ansible k8s -m cron -a "name='backup servcie' minute=*/5 job='/usr/sbin/ntpdate time.nist.gov >/dev/null 2>&1'"
支援的引數
- state: 取值present表示建立定時任務,absent表示刪除定時任務
- disabled: yes表示註釋掉定時任務,no表示接觸註釋
Ansible playbook
Ansible的playbook由一個或多個play組成,play的功能就是為歸為一組的主機編排要執行的一系列task,其中每一個task就是呼叫Ansible的一個命令模組。
playbook的核心元素包括:
- hosts:執行任務的遠端主機組或列表
- tasks:要執行的任務列表
- variables:內建變數或自定義的變數
- templates:使用模板語法的檔案,通常為配置檔案
- handlers:和notify結合使用,由特定條件觸發,一般用於配置檔案變更觸發服務重啟
- tags:標籤,可在執行時通過標籤指定執行playbook中的部分任務
- roles:
playbook檔案遵循yaml的語法格式,執行命令的格式為 ansible-playbook <filename.yml> ... [options]
, 常用options包括
- --syntax 檢查playbook檔案語法是否正確
- --check 或 -C 只檢測可能會發生的改變,但不真正執行操作
- --list-hosts 列出執行任務的主機
- --list-tags 列出playbook檔案中定義所有的tags
- --list-tasks 列出playbook檔案中定義的所有任務集
- --limit 只針對主機列表中的某個主機或者某個組執行
- -f 指定併發數,預設為5個
- -t 指定某個或多個tags執行(前提playbook中有定義tags)
- -v 顯示過程 -vv -vvv更詳細
下面以批量安裝Nginx為例,儘可能介紹playbook各核心元素的用法。
定義palybook yaml檔案nginx_playbook.yml
---
- hosts: 192.168.40.201,192.168.40.205 # 主機列表,也可以是/etc/ansible/hosts中定義的主機分組名
remote_user: root # 遠端使用者
vars: # 自定義變數
version: 1.16.1
vars_files:
- ./templates/nginx_locations_vars.yml
tasks:
- name: install dependencies # 定義任務的名稱
yum: name={{item}} state=installed # 呼叫模組,具體要做的事情,這裡使用with_items迭代多個yum任務安裝必要的依賴
with_items:
- gcc
- gcc-c++
- pcre
- pcre-devel
- zlib
- zlib-devel
- openssl
- openssl-devel
- name: download nginx # 通過get_url模組下載nginx
get_url: url=http://nginx.org/download/nginx-{{version}}.tar.gz dest=/tmp/ mode=0755 force=no
- name: unarchive # 通過unarchive模組解壓nginx
unarchive: src=/tmp/nginx-{{version}}.tar.gz dest=/tmp/ mode=0755 copy=no
- name: configure,make and install # 通過shell模組執行shell命令編譯安裝
shell: cd /tmp/nginx-{{version}} && ./configure --prefix=/usr/local/nginx && make && make install
- name: start nginx # 通過shell模組執行shell命令啟動nginx
shell: /usr/local/nginx/sbin/nginx
- name: update config # 通過template模組動態生成配置檔案下發到遠端主機目錄
template: src=nginx.conf.j2 dest=/usr/local/nginx/conf/nginx.conf
notify: reload nginx # 在結束時觸發一個操作,具體操作通過handlers來定義
tags: reload # 對任務定義一個標籤,執行時通過-t執行帶指定標籤的任務
handlers:
- name: reload nginx # 與notify定義的內容對應
shell: /usr/local/nginx/sbin/nginx -s reload
1. 變數
在上面的示例中使用vars定義了變數version,在tasks中通過{{version}}進行引用。Ansible支援如下幾種定義變數的方式
1.在playbook檔案中定義
前面示例已經說明
2.命令列指定
在執行playbook時通過-e指定,如ansible-playbook -e "version=1.17.9" nginx_playbook.yml
, 這裡指定的變數將覆蓋playbook中定義的同名變數的值
3.hosts檔案中定義變數
在/etc/ansible/hosts檔案中也可以定義針對單個主機或主機組的變數,如
[nginx]
192.168.40.201 version=1.17.9 # 定義單個主機的變數
192.168.40.205
[nginx:vars] # 定義整個組的統一變數
version=1.16.1
4.在獨立的yaml檔案中定義變數
專門定義一個yaml變數檔案,然後在playbook檔案中通過var_files引用,如
# 定義存放變數的檔案
[root@ansible ]# cat var.yml
version: 1.16.1
# 編寫playbook
[root@ansible ]# cat nginx_playbook.yml
---
- hosts: nginx
remote_user: root
vars_files: # 引用變數檔案
- ./var.yml # 指定變數檔案的path(這裡可以是絕對路徑,也可以是相對路徑)
5.使用setup模組獲取到的變數
前面介紹setup模組可獲取遠端主機的資訊,可在playbook中直接引用setup模組獲取到的屬性,比如系統版本: ansible_distribution_major_version
2. 模板
playbook模板為我們提供了動態的配置服務,使用jinja2語言,支援多種條件判斷、迴圈、邏輯運算、比較操作等。應用場景就是定義一個模板配置檔案,然後在執行的時候動態生成最終的配置檔案下發到遠端主機。一般將模板檔案放在playbook檔案同級的templates目錄下,這樣在playbook檔案中可以直接引用,否則需要通過絕對路徑指定,模板檔案字尾名一般為 .j2。
本例中,我們將nginx.conf配置檔案作為模板檔案,新增需要動態配置的內容,並定義一個變數檔案,通過vars_files引入:vars_files: ./templates/nginx_locations_vars.yml
# 模板檔案
[root@tool-server nginx-deploy]# vim templates/nginx.conf.j2
...
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
# 這裡的內容動態生成
{% for location in nginx_locations %}
location {{location.path}} {
proxy_pass {{location.proxy}};
}
{% endfor %}
location / {
root html;
index index.html index.htm;
}
...
# 獨立的自定義變數檔案,用於填充模板檔案中的變數
[root@tool-server nginx-deploy]# vim templates/nginx_locations_vars.yml
nginx_locations:
- {"path": "/cns", "proxy": "http://192.168.40.202/cns"}
- {"path": "/admin", "proxy": "http://192.168.40.202/admin"}
3. handlers
handlers和notify結合使用,由特定條件觸發,一般用於配置檔案變更觸發服務重啟。在本例中我們在配置檔案變更時,通過notify定義了一個“reload nginx”的操作,然後在handlers部分定義“reload nginx”操作——通過shell模組呼叫nginx的reload來重新載入配置。
4. 標籤
playbook檔案中,如果只想執行某一個或幾個任務,則可以給任務打標籤,在執行的時候通過 -t 選擇帶指定標籤的任務執行,也可以通過 --skip-tags 選擇不帶指定標籤的任務執行。比如在本例中,我們在“update config”的task上加了“reload”的標籤,如果後面再修改配置,我們只需要執行“update config”的task並觸發reload nginx就行了,可以這麼執行playbook
[root@tool-server nginx-deploy]# ansible-playbook -t reload nginx_playbook.yml
5. when
可以在task上新增when表示當某個條件達到了該任務才執行,如
tasks:
- name: install nginx
yum: name=nginx state=installed
- name: update config for system6
template: src=nginx.conf.j2 dest=/usr/local/nginx/conf/nginx.conf
when: ansible_distribution_major_version == "6" # 判斷系統版本,為6才執行上面的template配置的檔案
6. roles
roles就是將變數、檔案、任務、模板及處理器放置在單獨的目錄中,並可以在playbook中include的一種機制,一般用於主機構建服務的場景中,但也可以是用於構建守護程式等場景。
roles的目錄結構,預設的roles目錄為/etc/ansible/roles
roles: # 所有的角色專案必須放在roles目錄下
project: # 具體的角色專案名稱,比如nginx、tomcat
files: # 用來存放由copy或script模組呼叫的檔案
templates: # 用來存放jinjia2模板,template模組會自動在此目錄中尋找jinjia2模板檔案
tasks: # 此目錄應當包含一個main.yml檔案,用於定義此角色的任務列表,此檔案可以使用include包含其它的位於此目錄的task檔案。
main.yml
handlers: # 此目錄應當包含一個main.yml檔案,用於定義此角色中觸發條件時執行的動作
main.yml
vars: # 此目錄應當包含一個main.yml檔案,用於定義此角色用到的變數
main.yml
defaults: # 此目錄應當包含一個main.yml檔案,用於為當前角色設定預設變數
main.yml
meta: # 此目錄應當包含一個main.yml檔案,用於定義此角色的特殊設定及其依賴關係
main.yml
我們將上面的例子通過roles改造一下
[root@tool-server ~]# cd /etc/ansible/roles/
[root@tool-server roles]# mkdir -p nginx/{tasks,vars,templates,handlers}
...#建立各目錄的mian.yml檔案,並將對應的內容加入檔案中
#最終目錄結構
[root@tool-server roles]# tree .
.
└── nginx
├── handlers
│ └── main.yml # 上例handlers部分的內容,直接 -name開頭,不需要再加 `handlers:`
├── tasks
│ └── main.yml # tasks部分內容,直接-name開頭,不需要加tasks,可以將各個task拆分為多個檔案,然後在main.yml中通過 `- include: install.yml` 形式的列表引入
├── templates
│ └── main.yml # templates/nginx.conf.j2的內容
└── vars
└── main.yml # templates/nginx_locations_vars.yml的內容
5 directories, 4 files
最後,在playbook中通過roles引入,
[root@ansible roles]# vim nginx_playbook.yml
---
- hosts: nginx
remote_user: root
roles:
- role: nginx # 指定角色名稱
roles將playbook的各個部分進行拆分組織,主要用於程式碼複用度較高的場景。
總結
Ansible是功能強大但又很輕量級的自動化運維工具,基於SSH協議批量對遠端主機進行管理,不僅可用於日常的服務維護,也可與Jenkins等CI/CD工具結合實現自動化部署。如果你需要在多於一臺伺服器上做重複又稍顯複雜的操作,那麼建議你使用Ansible,這將極大提高你的操作效率,並且所有操作文件化,更易維護與遷移。
歡迎關注作者公眾號:空山新雨的技術空間