添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
  • 專題四 - 虛擬機器的網路設計與大量佈建
  • 專題五 - 建立 rootfs 的無磁碟 Linux 系統環境
  • 專題六 - 以 rootfs 備份、復原系統,以 grub4dos 處理多重選單
  • 專題七 - 以虛擬機器模擬 EFU 取代 BIOS 環境
  • 專題八 - 軟體編譯行為
  • 專題十五 - 其他 (未完、待續)
  • 雲端資訊系統課程
  • 使用 git 進行版控 - 基礎操作
  • 使用 git 進行版控 - 分支與簡易合併
  • 使用 git 進行版控 - 多人共同開發之容器設定
  • 使用 git 進行版控 - 專題報告
  • 使用 Ansible 進行快速佈署 - 環境設定與 ad hoc
  • 使用 Ansible 進行快速佈署 - playbook 初探
  • 使用 Ansible 進行快速佈署 - 善用 playbook 變數
  • 使用 Ansible 進行快速佈署 - 迴圈, 條件控制, 錯誤排除等功能
  • 使用 Ansible 進行快速佈署 - 綜合練習
  • 使用 Docker 容器
  • 使用 Docker 容器 - 管理倉儲
  • 使用 podman 進行 container 管理
  • 碩班期末考-考前注意事項
  • 碩班期末考
  • Ansible 可以達成快速佈署,而且也能減輕 IT 人員的負擔。但是,如果依據前一章的設定,單純透過 ad hoc 單一指令來運作的話,那麼不就還得要重新撰寫 document?因為這些指令的內容還是得要記憶,對吧?這樣不好。 所以,就像 shell scripts 一樣,將指令寫成批次檔的概念,我們將 ad hoc 的內容寫成名為 playbook 的樣式, 讓 ansible 根據 playbook 去執行即可喔!未來要執行資料時,將 playbook 改一改,執行下去,全部受管控的 managed hosts 就全部更新了!方便快速得很!

  • 就像 shell script 簡單的說,可以將一系列的指令彙整成為類似批次檔一樣。 playbook 可以將前一章提到的 ansible ad hoc 指令, 彙整到一個文字檔,然後透過『 ansible-playbook filename.yml 』的方式,來將該動作執行完畢。而 playbook 又是純文字檔, 相當方便修改、彙整、紀錄等。
  • 前一章有個 ansible ad hoc 內容是這樣: $ ansible webserver1 -m copy -a 'src=/etc/hosts dest=/etc/hosts' 你可以將這一行改寫成為底下的模樣: - name: copy /etc/hosts to managed hosts hosts: webserver1 tasks: - name: copy /etc/hosts to another hosts copy: src: /etc/hosts dest: /etc/hosts 上面這個就是『 YAML 』格式的 playbook 內容!
  • YAML 格式:
  • 基本上, YAML 格式的要求是:『同一個階層的設定,需要使用相同的縮排』,至於縮排幾個空白字元,就沒有特別規定。 所以,簡單的說, YAML 對於縮排的需求有兩個基本的規則,一定要符合才行:
  • 每一個不同元素,只要其階層相同,那縮排必須要相同。如同上面的範例中,name, hosts, tasks 三個元素的階層相同, 所以縮排就一定要相同。
  • 子元件必須要有更多的縮排,其縮排空白必須要比父元件多。以上面的 copy 為例,他是 tasks 的子元件, 所以就一定要在 tasks 有更多的縮排才行!
  • 為符合 yaml 的格式設計,如果使用 vim 這個程式編輯器,那你可以在 ~/.vimrc 裡面增加這一行,讓 vim 偵測到副檔名為 .yml 時, 就自動以 2 個字元替代 tab 按鍵的產生: $ whoami $ vim ~/.vimrc autocmd FileType yaml setlocal ai ts=2 sw=2 et 如此一來,未來我們就可以直接使用 [tab] 來達成對齊之外,編輯的時候, .yml 格式也會自動縮排對齊!
  • playbook 格式:
  • 除了 Yaml 的格式之外,playbook 也有其特定的格式喔!剛剛看到的 playbook 就是一個基礎格式,我們可以分析一下上面的檔案, 你會發現到幾個基本的規則:
  • 整個 playbook 的運作開頭是由三個減號 (---) 開始的。
  • 之後第一個 play 接一個減號與一個空白 (- ),注意到是減號與空白喔!
  • 通常每個 play 會有三個指標 (keys),分別是 name, hosts, tasks。
  • 任務 (tasks) 底下可能會有好幾個連續的動作,每個動作同樣都以減號空白 (- ) 為開始, 然後接著模組名稱,在模組名稱底下則帶入該模組所需要的參數。
  • name 的功能: (其實,基本功能就是標題, label 的功能!)
  • 通常每個 playbook 可能會有好幾個 play,每個 play 裡面可能又有好幾個任務 (tasks),每個任務裡面都有獨自的模組與參數這樣。
  • 那如果以 ansible ad hoc 的角度來看,我們就是反覆不斷的執行指令而已。
  • playbook 為了讓大家知道該指令的功能是什麼,或者是該任務 (tasks) 的任務是什麼,因此給了 name 的參數, 後面接的訊息,就是執行 playbook 時,會提供給 IT 人員查看該動作意義的訊息。
  • 在 playbook 中,name 雖然是非必要的,但是 ansible 建議一定要寫!這才未來執行,才知道那是啥東西!
  • hosts 的功能:很簡單啊!就是 hosts/group 主機名稱列表的主機名稱群!
  • tasks 的功能:就是許多任務
  • 每一個任務依舊使用 (- ) 開頭,接的第一個指標通常也就是 name,紀錄該任務的功能說明
  • 接下來就是模組名稱,然後在模組名稱底下,就是該模組的參數, 也就是透過 ansible-doc 查到的參數與參數值,中間都用冒號 (:) 隔開而已。
  • $ ansible-playbook --syntax-check copy_hosts.yml ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each: JSON: Expecting value: line 1 column 1 (char 0) Syntax Error while loading YAML. mapping values are not allowed in this context The error appears to be in '/home/student/ansible-init/copy_hosts.yml': line 3, column 11, but maybe elsewhere in the file depending on the exact syntax problem. The offending line appears to be: - name: copy /etc/hosts to managed hosts hosts: webserver1 ^ here 如上所示,最後 3 行顯示錯誤的地方,原來是 hosts 的縮排多了一個空白字元的結果。改完之後重複執行一次, 系統就會提示沒問題了!
  • 測試一下僅執行環境檢查的 dry run 結果,此動作僅檢查環境,不會實際運作喔! $ ansible-playbook -C copy_hosts.yml PLAY [copy /etc/hosts to managed hosts] ********************************************* TASK [Gathering Facts] ************************************************************** ok: [webserver1] TASK [copy /etc/hosts to another hosts] ********************************************* ok: [webserver1] PLAY RECAP ************************************************************************** webserver1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 你會發現到中括號 [] 裡面,大部分就是 name 設計的名稱!這樣真的比較好理解工作項目! 所以, name 要寫清楚一點喔!最後一行則是顯示執行的結果,大部分都是 ok 的!
  • 實際執行此 playbook: $ ansible-playbook copy_hosts.yml 結果會跟上面一樣,只是,這次就真的是執行而不是僅檢查環境而已!
  • 實做練習:
  • 模仿上面的 playbook 設定,然後翻到前一章,找到新增用戶的指令如下: python3 -c "from passlib.hash import sha512_crypt; \ import getpass; \ print(sha512_crypt.using(rounds=5000).hash(getpass.getpass()))" Password: $6$I9E8lDkx9ThYK5y0$c7icc4zDLaLyBE3zacseBQeKBmkhUpNTUC.0RrK/6Od... ansible webserver1 -m user -a 'user=demouser uid=3000 password=$6$I9E8lDkx9T..'
  • 現在,新增一個新的用戶,名稱為 myuser1,uid 為 3101,密碼為加密過後的 itismyuser。 請將該設定值寫成名為 user_add.yml 的 playbook
  • 嘗試檢查語法,若沒問題,就直接執行這個 playbook 看看
  • 使用 ansible ad hoc 的指令功能,使用 id 檢查一下這個帳號 myuser1 是否已經存在其系統中了?
  • 範例規劃:安裝 http 以及處理首頁檔案
  • 管理員大概很常被要求要幫用戶處理 web server 的啟動與首頁的製作。大致上安裝、啟動、開機啟動、設置首頁檔案、防火牆的設定流程是不變的。 我們可以透過 playbook 來設定好這些資料!
  • 安裝的流程應該是使用 yum 模組的,安裝的軟體為 httpd,使用底下的方式找到 yum 的參數: $ ansible-doc yum ..... - name A package name or package specifier with version, like `name-1.0'. ..... - state Whether to install (`present' or `installed', `latest'), or remove (`absent' or `removed') a package. `present' and `installed' will simply ensure that a desired package is installed. `latest' will update the specified package if it's not of the latest available version. `absent' and `removed' will remove the specified package. Default is `None', however in effect the default action is `present' unless the `autoremove' option is enabled for this module, then `absent' is inferred. ..... 通常會使用 latest 強制安裝到最新,至於 installd 與 present 則是要求要有安裝。 如果要移除,才使用 removed 。
  • 啟動與開機啟動需要透過 service 模組的支援,所以檢查 service 的參數: $ ansible-doc service ..... - enabled Whether the service should start on boot. ..... = name Name of the service. ..... - state `started'/`stopped' are idempotent actions that will not run commands unless necessary. `restarted' will always bounce the service. `reloaded' will always reload. 是否要開機啟動,透過 enabled 為 true 或 false 來設計,至於 state 則是立刻啟動/關閉/重新啟動的設計。
  • 修改網頁,如果是新的網頁,然後只具有一兩行的話,可以使用 copy 的 content 內容來處理即可。
  • 開始撰寫 playbook :
  • 假設檔名設定為 web_first.yml 好了: $ whoami; pwd student /home/student/ansible-init $ vim web_first.yml - name: setup web server and add first web page hosts: webserver1 tasks: - name: install httpd packages name: httpd state: latest - name: start and enable httpd service service: name: httpd enabled: true state: started - name: create first web page for index.html copy: content: 'name: vbird tsai\nID: g090axxx\n' dest: /var/www/html/index.html
  • 開始檢查語法是否有問題: $ ansible-playbook --syntax-check web_first.yml playbook: web_first.yml
  • 測試執行檢查環境: $ ansible-playbook -C web_first.yml PLAY [setup web server and add first web page] ************************************** TASK [Gathering Facts] ************************************************************** ok: [webserver1] TASK [install httpd packages] ******************************************************* changed: [webserver1] TASK [start and enable httpd service] *********************************************** changed: [webserver1] TASK [create first web page for index.html] ***************************************** changed: [webserver1] PLAY RECAP ************************************************************************** webserver1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 這代表指令執行應該會成功 (ok=4),而且可能會有改變任務的項目有三個 (chaged=3)。
  • 執行、假查與測試:
  • 開始執行 playbook 囉! $ ansible-playbook web_first.yml PLAY [setup web server and add first web page] ************************************** TASK [Gathering Facts] ************************************************************** ok: [webserver1] TASK [install httpd packages] ******************************************************* changed: [webserver1] TASK [start and enable httpd service] *********************************************** changed: [webserver1] TASK [create first web page for index.html] ***************************************** changed: [webserver1] PLAY RECAP ************************************************************************** webserver1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $ ansible webserver1 -m command -a 'cat /var/www/html/index.html' webserver1 | CHANGED | rc=0 >> name: vbird tsai\nID: g090axxx\n 這樣看起來,確實是有成功的執行了將首頁貼上去的功能!
  • 使用 curl 檢查一下網頁囉! $ curl webserver1 curl: (7) Failed to connect to webserver1 port 80: No route to host $ ansible webserver1 -m command -a 'systemctl status httpd' webserver1 | CHANGED | rc=0 >> ● httpd.service - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled;vendor preset:disabled) Active: active (running) since Sun 2020-10-25 00:12:09 CST; 2min 53s ago Docs: man:httpd.service(8) Main PID: 28961 (httpd) Status: "Running, listening on: port 80" Tasks: 213 (limit: 11482) Memory: 39.1M CGroup: /system.slice/httpd.service ├─28961 /usr/sbin/httpd -DFOREGROUND ├─28962 /usr/sbin/httpd -DFOREGROUND ├─28963 /usr/sbin/httpd -DFOREGROUND ├─28964 /usr/sbin/httpd -DFOREGROUND └─28965 /usr/sbin/httpd -DFOREGROUND $ ansible webserver1 -m command -a 'firewall-cmd --list-all' webserver1 | CHANGED | rc=0 >> public (active) target: default icmp-block-inversion: no interfaces: ens3 sources: services: cockpit dhcpv6-client ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: 連不上 httpd 呢!原來是防火牆搞的鬼!我們都忘記啟動用戶端的防火牆 http 了!
  • 增加任務與重複執行 playbook:
  • 我們忘記加上 managed host 防火牆,所以現在要補強!防火牆使用 firewalld 模組: $ ansible-doc firewalld ..... - immediate Should this configuration be applied immediately, if set as permanent. [Default: False] type: bool ..... - permanent Should this configuration be in the running firewalld configuration or persist across reboots. [Default: (null)] type: bool ..... - service Name of a service to add/remove to/from firewalld. The service must be listed in output of firewall-cmd --get- services. [Default: (null)] type: str ..... = state Enable or disable a setting. For ports: Should this port accept (enabled) or reject (disabled) connections. The states `present' and `absent' can only be used in zone level operations (i.e. when no other parameters but zone and state are set). (Choices: absent, disabled, enabled, present) type: str ..... 我們目前只需要啟動 http 而已,所以可以改寫 web_first.yml 檔案了:
  • 改寫 web_first.yml 檔案: $ vim web_first.yml ..... - name: add http port to firewalld firewalld: immediate: true permanent: true service: http state: enabled $ ansible-playbook --syntax-check web_first.yml playbook: web_first.yml $ ansible-playbook web_first.yml PLAY [setup web server and add first web page] ************************************** TASK [Gathering Facts] ************************************************************** ok: [webserver1] TASK [install httpd packages] ******************************************************* ok: [webserver1] TASK [start and enable httpd service] *********************************************** ok: [webserver1] TASK [create first web page for index.html] ***************************************** ok: [webserver1] TASK [add http port to firewalld] *************************************************** changed: [webserver1] PLAY RECAP ************************************************************************** webserver1 : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $ curl webserver1 name: vbird tsai\nID: g090axxx\n 這樣就搞定了!上面看起來有被更動的,也只有最後一個防火牆而已,因此就變成了 chaged 囉!
  • 嘗試使用『 lineinfile 』模組,請自行查詢這個模組的可用參數。
  • 建立名為 hosts_modify.yml 的檔案,這個 playbook 的重點是:將『 172.16.200.254 bigdata 』加入 /etc/hosts 內。
  • 執行該 playbook 去影響 webserver1 主機
  • 使用 ansible ad hoc 的功能,去看看 /etc/hosts 有沒有成功的加入了該行資料?
  • 重複執行該 playbook,該行字會不會被持續加入呢?
  • $ ansible-playbook -vv copy_hosts.yml ansible-playbook 2.9.14 config file = /home/student/ansible-init/ansible.cfg configured module search path = ['/home/student/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.6/site-packages/ansible executable location = /usr/bin/ansible-playbook python version = 3.6.8 (default, Apr 16 2020, 01:36:27) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] Using /home/student/ansible-init/ansible.cfg as config file PLAYBOOK: copy_hosts.yml ************************************************************ 1 plays in copy_hosts.yml PLAY [copy /etc/hosts to managed hosts] ********************************************* TASK [Gathering Facts] ************************************************************** task path: /home/student/ansible-init/copy_hosts.yml:2 ok: [webserver1] META: ran handlers TASK [copy /etc/hosts to another hosts] ********************************************* task path: /home/student/ansible-init/copy_hosts.yml:5 changed: [webserver1] => {"changed": true, "checksum": "423f985239e1e7eb5d52becf62da d1fac3e3b475", "dest": "/etc/hosts", "gid": 0, "group": "root", "md5sum": "677944b 84b84bd729177b22a039b94c2", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:net_conf_t:s0", "size": 344, "src": "/home/sysadm/.ansible/tmp/ ansible-tmp-1603562867.5132856-62179-209476908331227/source", "state": "file", "uid" META: ran handlers META: ran handlers PLAY RECAP ************************************************************************** webserver1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 比較重要的是 chaged 那一段,可以看到內容就有如 ansible ad hoc 執行的訊息顯示流程! 私訊非常完整。同時注意,該段訊息是以大括號 { } 將訊息包起來的喔!
  • YAML 的額外語法說明
  • 除了之前談到的縮排之外,如果 yuml 需要註解,可以在任何地方增加 # 即可在後面加入註解: # 這是註解 -name: add file # 這也可以是註解
  • YAML 的字串,通常不用設定啥,就是字串了!只是,如果你需要定義更清楚,可以使用單、雙引號處理: this is string words. 'this is string words.' "this is string words." 上面的語法都是被接受的!
  • 如果有一行內容文字太長,你可能要分成好幾行,這樣比較好閱讀。這時,你可以使用兩個分隔字元來處理看看: - name: This playbook will treate your managed hosts for | its http service and php language and mysql SQL server. hosts: webserver1 如果使用管線符號 (|) 來處理,則底下的文字會主動貼到上面這行來。 要注意的是,playbook 主要判斷內容的依據是冒號 (:),所以底下幾行都會黏到第一行去!第二種語法是: - name: This playbook will treate your managed hosts for > its http service and php language and mysql SQL server. hosts: webserver1 兩者都可以達成這些目標喔!
  • 使用字典格式 (dictionaries),亦即透過大括號 { } 處理: # 原始的格式是這樣: - name: copy /etc/hosts to another hosts copy: src: /etc/hosts dest: /etc/hosts # 可以改成這樣子: - name: copy /etc/hosts to another hosts copy: { src: /etc/hosts, dest: /etc/hosts }
  • YAML 的列表功能,舉例來說,當你要安裝的軟體很多時,可以這樣處理: - name: setup web server and add first web page hosts: - webserver1 - dbserver1 tasks: - name: install httpd packages name: - httpd - php - mariadb state: latest 使用 (- ) 作為開頭,同樣需要縮排喔!這樣就可以接上許多列表的資料了!
  • 實做練習:加上 ftp 的服務功能
  • 實施的主機群,請使用 website 這個主機群組!
  • 設計一個 FTP 匿名登入伺服器的功能,需要的軟體主要是 vsftpd 這個服務,請查詢 yum 模組, 找到正確的參數,安裝好 vsftpd 模組
  • 這個服務每次開機都要啟動,請找 service 模組,同樣啟動這個服務!
  • 防火牆記得要放行 ftp 才行。
  • 設計一個 readme.txt 檔案,放置到 myuser1 的家目錄當中, 內容就填寫『 This FTP daemon setted by Ansible 』即可。記得,使用者、群組要修改成為 myuser1 所有才對喔!
  • 最後,使用 get_url 的模組,自我確認一下 ftp://webserver1/readmt.txt ,使用 myuser1 登入 (注意, 密碼為 itismyuser 喔!)是否可以將檔案儲存到 /dev/shm/checkftp.txt 當中?(因為使用 FTP 的關係, 你可能需要使用 ftp://username:password@hostname/dir/file 的格式來處理才行!)
  • 上述 playbook 請寫入名為 ftp_first.yml 檔案中,並且測試與執行。
  •