專題 - 使用 Ansible 進行快速佈署 - 善用 playbook 變數
上次更新日期 2020/11/08
雖然 playbook 很好用,但是如果每次要處理,都得要修改 playbook 主設定檔,實在很麻煩!因此, ansible 也提供可以內建變數的功能, 可以讓使用者類似修改設定檔即可,不用動到 ansible code 哩!此外,因為設定檔可能有機密資料,包括密碼資料等。因此, ansible 也內建密碼加密功能,可以提供管理者更有彈性的設計!將祕密資料分離開!同時還能自己設定密碼檔,方便自己記憶啊! 只要將密碼檔的權限設定好即可。
在 Playbook 內使用變數
變數設定向來就是重要的!不論是腳本程式還是一般傳統程式,將會變動的部份拆開到程式最上方,或者是直接獨立成為另一個設定檔, 都是很常見的技巧喔!
- 為什麼要使用變數與變數設定規則
- 有經驗的 IT 人員都知道,如果想要保持程式碼的乾淨與可重複利用,透過變數來處理是必須的!變數可以簡化很多設定的問題! 畢竟,你只要改變數內容,就能夠將整份程式碼重新跑出一個完全不同的資料!程式碼都不用改!這相當好用!
- 至於經常在 ansible 當中,用來作為變數的項目,大致上有這幾項:
- 使用者帳號名稱
- 所需要安裝/移除的軟體名稱
- 需要管理的服務名稱 (重新啟動、關閉等)
- 需要新建、移除等管理行為的檔名
- 需要從網路上面下載的檔案 (大部分可能是 url) 等
- 在 ansible 當中,變數的命名規則大致上是這樣的:
- 變數名稱開頭一定要是英文字元
- 變數名稱只能包含英文字元、數字與底線而已。
- 變數設定的位置與位階:
- 變數設定的位階主要有幾個思考方向:
- 全域設定 (global scope):變數設定在指令列或者是 ansible 設定檔內 (一般就是 ansible.cfg)
- playbook 設定 (play scope):將變數設定於 playbook 檔案內
- 主機清單檔案設定 (host scope):將變數設定在主機清單列表 (inventory) 檔案內
- 如果有相同的變數名稱被設定到不同的地方時,那麼哪一個設定值會生效呢?基本上就跟上面的順序一樣:
- 以指令列模式為主
- 再來是 playbook 當中的設定
- 最後才是 inventory 檔案內的宣告。
- 變數設定的位階主要有幾個思考方向:
- 實際進行變數的宣告-使用 playbook 裡面的 vars 以及 vars_files 的應用:
- 在 playbook 裡面設計變數,以 vars 來處理:
最簡單的方法,就是透過在 playbook 裡面加入 vars: 來規範變數名稱與內容即可。舉例來說,當你要建立一個名為 alex 的用戶, 未來可能還有不同的用戶名稱要設計,可以這樣做看看:
# 請注意必須使用正確的帳號與來到正確的目錄才行! $ whoami; pwd student /home/student/ansible-init $ cp user_add.yml var_user_add.yml $ vim var_user_add.yml --- - name: add user for managed hosts hosts: webserver1 vars: username: alex password: $6$CoZmgPgw3LD3Lyi2$6ljLHiSZm0m/luHYwYlE2VVKOSAX8O1DdzFkOHEF7gEr.. uid: 3102 tasks: - name: add username "{{username}}" user: user: "{{username}}" uid: "{{uid}}" password: "{{password}}" $ ansible-playbook --syntax-check var_user_add.yml playbook: var_user_add.yml $ ansible-playbook var_user_add.yml PLAY [add user for managed hosts] ************************************************ TASK [Gathering Facts] *********************************************************** ok: [webserver1] TASK [add username "alex"] ******************************************************* changed: [webserver1] PLAY RECAP *********************************************************************** webserver1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
幾個重點說明:
- 在 playbook 裡面,使用 vars: 來規範變數,在 var 底下則同樣使用 YAML 的語法, 設計好所需要的變數與變數值即可;
- 要應用變數時,最好使用雙引號將兩個大括號包起來的樣式來處理。
未來若需要修改使用者相關參數,直接改最上方的 vars: 底下的變數內容即可!會比較方便!
- 在 playbook 裡面設計變數,以外接 vars_files 來處理:
上面的資料中,依舊需要修改到設計的 playbook 檔案內容,如果你希望未來不要動到 playbook 主設計檔,怕被其他小夥伴搞亂時, 其實可以透過外接的設定檔!舉例來說,你將某個設定值寫入到其他設定檔,而你的 playbook 直接呼叫該檔案即可, 這樣就可以避免動到 playbook 主檔案了!
# 先將剛剛的檔案拆成兩部份,一部分還是 playbook,一部分則是完全僅變數 $ cp var_user_add.yml var_file_user_add.yml $ mkdir vars $ cp var_file_user_add.yml vars/username.yml # 修改 playbook 主檔案: $ vim var_file_user_add.yml --- - name: add user for managed hosts hosts: webserver1 vars_files: vars/username.yml tasks: - name: add username "{{username}}" user: user: "{{username}}" uid: "{{uid}}" password: "{{password}}" # 修改設定檔: $ vim vars/username.yml username: alex password: $6$CoZmgPgw3LD3Lyi2$6ljLHiSZm0m/luHYwYlE2VVKOSAX8O1DdzFkOHEF7gErUUWbvK... uid: 3102 $ ansible-playbook --syntax-check var_file_user_add.yml $ ansible-playbook var_file_user_add.yml PLAY [add user for managed hosts] ***************************************************** TASK [Gathering Facts] **************************************************************** ok: [webserver1] TASK [add username "alex"] ************************************************************ ok: [webserver1] PLAY RECAP **************************************************************************** webserver1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
同樣的,再次執行系統回報 OK,但是並不會修改到 alex 的任何資料!未來,你可以直接改 vars/username.yml 檔案內容, 然後直接執行 playbook 即可!相當容易修改!
- 在 playbook 裡面設計變數,以 vars 來處理:
- 實際進行變數的宣告-針對不同主機或主機群組,定義不同的變數值-inventory 內,或目錄設計
- 將變數直接藏在 inventory 檔案內 -- 官方不建議這樣做:
有時候,你可能會針對不同的主機給予不同的設定值,例如,不同的 Server 他啟用的服務不相同,所以, 你或許會將同一個變數放在不同的主機上,但是給予個別相異的變數值。舉例來說:
- website 主機群組需要安裝 httpd 軟體
- devel 主機群組需要安裝 gcc 軟體
- dbserver1 需要安裝 mariadb-server 軟體
- 全部系統的預設管理員帳號稱為 alex
$ vim inventory gitclient gitclient[01:20].ksu 172.17.20.[1:30] [website] webserver1 dbserver1 pkg=mariadb-server [devel] webserver1 devnode1 pronode1 [mylab:children] website devel [website:vars] pkg=httpd [devel:vars] pkg=gcc [mylab:vars] admuser=alex
未來你想要使用上面的變數來操作你的環境,就可以直接處理。只是,官方真的不建議這樣做,原因是,inventory 這個檔案會變得很複雜, 對於管理員來說,inventory 太複雜不是很好查閱,因為,主機名稱與變數搞在一起,很容易讓下一個承接者搞混,修改也不容易, 因此,上面的設定看看即可,知道有這種設計方式就好了。
- 將變數放置到 group_vars/ 以及 host_vars/ 『目錄底下』
基本上,ansible 官網建議不同的主機名稱、群組所需要的變數,盡量放置在個別的目錄與設定檔當中!而設定檔很簡單, 就放在兩個底下的基本目錄即可 (目錄名稱不可以改變!):
- group_vars/主機群組檔名:這個目錄放置類似 website, deve, mylab 等群組名稱
- host_vars/主機名:這個目錄放置類似 dbserver1, webserver1 等主機名
# 先將 inventory 內容修訂回來 $ vim inventory gitclient gitclient[01:20].ksu 172.17.20.[1:30] [website] webserver1 dbserver1 [devel] webserver1 devnode1 pronode1 [mylab:children] website devel # 開始設計剛剛指定的兩個主機群組設計: $ mkdir group_vars $ vim group_vars/website pkg: httpd $ vim group_vars/devel pkg: gcc $ vim group_vars/mylab admuser: alex $ mkdir host_vars $ vim host_vars/dbserver1 pkg: mariadb-server
你必需要注意的是,在 inventory 裡面的變數設定,使用的是傳統的等號的設計。但是在 host_vars 以及 group_vars 目錄底下的檔案, 則是以 YAML 格式來設計的!前面保持空白,使用冒號分隔變數與變數值才對喔! 現在,我們將將上述的資料做個列表,相關的檔案有點類似這樣:
ansible-init ↳-- ansible.cfg ↳-- group_vars ⇃ ↳-- devel ⇃ ↳-- mylab ⇃ ↳-- mwebsite ↳-- host_vars ⇃ ↳-- dbserver1
讓我們開始來安裝這些需要的軟體看看:
# 建立新的 playbook 檔案內容 $ vim var_host_install.yml --- - name: setup servers package hosts: - website - devel - mylab tasks: - name: install packages "{{pkg}}" for different server yum: name: "{{pkg}}" state: latest $ ansible-playbook --syntax-check var_host_install.yml $ ansible-playbook var_host_install.yml PLAY [setup servers package] ********************************************************** TASK [Gathering Facts] **************************************************************** ok: [devnode1] ok: [pronode1] ok: [webserver1] ok: [dbserver1] TASK [install packages "httpd" for different server] ********************************** ok: [webserver1] changed: [devnode1] changed: [dbserver1] ok: [pronode1] PLAY RECAP **************************************************************************** dbserver1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 devnode1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 pronode1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 webserver1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
你可以很輕鬆的發現,不同的主機之間可以共用同一個 playbook,而且各自的軟體並不會衝突! 亦即 webserver1 可以安裝 httpd,devnode1 可以安裝 gcc,dbserver1 可以安裝 mariadb-server。 當然我們知道我們的系統全部的軟體都安裝在同一部主機上,不過,從上面的輸出,則可以明顯的發現, 事實上,不同的主機名稱,安裝的軟體確實是不一樣的!
- 將變數直接藏在 inventory 檔案內 -- 官方不建議這樣做:
- 實際進行變數的宣告-使用指令列與變數陣列
- 使用指令列模式處理變數值:
事實上,除了在 playbook 與 host_vars/*, group_vars/* 裡面設定好變數名稱與變數值的 YAML 格式設計之外, 你也可以直接在指令列模式輸入變數喔!使用『 -e var=content 』的樣式來處理即可!缺點是,你就得要自己記得曾經下達過的變數內容了! 如下,我們來設計一下使用指令列模式的方式來建置新用戶好了!
# 先建立需要的建立帳號的 playbook 內容 $ vim var_cmd_user.yml --- - name: add "{{username}}" at "{{hostname}}" hosts: "{{hostname}}" tasks: - name: add username "{{username}}" user: user: "{{username}}" password: $6$CoZmgPgw3LD3Lyi2$6ljLHiSZm0m/luHYwYlE2VVKOSAX8O1DdzFkOHEF7g..... $ ansible-playbook --syntax-check var_cmd_user.yml \ > -e "hostname=webserver1 username=checkuser1" playbook: var_cmd_user.yml $ ansible-playbook var_cmd_user.yml \ > -e "hostname=webserver1 username=checkuser1" PLAY [add "checkuser1" at "webserver1"] ********************************************** TASK [Gathering Facts] *************************************************************** ok: [webserver1] TASK [add username "checkuser1"] ***************************************************** changed: [webserver1] PLAY RECAP *************************************************************************** webserver1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
將變數放置到指令列模式的方案,就如上面這樣囉!
- 讓變數以陣列形式存在:
變數也可以使用陣列的格式存在,例如某個變數檔案內容設計如下:
# 建立變數內容檔案: $ vim vars/arrauser.yml users: melody: firstname: melody lastname: tsai homedir: /home/nis/melody password: $6$CoZmgPgw3LD3Lyi2$6ljLHiSZm0m/luHYwYlE2VVKOSAX8O1 amanda: firstname: amanda lastname: tsai homedir: /home/nis/amanda password: $6$CoZmgPgw3LD3Lyi2$6ljLHiSZm0m/luHYwYlE2VVKOSAX8O1
上述檔案會建置出幾個陣列變數,大致內容如下:
users['melody']['firstname'] == melody users['melody']['lastname'] == tsai users['melody']['homedir'] == /home/nis/melody users['melody']['password'] == $6$CoZmgPgw3LD3Lyi2$6ljLHiSZm0m/luHYwYlE2VVKOSAX8O1 users['amanda']['firstname'] == amanda users['amanda']['lastname'] == tsai users['amanda']['homedir'] == /home/nis/amanda users['amanda']['password'] == $6$CoZmgPgw3LD3Lyi2$6ljLHiSZm0m/luHYwYlE2VVKOSAX8O1 # 另一種使用方式 (官網建議少用) users.melody.firstname == melody
嘗試使用這個設定檔吧!
$ vim var_array_user.yml --- - name: add user by array mode hosts: webserver1 vars_files: vars/arrauser.yml tasks: - name: add username "{{users['melody']['firstname']}}" user: user: "{{users['melody']['firstname']}}" password: "{{users['melody']['password']}}" $ ansible-playbook --syntax-check var_array_user.yml $ ansible-playbook var_array_user.yml PLAY [add user by array mode] ********************************************************* TASK [Gathering Facts] **************************************************************** ok: [webserver1] TASK [add username "melody"] ********************************************************** changed: [webserver1] PLAY RECAP **************************************************************************** webserver1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
這種方式比較適合某些特別的狀態,一般狀態倒是很少使用陣列方式。
- 使用指令列模式處理變數值:
- 使用 debug 模組搭配 register 註冊變數,取得 ansible 輸出訊息:
有時候我們可能會需要顯示某個模組的執行結果,而不是單純的 playbook 輸出正確與否而已。你當然可以使用 -vvv 來顯示過程, 只是,如此一來,就每個指令的結果都太詳細!如果你只需要某個指令運作的結果,可以透過『 register: 變數名 』來註冊某個變數, 然後再透過 debug 模組的 var 結果顯示即可!例如,上面的使用者陣列資料,你也可以將他修改成為底下這樣來運作喔:
$ vim var_array_user.yml --- - name: add user by array mode hosts: webserver1 vars_files: vars/arrauser.yml tasks: - name: add username "{{users['melody']['firstname']}}" user: user: "{{users['melody']['firstname']}}" password: "{{users['melody']['password']}}" register: output - name: show register output debug: var=output
如上所示, register 是在第一個任務 (tasks) 裡面,且需要與模組在相同等級的排列位置上,註冊一個名為 output 的變數,這個變數名稱可以隨便你取。 然後新增一個任務,該任務主要就是 debug 模組 (你可以自行 ansible-doc debug 去查詢相關的參數) 顯示 output 的結果而已,相當簡單。
$ ansible-playbook var_array_user.yml PLAY [add user by array mode] ******************************************************** TASK [Gathering Facts] *************************************************************** ok: [webserver1] TASK [add username "melody"] ********************************************************* ok: [webserver1] TASK [show register output] ********************************************************** ok: [webserver1] => { "output": { "append": false, "changed": false, "comment": "", "failed": false, "group": 3104, "home": "/home/melody", "move_home": false, "name": "melody", "password": "NOT_LOGGING_PASSWORD", "shell": "/bin/bash", "state": "present", "uid": 3104 } } PLAY RECAP *************************************************************************** webserver1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
你就可以看到 output 的顯示結果了!
- 實做練習:
- 建立 remove_web_pkg_content.yml,內容主要在進行某些軟體的移除:
- 針對的 hosts 為 webserver1
- 建立名為 pkgs 變數,這個變數內容包含 httpd, php, mariadb-server, mariadb 四個軟體
- 建立第 1 個任務,透過 file 模組,將 /var/www/html/index.html 刪除
- 建立第 2 個任務 (tasks),透過 yum 模組,使用變數功能移除上述的軟體,且為自動移除 (autoremove)
- 檢查上述 playbook 語法,正確後,執行上述 playbook。
- 執行完畢之後,再以 ansible ad hoc 的 shell 模組,使用 rpm -q 去查詢看看上面的軟體是否已經順利移除?
- 新增一個名為 add_service.yml 的檔案,內容主要在建立某個服務:
新增一個 play,主要的目的在增加 Server 內的一個服務- 這個 play 的主機應用在 webserver1 上面
- 設定底下的變數:
- 設定 pkgs 變數,內容有 httpd, mod_ssl, php 三個軟體名稱
- 設定 service 變數,內容為 httpd 這個服務
- 設定 fire_rule 變數,內容為 http 這個網路協定服務
- 設定 content 變數,內容為『姓名 \n 學號 \n』
- 設定任務:
- 第一個任務為使用 yum 模組,安裝 pkgs 變數內的軟體,使用狀態為最新
- 第二個任務為使用 service 模組,啟動 service 變數內的服務,且設定為開機啟動、目前立刻啟動
- 第三個任務為使用 firewalld 模組,增加 fire_rule 變數內的服務,為持續且目前可應用的防火牆規則
- 第四個任務為使用 copy 模組,讓 content 變數內的資料可以複製到 webserver1 的 /var/www/html/index.html 這個檔案內。
新增一個 play,主要的目的在使用本機 (localhost) 連線到 webserver1 檢查網頁內容:- 這個 play 的主機應用在 localhost 上面
- 因為不需要切換成為 root,所以務必設定『 become: false 』這個設定值!!
- 設定任務:
- 第一個任務為使用 uri 模組,檢測網址為 http://webserver1,狀態碼需要回傳 200(正常回應),同時, 註冊 (register) 一個名為 output 的變數,方便將訊息回傳
- 第二個任務為使用 debug 模組,將 output 這個註冊的變數顯示出來即可。
- 上述檔案執行後的結果會有點像這樣:
PLAY [add a service] ***************************************************************** TASK [Gathering Facts] *************************************************************** ok: [webserver1] TASK [install packages] ************************************************************** ok: [webserver1] TASK [start and enable] ************************************************************** ok: [webserver1] TASK [firewalld] ********************************************************************* ok: [webserver1] TASK [add index.html] **************************************************************** ok: [webserver1] PLAY [check web server] ************************************************************** TASK [Gathering Facts] *************************************************************** ok: [localhost] TASK [check content] ***************************************************************** ok: [localhost] TASK [show browser output] *********************************************************** ok: [localhost] => { "output": { "accept_ranges": "bytes", "changed": false, "connection": "close", "content_length": "20", "content_type": "text/html; charset=UTF-8", "cookies": {}, "cookies_string": "", "date": "Fri, 06 Nov 2020 21:33:17 GMT", "elapsed": 0, "etag": "\"14-5b371c58d85c0\"", "failed": false, "last_modified": "Fri, 06 Nov 2020 15:21:50 GMT", "msg": "OK (20 bytes)", "redirected": false, "server": "Apache/2.4.37 (centos) OpenSSL/1.1.1c", "status": 200, "url": "http://webserver1" } } PLAY RECAP *************************************************************************** localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 webserver1 : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 建立 remove_web_pkg_content.yml,內容主要在進行某些軟體的移除:
使用 ansible-vault 加密檔案
- 關於 ansible 的加密機制:
- 許多的機密資料,簡單的說,例如密碼資料,大部分都也是紀錄到 group_vars/ 或 host_vars/ 或是 playbook 本身, 以及許多外接的檔案等等。這些檔案預設都是以所有人都可查閱的方式存在的,也就是說,這些資料很容易不小心就流出去來的。 因此,ansible 確實需要使用加密機制來管理這些檔案比較妥當。
- ansible 提供了名為 ansible-vault 這個指令來進行檔案的編輯,編輯時,就能夠對這些被編輯的檔案加密了。 使用的加密機制為 AES256 喔!
- 關於 ansible-vault 的使用:
- 針對具有加密機制的檔案,可以使用底下的方式來建立、查詢與編輯:
# 基本語法: $ export EDITOR=vim $ ansible-vault create file.yml // 建立全新的加密檔案 $ ansible-vault view file.yml // 查閱加密的檔案內容 $ ansible-vault edit file.yml // 編輯加密的檔案內容 (一定會複寫一次)
舉例來說,讓我們來建立一個名為 secret1.yml 的檔案看看: (建立的密碼為 mydic )$ ansible-vault create secret1.yml New Vault password: <==輸入 mydic Confirm New Vault password: <==輸入 mydic
你得注意到,預設的 ansible-vault 只會主動呼叫 vi 指令,這是單純的 vi 而不是具有程式編輯的 vim 喔! 因此,建議在載入 bash 時,就主動的將 EDITOR 設定為 vim 比較妥當!$ vim ~/.bashrc export EDITOR=vim $ source ~/.bashrc
- 如果擔心密碼忘記,也能建立密碼檔,然後使用 --vault-password-file= 指定檔名
$ vim mypassword.txt mydic $ chmod 600 mypassword.txt $ ansible-vault edit --vault-password-file=mypassword.txt secret1.yml
這個 mypassword.txt 的檔案,建立只有你自己能夠讀寫的權限即可。當然,你也可以搬離這個目錄, 放置到你的家目錄的其他較為隱密的目錄去,就可以保存好你自己的密碼了。 - 使用 encrypt 以及 decrypt 進行加密與解密的動作:
# 將已經存在的 user_add.yml 加密: $ ansible-vault encrypt --vault-password-file=mypassword.txt \ > add_service.yml --output=secret2.yml Encryption successful $ ll add_service.yml secret2.yml -rw-rw-r--. 1 student student 998 Nov 6 23:21 add_service.yml -rw-------. 1 student student 4372 Nov 8 00:36 secret2.yml $ cat secret2.yml $ANSIBLE_VAULT;1.1;AES256 35366438653330333932363463613533343735366635663332643637636335356364353930363935 3631396436663632626339333436386138663737313131370a643737303361653464636136383364 31613763366231303565653934313739613262383366316163313562323463643962333831666230 .... $ ansible-vault view --vault-password-file=mypassword.txt secret2.yml --- - name: add a service hosts: - webserver1 ....
這樣就進行了加密!相當簡單吧!那如果需要將加密的檔案解密呢?$ cat secret1.yml $ANSIBLE_VAULT;1.1;AES256 30363939386632333666663234393436623138323061363637393234383065336437343061323738 6133313065643739633538373437396663643334643536320a393432613361373537373535363963 .... $ ansible-vault decrypt --vault-password-file=mypassword.txt secret1.yml $ cat secret1.yml --- - name: check ....
如果你沒有使用 --output=newoutfile 的話,那麼原本的檔案就會被解密了喔!要注意!要注意! - 使用 rekey 重建密碼:
# 1. 將 secret1.yml 加密 $ ansible-vault encrypt secret1.yml New Vault password: <==輸入 mydic Confirm New Vault password: <==輸入 mydic Encryption successful $ ansible-vault rekey secret1.yml Vault password: <==輸入 mydic New Vault password: <==輸入 gogodic Confirm New Vault password: <==輸入 gogodic Rekey successful
上述指令會將該檔案的密碼從 mydic 修訂成為 gogodic 喔!那如果你想要使用某個檔案的內容來修改成為正確的密碼, 可以使用 new-vault-password-file 來處理:$ ansible-vault rekey --new-vault-password-file=mypassword.txt secret1.yml Vault password: <==輸入 gogodic Rekey successful
- 針對具有加密機制的檔案,可以使用底下的方式來建立、查詢與編輯:
- 實做練習: 目的在將使用者帳密保密,然後使用 playbook 引入該設定檔來處理帳號新增
- 建立加密用的密碼檔,檔名為 secret3_vault.txt ,內容就是一個明碼的密碼,內容隨便你填寫。 只是權限一定要重新設定為 600 才好!
- 先用『 openssl passwd -6 』,然後輸入 mydic 讓系統自動產生一個 sha512 長度的密碼,並將該密碼記錄下來;
- 建立 secret3_user_profile.yml 的設定檔,此檔案必須要加密,加密的密碼採用 secret3_vault.txt 的內容,
至於此檔案的內容為:
username: mysec1 password: [[剛剛建立的密碼]]
- 建立名為 secret3_add_user.yml 的 playbook 檔案,內容有點類似這樣 (這個檔案不需要加密):
--- - name: create user hosts: - webserver1 vars_files: - secret3_user_profile.yml tasks: - name: create users "{{username}}" user: name: "{{username}}" password: "{{password}}"
- 開始執行 secret3_add_user.yml 的內容,分別使用底下三種方式執行看看:
$ ansible-playbook secret3_add_user.yml $ ansible-playbook --ask-vault-pass secret3_add_user.yml $ ansible-playbook --vault-password-file=secret3_vault.txt secret3_add_user.yml
- 使用『 ssh mysec1@client1 』並輸入 mydic 這個密碼,看看能不能登入用戶端電腦?
最後,當你使用 ls -l 去查閱相關資料時,就可以發現,其實很多加密的檔案,預設的權限都會是 600 的喔!很有趣!
使用 ansible facts 探索 managed hosts 的實際資料
- 使用 setup 模組取得 managed host 的參數:
- 有些時候,我們得要先知道 managed host 的相關參數之後,才有辦法進行啟動、關閉、安裝軟體等任務,最簡單的方式,
透過 setup 這個模組就可以知道了!
$ ansible webserver1 -m setup webserver1 | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "192.168.122.1", "172.17.200.1" ], "ansible_all_ipv6_addresses": [ webserver1 | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "192.168.122.1", "172.17.200.1" ], "ansible_all_ipv6_addresses": [ "fe80::5718:f7d5:ab79:9643" ], "ansible_apparmor": { "status": "disabled" }, "ansible_architecture": "x86_64", "ansible_bios_date": "01/01/2007", "ansible_bios_version": "0.5.1", "ansible_cmdline": { "BOOT_IMAGE": "(hd0,gpt2)/vmlinuz-4.18.0-147.el8.x86_64", "crashkernel": "auto", "quiet": true, "rd.lvm.lv": "centos/swap", "resume": "/dev/mapper/centos-swap", "rhgb": true, "ro": true, "root": "/dev/mapper/centos-root" }, .....
如上所示,會列出這個主機的相關資料。其中比較有趣的,就是 ansible_facts 裡面的資訊!那個是系統基本資料。 這個 setup 的模組,也是每次進行 playbook 時,系統會主動執行的一個模組。 - 使用 gather_facts: no 取消 setup 模組:如果你已經知道你的 managed host 系統相關資訊,因此不想要執行 setup 模組時,
也能夠使用 gather_facts 來取消,簡易的設定方式如下:
--- - name: some play book demo hosts: someserver gather_facts: no ...
不過,一般建議保留預設值,還是讓 ansible 去檢查一下 managed host 的狀態會比較好。
- 有些時候,我們得要先知道 managed host 的相關參數之後,才有辦法進行啟動、關閉、安裝軟體等任務,最簡單的方式,
透過 setup 這個模組就可以知道了!
- ansible_facts 檢測的內容
- 基本上,ansible_facts 如同上面 -m setup 的輸出結果一樣,大致上在檢查:
- 主機名稱 (hostname)
- 核心版本
- 網路卡代號
- IP 位址 (包括 IPv4 與 IPv6)
- 作業系統的版本 (基本上,就是 distributions)
- 環境變數的設定值
- 跟硬體有關的,如 CPU、記憶體、磁碟容量等。
- 若想實際知道 ansible_facts 紀錄的資訊主要有哪些,可以透過 debug 模組來分析 ansible_facts 這個變數內容即可!
例如底下這個處理方案:
$ vim hosts_facts.yml --- - name: list my managed hosts facts hosts: website tasks: - name: list managed hosts facts debug: var: ansible_facts $ ansible-playbook hosts_facts.yml PLAY [list my managed hosts facts] *************************************************** TASK [Gathering Facts] *************************************************************** ok: [dbserver1] ok: [webserver1] TASK [list managed hosts facts] ****************************************************** ok: [webserver1] => { "ansible_facts": { "all_ipv4_addresses": [ "192.168.122.1", "172.17.200.1" ], ....
其實,跟 setup 模組內容幾乎是一模一樣耶! - 那麼 ansible_facts 的資料如何取得與使用?其實它有這些變數名稱:
變數名稱 意義 ansible_facts['hostname'] 主機名稱,例如 gitserver200 ansible_facts['fqdn'] 主機的全名,例如 gitserver200.dic.ksu ansible_facts['default_ipv4']['address'] IPv4 的 IP 位址 ansible_facts['interfaces'] 全部網路卡的代號列表 ansible_facts['devices']['vda']['partitions']['vda1']['size'] 相關的磁碟容量 ansible_facts['dns']['nameservers'] DNS 伺服器 IP 列表 ansible_facts['kernel'] 核心版本 $ cp hosts_facts.yml hosts_facts2.yml $ vim hosts_facts2.yml --- - name: list my managed hosts facts hosts: website tasks: - name: list managed hosts facts debug: msg: | The IPv4 IP address is {{ansible_facts['default_ipv4']['address']}} The host name is {{ansible_facts['fqdn']}} The kernel version is {{ansible_facts['kernel']}} The network card is {{ansible_facts['interfaces']}} $ ansible-playbook hosts_facts2.yml PLAY [list my managed hosts facts] *************************************************** TASK [Gathering Facts] *************************************************************** ok: [webserver1] ok: [dbserver1] TASK [list managed hosts facts] ****************************************************** ok: [webserver1] => { "msg": "The IPv4 IP address is 172.17.200.1\nThe host name is gitclient200.ksu \n The kernel version is 4.18.0-147.el8.x86_64 \nThe network card is ['lo', 'ens3', 'virbr0', 'virbr0-nic']\n" } ok: [dbserver1] => { "msg": "The IPv4 IP address is 172.17.200.1\nThe host name is gitclient200.ksu \n The kernel version is 4.18.0-147.el8.x86_64 \nThe network card is ['virbr0-nic', 'ens3', 'virbr0', 'lo']\n" } PLAY RECAP *************************************************************************** dbserver1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 webserver1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
資料量立刻少很多喔!
- 基本上,ansible_facts 如同上面 -m setup 的輸出結果一樣,大致上在檢查:
- 使用自訂的 ansible_fact 資料:
- 除了預設的 facts 之外,使用者可以自訂『自己主機本身』的 fact 資料,這些資料主要放置在 /etc/ansible/facts.d/*.fact 檔案!
例如底下的範例,在建立屬於本機自己的 fact 相關資料。
# 先以 root 的身份進行建立 /etc/ansible/facts.d 目錄的功能 # mkdir /etc/ansible/facts.d # setfacl -m u:student:rwx /etc/ansible/facts.d # 新增 /etc/ansible/fscts.d/myset.fact ,內容主要填寫軟體與服務名稱 $ vim /etc/ansible/facts.d/myset.fact [pkgs] pkg_web = httpd pkg_db = mariadb-server [srv] srv_web = httpd srv_db = mariadb $ cd ~; ansible localhost -m setup | egrep -A3 -B3 'pkg|srv' "ansible_local": { "myset": { "pkgs": { "pkg_db": "mariadb-server", "pkg_web": "httpd" }, "srv": { "srv_db": "mariadb", "srv_web": "httpd" } } },
- 接下來,如果要使用到上面的自訂變數,基本上會是這樣的:
ansible_facts['ansible_local']['檔名']['中括號名稱']['變數名稱'] = 變數內容 ansible_facts['ansible_local']['myset']['pkgs']['pkg_web'] = httpd ansible_facts['ansible_local']['myset']['pkgs']['pkg_db'] = mariadb-server ansible_facts['ansible_local']['myset']['srv']['srv_web'] = httpd ansible_facts['ansible_local']['myset']['srv']['srv_db'] = mariadb
基本上,鳥哥自己認為,使用變數來處理即可。只是,既然也跟本機有關,了解一下有這種用法也是好的。
- 除了預設的 facts 之外,使用者可以自訂『自己主機本身』的 fact 資料,這些資料主要放置在 /etc/ansible/facts.d/*.fact 檔案!
例如底下的範例,在建立屬於本機自己的 fact 相關資料。
- 實做練習一:將自定的 myset.fact 檔案,複製到 managed host 上面
- 假定你預計讓 website 群組的主機具有 myweb.fact 的 ansible 本機設定,因此需要建立 myweb.fact 檔案,
這個檔案的內容大致上是這樣的:
[web] pkg = httpd srv = httpd state = started enabled = true fire_srv = http
- 寫一隻名為 myweb_fact_go.yml 的 playbook,內容是主要針對 website 的主機群組,然後:
- 設定兩個變數,分別是 src_file ,指向 myweb.fact 檔名,以及 dest_dir,位置在 /etc/ansible/facts.d/
- 使用 file 模組,使用遞迴方式建立上述 dest_dir 這個目錄
- 使用 copy 模組,將剛剛建立的檔案,複製到對方的 /etc/ansible/facts.d/myweb.fact 檔案。
- 執行上述 playbook 的內容,並觀察輸出資料是否正確執行了。
- 使用『 ansible website -m setup | less 』,然後觀察輸出資訊裡面有沒有剛剛指定的 myweb 相關的設定資訊?
- 假定你預計讓 website 群組的主機具有 myweb.fact 的 ansible 本機設定,因此需要建立 myweb.fact 檔案,
這個檔案的內容大致上是這樣的:
- 實做練習二:透過每部 managed host 自己的 fact 來處理服務運作的五個步驟
- 要先知道上面 myweb.fact 的結果中,會出現的變數名稱類似: ansible_facts['ansible_local']['myweb']['web']['pkg'] = httpd 這樣的格式! 所以,要先知道已經有 5 個新建的 ansible_facts 變數喔!
- 複製 add_service.yml 這個以前建立的檔案,複製成 myweb_fact_go2.yml 的 playbook ,並將內部的設計, 全部改以 ansible_facts 的變數取代。
- 執行上述的 playbook,確認執行過程沒有問題!