[{"content":"隨著 Ansible 版本（ansible-core）持續升級，除了控制端（Control Node）本身的改進外，Ansible 對受控端（Managed Node / Target Host）的 Python 或 PowerShell 版本要求也隨之提高。\n如果在企業內部環境中，受限於維運規範無法輕易升級受控端的 Python 或 PowerShell，透過 Execution Environment (EE) 將特定版本的 Ansible、Python 執行環境與 Collection 封裝在容器中，便能輕鬆維持與舊主機的環境相容性。\n本文將介紹如何使用 pipx 安裝 ansible-navigator、配置設定檔並使用 Execution Environment 執行 Playbook。\n為什麼需要 ansible-navigator？ 以往在 Control Node 上直接執行 ansible-playbook 時，所有的 Python 依賴套件、Ansible 版本與 Collection 都直接依賴本機作業系統環境，容易遇到以下痛點：\n環境污染與衝突：不同專案可能需要不同版本的 Collection 或 Python 函式庫。 目的端版本不相容：新版 Ansible 不再支援受控端過舊的 Python 版本（例如 Python 2.7 或 3.6）。 環境一致性問題：本機端測試通過的 Playbook，在 CI/CD 或同事電腦上可能因環境差異而失敗。 Ansible 官方推出的 ansible-navigator 搭配容器化 Execution Environment (EE)，透過 Docker 或 Podman 啟動容器來執行 Playbook，讓自動化環境達到高度隔離與標準化。\n1. 使用 pipx 安裝 ansible-navigator 以往官方常建議使用 pip install --user ansible-navigator 進行安裝，但此方式容易污染使用者的 Python 環境或造成套件衝突。\n推薦改用 pipx 進行安裝。pipx 會自動為每個 CLI 工具建立獨立的 Python 虛擬環境（virtual environment），並將執行檔連結到系統路徑中，既乾淨又便於管理。\n在 Ubuntu / Debian 上安裝 # 安裝 pipx sudo apt update sudo apt install -y pipx pipx ensurepath # 安裝 ansible-navigator pipx install ansible-navigator 安裝完成後，可執行以下指令確認版本：\nansible-navigator --version 2. 產生與配置設定檔 (ansible-navigator.yml) 安裝完成後，建議在專案根目錄或家目錄產生 ansible-navigator.yml 設定檔，省去每次執行指令時手動輸入一長串參數的麻煩。\n產生設定檔範本（注意避坑） # 先輸出到暫存檔 ansible-navigator settings --sample \u0026gt; ansible-navigator-new.yml # 再更名為正式設定檔 mv ansible-navigator-new.yml ansible-navigator.yml 💡 小提醒：建議先導出至暫存檔（如 ansible-navigator-new.yml）再更名。若直接重導向到 ansible-navigator.yml，Shell 在執行前會先建立空檔案，此時 ansible-navigator 讀取到空檔案會判定設定錯誤而中斷執行。\n3. 選擇 Execution Environment (EE) 容器映像檔 ansible-navigator 會透過容器引擎（Podman 或 Docker）拉取 EE 映像檔來執行任務。\nRed Hat 官方映像檔：需登入 Red Hat 註冊庫（Registry）。 社群維護映像檔：若無官方訂閱，可使用社群開源提供的 AWX / Ansible EE 映像檔，例如： Docker Hub: ppodgorsek/ansible-awx-ee Docker Hub: giuffrelab/awx-community-general-ee 經過實際測試，社群維護的 giuffrelab/awx-community-general-ee:31 穩定性良好且預載常用 collection。\n4. ansible-navigator.yml 設定檔範例 以下為推薦的 ansible-navigator.yml 配置內容：\n--- ansible-navigator: ansible: config: help: False path: ./ansible.cfg # 指定 ansible.cfg 路徑 cmdline: \u0026#34;--forks 10\u0026#34; # 額外傳入 ansible 的參數 doc: help: False plugin: name: debug type: module inventory: help: True entries: [] playbook: help: False ansible-builder: help: False workdir: /tmp/ ansible-runner: artifact-dir: ./runner-artifacts rotate-artifacts-count: 10 timeout: 300 job-events: True app: welcome collection-doc-cache-path: $HOME/.cache/ansible-navigator/collection_doc_cache.db color: enable: True osc4: True editor: command: vim console: True enable-prompts: True exec: shell: True command: /bin/bash execution-environment: # 容器引擎：auto (優先使用 podman，其次 docker) container-engine: auto # 傳入容器的額外參數 container-options: - \u0026#34;--net=host\u0026#34; enabled: True environment-variables: set: AWS_PAGER: \u0026#34;\u0026#34; # 指定使用的 Execution Environment 映像檔 image: giuffrelab/awx-community-general-ee:31 pull: policy: missing # 僅在本地不存在時才 pull format: json images: details: - ansible_collections - ansible_version inventory-columns: - ansible_network_os - ansible_network_cli_ssh_type - ansible_connection logging: level: debug append: False file: /tmp/ansible-navigator.log # mode 可設為 stdout（傳統文字輸出）或 interactive（TUI 互動介面） mode: stdout playbook-artifact: enable: True replay: /tmp/test_artifact.json save-as: \u0026#34;{playbook_dir}/{playbook_name}-artifact-{time_stamp}.json\u0026#34; settings: effective: False sample: False schema: json sources: False time-zone: Asia/Taipei 完整設定項目與說明可參考官方文件：Ansible Navigator Settings。\n5. 執行 Playbook 與常用指令 設定完成後，原本使用 ansible-playbook 執行的工作即可改用 ansible-navigator run：\n# 執行 Playbook ansible-navigator run site.yml \\ -i inventory.ini \\ -e \u0026#34;var1=value1\u0026#34; 其他常用子命令 除了執行 Playbook 外，ansible-navigator 亦整合了多項強大功能：\n查閱模組文件： ansible-navigator doc ansible.builtin.copy 檢視目前環境中的 Collections： ansible-navigator collections 檢視 EE 容器映像檔細節： ansible-navigator images 重播先前的執行紀錄（Artifact）： ansible-navigator replay ./runner-artifacts/site-artifact-xxxx.json 結語 透過 ansible-navigator 與 Execution Environment（EE），不僅能將自動化執行環境完全標準化與容器化，更能在不升級目的端老舊主機 Python / PowerShell 的限制下，靈活切換不同版本的 ansible-core 與 Collection，是維護異質環境非常實用且優雅的解決方案。\n","permalink":"https://ansible.cloudns.pro/post/ansible-navigator/using-ansible-navigator/","summary":"\u003cp\u003e隨著 Ansible 版本（\u003ccode\u003eansible-core\u003c/code\u003e）持續升級，除了控制端（Control Node）本身的改進外，Ansible 對受控端（Managed Node / Target Host）的 Python 或 PowerShell 版本要求也隨之提高。\u003c/p\u003e\n\u003cp\u003e如果在企業內部環境中，受限於維運規範無法輕易升級受控端的 Python 或 PowerShell，透過 \u003cstrong\u003eExecution Environment (EE)\u003c/strong\u003e 將特定版本的 Ansible、Python 執行環境與 Collection 封裝在容器中，便能輕鬆維持與舊主機的環境相容性。\u003c/p\u003e\n\u003cp\u003e本文將介紹如何使用 \u003ccode\u003epipx\u003c/code\u003e 安裝 \u003ccode\u003eansible-navigator\u003c/code\u003e、配置設定檔並使用 Execution Environment 執行 Playbook。\u003c/p\u003e","title":"使用 ansible-navigator 與 Execution Environment 執行 Playbook"},{"content":"ansible template 模組的範本可以使用 jinja2 語法，在一般應用上足敷使用，真的要當程式來寫，for 回圈要配置變數時，就會遇到問題了。\n來看看這情境\n{% set data = hostvars | dict2items | rejectattr(\u0026#39;key\u0026#39;, \u0026#39;equalto\u0026#39;, \u0026#39;localhost\u0026#39;) | items2dict %} {% set data_list = [] %} {% for _hostname, _hostvar in data.items() %} {% set data_list = data_list + [{\u0026#39;key\u0026#39;: _hostname, \u0026#39;value\u0026#39;: {\u0026#39;check_result\u0026#39;: \u0026#39;check_result\u0026#39; | extract(_hostvar) }}] %} {% endfor %} {% set final_data = data_list | items2dict %} 預期 data_list 會有結果，但最終結果會發現 data_list 仍然是空的。\n我沒有去翻閱 jinja2 的實作，但我猜測，應該是變數的設置只限於回圈裏面。\n找了好幾篇文章，終於找到可以解決的方式：\nSetting a variable in a loop doesn’t work? Change the value of a variable inside a loop 但要先說這不是官方解法，未來有可能會失效。\n解法是利用 namespace object，一樣用上面當例子，改寫如下\n{% set data = hostvars | dict2items | rejectattr(\u0026#39;key\u0026#39;, \u0026#39;equalto\u0026#39;, \u0026#39;localhost\u0026#39;) | items2dict %} {% set ns = namespace(data_list = []) %} {% for _hostname, _hostvar in data.items() %} {% set ns.data_list = ns.data_list + [{\u0026#39;key\u0026#39;: _hostname, \u0026#39;value\u0026#39;: {\u0026#39;check_result\u0026#39;: \u0026#39;check_result\u0026#39; | extract(_hostvar) }}] %} {% endfor %} {% set final_data = ns.data_list | items2dict %} 利用 namespace object 的寫法，就可以有符合預期的結果了。\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-template-nested-variable/","summary":"\u003cp\u003eansible template 模組的範本可以使用 jinja2 語法，在一般應用上足敷使用，真的要當程式來寫，for 回圈要配置變數時，就會遇到問題了。\u003c/p\u003e","title":"Template 裡 for 回圈內的變數處理"},{"content":"依據 Discovering variables: facts and magic variables 這篇官方的文件， ansible_facts 裡有提供 ansible_lvm，可以查到 LVM 的資訊，但實際上執行以後，卻沒看到。\n找到半天，找到這篇 Why is my logical volume not showing in the ansible_lvm variable? ，才恍然大悟。\n原來，要能收集到這個資訊，需要有 root 的權限才行。\n所以，若連線的身分不是 root，那麼就得用 become: true 切到有足夠權限的身分才行。\ntasks: - name: Gather ansible_lvm facts become: true ansible.builtin.setup: filter: ansible_lvm ","permalink":"https://ansible.cloudns.pro/post/system/ansible_lvm/","summary":"\u003cp\u003e依據 \u003ca href=\"https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_vars_facts.html\"\u003eDiscovering variables: facts and magic variables\u003c/a\u003e 這篇官方的文件，\nansible_facts 裡有提供 ansible_lvm，可以查到 LVM 的資訊，但實際上執行以後，卻沒看到。\u003c/p\u003e","title":"使用 ansible_lvm 要注意的地方"},{"content":"想為 List 裡的每個元素加字串，也就是原本是這樣的 List\nmy_list: - apple - banana - watermelon 要讓輸出結果變為\nnew_list: - \u0026#34;fruit: apple\u0026#34; - \u0026#34;fruit: banana\u0026#34; - \u0026#34;fruit: watermelon\u0026#34; 那該怎麼做呢？有好幾種方式可以作\n第一種方式是用 loop\n- name: Use loop to add string to elements in list hosts: all vars: my_list: - apple - banana - watermelon tasks: - name: Set variable \u0026#39;new_list\u0026#39; ansible.builtin.set_fact: new_list: [] - name: Iterate loop: \u0026#34;{{ my_list }}\u0026#34; ansible.builtin.set_fact: new_list: \u0026#34;{{ new_list + [ \u0026#39;fruit: \u0026#39; + item ] }}\u0026#34; - name: Display ansible.builtin.debug: msg: \u0026#34;{{ new_list }}\u0026#34; 執行以後，可以看到輸出結果的確如想要的結果。\nTASK [Iterate] ******************************************************************************************************************** ok: [localhost] =\u0026gt; (item=apple) ok: [localhost] =\u0026gt; (item=banana) ok: [localhost] =\u0026gt; (item=watermelon) TASK [Display] ******************************************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: [ \u0026#34;fruit: apple\u0026#34;, \u0026#34;fruit: banana\u0026#34;, \u0026#34;fruit: watermelon\u0026#34; ] } 第二種方式是利用 map 搭配 ansible.builtin.regex_replace 這個 filter 來作\n- name: Use loop to add string to elements in list hosts: all vars: my_list: - apple - banana - watermelon tasks: - name: Set variable \u0026#39;new_list\u0026#39; ansible.builtin.set_fact: new_list: [] - name: Iterate ansible.builtin.set_fact: new_list: \u0026#34;{{ my_list | map(\u0026#39;regex_replace\u0026#39;, \u0026#39;(.+)\u0026#39;, \u0026#39;fruit: \\\\1\u0026#39;) | list }}\u0026#34; - name: Display ansible.builtin.debug: msg: \u0026#34;{{ new_list }}\u0026#34; 可以看到輸出結果如下\nTASK [Display] ******************************************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: [ \u0026#34;fruit: apple\u0026#34;, \u0026#34;fruit: banana\u0026#34;, \u0026#34;fruit: watermelon\u0026#34; ] } 跟第一個方式相比，少了一個使用 loop 的 task，簡潔許多。\n參考資料 Searching strings with regular expressions ","permalink":"https://ansible.cloudns.pro/post/tips/tip-add-string-to-elements-in-list/","summary":"\u003cp\u003e想為 List 裡的每個元素加字串，也就是原本是這樣的 List\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003emy_list\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"l\"\u003eapple\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"l\"\u003ebanana\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"l\"\u003ewatermelon\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e要讓輸出結果變為\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003enew_list\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;fruit: apple\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;fruit: banana\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;fruit: watermelon\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e那該怎麼做呢？有好幾種方式可以作\u003c/p\u003e","title":"為 List 裡的每個元素加字串"},{"content":"Ansible 跟 IBM 合作推出了 Watson code assistant 以協助開發者撰寫 Ansible playbook，以下介紹一下怎麼使用。\n安裝方法可以參考這篇：Installing the Ansible VS Code extension\n安裝 Visual Studio Code 執行 Visual Studio Code 從左側選單點選 Extensions ，找 Ansible，然後點選 Install 選單找 File\u0026gt;Preferences\u0026gt;Settings 在搜尋欄輸入 lightspeed 啟用以下項目 勾選 Ansible\u0026gt;Lightspeed 勾選 Ansible\u0026gt;Lightspeed\u0026gt;Suggestion 在左邊選單點選 \u0026ldquo;A\u0026rdquo; 的圖案，再點選 Connect 登入 Red Hat 網站或是 Github 。 這樣就可以使用了。\n","permalink":"https://ansible.cloudns.pro/post/ansible-lightspeed-with-watson-code-assistant/","summary":"Ansible 跟 IBM 合作推出了 Watson code assistant 以協助開發者撰寫 Ansible playbook，以下介紹一下怎麼使用。 安裝方法可以參考這篇：Installing the Ansible VS Code extension 安裝 Visual Studio","title":"Ansible Lightspeed With Watson Code Assistant"},{"content":"要作檔案的複製，可以用 copy ，這會走 SSH 協定；網站檔案上傳，可以用 uri 模組，參數帶入 POST method ，就可以上傳檔案。\n那 FTP 檔案上傳，可以怎麼做呢？\n我自己想到可以用 shell/command 模組，有蠻多指令都可以做到 FTP 上傳的：\nncftp: ncftp 有提供 ncftpput 可以作上傳。 curl: curl 支援 FTP，可以作上傳。 lftp: lftp 指令可以作上傳。 後來在 How PUT file into FTP with Ansible? 看到有網友分享的自製 FTP 模組：ftp - Transfer files and directories from or to FTP server\n所以有蠻多方法可以達成的，提供出來給大家參考。\n","permalink":"https://ansible.cloudns.pro/post/ansible-ftp/","summary":"\u003cp\u003e要作檔案的複製，可以用 copy ，這會走 SSH 協定；網站檔案上傳，可以用 uri 模組，參數帶入 POST method ，就可以上傳檔案。\u003c/p\u003e\n\u003cp\u003e那 FTP 檔案上傳，可以怎麼做呢？\u003c/p\u003e","title":"寫 Ansible playbook 來作FTP上傳"},{"content":"要使用 Ansible 來連到 kubernetes，可以透過 kubernetes.core 這個 collection。\nkubernetes.core 這個 collection 主要是使用 Kubernetes Python Client 這個函式庫，得用 apt install 安裝 python3-kubernetes\nsudo apt install -y python3-kuberentes ansible-galaxy collections install kubernetes.core 接下來就可以寫個 playbook 來取得指定名稱空間裡的 pods\n--- - name: Fetch pod information hosts: localhost tasks: - name: Fetch all pods which are running ansible.builtin.set_fact: deployments_pod: \u0026#34;{{ lookup(\u0026#39;k8s\u0026#39;, kind=\u0026#39;Pod\u0026#39;, namespace=\u0026#39;practice\u0026#39;, wantlist=True) }}\u0026#34; - name: Display deployments_pod when: false ansible.builtin.debug: msg: \u0026#34;{{ deployments_pod | to_json }}\u0026#34; 這樣輸出的結果有點多，這邊要利用 json_query 來整理一下，所以先用 ansible-galaxy 安裝 community.general\nansible-galaxy collection install community.general 然後改寫 playbook 如下\n--- - name: Fetch pod information hosts: localhost tasks: - name: Fetch all pods which are running ansible.builtin.set_fact: deployments_pod: \u0026#34;{{ lookup(\u0026#39;k8s\u0026#39;, kind=\u0026#39;Pod\u0026#39;, namespace=\u0026#39;practice\u0026#39;, wantlist=True) }}\u0026#34; - name: Display deployments_pod ansible.builtin.debug: msg: \u0026#34;{{ deployments_pod | community.general.json_query(\u0026#39;[].metadata.name\u0026#39;) | join(\u0026#39;,\u0026#39;) }}\u0026#34; 透過 json_query ，可以只取出 pod 的名稱出來顯示，這邊加上了 join(',')，將結果用 \u0026lsquo;,\u0026rsquo; 做分隔。\n結果會是這樣子\nPLAY [Fetch pod information] ******************************************************************************************* TASK [Gathering Facts] ************************************************************************************************* ok: [localhost] TASK [Fetch all pods which are running] ******************************************************************************** ok: [localhost] TASK [Display deployments_pod] ***************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;security-context-demo-default,hello-nginx-58f6cb4d7c-ttrrp\u0026#34; } PLAY RECAP ************************************************************************************************************* localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 參考資料 Ansible for Openshift Deployment kubernetes.core.k8s lookup – Query the K8s API ","permalink":"https://ansible.cloudns.pro/post/using-ansible-to-get-pod-kubernetes/","summary":"\u003cp\u003e要使用 Ansible 來連到 kubernetes，可以透過 kubernetes.core 這個 collection。\u003c/p\u003e","title":"用 Ansible 取得 Kubernetes pod 資訊"},{"content":"Angular/Vue 這類的前端框架，在執行 npm run build 建置以後，會產生 dist 的資料夾，裏面就是要佈署的檔案。一般會使用 tar czf dist.tar.gz dist 將該資料夾裡的檔案打包為 tarball。\n使用 Ansible 佈署時，需要使用 unarchive 模組解壓縮，這時會直接解壓縮出 dist 目錄。\n通常解法會有兩種，第一種是在打包時，先進入 dist 資料夾，再進行打包。\n第二種方法就是本文要介紹的小技巧。\n這個小技巧是 Google 找到的，網址在這邊：Extract without first directory\n方法就是利用 unarchive 模組的 extra_opts 參數，因為 tarball 檔案，unarchive 模組會使用 tar 去解壓縮，tar 有個參數：--strip-components=NUMBER ，利用這個參數就可以移除掉前面 NUMBER 層的目錄。\n範例如下\n- name: Extract archive unarchive: src: file.tar.gz dest: /foo/bar extra_opts: - \u0026#34;--strip-components=1\u0026#34; 現在大家就知道可以透過 unarchive 模組的 extra_opts ，帶入解壓縮指令的參數來達到我們的目的了。\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-extract-without-first-directory/","summary":"\u003cp\u003eAngular/Vue 這類的前端框架，在執行 \u003ccode\u003enpm run build\u003c/code\u003e 建置以後，會產生 dist 的資料夾，裏面就是要佈署的檔案。一般會使用 \u003ccode\u003etar czf dist.tar.gz dist\u003c/code\u003e 將該資料夾裡的檔案打包為 tarball。\u003c/p\u003e\n\u003cp\u003e使用 Ansible 佈署時，需要使用 unarchive 模組解壓縮，這時會直接解壓縮出 dist 目錄。\u003c/p\u003e\n\u003cp\u003e通常解法會有兩種，第一種是在打包時，先進入 dist 資料夾，再進行打包。\u003c/p\u003e\n\u003cp\u003e第二種方法就是本文要介紹的小技巧。\u003c/p\u003e","title":"解壓縮只取第二層目錄以下的檔案與目錄"},{"content":"說明 延續之前的安裝，接下來要安裝 microk8s。\n環境有兩個 node，一個 master 一個是 worker。\n安裝kubectl 要在 master 主機上安裝 kubectl。\nUbuntu 可以配置套件庫來安裝\nwget --quiet --output-document - https://packages.cloud.google.com/apt/doc/apt-key.gpg | \\ sudo gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/kubernetes-archive-keyring.gpg --import echo \u0026#34;deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main\u0026#34; | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo chmod 0644 /usr/share/keyrings/kubernetes-archive-keyring.gpg sudo apt install kubectl 要在 master 主機上安裝 kubectl，先登入 master 主機。\ncurl -LO \u0026#34;https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl\u0026#34; sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl 安裝 microk8s 安裝很簡單，在 Ubuntu 裡，可以用 snap 安裝。登入 master 主機以後，輸入以下指令安裝\nsudo snap install microk8s --classic sudo microk8s status --wait-ready 等一段時間，就裝好了。\n為了讓後續有權限，在 master node 跟 worker node 主機裡，把自己加入 microk8s 群組\nsudo usermod -aG microk8s $(whoami) 加完以後，登出，然後再登入。\n再來是加 worker node，先在 master 主機設置 host table，加入 worker 的 IP 與主機名稱對照\necho \u0026#34;\u0026lt;worker_ip\u0026gt; \u0026lt;worker_hostname\u0026gt;\u0026#34; | sudo tee -a /etc/hosts 取得指令\nmicrok8s add-node 這邊會顯示加入的指令，複製有 --worker 那一行。再登入 worker 主機，輸入剛剛取得的指令，這個步驟需要一段時間。\n先回到 master 主機，先取得 kubernetes 設定檔。\nmicrok8s config \u0026gt;~/.kube/config 再使用 kubectl get nodes 察看 node 是否已經加成功。\n這邊如果沒有看到 node ，就表示有問題，可以用以下指令移除 worker node\n移除節點\nmicrok8s leave sudo snap restart microk8s 或者是重新安裝\nsudo snap remove microk8s sudo snap install microk8s --classic 至此，microk8s 就安裝完成了。\n參考資料 使用 MicroK8s 架設 Kubernetes 叢集的完整過程解析 ","permalink":"https://ansible.cloudns.pro/post/awx/install-awx-on-k8s-2/","summary":"\u003ch2 id=\"說明\"\u003e說明\u003c/h2\u003e\n\u003cp\u003e延續之前的安裝，接下來要安裝 microk8s。\u003c/p\u003e\n\u003cp\u003e環境有兩個 node，一個 master 一個是 worker。\u003c/p\u003e","title":"Install AWX on K8S(2)"},{"content":"用來確定檔案裡有指定文字片斷的模組，使用很簡單。\n我們直接用範例來說明，第一個例子是確定 sshd_config 裡有以下文字，如果沒有，先備份檔案，然後把這段文字放進去。\nMatch User ansible-agent PasswordAuthentication no 使用模組時，這樣寫\n- name: Insert/Update \u0026#34;Match User\u0026#34; configuration block in /etc/ssh/sshd_config ansible.builtin.blockinfile: path: /etc/ssh/sshd_config block: | Match User ansible-agent PasswordAuthentication no state: present backup: yes path: 是要處理的檔案路徑 block: 是要安插或移除的文字片斷 state: present 表示要有這段文字，若是 absent ，就是要沒有這段文字。 backup: yes 表示要備份，預設是不備份。 再舉另外一個例子，這是要在 \u0026lt;body\u0026gt; 後面加入這段 HTML\n\u0026lt;h1\u0026gt;Welcome to {{ ansible_hostname }}\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;Last updated on {{ ansible_date_time.iso8601 }}\u0026lt;/p\u0026gt; 使用模組時，這樣寫\n- name: Insert/Update HTML surrounded by custom markers after \u0026lt;body\u0026gt; line ansible.builtin.blockinfile: path: /var/www/html/index.html marker: \u0026#34;\u0026lt;!-- {mark} ANSIBLE MANAGED BLOCK --\u0026gt;\u0026#34; insertafter: \u0026#34;\u0026lt;body\u0026gt;\u0026#34; block: | \u0026lt;h1\u0026gt;Welcome to {{ ansible_hostname }}\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;Last updated on {{ ansible_date_time.iso8601 }}\u0026lt;/p\u0026gt; marker: 在文字片段安插到檔案裡的時候，前後會加上一段註解，marker 就是註解的範本。{mark} 會被替換為 BEGIN 或 END， BEGIN 或 END 可以用 marker_begin, marker_end 來指定。 insertafter: \u0026quot;\u0026lt;body\u0026gt;\u0026quot; 表示要安插在 \u0026lt;body\u0026gt; 之後。 看完這兩個例子，相信你應該會使用這個模組了。\n最後一個要提醒的地方是，如果 playbook 裡有多個 task 都是對同個檔案處理文字片段時，一定要加上 marker ，確保 marker 是不一樣的，否則的話，會導致後面的 task 蓋掉前面 task 所新增的文字片段。\n","permalink":"https://ansible.cloudns.pro/post/blockinfile/","summary":"\u003cp\u003e用來確定檔案裡有指定文字片斷的模組，使用很簡單。\u003c/p\u003e","title":"blockinfile"},{"content":"情境是這樣的，Playbook 在送出 HTTP 請求後，需要送出一個 HTTP 請求去持續詢問是否完成，如果還沒完成，就等待一段時間後，再去詢問，那這個情境下可以怎麼做呢？\n若是寫程式，一般會用一個迴圈持續的去發送 HTTP 請求，取得回傳值以後，看是否完成，若還沒有，就等待一下，重複前面的步驟；若是已經完成就跳離迴圈。\nAnsible playbook 裡的迴圈是變形過的，不太適合這樣做，好在 uri 模組本身已經有提供這種機制。\n下面直接看範例\n--- - name: Playbook for Web automation hosts: localhost tasks: - name: Check if API is available and returning status 200 uri: url: https://\u0026lt;api-server\u0026gt;/api/status register: result until: \u0026#34;result.status == 200\u0026#34; retries: 5 delay: 10 這會對 https:///api/status 這個端點發送 HTTP 請求，然後看回應的狀態碼是否為 200 ，若不是，就重試 5 次，每次間隔 10 秒。\n上面範例是使用 GET，那如果是用 POST，又該怎麼寫？\n- name: Playbook for Web automation hosts: localhost tasks: - name: Wait for API endpoint to return 201 created uri: url: \u0026#34;https://\u0026lt;api-server\u0026gt;/api/users\u0026#34; method: POST body: |- { \u0026#34;name\u0026#34;: \u0026#34;John\u0026#34;, \u0026#34;Location\u0026#34;: \u0026#34;Taiwan\u0026#34; } return_content: yes status_code: 201 register: uri_result until: \u0026#34;uri_result.status == 201\u0026#34; retries: 5 delay: 10 - debug: var: uri_result.content 這邊就是對 https:///api/users 發送 HTTP 請求，然後看回應的狀態是否為 201，若不是，就重試 5 次，每次間隔 10 秒。\nuntil 裡也可以使用回傳回來的 JSON 內容來做檢查，例如\n- name: Playbook for Web automation hosts: localhost tasks: - name: Wait for API endpoint to return token uri: url: \u0026#34;https://\u0026lt;api-server\u0026gt;/api/login\u0026#34; method: POST body_format: json body: |- { \u0026#34;name\u0026#34;: \u0026#34;John\u0026#34;, \u0026#34;password\u0026#34;: \u0026#34;password\u0026#34; } return_content: yes register: uri_result until: \u0026#34;\u0026#39;token\u0026#39; in uri_result.content\u0026#34; retries: 5 delay: 10 - debug: var: uri_result.content 這邊就是檢查回傳內容是否有 \u0026rsquo;token'\n透過以上的範例，相信你已經知道\nuri 模組可以用來存取 Web API 或是某個網址。 透過 retry until 的組合，可以用來驗證結果，並持續重試直到滿足條件。 參考資料 Ansible Wait for URL to respond or Retry ansible.builtin.uri module – Interacts with webservices — Ansible Documentation ","permalink":"https://ansible.cloudns.pro/post/wait-for-url-to-respond-or-retry/","summary":"\u003cp\u003e情境是這樣的，Playbook 在送出 HTTP 請求後，需要送出一個 HTTP 請求去持續詢問是否完成，如果還沒完成，就等待一段時間後，再去詢問，那這個情境下可以怎麼做呢？\u003c/p\u003e","title":"等待 API 回應完成"},{"content":"在撰寫 Playbook 時，難免會用到敏感性的資訊，Ansible 提供了 ansible-vault 這個工具，可以針對檔案或是字串來做加密。\n如果變數內容需要加密的話，該怎麼使用呢？\n舉個例子，假設 playbook 或 inventory 裏面的 foo 這個變數的內容 \u0026ldquo;password123\u0026rdquo; 需要加密，那麼要先使用 ansible-vault 來加密字串。\nansible-vault encrypt_string password123 --ask-vault-pass 執行以後，會詢問 vault 的密碼，這個密碼是在後續執行 playbook 時會用到解密的鑰匙。\n詢問完密碼，就會輸出這些內容\n!vault | $ANSIBLE_VAULT;1.1;AES256 66333264313637393563336433623136303366613464643938643133643234386664383738336139 6536653132383166333736386130383264373230643734650a633235643336643536336163663864 61303063376639643139643331306133313533326463616635323838333733653862613736333430 6366373436343532340a313137336138383135343336333538656161666134303132653936656331 3131 Encryption successful 複製起來，把內容貼到 playbook 或 inventory 裡\n--- - name: Test vault hosts: all vars: foo: !vault | $ANSIBLE_VAULT;1.1;AES256 66333264313637393563336433623136303366613464643938643133643234386664383738336139 6536653132383166333736386130383264373230643734650a633235643336643536336163663864 61303063376639643139643331306133313533326463616635323838333733653862613736333430 6366373436343532340a313137336138383135343336333538656161666134303132653936656331 3131 tasks: - debug: var: foo 然後在執行時，需要指定 --ask-vault-pass\nansible-playbook -i localhost, -c local --ask-vault-pass test-vault.yml 那這邊還有些變形的用法，後續整理好，再來分享。\n參考資料 Ansible: How to encrypt some variables in an inventory file in a separate vault file? ","permalink":"https://ansible.cloudns.pro/post/encrypt-string-using-vault/","summary":"\u003cp\u003e在撰寫 Playbook 時，難免會用到敏感性的資訊，Ansible 提供了 ansible-vault 這個工具，可以針對檔案或是字串來做加密。\u003c/p\u003e\n\u003cp\u003e如果變數內容需要加密的話，該怎麼使用呢？\u003c/p\u003e","title":"使用ansible-Vault加密字串"},{"content":"以前我不知道有 script 模組，所以要執行自己的腳本，都是先把腳本複製過去，再用 shell/command 去執行。\n有了 script 模組，就不需要這麼麻煩了，他會幫你處理掉複製腳本的事情。\nPlaybook 範例如下\n--- - name: Test script module hosts: all tasks: - name: Script script: ./scripts/hello.sh John register: shell_result - debug: var: shell_result.stdout_lines 然後在 scripts 目錄下放一個 hello.sh 的腳本，hello.sh 這個腳本會印出 Hello 的字串。\n執行這個 playbook 以後，就會看到結果\nPLAY [Test script module] ********************************************************************************************** TASK [Gathering Facts] ************************************************************************************************* ok: [192.168.11.11] TASK [Script] ********************************************************************************************************** changed: [192.168.11.11] TASK [debug] *********************************************************************************************************** ok: [192.168.11.11] =\u0026gt; { \u0026#34;shell_result.stdout_lines\u0026#34;: [ \u0026#34;Hello John\u0026#34; ] } PLAY RECAP ************************************************************************************************************* 192.168.11.11 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 這樣就方便多了，不需要先複製，再執行。\n參考資料 ansible.builtin.script module – Runs a local script on a remote node after transferring it — Ansible Documentation ","permalink":"https://ansible.cloudns.pro/post/script/","summary":"\u003cp\u003e以前我不知道有 script 模組，所以要執行自己的腳本，都是先把腳本複製過去，再用 shell/command 去執行。\u003c/p\u003e","title":"Script"},{"content":"使用模組常遇到的情況是不知道傳回來的變數是什麼型態，後續使用就不知道怎麼用。\n在這個時候可以怎麼做呢？\n在這個時候可以使用 type_debug 這個 filter 來顯示。\n- debug: msg: \u0026#34;{{ item|type_debug }}\u0026#34; loop: - \u0026#34;Foo\u0026#34; - 123 - [] - name: foo 結果會是\nTASK [debug] ************************************************************************************ ok: [localhost] =\u0026gt; (item=Foo) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;AnsibleUnicode\u0026#34; } ok: [localhost] =\u0026gt; (item=123) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;int\u0026#34; } ok: [localhost] =\u0026gt; (item=[]) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;list\u0026#34; } ok: [localhost] =\u0026gt; (item={\u0026#39;name\u0026#39;: \u0026#39;foo\u0026#39;}) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;dict\u0026#34; } 額外分享一個技巧，若需要依據變數型態來顯示的話，可以用\n- set_fact: case: int: \u0026#34;tasks-int\u0026#34; AnsibleUnicode: \u0026#34;tasks-str\u0026#34; list: \u0026#34;tasks-list\u0026#34; dict: \u0026#34;tasks-dict\u0026#34; default: \u0026#34;tasks-default\u0026#34; - set_fact: v: \u0026#34;foo\u0026#34; - debug: msg: \u0026#34;{{ case[v|type_debug] }}\u0026#34; 參考資料 Type tests Ansible - check variable type ","permalink":"https://ansible.cloudns.pro/post/tips/tip-check-variable-type/","summary":"\u003cp\u003e使用模組常遇到的情況是不知道傳回來的變數是什麼型態，後續使用就不知道怎麼用。\u003c/p\u003e\n\u003cp\u003e在這個時候可以怎麼做呢？\u003c/p\u003e","title":"小技巧-檢查變數型態"},{"content":"Ansible 可以透過 WinRM 連線到 Windows 主機進行操作，這部份的設置可以參考 Setting up a Windows Host\n這篇文章裡，有一部份是我之前沒注意到的，就是 Windows 主機除了可以用 WinRM 之外，也可以用 SSH 來操作。\n在 Windows Server 2019 以後，Microsoft 也提供了 OpenSSH Server 的功能，讓 IT 人員可以安裝。在安裝上去以後，就可以使用 SSH 來連線操作。\nMicrosoft 提供了如何安裝的說明文件：Install OpenSSH for Windows\n開啟「設定」(Settings)，選擇「應用程式」(App)，再選擇「選用功能」(Optional Features)。 找 OpenSSH server 來安裝。 裝好以後，OpenSSH 服務會自動啟動，防火牆 22 也會啟用。\n接下來就可以用 ssh 來測試，沒加入 AD 的話，domain 可以不用輸入。\nssh domain\\username@servername ssh username@servername 如果是 Windows 2019 以前的版本，可以從 PowerShell Win32-OpenSSH 這邊下載 .msi 來安裝 PowerShell/Win32-OpenSSH github\n同樣也是裝好以後，OpenSSH 服務會自動啟動，防火牆 22 也會啟用。\n接下來是講 Ansible 需要注意的事情。\n預設的 shell 是使用 cmd，照文件說，若需要修改，是要改 ansible_shell_type 變數，這應該是要在 inventory 主機裡加入主機變數：ansible_shell_type，變數內容可以是 cmd 或 powershell。 inventory 主機裡要加入 ansible_connection 主機變數，告知要使用 ssh 連線。 可能會需要在 ansible.cfg 裡加上 remote_tmp 設定，指定為 C:\\TEMP inventory 裡會是這樣\n192.168.192.11 ansible_user=Administrator ansible_connection=ssh ansible_shell_type=cmd Playbook 裡可以使用 win_ 開頭的模組，或是使用 raw 模組\n--- - name: Windows Server Automation hosts: all gather_facts: no tasks: - name: shell raw: | powershell -executionpolicy bypass -File d:\\script\\du.ps1 register: shell_result - debug: var: shell_result.stdout - name: ping win_ping - name: win_shell win_shell: | help register: shell_result - debug: var: shell_result.stdout 使用 OpenSSH 的設置方式比使用 WinRM 簡單多了，而且在 Windows Server 2019 以後的版本都可以安裝，以後 Ansible 要控制 Windows 主機就更簡單了。\n","permalink":"https://ansible.cloudns.pro/post/windows-ssh-setup/","summary":"\u003cp\u003eAnsible 可以透過 WinRM 連線到 Windows 主機進行操作，這部份的設置可以參考 \u003ca href=\"https://docs.ansible.com/ansible/latest/os_guide/windows_setup.html\"\u003eSetting up a Windows Host\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e這篇文章裡，有一部份是我之前沒注意到的，就是 Windows 主機除了可以用 WinRM 之外，也可以用 SSH 來操作。\u003c/p\u003e","title":"Windows SSH setup"},{"content":"最近需要連到遠端主機取得截圖，那就在想是不是有方法可以做到？\n稍微找了網路的資訊，很快就找到可以使用 ImageMagick 來轉換文字為圖片，那麼就可以用 Ansible 了。\n首先為了避免每台主機都安裝 ImageMagick，所以是在執行 ansible-playbook 的主機，也就是本機上安裝 ImageMagick，然後再連線到遠端執行指令，取得指令輸出後，再到本機用 ImageMagick 來轉換。\n依據上述的邏輯，很快就可以寫出 playbook 如下：\n--- - name: Capture command output and convert to image hosts: all tasks: - name: Display content of /etc/redhat-release shell: cat /etc/redhat-release register: redhat_release_result - name: hostname shell: hostname register: hostname_result - name: Convert command output as image shell: echo -e \u0026#34;{{ hostname_result.stdout }}\\n{{ redhat_release_result.stdout }}\u0026#34; | convert label:@- {{ hostname_result.stdout }}.png delegate_to: localhost 參考資料 ＊ How To Save Linux Command Output To An Image Or A Text File\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-command-output-to-image/","summary":"\u003cp\u003e最近需要連到遠端主機取得截圖，那就在想是不是有方法可以做到？\u003c/p\u003e","title":"將指令輸出轉為圖片"},{"content":"在 Ansible Automation Controller 可以將日誌發送到其他的日誌聚合主機上，目前支援的日誌類型有\nLogstash splunk loggly sumologic other 這篇主要是說明 Logstash 該如何設置。\n假設 這篇文章假設你已經架設好 ElasticSearch ，而且使用的是 RHEL8。\n安裝 Logstash 首先是安裝 logstash，logstash 的安裝很簡單，新增 /etc/yum.repos.d/elasticsearch.repo\n[elasticsearch-7.x] name=Elasticsearch repository for 7.x packages baseurl=https://artifacts.elastic.co/packages/oss-7.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=1 autorefresh=1 type=rpm-md 輸入以下指令安裝 logstash\nsudo yum install -y logstash 預設的 elasticsearch plugin 有版本匹配問題，需要改用 logstash-output-opensearch plugin\n/usr/share/logstash/bin/logstash-plugin install logstash-output-opensearch 新增 /etc/logstash/conf.d/pipeline.conf\ninput { tcp { port =\u0026gt; 5044 codec =\u0026gt; line } } filter { json { source =\u0026gt; \u0026#34;message\u0026#34; } } output { opensearch { hosts =\u0026gt; [\u0026#34;http://\u0026lt;elasticsearch_server\u0026gt;:9200\u0026#34;] index =\u0026gt; \u0026#34;aap-%{+YYYY.MM.dd}\u0026#34; #user =\u0026gt; \u0026#34;elastic\u0026#34; #password =\u0026gt; \u0026#34;changeme\u0026#34; } stdout {} } 設定說明如下\nlog 轉發的這類服務，都是以 pipeline 形式來設定，所以會有 input -\u0026gt; filter -\u0026gt; output input 使用 TCP，並 listen 5044；codec 可以選 line 或 json，automation controller 送出的格式是 line。 filter 使用 json 來解析 message 這個欄位，因為 message 這欄位裡是 json 格式的字串。 output 輸出到 opensearch，index 指定為 aap-\u0026lt;日期\u0026gt; ；在 Kibana 裡建立索引時，就是使用 aap-* 來作為 pattern 設定完成後，啟用服務\nsystemctl enable --now logstash 啟動後要等一下，因為要啟動 JVM 來執行 JRuby，這段時間可以使用 journalctl 來檢查輸出\njournalctl -u logstash -f Automation controller 的設置 完成 Logstash 安裝與啟用以後，到 Automation Controller 裡，從左邊選「設置」，右邊選「日誌」，點選「編輯」\n日誌紀錄聚合器，填入主機名稱或是 IP 日誌紀錄聚合器端口，填入 5044 ，這個 port 號碼就是前面 logstash 設定 input 裡所指定的。 日誌紀錄聚合器類型，選擇 Logstash 日誌紀錄聚合器協議，選擇 TCP 設定好以後，存檔，這樣就大功告成了。\n參考資料 How to Install ELK Stack on RHEL 8 / CentOS 8 How to Setup Multi Node Elastic Stack Cluster on RHEL 8 / CentOS 8 OSS Logstash 7.16.1 incompatible with Elasticsearch 7.10.2 logstash-output-opensearch Introduction to Logstash TCP input JSON filter plugin ","permalink":"https://ansible.cloudns.pro/post/ansible-automation-platform/send-log-to-logstash/","summary":"\u003cp\u003e在 Ansible Automation Controller 可以將日誌發送到其他的日誌聚合主機上，目前支援的日誌類型有\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eLogstash\u003c/li\u003e\n\u003cli\u003esplunk\u003c/li\u003e\n\u003cli\u003eloggly\u003c/li\u003e\n\u003cli\u003esumologic\u003c/li\u003e\n\u003cli\u003eother\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e這篇主要是說明 Logstash 該如何設置。\u003c/p\u003e","title":"Logstash 的安裝設定與日誌的轉送"},{"content":"資料來源：\nOn-Demand execution with Red Hat OpenShift How to setup an OpenShift container group with AAP Ansible Automation platform 裡的 Automation controller 在執行 playbook 時，已經改用 execution environment (執行環境)這個容器來執行了，換言之，若有建置 OpenShift 的話，應該也可以使用 OpenShift 的運算資源來運行執行環境。\n資料來源的文章就是在介紹設定的方法。\n首先到 OpenShift ，建置新的 Project\noc new-project ansible-automation 然後建立服務帳號跟配置權限\noc create serviceaccount aap-sa oc adm policy add-role-to-user edit -z aap-sa 若需要更細部的權限控制，可以自己建立 Role，先將以下內容命名為 aap-sa-role.yml，然後 apply: oc apply -f aap-sa-role.yml\nkind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: aap-sa-role namespace: ansible-automation rules: - apiGroups: - \u0026#34;\u0026#34; resources: - pods/exec - pods/attach - pods - secrets verbs: - get - list - watch - create - delete - update 將 aap-sa 這個服務帳號跟 aap-sa-role 這個 role 做連結\noc adm policy add-role-to-user aap-sa-role -z aap-sa 然後取得服務帳號的 token\noc serviceaccounts get-token aap-sa 回到 Automation controller，先登入，在左邊選單裡選到 Credentials，新增 credential\nName 填 \u0026ldquo;OCP service account\u0026rdquo; Credential type 選 \u0026ldquo;OpenShift on Kubernetes API Bearer token\u0026rdquo; API authentication bearer token 填前面取得的「服務帳號 token」 接著到 Instance groups ，選擇新增 Container group。\nName 填 OCP Credential 選剛剛建立的 \u0026ldquo;OCP service account\u0026rdquo; Custom pod spec 內容如下 apiVersion: V1 kind: Pod metadata: namespace: ansible-automation spec: serviceAccount: aap-sa containers: - name: worker args: - ansible-runner - worker - \u0026#39;--private-data-dir=/runner\u0026#39; 儲存以後，接著要設定 Job template ，把裡面的 instance group 選為剛剛建立的 \u0026ldquo;OCP\u0026rdquo; container group。 試著執行 Job template，Automation controller 就會到 OpenShift 建立 execution environment 的 pod 來執行了。\n現在已經可以在 OpenShift 裡運行 execution environment ，那麼是不是可以再多利用 OpenShift 的能力，多開幾個 pod，就可以同時處理了呢？ 可以的喔，只要在 Job template 裡的 job slicing 指定數量，Automation controller 就會在 OpenShift 裡去建立指定數量的 pod 來運行 execution environment。\nAutomation controller 搭配 OpenShift/Kubernetes 這類的容器平台以後，就可以使用容器平台的運算能力來提升 Automation controller 在執行 playbook 的效能，就不再受限於主機的能力了。\n","permalink":"https://ansible.cloudns.pro/post/ansible-automation-platform/on-demand-execution-with-red-hat-openshift/","summary":"\u003cp\u003e資料來源：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.ansible.com/blog/on-demand-execution-with-red-hat-openshift\"\u003eOn-Demand execution with Red Hat OpenShift\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.automate.nyc/ansible/aap-container-group/\"\u003eHow to setup an OpenShift container group with AAP\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAnsible Automation platform 裡的 Automation controller 在執行 playbook 時，已經改用 execution environment (執行環境)這個容器來執行了，換言之，若有建置 OpenShift 的話，應該也可以使用 OpenShift 的運算資源來運行執行環境。\u003c/p\u003e\n\u003cp\u003e資料來源的文章就是在介紹設定的方法。\u003c/p\u003e","title":"使用 Red Hat OpenShift 來作為執行環境的平台"},{"content":"在推特上看到有人分享這篇：Deploy Percona Server for MongoDB Replica Set With Ansible - Percona Database Performance Blog，覺得挺值得參考的。\n你能學到什麼？\n依據不同 Linux 發行版以及 host var 來執行相對應的 task 配置 Inventory 與加上 host vars 配置 group vars 文章裡所有的檔案都在 Github Gist: Deploy Percona Server for MongoDB Replica set with Ansible 從 main.yml 裡可以看到佈署流程如下：\n下載 rpm 或是 deb 安裝下載好的 rpm/deb 使用預先寫好的 template 來配置 mongod 配置 ssl key 與使用者 應用 shell 來啟動服務 下次若是需要配置 mongodb 的時候，就可以參考這份 playbook 來做了。\np.s. 順便 fork 一份在自己的 github 裡，作為備用。 https://gist.github.com/elleryq/933381a96155708e944079d76d2f7048\n","permalink":"https://ansible.cloudns.pro/post/database/deploy-percona-server-for-mongodb-replica-set/","summary":"\u003cp\u003e在推特上看到有人分享這篇：\u003ca href=\"https://www.percona.com/blog/deploy-percona-server-for-mongodb-replica-set-with-ansible/\"\u003eDeploy Percona Server for MongoDB Replica Set With Ansible - Percona Database Performance Blog\u003c/a\u003e，覺得挺值得參考的。\u003c/p\u003e\n\u003cp\u003e你能學到什麼？\u003c/p\u003e","title":"Deploy Percona Server for Mongodb Replica Set"},{"content":"Terrible 不是「糟糕」的意思，而是 Terraform + Ansible = TERRAform to ansiBLE 。\n簡單的說，是可以從 terraform state 檔案產出 inventory 的工具。\n安裝 安裝使用 pip 就可以安裝\n# Ubuntu sudo apt install python3-pip # RHEL sudo yum install python3-pip # pip pip install terrible 使用 Ansible 要使用，就在 inventory 資料夾裡，建立一個 shell script，內容如下\n#!/usr/bin/env bash terrible \u0026#34;$@\u0026#34; 就可以了。Ansible 專案的參考目錄佈局如下\n. ├── ansible.cfg ├── inventory │ ├── group_vars │ └── terrible ├── playbooks │ └── site.yml ├── requirements.yml ├── roles │ └── example_role └── terraform ├── terraform.tf ├── terraform.tfstate ├── terraform.tfvars └── variables.tf 結語 最後再去看了一下 github 上最後的 commit 時間以及 pypi 網站上的時間，發現已經是8年前，看起來是失修了，若要使用，可能需要自行修改 terrible 的原始碼才能使用。\nTerrible terrible on PyPI terrible on GitHub ","permalink":"https://ansible.cloudns.pro/post/terrible/","summary":"\u003cp\u003e\u003ca href=\"https://terrible.readthedocs.io/en/latest/readme.html\"\u003eTerrible\u003c/a\u003e 不是「糟糕」的意思，而是 Terraform + Ansible = TERRAform to ansiBLE 。\u003c/p\u003e\n\u003cp\u003e簡單的說，是可以從 terraform state 檔案產出 inventory 的工具。\u003c/p\u003e","title":"Terrible"},{"content":"上週在測試 playbook 時，發現 become 行為不如我預期。\n我的 playbook 是這樣寫\n--- - name: Main hosts: ap_servers become_user: jbossadm roles: - role: deploy.jboss become_user: jbossadm deploy.jboss 這個 role 裡的 task ，我使用 shell 模組執行 whoami\n--- - name: whoami shell: whoami 我連線到指定主機的使用者是 jenkins，可以切換為 jbossadm 身份。那我在執行以後，卻發現 whoami 仍然顯示為 jenkins，我百思不得其解。\n經過詢問同事以後，才知道我的認知是錯的，我以為寫了 become_user: jbossadm 就會有切換使用者的效果，但實際不然，還需要加上 become 與 become_method 才會有效果。所以正確的寫法應該是\n--- - name: Main hosts: ap_servers roles: - role: deploy.jboss become_user: jbossadm become_method: sudo become: yes 這樣才會是正確的。\n參考資料 同事 Understanding privilege escalation: become ansible的become ","permalink":"https://ansible.cloudns.pro/post/ansible-become-in-role/","summary":"\u003cp\u003e上週在測試 playbook 時，發現 become 行為不如我預期。\u003c/p\u003e","title":"Ansible Become in role"},{"content":"簡單的說，Ansible facts 是 Ansible 連線到主機時所收集的資訊，這些資訊可以在後續 Playbook 裏面使用，資訊很多，像是主機名稱、IP等等的。\n在單獨使用 ansible 執行 ad-hoc 命令時，可以用 setup 模組來收集。\nansible -i \u0026lt;your_inventory\u0026gt; -m setup \u0026lt;host\u0026gt; 執行以後，會輸出很多資訊，你可以先導向到特定檔案再來檢視，例如：\nansible -i 192.168.19.19, -m setup all \u0026gt;/tmp/my_file 在執行 Playbook 時，預設就會執行 setup 來收集資訊，若是想加快速度，可以不收集這些資訊\n--- - name: Example 1 hosts: all gather_facts: no tasks: - debug: msg: \u0026#34;Example\u0026#34; 那麼已經收集以後，該怎麼使用這些資訊呢？只要參考 ansible -m setup 的輸出，看有哪些變數，就可以直接使用，例如\n--- - name: Example 2 hosts: all gather_facts: yes tasks: - debug: msg: \u0026#34;IP 位址：{{ ansible_default_ipv4.address }}\u0026#34; 小技巧，因為變數眾多，有時會需要知道變數是哪種型態，這時候可以用 type_debug 來顯示出型態。\n- name: Example 3 hosts: all gather_facts: yes tasks: - debug: msg: \u0026#34;ansible_default_ipv4 的變數型態是 {{ ansible_default_ipv4 | type_debug }}\u0026#34; 執行以後，可以看到輸出結果如下\n... 省略 ... TASK [debug] ******************************************************************* ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;ansible_default_ipv4 的變數型態是 dict\u0026#34; } ... 省略 ... 變數型態有 list, dict, AnsibleUnsafeText。\nAnsibleUnsafeText 就是字串，list/dict 可以搭配 loop 來做使用。\n透過 Facts，在 Playbook 撰寫上就可以省掉取得主機資訊的 tasks，直接就可以作使用，例如可以依據主機的 Linux 發行版來決定要執行什麼工作；或者是取得 IP 位址做設定。\n在 Ansible automation platform 使用時，也可以使用這些資訊來做篩選。Ansible automation platform 的 Inventory 有分為兩種，一種是一般的 Inventory，另外一種則是 Smart Inventory 。\n什麼是 Smart Inventory 呢？Smart Inventory 是基礎於已經設置好的主機，加上篩選條件，篩選出符合條件的主機，就不需要再另外新增 Inventory。\n篩選條件就可以依據 facts 來做設置，所以可以篩選出所有 Linux 發行版是 RHEL8.6 的主機，或是 Linux 發行版是 Ubuntu 的主機。\n所以，去了解並善用 ansible facts 已經收集的資訊可以讓你在撰寫 Ansible playbook 上更加輕鬆。\n參考資料 Ansible Facts and How to use them – Ansible Variable list ","permalink":"https://ansible.cloudns.pro/post/ansible-facts/","summary":"\u003cp\u003e簡單的說，Ansible facts 是 Ansible 連線到主機時所收集的資訊，這些資訊可以在後續 Playbook 裏面使用，資訊很多，像是主機名稱、IP等等的。\u003c/p\u003e","title":"Ansible Facts"},{"content":"Ansible 2.4 以後引入了 include_tasks 與 import_tasks ，那這兩者的差異在哪裡呢？\n在 Ansible 的文件網站裡有說明這部份\nIncludes vs Imports Dynamic vs Static 另外也可參閱：What\u0026rsquo;s the difference between include_tasks and import_tasks?\n簡單的說明如下：\nIncludes 是動態的，執行到中途，再去載入，所以可以搭配變數做出變化，含括不同的檔案。例如\n- include_tasks: prerequisites_{{ ansible_os_family | lower }}.yml 限制如下\n--list-tags 無法顯示被含括檔案裡的 tags --list-tasks 無法顯示被含括檔案裡的 tasks 無法使用通知去觸發被含括檔案裡的 handler 如果打算起始的 task 是在被含括檔案裡的話，那麼無法使用 --start-at-task 來指定起始的 task Imports 是靜態的，在執行前就載入了，這就無法搭配變數做出變化。\n- import_tasks: prepare_filesystem.yml - import_tasks: install_prerequisites.yml - import_tasks: install_application.yml 限制如下\n無法搭配 with_* 或 loop 來使用 無法引入檔名相依於變數的檔案。 這兩種方法各有其優缺點， What\u0026rsquo;s the difference between include_tasks and import_tasks? 的這個回覆就說明的很仔細\n我自己目前是都使用 include_tasks 比較多，未來應該要好好想一想，什麼時候用 import_tasks 會比較好些。\n","permalink":"https://ansible.cloudns.pro/post/difference-between-include-and-import/","summary":"\u003cp\u003eAnsible 2.4 以後引入了 include_tasks 與 import_tasks ，那這兩者的差異在哪裡呢？\u003c/p\u003e","title":"include_tasks 與 import_tasks 的差異"},{"content":"Red Hat 在推出 Ansible Automation Platform 2.0 版以後，同時也推出了 Upgrade assistant 來提供升級的步驟與建議。\n要使用 Upgrade assistant ，你必須要有 Red Hat developer account，登入以後才能使用。\n網址：Ansible Automation Platform Upgrade assistant\n使用方法很簡單，在 Current version 選擇目前的版本，然後在 Target version 選擇要升級過去的版本，按下 Next。 選擇以後若無法按下 Next，會有訊息提示你為什麼無法升級。\n按下 Next 以後，會告訴你哪些功能在新的版本裡已經被移除了。選擇已經閱讀以後，再按下 Next ，會告訴你該做的事情，像是 Release note、備份、資料庫需求等資訊。\n再來會詢問環境資訊，\n最後就會告知步驟。\nRed Hat 提供這樣的工具，提供了升級 Ansible Automation Platform 的建議，讓我們可以不用自己去看文件去摸索，還蠻方便的。\n希望 Red Hat 其他的產品像是 Satellite 、OpenShift Container platform 也有這樣的升級工具可以使用。\n","permalink":"https://ansible.cloudns.pro/post/ansible-automation-platform/upgrade-assistant/","summary":"\u003cp\u003eRed Hat 在推出 Ansible Automation Platform 2.0 版以後，同時也推出了 Upgrade assistant 來提供升級的步驟與建議。\u003c/p\u003e","title":"Ansible Automation Platform Upgrade assistant"},{"content":"Red Hat Ansible automation platform 引入了 Execution Environment ，Execution Environment 說穿了，就是包著 Ansible 執行環境的容器映像。 原本裏面有的 Automation hub 軟體可以怎麼跟 Execution Environment 結合呢?\n資料來源：8 private automation hub features about execution environments\n第一個是 Registry，可以用來存放 Execution Environment 容器映像。這部份主要是使用 pulp container registry 來做的，目前只支援存放 Execution Environment 容器映像。\n第二個是定義 Remote registry，類似 Mirror registry 或是 Proxy 的概念，當 Automation controller 或 execution node 跟 Automation hub 拉取 Execution Environment 容器映像時，會先看本地端有沒有，若沒有再去 remote registry 拉取。\n第三個是為 Remote registry 建立索引，主要是方便存取 Remote registry 用的。\n第四個是 Mirror 容器映像。\n第五個是提供稽核軌跡，當有推送或是有變動時，在 Automation hub 裡看得到。\n第六個是提供拉取容器映像的指令。\n第七個是在點選 \u0026ldquo;Use in controller\u0026rdquo; 後，會驅動 Automation controller 去拉取 Automation hub 上的 Execution Environment 容器映像。\n第八個是 RBAC。\n從 2.1 以後的 Automation hub 附加了 container registry，以便讓 Automation controller 能拉取 Execution Environment 容器映像，這樣就不需要自行用 docker registry 或是 harbor 來架設 registry 伺服器，讓整個 Ansible automation platform 更為完整。\n","permalink":"https://ansible.cloudns.pro/post/ansible-automation-platform/automation-hub/","summary":"\u003cp\u003eRed Hat Ansible automation platform 引入了 Execution Environment ，Execution Environment 說穿了，就是包著 Ansible 執行環境的容器映像。\n原本裏面有的 Automation hub 軟體可以怎麼跟 Execution Environment 結合呢?\u003c/p\u003e","title":"Automation Hub 的8個跟 Execution environment 相關的功能"},{"content":"因為之前寫程式的經驗，很直覺的想可以在 block 加上 loop，像這樣\n- set_fact: user_list: - John - Mary - Jane - block: - debug: msg: \u0026#34;start of loop\u0026#34; - debug: msg: \u0026#34;Hello {{ item }}\u0026#34; - debug: msg: \u0026#34;end of loop\u0026#34; loop: \u0026#34;{{ user_list }}\u0026#34; 但很遺憾，不能這樣使用，Ansible 會抱怨你使用了錯誤的語法。\n後來才找到可以用另外一種寫法來做到：How to loop blocks of code in Ansible\n作法是這樣的，把 block 裡的 tasks 搬到另外一個 yaml 檔案裡，例如 block1.yml\n--- # block1.yml - debug: msg: \u0026#34;start of loop\u0026#34; - debug: msg: \u0026#34;Hello {{ item }}\u0026#34; - debug: msg: \u0026#34;end of loop\u0026#34; 然後原來的回圈改用 include_tasks\n- set_fact: user_list: - John - Mary - Jane - include_tasks: block1.yml loop: \u0026#34;{{ user_list }}\u0026#34; 雖然需要拆分到另外一個檔案，但改寫為這樣就達到目的了。\n","permalink":"https://ansible.cloudns.pro/post/block-with-loop/","summary":"\u003cp\u003e因為之前寫程式的經驗，很直覺的想可以在 block 加上 loop，像這樣\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e- \u003cspan class=\"nt\"\u003eset_fact\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003euser_list\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003eJohn\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003eMary\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"l\"\u003eJane\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e- \u003cspan class=\"nt\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"nt\"\u003edebug\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003emsg\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;start of loop\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"nt\"\u003edebug\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003emsg\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Hello {{ item }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"nt\"\u003edebug\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003emsg\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;end of loop\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eloop\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ user_list }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"如何把 block 放在回圈裡？"},{"content":"之前想要產生一堆使用者，例如 user01, user02, user03\u0026hellip; ，那時候在想用 with_items 或 loop 要怎麼做？好像沒有好的方法，找了好一會，才在 Ansible 文件裡找到，原來 Ansible 已經有內建序列可以這樣用了。\n序列的用法可以參考這裡：ansible.builtin.sequence lookup – generate a list based on a number sequence\n只要在 task 加上 with_sequence ，就可以了。\n以文件裡的例子來說明，\n- name: create some test users ansible.builtin.user: name: \u0026#34;{{ item }}\u0026#34; state: present groups: \u0026#34;evens\u0026#34; with_sequence: start=0 end=32 format=testuser%02x 這主要是使用 user 模組來建立測試使用者\nwith_sequence 表示要使用 sequence，後面的 start, end, format 是參數 start 表示從 0 開始 end 表示到 32 就結束 format 表示要格式化為 user00, user01, user02 這樣子，所以 item 內容就是 user00, user01, user02\u0026hellip; 如果是要間隔 2，類似 2, 4, 6, 8 的話，可以用 stride，例如\n- debug: msg: \u0026#34;{{ item }}\u0026#34; with_sequence: start=0 end=10 stride=2 format=\u0026#34;hello %02d\u0026#34; 最後要說的參數是 count，這個參數不能跟 end 一起用，count 主要是指要有 10 個，例如\n- debug: msg: \u0026#34;{{ item }}\u0026#34; with_sequence: start=0 count=10 stride=2 format=\u0026#34;hello %02d\u0026#34; 這樣會出現 \u0026ldquo;hello 00\u0026rdquo;, \u0026ldquo;hello 02\u0026rdquo;, \u0026ldquo;hello 04\u0026rdquo;, \u0026ldquo;hello 06\u0026rdquo;, \u0026hellip; \u0026ldquo;hello 18\u0026rdquo;，共十次。\n使用 with_sequence，之後就不用挖空心思去想怎麼產生出連續的數列了。\n","permalink":"https://ansible.cloudns.pro/post/sequence/","summary":"\u003cp\u003e之前想要產生一堆使用者，例如 user01, user02, user03\u0026hellip; ，那時候在想用 with_items 或 loop 要怎麼做？好像沒有好的方法，找了好一會，才在 Ansible 文件裡找到，原來 Ansible 已經有內建序列可以這樣用了。\u003c/p\u003e","title":"序列"},{"content":"2022 年 10 月 18 日 ~ 2022 年 10 月 19 日，Red Hat 將在 Chicago 舉辦 AnsibleFest 2022，有多項議程也有可以實作的工作坊，有興趣的人可以透過這個連結報名：http://ansiblefest.com/\n資料來源 The Automation experience: AnsibleFest-2022 ","permalink":"https://ansible.cloudns.pro/post/news/ansiblefest-2022/","summary":"\u003cp\u003e2022 年 10 月 18 日 ~ 2022 年 10 月 19 日，Red Hat 將在 Chicago 舉辦 AnsibleFest 2022，有多項議程也有可以實作的工作坊，有興趣的人可以透過這個連結報名：http://ansiblefest.com/\u003c/p\u003e","title":"AnsibleFest-2022"},{"content":"在 RHEL 裡要設定防火牆，主要是使用 firewall-cmd 這個指令，在 Ansible 對應的模組是 ansible.posix.firewalld。\n若熟悉 firewall-cmd 用法，對於使用這模組會很容易入手。\n以下就幾個常用的用法做說明。\n在防火牆開通 HTTP 服務，或者是開通 8081 port，然後在開通後立即更新防火牆狀態。\n- name: permit traffic in default zone for https service ansible.posix.firewalld: service: https permanent: yes state: enabled immediate: yes - name: permit traffic in default zone on port 8081/tcp ansible.posix.firewalld: port: 8081/tcp permanent: yes state: enabled immediate: yes 以上的 playbook 對應到實際的指令如下\nfirewall-cmd --add-service https --permanent firewall-cmd --reload firewall-cmd --add-port \u0026#34;8081/tcp\u0026#34; --permanent firewall-cmd --reload 那要關閉指定的 port 該怎麼做呢？跟上面開通的用法很相近，差異在於把 state 改為 disabled\n- name: do not permit traffic in default zone on port 8081/tcp ansible.posix.firewalld: port: 8081/tcp permanent: yes state: disabled immediate: yes 以上的 playbook 對應的實際的指令如下\nfirewall-cmd --remove-port=\u0026#34;8081/tcp\u0026#34; --permanent firewall-cmd --reload 那也可以針對 zone 來設定，或者是設定規則跟 port forwarding 等等，這邊因為這些不常用到，就先略過，等之後有遇到特殊用法，再來介紹。\n參考資料 ansible.posix.firewalld ","permalink":"https://ansible.cloudns.pro/post/system/firewalld/","summary":"\u003cp\u003e在 RHEL 裡要設定防火牆，主要是使用 firewall-cmd 這個指令，在 Ansible 對應的模組是 ansible.posix.firewalld。\u003c/p\u003e","title":"ansible.posix.firewalld"},{"content":"Ansible 本身在連線時，就會取得主機的相關資訊，這裏面就包含了 IP。\n--- - name: Get IP address of the host hosts: all tasks: - name: Display IP debug: var: ansible_default_ipv4[\u0026#39;address\u0026#39;] 那如果要取得 inventory 裡每台主機的 IP 或指定群組裡的 IP 呢？這時候可以用 hostvars，舉個例子，比如要把 db_servers 這個群組裡的主機與 IP 的對應都放到本機的 /tmp/hosts 裡。\n先撰寫 template，命名為 hosts.tmpl\n{% for host in groups[\u0026#39;ubuntu\u0026#39;] %} {{ hostvars[host][\u0026#39;ansible_default_ipv4\u0026#39;][\u0026#39;address\u0026#39;] }} {{ hostvars[host][\u0026#39;ansible_hostname\u0026#39;] }} {% endfor %} - name: Collect IP address and save as /tmp/hosts hosts: all tasks: - template: src: hosts.tmpl dest: /tmp/hosts delegate_to: localhost 在執行以後，可以看看本地端的 /tmp/hosts，就會是類似 /etc/hosts 的格式了。\n參考資料 In a template, get all the IPs of all machines in a group (Example) Ansible: get current target host\u0026rsquo;s IP address - Stack Overflow ","permalink":"https://ansible.cloudns.pro/post/system/get-host-ip/","summary":"\u003cp\u003eAnsible 本身在連線時，就會取得主機的相關資訊，這裏面就包含了 IP。\u003c/p\u003e","title":"如何取得主機的IP"},{"content":"最近要使用 smartmontools 套件裡的 smartctl 來查閱硬碟的 S.M.A.R.T. 狀態，做定期檢查，以免來不及去備份跟更換。這邊打算寫 ansible playbook 來作，所以就需要先取得主機上的所有硬碟。 好在 Ansible 本身在收集資訊時，就已經收集了，只是，這裏面還包含有 CD-ROM、Loop 等的裝置，我只想要 SATA 類型的啊~\n要做到這件事情，基本上只要搭配 when 跟 loop 就可以取得了。\n--- - name: Get all harddisk hosts: all tasks: - set_fact: device_list: [] - name: get device name set_fact: device_list: \u0026#34;{{ device_list + [ item.key ] }}\u0026#34; no_log: True with_dict: \u0026#34;{{ ansible_devices }}\u0026#34; when: \u0026#34;item.value.host.startswith(\u0026#39;SATA\u0026#39;) and item.value.removable==\u0026#39;0\u0026#39;\u0026#34; - name: show all values for selected device name debug: var: device_list 宣告一個 device_list 變數，後續的迴圈會把找到的裝置名稱放到裏面去。 使用 with_dict 跟 when 來做篩選， item.value.host.startswith('SATA') 表示符合 SATA 類型的裝置都要，item.value.removable=='0' 是要篩選掉 CD-ROM 跟 usb storage 這類的裝置。 顯示 在篩選出來以後，後續就可以用 smartctl -H 去查閱 S.M.A.R.T. 資訊啦。\n- name: check S.M.A.R.T. shell: | echo -n \u0026#34;/dev/{{ item }} S.M.A.R.T. status = \u0026#34; smartctl -H \u0026#34;/dev/{{ item }}\u0026#34; -j | jq -r \u0026#34;.smart_status.passed\u0026#34; register: shell_result loop: \u0026#34;{{ device_list }}\u0026#34; become: yes - name: Display S.M.A.R.T. status debug: msg: \u0026#34;{{ item.stdout }}\u0026#34; loop: \u0026#34;{{ shell_result.results }}\u0026#34; loop_control: label: \u0026#34;{{ item.stdout }}\u0026#34; smartctl 可以加上 -j 參數，取得 json 的結果，這樣後續就可以使用 jq 來找指定的資訊，比較快速。 顯示：這邊就使用了前篇：小技巧 - 如何在迴圈裡註冊變數 的技巧，避免輸出過多資訊。 參考資料 Ansible: Using ansible facts, how can I get a disk device based on the storage controller value and then set the device as a variable ","permalink":"https://ansible.cloudns.pro/post/system/get-all-ata-disks/","summary":"\u003cp\u003e最近要使用 smartmontools 套件裡的 smartctl 來查閱硬碟的 S.M.A.R.T. 狀態，做定期檢查，以免來不及去備份跟更換。這邊打算寫 ansible playbook 來作，所以就需要先取得主機上的所有硬碟。\n好在 Ansible 本身在收集資訊時，就已經收集了，只是，這裏面還包含有 CD-ROM、Loop 等的裝置，我只想要 SATA 類型的啊~\u003c/p\u003e","title":"取得所有 SATA 的磁碟"},{"content":"單一個模組執行結果，可以使用 register 把結果放到變數裡。\n如果這模組要搭配迴圈執行多次，又要把結果放到變數裡時，要怎麼寫呢？因為之前沒有用過，腦袋不禁打結了，心裡開始在盤算該怎麼處理比較好？但好在，早有人提出解答。\nStackOverflow 上的說明：Register variables in with_items loop in Ansible playbook\n簡單的說，不需要特別做什麼處理，照寫就可以，只是取得的變數格式有些不同。取得的變數會把每次執行的結果放到 .results 裡，存為一個 list。舉個例子來說明，在沒有使用 loop 的情況是這樣：\n--- - name: Register without loop hosts: all tasks: - name: shell shell: hostname register: shell_result - name: display debug: var: shell_result 輸出結果如下(摘錄)\nTASK [display] ************************************************************************************************ ok: [localhost] =\u0026gt; { \u0026#34;shell_result\u0026#34;: { \u0026#34;changed\u0026#34;: true, \u0026#34;cmd\u0026#34;: \u0026#34;hostname\u0026#34;, \u0026#34;delta\u0026#34;: \u0026#34;0:00:00.004216\u0026#34;, \u0026#34;end\u0026#34;: \u0026#34;2022-09-03 05:59:29.924106\u0026#34;, \u0026#34;failed\u0026#34;: false, \u0026#34;rc\u0026#34;: 0, \u0026#34;start\u0026#34;: \u0026#34;2022-09-03 05:59:29.919890\u0026#34;, \u0026#34;stderr\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;stderr_lines\u0026#34;: [], \u0026#34;stdout\u0026#34;: \u0026#34;example-host\u0026#34;, \u0026#34;stdout_lines\u0026#34;: [ \u0026#34;example-host\u0026#34; ] } } PLAY RECAP **************************************************************************************************** localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 這時可以看到 shell_result 是個 dict 型態的變數。\n再加上 loop 以後，同樣，舉個例子來看。\n--- - name: Register with loop hosts: all vars: cmd_list: - hostname - date - uptime tasks: - name: shell shell: \u0026#34;{{ item }}\u0026#34; register: shell_result loop: \u0026#34;{{ cmd_list }}\u0026#34; - name: display debug: var: shell_result 輸出結果如下(摘錄)，這時就會看到 shell_result 多了一個 list 型態的 results 屬性。\nTASK [display] ************************************************************************************************ ok: [localhost] =\u0026gt; { \u0026#34;shell_result\u0026#34;: { \u0026#34;changed\u0026#34;: true, \u0026#34;msg\u0026#34;: \u0026#34;All items completed\u0026#34;, \u0026#34;results\u0026#34;: [ { \u0026#34;ansible_loop_var\u0026#34;: \u0026#34;item\u0026#34;, \u0026#34;changed\u0026#34;: true, \u0026#34;cmd\u0026#34;: \u0026#34;hostname\u0026#34;, \u0026#34;delta\u0026#34;: \u0026#34;0:00:00.003129\u0026#34;, \u0026#34;end\u0026#34;: \u0026#34;2022-09-03 06:12:38.139077\u0026#34;, \u0026#34;failed\u0026#34;: false, \u0026#34;invocation\u0026#34;: { \u0026#34;module_args\u0026#34;: { \u0026#34;_raw_params\u0026#34;: \u0026#34;hostname\u0026#34;, \u0026#34;_uses_shell\u0026#34;: true, \u0026#34;argv\u0026#34;: null, \u0026#34;chdir\u0026#34;: null, \u0026#34;creates\u0026#34;: null, \u0026#34;executable\u0026#34;: null, \u0026#34;removes\u0026#34;: null, \u0026#34;stdin\u0026#34;: null, \u0026#34;stdin_add_newline\u0026#34;: true, \u0026#34;strip_empty_ends\u0026#34;: true, \u0026#34;warn\u0026#34;: true } }, \u0026#34;item\u0026#34;: \u0026#34;hostname\u0026#34;, \u0026#34;rc\u0026#34;: 0, \u0026#34;start\u0026#34;: \u0026#34;2022-09-03 06:12:38.135948\u0026#34;, \u0026#34;stderr\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;stderr_lines\u0026#34;: [], \u0026#34;stdout\u0026#34;: \u0026#34;example-host\u0026#34;, \u0026#34;stdout_lines\u0026#34;: [ \u0026#34;example-host\u0026#34; ] }, { \u0026#34;ansible_loop_var\u0026#34;: \u0026#34;item\u0026#34;, \u0026#34;changed\u0026#34;: true, \u0026#34;cmd\u0026#34;: \u0026#34;date\u0026#34;, \u0026#34;delta\u0026#34;: \u0026#34;0:00:00.009256\u0026#34;, \u0026#34;end\u0026#34;: \u0026#34;2022-09-03 06:12:38.286830\u0026#34;, \u0026#34;failed\u0026#34;: false, \u0026#34;invocation\u0026#34;: { \u0026#34;module_args\u0026#34;: { \u0026#34;_raw_params\u0026#34;: \u0026#34;date\u0026#34;, \u0026#34;_uses_shell\u0026#34;: true, \u0026#34;argv\u0026#34;: null, \u0026#34;chdir\u0026#34;: null, \u0026#34;creates\u0026#34;: null, \u0026#34;executable\u0026#34;: null, \u0026#34;removes\u0026#34;: null, \u0026#34;stdin\u0026#34;: null, \u0026#34;stdin_add_newline\u0026#34;: true, \u0026#34;strip_empty_ends\u0026#34;: true, \u0026#34;warn\u0026#34;: true } }, \u0026#34;item\u0026#34;: \u0026#34;date\u0026#34;, \u0026#34;rc\u0026#34;: 0, \u0026#34;start\u0026#34;: \u0026#34;2022-09-03 06:12:38.277574\u0026#34;, \u0026#34;stderr\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;stderr_lines\u0026#34;: [], \u0026#34;stdout\u0026#34;: \u0026#34;西元2022年09月03日 (週六) 06時12分38秒 CST\u0026#34;, \u0026#34;stdout_lines\u0026#34;: [ \u0026#34;西元2022年09月03日 (週六) 06時12分38秒 CST\u0026#34; ] }, { \u0026#34;ansible_loop_var\u0026#34;: \u0026#34;item\u0026#34;, \u0026#34;changed\u0026#34;: true, \u0026#34;cmd\u0026#34;: \u0026#34;uptime\u0026#34;, \u0026#34;delta\u0026#34;: \u0026#34;0:00:00.004768\u0026#34;, \u0026#34;end\u0026#34;: \u0026#34;2022-09-03 06:12:38.433260\u0026#34;, \u0026#34;failed\u0026#34;: false, \u0026#34;invocation\u0026#34;: { \u0026#34;module_args\u0026#34;: { \u0026#34;_raw_params\u0026#34;: \u0026#34;uptime\u0026#34;, \u0026#34;_uses_shell\u0026#34;: true, \u0026#34;argv\u0026#34;: null, \u0026#34;chdir\u0026#34;: null, \u0026#34;creates\u0026#34;: null, \u0026#34;executable\u0026#34;: null, \u0026#34;removes\u0026#34;: null, \u0026#34;stdin\u0026#34;: null, \u0026#34;stdin_add_newline\u0026#34;: true, \u0026#34;strip_empty_ends\u0026#34;: true, \u0026#34;warn\u0026#34;: true } }, \u0026#34;item\u0026#34;: \u0026#34;uptime\u0026#34;, \u0026#34;rc\u0026#34;: 0, \u0026#34;start\u0026#34;: \u0026#34;2022-09-03 06:12:38.428492\u0026#34;, \u0026#34;stderr\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;stderr_lines\u0026#34;: [], \u0026#34;stdout\u0026#34;: \u0026#34; 06:12:38 up 26 days, 15:24, 1 user, load average: 0.43, 0.45, 0.60\u0026#34;, \u0026#34;stdout_lines\u0026#34;: [ \u0026#34; 06:12:38 up 26 days, 15:24, 1 user, load average: 0.43, 0.45, 0.60\u0026#34; ] } ] } } PLAY RECAP **************************************************************************************************** localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 知道結果會是這樣以後，就可以再用 loop 來處理了。在上面的 playbook 最後加入以下 task，就可以只印出輸出結果了。\n- name: Display only stdout debug: msg: \u0026#34;{{ item.stdout }}\u0026#34; loop: \u0026#34;{{ shell_result.results }}\u0026#34; loop_control: label: \u0026#34;{{ item.stdout }}\u0026#34; 輸出結果如下（摘錄)\nTASK [Display only stdout] ************************************************************************************ ok: [localhost] =\u0026gt; (item=example-host) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;example-host\u0026#34; } ok: [localhost] =\u0026gt; (item=西元2022年09月03日 (週六) 06時17分05秒 CST) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;西元2022年09月03日 (週六) 06時17分05秒 CST\u0026#34; } ok: [localhost] =\u0026gt; (item= 06:17:05 up 26 days, 15:28, 1 user, load average: 0.47, 0.49, 0.58) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34; 06:17:05 up 26 days, 15:28, 1 user, load average: 0.47, 0.49, 0.58\u0026#34; } 這邊有使用到另外一個小技巧，避免輸出過多的資訊，就是 loop_control，這是在 2.2 以後所提供的語法。如果不使用，輸出結果會是像下面這樣子，可以看到，非常的冗長，導致不容易閱讀。\nTASK [Display only stdout] ************************************************************************************ ok: [localhost] =\u0026gt; (item={\u0026#39;cmd\u0026#39;: \u0026#39;hostname\u0026#39;, \u0026#39;stdout\u0026#39;: \u0026#39;example-host\u0026#39;, \u0026#39;stderr\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;rc\u0026#39;: 0, \u0026#39;start\u0026#39;: \u0026#39;2022-09-03 06:21:09.487145\u0026#39;, \u0026#39;end\u0026#39;: \u0026#39;2022-09-03 06:21:09.490120\u0026#39;, \u0026#39;delta\u0026#39;: \u0026#39;0:00:00.002975\u0026#39;, \u0026#39;changed\u0026#39;: True, \u0026#39;invocation\u0026#39;: {\u0026#39;module_args\u0026#39;: {\u0026#39;_raw_params\u0026#39;: \u0026#39;hostname\u0026#39;, \u0026#39;_uses_shell\u0026#39;: True, \u0026#39;warn\u0026#39;: True, \u0026#39;stdin_add_newline\u0026#39;: True, \u0026#39;strip_empty_ends\u0026#39;: True, \u0026#39;argv\u0026#39;: None, \u0026#39;chdir\u0026#39;: None, \u0026#39;executable\u0026#39;: None, \u0026#39;creates\u0026#39;: None, \u0026#39;removes\u0026#39;: None, \u0026#39;stdin\u0026#39;: None}}, \u0026#39;stdout_lines\u0026#39;: [\u0026#39;example-host\u0026#39;], \u0026#39;stderr_lines\u0026#39;: [], \u0026#39;failed\u0026#39;: False, \u0026#39;item\u0026#39;: \u0026#39;hostname\u0026#39;, \u0026#39;ansible_loop_var\u0026#39;: \u0026#39;item\u0026#39;}) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;example-host\u0026#34; } ok: [localhost] =\u0026gt; (item={\u0026#39;cmd\u0026#39;: \u0026#39;date\u0026#39;, \u0026#39;stdout\u0026#39;: \u0026#39;西元2022年09月03日 (週六) 06時21分09秒 CST\u0026#39;, \u0026#39;stderr\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;rc\u0026#39;: 0, \u0026#39;start\u0026#39;: \u0026#39;2022-09-03 06:21:09.627735\u0026#39;, \u0026#39;end\u0026#39;: \u0026#39;2022-09-03 06:21:09.630569\u0026#39;, \u0026#39;delta\u0026#39;: \u0026#39;0:00:00.002834\u0026#39;, \u0026#39;changed\u0026#39;: True, \u0026#39;invocation\u0026#39;: {\u0026#39;module_args\u0026#39;: {\u0026#39;_raw_params\u0026#39;: \u0026#39;date\u0026#39;, \u0026#39;_uses_shell\u0026#39;: True, \u0026#39;warn\u0026#39;: True, \u0026#39;stdin_add_newline\u0026#39;: True, \u0026#39;strip_empty_ends\u0026#39;: True, \u0026#39;argv\u0026#39;: None, \u0026#39;chdir\u0026#39;: None, \u0026#39;executable\u0026#39;: None, \u0026#39;creates\u0026#39;: None, \u0026#39;removes\u0026#39;: None, \u0026#39;stdin\u0026#39;: None}}, \u0026#39;stdout_lines\u0026#39;: [\u0026#39;西元2022年09月03日 (週六) 06時21分09秒 CST\u0026#39;], \u0026#39;stderr_lines\u0026#39;: [], \u0026#39;failed\u0026#39;: False, \u0026#39;item\u0026#39;: \u0026#39;date\u0026#39;, \u0026#39;ansible_loop_var\u0026#39;: \u0026#39;item\u0026#39;}) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;西元2022年09月03日 (週六) 06時21分09秒 CST\u0026#34; } ok: [localhost] =\u0026gt; (item={\u0026#39;cmd\u0026#39;: \u0026#39;uptime\u0026#39;, \u0026#39;stdout\u0026#39;: \u0026#39; 06:21:09 up 26 days, 15:32, 1 user, load average: 0.53, 0.50, 0.55\u0026#39;, \u0026#39;stderr\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;rc\u0026#39;: 0, \u0026#39;start\u0026#39;: \u0026#39;2022-09-03 06:21:09.769529\u0026#39;, \u0026#39;end\u0026#39;: \u0026#39;2022-09-03 06:21:09.773419\u0026#39;, \u0026#39;delta\u0026#39;: \u0026#39;0:00:00.003890\u0026#39;, \u0026#39;changed\u0026#39;: True, \u0026#39;invocation\u0026#39;: {\u0026#39;module_args\u0026#39;: {\u0026#39;_raw_params\u0026#39;: \u0026#39;uptime\u0026#39;, \u0026#39;_uses_shell\u0026#39;: True, \u0026#39;warn\u0026#39;: True, \u0026#39;stdin_add_newline\u0026#39;: True, \u0026#39;strip_empty_ends\u0026#39;: True, \u0026#39;argv\u0026#39;: None, \u0026#39;chdir\u0026#39;: None, \u0026#39;executable\u0026#39;: None, \u0026#39;creates\u0026#39;: None, \u0026#39;removes\u0026#39;: None, \u0026#39;stdin\u0026#39;: None}}, \u0026#39;stdout_lines\u0026#39;: [\u0026#39; 06:21:09 up 26 days, 15:32, 1 user, load average: 0.53, 0.50, 0.55\u0026#39;], \u0026#39;stderr_lines\u0026#39;: [], \u0026#39;failed\u0026#39;: False, \u0026#39;item\u0026#39;: \u0026#39;uptime\u0026#39;, \u0026#39;ansible_loop_var\u0026#39;: \u0026#39;item\u0026#39;}) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34; 06:21:09 up 26 days, 15:32, 1 user, load average: 0.53, 0.50, 0.55\u0026#34; } 最後整理一下，這篇分享了兩個技巧：\nregister 是可以搭配 loop 使用的，使用時，會多出一個 results 屬性，後面可以對 results 做處理就好。 可以使用 loop_control 來避免顯示過多資訊，提升可閱讀性。 ","permalink":"https://ansible.cloudns.pro/post/tips/tip-register-variable-in-loop/","summary":"\u003cp\u003e單一個模組執行結果，可以使用 register 把結果放到變數裡。\u003c/p\u003e\n\u003cp\u003e如果這模組要搭配迴圈執行多次，又要把結果放到變數裡時，要怎麼寫呢？因為之前沒有用過，腦袋不禁打結了，心裡開始在盤算該怎麼處理比較好？但好在，早有人提出解答。\u003c/p\u003e","title":"小技巧 - 如何在迴圈裡註冊變數"},{"content":"說明 現在新版的 AWX 依照官方網站的說法，只能安裝在容器平台上了，接下來的幾篇文將說明一下如何安裝 AWX。\n首先，先選定 K8S 容器平台，這裡我們選定 microk8s，主要有幾個原因：\n容易安裝而且容易取得：新版的 Ubuntu 都提供了 snapcraft 這個套件管理工具，而 microk8s 已經被封裝為 snap 套件，很容易就可以安裝。 單機即可使用：microk8s可以安裝在單機上，就不需要多台主機才能安裝。 再來有兩個事情要準備：\n架設 NFS 伺服器：在架設 AWX 時，會一併安裝 PostgreSQL 與 Redis 等服務，這些服務會需要 Physical Volume 。 預留 IP 區段：安裝 AWX 以後，需要可以存取 AWX，這裡預計使用 MetalLB ，而 MetalLB 會拿這個預留 IP 區段裡的一個 IP 來當作 AWX 的入口。 架設 NFS 伺服器 在 Ubuntu 架設 NFS 伺服器，需要安裝 nfs-common 與 nfs-kernel-server 這兩個套件：\nsudo apt install nfs-common nfs-kernel-server 再來建立要分享的目錄\nsudo mkdir /nfs-share sudo chown nobody:nogroup /nfs-share sudo chmod 0777 /nfs-share 然後在 /etc/exports 裡增加一行\n/nfs-share *(rw,sync,no_subtree_check,no_root_squash,insecure) 啟用 NFS 伺服器\nsudo systemctl start nfs-server 檢查是否成功\nsudo systemctl status nfs-server sudo showmount -e localhost MetalLB 預留 IP 區段，就是去無線基地台或是 DHCP 伺服器裡去調整配發的 IP 範圍，例如原本是 192.168.11.1~192.168.11.254，就改為 192.168.11.1~192.168.11.240 ，表示不配發 192.168.11.241~192.168.11.255 這個區段的 IP 。之後等安裝完 microk8s 跟 MetalLB 以後，再來設定 MetalLB。\n參考資料 這裡也先預留參考資料在這裡，作為之後參考使用。\nUse NFS for Persistent Volumes 使用 MicroK8s 架設 Kubernetes 叢集的完整過程解析 | The Will Will Web 使用 MicroK8s 架設 Kubernetes 叢集時應注意的連線管理注意事項 | The Will Will Web AWX Operator ","permalink":"https://ansible.cloudns.pro/post/awx/install-awx-on-k8s-1/","summary":"\u003ch2 id=\"說明\"\u003e說明\u003c/h2\u003e\n\u003cp\u003e現在新版的 AWX 依照官方網站的說法，只能安裝在容器平台上了，接下來的幾篇文將說明一下如何安裝 AWX。\u003c/p\u003e","title":"Install AWX on K8S(1)"},{"content":"Playbook 是使用 YAML 格式，在使用上難免會遇到要放很長的字串的情況，想保留可讀性又不想有多餘的換行符號，該怎麼辦呢？\n在 YAML 裡已經有規範此部份，在這種情況有四種方法可以幫助我們：\n|: 其下內容的換行，就是換行，最後一行會有換行。 \u0026gt;: 其下內容的換行，不會是換行，會變為一個很長的字串，最後會有換行。 |-: 其下內容的換行，就是換行，但最後一行不會有換行。 \u0026gt;-: 其下內容的換常，不會是換行，最後一行也不會有換行。 直接來看看範例\n--- - name: Test long string hosts: all vars: s1: \u0026#34;hello\u0026#34; s2: | s2 this is my very very very long string line1 line2 line3 s3: \u0026gt; s3 this is my very very very long string line1 line2 line3 s4: |- s4 this is my very very very long string line1 line2 line3 s5: \u0026gt;- s5 this is my very very very long string line1 line2 line3 tasks: - name: s1 copy: content: \u0026#34;{{ s1 }}\u0026#34; dest: \u0026#34;/tmp/s1.txt\u0026#34; - name: s2 copy: content: \u0026#34;{{ s2 }}\u0026#34; dest: \u0026#34;/tmp/s2.txt\u0026#34; - name: s3 copy: content: \u0026#34;{{ s3 }}\u0026#34; dest: \u0026#34;/tmp/s3.txt\u0026#34; - name: s4 copy: content: \u0026#34;{{ s4 }}\u0026#34; dest: \u0026#34;/tmp/s4.txt\u0026#34; - name: s5 copy: content: \u0026#34;{{ s5 }}\u0026#34; dest: \u0026#34;/tmp/s5.txt\u0026#34; s2~s5 這四個變數裡的內容分別以 |, \u0026gt;, |-, \u0026gt;- 來定義。\n接著來看看執行結果\n$ cat /tmp/s1.txt hello% $ cat /tmp/s2.txt s2 this is my very very very long string line1 line2 line3 $ cat /tmp/s3.txt s3 this is my very very very long string line1 line2 line3 $ cat /tmp/s4.txt s4 this is my very very very long string line1 line2 line3% $ cat /tmp/s5.txt s5 this is my very very very long string line1 line2 line3% 從執行結果，就可以看到如同之前所描述的情況。\n簡單的說，\u0026gt; 跟 \u0026gt;- 可以增加 YAML 的可讀性，又不會有多餘的換行符號。而 | 跟 |- 則可以讓字串跟定義的一致，在 YAML 裡看到換行，那字串裡就會有換行符號。\n參考資料 syntax - How do I break a string in YAML over multiple lines? ","permalink":"https://ansible.cloudns.pro/post/long-string-in-yaml/","summary":"\u003cp\u003ePlaybook 是使用 YAML 格式，在使用上難免會遇到要放很長的字串的情況，想保留可讀性又不想有多餘的換行符號，該怎麼辦呢？\u003c/p\u003e","title":"YAML 裡的字串很長該怎麼做？"},{"content":"使用場景 寫作 Playbook 若遇到這兩種情況時，可以怎麼做呢？\n新增內容到 list 裡 合併兩個 list 方法 方法相當簡單，使用 + 就可以。\n新增內容到 list 時，可以這樣寫\n- name: 配置 list set_fact: result_list: [] - name: 取得時間 shell: date +%T register: shell_result - name: 附加內容到 result_list set_fact: result_list: \u0026#34;{{ result_list + [ shell_result.stdout ]}}\u0026#34; - name: 再次取得時間 shell: sleep 3 \u0026amp;\u0026amp; date +%T register: shell_result - name: 附加內容到 result_list set_fact: result_list: \u0026#34;{{ result_list + [ shell_result.stdout ]}}\u0026#34; 若是要合併兩個 list，就是這樣寫\n- name: 配置兩個 list set_fact: list_one: - 1 - 2 - 3 list_two: - 4 - 5 - 6 - name: 合併兩個 list set_fact: lists_merged: \u0026#34;{{ list_one + list_two }}\u0026#34; 結論 在做例如檢查性的 playbook 時，透過這個技巧，就可以持續把項目的檢查結果加到 list 裡。檢查的結過可以在最後用 template 去處理 list 來顯示就可以了。\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-append-list/","summary":"使用場景 寫作 Playbook 若遇到這兩種情況時，可以怎麼做呢？ 新增內容到 list 裡 合併兩個 list 方法 方法相當簡單，使用 + 就可以。 新增內容到 list 時，可以這樣寫 - name: 配置 list","title":"如何在 list 裡新增內容或合併兩個 list?"},{"content":"使用 postgresql_xxx 的模組存取 Postgresql 資料庫時，一般會需要切換為 postgres 使用者來進行操作。在 Ansible 可以怎麼去做呢？\n在 Ansible 裡，可以用 become_user / become 來處理。\n下面用 postgresql_user 來重置 test 使用者的密碼來當作例子，\n- name: pd reset database user become: yes become_method: sudo become_user: postgres community.postgresql.postgresql_user: db: test name: test password: \u0026#34;\u0026#34; 說明如下：\nbecome: yes ，表示要切換使用者。 become_method: sudo，表示要使用 sudo 來切換。 become_user: postgres，表示切換過去的使用者名稱是 postgres 下面做一點組合，先建立名稱是 awx 的資料庫，然後再去建立可以操作這個資料庫的 awx 使用者，密碼設定為 redhat\n- name: Create database with name \u0026#34;awx\u0026#34; and specific encoding and locale # settings community.postgresql.postgresql_db: name: awx encoding: UTF-8 lc_collate: en_US.UTF-8 lc_ctype: en_US.UTF-8 template: template0 become: yes become_method: sudo become_user: postgres - name: Connect to awx database, create awx user, and grant access to database and products table community.postgresql.postgresql_user: db: awx name: awx password: redhat priv: ALL state: present become: yes become_method: sudo become_user: postgres 看到這邊相信你應該知道怎麼應用這些模組了。\n參考資料 How to set postgres password using ansible community.postgresql.postgresql_user module – Create, alter, or remove a user (role) from a PostgreSQL server instance community.postgresql.postgresql_db module – Add or remove PostgreSQL databases from a remote host ","permalink":"https://ansible.cloudns.pro/post/database/postgresql_user/","summary":"\u003cp\u003e使用 postgresql_xxx 的模組存取 Postgresql 資料庫時，一般會需要切換為 postgres 使用者來進行操作。在 Ansible 可以怎麼去做呢？\u003c/p\u003e","title":"postgresql_user"},{"content":"What\u0026rsquo;s new in Ansible Automation Platform 2.2\n最近 2.2 剛出，相較於 2.1 ，又增加了什麼呢？\n在 Automation controller 裡有介面可以比較清楚的看到 Automation controller 與 execution node/hybrid node/hop node 的關係了。 Ansible automation hub 增加了 Red Hat 認証過的 collection。 增加了 ansible-navigator, ansible-lint 還有 VSCode language server 的支援。 增強網路自動化的 collection：改用 libssh，還有預設啟用了直接執行，所以速度會提升。再來是提升對 Arista EOS, Cisco IOS XE, Cisco NX-OS, Cisco IOS XR, Juniper JunOS 和 VyOS 的支援。 提供了 Automation service catalog。 自動化資料的報告與分析現在已經整合進來了。 支援 Red Hat Enterprise Linux 9 Ansible Automation Platform Automation controller Automation hub Automation services catalog Insights for Ansible Automation Platform 2.2 4.2 4.5, hosted service 1.0 Private (Technology Preview), hosted service (Retired) hosted service 詳細的說明，可以參考這篇：May 2022 Release，有針對各個元件說明新增的功能。\n簡單的說，大功能沒變，主要是功能增強。\n","permalink":"https://ansible.cloudns.pro/post/ansible-automation-platform/aap-2.2.0/","summary":"\u003cp\u003e\u003ca href=\"https://www.ansible.com/blog/whats-new-in-ansible-automation-platform-2.2\"\u003eWhat\u0026rsquo;s new in Ansible Automation Platform 2.2\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e最近 2.2 剛出，相較於 2.1 ，又增加了什麼呢？\u003c/p\u003e","title":"Ansible Automation Platform 2.2"},{"content":"有些時候，會需要取得字串中的某個部份來使用，這時候可以怎麼做呢？\n場景1：知道需要的部份在固定的位置 這種情況很簡單，就用 [start:end:step] 來處理就可以，如果你熟悉 Python 的話會覺得很熟悉。基本上這裡的用法就跟 Python 處理字串的用法是一樣的。\n像 [-2:] ，表示是字串最後兩個字元；[3:6] 表示是字串裡第四個字元到第六個字元，[0:2] 或 [:2] 都表示是取字串前面兩個字元。\n--- # test-substring.yaml # ansible-playbook -i localhost, -c local test-substring.yaml - name: Get substring hosts: all vars: content: \u0026#34;01234567890\u0026#34; tasks: - name: Get substring set_fact: new_content_1: \u0026#34;{{ content[-2:] }}\u0026#34; new_content_2: \u0026#34;{{ content[3:6] }}\u0026#34; - name: Display debug: msg: \u0026#34;new_content_1={{ new_content_1 }} new_content2={{ new_content_2 }}\u0026#34; 執行結果\nTASK [Display] ***************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;new_content_1=90 new_content2=345\u0026#34; } 場景2：字串位置不一定，但是有規則可循 這種情況可以利用 regular expression 的 group 來處理，Ansible 的文件有提到這部份：Searching strings with regular expressions\n摹擬情境如下，現在有個字串是 \u0026ldquo;/opt/jboss/MyApps/installedApps/OrzXD.ear/XDWeb.war/WEB-INF/classes/\u0026quot;，想要取出 \u0026ldquo;Orz\u0026rdquo; 跟 \u0026ldquo;.ear\u0026rdquo; 中間的字串，還有 \u0026ldquo;/\u0026rdquo; 跟 \u0026ldquo;Web.war\u0026rdquo; 中間的字串，那麼就可以這樣寫。\n--- # test-regex_search.yaml # ansible-playbook -i localhost, -c local test-regex_search.yaml - name: Test regex_search hosts: all vars: content: \u0026#34;/opt/jboss/MyApps/installedApps/OrzXD.ear/XDWeb.war/WEB-INF/classes/\u0026#34; tasks: - name: Use regex_search set_fact: result1: \u0026#34;{{ content | regex_search(\u0026#39;\\\\/opt\\\\/jboss\\\\/MyApps\\\\/installedApps\\\\/Orz(.+).ear\\\\/(.+)Web.war\\\\/WEB-INF\\\\/classes\\\\/\u0026#39;, \u0026#39;\\\\1\u0026#39;) | first }}\u0026#34; result2: \u0026#34;{{ content | regex_search(\u0026#39;\\\\/opt\\\\/jboss\\\\/MyApps\\\\/installedApps\\\\/Orz(.+).ear\\\\/(.+)Web.war\\\\/WEB-INF\\\\/classes\\\\/\u0026#39;, \u0026#39;\\\\2\u0026#39;) | first }}\u0026#34; - debug: var: result1 - debug: var: result2 說明：\n\u0026quot;\\\\/opt\\\\/jboss\\\\/MyApps\\\\/installedApps\\\\/Orz(.+).ear\\\\/(.+)Web.war\\\\/WEB-INF\\\\/classes\\\\/\u0026quot; 這個字串是描述規則，表示要把符合這規則的字串找出來。 有括號括起來的地方 (.+) ，表示是 group，要擷取出來的部份。 在 regular expression 裡，/ 表示搜尋，但因為是路徑，我們不需要被認定為搜尋，所以在 / 前面加上 \\\\ 來告知要把 / 處理為正常的 / ，而非搜尋。 執行結果如下\nTASK [debug] ********************************************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;result1\u0026#34;: \u0026#34;XD\u0026#34; } TASK [debug] ********************************************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;result2\u0026#34;: \u0026#34;XD\u0026#34; } 以上介紹了兩種可以取得部份字串的方法，希望對大家有幫助。\n參考資料 Extracting part of the string using Ansible regex_search and save the output as a variable Ansible Regexp groups, patterns or something else? Searching strings with regular expressions ","permalink":"https://ansible.cloudns.pro/post/tips/tip-extract-part-of-string/","summary":"\u003cp\u003e有些時候，會需要取得字串中的某個部份來使用，這時候可以怎麼做呢？\u003c/p\u003e","title":"小技巧 - 取得字串中指定的部份"},{"content":"前兩天是 Red Hat Summit，Red Hat 也趁勢公佈了一個消息： Updates to using Ansible in RHEL 8.6 and 9.0\n在 RHEL 8.4 之前要安裝 Ansible，都需要額外添加 Ansible 的 repository 來安裝，這新聞講的是，在 RHEL 8.6 / 9.0 以後，ansible-core 已經被納入到 AppStream repository， 也就是說，不需要再額外添加 Ansible 的 repository 就可以使用 Ansible。\n但 Ansible repository 仍然會保留，這裡主要是放 Ansible engine ，在 RHEL 8.6 仍然可以使用，只是沒有安全性或錯誤修正了，正式結束的時間大約是 2023 年 9 月。\n在文章裡有特別解釋 Ansible engine 跟 Ansible core 的差異，主要差異還是在於支援的模組，Ansible engine 包含 3,387 個模組，而 Ansible core 僅僅包含約 127 個模組，也缺少了許多好用的模組，例如 json_query, ipaddr 等等的。\n就這樣看起來，目前不需要急著改用 ansible core，若改用，立刻就會遇到要調整 playbook 的問題。但看起來 Red Hat 是鐵了心要因應 Ansible 版本路線調整，來做處理，所以也是要慢慢去處理，逐步更換。\n","permalink":"https://ansible.cloudns.pro/post/updates-to-using-ansible-in-rhel-8.6-9.0/","summary":"\u003cp\u003e前兩天是 Red Hat Summit，Red Hat 也趁勢公佈了一個消息： \u003ca href=\"https://www.redhat.com/en/blog/updates-using-ansible-rhel-86-and-90\"\u003eUpdates to using Ansible in RHEL 8.6 and 9.0\u003c/a\u003e\u003c/p\u003e","title":"RHEL 8.6 與 9.0 以後的 Ansible"},{"content":"debug 模組的用途，顧名思義就是除錯用的，一般用來在 playbook 裡列印變數內容，或是指定的訊息。在預設的情況下，模組只會有狀態的輸出， 像是 changed, ignored 等等的，使用 debug 模組，就可以印出變數內容或者是運算式的結果。基本上就把他想做是 bash 裡的 echo，或是 python 裡的 print。\ndebug 模組支援兩種基本的用法：msg, var\nmsg - name: How to use debug module with msg hosts: all tasks: - name: Display message msg: \u0026#34;Hello world!\u0026#34; 用 ansible-playbook 執行以後，可以看到輸出結果\nTASK [Display message ********************************************************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;Hello world!\u0026#34; } var - name: How to use debug module with var hosts: all var: guest_name: \u0026#34;John\u0026#34; tasks: - name: Display var var: guest_name 用 ansible-playbook 執行以後，可以看到輸出結果\nTASK [Display var ********************************************************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;guest_name\u0026#34;: \u0026#34;John\u0026#34; } 參考資料 How To Use Debug Module In Ansible Playbooks ansible.builtin.debug module – Print statements during execution ","permalink":"https://ansible.cloudns.pro/post/debug/","summary":"\u003cp\u003edebug 模組的用途，顧名思義就是除錯用的，一般用來在 playbook 裡列印變數內容，或是指定的訊息。在預設的情況下，模組只會有狀態的輸出，\n像是 changed, ignored 等等的，使用 debug 模組，就可以印出變數內容或者是運算式的結果。基本上就把他想做是 bash 裡的 echo，或是 python 裡的 print。\u003c/p\u003e","title":"如何使用debug模組"},{"content":"在遇到執行 playbook 花費較多時間的情況時，該怎麼去進行分析，找出執行效能瓶頸呢？\n在 ansible-core 2.15 版以前，可以在 ansible.cfg 裡加上 callback_whitelist = profile_tasks 來進行分析。 在 ansible-core 2.15 版以後，就強制要使用新的設定 callback_enabled = profile_tasks 了。\n設定方法如下：(ansible.cfg 可以是在 playbook 所在的路徑，也可以修改 /etc/ansible/ansible.cfg)\n# 2.15 之前 [defaults] callback_whitelist = profile_tasks # 2.15 之後 [defaults] callback_enabled = profile_tasks 那麼在執行 playbook 時，就會輸出每個 task 的運行時間，讓你知道哪個 task 花費最多時間。\nPLAY [NTP] ************************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************* Monday 18 April 2022 10:39:45 +0800 (0:00:00.016) 0:00:00.016 ********** ok: [taipei-2-2] ok: [taipei-2-1] ok: [taipei-1-2] ok: [taipei-1-1] ok: [taipei-1-3] ok: [tainan-1-3] ok: [tainan-1-2] ok: [tainan-1-1] ok: [tainan-1-4] ok: [taipei-2-3] TASK [Make sure NTP enabled and started] ******************************************************************************* Monday 18 April 2022 10:39:55 +0800 (0:00:10.116) 0:00:10.133 ********** ok: [taipei-2-2] ok: [taipei-2-1] ok: [taipei-1-2] ok: [taipei-1-3] ok: [taipei-1-1] ok: [taipei-2-3] ok: [tainan-1-1] ok: [tainan-1-3] ok: [tainan-1-4] ok: [tainan-1-2] PLAY RECAP ************************************************************************************************************* tainan-1-1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 tainan-1-2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 tainan-1-3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 tainan-1-4 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 taipei-1-1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 taipei-1-2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 taipei-1-3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 taipei-2-1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 taipei-2-2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 taipei-2-3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Monday 18 April 2022 10:39:58 +0800 (0:00:03.264) 0:00:13.397 ********** =============================================================================== Gathering Facts ------------------------------------------------------------------------------------------------ 10.12s Make sure NTP enabled and started ------------------------------------------------------------------------------- 3.26s 除了 task 以外，也可以分析 role 執行效能的話，這時可以再加上 profile_roles\n# 2.15 之後 [defaults] callback_enabled = profile_tasks,profile_roles 參考資料 Using the profile module to time Ansible playbook runs Callback plugins ansible.posix.profile_tasks – adds time information to tasks ansible.posix.profile_roles – adds timing information to roles ","permalink":"https://ansible.cloudns.pro/post/profiling-tasks/","summary":"\u003cp\u003e在遇到執行 playbook 花費較多時間的情況時，該怎麼去進行分析，找出執行效能瓶頸呢？\u003c/p\u003e\n\u003cp\u003e在 ansible-core 2.15 版以前，可以在 ansible.cfg 裡加上 \u003ccode\u003ecallback_whitelist = profile_tasks\u003c/code\u003e 來進行分析。\n在 ansible-core 2.15 版以後，就強制要使用新的設定 \u003ccode\u003ecallback_enabled = profile_tasks\u003c/code\u003e 了。\u003c/p\u003e","title":"分析任務執行時間"},{"content":"我最早是用 Jenkins + Ansible 來執行 Playbook ，後來才用 AWX/Ansible Tower。最近在 Reddit 上看到有人介紹 Rundeck，想說來試用看看。\n在 Rundeck 的文件裡，就有教學文章了：Rundeck and Ansible integration\n安裝 Rundeck 安裝 Rundeck 相當簡單，只要到 Rundeck 下載網址 下載對應的套件檔，就可以安裝。我是用 Ubuntu，所以下載 .deb 檔案，用 dpkg -i 就可以安裝了。\n設定 預設 Rundeck 是 Listen 4440 ，如果不設定 nginx 作 reverse proxy 的話，可以修改這兩個檔案：\n/etc/rundeck/rundeck-config.properties /etc/rundeck/framework.properties 把裡面的 http://localhost:4440 修改為 http://\u0026lt;your-ip\u0026gt;:4440 就可以了。\n設定完成，重新啟動。\nsudo systemctl restart rundeckd 重新啟動需要一段時間。\nRundeck Rundeck 本身已經有 Ansible 的 plugin，所以不需要額外安裝，但 Rundeck 主機上需要先安裝好 ansible 才行。\nRundeck 預設的帳號跟密碼是 admin / admin。\n登入以後要先新增 Project，新增完成後，點選左下角的 PROJECT SETTINGS ，再選 EDIT CONFIGURATION 。\n然後點到 Default Node executor 頁籤，這裡要把 Executor 改為 Ansible Ad-Hoc Node Executor，然後 Executable 欄位選為 /bin/bash\n連線需要帳號跟密碼，點選左下角的 PROJECT SETTINGS，再選 Key storage，到這裡去新增，然後把 private key 上傳上去。\n接著再點左下角的 PROJECT SETTINGS，再選 EDIT CONFIGURATION，再點到 Default Node executor 頁籤，往下捲到 SSH connection 的區塊。\n預設的使用者名稱是 rundeck，但這邊因為我拿 Rundeck 主機當作目的主機，Rundeck 主機上的 rundeck 帳號是無法登入的，所以我另外新增 ansible 帳號，這裡填的使用者名稱就改為 ansible 。 再點 SSH Key Storage Path 欄位旁的 Select 按鈕 ，選到剛剛新增的 Key ，選完以後，按下儲存。\n再來是設定 Node，選左下角的 PROJECT SETTINGS，再選 EDIT NODE。\n點選 Add a new Node Source，這時會跳出選單，選 Ansible Resource Model Source。\n這裡主要填 ansible inventory file path 就可以，主機清單可以預先放到 Rundeck 上的路徑，我是放在 /etc/ansible/hosts ，所以 ansible inventory file path 就是填 /etc/ansible/hosts\n新增完成以後，點選左邊的 NODES，就會出現 Nodes。\n有了 Node ，就可以去新增 Job，這邊就是填 playbook 的資訊就可以。\n我在弄後面這幾個步驟，花了很多時間，明明就是照著文件來作，卻始終看不到 NODES。然後也僅僅試成功一次執行 Ansible playbook。\n好吧，今天就弄到這裡，等有空再來詳細看為什麼 Rundeck 抓 Node 會有問題。\n","permalink":"https://ansible.cloudns.pro/post/rundeck-and-ansible-integration/","summary":"\u003cp\u003e我最早是用 Jenkins + Ansible 來執行 Playbook ，後來才用 AWX/Ansible Tower。最近在 Reddit 上看到有人介紹 Rundeck，想說來試用看看。\u003c/p\u003e\n\u003cp\u003e在 Rundeck 的文件裡，就有教學文章了：\u003ca href=\"https://docs.rundeck.com/docs/learning/howto/using-ansible.html\"\u003eRundeck and Ansible integration\u003c/a\u003e\u003c/p\u003e","title":"Rundeck 的 Ansible 整合"},{"content":"有同事問我這兩個變數的差異在哪裡？\n我查了之後才知道，其實是一樣的。這部份可以在 ansible 原始碼裏面看到。\n一般使用上，在 hosts 裏面用 ansible_user，在 playbook 裡則是用 remote_user 。 所以 ansible_user 在一開始執行的時候就被使用到，而 remote_user 則是會在不同的 play 去設定，以便針對不同的 host 做事情。 若 host 的使用者都一樣時，就不需要設定。\nAnsible remote_user vs ansible_user\n","permalink":"https://ansible.cloudns.pro/post/ansible_user-and-remote_user/","summary":"\u003cp\u003e有同事問我這兩個變數的差異在哪裡？\u003c/p\u003e\n\u003cp\u003e我查了之後才知道，其實是一樣的。這部份可以在 ansible 原始碼裏面看到。\u003c/p\u003e","title":"ansible_user 與 remote_user 的差異"},{"content":"在 Windows 要取得本機帳號清單，Ansible 沒有這樣的模組，只能透過 win_shell 或 win_powershell 來達成。\nPowerShell 要使用的指令是 Get-LocalUser 。\n輸出的結果是這樣子的\nPS C:\\Users\\Administrator\u0026gt; Get-LocalUser Name Enabled Description ---- ------- ----------- Administrator True Built-in account for administering the computer/domain DefaultAccount False A user account managed by the system. Guest False Built-in account for guest access to the computer/domain WDAGUtilityAccount False A user account managed and used by the system for Windows Defender Application Guard scen... winrm01 True 若需要其他欄位，可以用 Select\nPS C:\\Users\\Administrator\u0026gt; Get-LocalUser | Select Name, PasswordExpires Name PasswordExpires ---- --------------- Administrator DefaultAccount Guest WDAGUtilityAccount 4/22/2022 9:07:12 AM winrm01 在 Playbook 裡可以這樣寫\n- name: Get-LocalUser ansible.windows.win_shell: Get-LocalUser register: shell_output - name: Display local users debug: var: shell_output.stdout - name: Get-LocalUser | Select Name, PasswordExpires ansible.windows.win_shell: Get-LocalUser register: shell_output - name: Display local users with customized columns debug: var: shell_output.stdout 如果在 Ansible playbook 裏面需要做一些處理或判斷的話，文字的輸出其實不是很方便。這時候可以透過 PowerShell 的 ConvertTo-Json 跟 Ansible 的 from_json 將輸出轉為可處理的變數。\n- name: Get-LocalUser ansible.windows.win_shell: Get-LocalUser | ConvertTo-Json register: shell_output - name: Convert to Variable set_fact: user_list: \u0026#34;{{ shell_output.stdout | from_json }}\u0026#34; - name: Display local users debug: var: user_list 看到這邊，相信你已經知道怎麼去作 Windows 的帳號清查了。\n資料來源 How to List All User Accounts on a Windows System Using PowerShell ","permalink":"https://ansible.cloudns.pro/post/windows-get-local-users/","summary":"\u003cp\u003e在 Windows 要取得本機帳號清單，Ansible 沒有這樣的模組，只能透過 win_shell 或 win_powershell 來達成。\u003c/p\u003e\n\u003cp\u003ePowerShell 要使用的指令是 \u003ccode\u003eGet-LocalUser\u003c/code\u003e 。\u003c/p\u003e","title":"Windows-取得本機帳號清單"},{"content":"需求是這樣子的，需要把 List 裡的元素轉置為 dict，再放到 List 裡。\n也就是\nmy_users: - aaa - bbb - ccc 要轉換為\nmy_users: - Name: aaa - Name: bbb - Name: ccc 用 Ansible 該怎麼做呢？看這篇：Using filters to manipulate data 看了好久，都沒找到適合的 filter\u0026hellip;\n試了好一會，終於試出來，在這邊分享。這個方法需要使用 loop ，再搭配 List 可以相加的特性。Playbook 如下\n- name: Transform data vars: orig_users: - aaa - bbb - ccc my_users: [] set_fact: my_users: \u0026#34;{{ my_users + [{} | combine({\u0026#39;Name\u0026#39;: item})] }}\u0026#34; loop: \u0026#34;{{ orig_users }}\u0026#34; 說明如下：\n利用 combine 這個 filter 來組出 dict 利用 loop 去 iterate orig_users 用 my_users + [{} | combine({'Name': item})] 來做 List append 用這樣的方式，就可以去做出轉置了。\n參考資料：\nHow to append to lists in Ansible ","permalink":"https://ansible.cloudns.pro/post/how-to-transform-list-to-object-list/","summary":"\u003cp\u003e需求是這樣子的，需要把 List 裡的元素轉置為 dict，再放到 List 裡。\u003c/p\u003e\n\u003cp\u003e也就是\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003emy_users\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e- \u003cspan class=\"l\"\u003eaaa\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e- \u003cspan class=\"l\"\u003ebbb\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e- \u003cspan class=\"l\"\u003eccc\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e要轉換為\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003emy_users\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e- \u003cspan class=\"nt\"\u003eName\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eaaa\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e- \u003cspan class=\"nt\"\u003eName\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ebbb\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e- \u003cspan class=\"nt\"\u003eName\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eccc\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e用 Ansible 該怎麼做呢？看這篇：\u003ca href=\"https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html\"\u003eUsing filters to manipulate data\u003c/a\u003e 看了好久，都沒找到適合的 filter\u0026hellip;\u003c/p\u003e","title":"將 List 轉置為 dict 的 list"},{"content":"一般來說，Ansible Playbook 要讓 Ansible Tower (或新的名字 Ansible Automation Controller) 或 AWX 使用，有幾種方式：\n放在 Ansible Tower / Ansible Automation Controller / AWX 的主機裡，這樣的作法是最簡單，但若需要放新的 playbook 進去，勢必要使用 SSH 登入，然後才能處理。 放在 git server，這是 Best practice，一來 playbook 的變更有紀錄可循，二來也能很方便的取用。但缺點是需要架設 git server，這時候就會自建 gitlab、gitea 或是放在外部的 github、gitlab 。 這裡要介紹一種方式，是我突然想到的，也是我之前忽略的。\ngit server 本身只要有 SSH server ，其實就可以了，無需額外架設。架設的方法可以參考 Setting up the server\n以下紀錄如何進行\n第一步，先準備好 Linux 主機，已經安裝好 git 與 SSH 伺服器。\n第二步，建立一個使用者帳號，名稱為 git\nsudo adduser git 第三步，在 git 使用者家目錄下，建立 .ssh/authorized_keys 檔案，並變更權限為 0600\nsu git -c \u0026#34;cd /home/git \u0026amp;\u0026amp; mkdir -p .ssh \u0026amp;\u0026amp; touch .ssh/authorized_keys \u0026amp;\u0026amp; chmod 0600 .ssh/authorized_keys\u0026#34; 第四步，把可以登入使用者的 SSH Public key 放到 git 使用者的 .ssh/authorized_keys 檔案裡。\n這邊可以先把要登入的主機的 SSH public key 先上傳到 git server 的 /tmp 目錄，然後再用 cat 指令，把 SSH public key 內容附加到 .ssh/authorized_keys 裡。\ncat /tmp/id_rsa.pub \u0026gt;\u0026gt; /home/git/.ssh/authorized_keys 或者是就用編輯器去編輯 .ssh/authorized_keys，然後把 SSH public key 內容複製到裏面去。\n第五步，從要登入的主機 SSH private key 登入\nssh git@\u0026lt;git-server\u0026gt; 第五步，這邊我們把專案統一放到 /srv/git 目錄下，這邊以 project1 為例\nmkdir -p /srv/git/project1 cd /srv/git/project1 git init --bare chown -R git:git /srv/git 第六步，在其他主機以 git 指令驗證\ngit clone git@\u0026lt;git-server\u0026gt; 大功告成，這樣就做出一個最簡單的 Git server 了。使用 git 指令就可以操作，也可以透過 SSH 指令去新增專案了。\nssh git@\u0026lt;git-server\u0026gt; \u0026#34;mkdir -p /srv/git/project2 \u0026amp;\u0026amp; cd /srv/git/project2 \u0026amp;\u0026amp; git init --bare\u0026#34; 這時候到 Ansible Tower 上，先新增 Credential :\nCredential type 選擇 Source control SCM private key，填入前面使用的 SSH private key 按下 Save。接下來新增專案：\n類型選為 Git SCM URL 填入 git@\u0026lt;git-server\u0026gt; SCM Credential 選到剛剛新增的 Credential 按下 Save，Ansible Tower 就會開始更新。\n好了，經過這樣的設定，Ansible Tower 就已經跟剛剛建置好的 git server 整合到一起了。\n","permalink":"https://ansible.cloudns.pro/post/simplest-git-server/","summary":"\u003cp\u003e一般來說，Ansible Playbook 要讓 Ansible Tower (或新的名字 Ansible Automation Controller) 或 AWX 使用，有幾種方式：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e放在 Ansible Tower / Ansible Automation Controller / AWX 的主機裡，這樣的作法是最簡單，但若需要放新的 playbook 進去，勢必要使用 SSH 登入，然後才能處理。\u003c/li\u003e\n\u003cli\u003e放在 git server，這是 Best practice，一來 playbook 的變更有紀錄可循，二來也能很方便的取用。但缺點是需要架設 git server，這時候就會自建 gitlab、gitea 或是放在外部的 github、gitlab 。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e這裡要介紹一種方式，是我突然想到的，也是我之前忽略的。\u003c/p\u003e\n\u003cp\u003egit server 本身只要有 SSH server ，其實就可以了，無需額外架設。架設的方法可以參考 \u003ca href=\"https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server\"\u003eSetting up the server\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e以下紀錄如何進行\u003c/p\u003e","title":"最簡單的 git server"},{"content":"最近想要試著在 Oracle Linux 上安裝 Ansible Tower，Ansible Tower 的安裝腳本會中止安裝， 因為這並不是 Ansible Tower 所支援的發行版，那我就想是不是可以繞過 Linux 發行版本的檢查。\n在 Ansible Tower 的安裝腳本裡去找，有找到，但卻太複雜，改不了，大致知道是依據 facts 來做。 那只好退而求其次，改為修改 ansible_distribution 這變數，看能不能騙過 Ansible Tower 的安裝腳本。\n要變更 ansible_distribution 的方法意外的簡單，只要在執行 ansible_playbook 時，加上 -e ansible_distribution=RedHat 就可以了。\n驗證的 playbook 如下，很簡單的印出這兩個變數的內容。\n--- - name: gather information hosts: all tasks: - name: \u0026#34;Display\u0026#34; debug: msg: \u0026#34;{{ ansible_distribution }} {{ ansible_distribution_version }}\u0026#34; 先執行第一次，可以得到結果\n$ ansible-playbook -i localhost, -u ansible -k playbook.yml TASK [Display] ******************************************************************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;OracleLinux 8.5\u0026#34; } 第二次加上 -e ansible_distribution=RedHat，得到結果如下\n$ ansible-playbook -i localhost, -e ansible_distribution=RedHat -u ansible -k playbook.yml TASK [Display] ******************************************************************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;RedHat 8.5\u0026#34; } 只是事情往往沒有人所想的簡單，Ansible Tower 的安裝腳本太複雜，有太多 play，並不是很確定這樣是否都能生效。 所以這時我就想，ansible_distribution 是怎麼取得的呢？ 翻找了 Ansible 的原始碼，找到了這一段：https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/system/distribution.py\n單看程式碼，就可以猜到 Ansible 是怎麼做的了。他是直接去判斷 /etc 下是否有對應的 *-release 檔案來做判斷，然後讀取裡面的資訊。\n在 OracleLinux 裡，是讀取 /etc/oracle-release；在 Red Hat Enterprise Linux 裡，是讀取 /etc/redhat-release。\n所以這樣要騙過 Ansible 就簡單了，只要移除 /etc/oracle-release，然後把另外一台 Red Hat Enterprise Linux 的 /etc/redhat-release 與 /etc/os-release 複製過來，就可以順利讓 ansible_distribution 變為 RedHat 了。\n","permalink":"https://ansible.cloudns.pro/post/study-ansible_distribution/","summary":"\u003cp\u003e最近想要試著在 Oracle Linux 上安裝 Ansible Tower，Ansible Tower 的安裝腳本會中止安裝，\n因為這並不是 Ansible Tower 所支援的發行版，那我就想是不是可以繞過 Linux 發行版本的檢查。\u003c/p\u003e\n\u003cp\u003e在 Ansible Tower 的安裝腳本裡去找，有找到，但卻太複雜，改不了，大致知道是依據 facts 來做。\n那只好退而求其次，改為修改 ansible_distribution 這變數，看能不能騙過 Ansible Tower 的安裝腳本。\u003c/p\u003e","title":"研究-ansible_distribution"},{"content":"最近幫同事看 DRBD 還有準備考 RHCSA/RHCE，就想說可以趁這機會來練習如何用 Ansible 來操作磁碟分割區與 LVM。\n這邊有個誤會，我一直以來都以為 pvcreate / vgcreate / lvcreate 都有對應的模組可以使用，經過這次研讀後，發現只要用到 lvg 跟 lvol 這兩個模組就可以來建立。\ncommunity.general.lvg 是 LVM volume groups 的縮寫, 主要是用來設置 LVM volume groups 的模組。 這個模組包辦了 pvcreate / vgcreate 這兩個指令。\n例如要建立 volume group，就用\n- name: 在 /dev/sda1 跟 /dev/sdb1 之上建立 volume group，其 extend size 設置為 32MB community.general.lvg: vg: vg.services pvs: /dev/sda1,/dev/sdb1 pesize: 32 要移除，就加上 state: absent\n- name: 移除名稱是 vg.services 的 volume group community.general.lvg: vg: vg.services state: absent 若是要建立 local volume，則是用 community.general.lvol。\n- name: 建立一個大小為 512m 的 local volume community.general.lvol: vg: firefly lv: test size: 512 要刪掉，就加上 state: absent\n- name: 移除 local volume community.general.lvol: vg: firefly lv: test state: absent force: yes 這個模組也可以建立 thinpool、cache pool 這些。 這邊可以參照 community.general.lvol下面的範例來複製使用，會比較快。\n最後附上我去初始化 DRBD 所需要的 local volume 的 playbook，這個 playbook 首先使用 parted 去做出磁碟分割區，然後標注給 LVM 使用。 接著再使用 lvg 跟 lvol 來建立所需要的 Local volume。\n--- - name: Create LVM for DRBD hosts: all become: yes vars: vg_name: drbdpool tasks: - name: Create a new primary partition for LVM community.general.parted: device: /dev/sdb number: 1 align: optimal flags: [ lvm ] state: present - name: Create a volume group on top of /dev/sda1 with physical extent size = 32MB community.general.lvg: vg: \u0026#34;{{ vg_name }}\u0026#34; pvs: /dev/sdb1 state: present - name: Create a logical volume community.general.lvol: vg: \u0026#34;{{ vg_name }}\u0026#34; lv: drbddata size: 100%FREE 參考資料\nTest playbook for Ansible lvol module Using Ansible to automate Logical Volume Manager configurations ","permalink":"https://ansible.cloudns.pro/post/system/lvm/","summary":"\u003cp\u003e最近幫同事看 DRBD 還有準備考 RHCSA/RHCE，就想說可以趁這機會來練習如何用 Ansible 來操作磁碟分割區與 LVM。\u003c/p\u003e\n\u003cp\u003e這邊有個誤會，我一直以來都以為 pvcreate / vgcreate / lvcreate 都有對應的模組可以使用，經過這次研讀後，發現只要用到 lvg 跟 lvol 這兩個模組就可以來建立。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://docs.ansible.com/ansible/latest/collections/community/general/lvg_module.html\"\u003ecommunity.general.lvg\u003c/a\u003e 是 LVM volume groups 的縮寫, 主要是用來設置 LVM volume groups 的模組。\n這個模組包辦了 pvcreate / vgcreate 這兩個指令。\u003c/p\u003e","title":"LVM - lvg and lvol"},{"content":"在 Reddit 上看到有趣的標題：Recording Ansible playbooks from AWX with ara\n覺得有趣是因為居然可以側錄 Playbook ，而且從文章看起來，可以不需要使用 Ansible Tower / AWX 就可以很方便的去查閱執行結果，這種好東西要找時間來試試看。\n前面的那篇，其實講 awx 比較多，所以下面的操作我是參考 ara 的網站來做的：https://ara.recordsansible.org/\n安裝 安裝的方法相當簡單，首先得要有 pip，在 RHEL8 可以用以下指令安裝\nsudo yum install -y python3-pip 接著安裝 ara\npython3 -m pip install --user \u0026#34;ara[server]\u0026#34; 使用 使用的方法很簡單，設置 ANSIBLE_CALLBACK_PLUGINS 這個環境變數就可以。\nexport ANSIBLE_CALLBACK_PLUGINS=\u0026#34;$(python3 -m ara.setup.callback_plugins)\u0026#34; 然後執行 playbook\nansible-playbook -i inventory your_playbook.yml 第一次的時候，會出現初始化的訊息，第二次就不會了。\nPlaybook 執行完以後，就可以使用 ara 指令來察看結果。\n例如要察看執行過的 playbook 列表\nara playbook list 想知道其他的子指令，可以用 ara --help 取得，目前有提供這些子指令\nCommands: complete print bash completion command (cliff) expire Expires objects that have been in the running state for too long help print detailed help for another command (cliff) host delete Deletes the specified host and associated resources host list Returns a list of hosts based on search queries host metrics Provides metrics about hosts host show Returns a detailed view of a specified host play delete Deletes the specified play and associated resources play list Returns a list of plays based on search queries play show Returns a detailed view of a specified play playbook delete Deletes the specified playbook and associated resources playbook list Returns a list of playbooks based on search queries playbook metrics Provides metrics about playbooks playbook prune Deletes playbooks beyond a specified age in days playbook show Returns a detailed view of a specified playbook record delete Deletes the specified record and associated resources record list Returns a list of records based on search queries record show Returns a detailed view of a specified record result delete Deletes the specified result and associated resources result list Returns a list of results based on search queries result show Returns a detailed view of a specified result task delete Deletes the specified task and associated resources task list Returns a list of tasks based on search queries task metrics Provides metrics about actions in tasks task show Returns a detailed view of a specified task Web UI 嫌打指令太麻煩，也可以啟動 Web Server，ara 本來是用 Django 開發的，所以很容易就可以啟動。\nara-manage runserver 0.0.0.0:8000 這邊借一下 ara 官方的圖片來展示\n使用 Container 前面用的方式是把整個 ARA API server 裝到本機，ara 有提供另外一種安裝方式，可以讓 ARA API server 以 Container 方式啟動。\n# 建立資料夾作為 volume ，用來存放設定跟 sqlite 資料庫。 mkdir -p ~/.ara/server # 以 podman 啟動 API server，ara API server 的 container image 是放在 dockerhub 上。 podman run --name api-server --detach --tty \\ --volume ~/.ara/server:/opt/ara:z -p 8000:8000 \\ docker.io/recordsansible/ara-api:latest # 安裝 ARA client python3 -m pip install --user ara # 設定 ANSIBLE_CALLBACK_PLUGINS 來捕捉執行 Playbook 的運行結果。 export ANSIBLE_CALLBACK_PLUGINS=\u0026#34;$(python3 -m ara.setup.callback_plugins)\u0026#34; # 設定環境變數，讓 ARA callback 知道 API server 在哪裡。 export ARA_API_CLIENT=\u0026#34;http\u0026#34; export ARA_API_SERVER=\u0026#34;http://127.0.0.1:8000\u0026#34; # 執行 playbook ansible-playbook playbook.yaml 結論 ara 這個專案補足了一部份 AWX / Ansible Tower(現改名為 Ansible automation controller) 在呈現結果上的的缺陷， 即使不使用 AWX / Ansible Tower，也可以透過 ara 來察看執行的歷史， 所以大家可以安裝來試試看。\n若想要參與這個專案的開發，可以到 GitHub 這邊來參與：https://github.com/ansible-community/ara-collection/\n","permalink":"https://ansible.cloudns.pro/post/recording-ansible-playbooks-with-ara/","summary":"\u003cp\u003e在 Reddit 上看到有趣的標題：\u003ca href=\"https://ara.recordsansible.org/blog/2021/12/23/recording-ansible-playbooks-from-awx-with-ara/\"\u003eRecording Ansible playbooks from AWX with ara\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e覺得有趣是因為居然可以側錄 Playbook ，而且從文章看起來，可以不需要使用 Ansible Tower / AWX 就可以很方便的去查閱執行結果，這種好東西要找時間來試試看。\u003c/p\u003e","title":"使用 ara 來側錄 Ansible Playbook"},{"content":"因為需要知道受管主機上的 Python，所以就弄了個簡單的 Playbook 來偵測。\nAnsible 因為本身需要 Python 來運行 Playbook，自然會收集 Python 的資訊以作為執行的參考。\n在 gather_facts 沒有被設定為 no 的情況下，Ansible 在執行 playbook 時就會收集受管主機的相關資訊，因此可以使用以下變數來取得 Python 的版本資訊\nansible_facts.python ansible_facts.python.executable ansible_facts.python.version 下面這個 Playbook 就展示了如何印出 Python 的執行檔路徑、版本資訊與 Linux 發行版資訊。\n--- - name: Test interpreter hosts: all tasks: - name: display python version debug: msg: \u0026#34;{{ansible_facts.python.executable}} {{ansible_facts.python.version.major}}.{{ansible_facts.python.version.minor}}\u0026#34; - name: display distribution version debug: msg: \u0026#34;{{ansible_distribution}} {{ansible_distribution_version}}\u0026#34; 那麼 Ansible 是怎麼判斷使用哪個 Python 呢？這邊是可以在 ansible.cfg 裡設定的。\n在 ansible.cfg 的 [defaults] 區段裡加入 interpreter_python= 就可以告知 ansible 該怎麼去找 python\nauto_legacy: 這會偵測受管主機的作業系統、Linux 發行套件以及 Python 版本，然後依據一份內定的表格來判斷使用哪一個 python。 auto: 在 2.12 後，auto 就是預設值，這會偵測受管主機的作業系統、Linux 發行套件以及 Python 版本來決定使用哪一個 python。 auto_legacy_silent: 跟 auto_legacy 一樣，只是不印出 warning auto_silent: 跟 auto 一樣，只是不印出 warning auto_legacy 跟 auto 主要的差異就是偵測 Python 的方法不一樣。\n如果想要直接指定 python 路徑也是可以的，所以 ansible.cfg 裡也可以這樣寫，讓 Ansible 使用 /usr/bin/python3\n[defaults] interpreter_python = /usr/bin/python3 以下列出幾個 Linux 發行版本所偵測出來的 Python 版本：\nRHEL 7: /usr/bin/python 2.7 RHEL 8: /usr/libexec/platform-python 3.6 Ubuntu 20.04: /usr/bin/python 2.7 參考文件 Interpreter Discovery Python 3 Support ","permalink":"https://ansible.cloudns.pro/post/system/detect-python-version/","summary":"\u003cp\u003e因為需要知道受管主機上的 Python，所以就弄了個簡單的 Playbook 來偵測。\u003c/p\u003e\n\u003cp\u003eAnsible 因為本身需要 Python 來運行 Playbook，自然會收集 Python 的資訊以作為執行的參考。\u003c/p\u003e","title":"如何偵測受管主機上的Python版本"},{"content":"今天在 Reddit 上看到這篇：How to use ansible-doc manpages in vim : ansible\n覺得很實用，就來介紹一下。\n在 vim 裡，可以按下 K ，來查詢游標當下的關鍵字說明，所以可以透過在 .vimrc 裡增加以下這行：\nautocmd BufNewFile,BufRead *.yml set keywordprg=ansible-doc 之後開啟 playbook ，游標移到 task 的模組上面，按下 K ，vim 就會執行 ansible-doc 來查詢模組的使用方法，這樣就可以不需要打開瀏覽器來查找用法了。\n","permalink":"https://ansible.cloudns.pro/post/how-to-use-ansible-doc-manpages-in-vim/","summary":"\u003cp\u003e今天在 Reddit 上看到這篇：\u003ca href=\"https://www.reddit.com/r/ansible/comments/rqyrx7/how_to_use_ansibledoc_manpages_in_vim/\"\u003eHow to use ansible-doc manpages in vim : ansible\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e覺得很實用，就來介紹一下。\u003c/p\u003e","title":"如何在 vim 直接查詢 ansible module 使用方法"},{"content":"這篇主要是講如何安裝 Ansible Automation Platform 2.1.0 。\n硬體需求：\nCPUs: 4 RAM: 16G 環境是 Red Hat Enterprise Linux 8.4，需要先使用 subscription-manager 註冊。\n下載地點需要登入 Red Hat Customer Portal：https://access.redhat.com/downloads/content/480/\n這裡是選 Ansible Automation Platform 2.1.0 Setup Bundle 來下載，網速不快的話，得要耐心等。\n下載以後，就用 tar xvf 解開。解開後會有 ansible-automation-platform-setup-bundle-2.1.0 的目錄。進入該目錄，編輯 inventory 這個檔案的內容。主要修改以下項目：\n[all:vars] admin_password=\u0026#39;\u0026lt;your_password\u0026gt;\u0026#39; pg_password=\u0026#39;\u0026lt;your_db_password\u0026gt;\u0026#39; registry_username=\u0026#39;\u0026lt;your_rhn_account\u0026gt;\u0026#39; registry_password=\u0026#39;\u0026lt;your_rhn_password\u0026gt;\u0026#39; 修改完畢以後，輸入\n./setup.sh 就會開始進行安裝了。\n安裝完成後，使用瀏覽器去瀏覽，看能否登入使用，若可以登入，就是大功告成了。 若安裝有錯誤，就依照錯誤訊息來看怎麼處理跟排除，完成後，再執行一次 ./setup.sh 即可。\n","permalink":"https://ansible.cloudns.pro/post/ansible-automation-platform-2.1.0-installation/","summary":"\u003cp\u003e這篇主要是講如何安裝 Ansible Automation Platform 2.1.0 。\u003c/p\u003e\n\u003cp\u003e硬體需求：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eCPUs: 4\u003c/li\u003e\n\u003cli\u003eRAM: 16G\u003c/li\u003e\n\u003c/ul\u003e","title":"安裝 Ansible Automation Platform 2.1.0"},{"content":"AWX 目前最新版本是 19.5.0，從 18.0.0 開始，安裝方法只有一種，就是以 AWX Operator 形式安裝在 k8s / OpenShift 上。\n想要安裝到本機使用，只有兩種方法，第一種是安裝為開發 AWX 用的環境，第二種方法是退版，使用 17.1.0。這邊要介紹的是第二種方法，安裝 17.1.0。\n環境： Red Hat Enterprise Linux 8.5\n安裝 git 首先安裝 git，因為需要用 git 取得 AWX 的原始碼，主要是使用 installer 目錄裡的內容。\nsudo yum -y install git ansible git clone https://github.com/ansible/awx.git git checkout 17.1.0 安裝 docker 與 docker-compose sudo yum install python3-pip sudo yum-config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo sudo yum install docker-ce docker-ce-cli containerd.io sudo pip3 install docker docker-compose sudo curl -L \u0026#34;https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)\u0026#34; -o /usr/local/bin/docker-compose 編輯 inventory 切到 awx/installer 目錄下，編輯 inventory，加入以下內容\nadmin_password=\u0026lt;your_password\u0026gt; 若需要 SSL ，也是在此檔案裡去指定憑證位置跟相關設定。\n安裝 好了以後，執行以下指令安裝即可\nansible-playbook -i inventory install.yml 完成以後，就可以用瀏覽器來開啟了。\n","permalink":"https://ansible.cloudns.pro/post/awx/awx-17.1.0-installation/","summary":"\u003cp\u003eAWX 目前最新版本是 19.5.0，從 18.0.0 開始，安裝方法只有一種，就是以 AWX Operator 形式安裝在 k8s / OpenShift 上。\u003c/p\u003e\n\u003cp\u003e想要安裝到本機使用，只有兩種方法，第一種是安裝為開發 AWX 用的環境，第二種方法是退版，使用 17.1.0。這邊要介紹的是第二種方法，安裝 17.1.0。\u003c/p\u003e","title":"安裝 AWX 17.1.0"},{"content":"在購買 Ansible Tower license 或是取得 Ansible Tower Trial license 以後，一般可以直接在 Ansible Tower 裡登入 RHN 帳號， 從而取得 license。但是在離線環境的時候，就沒辦法這樣做，這時候得從 https://acccess.redhat.com 網站上進行訂閱分配，然後取得 license 檔案。這個檔案就可以在離線環境的時候，提供給 Ansible Tower 使用。\n在 Ansible Tower 3.7.x 以前，所使用的 license 檔案格式是 JSON，但現在從 https://access.redhat.com 上所製作出來的 license 檔案 不管格式怎麼選，都是是 zip 檔案，這個檔案又被稱為 manifest 檔案。所以在 Ansible Tower 3.7.x 就無法使用，這時候就需要請 Red Hat support team 來幫忙取得。\n如果現在是使用 3.7.x ，建議是儘早升級到 Ansible Tower 3.8.x 以後的版本會比較妥當。\n","permalink":"https://ansible.cloudns.pro/post/ansible-tower-license-file-format/","summary":"\u003cp\u003e在購買 Ansible Tower license 或是取得 Ansible Tower Trial license 以後，一般可以直接在 Ansible Tower 裡登入 RHN 帳號，\n從而取得 license。但是在離線環境的時候，就沒辦法這樣做，這時候得從 \u003ca href=\"https://acccess.redhat.com\"\u003ehttps://acccess.redhat.com\u003c/a\u003e 網站上進行訂閱分配，然後取得\nlicense 檔案。這個檔案就可以在離線環境的時候，提供給 Ansible Tower 使用。\u003c/p\u003e","title":"Ansible Tower license 檔案的格式"},{"content":"這兩天遇到一個狀況，以瀏覽器登入 Ansible Tower 網站，發生了無法設定 License 的情況。是故，只能透過 CLI 方式來進行。\n方法有幾個：\n使用 tower-cli (若是 AWX，就是 awx) 使用 curl 使用 Tower 這個 collection (3.8.0 以後，而且這 module 在 automation hub) 使用 tower-cli / awx tower-cli setting modify LICENSE \u0026#39;{\u0026#34;eula_accepted\u0026#34; : \u0026#34;true\u0026#34;, \u0026#34;subscription_name\u0026#34;: \u0026#34;Enterprise Tower up to 100 Nodes\u0026#34;, ....}\u0026#39; awx setting modify LICENSE \u0026#39;{\u0026#34;eula_accepted\u0026#34; : \u0026#34;true\u0026#34;, \u0026#34;subscription_name\u0026#34;: \u0026#34;Enterprise Tower up to 100 Nodes\u0026#34;, ....}\u0026#39; 不過，說真的，誰會知道後面要填什麼\u0026hellip;在已經有 license 的主機上取得的結果大致是這樣\n{\u0026#39;subscription_name\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;sku\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;support_level\u0026#39;: None, \u0026#39;instance_count\u0026#39;: 20, \u0026#39;license_date\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;license_type\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;product_name\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;valid_key\u0026#39;: True, \u0026#39;pool_id\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;satellite\u0026#39;: False} 使用 curl 這方法跟上面是相似的，因為上面的 tower-cli / awx 也是使用 Tower API 來處理。\n使用 Tower collection Tower 這個 Collection 是放在 Red Hat Automation Hub 上，所以用 ansible-galaxy collection install 的時候，會出現錯誤，因為 galaxy.ansible.com 上並沒有這個 collection。\n取巧的步驟可以參考下面。\n第一步，編輯 ansible.cfg\n[defaults] collections_paths=./collections 第二步，安裝 ansible.tower 這個 collection。\n到這個網址：https://console.redhat.com/ansible/automation-hub/repo/published/ansible/tower 下載 tarball ，下載完成後解壓縮放到 collections/ansible_collections/ansible/tower 下面。\n# 假設 tarball 路徑是 ~/Downloads/ansible-tower-3.8.4.tar.gz mkdir -p collections/ansible_collections/ansible/tower cd collections/ansible_collections/ansible/tower tar xf ~/Downloads/ansible-tower-3.8.4.tar.gz 第三步，新增 playbook.yml\n--- - hosts: localhost collections: - ansible.tower # - awx.awx #when using awx.awx tasks: - name: Upload manifest delegate_to: localhost tower_license: manifest: \u0026#34;{{ manifest }}\u0026#34; eula_accepted: yes tower_username: \u0026#34;{{ tower_username }}\u0026#34; tower_password: \u0026#34;{{ tower_password }}\u0026#34; tower_host: \u0026#34;{{ tower_host }}\u0026#34; validate_certs: no 第四步，到 access.redhat.com 去配置 subscription (步驟可以參考 4. Import a Subscription — Ansible Tower User Guide v3.8.4 )，然後下載為 manifest.zip，在 Tower 主機裡執行以下指令來匯入 license\nansible-playbook playbook.yml -e manifest=./manifest.zip \\ -e tower_username=\u0026lt;tower_admin\u0026gt; \\ -e tower_password=\u0026lt;tower_admin_password\u0026gt; \\ -e tower_host=\u0026lt;tower_host\u0026gt; 這樣就大功告成了。\n補充 把 Red Hat Automation Hub 加到 galaxy server list 的方法是在 ansible.cfg 裡加入\n[galaxy] server_list = automation_hub [galaxy_server.automation_hub] url=https://cloud.redhat.com/api/automation-hub/ auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token token=my_ah_token 參考資料 https://access.redhat.com/solutions/3065701 Using collections — Ansible Documentation ","permalink":"https://ansible.cloudns.pro/post/upload-ansible-tower-license-in-cli/","summary":"\u003cp\u003e這兩天遇到一個狀況，以瀏覽器登入 Ansible Tower 網站，發生了無法設定 License 的情況。是故，只能透過 CLI 方式來進行。\u003c/p\u003e\n\u003cp\u003e方法有幾個：\u003c/p\u003e","title":"以指令設定 Ansible Tower 的 License"},{"content":"轉貼去年 12 月時寫的 ansible-builder。\n看到這篇：紅帽推出IT自動化工具Ansible Builder以加速執行環境創建 | iThome，所以就來試試看。\n就我試用過以後，我的理解是，這工具可以幫忙創建出一個具有 Ansible 環境的 container image。\n環境是定義在 execution-environment.yml 裡，讓我們直接看範例\n--- version: 1 # 即基礎 image，目前來說，都是用 quay.io/ansible/ansible-runner:stable-2.9-devel base_image: \u0026#39;quay.io/ansible/ansible-runner:stable-2.9-devel\u0026#39; # 需要自訂 ansible.cfg 的話，這邊就是填 ansible.cfg 的路徑檔名 ansible_config: \u0026#39;ansible.cfg\u0026#39; # 相依 # galaxy 是填 requirements.yml，檔案裡描述 playbook 會用到的 role/collection，沒用到可以不填 # python 則是填 requirements.txt，檔案裡描述會使用到的 Python modules，沒用到可以不填 dependencies: galaxy: requirements.yml python: # 額外要加入的 docker image 建置步驟 # prepend 會在預定的建置步驟之前 # append 則是在預定的建置步驟之後 additional_build_steps: prepend: | RUN whoami RUN cat /etc/os-release append: - RUN echo This is a post-install command! - RUN ls -la /etc 有了 execution-environment.yml 之後，就可以用 ansible-builder 來建置。\n首先，得先安裝 ansible-builder 這工具：\npip3 install ansible-builder 接著就可以建置了\nansible-builder build --tag=example 建置完成，會有 container image，在目錄下則會出現 context 資料夾，這個資料夾裏面就是 ansible-builder 建置過程中所產出的 Dockerfile 以及建置 container image 所需的檔案。\n打開 Dockerfile ，就會看到 ansible-builder 幫我們產出了什麼。\nFROM quay.io/ansible/ansible-runner:stable-2.9-devel as galaxy ADD ansible.cfg ~/.ansible.cfg ADD requirements.yml /build/ RUN ansible-galaxy role install -r /build/requirements.yml --roles-path /usr/share/ansible/roles RUN ansible-galaxy collection install -r /build/requirements.yml --collections-path /usr/share/ansible/collections RUN mkdir -p /usr/share/ansible/roles /usr/share/ansible/collections FROM quay.io/ansible/python-builder:latest as builder ADD requirements_combined.txt /tmp/src/requirements.txt RUN assemble FROM quay.io/ansible/ansible-runner:stable-2.9-devel RUN whoami RUN cat /etc/os-release COPY --from=galaxy /usr/share/ansible/roles /usr/share/ansible/roles COPY --from=galaxy /usr/share/ansible/collections /usr/share/ansible/collections COPY --from=builder /output/ /output/ RUN /output/install-from-bindep \u0026amp;\u0026amp; rm -rf /output/wheels RUN echo This is a post-install command! RUN ls -la /etc 大抵來說，\n使用了 multi stage build 以減少 docker image 的大小 使用 ansible-galaxy 安裝相依的 role/collection 會看到 additional_build_steps 裡描述的步驟 好，那建置出 docker image 以後，怎麼使用呢？\n假設 playbook 是放在 project 目錄下，那麼就這樣執行\ndocker run --rm -v /runner/project:$(pwd)/project -it example:latest ansible-playbook -i localhost, -c local /runner/project/test.yml 這邊稍微取了點巧，只簡單用 local connection (-i localhost, -c local) 在本機執行，你也可以在這邊使用自己的 inventory。\n建置出 Ansible 執行環境的 docker image 以後，除了可以固定住執行 Ansible playbook 的環境，也有利於打造出標準化的 CD 環境，進而減少開發與佈署的時間。\n","permalink":"https://ansible.cloudns.pro/post/ansible-builder/","summary":"\u003cp\u003e轉貼去年 12 月時寫的 ansible-builder。\u003c/p\u003e\n\u003cp\u003e看到這篇：\u003ca href=\"https://www.ithome.com.tw/news/141682\"\u003e紅帽推出IT自動化工具Ansible Builder以加速執行環境創建 | iThome\u003c/a\u003e，所以就來試試看。\u003c/p\u003e\n\u003cp\u003e就我試用過以後，我的理解是，這工具可以幫忙創建出一個具有 Ansible 環境的 container image。\u003c/p\u003e","title":"ansible-builder"},{"content":"在9月底的時候，Red Hat 釋出了 Ansible Automation Platform 2，詳情可以參考： Introducing Ansible Automation Platform 2\n主要的變動，這邊大致整理如下：\nAnsible 拆出 Ansible core (Ansible base)，也就是把核心引擎拆分出來，這是大約年初時的變動。原來的 Ansible 則變為 Ansible Community，類似 Meta package 的概念， 所以之後在安裝 Ansible 時，就變成是安裝 Ansible core package 跟模組/collection 的 package。對一般使用 Ansible 的人來說，沒有太大改變。好處是模組/collection就不一 定要等新版 Ansible 釋出才能有更新。 Ansible Tower 的部份是更名為 Automation controller ，並加入了執行環境的管理。 Red Hat 這次發佈的消息裡，包含了可以在線上試用的環境，你可以透過這個網站來使用，而無需安裝：Experience Ansible Automation Platform with Self-Paced Labs\nAutomation Controller ，也就是 Ansible Tower 的 UI 改動不大，基本上跟之前的 Ansible Tower 3.x 差不多。\n執行環境是新增加的部份。\n為了搭配這個執行環境，Job template 也做了調整\n利用 rpm 指令看安裝了哪些套件\n再來看看 Ansible navigator，執行 Ansible navigator 之前，需要先用 podman 登入 registry.redhat.io，ansible-navigator 會從 registry.redhat.io 去拉取 container image，然後執行。\n執行以後，可以看到如下的畫面\n透過這個畫面可以去察看這台機器上的 collections, config, inventory 等等。\n簡單的說，這次的 Ansible Automation Platform 2 主要是加入了「執行環境」的元素然後重新包裝，之後得找時間針對執行環境這個元素來做研究。\n","permalink":"https://ansible.cloudns.pro/post/ansible-automation-platform-2/","summary":"\u003cp\u003e在9月底的時候，Red Hat 釋出了 Ansible Automation Platform 2，詳情可以參考： \u003ca href=\"https://www.ansible.com/blog/introducing-ansible-automation-platform-2\"\u003eIntroducing Ansible Automation Platform 2\u003c/a\u003e\u003c/p\u003e","title":"Ansible automation Platform 2"},{"content":"要怎麼佈署 repository 伺服器呢？\n這蠻簡單的，可以參考\nhttps://www.redhat.com/sysadmin/how-mirror-repository https://gist.github.com/ziozzang/f37f04c27cff85f093e146a27537fe81 受管主機的環境：RHEL 8.2\n要做一個 repository 伺服器，第一個要先註冊到紅帽，因為需要從他的 Repository 伺服器下載套件。 第二個是安裝 yum-utils, httpd, createrepo。\n我的 Playbook 資料夾路徑安排如下\n. |____files | |____sync-repo.sh |____playbook.yml files/sync-repo.sh 是用來同步的 script。 playbook.yml 是主要的 playbook。 先來看 playbook.yml\n--- - name: Install repo server hosts: all become: yes vars_prompt: - name: username prompt: \u0026#34;Your Red Hat account username\u0026#34; private: no - name: password prompt: \u0026#34;Your Red Hat account password\u0026#34; private: yes tasks: - name: Register redhat_subscription: state: present # org_id: \u0026#34;{{ organization_key }}\u0026#34; # activationkey: \u0026#34;{{ activation_key }}\u0026#34; username: \u0026#34;{{ username }}\u0026#34; password: \u0026#34;{{ password }}\u0026#34; force_register: yes when: username | length \u0026gt; 0 and password | length \u0026gt; 0 - name: Install required packages yum: name: - yum-utils - createrepo - httpd state: present - name: Enable Apache service: name: httpd enabled: yes state: started - name: Install script copy: src: files/sync-repo.sh dest: /usr/local/bin/sync-repo.sh mode: 0755 - name: Install crontab cron: name: \u0026#34;Sync repositories\u0026#34; minute: \u0026#34;0\u0026#34; hour: \u0026#34;2\u0026#34; job: \u0026#34;/usr/local/bin/sync-repo.sh\u0026#34; 使用 vars_prompt 來詢問 Red Hat account 的帳號跟密碼 安裝必要的套件。 安裝 httpd，然後啟用跟啟動。 把 script 放到伺服器裡 新增 cron job。 files/sync-repo.sh 裡面則是\n#!/bin/bash # you can use `yum repolist` to get repositories WWWROOT=/var/www/html for repoid in rhel-8-for-x86_64-baseos-rpms rhel-8-for-x86_64-baseos-rpms; do reposync --nogpgcheck --download-metadata --repoid=${repoid} -p ${WWWROOT} done 執行完 playbook，repository 伺服器就安裝好了，下載、同步套件的工作則會等到半夜兩點才執行。若需要立刻執行，可以用下列指令來執行。\nansible -m shell -a \u0026#34;/usr/local/bin/sync-repo.sh\u0026#34; -i \u0026lt;your_host\u0026gt; -u \u0026lt;username\u0026gt; -k ","permalink":"https://ansible.cloudns.pro/post/mirror-repository/","summary":"\u003cp\u003e要怎麼佈署 repository 伺服器呢？\u003c/p\u003e\n\u003cp\u003e這蠻簡單的，可以參考\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.redhat.com/sysadmin/how-mirror-repository\"\u003ehttps://www.redhat.com/sysadmin/how-mirror-repository\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://gist.github.com/ziozzang/f37f04c27cff85f093e146a27537fe81\"\u003ehttps://gist.github.com/ziozzang/f37f04c27cff85f093e146a27537fe81\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e受管主機的環境：RHEL 8.2\u003c/p\u003e","title":"佈署 repository 伺服器的 Playbook"},{"content":"Ansible 4.3.0 在 2021/07/20 釋出了。\n公告： (Ansible 4.3.0 final has been released!) ChangeLog 這一版有什麼新的功能呢？摘錄如下\nAnsible-core 的版本是 2.11.3 有變更的 Collections (摘錄) community.digitalocean 由 1.7.0 升級到 1.8.0 community.general 由 3.3.0 升級到 3.4.0 community.hashi_vault 由 1.3.0 升級到 1.3.2 community.postgresql 由 1.3.0 升級到 1.4.0 community.vmware 由 1.11.0 升級到 1.12.0 community.zabbix 由 1.3.0 升級到 1.4.0 netapp.ontap 由 21.7.0 升級到 21.8.1 新的 Plugin community.zabbix.zabbix_inventory 新的 Module community.general.keycloak_clientscope community.general.keycloak_role community.general.gitlab_protected_branch community.zabbix.zabbix_globalmacro netapp.ontap.na_ontap_cifs_local_user_set_password netapp.ontap.na_ontap_fdsd netapp.ontap.na_ontap_fdsp netapp.ontap.na_ontap_fdspt netapp.ontap.na_ontap_fdss netapp.ontap.na_ontap_partitions ","permalink":"https://ansible.cloudns.pro/post/ansible-4.3.0/","summary":"\u003cp\u003eAnsible 4.3.0 在 2021/07/20 釋出了。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e公告： (\u003ca href=\"https://groups.google.com/g/ansible-announce/c/ssbMIqs4qNM\"\u003eAnsible 4.3.0 final has been released!\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ansible-community/ansible-build-data/blob/main/4/CHANGELOG-v4.rst#v4-3-0\"\u003eChangeLog\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e這一版有什麼新的功能呢？摘錄如下\u003c/p\u003e","title":"Ansible 4.3.0"},{"content":"主要是想試著用 vagrant 搭建 keepalived 環境來練習。\n環境需要四台機器：\nkeepalived: 兩台，一台 master，一台 slave，這兩台同時也會安裝 HAProxy。 主機名稱：master, 192.168.60.11 主機名稱：slave: 192.168.60.12 Apache: 一台，當作是 HAProxy 的 backend。 主機名稱：u3 Bastion: 一台，當作是客戶端，用來存取 VIP。 主機名稱：u4 因為 Vagrantfile 裏面是針對每一台主機去指定 provisioner 使用 Ansible，所以是個別去執行 ansible playbook。這裡有三台主機指定了 provisioner，所以會執行三次。\n這也會影響到 playbook 的寫法，這邊我是儘量把共用的部份抽取出來，然後使用 include_tasks: xxx.yml 來包含共用的部份。\n整份程式碼放在 elleryq/vagrant-keepalived-demo: Demo keepalived with Vagrant\n這裡不多做贅述，只紀錄這次比較印象深刻的幾個模組用法：\nseport: 要使用這個模組，在 RHEL8/CentOS8 裡要安裝 python3-libselinux 跟 python3-policycoreutils。 firewalld: 要立即生效，記得加上 immediate: yes。 ","permalink":"https://ansible.cloudns.pro/post/setup-keepalived/","summary":"\u003cp\u003e主要是想試著用 vagrant 搭建 keepalived 環境來練習。\u003c/p\u003e\n\u003cp\u003e環境需要四台機器：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ekeepalived: 兩台，一台 master，一台 slave，這兩台同時也會安裝 HAProxy。\n\u003cul\u003e\n\u003cli\u003e主機名稱：master, 192.168.60.11\u003c/li\u003e\n\u003cli\u003e主機名稱：slave: 192.168.60.12\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eApache: 一台，當作是 HAProxy 的 backend。\n\u003cul\u003e\n\u003cli\u003e主機名稱：u3\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eBastion: 一台，當作是客戶端，用來存取 VIP。\n\u003cul\u003e\n\u003cli\u003e主機名稱：u4\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e","title":"Keepalived"},{"content":"在看 Ansible 4.1.0 的釋出新聞時，看到 Ansible navigator 這個專案，這個專案的網址是在 GitHub - ansible/ansible-navigator: A text-based user interface (TUI) for the Red Hat Ansible Automation Platform.\n從說明可以得知，這是 Ansible Automation Platform 的 text-based 使用者介面 (TUI)，而不是 Ansible Tower 的 text-based 使用者介面，這讓我有點小失望。\n目前只提供了 pip 的安裝方式\npip install ansible-navigator 執行以後，會先使用 docker 去拉取 ansible-navigator-demo-ee 的 container image 下來。 接著就可以看到畫面，大致的使用狀況可以參考 Youtube https://youtu.be/J9PBKi8ydi4 操作方式跟 vi 很接近，我想可能要花點時間來挖掘一下，看可以怎麼來利用。\n","permalink":"https://ansible.cloudns.pro/post/ansible-navigator/","summary":"\u003cp\u003e在看 Ansible 4.1.0 的釋出新聞時，看到 Ansible navigator 這個專案，這個專案的網址是在 \u003ca href=\"https://github.com/ansible/ansible-navigator\"\u003eGitHub - ansible/ansible-navigator: A text-based user interface (TUI) for the Red Hat Ansible Automation Platform.\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e從說明可以得知，這是 Ansible Automation Platform 的 text-based 使用者介面 (TUI)，而不是 Ansible Tower 的 text-based 使用者介面，這讓我有點小失望。\u003c/p\u003e","title":"Ansible navigator"},{"content":"Task 要依據 Linux 發行版來處理，該怎麼做呢？\n這些資訊在 gather_facts 後，會放到 ansible_facts 裡，在寫 task 時，就可以直接使用。\n主要的變數有這幾個：\nansible_distribution: 發行版名稱，例如 \u0026ldquo;CentOS\u0026rdquo; ansible_distribution_major_version: 發行版主要版號，例如 \u0026ldquo;7\u0026rdquo; ansible_distribution_version: 發行版版本，例如 \u0026ldquo;7.5.1804\u0026rdquo; ansible_os_family: 發行版家族名稱，例如 CentOS 的 ansible_os_family 會是 RedHat 要看 ansible_facts 還有哪些變數可使用，可以參考 Discovering variables: facts and magic variables — Ansible Documentation\n舉個例子：\n--- - name: Detect distribution example hosts: all gather_facts: yes tasks: - name: Enable satellite-tools repository rhsm_repository: name: rhel-7-server-satellite-tools-6.8-rpms state: enabled when: ansible_distribution == \u0026#34;RedHat\u0026#34; and ansible_distribution_major_version == \u0026#34;7\u0026#34; - name: Enable satellite-tools repository rhsm_repository: name: satellite-tools-6.8-for-rhel-8-x86_64-rpms state: enabled when: ansible_distribution == \u0026#34;RedHat\u0026#34; and ansible_distribution_major_version == \u0026#34;8\u0026#34; 參考資料 An introduction to Ansible facts | Enable Sysadmin Discovering variables: facts and magic variables — Ansible Documentation ","permalink":"https://ansible.cloudns.pro/post/system/detect-distribution/","summary":"\u003cp\u003eTask 要依據 Linux 發行版來處理，該怎麼做呢？\u003c/p\u003e\n\u003cp\u003e這些資訊在 gather_facts 後，會放到 ansible_facts 裡，在寫 task 時，就可以直接使用。\u003c/p\u003e\n\u003cp\u003e主要的變數有這幾個：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eansible_distribution: 發行版名稱，例如 \u0026ldquo;CentOS\u0026rdquo;\u003c/li\u003e\n\u003cli\u003eansible_distribution_major_version: 發行版主要版號，例如 \u0026ldquo;7\u0026rdquo;\u003c/li\u003e\n\u003cli\u003eansible_distribution_version: 發行版版本，例如 \u0026ldquo;7.5.1804\u0026rdquo;\u003c/li\u003e\n\u003cli\u003eansible_os_family: 發行版家族名稱，例如 CentOS 的 ansible_os_family 會是 RedHat\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e要看 ansible_facts 還有哪些變數可使用，可以參考 \u003ca href=\"https://docs.ansible.com/ansible/latest/user_guide/playbooks_vars_facts.html\"\u003eDiscovering variables: facts and magic variables — Ansible Documentation\u003c/a\u003e\u003c/p\u003e","title":"如何判別 Linux 發行版"},{"content":"Ansible 4.2.0 在 2021/06/30 釋出了。\n公告： (Ansible 4.2.0 final has been released!) ChangeLog 這一版有什麼新的功能呢？摘錄如下\nAnsible 4.2.0 的核心 Ansible Core 已經是 2.11.2 ，主要是安全更新與修正問題，這部份可以參考 ChangeLog 模組需要調整的地方，可以參考 Porting Guide 4.x 的發佈周期大約是三周，預定 4.3.0 的發佈會是在 2021/07/20 預定 5.0.0 的發佈會是在 2021/11 想不到後天就要釋出 4.3.0 了，好快。\n","permalink":"https://ansible.cloudns.pro/post/ansible-4.2.0/","summary":"\u003cp\u003eAnsible 4.2.0 在 2021/06/30 釋出了。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e公告： (\u003ca href=\"https://groups.google.com/g/ansible-devel/c/J1Yr2Fa2fgc\"\u003eAnsible 4.2.0 final has been released!\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ansible-community/ansible-build-data/blob/main/4/CHANGELOG-v4.rst#v4-2-0\"\u003eChangeLog\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e這一版有什麼新的功能呢？摘錄如下\u003c/p\u003e","title":"Ansible 4.2.0"},{"content":"Ansible 4.1.0 在 2021/06/11 釋出了。\n公告： (Ansible 4.1.0 final has been released!) ChangeLog 這一版有什麼新的功能呢？摘錄如下\nAnsible 4.1.0 的核心 Ansible Core 已經是 2.11.1 ，這次比較主要的變動還是在於模組，需要調整的地方，可以參考 Porting Guide 預定 4.2.0 的發佈會是在 2021/06/29 預定 5.0.0 的發佈會是在 2021/11 ","permalink":"https://ansible.cloudns.pro/post/ansible-4.1.0/","summary":"\u003cp\u003eAnsible 4.1.0 在 2021/06/11 釋出了。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e公告： (\u003ca href=\"https://groups.google.com/g/ansible-devel/c/JnJU7g0XjLo\"\u003eAnsible 4.1.0 final has been released!\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ansible-community/ansible-build-data/blob/main/4/CHANGELOG-v4.rst#v4-1-0\"\u003eChangeLog\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e這一版有什麼新的功能呢？摘錄如下\u003c/p\u003e","title":"Ansible 4.1.0"},{"content":"Ansible 在 2021 年五月中的時候釋出了。\n公告： (Ansible 4.0.0 final has been released!) ChangeLog 這一版有什麼新的功能呢？摘錄如下\nAnsible 3.0.0 的核心 Ansible Core 是 2.10.5。 Ansible 4.0.0 的核心 Ansible Core 已經是 2.11 ，有些語法跟之前不相容，需要調整。請參考 Porting Guide 增加了 ansible-test 指令，可以測試 collections，關於這指令，可以參考 Introduction to ansible-test ansible-galaxy collection install 多了 --upgrade 選項，可以用這來升級。 有些 collections 已經變為 Ansible 4.0.0 裡的一部份，關於 modules / collections 的變動，可以參考 ChangeLog 。 接下來的每三周會釋出 4.1.0, 4.2.0\u0026hellip;\n","permalink":"https://ansible.cloudns.pro/post/ansible-4.0.0/","summary":"\u003cp\u003eAnsible 在 2021 年五月中的時候釋出了。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e公告： (\u003ca href=\"https://groups.google.com/g/ansible-announce/c/H7LvB-uYMWg\"\u003eAnsible 4.0.0 final has been released!\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ansible-community/ansible-build-data/blob/main/4/CHANGELOG-v4.rst#v4-0-0\"\u003eChangeLog\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e這一版有什麼新的功能呢？摘錄如下\u003c/p\u003e","title":"Ansible 4.0.0"},{"content":"網友 Weithenn 分享的好文，是講怎麼用 Ansible 設定 Cisco UCS CIMC 的文章，現整理目錄如下：\nAnsible - 設定 Cisco UCS CIMC 時區 Ansible - 設定 Cisco UCS CIMC DNS 和停用 IPv6 Ansible - 設定 Cisco UCS CIMC Fan Policy Ansible - 設定 Cisco UCS CIMC Mail Alert Ansible - 設定 Cisco UCS CIMC 40Gb vNIC 參數 Ansible - 設定 Cisco UCS CIMC NTP 時間校時 主要連線到 Cisco 的部份是使用 shell module 搭配 ssh 指令來處理，摘錄一部份 playbook 如下：\n- name: Check Cisco UCS CIMC NTP server status shell: | sshpass -p \u0026#34;{{ cimc.password }}\u0026#34; ssh -T -o StrictHostKeyChecking=no {{ cimc.username}}@\u0026#34;{{ inventory_hostname }}\u0026#34; \u0026lt;\u0026lt; EOL scope cimc/network/ntp show detail EOL register: check_ntp_server 可以看到先用 sshpass 帶入密碼，再執行 ssh ，連線以後，並非一般的 SHELL，所以直接用 Here document 方式把指令送過去。\n學習了，謝謝 Weithenn 分享的好文。\n","permalink":"https://ansible.cloudns.pro/post/cisco-ucs-cimc/","summary":"\u003cp\u003e網友 \u003ca href=\"https://www.weithenn.org\"\u003eWeithenn\u003c/a\u003e 分享的好文，是講怎麼用 Ansible 設定 Cisco UCS CIMC 的文章，現整理目錄如下：\u003c/p\u003e","title":"[網友好文]Cisco UCS CIMC系列文章"},{"content":"前一陣子在撰寫 playbook 操作 OpenShift 時，常常模組是同一個，裏面的 kubeconfig 是固定的，寫起來就很重複。 在以前不知道有 module_defaults 的時候，都是用變數來處理。現在知道有 module_defaults 以後，就可以用這個語法來處理了。\n讓我們先看看沒有用 module_defaults 之前的用法：\n--- - name: OpenShift example hosts: localhost tasks: - name: Create project community.okd.k8s: kubeconfig: \u0026#34;/etc/kubeconfig\u0026#34; state: present definition: kind: Project apiVersion: project.openshift.io/v1 metadata: name: \u0026#34;Example\u0026#34; annotations: openshift.io/display-name: \u0026#34;Example\u0026#34; spec: finalizers: - kubernetes - name: Import image into image stream community.okd.k8s: kubeconfig: \u0026#34;/etc/kubeconfig\u0026#34; state: present definition: kind: ImageStream apiVersion: project.openshift.io/v1 metadata: name: \u0026#34;hello-nginx\u0026#34; namespace: \u0026#34;Example\u0026#34; spec: lookupPolicy: local: false tags: - name: \u0026#34;1.0.0\u0026#34; from: kind: DockerImage name: \u0026#34;quay.io/redhattraining/hello-nginx\u0026#34; generation: 1 referencePolicy type: Source 這個時候，就可以利用 module_defaults，那麼 playbook 就可以改寫為\n--- - name: OpenShift example hosts: localhost module_defaults: community.okd.k8s: kubeconfig: \u0026#34;/etc/kubeconfig\u0026#34; tasks: - name: Create project community.okd.k8s: state: present definition: kind: Project apiVersion: project.openshift.io/v1 metadata: name: \u0026#34;Example\u0026#34; annotations: openshift.io/display-name: \u0026#34;Example\u0026#34; spec: finalizers: - kubernetes - name: Import image into image stream community.okd.k8s: state: present definition: kind: ImageStream apiVersion: project.openshift.io/v1 metadata: name: \u0026#34;hello-nginx\u0026#34; namespace: \u0026#34;Example\u0026#34; spec: lookupPolicy: local: false tags: - name: \u0026#34;1.0.0\u0026#34; from: kind: DockerImage name: \u0026#34;quay.io/redhattraining/hello-nginx\u0026#34; generation: 1 referencePolicy type: Source 這樣就可以把共用的 kubeconfig 都寫在 module_defaults 裡，日後調整會比較容易。\n參考資料：Module defaults — Ansible Documentation\n","permalink":"https://ansible.cloudns.pro/post/module-defaults/","summary":"\u003cp\u003e前一陣子在撰寫 playbook 操作 OpenShift 時，常常模組是同一個，裏面的 kubeconfig 是固定的，寫起來就很重複。\n在以前不知道有 \u003ccode\u003emodule_defaults\u003c/code\u003e 的時候，都是用變數來處理。現在知道有 \u003ccode\u003emodule_defaults\u003c/code\u003e 以後，就可以用這個語法來處理了。\u003c/p\u003e","title":"Module 預設值 - module defaults"},{"content":"前兩天在執行 playbook 時，想試著以 \u0026ndash;extra-vars / -e 帶入 boolean 型態的變數，卻發現怎麼傳都不行。\n我試了\nTrue / False true / false yes / no 都不行。\n後來試著去把變數印出來，發現都是字串，而非 boolean。\n# test-bool.yml --- - name: Test \u0026#34;--extra-vars\u0026#34; / \u0026#34;-e\u0026#34; with boolean hosts: localhost vars: foo: no tasks: - debug: var: foo 以 ansible-playbook -i localhost, -c local -e foo=yes test-bool.yml 來執行\n輸出結果：\nPLAY [Test \u0026#34;--extra-vars\u0026#34; / \u0026#34;-e\u0026#34; with boolean] *************************************************** TASK [Gathering Facts] *************************************************************************** ok: [localhost] TASK [debug] ************************************************************************************* ok: [localhost] =\u0026gt; { \u0026#34;foo\u0026#34;: \u0026#34;yes\u0026#34; } PLAY RECAP *************************************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 會看到 foo 是個字串。\n當然我們可以做額外的判斷，然後使用 | bool 來處理，但這樣實在是不太方便。\n後來上網找了一下，發現有人提到一樣的情況：\nUnable to pass boolean value False through \u0026ndash;extra-vars argument · Issue #17193 · ansible/ansible ansible-playbook \u0026ndash;extra-vars does not translate \u0026lsquo;yes\u0026rsquo; or \u0026rsquo;no\u0026rsquo; to boolean values · Issue #14329 · ansible/ansible 解決方法也很簡單，就是改傳 json 進去。\nansible-playbook -i localhost, -c local -e \u0026#39;{\u0026#34;foo\u0026#34;:true}\u0026#39; test-bool.yml 這樣就可以解決了。\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-extra-vars-with-boolean-variable/","summary":"\u003cp\u003e前兩天在執行 playbook 時，想試著以 \u0026ndash;extra-vars / -e 帶入 boolean 型態的變數，卻發現怎麼傳都不行。\u003c/p\u003e","title":"小技巧 - 在 --extra-vars 帶入 boolean 變數"},{"content":"oc start-build 是 OpenShift 裡很方便的一個指令，事先建立好 build config 以後，就可以用 start-build 來指示 openshift 來幫忙建置，在建置完成以後，就自動完成佈署了。\n等等，那 oc start-build 不是直接用 command/shell 模組就可以完成了嗎？為什麼還需要特別寫？ 這是因為使用指令的話，在同時執行多個工作時，在後續的 oc get 會有些問題，所以才想去試試。\n我在 Ansible 模組相關的文件裡去找，找了許久，都沒有找到適當的模組可以幫我完成這件事情。 後來不得已，才去看 oc 這個指令的原始碼，這才看到 oc 其實也是用 OpenShift 的 API 來進行這些事情。\n原始碼網址：oc/buildinstantiatebinary.go at 4c2094c1d599734b770d74b2772651d5ff21fa1b · openshift/oc\nfunc (c *buildInstatiateBinary) InstantiateBinary(name string, options *buildv1.BinaryBuildRequestOptions, r io.Reader) (*buildv1.Build, error) { result := \u0026amp;buildv1.Build{} err := c.client.Post(). Namespace(c.ns). Resource(\u0026#34;buildconfigs\u0026#34;). Name(name). SubResource(\u0026#34;instantiatebinary\u0026#34;). Body(r). VersionedParams(options, scheme.ParameterCodec). Do(context.TODO()). Into(result) return result, err } 從 go 的程式大致可以猜到網址是 buildconfigs ，也有 instantiatebinary\n循線去找 OpenShift API ，就找到了：BuildConfig [build.openshift.io/v1] - Workloads APIs | API reference | OpenShift Container Platform 4.6\n那接下來，使用 uri 模組就可以完成我想做的事情了。\n--- - name: Test `oc start-build` hosts: localhost vars: openshift_api_host: \u0026#34;https://api.example.com:6443\u0026#34; openshift_username: \u0026#34;user\u0026#34; openshift_password: \u0026#34;pass\u0026#34; openshift_project_name: \u0026#34;example-project\u0026#34; openshift_app_name: \u0026#34;example-app\u0026#34; validate_certs: false artifact_path: \u0026#34;build/artifact.jar\u0026#34; tasks: - name: Log in (obtain access token) community.okd.openshift_auth: host: \u0026#34;{{ openshift_api_host }}\u0026#34; username: \u0026#34;{{ openshift_username }}\u0026#34; password: \u0026#34;{{ openshift_password }}\u0026#34; validate_certs: \u0026#34;{{ validate_certs }}\u0026#34; register: openshift_auth_results - name: Read file content slurp: path: \u0026#34;{{ artifact_path }}\u0026#34; register: bin_file - name: Run `oc start-build` uri: url: \u0026#34;{{ openshift_api_host }}/apis/build.openshift.io/v1/namespaces/{{ openshift_project_name }}/buildconfigs/build-{{ openshift_app_name }}/instantiatebinary?name=build-{{ openshift_app_name }}\u0026amp;namespace={{ openshift_project_name }}\u0026amp;asFile={{ artifact_path | basename }}\u0026#34; headers: Accept: \u0026#34;application/json\u0026#34; Content-Type: \u0026#34;application/octet-stream\u0026#34; Authorization: \u0026#34;Bearer {{ openshift_auth_results.openshift_auth.api_key }}\u0026#34; method: POST validate_certs: \u0026#34;{{ validate_certs }}\u0026#34; body: \u0026#34;{{ bin_file.content }}\u0026#34; status_code: - 200 - 201 timeout: 900 register: openshift_start_build_result - name: Display build name debug: msg: \u0026#34;build name={{ openshift_start_build_result.json.metadata.name }}\u0026#34; 第一個 task 先使用 community.okd.openshift_auth 進行登入，透過這個 task 的結果，可以取得 API token。\n第二個 task 來使用 slurp 讀入檔案內容。\n第三個 task 使用 uri 送出 HTTP POST\nurl: 填入的就是 API 的網址，比較需要注意的地方有兩個 第一個是 path parameter，前面要帶入 Project name，後面要帶入 build config name 第二個是 Query parameter，這邊依照文件，必須要再一次帶入 Project name 跟 build config name，然後再帶入文件裡所說的 guery 參數，這裡我就只填 asFile，值是 artifact 的檔名。 headers: HTTP 標頭，主要是要帶入前面所取得的 API token，並且用 Content-Type 指示這次是要上傳檔案。 body: 因為我使用的 oc start-build 主要帶入的參數是 \u0026ndash;from-file，所以這邊就要帶入前面讀入的檔案內容。 這樣就可以順利呼叫到 start-build 了，請求的內容會是建立出來的 build 內容，所以可以用 openshift_start_build_result.json.metadata.name 來取得 build name\n現在可以順利進行 start-build 了，那麼該怎麼取得 build 的狀況呢？下期待續。\n","permalink":"https://ansible.cloudns.pro/post/how-to-run-oc-start-build/","summary":"\u003cp\u003e\u003ccode\u003eoc start-build\u003c/code\u003e 是 OpenShift 裡很方便的一個指令，事先建立好 build config 以後，就可以用 start-build 來指示 openshift 來幫忙建置，在建置完成以後，就自動完成佈署了。\u003c/p\u003e\n\u003cp\u003e等等，那 \u003ccode\u003eoc start-build\u003c/code\u003e 不是直接用 command/shell 模組就可以完成了嗎？為什麼還需要特別寫？\n這是因為使用指令的話，在同時執行多個工作時，在後續的 \u003ccode\u003eoc get\u003c/code\u003e 會有些問題，所以才想去試試。\u003c/p\u003e","title":"如何執行 oc start-build"},{"content":"在某些情況需要讀取檔案內容，例如送出 HTTP POST 請求，或者是需要對內容編碼，那麼可以怎麼去寫 Playbook 呢？\n首先想到可以用的方法是 lookup('file', 'your_file')\n像下面這個例子，就是讀取主控端機器上的 readme.txt，然後使用 debug 模組印出來。\n--- - name: Read file content hosts: all tasks: - name: Display file content debug: msg: \u0026#34;{{ lookup(\u0026#39;file\u0026#39;, \u0026#39;readme.txt\u0026#39;) }}\u0026#34; 用 lookup 有幾個要注意的地方：\nlookup 是在主控端執行，所以讀取的是主控端上的檔案。 lookup(\u0026lsquo;file\u0026rsquo;) 能處理的檔案內容只能是文字檔，如果是二進位檔就不行。 那麼，如果要讀取二進位檔案該怎麼辦呢？這時候可以用 slurp\n下面這個例子就是用 slurp 讀取檔案內容後，使用 uri 模組進行上傳。\n--- - name: Use HTTP POST to upload file hosts: all tasks: - name: Read binary file content slurp: path: \u0026#34;/bin/ls\u0026#34; register: bin_file - name: Send HTTP POST Request uri: url: \u0026#34;https://your_server/upload.php\u0026#34; headers: Accept: \u0026#34;application/json\u0026#34; Content-Type: \u0026#34;application/octet-stream\u0026#34; method: POST validate_certs: false body: \u0026#34;{{ bin_file.content }}\u0026#34; status_code: - 200 - 201 register: upload_result - name: Display upload_result debug: var: upload_result 使用 slurp，就可以避掉 lookup(\u0026lsquo;file\u0026rsquo;) 的限制。\n可以讀取受控端主機上的檔案，也可以利用 delegate_to: localhost 來讀取主控端主機上的檔案。 可以讀取二進位檔案來做進一步處理，例如做 base64 編碼 --- - name: Use base64 to encode file hosts: all tasks: - name: Read binary file content slurp: path: \u0026#34;/bin/ls\u0026#34; register: bin_file - name: Encode with base64 copy: content: \u0026#34;{{ bin_file.content | b64encode }}\u0026#34; dest: \u0026#34;/tmp/output.txt\u0026#34; 讀到這裡，相信你已經知道該怎麼寫 Ansible playbook 來讀取檔案內容，並做出更多變化了，讓我們繼續朝 Ansible Pro 前進！\n","permalink":"https://ansible.cloudns.pro/post/slurp-read-file-content/","summary":"\u003cp\u003e在某些情況需要讀取檔案內容，例如送出 HTTP POST 請求，或者是需要對內容編碼，那麼可以怎麼去寫 Playbook 呢？\u003c/p\u003e","title":"ansible.builtin.slurp - 讀取檔案內容"},{"content":"要存取 OpenShift ，可以透過 community.okd 這個模組來達成\n主要的說明文件：Community.Okd — Ansible Documentation\n原始碼位置：https://github.com/ansible-collections/community.okd\nGalaxy 上的頁面：https://galaxy.ansible.com/community/okd\n使用說明待補上\n","permalink":"https://ansible.cloudns.pro/post/openshift/","summary":"\u003cp\u003e要存取 OpenShift ，可以透過 community.okd 這個模組來達成\u003c/p\u003e","title":"OpenShift"},{"content":"仔細算算，已經查了 ansible_date_time 這個變數的用法超過三次，所以記錄一下，以後查找也方便。\nAnsible 在收 facts 時，會把受管主機(遠端機器)的日期時間放到 ansible_date_time 這個變數裡。\nansible_date_time 有以下屬性可以使用：\ndate: 日期，格式為 \u0026ldquo;年-月-日\u0026rdquo;，例如: \u0026ldquo;2021-05-03\u0026rdquo; day\u0026quot;: 日，例如：\u0026ldquo;03\u0026rdquo; epoch: 自 1970-01-01 0:0:0 起到現在的總秒數，例如 \u0026ldquo;1620055364\u0026rdquo; hour: 時，例如：\u0026ldquo;11\u0026rdquo;, iso8601: ISO8601 格式的日期時間，例如：\u0026ldquo;2021-05-03T15:22:44Z\u0026rdquo; iso8601_basic: 一樣是 ISO8601 格式的日期時間，沒有分隔符號，時間是\u0026quot;時分秒微秒\u0026quot;，例如：\u0026ldquo;20210503T112244489703\u0026rdquo; iso8601_basic_short: 一樣是 ISO8601 格式的日期時間，沒有分隔符號，時間是\u0026quot;時分秒\u0026quot;，例如：\u0026ldquo;20210503T112244\u0026rdquo; iso8601_micro: 一樣是 ISO8601 格式的日期時間，加上微秒，例如：\u0026ldquo;2021-05-03T15:22:44.489703Z\u0026rdquo; minute: 分，例如：\u0026ldquo;22\u0026rdquo; month\u0026quot;: 月，例如：\u0026ldquo;05\u0026rdquo; second: 秒，例如：\u0026ldquo;44\u0026rdquo; time: 時間，例如：\u0026ldquo;11:22:44\u0026rdquo; tz\u0026quot;: 時區，例如 \u0026ldquo;EDT\u0026rdquo; tz_offset: 時差，例如 \u0026ldquo;-0400\u0026rdquo; weekday: 星期幾，例如：\u0026ldquo;Monday\u0026rdquo; weekday_number: 星期幾，使用數字表示，例如：\u0026ldquo;1\u0026rdquo; weeknumber: 一年的第幾週，例如：\u0026ldquo;18\u0026rdquo; year: 年，例如：\u0026ldquo;2021\u0026rdquo; 那麼該怎麼使用呢？\n--- - name: How to use ansible_date_time hosts: all gather_facts: true tasks: - name: Display ansible_date_time in ISO8601 debug: msg: \u0026#34;Current date/time is {{ ansible_date_time.iso8601 }}\u0026#34; 這邊要注意的一點是 gather_facts: true\n如果沒有這一行或執行 setup 模組的話，ansible_date_time 是會被視為一個未定義的變數的。\n--- - name: Test ansible_date_time hosts: all gather_facts: false tasks: - debug: var: ansible_date_time - setup: - debug: var: ansible_date_time 執行上面的 playbook 以後，輸出結果如下\nPLAY [Test ansible_date_time] ********************************************************************************************** TASK [debug] *************************************************************************************************************** ok: [10.11.12.13] =\u0026gt; { \u0026#34;ansible_date_time\u0026#34;: \u0026#34;VARIABLE IS NOT DEFINED!\u0026#34; } TASK [setup] *************************************************************************************************************** ok: [10.11.12.13] TASK [debug] *************************************************************************************************************** ok: [10.11.12.13] =\u0026gt; { \u0026#34;ansible_date_time\u0026#34;: { \u0026#34;date\u0026#34;: \u0026#34;2021-05-03\u0026#34;, \u0026#34;day\u0026#34;: \u0026#34;03\u0026#34;, \u0026#34;epoch\u0026#34;: \u0026#34;1620055364\u0026#34;, \u0026#34;hour\u0026#34;: \u0026#34;11\u0026#34;, \u0026#34;iso8601\u0026#34;: \u0026#34;2021-05-03T15:22:44Z\u0026#34;, \u0026#34;iso8601_basic\u0026#34;: \u0026#34;20210503T112244489703\u0026#34;, \u0026#34;iso8601_basic_short\u0026#34;: \u0026#34;20210503T112244\u0026#34;, \u0026#34;iso8601_micro\u0026#34;: \u0026#34;2021-05-03T15:22:44.489703Z\u0026#34;, \u0026#34;minute\u0026#34;: \u0026#34;22\u0026#34;, \u0026#34;month\u0026#34;: \u0026#34;05\u0026#34;, \u0026#34;second\u0026#34;: \u0026#34;44\u0026#34;, \u0026#34;time\u0026#34;: \u0026#34;11:22:44\u0026#34;, \u0026#34;tz\u0026#34;: \u0026#34;EDT\u0026#34;, \u0026#34;tz_offset\u0026#34;: \u0026#34;-0400\u0026#34;, \u0026#34;weekday\u0026#34;: \u0026#34;Monday\u0026#34;, \u0026#34;weekday_number\u0026#34;: \u0026#34;1\u0026#34;, \u0026#34;weeknumber\u0026#34;: \u0026#34;18\u0026#34;, \u0026#34;year\u0026#34;: \u0026#34;2021\u0026#34; } } PLAY RECAP ***************************************************************************************************************** 10.11.12.13 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 所以 ansible_date_time 裡的日期時間是受管主機上的日期時間，那如果想要取得執行 ansible playbook 的主機上的日期時間呢？ 這時候可以使用 lookup(\u0026lsquo;pipe\u0026rsquo;) 來取得：\n- hosts: all tasks: - debug: msg: \u0026#34;{{ lookup(\u0026#39;pipe\u0026#39;,\u0026#39;date \\\u0026#34;+%Y-%m-%d %H:%M:%S\\\u0026#34;\u0026#39;) }} 好囉，下次要用到 ansible_date_time 時，來看這篇就知道怎麼用了。\n參考資料：\nWorking with date and timestamp in Ansible - My Daily Tutorials ","permalink":"https://ansible.cloudns.pro/post/system/ansible_date_time/","summary":"\u003cp\u003e仔細算算，已經查了 ansible_date_time 這個變數的用法超過三次，所以記錄一下，以後查找也方便。\u003c/p\u003e","title":"ansible_date_time"},{"content":"狀況描述 在 Ansible Tower 上已經設置好 Job template，Playbook 會接收 version 參數，但使用 tower-cli 或 curl 去呼叫 API 帶入 version 啟動 job template 後，發現 playbook 沒有用到 version\n用 tower-cli 啟動 job template 並帶入 version 參數。\ntower-cli job launch --job-template=14 --extra-vars=\u0026#34;version=2.5.9\u0026#34; 處理方法 在 Job template 頁面，把 extra variables 欄位的 Prompt on Launch 勾選起來就可以了。\n參考資料 extra vars being ignored by the server · Issue #295 · ansible/tower-cli Tower CLI reference ","permalink":"https://ansible.cloudns.pro/post/tower-job-template-with-extra-vars/","summary":"\u003ch2 id=\"狀況描述\"\u003e狀況描述\u003c/h2\u003e\n\u003cp\u003e在 Ansible Tower 上已經設置好 Job template，Playbook 會接收 version 參數，但使用 tower-cli 或 curl 去呼叫 API 帶入 version 啟動 job template 後，發現 playbook 沒有用到 version\u003c/p\u003e","title":"Ansible Tower - Launch job template API 未處理 extra vars"},{"content":"要執行指定的 Tasks 時，可以藉著 tag 來幫助我們。\n# Filename: install-app.yml - name: Install application hosts: dbservers vars: packages: - postfix - mariadb-server tasks: - name: Ensure that packages are installed yum: name: \u0026#34;{{ packages }}\u0026#34; state: installed tags: - install - name: debug: msg: \u0026#34;Debug message\u0026#34; 以上面的例子來說，Ensure that packages are installed 這個 task 就有加上 install 這個 tag\n在執行的時候，就可以使用 -t install 來表明只執行這個 task：\nansible-playbook -i inventory -t install install-app.yml 如果沒有用 -t 指定 tag 時，這兩個 task 都會被執行到。\n那麼，如果想要沒有指定 tag 時，兩個 task 都不給執行時的話，該怎麼辦呢？這時候我們可以使用關鍵字 never，使用了 never 之後，如果沒有指定 tag，就都不會執行。\n我們舉另外一個例子來說明：\n--- # Filename: running-selected-task.yml - name: Running selected task example hosts: localhost gather_facts: false tasks: - debug: msg: \u0026#34;AAA\u0026#34; tags: - never - aaa - debug: msg: \u0026#34;BBB\u0026#34; tags: - never - bbb 這個 playbook 裡有兩個 task，一個會顯示 AAA，加上了 never 與 aaa 這兩個 tag；另一個則顯示 BBB，加上了 never 與 bbb 這兩個 tag。\n先不指定 tag 來執行看看：\n$ ansible-playbook -i localhost, -c local running-selected-task.yml PLAY [Running selected task example] ********************************************************************************************* PLAY RECAP *********************************************************************************************************************** 你會發現沒有任何 task 被執行。\n接著來試試看加上 -t aaa\n$ ansible-playbook -i localhost, -c local -t aaa running-selected-task.yml PLAY [Running selected task example] ********************************************************************************************* TASK [debug] ********************************************************************************************************************* ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;AAA\u0026#34; } PLAY RECAP *********************************************************************************************************************** localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 的確就只顯示了 \u0026lsquo;AAA\u0026rsquo;。\n然後試試看加上 -t bbb\n$ ansible-playbook -i localhost, -c local -t bbb running-selected-task.yml PLAY [Running selected task example] ********************************************************************************************* TASK [debug] ********************************************************************************************************************* ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;BBB\u0026#34; } PLAY RECAP *********************************************************************************************************************** localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 最後，如果這兩個 task 都要執行的話呢？那就是用 -t aaa,bbb 囉\n$ ansible-playbook -i localhost, -c local -t aaa,bbb running-selected-task.yml PLAY [Running selected task example] ********************************************************************************************* TASK [debug] ********************************************************************************************************************* ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;AAA\u0026#34; } TASK [debug] ********************************************************************************************************************* ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;BBB\u0026#34; } PLAY RECAP *********************************************************************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 透過 tag ，我們可以只執行 playbook 裡一部份的 task，而不需要執行全部，在先期的開發上有很大的幫助。看到這裡，相信你應該知道 tag 該怎麼應用了。\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-running-selected-task/","summary":"\u003cp\u003e要執行指定的 Tasks 時，可以藉著 tag 來幫助我們。\u003c/p\u003e","title":"小技巧 - 執行指定的 task"},{"content":"最近在使用 openshift 的指令 - oc，oc 可以使用 template 來輸出所需要的結果，可是 oc 的 template 裡剛巧也是用 {{，這就導致了 Ansible 以為這是自己要處理的而導致處理錯誤。\n那麼該怎麼辦呢？\n這時候可以用兩種方式解決：\n第一種方式是使用 {% raw %} ... {% endraw %}\n舉個例子：\n--- - name: Escape double braces - using raw hosts: localhost tasks: - name: Run openshift command shell: oc get pods -o go-template=\u0026#39;Hello, World! {% raw %}{{ {% endraw %}\u0026#34;\\n\u0026#34;{% raw %} }}{% endraw %}\u0026#39; register: shell_result 這樣子就可以讓 oc 能使用 {{ }} 了。 如果覺得在 {{ }} 前後加上 {% raw %}...{% endraw %} 很麻煩的話，可以直接加前後，例如\n- name: Run openshift command shell: \u0026#34;{% raw %}oc get pods -o go-template=\u0026#39;Hello, World! {{ \\\u0026#34;\\n\\\u0026#34; }}\u0026#39;{% endraw %}\u0026#34; register: shell_result 第二種方式是使用 !unsafe\n例如：\n--- - name: Escape double braces - using unsafe hosts: localhost tasks: - name: Test vars: cmd_string: !unsafe docker inspect --format \u0026#39;{{ .NetworkSettings.IPAddress }}\u0026#39; silly_lovelace shell: \u0026#34;{{ cmd_string }}\u0026#34; register: shell_result - debug: msg: \u0026#34;{{ shell_result.stdout }}\u0026#34; 這裡有點不一樣的是，預先宣告字串在 vars 裡，然後才帶入到 shell ，這是使用 !unsafe 時要注意的地方。\n參考資料：\nAdvanced Syntax — Ansible Documentation docker - Escaping double curly braces in Ansible - Stack Overflow ","permalink":"https://ansible.cloudns.pro/post/tips/tip-escape-double-brace/","summary":"\u003cp\u003e最近在使用 openshift 的指令 - oc，oc 可以使用 template 來輸出所需要的結果，可是 oc 的 template 裡剛巧也是用 \u003ccode\u003e{{\u003c/code\u003e，這就導致了 Ansible 以為這是自己要處理的而導致處理錯誤。\u003c/p\u003e\n\u003cp\u003e那麼該怎麼辦呢？\u003c/p\u003e","title":"小技巧 - 遇到需要兩個大括號該怎麼辦？"},{"content":"目前主要的課程、證照都是紅帽推出的。已經退休的課程跟證照，下面就不列出來了。\n課程 DO294: Red Hat 系統管理 III - Linux 自動化 (Red Hat Enterprise Linux Automation with Ansible) DO417: Microsoft Windows Automation with Red Hat Ansible DO447: Red Hat 高級自動化 - Ansible 最佳實踐 DO448: Advanced Automation - Ansible best practices with exam DO457: Red Hat Ansible for Network Automation RH358: Red Hat Service Management and Automation RH415: Red Hat Security: Linux in Physical, Virtual, and Cloud 在恆逸資訊、聯成電腦比較容易看到的是 DO294, DO447, RH358，其他的課程，得購買 Red Hat Online training 才上的到。\n證照 EX294： 上完 DO294 就可以考的證照。 EX447： 上完 DO447 就可以考的證照。 ","permalink":"https://ansible.cloudns.pro/post/course-and-certification/","summary":"\u003cp\u003e目前主要的課程、證照都是紅帽推出的。已經退休的課程跟證照，下面就不列出來了。\u003c/p\u003e","title":"課程與證照"},{"content":"這篇主要是延續前篇的 Tip - 處理 JSON 檔案，前篇寫完以後，突然想到，如果要移除其中一個鍵值該怎麼辦？\n例如：\n{ \u0026#34;force\u0026#34;: true, \u0026#34;foo\u0026#34;: \u0026#34;2021-04-10T08:04:12Z\u0026#34;, \u0026#34;id\u0026#34;: 1, \u0026#34;name\u0026#34;: \u0026#34;server.json\u0026#34; } 要把 \u0026lsquo;foo\u0026rsquo; 一除掉，變成\n{ \u0026#34;force\u0026#34;: true, \u0026#34;id\u0026#34;: 1, \u0026#34;name\u0026#34;: \u0026#34;server.json\u0026#34; } 一開始我是想到可以找找看 json_query 是否可以處理。\n這邊要離題帶一下，Ansible 的 json_query 函數，語法跟 jq 不太一樣，他是使用 JMESPath 。 特別離題帶一下的原因是因為，我之前寫的時候就傻傻的以為用 jq 語法就行了，試了許久，才發現不能這樣用。\n經過研究之後，發現 json_query 能做的有限，那麼就只能回歸到 Ansible 語法本身了。\nAnsible 可以透過 dict2item 這個 filter 來 iterate dictionary，那再搭配前篇提到的 combine ，就可以做到移除鍵值的功能了。\n寫法如下\n- name: Remove \u0026#39;foo\u0026#39; in server_conf vars: new_server_conf: {} set_fact: new_server_conf: \u0026#34;{{ new_server_conf | combine({item.key: item.value}) }}\u0026#34; when: \u0026#34;item.key != \u0026#39;foo\u0026#39;\u0026#34; loop: \u0026#34;{{ server_conf | dict2items }}\u0026#34; - name: Display new_server_conf debug: var: new_server_conf 使用 loop 搭配 dict2items，來遍訪 server_conf 裡的每個項目。 宣告 new_server_conf 來放新的值。 使用 set_fact 搭配 combine，來持續的合併 dictionary 使用 when 來篩選掉不要的項目 透過這樣的語法，就可以做到移除指定鍵值了。\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-json-file-handling-2/","summary":"\u003cp\u003e這篇主要是延續前篇的 \u003ca href=\"https://ansible.cloudns.pro/post/tips/tip-json-file-handling/\" title=\"Tip - 處理 JSON 檔案\"\u003eTip - 處理 JSON 檔案\u003c/a\u003e，前篇寫完以後，突然想到，如果要移除其中一個鍵值該怎麼辦？\u003c/p\u003e","title":"小技巧 - 處理 JSON 檔案之二"},{"content":"現在有不少服務都是使用 JSON 作為設定檔，所以常常會需要讀取 JSON 格式的設定檔，修改內容值後再寫回，那麼用 Ansible 的話，該怎麼做呢？\n在 Ansible 裡，我們可以使用 filter 來處理，主要有這三個 filter ：\nfrom_json to_json combine from_json，是解析 JSON 格式字串，並轉換為變數。像下面這樣寫，就可以將 JSON 格式字串轉為變數，放到 server_conf 變數裡。\n- set_fact: server_conf: \u0026#34;{{ json_string | from_json }}\u0026#34; to_json 是將變數轉換為 JSON 格式的字串。像下面這樣寫，就可以將變數轉為 JSON 格式的字串，並寫到 /tmp/foo.json\n- copy: content: \u0026#34;{{ server_conf | to_json }}\u0026#34; dest: \u0026#34;/tmp/foo.json\u0026#34; combine 則是跟變數做合併。\n- name: Combine example vars: foo_data: id: 100 name: \u0026#34;John Doe\u0026#34; set_fact: foo_data: \u0026#39;{{ foo_data | combine({\u0026#34;age\u0026#34;:25,\u0026#34;name\u0026#34;:\u0026#34;Mary Jane\u0026#34;}) }}\u0026#39; 以上面的例子來說，foo_data 的內容會變為\nfoo_data: id: 100 name: \u0026#34;Mary Jane\u0026#34; age: 25 除了多了 age 之外，name 也變為 Mary Jane 。\n下面就來看看怎麼使用。\n先說明一下環境：\n連線主機上有 /etc/server.json 檔案 /etc/server.json 裡的內容是 { \u0026#34;foo\u0026#34;: \u0026#34;2021-04-10T08:04:12Z\u0026#34;, \u0026#34;force\u0026#34;: true, \u0026#34;id\u0026#34;: 1, \u0026#34;name\u0026#34;: \u0026#34;server.json\u0026#34; } 完整的 Playbook 範例如下：\n--- - name: 讀取連線主機上的 server.json，讀取指定內容值、修改後寫回 hosts: all vars: server_conf_file: \u0026#34;/etc/server.json\u0026#34; tasks: - name: Read {{ server_conf_file }} shell: cat {{ server_conf_file }} register: shell_result - name: Parase JSON text to a variable set_fact: server_conf: \u0026#34;{{ shell_result.stdout | from_json }}\u0026#34; - name: Display variable debug: var: server_conf - name: Modify \u0026#34;foo\u0026#34; in server_conf set_fact: server_conf: \u0026#39;{{ server_conf | combine({\u0026#34;foo\u0026#34;:ansible_date_time.iso8601}) }}\u0026#39; - name: Display variable again debug: var: server_conf - name: Write back copy: content: \u0026#34;{{ server_conf | to_json }}\u0026#34; dest: \u0026#34;{{ server_conf_file }}\u0026#34; - name: Display file content shell: cat {{ server_conf_file }} register: shell_result - name: Display shell_result debug: var: shell_result.stdout 看完這個例子，相信你已經學會怎麼處理 JSON 格式的檔案了。\n附帶一提，YAML 格式也可以用相同的方式來處理，因為有 from_yaml 跟 to_yaml 這兩個 filter，把 from_json / to_json 替換為 from_yaml / to_yaml 就可以啦。\n參考資料:\nAnsible read JSON file - JSON file Parsing Ansible Dictionary - How to create and add items to dict Using filters to manipulate data — Ansible Documentation ","permalink":"https://ansible.cloudns.pro/post/tips/tip-json-file-handling/","summary":"\u003cp\u003e現在有不少服務都是使用 JSON 作為設定檔，所以常常會需要讀取 JSON 格式的設定檔，修改內容值後再寫回，那麼用 Ansible 的話，該怎麼做呢？\u003c/p\u003e","title":"小技巧 - 處理 JSON 檔案"},{"content":"copy 可以把檔案複製到連線的主機去。\n目的地一定都是連線過去的那台主機，例如下面的例子就是把本地主機上的 README.md 複製到連線主機上的 /tmp/README.md\n--- - name: Example for ansible.builtin.copy hosts: all tasks: - name: Copy local file to target copy: src: README.md dest: /tmp/README.md 那如果要複製連線主機上的檔案呢？那就要加上 remote_src: true\n--- - name: Example for ansible.builtin.copy hosts: all tasks: - name: Copy file on target to target copy: remote_src: true src: /etc/os-release dest: /tmp/os-release 在複製時，來源可以直接使用文字，copy 會把文字作為檔案的內容。\n--- - name: Example for ansible.builtin.copy hosts: all tasks: - name: Copy content to target copy: content: \u0026#34;Hello world!\u0026#34; dest: /tmp/README.md 如果連線主機上的檔案已經存在，可以使用 backup: true 來要求備份，檔案在備份後，檔名會是原來的檔名加上日期。 複製時，也可以指定擁有者、權限、SELinux 屬性等等。\n--- - name: Example for ansible.builtin.copy hosts: all tasks: - name: Copy content to target ansible.builtin.copy: src: /srv/myfiles/foo.conf dest: /etc/foo.conf owner: foo group: foo mode: u+rw,g-wx,o-rwx backup: true force 是一個需要特別說明的部份：\nforce 為 true 時，當連線主機上的檔案內容跟原始檔不相符時，就寫入。 force 為 false 時，當連線主機上沒有這檔案才寫入，如果已經有這檔案了，就不寫入。 ansible.builtin.copy 是最常被使用到的模組，請務必熟悉。\n參考資料：\nansible.builtin.copy – Copy files to remote locations — Ansible Documentation ","permalink":"https://ansible.cloudns.pro/post/copy/","summary":"\u003cp\u003ecopy 可以把檔案複製到連線的主機去。\u003c/p\u003e","title":"ansible.builtin.copy"},{"content":"Inventory 就是主機清單，裏面描述主機的連線資訊，一般文件常用的是 ini 格式。\n但在 DO447 的第二章有提到 inventory 格式的轉換，我自己是比較熟悉 ini 格式的 inventory，所以對於要轉換為 YAML 格式的地方就覺得比較卡頓。\n那該怎麼克服呢？我臨機一動，想到 ansible 有提供 ansible-inventory 指令，用這個就可以解決我的問題。\n假定已經有個 ini 格式的 inventory 檔案，內容如下\n# inventory [ubuntu20] u3 ansible_host=127.0.0.1 ansible_port=2201 ansible_user=\u0026#39;ubuntu\u0026#39; u1 ansible_host=127.0.0.1 ansible_port=2222 ansible_user=\u0026#39;vagrant\u0026#39; [ubuntu18] u4 ansible_host=127.0.0.1 ansible_port=2202 ansible_user=\u0026#39;vagrant\u0026#39; [ubuntu16] u2 ansible_host=127.0.0.1 ansible_port=2200 ansible_user=\u0026#39;vagrant\u0026#39; 接著就可以用下面指令來轉換\nansible-inventory -i inventory --list --yaml \u0026gt; inventory.yml 轉換結果如下\nall: children: ungrouped: hosts: u1: ansible_host: 127.0.0.1 ansible_port: 2222 ansible_user: vagrant u2: ansible_host: 127.0.0.1 ansible_port: 2200 ansible_user: vagrant u3: ansible_host: 127.0.0.1 ansible_port: 2201 ansible_user: ubuntu u4: ansible_host: 127.0.0.1 ansible_port: 2202 ansible_user: vagrant 透過這個指令就可以很快的轉換格式，也可以幫助自己去記憶跟學習 YAML 格式的 inventory 了。\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-inventory-conversion/","summary":"\u003cp\u003eInventory 就是主機清單，裏面描述主機的連線資訊，一般文件常用的是 ini 格式。\u003c/p\u003e\n\u003cp\u003e但在 DO447 的第二章有提到 inventory 格式的轉換，我自己是比較熟悉 ini 格式的 inventory，所以對於要轉換為 YAML 格式的地方就覺得比較卡頓。\u003c/p\u003e\n\u003cp\u003e那該怎麼克服呢？我臨機一動，想到 ansible 有提供 ansible-inventory 指令，用這個就可以解決我的問題。\u003c/p\u003e","title":"小技巧 - Inventory 格式的轉換"},{"content":"這是我在前兩天在寫 DO447 練習題時所發現的一個小技巧，覺得非常實用，特別是在無法上網查詢的時候。\nansible.cfg 是 ansible 預設會去讀取的設定檔，裏面可以設定很多，例如：\nhost_key_checking: 是否檢查 SSH Host key？ interpreter_python: 指定使用哪個 Python 來解譯 roles_path: role 的路徑 callback_whitelist: 啟用哪些 callback become: 切換特權帳戶 \u0026hellip; 等等，那裏面可以放哪些設定呢？該怎麼查詢呢？而且設定很多，不常使用的話，也背不起來。\n還好，Ansible 提供了 ansible-config 這個指令，我們可以利用這個指令。\nansible-config 提供三個主要功能：\nansible-config dump 傾印目前的設定，從這邊可以看到所有設定值，有被 ansible.cfg 影響到的設定會被標示出來。 ansible-config list 列出所有的設定以及其說明。 ansible-config view 瀏覽目前 ansible.cfg 的內容。 所以只要對某些設定有些印象，就可以透過這個指令來查，不需要上網查詢了。\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-ansible.cfg/","summary":"\u003cp\u003e這是我在前兩天在寫 DO447 練習題時所發現的一個小技巧，覺得非常實用，特別是在無法上網查詢的時候。\u003c/p\u003e\n\u003cp\u003eansible.cfg 是 ansible 預設會去讀取的設定檔，裏面可以設定很多，例如：\u003c/p\u003e","title":"祕訣 - 關於 ansible.cfg"},{"content":"lookup 是很方便的查詢函式，第一個參數是 \u0026lsquo;password\u0026rsquo; 的時候，可以用來產生密碼。\n第二個參數是一個字串，可以填這些：\n檔案路徑：檔案不存在時，會產生密碼，然後把密碼存到這檔案。如果檔案已經存在，那麼就會從這檔案讀取密碼出來。要確保每次都產生不同的密碼，可以用 /dev/null\n\u0026ldquo;chars=\u0026quot;：用來定義密碼裡的字元，例如 chars=ascii_letters 就表示密碼只會用英文字母產生。除了 ascii_lettters 之外，還可以放\ndigits capwords digits ascii_lowercase ascii_uppercase hexdigits octdigits printable punctuation 這些也可以混合使用，例如：chars=ascii_letters,digits。也可以不填，不填的話，字元會包含大小寫字母、數字跟 \u0026ldquo;.,:-_\u0026rdquo;\n\u0026ldquo;encrypt=\u0026quot;：產生密碼以後，要使用哪種加密法來加密，例如 encrypt=md5_crypt 。除了 md5_crypt 外，還可以用\nbcrypt sha256_crypt sha512_crypt 不填的話，就是不加密。\n\u0026ldquo;length=\u0026quot;：產出的密碼長度，預設長度是 20\n下面就來看看怎麼使用。\n- name: 產生密碼並存到 new_password 變數 set_fact: new_password: \u0026#34;{{ lookup(\u0026#39;password\u0026#39;, \u0026#39;/dev/null length=10 chars=ascii_leters,digits\u0026#39;) }}\u0026#34; - name: 印出產出的密碼 debug: msg: \u0026#34;new_password={{ new_password }}\u0026#34; 執行結果\nPLAY [Generate new password for \u0026#39;Ansible\u0026#39; Credential] *************************************************************************************************************************** TASK [Gathering Facts] ********************************************************************************************************************************************************** ok: [localhost] TASK [Generate new password and store in variable] ****************************************************************************************************************************** ok: [localhost] TASK [debug] ******************************************************************************************************************************************************************** ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;new_password=it7_9ac9ei\u0026#34; } PLAY RECAP ********************************************************************************************************************************************************************** localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 由於可以指定使用哪些字元，其實也可以用來產生亂數字串，不一定要當做密碼，這真的是很方便。\n參考資料：ansible.builtin.password – retrieve or generate a random password, stored in a file — Ansible Documentation\n","permalink":"https://ansible.cloudns.pro/post/lookup-password/","summary":"\u003cp\u003elookup 是很方便的查詢函式，第一個參數是 \u0026lsquo;password\u0026rsquo; 的時候，可以用來產生密碼。\u003c/p\u003e","title":"lookup - password"},{"content":"Inventory 就是主機清單，Ansible 要連到哪些主機做操作，就是依據這個檔案。\nInventory 可以使用很多種格式，每種格式的處理都依靠 Plugin，這可以在 ansible.cfg 裡去啟用跟關閉。\n例如要啟用 host_list、script、auto、yaml、ini、toml ，就可以這麼寫：\n[inventory] enable_plugins = host_list, script, auto, yaml, ini, toml 下面簡單介紹一下 host_list, yaml, ini 這三種格式，後續再針對每種格式做更詳盡的介紹。\nhost_list host_list 即是主機列表，以下面這個例子來說，就是 -i 後面所列出來的主機。\nansible-playbook -i 192.168.11.1,192.168.11.2, playbook.yml ini ini 格式的主機清單，這是最常見的一種，官方文件裡的舉例很常使用到。\n例如：\n[lb_servers] servera.lab.example.com [web_servers] serverb.lab.example.com serverc.lab.example.com [backend_server_pool] server[b:f].lab.example.com lb_servers, web_servers, backend_server_pool 就是 section，表示群組，每個 section 裡再去列出主機。\nYAML YAML 格式的主機清單，這種格式會比較要求縮排。\n以上面 ini 的例子，轉換為 YAML 以後，就會是\nlb_servers: hosts: servera.lab.example.com: web_servers: hosts: serverb.lab.example.com: serverc.lab.example.com: backend_server_pool: hosts: server[b:f].lab.example.com: 每個群組裡，會定義 hosts ，用來列出主機。\n格式間的轉換 格式間的轉換可以利用 Ansible 提供的工具：ansible-inventory ，來做轉換。\n例如：\nansible-inventory --yaml -i origin_inventory --list \\ --output destination_inventory.yml ","permalink":"https://ansible.cloudns.pro/post/inventory---overview/","summary":"\u003cp\u003eInventory 就是主機清單，Ansible 要連到哪些主機做操作，就是依據這個檔案。\u003c/p\u003e\n\u003cp\u003eInventory 可以使用很多種格式，每種格式的處理都依靠 Plugin，這可以在 ansible.cfg 裡去啟用跟關閉。\u003c/p\u003e","title":"Inventory - Overview"},{"content":"shell 是用來執行指令用的，等等，command 不也一樣嗎？。\n對，其實大同小異，但有個很重要的差別，就是 pipe 或重導向 。 command 只能執行單一個指令，若需要作 pipe 串接或重導向時，就需要用到 shell 了。\n這裡簡單舉四個例子，第一個是 iconv ，第二個是 grep，第三個是 awk，最後一個則是 expect 的範例。\n- name: 轉換編碼 shell: \u0026#34;iconv -f big5 -t utf-8 big5.txt \u0026gt; utf-8.txt\u0026#34; register: iconv_result ignore_errors: true - debug: var: iconv_result iconv 這個指令在轉換後，會把轉換結果直接輸出到 stdout，所以如果要存為檔案的話，就會需要用到 \u0026gt; 導向。\n來看第二個例子：\n- name: 找所有檔名裡有 \u0026#39;log\u0026#39; 的檔案 shell: ls -l | grep log 這個例子用到了 pipe，讓 grep 能依據 stdin 去搜尋 log。\n再來看第三個例子\n- name: 找 /etc/passwd 裡，所有帳號開頭為 i，後面跟著 7 個或 8 個數字的帳號，輸出為檔案 shell: \u0026#34;awk -F: \u0026#39;/^i[0-9]{7,8}/{print $1;}\u0026#39; /etc/passwd \u0026gt; /tmp/output.txt\u0026#34; 這個則是利用 awk 來找，然後輸出到 /tmp/output.txt\n最後一個是 expect 的例子：\n- name: 利用 expect 去等待機器用 PXE 開機起來。 shell: | set timeout 300 spawn ssh admin@{{ cimc_host }} expect \u0026#34;password:\u0026#34; send \u0026#34;{{ cimc_password }}\\n\u0026#34; expect \u0026#34;\\n{{ cimc_name }}\u0026#34; send \u0026#34;connect host\\n\u0026#34; expect \u0026#34;pxeboot.n12\u0026#34; send \u0026#34;\\n\u0026#34; exit 0 args: executable: /usr/bin/expect spawn 是啟動一個用 ssh 去連線的程序，接著用 expect 去等待特定的訊息出現，然後再送出準備好的回答。\n看到這邊，相信你可以理解 shell 跟 command 的差異了。\n","permalink":"https://ansible.cloudns.pro/post/shell/","summary":"\u003cp\u003eshell 是用來執行指令用的，等等，\u003ca href=\"https://ansible.cloudns.pro/post/command/\" title=\"command\"\u003ecommand\u003c/a\u003e 不也一樣嗎？。\u003c/p\u003e\n\u003cp\u003e對，其實大同小異，但有個很重要的差別，就是 pipe 或重導向 。\ncommand 只能執行單一個指令，若需要作 pipe 串接或重導向時，就需要用到 shell 了。\u003c/p\u003e","title":"ansible.builtin.shell"},{"content":"lookup 是很方便的查詢函式，第一個參數是 \u0026rsquo;template\u0026rsquo; 的時候，可以把範本檔案放到第二個參數，然後 lookup 會把範本內容替換變數以後，再傳回字串。\n一樣，舉個例子會比較容易理解。\n現在有一個範本檔案：index.html.j2\n\u0026lt;h1\u0026gt;Greeting\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;Hello! {{ name }}\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;The date is {{ ansible_date_time.iso8601 }}\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;Hostname: {{ ansible_hostname }} {{ inventory_hostname }}\u0026lt;/p\u0026gt; 然後撰寫 playbook 如下\n# 檔名：test-lookup-template.yml --- - name: lookup - template 的範例 hosts: all tasks: - name: 使用 lookup(\u0026#39;template\u0026#39;) 來處理範本檔案 vars: name: John Doe debug: msg: \u0026#34;{{ lookup(\u0026#39;template\u0026#39;, \u0026#39;index.html.j2\u0026#39;) }}\u0026#34; 然後試著執行看看\nansible-playbook -i localhost, -c local test-lookup-template.yml 執行結果如下\nPLAY [lookup - template 的範例] ************************************************************* TASK [Gathering Facts] ******************************************************************* ok: [localhost] TASK [使用 lookup(\u0026#39;template\u0026#39;) 來處理範本檔案] ***************************************************** ok: [localhost] =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;\u0026lt;h1\u0026gt;Greeting\u0026lt;/h1\u0026gt;\\n\u0026lt;p\u0026gt;Hello! John Doe\u0026lt;/p\u0026gt;\\n\u0026lt;p\u0026gt;The date is 2021-03-08T21:54:49Z\u0026lt;/p\u0026gt;\\n\u0026lt;p\u0026gt;Hostname: my-demo-host localhost\u0026lt;/p\u0026gt;\\n\u0026#34; } PLAY RECAP ******************************************************************************* localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 看看 msg ，你可以看到範本裡的變數 {{ name }}、{{ ansible_date_time.iso8601 }}、{{ ansible_hostname }}、{{ inventory_hostname }} 都已經替換掉。\nname 被替換為指定的 John Doe ansible_date_time.iso8601 被替換為 iso8601 格式的日期時間 ansible_hostname 被替換為主機名稱，因為是連線到本機，這邊會看到本機的主機名稱。 inventory_hostname 被替換為 inventory 裡所指定的主機名稱，指令裡是用 -i localhost,，所以這邊會看到 localhost lookup(\u0026rsquo;template\u0026rsquo;) 的作用跟 template 模組是一樣的，主要差別在於 lookup(\u0026rsquo;template\u0026rsquo;) 是處理過後，放到變數傳回來；而 template 模組是輸出到檔案。\n","permalink":"https://ansible.cloudns.pro/post/lookup-template/","summary":"\u003cp\u003elookup 是很方便的查詢函式，第一個參數是 \u0026rsquo;template\u0026rsquo; 的時候，可以把範本檔案放到第二個參數，然後 lookup 會把範本內容替換變數以後，再傳回字串。\u003c/p\u003e","title":"lookup - template"},{"content":"command 是用來執行指令用的。\n例如\n- name: Return motd to registered var command: cat /etc/motd register: mymotd 這行就是執行 cat /etc/motd，然後把執行結果放到 mymotd 變數裡。\n那如果要在指定的目錄下執行命令呢？我們可以使用 chdir\n- name: 切到 /tmp 目錄下，然後以 db_owner 使用者身分來建立空檔案。 command: touch db.sqlite3 become: yes become_user: db_owner args: chdir: /tmp 有些指令會需要很多參數，擺在一行裡會不容易閱讀，command 可以用 argv 來替代，提高可讀性。 以上面的例子來說，可以改寫為\n- name: 切到 /tmp 目錄下，然後以 db_owner 使用者身分來建立空檔案。 command: argv: - touch - db.sqlite3 become: yes become_user: db_owner args: chdir: /tmp command 的 creates 則是可以依據檔案是否存在來決定是否要執行指令。 這有一個先決要件，就是你需要知道指令會產生該檔案。\n首先，先產生一個叫做 test-command-creates.sh 的指令檔\n#!/bin/bash echo \u0026#34;$(date)\u0026#34; \u0026gt;\u0026gt; /tmp/test-command-creates.txt 從這指令檔可以看出，他會在 /tmp 下產生一個 test-command-creates.txt 的檔案，裡面是日期。 這裡刻意使用了 \u0026gt;\u0026gt; ，來確認新的內容會被附加到現有的檔案內容之後。\n接著，寫一個 playbook 來呼叫該指令檔\n--- # test-command-creates.yml - name: 測試 command 的 creates hosts: all tasks: - name: 當 /tmp/test-command-creates.txt 不存在時，才執行。 command: ./test-command-creates.sh args: creates: /tmp/test-command-creates.txt 然後執行\nansible-playbook -i localhost, -c local test-command-creates.yml 你會在執行結果中看到如下的字樣\nTASK [當 /tmp/test-command-creates.txt 不存在時，才執行。] *** changed: [localhost] 表示被執行了，用 cat /tmp/test-command-creates.txt 可以看到檔案內有目前的日期。\n接著再次執行一次 plybook\nansible-playbook -i localhost, -c local test-command-creates.yml 執行結果就只有\nTASK [當 /tmp/test-command-creates.txt 不存在時，才執行。] *** ok: [localhost] 檢查 /tmp/test-command-creates.txt，可以看到是之前的日期，沒有新的行，內容也沒被變更。 看到這裡，相信你已經知道怎麼去應用 command 的 creates 了。\n後面，我們會介紹另外一個跟 command 很相近的模組：shell\n","permalink":"https://ansible.cloudns.pro/post/command/","summary":"\u003cp\u003ecommand 是用來執行指令用的。\u003c/p\u003e","title":"ansible.builtin.command"},{"content":"lookup 函式的第一個參數可以填哪些項目，又能拿到什麼樣的資訊呢？你可以參考下面的一覽表。\n項目 用途 aws_secret 從 AWS Secrets Manager 取得機密資料 manifold 從 Manifold.co 取得憑證 (credential) vars Lookup templated value of variables sequence generate a list based on a number sequence first_found return first file found from list keyring grab secrets from the OS keyring nested composes a list with nested elements of other lists cpm_metering Get Power and Current data from WTI OOB/Combo and PDU devices list simply returns what it is given avi Look up Avi objects file 讀取檔案內容 conjur_variable Fetch credentials from CyberArk Conjur dnstxt query a domain(s)\u0026rsquo;s DNS txt fields k8s Query the K8s API template 以 Jinja2 處理、替換範本裡面的變數後，取得內容 cpm_status Get status and parameters from WTI OOB and PDU devices cartesian returns the cartesian product of lists nios Query Infoblox NIOS objects varnames Lookup matching variable names inventory_hostnames list of inventory hosts matching a host pattern passwordstore manage passwords with passwordstore.org\u0026rsquo;s pass utility redis fetch data from Redis onepassword fetch field values from 1Password laps_password Retrieves the LAPS password for a server nios_next_ip Return the next available IP address for a network dict returns key/value pair items from dictionaries etcd get info from an etcd server onepassword_raw fetch an entire item from 1Password hiera get info from hiera data config Lookup current Ansible configuration values nios_next_network Return the next available network range for a network-container subelements traverse nested key from a list of dictionaries shelvefile read keys from Python shelve file filetree recursively match all files in a directory tree gcp_storage_file Return GC Storage content mongodb lookup info from MongoDB cyberarkpassword get secrets from CyberArk AIM indexed_items rewrites lists to return \u0026lsquo;indexed items\u0026rsquo; csvfile read data from a TSV or CSV file chef_databag fetches data from a Chef Databag flattened return single list completely flattened aws_account_attribute Look up AWS account attributes password 從已存在的檔案取得密碼；若檔案不存在，就產生亂數密碼 template 以 Jinja2 處理、替換範本裡面的變數後，取得內容 random_choice return random element from list skydive Query Skydive objects aws_service_ip_ranges Look up the IP ranges for services provided in AWS such as EC2 and S3 env read the value of environment variables url return contents from URL items list of items credstash retrieve secrets from Credstash on AWS dig 使用 dnspython 函式庫查詢 DNS lines read lines from command rabbitmq Retrieve messages from an AMQP/AMQPS RabbitMQ queue together merges lists into synchronized list pipe read output from a command consul_kv Fetch metadata from a Consul key value store hashi_vault retrieve secrets from HashiCorp\u0026rsquo;s vault grafana_dashboard list or search grafana dashboards lastpass fetch data from lastpass fileglob list files matching a pattern aws_ssm Get the value for a SSM parameter or all parameters under a path ini read data from a ini file ","permalink":"https://ansible.cloudns.pro/post/lookup/","summary":"\u003cp\u003elookup 函式的第一個參數可以填哪些項目，又能拿到什麼樣的資訊呢？你可以參考下面的一覽表。\u003c/p\u003e","title":"lookup 一覽"},{"content":"你可以使用 ansible-doc -t lookup -l 列出所有可用的 lookup plugins。\n找到以後，就可以用 ansible-doc -t lookup \u0026lt;the_plugin\u0026gt; 來看它的用法。\n例如要看 dig 的詳細用法，就用 ansible-doc -t lookup dig\n","permalink":"https://ansible.cloudns.pro/post/tips/tip-lookup/","summary":"\u003cp\u003e你可以使用 \u003ccode\u003eansible-doc -t lookup -l\u003c/code\u003e 列出所有可用的 lookup plugins。\u003c/p\u003e\n\u003cp\u003e找到以後，就可以用 \u003ccode\u003eansible-doc -t lookup \u0026lt;the_plugin\u0026gt;\u003c/code\u003e 來看它的用法。\u003c/p\u003e","title":"祕訣 - 關於 lookup"},{"content":"lookup 是很方便的查詢函式，第一個參數是 \u0026lsquo;dig\u0026rsquo; 的時候，會拿第二個參數來做 DNS 查詢。\n例如下面的 playbook\n- debug: msg: \u0026#34;ansible.cloudns.pro IP Address: {{ lookup(\u0026#39;dig\u0026#39;, \u0026#39;ansible.cloudns.pro\u0026#39;) }}\u0026#34; 就等同於 dig ansible.cloudns.pro\n在使用 lookup(\u0026lsquo;dig\u0026rsquo;, \u0026lsquo;\u0026lt;your_domain\u0026gt;\u0026rsquo;) 之前，得先安裝套件：\nUbuntu: python-dnspython 或 python3-dnspython Red Hat / CentOS: python-dns 或 python3-dns 除了上面提到的以域名來找 IP 之外，也可以指定 DNS record type 來找。 例如，想找 example.org 的 MX record (SMTP伺服器位址)，就可以帶入 qtype=MX\n# dig example.org MX - name: \u0026#34;The MX record for example.org.\u0026#34; debug: msg: \u0026#34;{{ lookup(\u0026#39;dig\u0026#39;, \u0026#39;example.org.\u0026#39;, \u0026#39;qtype=MX\u0026#39;) }}\u0026#34; 要注意的是，lookup 是在執行 ansible-playbook 的也就是控制端主機上執行，而非被控端。\n參考資料：\ncommunity.general.dig – query DNS using the dnspython library — Ansible Documentation ","permalink":"https://ansible.cloudns.pro/post/lookup-dig/","summary":"\u003cp\u003elookup 是很方便的查詢函式，第一個參數是 \u0026lsquo;dig\u0026rsquo; 的時候，會拿第二個參數來做 DNS 查詢。\u003c/p\u003e","title":"lookup - dig"},{"content":"ansible.builtin.assert 這個模組可以用來檢查是否滿足指定的條件，不滿足的時候，會發生錯誤並離開。\n用法很簡單，在 that 裡指定條件式即可。\n- ansible.builtin.assert: that: - \u0026#34;\u0026#39;foo\u0026#39; != \u0026#39;bar\u0026#39;\u0026#34; 上面執行的結果，因為 \u0026lsquo;foo\u0026rsquo; 肯定不等於 \u0026lsquo;bar\u0026rsquo;，所以執行沒問題。\n再試試\n- ansible.builtin.assert: that: - \u0026#34;\u0026#39;foo\u0026#39; != \u0026#39;foo\u0026#39;\u0026#34; 這時就會有錯誤發生了，會告知 Assertion failed\nansible.builtin.assert 也可以用別名 \u0026lsquo;assert\u0026rsquo; 來代替，例如：\n- assert: that: - \u0026#34;\u0026#39;foo\u0026#39; != \u0026#39;foo\u0026#39;\u0026#34; fail_msg: \u0026#34;My Assertion failed\u0026#34; 有 fail_msg ，自然也有對應的：success_msg 這是在滿足條件式 (條件式為真)時，所要顯示的訊息。\n- assert: that: - \u0026#34;\u0026#39;foo\u0026#39; != \u0026#39;bar\u0026#39;\u0026#34; - 1 \u0026lt; 100 success_msg: \u0026#34;Yes, \u0026#39;foo\u0026#39; != \u0026#39;bar\u0026#39;\u0026#34; ","permalink":"https://ansible.cloudns.pro/post/assert/","summary":"\u003cp\u003eansible.builtin.assert 這個模組可以用來檢查是否滿足指定的條件，不滿足的時候，會發生錯誤並離開。\u003c/p\u003e\n\u003cp\u003e用法很簡單，在 that 裡指定條件式即可。\u003c/p\u003e","title":"ansible.builtin.assert"},{"content":"subelements 這個 filter 是取出 list 裡每個項目裡的 attribute ，然後轉為每個元素為 list 的 list。 xxx 很繞口，對吧，這個不太容易理解，用例子比較好講。\n從下面的變數定義可以看到，users 是一個 list，裏面有兩個項目，每個項目代表一個 user\n--- users: - name: paul password: \u0026#34;paul_pass\u0026#34; authorized: - keys/paul_key1.pub - keys/paul_key2.pub mysql: hosts: - \u0026#34;%\u0026#34; - \u0026#34;127.0.0.1\u0026#34; - \u0026#34;::1\u0026#34; - \u0026#34;localhost\u0026#34; groups: - wheel - name: john password: \u0026#34;john_pass\u0026#34; authorized: - keys/john_key.pub mysql: password: other-mysql-password hosts: - \u0026#34;utility\u0026#34; groups: - wheel - devops 在經過 subelements() 處理後，會變成以下的資料結構\n- - authorized: [keys/paul_key1.pub, keys/paul_key2.pub] groups: [wheel] mysql: hosts: [\u0026#39;%\u0026#39;, 127.0.0.1, \u0026#39;::1\u0026#39;, localhost] name: paul password: paul_pass - keys/paul_key1.pub - - authorized: [keys/paul_key1.pub, keys/paul_key2.pub] groups: [wheel] mysql: hosts: [\u0026#39;%\u0026#39;, 127.0.0.1, \u0026#39;::1\u0026#39;, localhost] name: paul password: paul_pass - keys/paul_key2.pub - - authorized: [keys/john_key.pub] groups: [wheel, devops] mysql: hosts: [utility] password: other-mysql-password name: john password: john_pass - keys/john_key.pub 也就是一個 list，裏面有三個 item；每個 item 又是一個 list，list 裡有兩個元素，第一個是 user，第二個則是 authorized 裡的值。\n接下來我們寫一個 playbook 來驗證看看\n--- # 檔名： test-sublements.yml - name: Test subelements hosts: all vars: users: - name: paul password: \u0026#34;paul_pass\u0026#34; authorized: - keys/paul_key1.pub - keys/paul_key2.pub mysql: hosts: - \u0026#34;%\u0026#34; - \u0026#34;127.0.0.1\u0026#34; - \u0026#34;::1\u0026#34; - \u0026#34;localhost\u0026#34; groups: - wheel - name: john password: \u0026#34;john_pass\u0026#34; authorized: - keys/john_key.pub mysql: password: other-mysql-password hosts: - \u0026#34;utility\u0026#34; groups: - wheel - devops tasks: - name: 用 loop 遍訪每個元素，印出 name 跟 key debug: msg: \u0026#34;user.name={{ item.0.name }} key={{ item.1 }}\u0026#34; loop: \u0026#34;{{ users | subelements(\u0026#39;authorized\u0026#39;) }}\u0026#34; - name: 輸出到 /tmp/subelements_output.yml 再來觀察 copy: content: \u0026#34;{{ users | subelements(\u0026#39;authorized\u0026#39;) | to_yaml }}\u0026#34; dest: /tmp/subelements_output.yml 這個 playbook 只有兩個 task，第一個 task 使用 loop 去遍訪 subelements() 輸出後的 list，這裡印出 item 的第一個元素跟第二個元素。如同前面所提的， 第一個元素是 user，所以 item.0 就等於 user，也就可以直接用 item.0.name 來取得 user.name。 第二個元素是 authorized 裡的值，這邊用 item.1 來存取。\n第二個 task 則是把 subelements() 的輸出結果轉為 yaml 檔以後，存到 /tmp/subelements_output.yml\n我們執行看看\nansible-playbook -i localhost, -c local test-sublements.yml 輸出結果大略如下：\n... 省略 ... TASK [用 loop 遍訪每個元素，印出 name 跟 key] **************************************************************************** ok: [localhost] =\u0026gt; (item=[{u\u0026#39;mysql\u0026#39;: {u\u0026#39;hosts\u0026#39;: [u\u0026#39;%\u0026#39;, u\u0026#39;127.0.0.1\u0026#39;, u\u0026#39;::1\u0026#39;, u\u0026#39;localhost\u0026#39;]}, u\u0026#39;password\u0026#39;: u\u0026#39;paul_pass\u0026#39;, u\u0026#39;authorized\u0026#39;: [u\u0026#39;keys/paul_key1.pub\u0026#39;, u\u0026#39;keys/paul_key2.pub\u0026#39;], u\u0026#39;groups\u0026#39;: [u\u0026#39;wheel\u0026#39;], u\u0026#39;name\u0026#39;: u\u0026#39;paul\u0026#39;}, u\u0026#39;keys/paul_key1.pub\u0026#39;]) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;user.name=paul key=keys/paul_key1.pub\u0026#34; } ok: [localhost] =\u0026gt; (item=[{u\u0026#39;mysql\u0026#39;: {u\u0026#39;hosts\u0026#39;: [u\u0026#39;%\u0026#39;, u\u0026#39;127.0.0.1\u0026#39;, u\u0026#39;::1\u0026#39;, u\u0026#39;localhost\u0026#39;]}, u\u0026#39;password\u0026#39;: u\u0026#39;paul_pass\u0026#39;, u\u0026#39;authorized\u0026#39;: [u\u0026#39;keys/paul_key1.pub\u0026#39;, u\u0026#39;keys/paul_key2.pub\u0026#39;], u\u0026#39;groups\u0026#39;: [u\u0026#39;wheel\u0026#39;], u\u0026#39;name\u0026#39;: u\u0026#39;paul\u0026#39;}, u\u0026#39;keys/paul_key2.pub\u0026#39;]) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;user.name=paul key=keys/paul_key2.pub\u0026#34; } ok: [localhost] =\u0026gt; (item=[{u\u0026#39;mysql\u0026#39;: {u\u0026#39;password\u0026#39;: u\u0026#39;other-mysql-password\u0026#39;, u\u0026#39;hosts\u0026#39;: [u\u0026#39;utility\u0026#39;]}, u\u0026#39;password\u0026#39;: u\u0026#39;john_pass\u0026#39;, u\u0026#39;authorized\u0026#39;: [u\u0026#39;keys/john_key.pub\u0026#39;], u\u0026#39;groups\u0026#39;: [u\u0026#39;wheel\u0026#39;, u\u0026#39;devops\u0026#39;], u\u0026#39;name\u0026#39;: u\u0026#39;john\u0026#39;}, u\u0026#39;keys/john_key.pub\u0026#39;]) =\u0026gt; { \u0026#34;msg\u0026#34;: \u0026#34;user.name=john key=keys/john_key.pub\u0026#34; } TASK [輸出到 /tmp/subelements_output.yml 再來觀察] *********************************************************************** changed: [localhost] ... 省略 ... 讓我們看看 /tmp/subelements_output.yml (使用 cat /tmp/subelements.yml)\n- - \u0026amp;id001 authorized: [keys/paul_key1.pub, keys/paul_key2.pub] groups: [wheel] mysql: hosts: [\u0026#39;%\u0026#39;, 127.0.0.1, \u0026#39;::1\u0026#39;, localhost] name: paul password: paul_pass - keys/paul_key1.pub - - *id001 - keys/paul_key2.pub - - authorized: [keys/john_key.pub] groups: [wheel, devops] mysql: hosts: [utility] password: other-mysql-password name: john password: john_pass - keys/john_key.pub 可以看出來，跟我們之前所預期的幾乎一樣。 只是輸出的結果裡，使用了 \u0026amp;id001 來定義錨點，第二個元素使用 *id001 來引用之前定義的錨點以減少資料量。\n看到這邊相信你已經了解 subelements 怎麼使用了吧。\n","permalink":"https://ansible.cloudns.pro/post/jinja2-filter---subelement/","summary":"\u003cp\u003esubelements 這個 filter 是取出 list 裡每個項目裡的 attribute ，然後轉為每個元素為 list 的 list。\nxxx\n很繞口，對吧，這個不太容易理解，用例子比較好講。\u003c/p\u003e\n\u003cp\u003e從下面的變數定義可以看到，users 是一個 list，裏面有兩個項目，每個項目代表一個 user\u003c/p\u003e","title":"Jinja2 filter - subelements"},{"content":"Ansible 釋出 3.0.0 了，之前的版本是 2.10，目前所釋出的 3.0.0 有點特別。 這是新聞稿：Announcing the Community Ansible 3.0.0 Package\n為什麼說有點特別呢？\nAnsible 2.9 之前，許多的模組跟 plugin 都在 Ansible 專案裡，所以如果模組開發者釋出模組與 plugin 的更新，勢必就要等 Ansible 釋出新版本，使用者才會拿到這更新。\n在 Ansible 2.9 之後，Ansible 開發團隊引入 collections ，collection 裡包含了模組、plugin\u0026hellip;等等，等於是整理了之前的模組。使用者要使用模組，可以藉由 ansible-galaxy 安裝 collection，就可以得到更新的模組跟 plugin。接下來，Ansible 開發團隊把原本內建的模組跟 plugin (現在是 collections 了) 拆出去成為獨立的 repository，在釋出 2.10 時，才把 ansible-base 與拆出去的 collections 組合起來。\n現在新的 3.0.0 則是更進一步，之後 Ansible 會拆為三個部分：\nAnsible core，這個就是之前的 ansible-base，是主要的 language 解譯器跟 runtime。版本號碼會照之前 2.9, 2.10, 2.11 來走。 Ansible collections on Galaxy，collection 的版本號碼則是由 collection 開發者來決定。 Ansible community，這個就是前兩者的綜合，大約有 80 幾個 collections，上千個模組跟 plugins。版本號碼變為 3.0.0，也就是這次新聞稿所提到的 Ansible 3.0.0。 好，簡單的說，之後就繼續使用 Ansible community 3.0.0，這就跟之前的 ansible 一樣，有內建的 collection 可以用。有需要使用到更新的 collections ，可以用 ansible-galaxy 來安裝 collection 到 playbook 所在的目錄下。\n如果，只使用到幾個 collections，不想裝沒用到的，那就可以裝 ansible-base，然後搭配 ansible-galaxy 來安裝 collections 。\n現在二月釋出 3.0.0，依照 Ansible 的 roadmap，很快在五月也要推出正式版的 4.0.0，開發的腳步加快了。 Ansible project 4.0 Roadmap 不過照這樣的速度，很快就會 10.0、11.0，會讓我們這些工程師追版本追到手軟，我希望是可以有 LTS 的版本，讓我們有比較長的緩衝時間可以去適應新版本。\n","permalink":"https://ansible.cloudns.pro/post/ansible-3.0.0/","summary":"\u003cp\u003eAnsible 釋出 3.0.0 了，之前的版本是 2.10，目前所釋出的 3.0.0 有點特別。\n這是新聞稿：\u003ca href=\"https://www.ansible.com/blog/announcing-the-community-ansible-3.0.0-package\"\u003eAnnouncing the Community Ansible 3.0.0 Package\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e為什麼說有點特別呢？\u003c/p\u003e","title":"Ansible 3.0.0"},{"content":"介紹如何在 RHEL 上安裝 Ansible 2.9，Ansible 提供了兩個主要的 repository ， 一個是 Red Hat 官方所提供的 repository，另外一個則是 EPEL 的 repository， 下面我們就針對這兩者來介紹其安裝方式。\n使用 Red hat repository 在 RHEL 上的安裝，要先確保使用 subscription-manager 註冊，然後啟用 Red Hat 提供的 repository\nRHEL 7\nsudo subscription-manager repos --enable rhel-7-server-ansible-2.9-rpms RHEL 8\nsudo subscription-manager repos --enable ansible-2.9-for-rhel-8-x86_64-rpms 接著就可以使用 yum 來安裝了。\nsudo yum -y install ansible 使用 EPEL repository 如果不使用 Red Hat 的 repository ，也可以使用 EPEL repository 。\nRHEL7\n先安裝 EPEL 提供的套件\nsudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 再啟用 ansible 可能會用到的 repository\nsudo subscription-manager repos --enable \u0026#34;rhel-*-optional-rpms\u0026#34; --enable \u0026#34;rhel-*-extras-rpms\u0026#34; --enable \u0026#34;rhel-ha-for-rhel-*-server-rpms\u0026#34; 使用 yum 來安裝\nsudo yum -y install ansible RHEL8\n一樣，先安裝 EPEL 提供的套件\nsudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm 再啟用 ansible 可能會用到的 repoistory，RHEL8 的 repository 跟 RHEL7 不太一樣\nsudo subscription-manager repos --enable \u0026#34;codeready-builder-for-rhel-8-$(/bin/arch)-rpms\u0026#34; 使用 yum 來安裝\nsudo yum -y install ansible ","permalink":"https://ansible.cloudns.pro/post/how-to-install-ansible-2.9-on-rhel/","summary":"\u003cp\u003e介紹如何在 RHEL 上安裝 Ansible 2.9，Ansible 提供了兩個主要的 repository ，\n一個是 Red Hat 官方所提供的 repository，另外一個則是 EPEL 的 repository，\n下面我們就針對這兩者來介紹其安裝方式。\u003c/p\u003e","title":"如何在 RHEL 上安裝 Ansible 2.9"},{"content":"Ubuntu 上的安裝很簡單，先加入 apt repository 以後，就可以安裝了。\nsudo apt update sudo apt install software-properties-common sudo apt-add-repository --yes --update ppa:ansible/ansible sudo apt install ansible ","permalink":"https://ansible.cloudns.pro/post/how-to-install-ansible-on-ubuntu/","summary":"\u003cp\u003eUbuntu 上的安裝很簡單，先加入 apt repository 以後，就可以安裝了。\u003c/p\u003e","title":"如何在 Ubuntu 上安裝 Ansible"},{"content":"控制端 (Control node) 必須要能以 SSH / WinRM 等協定連接到被控端 (Managed node)。\n對了，先說明一下：\n控制端：指的是執行 Ansible playbook 的主機。 被控端：指的是被控制的主機，也就是你想要操控的終端設備。 控制端主機上必須要有 Python 2.x / 3.x，所以大部分的 Unix-like 作業系統，如 Ubuntu, MacOS 等，都可以執行 Ansible，不過，Windows 就不行，詳情可以參考 Matt on \u0026hellip; Whatever: Why no Ansible controller for Windows?。 i 被控端主機必須要能接受 SSH / WinRM 連線，同樣的，也需要有 Python 2.x / 3.x\n","permalink":"https://ansible.cloudns.pro/post/prerequisites/","summary":"\u003cp\u003e控制端 (Control node) 必須要能以 SSH / WinRM 等協定連接到被控端 (Managed node)。\u003c/p\u003e","title":"需求規格"},{"content":"簡介 在介紹 Ansible 之前，必須要介紹 vagrant 這個工具。\nvagrant 是一個可以用來快速建立虛擬機器的工具，有了虛擬機，我們就可以快速地做出一個用來試驗 Ansible 的環境。\n它跨平台，支援以下平台：\nMac OS Windows Linux Debian CentOS 至於虛擬機器的部份，它可以用這些虛擬機器環境甚至是雲端環境來建立虛擬機器：\nVirtualBox VMWare AWS \u0026hellip; 下面先只介紹怎麼跟 VirtualBox 搭配。\n安裝 基本步驟，先安裝 VirtualBox，再安裝 vagrant。\nUbuntu 安裝 VirtualBox\necho \u0026#34;deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian $(lsb_release -c -s) contrib\u0026#34; | sudo tee /etc/sources.list.d/virtualbox.list wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add - sudo apt-get update sudo apt-get install virtualbox-6.1 接著是安裝 vagrant，先到 Vagrant 下載頁面 ，點選 Debian，然後點選 Download，再用 dpkg 安裝即可。\nMacOS 在 MacOS 下可以用 homebrew 來安裝。\n安裝 homebrew 很簡單，一行就搞定了\n/bin/bash -c \u0026#34;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\u0026#34; 接著安裝 VirtualBox\nbrew install virtualbox 再安裝 vagrant\nbrew install vagrant 使用 使用上很簡單，只有兩行，先 init，再 up 。 執行 vagrant init xxx 以後，會出現 Vagrantfile ，如果需要調整記憶體、IP 位址等，可以先行修改這個檔案，再來使用 vagrant up 啟動。\n建立 ubuntu 虛擬機器 mkdir -p ubuntu-vm cd ubuntu-vm vagrant init ubuntu/focal64 vagrant up 建立 CentOS 虛擬機器 mkdir -p centos-vm cd centos-vm vagrant init generic/centos8 vagrant up 以 SSH 登入虛擬機器 vagrant ssh 關閉虛擬機器 vagrant halt 移除虛擬機器 vagrant destroy 參考資料 VirtualBox 下載頁面 Getting Started | Vagrant - HashiCorp Learn ","permalink":"https://ansible.cloudns.pro/post/vagrant/","summary":"\u003ch2 id=\"簡介\"\u003e簡介\u003c/h2\u003e\n\u003cp\u003e在介紹 Ansible 之前，必須要介紹 vagrant 這個工具。\u003c/p\u003e","title":"Ansible 的好朋友 - vagrant"},{"content":" 專題 - 使用 Ansible 進行快速佈署 - 環境設定與 ad hoc Ansible中文權威指南 1.0.1 30天入門 Ansible 及 Jenkins 不自量力的WEITHENN - 分享 Ansible 文章，最近在分享控制網路設備的 Ansible playbook ，像是 CISCO 等。 Red Hat 工程師 Hazel 所撰寫的 Ansible 文章 ","permalink":"https://ansible.cloudns.pro/page/resources/","summary":"專題 - 使用 Ansible 進行快速佈署 - 環境設定與 ad hoc Ansible中文權威指南 1.0.1 30天入門 Ansible 及 Jenkins 不自量力的WEITHENN - 分享 Ansible 文章，最近在分享控制網","title":"資源"},{"content":"我是 elleryq，這裡主要是紀錄我使用 Ansible 與相關軟體的點點滴滴。\n已經取得的證照 EX447 EX280 正在努力的證照 DO180 ","permalink":"https://ansible.cloudns.pro/page/about/","summary":"我是 elleryq，這裡主要是紀錄我使用 Ansible 與相關軟體的點點滴滴。 已經取得的證照 EX447 EX280 正在努力的證照 DO180","title":"關於本站"}]