Ansible簡明教程
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 [email protected]
上面命令將~/.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=//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=//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": "//192.168.40.202/cns"}
- {"path": "/admin", "proxy": "//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,這將極大提高你的操作效率,並且所有操作文檔化,更易維護與遷移。
歡迎關注作者公眾號:空山新雨的技術空間