一、概述
- playbook與ad-hoc相比,是一種完全不同的運用ansible的方式,類似與saltstack的state狀態文件。ad-hoc無法持久使用,playbook可以持久使用。
- playbook是由一個或多個play組成的列表,play的主要功能在于將事先歸并為一組的主機裝扮成事先通過ansible中的task定義好的角色。
- 從根本上來講,所謂的task無非是調用ansible的一個module。將多個play組織在一個playbook中,即可以讓它們聯合起來按事先編排的機制完成某一任務。
參考文檔:https://ansible-tran.readthedocs.io/en/latest/docs/playbooks.html
Ansible 的基礎介紹和環境部署可以參考我這篇文章:??Ansible 介紹與實戰操作演示??
二、playbook 核心元素
- Hosts執行的遠程主機列表
- Tasks任務集
- Varniables內置變量或自定義變量在playbook中調用
- Templates模板,即使用模板語法的文件,比如配置文件等
- Handlers和notity結合使用,由特定條件觸發的操作,滿足條件方才執行,否則不執行
- Tags標簽,指定某條任務執行,用于選擇運行playbook中的部分代碼。
三、playbook 語法(yaml)
- playbook使用yaml語法格式,后綴可以是yaml,也可以是yml。
- YAML( /?j?m?l/ )參考了其他多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822,Clark Evans在2001年5月在首次發表了這種語言,另外Ingy d?t Net與OrenBen-Kiki也是這語言的共同設計者。
- YAML格式是類似JSON的文件格式。YAML用于文件的配置編寫,JSON多用于開發設計。
1)YAML 介紹
1、YAML 格式如下
- 文件的第一行應該以“—”(三個連字符)開始,表明YAML文件的開始。
- 在同一行中,#之后的內容表示注釋,類似于shell,python和ruby。
- YAML中的列表元素以“-”開頭并且跟著一個空格。后面為元素內容。
- 同一個列表之中的元素應該保持相同的縮進,否則會被當做錯誤處理。
- play中hosts、variables、roles、tasks等對象的表示方法都是以鍵值中間以“:”分隔表示,并且“:”之后要加一個空格。
2、playbooks yaml配置文件解釋
Hosts:運行指定任務的目標主機 remoute_user:在遠程主機上執行任務的用戶; sudo_user: tasks:任務列表 tasks的具體格式: tasks: - name: TASK_NAME module: arguments notify: HANDLER_NAME handlers: - name: HANDLER_NAME module: arguments ##模塊,模塊參數: 格式如下: (1)action: module arguments (2) module: arguments 注意:shell和command模塊后直接加命令,而不是key=value類的參數列表 handlers:任務,在特定條件下觸發;接受到其他任務的通知時被觸發;
3、示例
--- - hosts: web remote_user: root tasks: - name: install nginx##安裝模塊,需要在被控主機里加上nginx的源 yum: name=nginx state=present - name: copy nginx.conf##復制nginx的配置文件過去,需要在本機的/tmp目錄下編輯nginx.conf copy: src=/tmp/nginx.conf dest=/etc/nginx/nginx.conf backup=yes notify: reload#當nginx.conf發生改變時,通知給相應的handlers tags: reloadnginx#打標簽 - name: start nginx service#服務啟動模塊 service: name=nginx state=started tags: startnginx#打標簽 handlers: - name: reload service: name=nginx state=restarted
2)variables 變量
variables變量有四種定義方法。如下:
1、facts:可以直接調用
ansible中有setup模塊,這個模塊就是通過facts組件來實現的,主要是節點本身的一個系統信息,bios信息,網絡,硬盤等等信息。這里的variables也可以直接調用facts組件的facters我們可以使用setup模塊來獲取,然后直接放入我們的劇本之中調用即可。
ansible web -m setup
常用的幾個參數:
ansible_all_ipv4_addresses # ipv4的所有地址 ansible_all_ipv6_addresses # ipv6的所有地址 ansible_date_time # 獲取到控制節點時間 ansible_default_ipv4 # 默認的ipv4地址 ansible_distribution # 系統 ansible_distribution_major_version # 系統的大版本 ansible_distribution_version # 系統的版本號 ansible_domain #系統所在的域 ansible_env #系統的環境變量 ansible_hostname #系統的主機名 ansible_fqdn #系統的全名 ansible_machine #系統的架構 ansible_memory_mb #系統的內存信息 ansible_os_family # 系統的家族 ansible_pkg_mgr # 系統的包管理工具 ansible_processor_cores #系統的cpu的核數(每顆) ansible_processor_count #系統cpu的顆數 ansible_processor_vcpus #系統cpu的總個數=cpu的顆數*CPU的核數 ansible_python # 系統上的python
搜索
ansible web -m setup -a 'filter=*processor*'
2、用戶自定義變量
自定義變量有兩種方式
- 通過命令行傳入
ansible-playbook命令行中的 -e VARS,--extra-vars VARS,這樣就可以直接把自定義的變量傳入
使用playbook定義變量,實例如下:
--- - hosts: web remote_user: root tasks: - name: install {{ rpmname }} yum: name={{ rpmname }} state=present - name: copy {{ rpmname }}.conf copy: src=/tmp/{{ rpmname }}.conf dest=/etc/{{ rpmname }}/{{ rpmname }}.conf backup=yes notify: reload tags: reload{{ rpmname }} - name: start {{ rpmname }} service service: name={{ rpmname }} state=started tags: start{{ rpmname }} handlers: - name: reload service: name={{ rpmname }} state=restarted
使用:
ansible-playbook nginx.yml -e rpmname=keepalived ansible-playbook nginx.yml --extra-vars rpmname=keepalived
- 在playbook中定義變量
##在playbook中定義變量如下: vars: - var1: value1 - var2: value2
使用:
--- - hosts: web remote_user: root vars: - rpmname: keepalived tasks: - name: install {{ rpmname }} yum: name={{ rpmname }} state=present - name: copy {{ rpmname }}.conf copy: src=/tmp/{{ rpmname }}.conf dest=/etc/{{ rpmname }}/{{ rpmname }}.conf backup=yes notify: reload tags: reload{{ rpmname }} - name: start {{ rpmname }} service service: name={{ rpmname }} state=started tags: start{{ rpmname }} handlers: - name: reload service: name={{ rpmname }} state=restarted
3、通過roles傳遞變量
下面介紹roles會使用roles傳遞變量,小伙伴可以翻到下面看詳解講解。
4、 Host Inventory
可以在主機清單中定義,方法如下:
#向不同的主機傳遞不同的變量 IP/HOSTNAME varaiable=value var2=value2 #向組中的主機傳遞相同的變量 [groupname:vars] variable=value
3)流程控制
1、用when 來表示的條件判斷
- hosts: web remote_user: root#代表用root用戶執行,默認是root,可以省略 tasks: - name: createfile copy: content="test3" dest=/opt/p1.yml when: a=='3' - name: createfile copy: content="test4" dest=/opt/p1.yml when: a=='4'
如果a”3″,就將“test3”,寫入到web組下被管控機的/opt/p1.yml中,
如果a”4″,就將“test4”,寫入到web組下被管控機的/opt/p1.yml中。
執行
# 語法校驗 ansible-playbook--syntax-check p1.yml #執行 ansible-playbook -e 'a="3"' p1.yml
2、標簽(只執行配置文件中的一個任務)
- hosts: web tasks: - name: installnginx yum: name=nginx - name: copyfile copy: src=/etc/nginx/nginx.conf dest=/etc/nginx/nginx.conf tags: copyfile - name: start service: name=nginx static=restarted
執行
# 語法校驗 ansible-playbook--syntax-check p2.yml #執行 ansible-playbook -t copyfile p2.yml
3、循環 with_items
創建三個用戶
- hosts: web tasks: - name: createruser user: name={{ item }} with_items: - shy1 - shy2 - shy3 - name: creategroup group: name={{ item }} with_items: - group1 - group2 - group3
執行
#語法校驗 ansible-playbook--syntax-check p3.yml #執行 ansible-playbook p3.yml
4、循環嵌套(字典)
用戶shy1的屬組是group1,用戶shy2的屬組是group2,用戶shy3的屬組是group3
- hosts: web tasks: - name: creategroup group: name={{item}} with_items: - group3 - group4 - group5 - name: createuser user: name={{item.user}} group={{item.group}} with_items: - {'user': shy3,'group': group3} - {'user': shy4,'group': group4} - {'user': shy5,'group': group5}
執行
#語法校驗 ansible-playbook--syntax-check p4.yml #執行 ansible-playbook p4.yml
4)模板 templates
- 模板是一個文本文件,嵌套有腳本(使用模板編程語言編寫)
- Jinja2是python的一種模板語言,以Django的模板語言為原本
該模板支持:
字符串:使用單引號或雙引號; 數字:整數,浮點數; 列表:[item1, item2, ...] 元組:(item1, item2, ...) 字典:{key1:value1, key2:value2, ...} 布爾型:true/false 算術運算: +, -, *, /, //, %, ** 比較操作: ==, !=, >, >=,
- 通常模板都是通過引用變量來運用的
【示例】
1、定義模板
usernginx; #設置nginx服務的系統使用用戶 worker_processes{{ ansible_processor_vcpus }}; #工作進程數 error_log/var/log/nginx/error.log warn; #nginx的錯誤日志 pid/var/run/nginx.pid; #nginx啟動時候的pid events { worker_connections1024; #每個進程允許的最大連接數 } http { #http請求配置,一個http可以包含多個server #定義 Content-Type include /etc/nginx/mime.types; default_typeapplication/octet-stream; #日志格式 此處main與access_log中的main對應 #$remote_addr:客戶端地址 #$remote_user:http客戶端請求nginx認證的用戶名,默認不開啟認證模塊,不會記錄 #$timelocal:nginx的時間 #$request:請求method + 路由 + http協議版本 #status:http reponse 狀態碼 #body_bytes_sent:response body的大小 #$http_referer:referer頭信息參數,表示上級頁面 #$http_user_agent:user-agent頭信息參數,客戶端信息 #$http_x_forwarded_for:x-forwarded-for頭信息參數 log_formatmain'$http_user_agent' '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; #訪問日志,后面的main表示使用log_format中的main格式記錄到access.log中 access_log/var/log/nginx/access.logmain; #nginx的一大優勢,高效率文件傳輸 sendfileon; #tcp_nopush on; #客戶端與服務端的超時時間,單位秒 keepalive_timeout65; #gzipon; server { #http服務,一個server可以配置多個location listen {{ nginxport }}; #服務監聽端口 server_namelocalhost; #主機名、域名 #charset koi8-r; #access_log/var/log/nginx/host.access.logmain; location / { root /usr/share/nginx/html; #頁面存放目錄 indexindex.html index.htm; #默認頁面 } #error_page404/404.html; # 將500 502 503 504的錯誤頁面重定向到 /50x.html error_page 500 502 503 504/50x.html; location = /50x.html { #匹配error_page指定的頁面路徑 root /usr/share/nginx/html; #頁面存放的目錄 } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ .php$ { #proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ .php$ { #root html; #fastcgi_pass 127.0.0.1:9000; #fastcgi_indexindex.php; #fastcgi_paramSCRIPT_FILENAME/scripts$fastcgi_script_name; #includefastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /.ht { #denyall; #} } include /etc/nginx/conf.d/*.conf; }
2、定義yaml編排
--- - hosts: web remote_user: root vars: - rpmname: nginx - nginxport: 8088 tasks: - name: install {{ rpmname }} yum: name={{ rpmname }} state=present - name: copy {{ rpmname }}.conf copy: src=/tmp/{{ rpmname }}.conf dest=/etc/{{ rpmname }}/{{ rpmname }}.conf backup=yes notify: reload tags: reload{{ rpmname }} - name: start {{ rpmname }} service service: name={{ rpmname }} state=started tags: start{{ rpmname }} handlers: - name: reload service: name={{ rpmname }} state=restarted
使用
##使用reloadnginx標簽,重新加載劇本
copy與template的區別
- copy模塊不替代參數,template模塊替代參數
- template的參數幾乎與copy的參數完全相同
5)handlers(觸發事件)
notify:觸發 handlers:觸發的動作
使用上場景:修改配置文件時
【示例】 正常情況時handlers是不會執行的
- hosts: web tasks: - name: installredis yum: name=redis - name: copyfile template: src=redis.conf dest=/etc/redis.conf tags: copyfile notify: restart - name: start service: name=redis state=started handlers: - name: restart service: name=redis
執行
ansible-playbook -t copyfile p6.yml
6)roles
1、roles介紹與優勢
一般情況下將roles寫在/etc/ansible/roles中,也可以寫在其他任意位置(寫在其他位置要自己手動建立一個roles文件夾)
- 對于以上所有方式有個缺點就是無法實現同時部署web、database、keepalived等不同服務或者不同服務器組合不同的應用就需要寫多個yaml文件,很難實現靈活的調用
- roles用于層次性,結構化地組織playbook。roles能夠根據層次結果自動裝載變量文件、tasks以及handlers等。
- 要使用roles只需要在playbook中使用include指令即可。
- 簡單來講,roles就是通過分別將變量(vars)、文件(files)、任務(tasks)、模塊(modules)以及處理器(handlers)放置于單獨的目錄中,并且可以便捷的include它們地一種機制。
- 角色一般用于基于主機構建服務的場景中,但是也可以用于構建守護進程等場景中。4
2、目錄結構
創建目錄
mkdir -pv ./{nginx,mysql,httpd}/{files,templates,vars,tasks,handlers,meta,default}
- roles/
- mysql/:mysql服務的yml文件
- httpd/:apached服務的yml文件
- nginx/:nginx服務的yml文件
- files/:存儲由copy或者script等模塊調用的文件或者腳本;
- tasks/:此目錄中至少應該有一個名為main.yml的文件,用于定義各個task;其他文件需要由main.yml進行包含調用;
- handlers/:此目錄中至少應該有一個名為main.yml的文件,用于定義各個handler;其他文件需要由main.yml進行包含調用;
- vars/:此目錄至少應該有一個名為main,yml的文件,用于定義各個variable;其他的文件需要由main.yml進行包含調用;
- templates/:存儲由templates模塊調用的模板文件;
- meta/:此目錄中至少應該有一個名為main.yml的文件,定義當前角色的特殊設定以及依賴關系,其他文件需要由main.yml進行包含調用;
- default/:此目錄至少應該有一個名為main.yml的文件,用于設定默認變量;
3、實戰操作
【1】創建目錄
mkdir -pv ./{nginx,mysql,httpd}/{files,templates,vars,tasks,handlers,meta,default}
【2】定義配置文件
先下載nginx rpm部署包
# 下載地址:http://nginx.org/packages/centos/7/x86_64/RPMS/ wget http://nginx.org/packages/centos/7/x86_64/RPMS/nginx-1.18.0-1.el7.ngx.x86_64.rpm -O nginx/files/nginx-1.18.0-1.el7.ngx.x86_64.rpm
- nginx/tasks/main.yml
- name: cp copy: src=nginx-1.18.0-1.el7.ngx.x86_64.rpm dest=/tmp/nginx-1.18.0-1.el7.ngx.x86_64.rpm - name: install yum: name=/tmp/nginx-1.18.0-1.el7.ngx.x86_64.rpm state=latest - name: conf template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf tags: nginxconf notify: new conf to reload - name: start service service: name=nginx state=started enabled=true
- nginx/templates/nginx.conf.j2
usernginx; #設置nginx服務的系統使用用戶 worker_processes{{ ansible_processor_vcpus }}; #工作進程數 error_log/var/log/nginx/error.log warn; #nginx的錯誤日志 pid/var/run/nginx.pid; #nginx啟動時候的pid events { worker_connections1024; #每個進程允許的最大連接數 } http { #http請求配置,一個http可以包含多個server #定義 Content-Type include /etc/nginx/mime.types; default_typeapplication/octet-stream; #日志格式 此處main與access_log中的main對應 #$remote_addr:客戶端地址 #$remote_user:http客戶端請求nginx認證的用戶名,默認不開啟認證模塊,不會記錄 #$timelocal:nginx的時間 #$request:請求method + 路由 + http協議版本 #status:http reponse 狀態碼 #body_bytes_sent:response body的大小 #$http_referer:referer頭信息參數,表示上級頁面 #$http_user_agent:user-agent頭信息參數,客戶端信息 #$http_x_forwarded_for:x-forwarded-for頭信息參數 log_formatmain'$http_user_agent' '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; #訪問日志,后面的main表示使用log_format中的main格式記錄到access.log中 access_log/var/log/nginx/access.logmain; #nginx的一大優勢,高效率文件傳輸 sendfileon; #tcp_nopush on; #客戶端與服務端的超時時間,單位秒 keepalive_timeout65; #gzipon; server { #http服務,一個server可以配置多個location listen {{ nginxport }}; #服務監聽端口 server_namelocalhost; #主機名、域名 #charset koi8-r; #access_log/var/log/nginx/host.access.logmain; location / { root /usr/share/nginx/html; #頁面存放目錄 indexindex.html index.htm; #默認頁面 } #error_page404/404.html; # 將500 502 503 504的錯誤頁面重定向到 /50x.html error_page 500 502 503 504/50x.html; location = /50x.html { #匹配error_page指定的頁面路徑 root /usr/share/nginx/html; #頁面存放的目錄 } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ .php$ { #proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ .php$ { #root html; #fastcgi_pass 127.0.0.1:9000; #fastcgi_indexindex.php; #fastcgi_paramSCRIPT_FILENAME/scripts$fastcgi_script_name; #includefastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /.ht { #denyall; #} } include /etc/nginx/conf.d/*.conf; }
- nginx/vars/main.yml
nginxport: 9999
- nginx/handlers/main.yml
- name: new conf to reload service: name=nginx state=restarted
- 定義劇本文件(roles.yml)
- hosts: web remote_user: root roles: - nginx
最后的目錄結構如下:
執行
ansible-playbook roles.yml