#### 一、Ansible變量
##### facts變量
> facts組件是Ansible用于采集被控節點機器的設備信息,比如IP地址、操作系統、以太網設備、mac 地址、時間/日期相關數據,硬件信息等
- setup模塊
? - 用于獲取所有facts信息
```shell
## 常用參數
?? ?filter:用于過濾指定信息
# 通過setup模塊查看所有facts信息
ansible web1 -m setup
# facts變量是一個由龐大的{}構成的鍵值字典
# 在{}中,有很多層級的嵌套。可以通過參數過濾出第一個層級的內容
ansible webservers -m setup -a "filter=ansible_all_ipv4_addresses"
ansible webservers -m setup -a "filter=ansible_bios_version"
ansible webservers -m setup -a "filter=ansible_memtotal_mb"
ansible webservers -m setup -a "filter=ansible_hostname"
ansible webservers -m setup -a "filter=ansible_mem*"
ansible web1 -m setup > facts.txt; awk -F: '/mb/{print}' facts.txt
```
- debug模塊
? - 用于基本中使用facts變量打印變量信息
? - 默認有Gathering Facts任務,收集到Facts信息后可以使用該模塊打印
? - 調用變量格式:{{ 變量名 }}
```shell
## 常用參數
? ? msg:打印變量值,格式為:{{ 變量名 }}
? ? var:打印變量值,格式為:變量名
- name: test debug
? hosts: webservers
? tasks:
? ? - name: test debug msg
? ? ? debug:
? ? ? ? msg: "hostname: {{ansible_hostname}}; mem: {{ansible_memtotal_mb}}"
- name: test debug
? hosts: webservers
? tasks:
? ? - name: test debug var
? ? ? debug:
? ? ? ? var: ansible_hostname, ansible_bios_version
```
##### 自定義變量
- 通過變量的使用可以讓劇本更加靈活,多次運行劇本只需要調整對應變量名即可
- Ansible支持十幾種變量定義方式
- Ansible變量定義的位置,下列變量優先級從低到高
? - role defaults :roles defaults目錄下的變量
? - inventory vars:inventory文件中定義的變量
? - inventory group_vars:inventory文件組的變量
? - inventory host_vars:inventory文件主機的變量
? - playbook group_vars:劇本中組的變量
? - playbook host_vars:劇本中主機的變量
? - host facts:事實變量
? - play vars:vars定義的變量
? - play vars_prompt:vars_prompt定義的變量
? - play vars_files:vars_files導入的變量
? - registered vars:注冊變量
? - role and include vars:roles中單獨定義的及導入的變量
? - block vars (only for tasks in block):block中定義的變量
? - task vars (only for the task):任務中定義的變量
? - extra vars (always win precedence):命令行指定的變量
- Ansible變量定義的分類
? - 節點變量
? ```shell
? ## 在inventory文件中定義變量
? [webservers]
? web[1:2]
??
? [dbs]
? db1 username="natasha" ? #定義屬于db1主機的變量
? ……
??
? ## 定義變量在Playbook中的使用
? - name: create user with host vars
? ? hosts: db1
? ? tasks:
? ? ? - name: test host vars
? ? ? ? user:
? ? ? ? ? name: "{{ username }}"
? ? ? ? ? state: present
? ```
? - 組變量
? ```shell
? ## 在inventory文件中定義變量
? [webservers]
? web[1:2]
??
? ……
??
? #定義屬于組的變量,:vars是固定格式
? [webservers:vars]
? username="natasha"
??
? ## 定義變量在Playbook中的使用
? - name: create user with group vars
? ? hosts: webservers
? ? tasks:
? ? ? - name: test group vars
? ? ? ? user:
? ? ? ? ? name: "{{ username }}"
? ? ? ? ? state: present
? ```
? - 劇本變量
? ```shell
? ## Playbook中定義變量
? - name: create user with play vars
? ? hosts: webservers
? ? vars: ? ? ? ? ? ? ? ? ? ? #劇本中定義變量
? ? ? username: "natasha"?? ??? ?#定義變量
? ? ? password: "123456" ? ? ?#定義變量,數字作為密碼必須用引號,表示字符串
? ? tasks:
? ? ? - name: test play vars
? ? ? ? user:
? ? ? ? ? name: "{{ username }}"
? ? ? ? ? password: "{{ password|password_hash('sha512')}}"
? ? ? ? ? state: present
? ```
? - 文件變量
```shell
# 變量文件創建一個fvars.yml文件
username: "natasha"
password: "654321"
## 定義變量文件在Playbook中的使用
- name: create user with vars files
? hosts: db1
? vars_files: fvars.yml ? ? #調用定義變量的文件
? tasks:
? ? - name: test vars file
? ? ? user:
? ? ? ? name: "{{ username }}"
? ? ? ? password: "{{ password | password_hash('sha512')}}"
? ? ? ? state: present
```
##### 調用Facts變量信息收集
```shell
# 一定要開啟Facts信息收集,gather_facts: yes
- name: copy file with facts
? hosts: webservers
? tasks:
? ? - name: use facts
? ? ? copy:
? ? ? ?? ?#加\n換行,顯示兩條信息
? ? ? ? content: "hostname: {{ ansible_hostname }}\nbios_version: {{ ansible_bios_version }}"
? ? ? ? dest: /tmp/facts.txt
# 驗證收集
ansible webservers -a "cat /tmp/facts.txt"
```
##### Ansible補充模塊
- Firewalld模塊
? - 該模塊用于配置firewalld防火墻規則(默認拒絕訪問),對于明確允許的服務設置放行操作
? - 無論服務是否有名字,最終都基于TCP或UDP的端口,比如http服務基于TCP80端口。服務名和端口號對應關系的說明文件位于:/etc/services
```shell
## 常用參數
? ? port:聲明放行端口與通信類型
? ? permanent:永久生效,但不會立即生效
? ? immediate:立即生效,臨時生效
? ? state:enabled,放行;disabled拒絕
# 在webservers主機組安裝nginx軟件、啟動服務
- name: test firewalld
? hosts: webservers
? tasks:
? ? - name: install nginx
? ? ? yum:
? ? ? ? name: nginx
? ? ? ? state: present
? ? - name: start nginx
? ? ? service:
? ? ? ? name: nginx
? ? ? ? state: started
? ? ? ? enabled: true
curl -I http://web1;curl -I http://web2?? ??? ?#測試訪問
# 在webservers主機組安裝firewalld防火墻軟件、啟動服務并訪問測試
- name: test firewalld
? hosts: webservers
? tasks:
?? ?...
? ? - name: install firewalld
? ? ? yum:
? ? ? ? name: firewalld
? ? ? ? state: present
? ? - name: start firewalld
? ? ? service:
? ? ? ? name: firewalld
? ? ? ? state: started
? ? ? ? enabled: true
# 設置防火墻放行http訪問
- name: test firewalld
? hosts: webservers
? tasks:
? ?? ?...
? ? - name: allow http
? ? ? firewalld:
? ? ? ? port: 80/tcp
? ? ? ? permanent: true
? ? ? ? immediate: true
? ? ? ? state: enabled
```
- Template模塊
? - 用于上傳具備特殊格式的文件(如文件中包含變量),文件的語法叫Jinja2
? - 被控節點接收到文件時,模板文件中的變量名會被替換成具體的值
? - 相比于copy模塊更加靈活
```shell
## 常用參數
? ? src:要上傳的文件
? ? dest:目標文件路徑
# 通過facts變量找到被控節點對應ip的變量
# 創建index.html.j2文件將變量對號入座,主機名對應hostname,ip地址對應address
Welcome to {{ ansible_hostname }} on {{ ansible_eth0.ipv4.address }}
- name: upload index
? hosts: webservers
? tasks:
? ? - name: create web index
? ? ? template:
? ? ? ? src: index.html.j2
? ? ? ? dest: /usr/share/nginx/html/index.html
```
#### 二、PlayBook進階語法
##### 錯誤處理機制
> 當Playbook中有多個task時,其中某個任務執行過程中失敗則后續任務將被終止執行
>
> 使用ignore_errors對可能出現錯誤的task進行忽略處理,可以作用于任務級也可作用于全局級
```shell
# 任務級忽略錯誤
- name: test error task
? hosts: webservers
? tasks:
? ? - name: start mysqld
? ? ? service:?
? ? ? ? name: mysqld
? ? ? ? state: started
? ? ? ? enabled: true
? ? ? ignore_errors: true ? ? ? #任務級
? ? - name: touch file
? ? ? file:
? ? ? ? path: /tmp/mysql.txt
? ? ? ? state: touch
# 全局級忽略錯誤
- name: test error task
? hosts: webservers
? ignore_errors: true ? ? ? #全局級
? tasks:
? ? - name: start mysqld
? ? ? service:?
? ? ? ? name: mysqld
? ? ? ? state: started
? ? ? ? enabled: true
? ? - name: touch file
? ? ? file:
? ? ? ? path: /tmp/mysql.txt
? ? ? ? state: touch
```
##### 觸發執行任務
- 通過handlers定義一組任務
- 僅當某個任務觸發(notify)handlers時才會執行相應任務
- 如果有多個notify觸發執行handlers任務,也僅執行一次
- 僅當任務的執行狀態為changed是handlers任務才執行
- handlers任務在所有其他任務都執行后才執行
```shell
# 獲取nginx配置文件
- name: get nginx config file
? hosts: webservers
? tasks:
? ? - name: fetch nginx config file
? ? ? fetch:
? ? ? ? src: /etc/nginx/nginx.conf
? ? ? ? dest: ./
? ? ? ? flat: yes
# 編輯獲取文件的服務端口,調整為facts變量
vim +39 nginx.conf
...
? ? ? ? listen ? ? ? {{ http_port }} default_server;
? ? ? ? listen ? ? ? [::]:{{http_port}} default_server;
...
# 修改nginx服務端口為8000并重啟服務
- name: configure nginx
? hosts: webservers
? vars:
? ? http_port: 8000
? tasks:
? ? - name: upload nginx.conf
? ? ? template:
? ? ? ? src: nginx.conf
? ? ? ? dest: /etc/nginx/nginx.conf
? ? - name: restart nginx
? ? ? service:
? ? ? ? name: nginx
? ? ? ? state: restarted
######執行上條命令,修改文件并重啟服務,第二次執行命令,未修改文件但重啟服務
# 實現目標:只有修改了配置文件才會重啟服務
# 加入handlers觸發器
- name: configure nginx
? hosts: webservers
? vars:
? ? http_port: 80
? tasks:
? ? - name: upload nginx.conf
? ? ? template:
? ? ? ? src: nginx.conf
? ? ? ? dest: /etc/nginx/nginx.conf
? ? ? notify: restart nginx service ? ? #任務狀態為changed時觸發指定任務執行
? handlers:
? ? - name: restart nginx service
? ? ? service:
? ? ? ? name: nginx
? ? ? ? state: restarted
####!!!!!注意notify與handlers的name要一致否則回報錯
ERROR! The requested handler 'restart nginx service' was not found in either the main handlers list nor in the listening handlers list
```
##### when條件判斷
- 滿足條件時才執行任務,多任務使用and或or進行連接,表達邏輯關系
- when表達式中的變量不需要使用{{}}
```shell
## 常用操作符
? ? ==:相等
? ? !=:不等
? ? >:大于
? ? <:小于
? ? <=:小于等于
? ? >=:大于等于
# 單條件測試:當目標主機內存至少4G時安裝MySQL軟件
- name: test when
? hosts: dbs
? tasks:
? ? - name: install mysql soft
? ? ? yum:
? ? ? ? name: mysql-server
? ? ? ? state: present
? ? ? when:
? ? ? ? ansible_memtotal_mb >= 4096
# 多條件測試:當目標主機系統為Rocky8時發送文件,/etc/motd是用戶登錄時屏幕顯示的內容
- name: test when
? hosts: webservers
? tasks:
? ? - name: modify /etc/motd
? ? ? copy:?
? ? ? ? src: motd
? ? ? ? dest: /etc/motd
? ? ? when: > ? #多條件合并成1行
? ? ? ? ansible_distribution == "Rocky"
? ? ? ? and
? ? ? ? ansible_distribution_major_version == "8"
```
##### register注冊變量
- register用于捕獲和保存任務執行結果,它允許將其他任務的輸出作為變量使用
- register也是一個關鍵字,可以將任務執行的結果賦值給指定的變量名稱,并在后續任務中使用
- register可以捕獲各種類型的輸出,包括stdout、stderr、rc、changed等并與其他模塊一起使用,例如"when"條件、"loop"循環等
```shell
# 在web1主機執行創建/tmp/reg1.txt,捕獲命令執行結果并打印
- name: test register
? hosts: web1
? tasks:
? ? - name: create file
? ? ? file:
? ? ? ? path: /tmp/reg1.txt
? ? ? ? state: touch
? ? ? register: result
? ? - name: display result
? ? ? debug:
? ? ? ? msg: "{{result}}"?
# 在web1主機上執行任務,創建文件/tmp/abcdemo/abc。如果創建不成功,則通過debug輸出create failed
- name: test register
? hosts: web1
? ignore_errors: true ? #如果不忽略則任務2無法執行
? tasks:
? ? - name: create file
? ? ? file:
? ? ? ? path: /tmp/abcdemo/abc
? ? ? ? state: touch
? ? ? register: result
? ? - name: debug out
? ? ? debug:
? ? ? ? msg: "create failed"
? ? ? when: result.failed
```