ansible筆記
ansible失敗的地方
被控機器是Windows
1、被控機要開winrm端口
2、Windows的模塊非常少
如果某個主機執行失敗了,會生成retry文件,然后用--limit參數來重新執行即可
to retry, use: ansible --limit @xxx.retry
解決:
一大堆腳本,而且服務器上腳本不是最新
預估停機執行時間
注意:
任務重復執行問題
安全:密碼和密鑰,ansible管理機權限
ansible沒有回滾操作
ansible屬於非登錄shell


ansible執行過程大體過程如下圖,其中暖色調的代表已經模塊化


https://www.jianshu.com/p/575ced3a08fa
特點
無客戶端
無服務器端
基於模塊,用任意語言開發模塊
yaml訂制playbook
基於ssh工作
實現多級指揮
連接插件,連接被管理端
核心模塊
自定義模塊
插件完成模塊功能補充
playbooks定義任務
主機清單

架構圖

f

管理端支持local(連接管理機即自己連接自己的時候) 、ssh、zeromq 三種方式連接被管理端,默認使用基於ssh的連接---這部分對應基本架構圖中的連接模塊;
ansible安裝
主控機
管理節點操作
yum install -y epel-release
yum install -y ansible
任務執行模式
ansible系統由控制主機對被管節點的操作方式有兩種ad_hoc和playbook
ad_hoc單命令模式 可以對多台主機執行單個命令
ansible all -a "/bin/echo hello"
playbook模式
playbook通過多個tasks的集合完成一類功能如web的安裝部署,數據庫服務器的批量備份等
ansible提供了10個命令
ansible
ansible-doc
ansible-vault
ansible-pull
ansible-config
ansible-galaxy
ansible-playbook
ansible-connection
ansible-inventory
ansible-console
1、ansible
ansible命令管理主機
在官方文檔中命令行的名字是:Ad-Hoc Commands
ansible是指令核心部分,其主要用於執行ad-hoc命令,即單條命令。默認后面需要跟主機和選項部分,默認不指定模塊時,使用的是command模塊。如:
[root@localhost ~]# ansible 127.0.0.1 -a 'date'
-m:后面接調用模塊的名字
-a:后面接調用模塊的參數
ansible all -m shell -a "sh /tmp/kel.sh >>/tmp/kel.log"
參數:
-a 'Arguments', --args='Arguments' 命令行參數
-m NAME, --module-name=NAME 執行模塊的名字,默認使用 command 模塊,所以如果是只執行單一命令可以不用 -m參數
-M MODULE_PATH, --module-path=MODULE_PATH 要執行的模塊的路徑,默認為/usr/share/ansible/
-i PATH, --inventory=PATH 指定主機文件、主機目錄、可執行文件的路徑,默認為/etc/ansible/hosts.
-u Username, --user=Username 執行用戶,使用這個遠程用戶名而不是當前用戶
-U --sud-user=SUDO_User sudo到哪個用戶,默認為 root
-k --ask-pass 登錄密碼,提示輸入SSH密碼而不是基於密鑰的驗證
-K --ask-sudo-pass 提示密碼使用sudo -s --sudo sudo運行
-s --snippet 指定模塊顯示playbook片段
-S --su 用 su 命令
-f --forks=NUM 並行任務數。NUM被指定為一個整數,默認是5。 #ansible testhosts -a "/sbin/reboot" -f 10 重啟testhosts組的所有機器,每次重啟10台
--private-key=PRIVATE_KEY_FILE 私鑰路徑,使用這個文件來驗證連接
-vvv --verbose 查看詳細的報錯信息,類似/usr/local/mysql/bin/mysqlbinlog -vv
all 針對hosts 定義的所有主機執行
-o --one-line 壓縮輸出,摘要輸出.嘗試一切都在一行上輸出。
-t Directory, --tree=Directory 執行過程中的日志保存到這個目錄
-B 后台運行超時時間,ansible all -m ping -B 3600 -P 0
-T Seconds, --timeout=Seconds 時間,單位秒s
-P NUM, --poll=NUM 調查背景工作每隔數秒,調查后台程序時間。需要- b
-c Connection, --connection=Connection 連接類型使用。可能的選項是paramiko(SSH),SSH和地方。
--version ansible版本號
-C, --check 只是測試一下,不會真正去執行
-l SUBSET, --limit=SUBSET 進一步限制所選主機/組模式 --limit=192.168.0.15 只對這個ip執行或--limit=kvm 只對這個kvm組執行 ,除了kvm組不執行,其他組都執行ansible all -l kvm -m shell -a "sh /tmp/kel.sh >>/tmp/kel.log"
ansible --version ansible 2.4.2.0 config file = /etc/ansible/ansible.cfg configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.6/site-packages/ansible executable location = /usr/bin/ansible python version = 2.6.6 (r266:84292, Aug 18 2016, 15:13:37) [GCC 4.4.7 20120313 (Red Hat 4.4.7-17)]
查后台任務id ansible all -m ping -B 3600 -P 0 ansible_job_id:"123" xxx #查看后台任務id為123的任務狀態 ansible all -m async_status -a "jid='123'"
2、ansible-doc
查看模塊信息
-l:列出所有已安裝的模塊
-s :查看具體某模塊的用法,如果是extra模塊,必須cd到extra模塊目錄下面再執行,ansible-doc -s command
3、ansible-galaxy
ansible-galaxy 指令用於方便的從https://galaxy.ansible.com/ 站點下載官方收錄的playbooks,我們可以形象的理解其類似於centos下的yum、python下的pip。
ansible-galaxy install aeriscloud.docker
這個安裝了一個aeriscloud.docker組件,前面aeriscloud是galaxy上創建該模塊的用戶名,后面對應的是其模塊。
初始化一個role的目錄結構
ansible-galaxy init role_name
列出已安裝的roles
ansible-galaxy list
查看已安裝的roles信息
ansible-galaxy info bennojoy.mysql
卸載roles
ansible-galaxy remove bennojoy.mysql
安裝一個role
參數-p 指定role下載的目錄。
如果沒有指定-p , 那么role 會被自動下載到環境變量ANSIBLE_ROLES_PATH 定義的目錄下,
或者默認目錄/etc/ansible/roles 下。
ansible-galaxy -p /tmp/roles install bennojoy.nginx
安裝多個role
將所有依賴的role放在一個role.txt里面,-r參數指定role列表文件role.txt,類似pip install -r requirements.txt
ansible-galaxy -p /tmp/roles install -r /tmp/role.txt cat role.txt bennojoy.nginx bennojoy.mysql bennojoy.mongodb 或者 ansible-galaxy -p /tmp/roles install -r requirements.yml cat requirements.yml # from galaxy - src: yatesr.timezone # from GitHub - src: https://github.com/bennojoy/nginx # from GitHub , overriding the name and specifying a specific tag - src: https://github.com/bennojoy/nginx version: master name: nginx role # from a webserver , where the role is packaged in a tar.gz - src: https://some.webserver.example.com/files/master.tar.gz name: http-role
4、ansible-playbook
該指令是使用最多的指令,其通過讀取playbook 文件后,執行相應的動作
--tags=TAGS 只執行指定標簽的任務 例子:ansible-playbook test.yml --tags=copy 只執行標簽為copy的那個任務
--list-hosts 只打印有哪些主機會執行這個 playbook 文件,不是實際執行該 playbook 文件
--list-tasks 列出所有將被執行的任務
--syntax-check 對playbook執行語法檢查,但不執行它
--skip-tags=SKIP_TAGS 只運行任務不匹配這些值的標簽的playbook --skip-tags=copy_start
-e EXTRA_VARS, --extra-vars=EXTRA_VARS 額外的變量設置為鍵=值或YAML / JSON
--syntax-check 檢查yaml文件的語法
--verbose 查看輸出細節
--step 每執行一個任務后停止,等待用戶確認
-f 用多少個線程執行playbook任務,比如用10個線程 ansible-playbook -f 10 ngxin.yml
#ansible-playbook update.yml --extra-vars "hosts=vipers user=admin" 傳遞{{hosts}}、{{user}}變量,hosts可以是 ip或組名
5、ansible-pull
Ansible的另一種工作模式,pull模式,ansible默認使用push模式
支持直接從git下載playbook執行,需要遵循其規定的目錄格式,用處不是特別大,可以不關注
6、ansible-vault
ansible-vault主要應用於配置文件中含有敏感信息,又不希望他能被人看到,vault可以幫你加密/解密這個配置文件,屬高級用法。
主要對於playbooks里比如涉及到配置密碼或其他變量時,可以通過該指令加密,這樣我們通過cat看到的會是一個密碼串類的文件,編輯的時候需要輸入事先設定的密碼才能打開。
這種playbook文件在執行時,需要加上 –ask-vault-pass參數,同樣需要輸入密碼后才能正常執行。具體該部分可以參查官方博客。
[root@node1 ansible]# ansible-vault encrypt db_hosts New Vault password: Confirm New Vault password: Encryption successful [root@node1 ansible]# ansible -i db_hosts localhost -m ping ERROR! Decryption failed Decryption failed [root@node1 ansible]# ansible -i db_hosts --ask-vault-pass localhost -m ping Vault password: localhost | SUCCESS => { "changed": false, "ping": "pong" } [root@node1 ansible]# cat db_hosts $ANSIBLE_VAULT;1.1;AES256 61663966666265363465653064386666326234353433346163633838366532366236313032303636 6437313333333936396164663031633566613233343161650a333163333732616130343762636135 30303864663138643661393234336433313465623830333832663165393964353961323261373130 3135626236626435640a396338616563646532623966333337366365636665663563666432333539 61663632633130623733316232353836663366623136636432616332376266383263356264303765 6133616235363066356164653232326139643862653464623037
ansible核心模塊
Ansible 對遠程服務器的操作實際是通過模塊完成的。其工作原理如下
1、將模塊拷貝到遠程服務器
2、執行模塊定義的操作,完成對服務器的修改
3、在遠程服務器中刪除模塊
所有模塊官方文檔:http://docs.ansible.com/ansible/latest/modules/list_of_all_modules.html
ping模塊
ping一下你的遠程主機,嘗試ssh登錄遠程節點並檢查python版本,如果連接成功,返回pong,不需要任何參數
調試和測試類模塊
setup模塊
獲取遠程機器的facts數據,也就是機器配置
參數
filter:只返回符合過濾規則的facts數據
# 顯示所有機器的facts數據並存儲在/tmp/facts目錄下
# ansible all -m setup --tree /tmp/facts
# 只顯示內存相關內容
# ansible all -m setup -a 'filter=ansible_*_mb'
# 只顯示和facter有關的內容.
# ansible all -m setup -a 'filter=facter_*'
# 只顯示網卡信息
# ansible all -m setup -a 'filter=ansible_eth[0-2]'
debug模塊
參數
msg:定義打印的字符串
var:定義需要打印的變量
regester:定義注入變量
# Example that prints the loopback address and gateway for each host
- debug:
msg: "System {{ inventory_hostname }} has uuid {{ ansible_product_uuid }}"
- debug:
msg: "System {{ inventory_hostname }} has gateway {{ ansible_default_ipv4.gateway }}"
when: ansible_default_ipv4.gateway is defined
- shell: /usr/bin/uptime
register: result #將執行結果注入result變量
- debug:
var: result #打印result的內容
verbosity: 2
- name: Display all variables/facts known for a host
debug:
var: hostvars[inventory_hostname]
verbosity: 4
script模塊
在遠程節點上執行主控機上的腳步,其功能相當於scp + shell 的組合,腳本執行完成以后會在遠程服務器上刪除腳本文件
參數
chdir:在執行腳步之前先cd到這個目錄
- script: /some/local/script.sh --some-arguments 1234 # Run a script that creates a file, but only if the file is not yet created - script: /some/local/create_file.sh --some-arguments 1234 args: creates: /the/created/file.txt # Run a script that removes a file, but only if the file is not yet removed - script: /some/local/remove_file.sh --some-arguments 1234 args: removes: /the/removed/file.txt
copy模塊
復制前會比較遠程文件的checksum,如果相同則不復制,返回ok,如果不同才復制,返回changed
參數
mode:可以是數字形式也可以是符號形式,0644 ,01777,u+rwx , u=rw,g=r,o=r
owner:屬主
group:屬組
backup:默認no,先備份目標節點的源文件再復制,如果拷貝過程失敗,則源文件還能使用,而不是對目標文件備份一份!
validate:默認none,驗證復制后的文件,%s指代復制后的文件
dest:目標文件,必須是絕對路徑
src:源文件,可以是絕對路徑,也可以是相對路徑,/tmp/表示拷貝文件夾里內容,/tmp表示把文件夾也拷貝過去
force:默認yes,當目標文件跟源文件不一樣時會強制覆蓋目標文件,如果一樣,不會執行復制,別名thirsty,也就是thirsty等於force
follow:默認no,當拷貝的文件夾內有link存在的時候,那么拷貝過去的也會有link
- name: example copying file with owner and permissions copy: src: /srv/myfiles/foo.conf dest: /etc/foo.conf owner: foo group: foo mode: 0644 - name: The same example as above, but using a symbolic mode equivalent to 0644 copy: src: /srv/myfiles/foo.conf dest: /etc/foo.conf owner: foo group: foo mode: u=rw,g=r,o=r - name: Another symbolic mode example, adding some permissions and removing others copy: src: /srv/myfiles/foo.conf dest: /etc/foo.conf owner: foo group: foo mode: u+rw,g-wx,o-rwx - name: Copy a new "ntp.conf file into place, backing up the original if it differs from the copied version copy: src: /mine/ntp.conf dest: /etc/ntp.conf owner: root group: root mode: 0644 backup: yes - name: Copy a new "sudoers" file into place, after passing validation with visudo copy: src: /mine/sudoers dest: /etc/sudoers validate: /usr/sbin/visudo -cf %s - name: Copy a "sudoers" file on the remote machine for editing copy: src: /etc/sudoers dest: /etc/sudoers.edit remote_src: yes validate: /usr/sbin/visudo -cf %s - name: Copy using the 'content' for inline data copy: content: '# This file was moved to /etc/other.conf' dest: /etc/mine.conf'
template模塊
在復制的同時根據實際情況修改部分內容,這時不能用copy模塊,要用template模塊
template模塊使用的是python的jinja2模板引擎,這里不需要了解jinja2,只需要知道變量的表示法
{{}}就可以了
template模塊同樣具備copy模塊的權限設置,文件備份,驗證功能
參數
mode:可以是數字形式也可以是符號形式,0644 ,01777,u+rwx , u=rw,g=r,o=r
owner:屬主
group:屬組
backup:默認no,先備份目標節點的源文件再復制
validate:默認none,驗證復制后的文件,%s指代復制后的文件
dest:目標文件
src:源文件
force:默認yes,當目標文件跟源文件不一樣時會強制覆蓋目標文件,如果一樣,不會執行復制
follow:默認no,當拷貝的文件夾內有link存在的時候,那么拷貝過去的也會有link
roles/templates/server.xml中的template文件關鍵部分如下:
<?xml version="1.0" encoding="utf-8"?>
<code class="language-shell hljs handlebars">
<user username="{{ admin_username }}" password="{{ admin_password }}" roles="manager-gui"/>
</code>
當這個文件還沒被template執行的時候,本地的admin_username及admin_password 都是變量狀態。
當playbook執行完template的時候,遠程的admin_username*及admin_password 會變成變量所對應的值。
么在執行這個Playbook前,對應的那個template文件(俗稱模版),將在本地保持{{ admin_username }}及{{ admin_password }}的狀態。在Ansible調用template模版執行的時候,這里將由Jinjia2從”tomcat-servers”讀取對應的值,然后替換掉模版里的變量,
然后把這個替換變量值后的文件拷貝到遠程節點。
file模塊
用來設置遠程主機上的文件,軟鏈接symlinks,文件夾權限,也可以創建和刪除文件夾,文件
參數
path:目標路徑,別名dest,,name,也就是dest,,name等於path
recurse:遞歸設置文件屬性,當state為directory時候
mode:可以是數字形式也可以是符號形式,0644 ,01777,u+rwx , u=rw,g=r,o=r
owner:屬主
group:屬組
src:源鏈接,只能應用於state=link 、 state=hard的情況
force:默認yes,當目標文件跟源文件不一樣時會強制覆蓋目標文件,如果一樣,不會執行復制
follow:默認no,當拷貝的文件夾內有link存在的時候,那么拷貝過去的也會有link
state:默認file,file/link/directory/hard/touch/absent
file代表拷是文件;
link代表是個軟鏈接;
directory代表文件夾;
hard代表硬鏈接;
touch代表生成一個空文件;
absent代表刪除
#改變文件權限,數字權限必須以0開頭 - file: path: /etc/foo.conf owner: foo group: foo mode: 0644 #創建軟鏈接,這里的src和dest參數含義和copy模塊不一樣,file模塊里所操作的文件都是遠程節點上的文件 - file: src: /file/to/link/to dest: /path/to/symlink owner: foo group: foo state: link # 創建一個新文件 touch命令 - file: path: /etc/foo.conf state: touch mode: "u=rw,g=r,o=r" # touch the same file, but add/remove some permissions - file: path: /etc/foo.conf state: touch mode: "u+rw,g-wx,o-rwx" # 創建一個文件夾 - file: path: /etc/some_directory state: directory mode: 0755
user模塊/group模塊
user 模塊請求的是useradd , userdel , usermod 三個命令
group 模塊請求的是groupadd,groupdel, groupmod 三個命令
參數
group:主屬組
groups:多個附加屬組,用逗號分隔
home:家目錄
createhome:默認yes,是否創建家目錄
name:用戶名或群組名,必須,別名user,也就是user等於name
password:密碼,必須是加密過的密碼,python -c "from passlib.hash import sha512_crypt; import getpass; print(sha512_crypt.using(rounds=5000).hash(getpass.getpass()))"
remove:把家目錄也刪除,前提state為absent,相當於userdel -r
shell:設置用戶的登錄shell
uid:設置uid
gid:設置gid
state:創建或刪除用戶/群組,取值包括present 和absent
generate_ssh_key:是否生成密鑰
ssh_key_bits:sshkey的位數,最好設置為2048
ssh_key_file:默認.ssh/id_rsa,
ssh_key_type:默認rsa, 可選dsa,rsa
ssh_key_passphrase:sshkey的密碼
expires :用戶過期時間,過期時間為時間戳
- name: 添加用戶johnd,設置uid為1040,組為admin user: name: johnd comment: John Doe uid: 1040 group: admin - name: 添加用戶james,設組為admins,developers user: name: james shell: /bin/bash groups: admins,developers append: yes - name: 刪除用戶johnd user: name: johnd state: absent remove: yes - name: 創建密鑰是 2048位 SSH key 的用戶jsmith,保存位置在~jsmith/.ssh/id_rsa user: name: jsmith generate_ssh_key: yes ssh_key_bits: 2048 ssh_key_file: .ssh/id_rsa - name: 創建用戶james18,設置過期時間為2015/1/28 8:3:7 user: name: james18 shell: /bin/zsh groups: developers expires: 1422403387 #創建群組 ansible test -m group -a "name=ansible state=present gid=l234" -become #刪除群組 ansible test -m group -a "name=ansible state=absent" -become
yum模塊
管理yum包,fedora從版本22開始使用dnf代替yum,如果用fedora22推薦用dnf模塊來進行安裝包
參數
conf_file:yum的配置文件
disable_gpg_check:默認no, 只有state 為present 或 latest.才能指定disable_gpg_check
list:相當於yum list <package>
name:包名, 可以是'*' 表示yum -y update 更新所有包 或 rpm 文件的url路徑或本地路徑 ,同時 state=present ,別名pkg,也就是pkg等於name
state:用於描述安裝包最終狀態,present/latest/installed用於安裝包,removed/absent用於remove安裝包
update_cache:默認no,用於安裝包前執行更新list,只會影響state參數為present/latest的時候
- name: 安裝最新版本的Apache,如果已經安裝了老版本,那么會更新到最新版本 yum: name: httpd state: latest - name: 刪除 Apache 包 yum: name: httpd state: absent - name: 從testing repo 安裝Apache yum: name: httpd enablerepo: testing state: present - name: 安裝指定版本的 Apache yum: name: httpd-2.2.29-1.4.amzn1 state: present - name: 更新所有包 yum: name: '*' state: latest - name: 更新所有包 除外 kernel & foo yum: name: '*' state: latest exclude: kernel*,foo* - name: 從url中安裝nginx rpm 包 yum: name: http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm state: present - name: 從本地文件中安裝 nginx rpm 包 yum: name: /usr/local/src/nginx-release-centos-6-0.el6.ngx.noarch.rpm state: present - name: 安裝一組包 group install 'Development tools' yum: name: "@Development tools" state: present - name: 安裝一組包 group install 'Gnome desktop' yum: name: "@^gnome-desktop-environment" state: present - name: yum list 出ansible相關的包並注入 register result ,之后用 debug 模塊打印 yum: list: ansible register: result - name: 使用多個倉庫來安裝包 yum: name: sos enablerepo: "epel,ol7_latest" - name: 從多個禁用倉庫安裝包 yum: name: sos disablerepo: "epel,ol7_latest"
service模塊
管理遠程節點上的服務,比如httpd,sshd,nfs,crond等
參數
arguments:給命令行提供一些選項,別名: args,也就是args等於arguments
enabled:是否開機啟動
name:必選項,服務名稱
state:對當前服務執行啟動,停止、重啟、重新加載等操作(started,stopped,restarted,reloaded)
pattern:定義一個模式,如果通過status指令來查看服務的狀態時,沒有響應,就會通過ps指令在進程中根據該模式進行查找,如果匹配到,則認為該服務依然在運行
- name: 開啟服務 service: name: httpd state: started - name: 關服務 service: name: httpd state: stopped - name: 重啟服務 service: name: httpd state: restarted - name: 重載服務 service: name: httpd state: reloaded - name: 設置開機啟動服務 service: name: httpd enabled: yes - name: 啟動foo服務,根據/usr/bin/foo service: name: foo pattern: /usr/bin/foo state: started - name: 重啟網絡服務的eth0網卡 service: name: network state: restarted args: eth0 ansible all -m service -a 'name=network state=restarted args=eth0'
firewalld模塊
為某服務和端口添加firewalld規則,firewalld中有正在運行的規則和永久的規則,firewalld都支持
firewalld模塊要求遠程節點上的firewalld版本在0.2.11以上
參數
permanent:默認None,是否保存設置即使重啟機器
interface,默認None,從zone里增刪網卡
port:端口,形式端口/協議 ,端口范圍 端口-端口/協議
rich_rule:復雜的firewalld規則
service:服務名,為服務添加firewall規則
source:ip來源
state:狀態,enabled、disabled、present、absent
zone:work、drop、internal、external、trusted、home、dmz、public、block
#為https服務添加firewall規則 - firewalld: service: https permanent: true state: enabled #區域dmz - firewalld: zone: dmz service: http permanent: true state: enabled #為端口號8081/tcp,范圍161-162/udp添加firewall規則 - firewalld: port: 8081/tcp permanent: true state: disabled - firewalld: port: 161-162/udp permanent: true state: enabled #其他復雜規則 - firewalld: rich_rule: 'rule service name="ftp" audit limit value="1/m" accept' permanent: true state: enabled - firewalld: source: 192.0.2.0/24 zone: internal state: enabled - firewalld: zone: trusted interface: eth2 permanent: true state: enabled - firewalld: masquerade: yes state: enabled permanent: true zone: dmz - firewalld: zone: custom state: present permanent: true
shell模塊/raw模塊
在遠程節點通過/bin/sh執行命令,如果一個操作可以通過模塊yum,copy實現,那么建議不要用shell或command這樣的通用命令模塊
因為通用命令模塊不會根據具體操作的特點進行狀態status判斷,所以當沒有必要再重新執行的時候,他還是會重新執行一次
shell/raw 模塊相當於使用SSH 直接執行Linux 命令,不會進入到Ansible 的模塊子系統中,也可以執行遠程機器的shell腳本,不過shell腳本需要絕對路徑
shell:在節點執行shell命令,支持$HOME、<、>、|、;、& ,不支持傳入參數
參數
chdir:默認None,運行shell之前cd到某個目錄
creates:默認None,創建一個文件,如果這個文件存在則不運行shell
removes:默認None,刪除一個文件,如果這個文件不存在則不運行shell
executable:默認None,指定用哪種shell來執行命令,給出shell的絕對路徑,比如/bin/bash
- name: 執行shell命令,把標准輸出重定向到文件 shell: somescript.sh >> somelog.txt - name: 改變工作目錄在執行shell命令前 shell: somescript.sh >> somelog.txt args: chdir: somedir/ - name: somelog.txt不存在並改變工作目錄 shell: somescript.sh >> somelog.txt args: chdir: somedir/ creates: somelog.txt - name: bash處理重定向 shell: cat < /tmp/*txt args: executable: /bin/bash - name: 使用模板變量 (always use quote filter to avoid injection) shell: cat {{ myfile|quote }} - name: Run expect to wait for a successful PXE boot via out-of-band CIMC shell: | set timeout 300 spawn ssh admin@{{ cimc_host }} expect "password:" send "{{ cimc_password }}\n" expect "\n{{ cimc_name }}" send "connect host\n" expect "pxeboot.n12" send "\n" exit 0 args: executable: /usr/bin/expect delegate_to: localhost
command模塊
在遠程節點執行命令,不支持家目錄,重定向,管道 $HOME、<、>、|、;、&
和shell模塊類似,但有一個和shell模塊不同,command模塊多了一個傳入參數的方式
參數
chdir:默認None,運行shell之前cd到某個目錄
creates:默認None,創建一個文件,如果這個文件存在則不運行shell
removes:默認None,刪除一個文件,如果這個文件不存在則不運行shell
- name: 返回執行結果到變量 registered var command: cat /etc/motd register: mymotd - name: command模塊多了一個傳入參數的方式 command: /usr/bin/make_database.sh arg1 arg2 creates=/path/to/database - name: This command will change the working directory to somedir/ and will only run when /path/to/database doesn't exist. command: /usr/bin/make_database.sh arg1 arg2 args: chdir: somedir/ creates: /path/to/database - name: safely use templated variable to run command. Always use the quote filter to avoid injection issues. command: cat {{ myfile|quote }} register: myoutput
cron模塊
管理cron.d 目錄 crontab 文件
參數
cron_file:如果指定該選項,則用該文件替換遠程主機上的cron.d目錄下的用戶任務計划,與user參數一起用
backup:默認no,對遠程主機上的原任務計划內容修改之前做備份,萬一出故障還原回來,而不是備份任務計划
job:要執行的任務,依賴於state=present 別名value ,也就是job等於value
user:默認root,操作哪個用戶的crontab
disabled:禁用job,默認no,job狀態必須是state=present
name:該任務的描述(必須項)
minute:分鍾(0-59,*,*/2,……),不寫默認為*
hour:小時(0-23,*,*/2,……),不寫默認為*
day:日(1-31,*,*/2,……),不寫默認為*,別名dom ,也就是day等於dom
month:月(1-12,*,*/2,……),不寫默認為*
weekday:周(0-7,*,……),不寫默認為*,別名dow,也就是weekday等於dow
special_time:指定什么時候執行,參數:reboot/yearly/annually/monthly/weekly/daily/hourly
state:狀態,參數:present:創建任務 、absent:刪除任務
# 5點和2點運行 一個ls命令"0 5,2 * * ls -alh > /dev/null" - cron: name: "check dirs" minute: "0" hour: "5,2" job: "ls -alh > /dev/null" # 移除名叫an old job的作業 - cron: name: "an old job" state: absent # 創建一個作業 "@reboot /some/job.sh" - cron: name: "a job for reboot" special_time: reboot job: "/some/job.sh" # 建一個環境變量 "PATH=/opt/bin" - cron: name: PATH env: yes value: /opt/bin # Creates an entry like "APP_HOME=/srv/app" and insert it after PATH # declaration - cron: name: APP_HOME env: yes value: /srv/app insertafter: PATH # 建一個cron文件存放在 /etc/cron.d - cron: name: yum autoupdate weekday: 2 minute: 0 hour: 12 user: root job: "YUMINTERACTIVE: 0 /usr/sbin/yum-autoupdate" cron_file: ansible_yum-autoupdate # 刪除一個cron文件 /etc/cron.d - cron: name: "yum autoupdate" cron_file: ansible_yum-autoupdate state: absent # 刪除 "APP_HOME" 環境變量 - cron: name: APP_HOME env: yes state: absent
unarchive模塊
unarchive模塊用於解壓文件,其作用類似於Linux 下的tar 命令。
默認情況下,unarchive的作用是將主控機的壓縮包拷貝到遠程服務器,然后進行解壓。
遠程機器需要已經安裝gtar/unzip
參數:
remote_src: 默認no,表示在解壓文件之前,先將控制節點上的文件復制到遠程主機中,然后再進行解壓,即使遠程主機已經有這個壓縮文件也不檢查,yes表示解壓遠程主機上的文件,即使遠程主機無這個文件
src: 必須,指定壓縮文件的路徑,該選項的取值取決於remote_src 的取值, 如果remote_src:取值為yes ,則src 指定的是遠程服務器中壓縮包的地址,如果remote_src取值為no, 則src 指向的是控制節點中的路徑;
dest: 必須,該選項指定的是遠程服務器上的絕對路徑,表示壓縮文件解壓的路徑
list_files:默認no ,如果該選項取值為yes ,也會解壓文件,並且在ansible 的返回值中列出壓縮包里的文件
exclude: 解壓文件時排除exclude 選項指定的文件或目錄列表;
keep_newer:默認False ,如果該選項取值為True ,那么,當目標地址中存在同名的文件,並且文件比壓縮包中的文件更新時,不進行覆蓋;
owner: 文件或目錄解壓以后的所有者
group:文件或目錄解壓以后所屬的群組
mode: 文件或目錄解壓以后的權限
- name: Extract foo.tgz into /var/lib/foo unarchive: src: foo.tgz dest: /var/lib/foo - name: Unarchive a file that is already on the remote machine unarchive: src: /tmp/foo.zip dest: /usr/local/bin remote_src: yes - name: Unarchive a file that needs to be downloaded (added in 2.0) unarchive: src: https://example.com/example.zip dest: /usr/local/bin remote_src: yes
stat模塊
stat 模塊用於獲取遠程服務器上的文件信息,其作用類似於Linux 下的stat 命令。
stat模塊可以獲取atime 、ctime 、mtime 、checksum 、size 、uid 、gid 等信息
參數:
path: 指定文件或目錄的路徑
# Obtain the stats of /etc/foo.conf, and check that the file still belongs # to 'root'. Fail otherwise. - stat: path: /etc/foo.conf register: st - fail: msg: "Whoops! file ownership has changed" when: st.stat.pw_name != 'root' # Determine if a path exists and is a symlink. Note that if the path does # not exist, and we test sym.stat.islnk, it will fail with an error. So # therefore, we must test whether it is defined. # Run this to understand the structure, the skipped ones do not pass the # check performed by 'when' - stat: path: /path/to/something register: sym - debug: msg: "islnk isn't defined (path doesn't exist)" when: sym.stat.islnk is not defined - debug: msg: "islnk is defined (path must exist)" when: sym.stat.islnk is defined - debug: msg: "Path exists and is a symlink" when: sym.stat.islnk is defined and sym.stat.islnk - debug: msg: "Path exists and isn't a symlink" when: sym.stat.islnk is defined and sym.stat.islnk == False # Determine if a path exists and is a directory. Note that we need to test # both that p.stat.isdir actually exists, and also that it's set to true. - stat: path: /path/to/something register: p - debug: msg: "Path exists and is a directory" when: p.stat.isdir is defined and p.stat.isdir # Don't do md5 checksum - stat: path: /path/to/myhugefile get_md5: no # Use sha256 to calculate checksum - stat: path: /path/to/something checksum_algorithm: sha256
mount 模塊
在遠程服務器上掛載磁盤,當進行掛盤操作時,如果掛載點指定的路徑不存在,將創建該路徑
參數
state:可以取值為present, absent, mounted, unmounted , 其中, mounted 與unmounted 用來處理磁盤的掛載和卸載, 並且會正確配置fstab 文件, preset 與absent 只會設置fstab 文件, 不會去操作磁盤
fstype:指定文件系統類型, 當state 取值為present 或mounted 時,該選項為必填選項
src:掛載的設備
path: 掛載點的路徑
# Before 2.3, option 'name' was used instead of 'path' - name: Mount DVD read-only mount: path: /mnt/dvd src: /dev/sr0 fstype: iso9660 opts: ro,noauto state: present - name: Mount up device by label mount: path: /srv/disk src: LABEL=SOME_LABEL fstype: ext4 state: present - name: Mount up device by UUID mount: path: /home src: UUID=b3e48f45-f933-4c8e-a700-22a159ec9077 fstype: xfs opts: noatime state: present
synchronize模塊
synchronize 模塊是對rsync 命令的封裝,以便對常見的rsync 任務進行處理
注意:主控機和遠程主機都需要安裝rsync,rsync daemon必須在主控機和遠程主機都運行
synchronize模塊不一定能完全代替rsync命令
參數
src : 需要同步到遠程服務器的文件或目錄
dest :遠程服務器保存數據的路徑
archive :默認yes ,相當於同時開啟recursive 、links 、perms 、times 、owner 、group 、-D 等選項
compress :默認yes ,表示在文件同步過程中是否啟用壓縮
delete :默認no ,當取值為yes 時,表示刪除dest 中存在而src 中不存在的文件
過濾: (.rsync-filter )files to the source directory,排除同步rsync-filter 文件里面指定的文件
- name: Synchronization of src on the control machine to dest on the remote hosts synchronize: src: some/relative/path dest: /some/absolute/path - name: Synchronization using rsync protocol (push) synchronize: src: some/relative/path/ dest: rsync://somehost.com/path/ - name: Synchronization using rsync protocol (pull) synchronize: mode: pull src: rsync://somehost.com/path/ dest: /some/absolute/path/ - name: Synchronization using rsync protocol on delegate host (push) synchronize: src: /some/absolute/path/ dest: rsync://somehost.com/path/ delegate_to: delegate.host - name: Synchronization using rsync protocol on delegate host (pull) synchronize: mode: pull src: rsync://somehost.com/path/ dest: /some/absolute/path/ delegate_to: delegate.host - name: Synchronization without any --archive options enabled synchronize: src: some/relative/path dest: /some/absolute/path archive: no - name: Synchronization with --archive options enabled except for --recursive synchronize: src: some/relative/path dest: /some/absolute/path recursive: no - name: Synchronization with --archive options enabled except for --times, with --checksum option enabled synchronize: src: some/relative/path dest: /some/absolute/path checksum: yes times: no - name: Synchronization without --archive options enabled except use --links synchronize: src: some/relative/path dest: /some/absolute/path archive: no links: yes - name: Synchronization of two paths both on the control machine synchronize: src: some/relative/path dest: /some/absolute/path delegate_to: localhost - name: Synchronization of src on the inventory host to the dest on the localhost in pull mode synchronize: mode: pull src: some/relative/path dest: /some/absolute/path - name: Synchronization of src on delegate host to dest on the current inventory host. synchronize: src: /first/absolute/path dest: /second/absolute/path delegate_to: delegate.host - name: Synchronize two directories on one remote host. synchronize: src: /first/absolute/path dest: /second/absolute/path delegate_to: "{{ inventory_hostname }}" - name: Synchronize and delete files in dest on the remote host that are not found in src of localhost. synchronize: src: some/relative/path dest: /some/absolute/path delete: yes recursive: yes # This specific command is granted su privileges on the destination - name: Synchronize using an alternate rsync command synchronize: src: some/relative/path dest: /some/absolute/path rsync_path: "su -c rsync" # Example .rsync-filter file in the source directory # - var # exclude any path whose last part is 'var' # - /var # exclude any path starting with 'var' starting at the source directory # + /var/conf # include /var/conf even though it was previously excluded - name: Synchronize passing in extra rsync options synchronize: src: /tmp/helloworld dest: /var/www/helloworld rsync_opts: - "--no-motd" - "--exclude=.git" # Hardlink files if they didn't change - name: Use hardlinks when synchronizing filesystems synchronize: src: /tmp/path_a/foo.txt dest: /tmp/path_b/foo.txt link_dest: /tmp/path_a/
get_url模塊
類似於wget和curl的功能,可以進行下載以及webapi交互等操作
支持HTTP, HTTPS, FTP
參數:
backup:默認no,創建一個包括時間戳信息的備份文件,這樣你可以得到原始文件,如果你不正確地弄錯了
checksum:
如果將校驗和傳遞給此參數,則將在下載目標文件的摘要后計算摘要,以確保其完整性。格式:<algorithm>:<checksum>,例如:checksum =“sha256:D98291AC [...] B6DC7B97”如果你擔心可移植性,只有sha1算法可用於所有平台和python版本。可以安裝第三方hashlib庫以訪問其他算法。此外,如果將校驗和傳遞給此參數,並且文件位於dest位置下,則將計算destination_checksum,如果校驗和等於destination_checksum,則將跳過文件下載(除非force為true)
dest:目標文件,必須
force:默認no,當目標文件跟源文件不一樣時會強制覆蓋目標文件,如果一樣,不會執行復制,別名thirsty,也就是thirsty等於force
mode:可以是數字形式也可以是符號形式,0644 ,01777,u+rwx , u=rw,g=r,o=r
owner:屬主
group:屬組
timeout:默認10秒,單位秒 超時請求
url:HTTP, HTTPS, FTP形式URL
url_username:用於HTTP基本認證的用戶名。對於允許空密碼的站點,可以在不使用url_password的情況下使用此參數。
url_password:用於HTTP基本認證的密碼。如果未指定url_username參數,則不會使用url_password參數。
use_proxy:默認yes,如果no,它將不使用代理,即使在目標主機上的環境變量中定義了一個代理。
validate_certs:默認yes,如果no,SSL證書將不會驗證。這只應在使用自簽名證書的個人控制站點上使用。
tmp_dest:臨時文件下載到的絕對路徑。默認為TMPDIR,TEMP或TMP env變量或特定於平台的值
- name: 下載文件 foo.conf get_url: url: http://example.com/path/file.conf dest: /etc/foo.conf mode: 0440 - name: 下載並校驗文件(sha256) get_url: url: http://example.com/path/file.conf dest: /etc/foo.conf checksum: sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c - name: D下載並校驗文件 (md5) get_url: url: http://example.com/path/file.conf dest: /etc/foo.conf checksum: md5:66dffb5228a211e61d6d7ef4a86f5758 - name: 用ftp下載一個文件 get_url: url: file:///tmp/afile.txt dest: /tmp/afilecopy.txt
fetch模塊
從遠程機器拷貝文件到控制機
參數
dest:必選項,必須是一個目錄,假如目錄是/backup/,文件名是/etc/profile,機器是192.168.3.6,那么保存的路徑是/backup/192.168.3.6/etc/profile
flat:如果dest是/backup/而不是/backup,那么就會修改默認行為,那么保存的路徑是/backup/profile
src :必選項,遠程機器的文件位置,必須是一個文件,不能是目錄,后續可能會支持目錄
validate_checksum:默認yes,驗證源文件和目標文件的校驗和
# 存儲文件在目標路徑/tmp/fetched/192.168.3.6/tmp/somefile - fetch: src: /tmp/somefile dest: /tmp/fetched # 直接定義一個路徑 - fetch: src: /tmp/somefile dest: /tmp/prefix-{{ inventory_hostname }} flat: yes # 定義一個目標路徑 - fetch: src: /tmp/uniquefile dest: /tmp/special/ flat: yes # 存儲在針對playbook的相對路徑 - fetch: src: /tmp/uniquefile dest: special/prefix-{{ inventory_hostname }} flat: yes
core模塊和extra模塊
在ansible文檔上查看單個模塊會顯示是core模塊還是extra模塊
yum就是一個core模塊,archive就是一個extra模塊
core模塊
不需要額外下載和配置,安裝ansible后就可以直接使用
extra模塊
需要進行下載和額外配置才能使用
額外的模塊托管在Github上的,ansible-modules-extras <http://github.com/ansible/ansible-modules-extras>
使用方法
1、下載extra模塊
cd /tmp/
git clone https://github.com/ansible/ansible-modules-extras.git
2、修改配置文件
/etc/ansible/ansible.cfg
#library = /tmp/ansible-modules-extras/
ansible配置文件 ansible.cfg
注意:修改了配置文件不需要重啟ansible,因為ansible不是服務端,沒有后台運行,修改了配置文件馬上生效
ansible.cfg提供的是默認配置,在inventory文件里或playbook里沒有定義的配置,ansible.cfg提供默認配置,例如sudo_user這個選項
module_set_locale 設置本地的環境變量
inventory = /etc/ansible/hosts 這個一個靜態的ini格式的文件,指定主機文件、主機目錄、可執行文件的路徑,默認為/etc/ansible/hosts.
#library = /usr/share/my_modules/ Ansible默認搜尋extra模塊的位置
remote_tmp = $HOME/.ansible/tmp Ansible 通過遠程傳輸模塊到遠程主機,然后遠程執行,執行后在清理現場,所以你看不到遠程主機有python腳本或模塊存在
pattern = * 如果沒有提供“hosts”節點,這是playbook要通信的默認主機組.默認值是對所有主機通信
forks = 5 在與主機通信時的默認並行進程數 ,默認是5
poll_interval = 15 當具體的poll interval 沒有定義時,多少時間回查一下這些任務的狀態, 默認值是15秒
sudo_user = root sudo使用的默認用戶 ,默認是root
#ask_sudo_pass = True 用來控制Ansible playbook 在執行sudo之前是否詢問sudo密碼.默認為False
#ask_pass = True 控制Ansible playbook 是否會自動默認彈出密碼,默認為False,如果改為true,ansible命令就不需要用-k選項
transport = smart 通信機制.默認 值為’smart’。如果本地系統支持 ControlPersist技術的話,將會使用(基於OpenSSH)‘ssh’,如果不支持講使用‘paramiko’.其他傳輸選項包括‘local’, ‘chroot’,’jail’等等
#remote_port = 22 遠程SSH端口。 默認是22
module_lang = C 模塊和系統之間通信的計算機語言,默認是C語言
gathering = implicit 控制默認facts收集(遠程系統變量). 默認值為’implicit’, 每一次play,facts都會被收集
#roles_path = /etc/ansible/roles roles 路徑指的是’roles/’下的目錄,用於playbook搜索Ansible roles
#host_key_checking = False 檢查主機密鑰
sudo_exe = sudo 如果在其他遠程主機上使用另一種方式執sudo操作.可以使用該參數進行更換
#what flags to pass to sudo 傳遞sudo之外的參數
#sudo_flags = -H
#SSH timeout SSH超時時間
timeout = 10
#remote_user = root 使用/usr/bin/ansible-playbook鏈接的默認用戶名,如果不指定,會使用當前登錄的用戶名
#log_path = /var/log/ansible.log 日志文件存放路徑
#module_name = command ansible命令執行默認的模塊
#executable = /bin/sh 在sudo環境下產生一個shell交互接口. 用戶只在/bin/bash的或者sudo限制的一些場景中需要修改
#jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n 允許開啟Jinja2拓展模塊
#private_key_file = /root/.ssh/id_rsa 私鑰文件存儲位置
ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host} 這個設置可以告知用戶,Ansible修改了一個文件,並且手動寫入的內容可能已經被覆蓋.
#display_skipped_hosts = True 顯示任何跳過任務的狀態 ,默認是顯示
#error_on_undefined_vars = False 如果所引用的變量名稱錯誤的話, 將會導致ansible在執行步驟上失敗
#system_warnings = True 允許禁用系統運行ansible相關的潛在問題警告
#deprecation_warnings = True 允許在ansible-playbook輸出結果中禁用“不建議使用”警告
#command_warnings = False 當shell和命令行模塊被默認模塊簡化時,Ansible 將默認發出警告
#nocows = 1 默認ansible可以調用一些cowsay的特性 開啟/禁用:0/1
#nocolor = 1 輸出帶上顏色區別, 開啟/關閉:0/1
在線查看ansible.cfg文件
https://raw.githubusercontent.com/ansible/ansible/devel/examples/ansible.cfg
ansible配置文件解釋列表
http://docs.ansible.com/ansible/latest/installation_guide/_config.html
http://docs.ansible.com/ansible/latest/installation_guide/intro_configuration.html
ansible會按照下面順序查找配置文件
ANSIBLE_CONFIG (environment variable if set)
ansible.cfg (in the current directory)
~/.ansible.cfg (in the home directory)
/etc/ansible/ansible.cfg
inventory配置
指定inventory配置文件
1、在/etc/ansible/ansible.cfg中修改
inventory = /etc/ansible/hosts
2、命令行中傳遞inventory配置文件
利用參數-i傳遞主機清單配置文件
ansible-playbook -i /etc/ansible/hosts site.yml
靜態inventory
一組相似的 hostname , 可簡寫如下,一般建議使用ip,而不使用主機名或域名,需要反解析:
[webservers]
www[01:50].example.com
數字的簡寫模式中,01:50 也可寫為 1:50,意義相同.你還可以定義字母范圍的簡寫模式:
[databases]
db-[a:f].example.com
inventory變量
主機變量
分配變量給主機很容易做到,這些變量定義后可在 playbooks 中使用:
[atlanta]
host1 http_port=80 maxRequestsPerChild=808 #maxRequestsPerChild 稱為主機變量
host2 http_port=303 maxRequestsPerChild=909
組變量
也可以定義屬於整個組的變量,這樣就不用單獨一台一台主機定義變量:
[atlanta]
host1
host2
[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
[docker] #定義了一組叫docker 172.16.1.11 #組下面的主機 172.16.1.12 #172.11.11.11 # ansible_ssh_pass='123456' [docker:vars] #針對docker組使用inventroy內置變量定義了ssh登陸密碼,中括號里寫組名:vars ansible_ssh_pass='123456' [kvm] 172.16.1.13 172.16.1.14 [docker:children] #組的繼承,docker下面包含一個kvm組,kvm組里會繼承docker組所有變量ansible_ssh_pass kvm
按目錄結構定義變量
通過/etc/ansible/ 定義文件表示變量
創建:/etc/ansible/host_vars/
創建:/etc/ansible/group_vars/
host_vars目錄下文件名,要和/etc/ansible/hosts文件里的host名一致,並且是yaml格式文件
group_vars目錄下文件名,要和/etc/ansible/hosts文件里的group名一致,並且是yaml格式文件
host_vars目錄下目錄名,ansible會讀取目錄下所有文件內容,並且是yaml格式文件
group_vars目錄下目錄名,ansible會讀取目錄下所有文件內容,並且是yaml格式文件
比如
主機變量
/etc/ansible/hosts
client_105 #主機名
/etc/ansible/host_vars/client_105.yml
---
client_105_key: 105
組變量
/etc/ansible/hosts
[kvm]
192.168.3.6
/etc/ansible/group_vars/kvm.yml
---
ntp_server: ntp.atlanta.example.com
目錄下
/etc/ansible/host_vars/client_105/1.yml
/etc/ansible/host_vars/client_105/2.yml
/etc/ansible/host_vars/client_105/x.yml
/etc/ansible/group_vars/kvm/1.yml
/etc/ansible/group_vars/kvm/2.yml
/etc/ansible/group_vars/kvm/x.yml
Inventory行為參數(behavioral inventory parameters )
覆蓋Ansible 默認配置時
ansible_ssh_host
將要連接的遠程主機名.與你想要設定的主機的別名不同的話,可通過此變量設置.
ansible_ssh_port
ssh端口號.如果不是默認的端口號,通過此變量設置.
ansible_ssh_user
默認的 ssh 用戶名
ansible_ssh_pass
ssh 密碼(這種方式並不安全,我們強烈建議使用ansible命令行中 -k 參數 或 SSH 密鑰)
ansible_sudo_pass
sudo 密碼(這種方式並不安全,我們強烈建議使用 -K)
ansible_sudo_exe (new in version 1.8)
sudo 命令路徑(適用於1.8及以上版本)
ansible_become
強制使用sudo提權
ansible_become_method
使用哪種提權方法,例如sudo
ansible_become_user
sudo用戶,切換到哪個用戶執行命令
ansible_become_pass
sudo用戶密碼
ansible_connection
與主機的連接類型.比如:local, ssh ,winrm, paramiko. Ansible 1.3 以前默認使用 paramiko.1.3 以后默認使用 'smart','smart' 方式會根據是否支持 ControlPersist, 來判斷'ssh' 方式是否可行.從Ansible 1.3 版本開始, Ansible 默認使用Open SSH實現各服務器間通信
ansible_ssh_private_key_file
ssh 使用的私鑰文件.適用於有多個密鑰,而你不想使用 SSH 代理的情況.
ansible_shell_type
目標系統的shell類型.默認情況下,命令的執行使用 'bash' 語法,可設置為 'csh' 或 'fish'.
ansible_python_interpreter
目標主機的 python 路徑.適用於的情況: 系統中有多個 Python, 或者命令路徑不是"/usr/bin/python",比如 \*BSD, 或者 /usr/bin/python
不是 2.X 版本的 Python.我們不使用 "/usr/bin/env" 機制,因為這要求遠程用戶的路徑設置正確,且要求 "python" 可執行程序名不可為 python以外的名字(實際有可能名為python26).
與 ansible_python_interpreter 的工作方式相同,可設定如 ruby 或 perl 的路徑
多個inventory列表
配置支持多個inventory
首先需要修改ansible.cfg中inventory 的定義改成一個目錄
inventory = /etc/ansible/inventory #/etc/ansible/inventory 是一個目錄
然后我們在目錄里面放入多個hosts文件
[root@ceshi2 ansible]# tree inventory
inventory
├── docker
└── kvm
cat docker
[docker]
172.16.1.11
172.16.1.12
#172.11.11.11 # ansible_ssh_pass='123456'
[docker:vars]
ansible_ssh_pass='123456'
cat kvm
[kvm]
172.16.1.13
172.16.1.14
ansible all -i /etc/ansible/inventory -a 'uptime' # -i可以指定目錄
動態inventory
動態inventory的意思是所有的變量可以從外部獲取,也就是說我們可以從CMDB以及zabbix系統拉取所有的主機信息然后使用ansible進行管理。
引用inventory只需要把ansible.cfg文件中的inventory定義值改成一個執行腳本即可。
inventory = /etc/ansible/inventory.py #/etc/ansible/inventory.py 是一個py文件
#!/usr/bin/env python # -*- coding:utf-8 -*- # @Author : huazai # @Time : 2017/11/27 14:11 # @File : inventory.py # @Description : import json host1ip = ['192.168.1.15'] host2ip = ['192.168.1.110'] group = 'test11' # 給一個組名 group2 = 'test22' hostdata = {group:{"hosts":host1ip},group2:{"hosts":host2ip}} print json.dumps(hostdata,indent=4)
ansible -i inventory.py test11 -a 'uptime' -k
SSH password:
192.168.1.15 | SUCCESS | rc=0 >>
07:25:27 up 3:56, 3 users, load average: 0.00, 0.00, 0.00
192.168.1.110 | SUCCESS | rc=0 >>
07:25:27 up 7 min, 3 users, load average: 0.00, 0.02, 0.00
按照Ansible 的約定,我們需要寫一個動態腳本來獲取服務器的列表。這個腳本必須支持 --list 選項和--host 選項。
--list 選項以json 的格式返回以組名為key ,服務器列表為value 的數據。
--host 返回一個字典,該字典中包含了這個服務器的詳細信息。
python hosts.py --list { "webservers":[ "foo.example.com", "bar.example.com" ], "dbservers ": [ "one.example.com", "two.example.com", "three.example.com" ] } python hosts.py --host=foo.example.com { "ansible_user":"lmx", "ansible_port":2099 }
表結構
mysql > show create table hosts\G Create Table: CREATE TABLE 'hosts'( `id`int(11) NOT NULL AUTO_INCREMENT, `host` varchar(15) DEFAULT NULL , `groupname` varchar(15) DEFAULT NULL , `username` varchar(15) DEFAULT NULL , `port` int(11) DEFAULT '22', PRIMARY KEY ('id') ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 id 是表的主鍵, host 是服務器的ip 地址或主機名稱 groupname 是Ansible 中的組名 username SSH 連接的用戶名 port SSH 連接的端口號
hosts.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # @Author : huazai # @Time : 2018/5/31 9:47 # @File : dd.py # @Description : from __future__ import print_function import argparse import json from collections import defaultdict from contextlib import contextmanager import pymysql def to_json(in_dict): return json.dumps(in_dict,sort_keys=True,indent=2) @contextmanager def get_conn(**kwargs): conn=pymysql.connect(**kwargs) try: yield conn #關鍵是yield 和contextmanager finally: conn.close() def parse_args(): parse=argparse.ArgumentParser(description='openstack inventory module') group=parse.add_mutually_exclusive_group(required=True) group.add_argument('--list',action='store_true',help='list active servers') group.add_argument('--host',help='list details about the specific host') return parse.parse_args() def list_all_hosts(conn): hosts=defaultdict(list) with conn as cur: #上下文管理 cur.execute('select * from hosts') rows=cur.fetchall() for row in rows: no,host,group,user,port = row hosts[group].append(host) return hosts def get_host_detail(conn,host): details = {} with conn as cur: cur.execute("select * from hosts where host='{0}'".format(host)) rows = cur.fetchall() if rows: no,host,group,user,port=rows[0] details.update(ansible_user=user,ansible_port=port) return details def main(): parser=parse_args() with get_conn(host='127.0.0.1',user='abc',passwd='abc',db='test') as conn: if parser.list: hosts=list_all_hosts(conn) print(to_json(hosts)) else: details = get_host_detail(conn,parser.host) print (to_json(details)) if __name__=='__main__': main()
ansible test -i hosts.py -m ping
主機分組切片
- command: /opt/application/migrate_db.py
when: inventory_hostname == webservers[0]
playbook劇本
playbook選項
https://github.com/lorin/ansible-quickref
注意:
yaml文件里 等於號 等價於 冒號, mode=600 等價於 mode: 600
playbook劇本主要三部分
1、在什么機器以什么身份執行,hosts,users,sudo,sudo_user
2、執行的任務是什么,tasks
3、善后的任務有什么,handlers
YAML語法
1、文件開始符
---
2、數組list,橫線后面有空格
- element1
- element2
- element3
3、字典 hash or dictionary,冒號后面有空格
key: value
4、復雜的字典
字典嵌套
languages:
ruby: Elite
python: Elite
dotnet: Lame
字典和數組的嵌套
- languages:
ruby: Elite
python: Elite
dotnet:
- lisp
- fortran
- erlang
5、注意
變量里有冒號:時要加引號
foo: "somebody i a colon here: so i did"
變量以為"{"開頭時要加引號
foo: "{{ variable }}"
YAML 的語法規則如下
---:聲明這是一個yaml文件,非必須
YAML 中的字段大小寫敏感
YAML 與Python 一樣,使用縮進表示層級關系
YAML 的縮進不允許使用Tab 鍵,只允許使用空格,且空格的數目不重要,只要相同層級的元素左側對齊即可
"#"表示注釋,從這個字符一直到行尾都會被解析器忽略
hosts:被控主機ip,或主機組,或all
remote_user:以某個用戶身份執行
vars:變量
tasks:playbook核心,定義順序執行的動作action,每個action調用一個ansible模塊
action語法
name:每個action最好有name屬性,這是供人類讀的,寫name是個好習慣,playbook執行時會顯示對應的name
module:module_parameter=module_value
handers:playbook的event處理操作,有且僅有在action觸發時才會執行,但多次觸發只執行一次,並按照聲明順序執行
參數:傳入到模塊執行的參數,比如,copy模塊需要src,dest,owner,group,mode等參數
YAML 支持三種格式的數據,分別是:
對象:鍵值對的集合,又稱為映射,類似於Python 中的字典
數組: 一組按次序排列的值,又稱為序列(sequence), 類似於Python 中的列表
純量(scalars): 單個的、不可再分的值,如字符串、布爾值與數字
安裝PyYAML模塊
pip install PyYAML
#讀取yaml文件 import yaml with open('data.yaml') as f: print (yaml.load(f)) ['Apple','Orange','Strawberry','Mango']
YAML 中可以使用多種方式指定布爾值。例如,下面的YAML 格式都是合法的:
create_key: yes
needs_agent:no
needs_agent:NO
knows_oop: True
likes_emacs: TRUE
uses_cvs: false
轉換為Python 代碼以后,對變量的取值進行了格式化
{'create_key': True ,
'know_oop': True,
'likes_emacs': True ,
'needs_agent': False,
'uses_cvs': False}
注意:當playbook使用vars.yml外部變量文件的時候,變量文件里面的yes、no要加單引號否則會當成布爾值
cat vars.yml --- redis_settings: appendonly: 'no' #no和yes需要使用加單引號的字符串,否則會當成布爾值
雙引號引用字符串
如果字符串中包含特殊字符,需要使用雙引號包含起來。
例如,下面的例子中,字符串包含冒號
冒號對於YAML 來說是一個特殊字符,因此,需要使用雙引號包含起來。
foo: "somebody said I should put a colon here: so I did"
如果字符串的內容比較長,可以使用">"來折疊換行。也就是說,接下來縮進的內容都是這個字符串的一部分。
that: >
Foo
Bar
針對每一組主機的一個action組成一個play,一般一個playbook中只包含一個play
tasks中每個action都是對模塊的調用,在每個action中
冒號前是模塊的名字
冒號后是模塊的參數
web.yml
- hosts: test \\主機組,在/etc/ansible/hosts定義
remote_user: root \\遠端執行任務的用戶
tasks: \\任務
-name: install httpd \\任務描述
command: yum -y install httpd \\調用ansible的command模塊安裝httpd
-name: provide httpd.conf \\任務描述
copy:src="/root/httpd.conf" dest="/etc/httpd/conf/httpd.conf" \\調用ansible的copy模塊,httpd安裝完成后將事先准備好的httpd.conf文件復制到/etc/httpd/conf目錄下
tags: conf \\給此任務打標記,可單獨執行標記的任務
notify: \\文件內容變更通知
- server restart \\通知到指定的任務
- name: server start \\任務描述
service: name=httpd state=started enabled=true \\調用ansible的service模塊的屬性定義安裝完成httpd以后httpd服務的管理
handlers: \\定義接受關注的資源變化后執行的動作
- name: server restart \\任務描述
service: name=httpd state=restarted \\當關注的資源發生變化后調用service模塊,采取的響應的動作
例子 heartbeat.yaml - hosts: hbhosts remote_user: root tasks: - name: ensure heartbeat latest version yum: name=heartbeat state=present - name: authkeys configure file copy: src=/root/hb_conf/authkeys dest=/etc/ha.d/authkeys - name: authkeys mode 600 file: path=/etc/ha.d/authkeys mode=600 notify: - restart heartbeat - name: ha.cf configure file copy: src=/root/hb_conf/ha.cf dest=/etc/ha.d/ha.cf notify: - restart heartbeat handlers: - name: restart heartbeat service: name=heartbeat state=restarted
或
例子 heartbeat.yaml --- - hosts: hbhosts remote_user: root become: yes become_method: sudo tasks: - name: ensure heartbeat latest version yum: name=heartbeat state=present - name: authkeys configure file copy: src=/root/hb_conf/authkeys dest=/etc/ha.d/authkeys - name: authkeys mode 600 file: path=/etc/ha.d/authkeys mode=600 notify: - restart heartbeat - name: ha.cf configure file copy: src=/root/hb_conf/ha.cf dest=/etc/ha.d/ha.cf notify: - restart heartbeat handlers: - name: restart heartbeat service: name=heartbeat state=restarted
參數的寫法
key=value file: path=/etc/ha.d/authkeys mode=600 owner=root 或
多行 file: path=/etc/ha.d/authkeys mode=600 owner=root 或
yaml字典格式 file: path: /etc/ha.d/authkeys mode: 600 owner: root
handler
每個編程語言都有event機制,handler就是playbook的event
handlers里面每個handler都是對模塊的一次調用
只有在action的狀態為changed時才會執行該action的handler
testhandler.yaml - hosts: lb remote_user: root vars: random_number: "{{ 1000 | random }}" tasks: - name: copy the /etc/hosts to /tmp/hosts.{{ 1000 | random }} copy: src=/etc/hosts dest=/tmp/hosts.{{ 1000 | random }} notify: #因為文件名是隨機數,源和目標永遠都不一樣,所以永遠都會執行這個handler - call by /tmp/hosts.random_number - name: copy the /etc/hosts to /tmp/hosts copy: src=/etc/hosts dest=/tmp/hosts notify: - call by /tmp/hosts handlers: - name: call by /tmp/hosts debug: msg="call by /tmp/hosts" - name: call by /tmp/hosts.random_number debug: msg="call by /tmp/hosts.random_number"
notify里的名字跟handlers里的name一一對應
call by /tmp/hosts -》call by /tmp/hosts
call by /tmp/hosts.random_number -》 call by /tmp/hosts.random_number
handler按一定順序執行,即使call by /tmp/hosts.random_number先觸發,handler依然先執行call by /tmp/hosts
handler 只會在所有task 執行完后執行。並且,即便一個handler 被觸發多次,它也只會執行一次。handler 並不是在被觸發時立即執行,而是按照action中定義的順序執行。
一般情況下, handler 都位於action的最后,即在所有任務執行完成以后再執行。
Ansible 官方文檔提到handler 的唯一用途,就是重啟服務與服務器
serial選項
串行執行,serial指定串行值
無論webservers 組中有多少服務器,無論--forks 選項取值為多少, 一次只更新一台服務器,更新完成以后再更新下一台服務器
- name: test play
hosts: webservers
serial: 1
local_action選項
使用local_action只在主控機執行操作
tasks: - name: take out of load balancer pool local_action: command /usr/bin/take_out_of_pool {{inventory_hostname}}
playbook變量
1、用戶自定義變量,vars, vars_files ,vars_prompt,這些變量都可以用在jinja2文件里
2、來自遠程主機收集到的facts變量
3、內置系統變量,template模塊
4、把action結果傳入變量,叫注冊變量
5、在執行playbook時傳入變量,叫額外變量
變量名約束
變量名稱應為字母,數字和下划線。
變量應始終以字母開頭。
變量名不應與python屬性和方法名沖突。
變量作用域
global全局作用域: 設置在config, 環境變量, 和命令行中的變量
play: 作用於play和包含的structure, 變量, role中的default和vars
host: inventory, facts和register產生的變量, 只作用於某個host
變量優先級(從低到高)
role defaults
inventory vars
inventory group_vars
inventory host_vars
playbook group_vars
playbook host_vars
host facts
play vars
play vars_prompt
play vars_files
registered vars
set_facts
role and include vars
block vars (only for tasks in block)
task vars (only for the task)
extra vars (always win precedence)
用戶自定義變量
vars關鍵字自定義變量,使用{{}}引用起來
cat a.yml --- - hosts: test gather_facts: False vars: var1: haha var2: your name is tasks: - debug: msg="{{var2}} {{var1}}" cat b.yml --- - hosts : test gather_facts: False vars_files: - /tmp/var_file1.yml #建議用絕對路徑 tasks: - debug: msg="{{var1}}" var_file1.yml 里的內容: var1: hello Han××× cat b.yml --- - hosts: client_105 gather_facts: False vars_prompt: - name: 'client_105_key' prompt: 'Input key' #交互時提示信息 private: no #輸入數據是否顯示 tasks: - name: print 105_key debug: msg="{{ client_105_key }}"
facts變量
ansible通過setup模塊收集主機信息,這些主機信息叫facts
每個playbook執行前都會默認執行setup模塊,所以這些facts信息可以直接以變量形式使用
setup 模塊收集到的信息,是 json 格式
說明:通常facts數據的頂級key為ansible_facts,在引用時應該將其包含在變量表達式中。
但自動收集的facts比較特殊,它以ansible_facts作為key,ansible每次收集后會自動將其注冊為變量,
所以facts中的數據都可以直接通過變量引用,甚至連頂級key ansible_facts都要省略。
cat a.yml --- - hosts: test tasks: - debug: msg="{{ansible_all_ipv4_addresses}} {{ansible_os_family}}"
搜集facts信息會額外消耗時間,如果不需要facts信息,在playbook中通過關鍵字
gather_facts來控制是否收集
cat a.yml --- - hosts: test gather_facts: no
內置系統變量,template模塊
在playbook中定義的變量,可以直接在template中使用,同時facts變量也可以直接在template中使用
當然也包含在inventory里面定義的host和group變量。只要是在playbook中可以訪問的變量,都可以在template文件中使用。
下面使用template模塊復制文件index.html.j2,並且替換index.html.j2中的變量
facts變量 {{ ansible_hostname }} {{ ansible_default_ipv4.address }} 用戶自定義的變量 {{ defined_name }} index.html.j2文件 <html> <title>Demo</title> <body> <div class="block" style="height: 99%;"> <div class="centered"> <h1>#46 Demo \{\{ defined_name \}\}</h1> <p>Served by \{\{ ansible_hostname \}\} (\{\{ ansible_default_ipv4.address \}\}).</p> </div> </div> </body> </html>
a.yml
cat a.yml --- - hosts : web vars: defined_name: "hello lin" tasks: - name: write the default index.html file template: src=/tmp/index2.html.j2 dest=/var/www/html/index.html
注冊變量
register關鍵字,多個action之間傳遞變量,上一個action結果傳遞到下個action
cat a.yml --- - hosts : test tasks: - shell : ls /tmp/ register: result ignore_errors: True - debug: msg="{{result.stdout}}" 說明: 執行shell 模塊后,返回信息是 json 格式的。再通過 register 注冊到 result 變量。 然后,通過 debug 模塊,輸出 result 變量的stdout的值。
額外變量
第一種情況:hosts和user必須從命令行傳入值,如果在命令行中不傳入值則playbook報錯
第二種情況:var1可以從命令行傳入值,如果在命令行傳入值則會覆蓋playbook里面var1定義值(變量優先級)
第一種情況 cat a.yml --- - hosts : "{{hosts}}" remote_user: "{{user}}" gather_facts: False tasks: - debug: msg="{{var1}}" 第二種情況 cat a.yml --- - hosts : web gather_facts: False vars: var1: "AAA" tasks: - debug: msg="{{var1}}"
命令行傳入變量值三種方式
普通方式傳入
ansible-playbook a.yml -e 'hosts=web user=root'
json方式傳入
ansible-playbook a.yml -e '{'hosts':'web','user':'root'}'
外部文件方式傳入
ansible-playbook a.yml -e '@/tmp/vars.json'
playbook引用json格式變量
facts變量或者register返回的變量都是json格式
在playbook里面引用json格式變量,有三種方法
例子
注冊變量返回的結果是json格式
- shell : ls /tmp/ register: result - debug: msg="{{result}}" TASK [debug] ************************************************** ok: [192.168.188.109] => { "msg": { "changed": true, "cmd": "echo hello world", "delta": "0:00:00.001890", "end": "2018-01-18 17:12:00.178123", "failed": false, "rc": 0, "start": "2018-01-18 17:12:00.176233", "stderr": "", "stderr_lines": [], "stdout": "hello world", "stdout_lines": [ "hello world" ] } }
1、點號
- debug: msg="{{result.stdout}} "
2、中括號
- debug: msg="{{result['stdout']}} "
3、訪問json里面的列表
- debug: msg="{{result['stdout_lines'][0]}} "
playbook邏輯控制語句
when:條件判斷語句
loop:循環語句,vars插件和lookup插件提供
block:把幾個action組成一個代碼塊,便於針對一組操作異常進行處理
注意:{{ item }}這個變量名是ansible內置的,不能變
when語句
遠程主機是debian就立刻關機
tasks: - name: "shutdown debian systems" command: /sbin/shutdown -t now when: ansible_os_family == "Debian"
判斷真假
vars: epic: true tasks: - shell: echo "HELLO" when: epic 或 when: not epic
判斷變量是否已經定義了
tasks: - shell: echo "HELLO {{ foo }}" when: foo is defined tasks: - shell: echo "not defined foo" when: foo is not defined
使用and ,or進行判斷
tasks: - shell: echo "HELLO {{ foo }}" when: foo is defined tasks: - shell: echo "not defined foo" when: (foo is not defined) or (ansible_distribution=="Debian")
loop語句
with_lines
with_fileglob
with_first_found
with_diet
with_flattened
with_indexed_items
with_nested
with_random_choice
with_sequence
with_together
with_subelements
with_file
列表循環
- name: add users user: name={{item}} state=present groups=wheel with_items: - testuser1 - testuser2 vars: somelist: ['testuser1','testuser2'] tasks: - name: add users user: name={{item}} state=present groups=wheel with_items: "{{somelist}}"
#如果列表里面的hash類型 - name: add users user: name={{ item.name }} state=present groups={{ item.groups }} with_items: - { name : 'testuser1',groups : 'wheel'} - { name : 'testuser2',groups : 'vsftp'}
#如果某個選項大於3就打印 vars: item: [1,2,3,4,5,6,7] tasks: - name: add users command: echo {{item}} with_items: item when: item > 3
嵌套循環
- name: give users access to multiple databases mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo with_nested: - [ 'alice', 'bob' ] - [ 'clientdb','employeedb','providerd' ]
哈希循環
--- - hosts: all gather_facts: False vars: user: Bob_hou: name: Bob_Hou shell: bash Jmilk: name: Jmilk shell: zsh tasks: - name: debug loops debug: "msg=\"name -----> {{item.key }} value -----> {{item.value.name }} shell -----> {{ item.value.shell }}\"" with_dict: "{{ user }}"
文件循環
--- - hosts: all gather_facts: False tasks: - name: debug loops debug: "msg=\"files -----> {{ item }}\"" with_fileglob: - /root/playbook/*.yaml
條件判斷循環,until\retries\delay
--- - hosts: all gather_facts: False tasks: - name: debug loops shell: cat /root/ansible register: host until: host.stdout.startswith("cat") retries: 5 delay: 5
序列循環
類似於Python 中的range 函數。
在使用with_sequence 時,我們可以指定起點、終點和步長。
# create some test users - user: name:"{{item}}" state: present groups: "events" with_sequence: start=0 end=32 format=testuser%02x
register循環,接受多個task的結果
這個是jinja2的語法:{% for i in ret.results %}
--- - hosts: all gather_facts: True tasks: - name: debug loops shell: "{{ item }}" with_items: - hostname - uname register: ret - name: display loops debug: "msg=\"{% for i in ret.results %} {{ i.stdout }} {% endfor %}\""
標簽
標簽tags執行部分action,tags可以和一個play(就是很多個task)或者一個task進行捆綁
ansible-playbook提供了“--skip-tags”和“--tags” 來指明是跳過特定的tags還是執行特定的tags。
always
tagged
untagged
all
- hosts: test-agent tasks: - command: echo test1 tags: - test1 - command: echo test2 tags: - test2 - command: echo test3 tags: - test3
當執行 ansible-playbook test1.yml --tags="test1,test3" ,則只會執行 test1和test3的echo命令
當執行 ansible-playbook test1.yml --skip-tags="test2" ,同樣只會執行 test1和test3的echo命令
- hosts: test-agent1 tags: - play1 tasks: - command: echo This is - command: echo agent1 - hosts: test-agent2 tags: - play2 tasks: - command: echo This is - command: echo agent2 - hosts: test-agent3 tags: - play3 tasks: - command: echo This is - command: echo agent3
當執行 ansible-playbook test2.yml --tags="play1,play3" ,則只會執行 play1和play3的tasks。
當執行 ansible-playbook test2.yml --skip-tags="play2" ,同樣只會執行 test1和test3的tasks。
always標簽
即使只執行某個標簽,always標簽也會被執行
tasks: - debug: msg="always print this debug message" tags: - always - yum: name{{item}} state=installed with_items: - httpd tags: - packages
ansible-playbook test_always.yml --tags="packages"
tasks: - yum: name{{item}} state=installed with_items: - httpd tags: - tagged
ansible-playbook test_always.yml --tags tagged
執行所有標記了標簽的任務
tasks: - yum: name{{item}} state=installed with_items: - httpd tags: - tagged ansible-playbook test_always.yml --tags untagged
執行所有沒有標記標簽的任務
tasks: - yum: name{{item}} state=installed with_items: - httpd tags: - tagged
ansible-playbook test_always.yml --tags all
不管有無標記標簽都執行所有任務
include語句使用標簽
- included: foo.yml
tags: [web,foo]
role使用標簽
roles: - { role: webserver,port: 5000 tags: ['web','foo']}
插件
插件是對ansible功能的補充,在ansible的配置文件中,每種類型的插件都有自己的配置變量
因此放置的目錄並不相同
插件類型
#action_plugins = /usr/share/ansible/plugins/action
#cache_plugins = /usr/share/ansible/plugins/cache
#callback_plugins = /usr/share/ansible/plugins/callback
#connection_plugins = /usr/share/ansible/plugins/connection
#lookup_plugins = /usr/share/ansible/plugins/lookup
#inventory_plugins = /usr/share/ansible/plugins/inventory
#vars_plugins = /usr/share/ansible/plugins/vars
#filter_plugins = /usr/share/ansible/plugins/filter
#test_plugins = /usr/share/ansible/plugins/test
#terminal_plugins = /usr/share/ansible/plugins/terminal
#strategy_plugins = /usr/share/ansible/plugins/strategy
#inventory_plugins = /usr/share/ansible/plugins/inventory
#enable_plugins = host_list, virtualbox, yaml, constructed
action插件
和模塊使用方法類似,只不過執行目標不是遠程主機,而是在ansible的控制節點上
cache插件
為facts提供緩存,以避免多次執行playbook時搜集facts上有過多開銷
callback插件
執行playbook后,提供額外行為,例如,將執行結果發送到email,或寫入log中
官方提供的一些callback插件
https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/callback
connection插件
ansible為管理節點和遠程節點之間提供了更多連接方法。默認的連接協議是基於paramiko的ssh協議
paramiko基本已經夠用,如果有高級需求,則可以通過自定義插件來提供snmp,message bus等傳輸協議
filters插件
過濾器提供更多功能
lookup插件
lookup功能提供更多功能
strategy插件
為執行playbook提供更多執行策略,控制play在執行時的策略,默認策略是linear
即所有遠程主機都執行完某一個任務之后,再執行下一個任務,ansible官方的strategy插件
提供了另外一個策略free,允許每個遠程主機盡快地執行到play的結尾
從ansible2.0開始,支持free策略,允許執行較快的遠程主機提前完成action部署,不用等其他遠程主機一起執行action
- hosts: all
strategy: free
task:
...
shell插件
通過shell插件提供遠程主機上更多類型的shell(csh,ksh,tcsh)
test插件
jinja2 test提供更多功能
vars插件
ansible將inventory/playbook命令行中的變量注入ansible中,通過vars插件
實現更多變量注入功能
如何使用callback 插件
timer:記錄playbook執行時間
log plays:把執行結果記錄在/var/log/ansible/hosts對應主機名文件里
1、下載 callback plugins 文件
使用callback插件,首先從官網提供的callback插件下載需要使用的插件對應的python文件
將下載的文件保存在 /usr/share/ansible/plugins/callback目錄下
2、配置 ansible.cfg
配置放置 callback 插件的 Python 文件的位置
在ansible.cfg里啟用插件
callback_plugins = /usr/share/ansible/plugins/callback
callback_whitelist = timer, log plays
3、playbook執行的時候自動會記錄timer 和 log plays
lookup 插件
1、file:獲取文件內容
---
- hosts: all
tasks:
- debug: msg="the value of foo.txt is {{ lookup('file', '/etc/foo.txt') }}"
2、password:生成密碼字符串
如果文件已存在,則不會向其寫入任何數據。 如果文件有內容,那些內容將作為密碼讀入。 空文件導致密碼以空字符串返回。
---
- hosts: all
tasks:
# 使用只有ascii字母且長度為8的隨機密碼創建一個mysql用戶:
- mysql_user: name={{ client }} password="{{ lookup('password', '/tmp/passwordfile chars=ascii_letters length=8') }}" priv={{ client }}_{{ tier }}_{{ role }}.*:ALL # 使用只有數字的隨機密碼創建一個mysql用戶: - mysql_user: name={{ client }} password="{{ lookup('password', '/tmp/passwordfile chars=digits') }}" priv={{ client }}_{{ tier }}_{{ role }}.*:ALL # 使用許多不同的字符集使用隨機密碼創建一個mysql用戶: - mysql_user: name={{ client }} password="{{ lookup('password', '/tmp/passwordfile chars=ascii_letters,digits,hexdigits,punctuation') }}" priv={{ client }}_{{ tier }}_{{ role }}.*:ALL
3、env :讀取環境變量
tasks:
- debug: msg="{{ lookup('env','HOME') }} is an environment variable"
4、pipe :讀取Linux命令執行結果
tasks:
- debug: msg="{{ lookup('pipe','date') }} is the raw result of running this command"
5、csvfile :讀取csv文件
- debug: msg="The atomic number of Lithium is {{ lookup('csvfile', 'Li file=/tmp/elements.csv delimiter=,') }}" - debug: msg="The atomic mass of Lithium is {{ lookup('csvfile', 'Li file=/tmp/elements.csv delimiter=, col=2') }}" 參數 默認值 描述 file ansible.csv 要加載的文件名稱 col 1 要輸出的列,索引從0開始 delimiter TAB 文件的分隔符 default empty string 如果key不在csv文件中,則為默認返回值 encoding utf-8 使用的CSV文件的編碼(字符集)(added in version 2.1)
6、ini :讀取ini/properties文件
在section下查找以key1 = value1的格式來讀取文件的內容。
ini 參數格式
lookup('ini', 'key [type=<properties|ini>] [section=section] [file=file.ini] [re=true] [default=<defaultvalue>]')
第一個值必須是ini文件里的key
字段 默認值 描述
type ini 文件類型。 可以是ini或properties (對於java)。
file ansible.ini 要加載的文件名稱
section global 在哪里查找key
re False 開啟正則匹配
default empty string 如果key不在文件中,則為默認返回值
users.ini
[production]
# My production information
user=robert pass=somerandompassword [integration] # My integration information user=gertrude pass=anotherpassword tasks: - debug: msg="User in integration is {{ lookup('ini', 'user section=integration file=/tmp/users.ini') }}" - debug: msg="User in production is {{ lookup('ini', 'pass section=production file=/tmp/users.ini') }}"
7、dig:dns查詢
此模塊依賴dnspython 庫
- debug: msg="The IPv4 address for example.com. is {{ lookup('dig', 'example.com.')}}" - debug: msg="The TXT record for example.org. is {{ lookup('dig', 'example.org.', 'qtype=TXT') }}" - debug: msg="The TXT record for example.org. is {{ lookup('dig', 'example.org./TXT') }}"
其他
tasks:
- debug: msg="{{ lookup('pipe','date') }} is the raw result of running this command" # redis_kv lookup requires the Python redis package - debug: msg="{{ lookup('redis_kv', 'redis://localhost:6379,somekey') }} is value in Redis for somekey" # dnstxt lookup requires the Python dnspython package - debug: msg="{{ lookup('dnstxt', 'example.com') }} is a DNS TXT record for example.com" - debug: msg="{{ lookup('template', './some_template.j2') }} is a value from evaluation of this template" # loading a json file from a template as a string - debug: msg="{{ lookup('template', './some_json.json.j2', convert_data=False) }} is a value from evaluation of this template" - debug: msg="{{ lookup('etcd', 'foo') }} is a value from a locally running etcd" # shelvefile lookup retrieves a string value corresponding to a key inside a Python shelve file - debug: msg="{{ lookup('shelvefile', 'file=path_to_some_shelve_file.db key=key_to_retrieve') }}
過濾器插件
過濾器對普通變量的操作
default:為未定義的變量提供默認值
omit:與default一起使用,忽略變量的占位符,ansible會按照沒有傳這個參數的值來處理
{{ result.cmd|default(5) }}
result.cmd 如果沒有定義的話,則其默認值為5
- name: touch files with an optional mode
file: dest={{item.path}} state=touch mode={{item.mode|default(omit)}} with_items: - path: /tmp/foo - path: /tmp/bar - path: /tmp/baz mode: "0444"
對於列表中的前兩個文件,默認mode將由系統的umask確定,因為mode=parameter 不會發送到文件模塊,而最后的文件將接收mode=0444選項
default(omit)在沒有定義mode時忽略mode變量
mandatory:強制定義變量,否則報錯
如果變量未定義,則來自ansible和ansible.cfg的默認行為失敗,但您可以將其關閉。
默認ansible.cfg中的error_on_undefined_vars=True
---
- hosts: localhost
remote_user: root
tasks:
- debug: msg="{{ variable | mandatory }}"
int:將變量變為整型
vars:
string_value: "6" tasks: - name: "yes" debug: msg='YES' when: string_value | int > 5
bool:判斷變量是否為布爾類型
- debug: msg=test
when: some_string_value | bool
ternary:類似於編程語言中的(A?B:C)
vars:
name: "John" tasks: - name: "true of false take different value" debug: msg="{{ ('name' == 'John') | ternary('Mr','Ms') }}"
過濾器對文件路徑的操作
Linux
獲取路徑的文件名:{{ path | basename }}
獲取路徑中的目錄:{{ path | dirname }}
擴展為實際的目錄:{{ path | expanduser }}
獲取軟連接的真實路徑:{{ path | realpath }}
獲取文件名的名稱和擴展名:{{ path | splitext }}
windows
獲取路徑的文件名:{{ path | win_basename }}
獲取路徑的目錄名:{{ path | win_dirname }}
分割成多個部分:{{ path | win_splitdrive }}
分割成多個部分驅動器部分:{{ path | win_splitdrive | first }}
分割成多個部分文件名部分:{{ path | win_splitdrive | last }}
過濾器對字符串變量的操作
caplitalize:為字符串首字母大寫
vars:
string_value: "john" tasks: - name: "cap" shell: echo {{ string_value | caplitalize }}
quote:為字符串增加雙引號
vars:
string_value: "John" tasks: - name: "quote" shell: echo {{ string_value | quote }}
hash:獲取字符串得hash值
tasks:
- name: "hash" shell: echo {{ 'test1'|hash('sha1') }} shell: echo {{ 'test1'|hash('md5') }}
comment:注釋
支持各種語言的注釋
{{ "this is the comment" | comment }}
{{ "this is the comment" | comment('c') }} {{ "this is the comment" | comment('cblock') }} {{ "this is the comment" | comment('erlang') }} {{ "this is the comment" | commen('xml')t }} {{ "this is the comment" | comment('plain', prefix='#######\n#', postfix='#\n#######\n ###\n #') }}
regex_replace:用正則表示對字符串進行替換
# convert "ansible" to "able"
{{ 'ansible' | regex_replace('^a.*i(.*)$', 'a\\1') }} # convert "foobar" to "bar" {{ 'foobar' | regex_replace('^f.*o(.*)$', '\\1') }} # convert "localhost:80" to "localhost, 80" using named groups {{ 'localhost:80' | regex_replace('^(?P<host>.+):(?P<port>\\d+)$', '\\g<host>, \\g<port>') }}
ip:字符串ip地址轉換
vars:
myvar: "192.168.3.6" myvar6: "fe80:dcfd:1e54:728d:a99e" CIDR: "192.0.2.1/24'" tasks: - name: "check ip" debug: msg={{ myvar | ipaddr }} debug: msg={{ myvar | ipv4 }} debug: msg={{ myvar6 | ipv6 }} debug: msg={{ CIDR | ipaddr('address') }}
to_datetime:字符串轉換為時間戳
tasks:
- name: "datetime filter" debug: msg={{ "2016-06-06 20:00:12" | to_datetime }}
過濾器對json的操作
format:將變量值按照json/yaml輸出
更改數據格式,其結果是字符串
{{ some_variable | to_json }}
{{ some_variable | to_yaml }} 對於人類可讀的輸出 {{ some_variable | to_nice_json }} {{ some_variable | to_nice_yaml }}
合並兩個json對象
tasks:
- name: "combine" debug: msg={{ {'a':1,'b':2}| combine({'b':3}) }}
過濾器對數據結構的操作
數據結構:list、set
random:取隨機數
從列表中隨機獲取元素
{{ ['a','b','c','d','e','f']|random }}
從0-59 的整數中隨機獲取一個數
{{ 59 |random}}
從0-100 中隨機獲取能被10 整除的數(可以理解為0 10 20 30 40 50 ...100 的隨機數)
{{ 100 |random(step=10) }}
從0-100 中隨機獲取1 開始步長為10 的數(可以理解為1 11 21 31 41...91 的隨機數)
{{ 100 |random(1, 10) }}
{{ 100 |random(start=1, step=10) }}
取最小的值
{{ [3, 4, 2] | min }}
取最大的值
{{ [3, 4, 2] | max }}
列表轉換字符
{{ [3, 4, 2] | join(" ") }}
對列表唯一過濾
{{ [3, 4, 2] | unique }}
過濾器測試功能
測試字符串
when: ansible_os_family | match("Red[Hh]at" )
when: url | search("/users/.*/resources/.*")
版本比較
檢查ansible_distribution_version版本是否大於或等於'12 .04',條件成立返回True。
{{ ansible_distribution_version | version_compare('12.04', '>=') }} 進行嚴格的版本檢查 {{ sample_version_var | version_compare('1.0', operator='lt', strict=True) }}
測試list的包含關系
vars:
a: [1,2,3,4,5] b: [2,3] tasks: - debug: msg="A includes B" when: a|issuperset(b) - debug: msg="B is included in A" when: b|issubset(a)
測試文件路徑
- debug: msg="path is a directory"
when: mypath|is_dir - debug: msg="path is a file" when: mypath|is_file - debug: msg="path is a symlink" when: mypath|is_link - debug: msg="path already exists" when: mypath|exists - debug: msg="path is {{ (mypath|is_abs)|ternary('absolute','relative')}}" - debug: msg="path is the same file as path2" when: mypath|samefile(path2) - debug: msg="path is a mount" when: mypath|ismount
測試任務執行結果
tasks:
- shell: /usr/bin/foo register: result ignore_errors: True - debug: msg="it failed" when: result|failed - debug: msg="it changed" when: result|changed - debug: msg="it succeeded in Ansible >= 2.1" when: result|succeeded - debug: msg="it succeeded" when: result|success - debug: msg="it was skipped" when: result|skipped
變量可以通過過濾器修改。過濾器與變量用管道符號( | )分割,並且也可以用圓括號傳遞可選參數。
多個過濾器可以鏈式調用,前一個過濾器的輸出會被作為 后一個過濾器的輸入
vars:
string_value: "steven"
tasks:
- name: "quote"
shell: echo {{ string_value | | caplitalize|quote |hash('md5') }}
jinja2 模版語法
讀取json格式變量
下面2種方式效果是一樣的,如果變量或屬性不存在,會返回一個未定義值。
{{ foo.bar }} {{ foo['bar'] }}
注釋
要注釋模板中一行,默認使用 {# ... #} 注釋語法。
轉義
簡單的使用單引號進行轉義
對於較大的段落,使用raw進行轉義
{% raw %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endraw %}
包含 > 、 < 、 & 或 " 字符的變量,必須要手動轉義
{{ user.username|e }}
控制結構
控制結構指的是所有的那些可以控制程序流的東西 —— 條件(比如 if/elif/ekse )、 for 循環、以及宏和塊之類的東西。控制結構在默認語法中以 {% .. %} 塊的形式出現。
for語句
遍歷序列
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
在模板中如何遍歷某一組內的所有主機? {% for host in groups['db_servers'] %} {{ host }} {% endfor %} 獲取ip地址 {% for host in groups['db_servers'] %} {{ hostvars[host]['ansible_eth0']['ipv4']['address'] }} {% endfor %}
獲取組中第一個主機的ip地址 {{ hostvars[groups['webservers'][0]]['ansible_eth0']['ipv4']['address'] }}
迭代字典
{% for key, value in my_dict.iteritems() %}
<dt>{{ key|e }}</dt>
<dd>{{ value|e }}</dd>
{% endfor %}
循環 10 次迭代之后會終止處理,注:使用break, 需要開啟輪詢控制. 具體是在ansible.cfg的jinja2_extensions變量加上jinja2.ext.loopcontrols.
{% for user in users %}
{%- if loop.index >= 10 %}{% break %}{% endif %}
{%- endfor %}
{% for user in users if loop.index <= 10 %}
{{ loop.index }}
{%- endfor %}
在一個 for 循環塊中你可以訪問這些特殊的變量
loop.index 當前循環迭代的次數(從 1 開始)
loop.index0 當前循環迭代的次數(從 0 開始)
loop.revindex 到循環結束需要迭代的次數(從 1 開始)
loop.revindex0 到循環結束需要迭代的次數(從 0 開始)
loop.first 如果是第一次迭代,為 True 。
loop.last 如果是最后一次迭代,為 True 。
loop.length 序列中的項目數。
loop.cycle 在一串序列間期取值的輔助函數。
if 語句
Jinja 中的 if 語句類似 Python 中的 if 語句。
{% if kenny.sick %}
Kenny is sick.
{% elif kenny.dead %}
You killed Kenny! You bastard!!!
{% else %}
Kenny looks okay --- so far
{% endif %}
過濾器
過濾器段允許你在一塊模板數據上應用常規 Jinja2 過濾器。只需要把代碼用 filter 節包裹起來
{% filter upper %}
This text becomes uppercase
{% endfilter %}
變量賦值
在代碼塊中,你也可以為變量賦值。在頂層的(塊、宏、循環之外)賦值是可導出的,即 可以從別的模板中導入。
賦值使用 set 標簽,並且可以為多個變量賦值
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}
表達式
{% ... %} 用於執行諸如 for 循環 或賦值的語句
{{ ... }} 把表達式的結果打印到模板上
if 表達式
一般的語法是
<do something> if <something is true> else <do something else>
例如
{{ '[%s]' % page.title if page.title is defined else 'undefined' }}
字面量
表達式最簡單的形式就是字面量。字面量表示諸如字符串和數值的 Python 對象。
"Hello World" 雙引號或單引號中間的一切都是字符串。無論何時你需要在模板中使用一個字 符串(比如函數調用、過濾器或只是包含或繼承一個模板的參數),它們都是 有用的。
42/42.23 直接寫下數值就可以創建整數和浮點數。如果有小數點,則為浮點數,否則為 整數。記住在 Python 里, 42 和 42.0 是不一樣的。
['list','of','objects'] 一對中括號括起來的東西是一個列表。列表用於存儲和迭代序列化的數據。
('tuple','of','values') 元組與列表類似,只是你不能修改元組。如果元組中只有一個項,你需要以逗號 結尾它。元組通常用於表示兩個或更多元素的項。更多細節見上面的例子。
{dict':'of','key':'and','value':'pairs'} Python 中的字典是一種關聯鍵和值的結構。鍵必須是唯一的,並且鍵必須只有一個 值。字典在模板中很少使用,罕用於諸如 xmlattr() 過濾器之類。
true/false true 永遠是 true ,而 false 始終是 false,true 、 false 和 none 實際上是小寫的,為了一致性(所有的 Jinja 標識符是小寫的),你應該使用小寫的版本
算術
Jinja 允許你用計算值。支持下面的 運算符
+ 把兩個對象加到一起。通常對象是素質,但是如果兩者是字符串或列表,你可以用這 種方式來銜接它們。無論如何這不是首選的連接字符串的方式!連接字符串見 ~ 運算符。 {{ 1 + 1 }} 等於 2 。
- 用第一個數減去第二個數。 {{ 3 - 2 }} 等於 1 。
/ 對兩個數做除法。返回值會是一個浮點數。 {{ 1 / 2 }} 等於 {{ 0.5 }} 。
// 對兩個數做除法,返回整數商。 {{ 20 // 7 }} 等於 2 。
% 計算整數除法的余數。 {{ 11 % 7 }} 等於 4 。
* 用右邊的數乘左邊的操作數。 {{ 2 * 2 }} 會返回 4 。也可以用於重 復一個字符串多次。 {{ ‘=’ * 80 }} 會打印 80 個等號的橫條。
** 取左操作數的右操作數次冪。 {{ 2**3 }} 會返回 8 。
比較
== 比較兩個對象是否相等。
!= 比較兩個對象是否不等。
> 如果左邊大於右邊,返回 true 。
>= 如果左邊大於等於右邊,返回 true 。
< 如果左邊小於右邊,返回 true 。
<= 如果左邊小於等於右邊,返回 true 。
邏輯
對於 if 語句,在 for 過濾或 if 表達式中,它可以用於聯合多個表達式
and 如果左操作數和右操作數同為真,返回 true 。
or 如果左操作數和右操作數有一個為真,返回 true 。
not 對一個表達式取反(見下)。
(expr) 表達式組。
is 和 in 運算符同樣支持使用中綴記法: foo is not bar 和 foo not in bar 而不是 not foois bar 和 not foo in bar 。所有的 其它表達式需要前綴記法 not (foo and bar)
其它運算符
in 運行序列/映射包含檢查。如果左操作數包含於右操作數,返回 true 。比如 {{ 1 in[1,2,3] }} 會返回 true 。
is 運行一個 測試 。
應用一個 過濾器 。
~ 把所有的操作數轉換為字符串,並且連接它們。 {{ "Hello " ~ name ~ "!" }} 會返回(假設 name 值為 ''John' ) Hello John! 。
() 調用一個可調用量:{{ post.render() }} 。在圓括號中,你可以像在 python 中一樣使用位置參數和關鍵字參數: {{ post.render(user, full=true) }} 。
. / [] 獲取一個對象的屬性。
role 和ansible galaxy
重用playbook
1、include語句
主要重用action,可以將多個action放在多個文件,避免playbook過於臃腫
include指令類似如下,可以像普通tasks命令一樣在playbook中混合使用
tasks:
- include: /tmp/tasks/foo.yml
cat /tmp/tasks/foo.yml --- # possibly saved as /tmp/tasks/foo.yml - name: placeholder foo command: /bin/foo - name: placeholder bar command: /bin/bar
在include中使用參數,parameterized include
tasks: - include: wordpress.yml wp_user=timmy - include: wordpress.yml wp_user=alice - include: wordpress.yml wp_user=bob 或者 --- - hosts: lb vars: wp_user: "timmy" remote_user: root tasks: - include: wordpress.yml
2、role
role類似於python的package,可以重用一組文件,形成完整功能
ansible會按照下面順序查找roles_path
1、ANSIBLE_ROLES_PATH #環境變量 2、/etc/ansible/ansible.cfg : #roles_path = /etc/ansible/roles #如果沒有設置環境變量就用配置文件里,可以設置多個路徑,用逗號隔開 3、/etc/ansible/roles #如果沒有設置環境變量也沒有配置文件里設置roles_path 那么使用默認的路徑
調整role和任務順序
pre_tasks
post_tasks
如果在執行一個role時,需要在其前或其后依然要執行某些任務,我們可以使用pre_tasks及post_tasks來聲明。
pre_tasks是在role之前執行,而post_tasks則在role之后執行
- name: deply webservers host: webservers vars_files: - secrets.yml pre_tasks: - name: update yum cache yum: update_cache=yes roles: - role: apache database_host: {{ hostvars.db.ansible_eth0.ipv4.address }} domains: - exampel.com - www.example.com post_tasks: - name: print something shell: echo "The roles have been updated!"
條件測試調用role
vim roles.yml --- - hosts:web remote_user: root roles: - role: nginx when: "ansible_distribution_major_version == '7'"
完整的role目錄結構
這里面任何一個文件都不是必須的,如果文件不存在,則跳過該文件的加載
調用:ansible-playbook -i hosts site.yml
主機清單設置group_vars目錄,分類設置各類主機的變量
group_vars:
nginx
mysql
all
├── library #目錄下存放callback二次開發,mysqldb,filter plugin等庫文件
├── simple
│ ├── defaults #文件中的變量都會被加入play,這個是默認變量,優先級比vars低
│ │ └── main.yml
│ ├── files #copy、script模塊使用這個目錄下的文件
│ ├── handlers #文件中的handlers都會被加入play
│ │ └── main.yml
│ ├── meta #文件中的所有依賴的role都會被加入play
│ │ └── main.yml
│ ├── README.md
│ ├── tasks #文件中的任務都會被加入play,role的入口文件
│ │ └── main.yml
│ ├── templates #存放jinja2模版文件,例如nginx.conf.j2
│ ├── tests
│ │ ├── inventory
│ │ └── test.yml
│ └── vars #文件中的變量都會被加入play
│ └── main.yml
├── site.yml #總入口文件
├── group_vars
│ └── nginx #主機清單的nginx組的組變量
├── hosts #主機清單
role目錄標准化


引用其他main.yml 文件
Ansible 提供了兩個關鍵字, include和include_vars ,來分別引入role 中非main.yml 其他文件包含的tasks和vars
默認

引入其他文件yaml文件

role的依賴
role 依賴關系的定義文件是x/meta/main.yml
如果role x 依賴role y ,那么在Playbook 中調用role x 之前會先調用role y。
當多個role 依賴同一個role 時, Ansible 會自動進行過濾,避免重復調用相同參數的role
第一種方法:dependencies
db 和Web 都依賴role common。如果在Playbook中調用db 和Web,
那么Ansible 會保證在 db 和Web 運行前,先運行 common ,並且只運行一次。
依賴關系中和role 的調用一樣,也是可以加入參數的,下面是加入參數的meta/main.yml 文件的例子。
在Ansible 的去重機制中,只有對個相同的role 進行參數相同的調用時,才算是重復的。
--- dependencies : - { role: common, name:"NAME IN DB"}
第二種方法:把引用的role放在最前面,先執行
site.yml roles: - common #先執行common role - db - web
ansible galaxy網站
訪問https://galaxy.ansible.com/ ,通過BROWSE ROLES 找到你需要的role 。
windows相關的role
https://galaxy.ansible.com/mrlesmithjr/windows-iis/

windows遠程管理
https://www.jianshu.com/p/4dcdf2a5cfe5
Windows Playbook示例
執行powershell腳本
- name: test script module
hosts: windows
tasks:
- name: run test script
script: files/test_script.ps1
獲取ip地址信息
- name: test raw module
hosts: windows
tasks:
- name: run ipconfig
win_command: ipconfig
register: ipconfig
- debug: var=ipconfig
使用dos命令,移動文件
- name: another raw module example
hosts: windows
tasks:
- name: Move file on remote Windows Server from one location to another
win_command: CMD /C "MOVE /Y C:\teststuff\myfile.conf C:\builds\smtp.conf"
使用powershell命令,移動文件
- name: another raw module example demonstrating powershell one liner
hosts: windows
tasks:
- name: Move file on remote Windows Server from one location to another
win_command: Powershell.exe "Move-Item C:\teststuff\myfile.conf C:\builds\smtp.conf"
https://www.jianshu.com/p/4dcdf2a5cfe5
add_host
assert
async
debug
fail
fetch
group_by
include_vars
meta
pause
raw
script
set_fact
setup
slurp
template (also: win_template)
windows模塊
http://docs.ansible.com/ansible/latest/modules/list_of_windows_modules.html
win_acl - Set file/directory/registry permissions for a system user or group
win_acl_inheritance - Change ACL inheritance
win_audit_policy_system - Used to make changes to the system wide Audit Policy.
win_audit_rule - Adds an audit rule to files, folders, or registry keys
win_certificate_store - Manages the certificate store
win_chocolatey - Manage packages using chocolatey
win_command - Executes a command on a remote Windows node
win_copy - Copies files to remote locations on windows hosts
win_defrag - Consolidate fragmented files on local volumes
win_disk_facts - Show the attached disks and disk information of the target host
win_disk_image - Manage ISO/VHD/VHDX mounts on Windows hosts
win_dns_client - Configures DNS lookup on Windows hosts
win_domain - Ensures the existence of a Windows domain.
win_domain_controller - Manage domain controller/member server state for a Windows host
win_domain_group - creates, modifies or removes domain groups
win_domain_membership - Manage domain/workgroup membership for a Windows host
win_domain_user - Manages Windows Active Directory user accounts
win_dotnet_ngen - Runs ngen to recompile DLLs after .NET updates
win_dsc - Invokes a PowerShell DSC configuration
win_environment - Modify environment variables on windows hosts
win_eventlog - Manage Windows event logs
win_eventlog_entry - Write entries to Windows event logs
win_feature - Installs and uninstalls Windows Features on Windows Server
win_file - Creates, touches or removes files or directories.
win_file_version - Get DLL or EXE file build version
win_find - Return a list of files based on specific criteria
win_firewall - Enable or disable the Windows Firewall
win_firewall_rule - Windows firewall automation
win_get_url - Fetches a file from a given URL
win_group - Add and remove local groups
win_group_membership - Manage Windows local group membership
win_hotfix - install and uninstalls Windows hotfixes
win_iis_virtualdirectory - Configures a virtual directory in IIS.
win_iis_webapplication - Configures IIS web applications
win_iis_webapppool - configures an IIS Web Application Pool
win_iis_webbinding - Configures a IIS Web site binding.
win_iis_website - Configures a IIS Web site.
win_lineinfile - Ensure a particular line is in a file, or replace an existing line using a back-referenced regular expression.
win_mapped_drive - maps a network drive for a user
win_msg - Sends a message to logged in users on Windows hosts.
win_msi - Installs and uninstalls Windows MSI files (D)
win_nssm - NSSM - the Non-Sucking Service Manager
win_owner - Set owner
win_package - Installs/uninstalls an installable package
win_pagefile - Query or change pagefile configuration
win_path - Manage Windows path environment variables
win_ping - A windows version of the classic ping module
win_power_plan - Changes the power plan of a Windows system
win_product_facts - Provides Windows product information (product id, product key)
win_psexec - Runs commands (remotely) as another (privileged) user
win_psmodule - Adds or removes a Powershell Module.
win_rabbitmq_plugin - Manage RabbitMQ plugins
win_reboot - Reboot a windows machine
win_reg_stat - returns information about a Windows registry key or property of a key
win_regedit - Add, change, or remove registry keys and values
win_region - Set the region and format settings
win_regmerge - Merges the contents of a registry file into the windows registry
win_robocopy - Synchronizes the contents of two directories using Robocopy
win_route - Add or remove a static route.
win_say - Text to speech module for Windows to speak messages and optionally play sounds
win_scheduled_task - Manage scheduled tasks
win_scheduled_task_stat - Returns information about a Windows Scheduled Task
win_security_policy - changes local security policy settings
win_service - Manage and query Windows services
win_share - Manage Windows shares
win_shell - Execute shell commands on target hosts.
win_shortcut - Manage shortcuts on Windows
win_stat - returns information about a Windows file
win_tempfile - Creates temporary files and directories.
win_template - Templates a file out to a remote server.
win_timezone - Sets Windows machine timezone
win_toast - Sends Toast windows notification to logged in users on Windows 10 or later hosts
win_unzip - Unzips compressed files and archives on the Windows node
win_updates - Download and install Windows updates
win_uri - Interacts with webservices
win_user - Manages local Windows user accounts
win_user_right - Manage Windows User Rights
win_wait_for - Waits for a condition before continuing
win_wakeonlan - Send a magic Wake-on-LAN (WoL) broadcast packet
win_webpicmd - Installs packages using Web Platform Installer command-line
win_whoami - Returns information about the current user and process
具體步驟
1、在管理機安裝pywinrm
pip install pywinrm
2、在被控機執行winrm設置腳本
checkclientenv.bat winrm set winrm/config/service/auth @{Basic="true"} winrm set winrm/config/service @{AllowUnencrypted="true"}
checkclientenv.ps1 $RootDir = Split-Path -Parent $MyInvocation.MyCommand.Definition $RootDir "" sleep 1; Write-Host -ForegroundColor Yellow "正在檢查當前數據庫服務器的環境......"; sleep 2 "" Get-WmiObject -Class Win32_OperatingSystem | Select-Object -ExpandProperty Caption | Out-Null $ComInfo =(gwmi -Class win32_operatingsystem).Caption Write-Host "當前系統版本為:$($ComInfo)"; "" #獲取當前系統的外網IP $ExternalIP = '' Try {$ExternalIP = Invoke-WebRequest http://myip.ipip.net| Select -ExpandProperty Content -ErrorAction SilentlyContinue} catch [System.Net.WebException] { Write-Host -ForegroundColor Red "當前主機無法訪問外網!!"} IF ($ExternalIP -ne '') { Write-Host -ForegroundColor Green "當前主機外網IP為$($ExternalIP)" } "" #獲取當前系統的Powershell版本 $PSVersion = $PSVersionTable.PSVersion.Major Write-Host -ForegroundColor Yellow "當前Powershell版本為$PSVersion" ##安裝Powershell更新補丁 IF ($PSVersion -lt 5) { Write-Host -ForegroundColor Yellow "當前Powershell版本需要更新,正在打開Window update功能......";sleep 3 set-Service -name wuauserv -StartupType Manual start-Service -name wuauserv Write-Host "" switch($ComInfo) { {$ComInfo.contains("2012") -and $ComInfo.contains("R2")} {wusa.exe "$RootDir\PowerShell_v5\Win8.1AndW2K12R2-KB3134758-x64.msu"} {$ComInfo.contains("2012") -and $ComInfo.notcontains("R2") } {wusa.exe "$RootDir\PowerShell_v5\W2K12-KB3134759-x64"} {$ComInfo.contains("2008") -and $ComInfo.contains("R2") } {wusa.exe "$RootDir\PowerShell_v5\Win7AndW2K8R2-KB3134760-x64"} {$ComInfo.contains("Windows 8") -or $ComInfo.contains("Windows 8.1")} {wusa.exe "$RootDir\Tools\PowerShell_v5\Win8.1-KB3134758-x86"} {$ComInfo.contains("Windows 7")} {wusa.exe "$RootDir\PowerShell_v5\Win7-KB3134760-x86.msu"} Default { -ForegroundColor Red "當前系統無法自動更新Powershell V5版本,請手動更新后再重新運行腳本!等待5秒后腳本自動退出!";sleep 5;exit} } Write-Host "補丁安裝完成后需要重啟服務器!等待5秒后腳本自動退出!";sleep 5;exit } "" #判斷WinRm服務是否啟動 $WinRMstatus = Get-Service WinRM | Where-Object {$_.Status -eq "running"} IF($WinRMstatus.count -eq 0) { Write-Host "正在開啟WinRM服務......";Enable-PSRemoting –Force } #判斷WinRM服務是否開啟監聽端口 $WinRMport = winrm e winrm/config/listener IF($WinRMport.count -eq 0) { Write-Host -NoNewline "正在開啟WinRM監聽端口......";Enable-PSRemoting –Force;Write-Host -ForegroundColor Green "OK" } Write-Host "" Write-Host "測試本機的WinRM服務是否能正常連接......" Try {Test-WsMan 127.0.0.1 -ErrorAction Stop | Out-Null} Catch [System.InvalidOperationException] { Write-Host -ForegroundColor Red "WinRM服務連接異常,請檢查相關配置,等待15秒后腳本自動退出!";sleep 15;exit} Write-Host -ForegroundColor Green "本機的WinRM服務連接正常!" "" ##添加WinRM信任列表,在客戶端添加,而不是服務端 $tr = Get-Item wsman:\localhost\client\trustedhosts | Select -Property value IF($tr.value -ne "*") { Write-Host "正在添加WinRM信任列表......" Set-Item wsman:\localhost\client\trustedhosts * -Force Restart-Service WinRM } "" Write-Host "WinRM服務連接配置完成!"; "" Write-Host -ForegroundColor Yellow "請手動允許數據庫服務器上的防火牆通過WinRM端口(允許外部網絡,默認5895)和數據庫鏡像端口(允許內部網絡,默認5022)通過!";sleep 5; "" Write-Host "當前數據庫服務器的環境完成!等待10秒后腳本自動退出!";sleep 10;exit
3、inventory 文件
[windows] 10.154.175.156 [linux] 192.168.3.9 [windows:vars] ansible_user=Administrator ansible_password=1qaz2wsx!@#123 ansible_port=5985 #winrm的端口 ansible_connection=winrm ansible_winrm_server_cert_validation=ignore
4、Windows Playbook
獲取ip地址信息 --- - hosts: windows tasks: - name: run ipconfig win_command: ipconfig register: result - name: print ipconfig debug: msg="{{ result }}"
5、執行playbook
ansible-playbook /tmp/site.yml
補充
對命令輸出的信息進行utf-8編碼,修改winrm模塊的protocol.py
sed -i "s#tdout_buffer.append(stdout)#tdout_buffer.append(stdout.decode('gbk').encode('utf-8'))#g" /usr/lib/python2.6/site-packages/winrm/protocol.py
sed -i "s#stderr_buffer.append(stderr)#stderr_buffer.append(stderr.decode('gbk').encode('utf-8'))#g" /usr/lib/python2.6/site-packages/winrm/protocol.py
ansible的優化
1、開啟SSH長連接
ansible是通過使用ssh和遠程主機進行通信,所以對ssh有這很強的依賴。在OpenSSH 5.6以后支持Multiplexing這個特性,可以通過在ansible配置中設置以支持該特性。
ansible中控機上執行一次與遠程主機的連接之后,這個連接會持久保持設定時間之久。可以通過netstat命令查看到ESTABLISHED狀態的連接信息。
如下是配置參數,設置長連接保持時間為5天;control_path指定socket文件所保存的位置。
cat /etc/ansible/ansible.cfg
ssh_args = -o ControlMaster=auto -o ControlPersist=5d
control_path = /etc/ansible/ssh-socket/ #control_path需要預先創建給寫權限
2、開啟pipelining
默認情況下,ansible的執行流程是把生成好的本地python腳本push到遠程服務器然后運行。如果開啟了pipelining,整個流程少了一個push腳本到遠程服務器的步驟,直接在SSH的會話中進行,可以提高整個執行效率。
cat /etc/ansible/ansible.cfg
pipelining = True
需要注意的是:如果開啟pipelining,需要被控的遠程服務器將/etc/sudoers中的”Defaults requiretty”注釋掉,否則會出現類似如:you must have a tty to run sudo 的報錯。
3、開啟accelerate模式
accelerate模式類似於SSH的Multiplexing功能,都是使ansible控制服務器和遠程服務器之間保持長連接。
accelerate模式是使用python程序在遠程服務器上運行一個守護進程,ansible通過這個守護進程監聽的端口進行通信。
使用accelerate模式,需要控制服務器和遠程服務器都安裝python-keyczar包
accelerate模式的開啟方法很簡單,只要在playbook中配置accelerate: true即可。
cat /etc/ansible/ansible.cfg
[accelerate]
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0
4、對facts設置優化
playbook默認第一個task是Gathering Facts收集各主機的facts信息,以方便我們在paybook中直接引用facts里的信息。
如果既想用facts信息,有希望能提高playbook的效率的話,可以采用facts緩存來實現。
facts緩存支持多種方式:json文件方式,redis方式,memcache方式等。
facts存儲不支持遠端的redis/memcache,需要在ansible的控制服務器上安裝redis/memcache;同時,還需要安裝python的redis模塊/memcache模塊
1)json文件方式
cat /etc/ansible/ansible.cfg
gathering=smart
fact_caching_timeout=86400
fact_caching=jsonfile
fact_caching_connection=/path/to/ansible_fact_cache #這是一個目錄,目錄下會生成各個機器會以機器名為文件名
2)redis方式
cat /etc/ansible/ansible.cfg
gathering=smart
fact_caching_timeout=86400
fact_caching=redis
3)memcache方式
cat /etc/ansible/ansible.cfg
gathering=smart
fact_caching_timeout=86400
fact_caching=memcached
pycharm的yaml插件
插件地址:https://github.com/vermut/intellij-ansible
安裝

設置
Editor → File Types → YAML/Ansible
添加 *.yaml 、*.yml ,提示已經關聯過yaml,yml,直接覆蓋即可



新建一個a.yml自動關聯插件


右上角顯示語法是否正確

f
