乾貨 | Ansible 上手指南
點選上方“中興開發人員社群”,關注我們
每天讀一篇一線開發人員原創好文
前言
近期在重構一款命令列工具。使用 golang 又一次開發。但須要繼續維持原有的命令,同一時候新增新命令。
在重構的過程中,須要對現命令列工具和原命令列工具的命令輸出結果進行比對,確保全然一致(專案要求)。命令列工具須要在部署完畢系統之後進行使用,每一個系統完畢時的部署元件又略微有點差異。
所以事實上須要在多套服務主機上進行測試。
須要做這些動作:
拷貝一些配置檔案到主機上:使用者配置、IP和port檔案
安裝命令列工具,確保使其在服務主機上能夠使用
執行一堆測試命令
按理說,我不斷把須要的配置和二進位制檔案複製到主機上進行測試也能完畢。
但在使用的過程中存在以下幾個問題:
測試發現,結果不正確時須要及時改動程式碼。再次拷貝二進位制檔案到主機上
主機環境須要多次推倒,又一次部署,驗證版本號更新問題
須要手動一個一個命令的執行
測試有幾套主機
看上去手動的方法。有點費勁。
眼下我從事的工作就是 PaaS
部署相關的,部署層面的指令碼的執行、元件的安裝、服務的啟動等都是使用 Ansible 來操作。詳細的指令碼編寫由其它同事,我僅僅知道這個東西是幹嘛的。沒實質性的學習。於是想借這個機會主動學習下 Ansible.
學習之處,差點犯了老問題,即:從頭開始看官方文件,而不注重當前須要解決的問題。
由於事實上整個 Ansible 的內容體系非常多。
不注重當前須要解決的問題,會導致你抓不住重點。
意識到後專注在當前須要解決的問題上:
拷貝配置檔案和安裝指令碼到多個主機上
在多個主機上測試命令列工具
Ansible
看了上面的事件背景。你大概知道這個 Ansible 究竟是個什麼東西。
Ansible 是一個配置管理和應用部署工具。即在管理主機上操作一些命令就能在節點主機上進行對應的動作。由 Python 編寫。由模組化組成,即執行動作的實體。在 ansible 上都是靠著對應的模組執行動作,比方拷貝 copy 模組、執行 command 模組、shell 模組、檔案 file 模組等。
Ansible 的目標有例如以下:
自己主動化部署應用
自己主動化管理配置
自己主動化的持續交付
自己主動化的(AWS)雲服務管理。
原理
管理主機從 hosts 裡讀取主機清單,通過 playbook 按順序同一時候對管理的主機進行對應的操作。
如圖:
管理主機主要是對主機的定義和配置、編寫 playbook(即節點主機的執行動作)。
執行:
1. 命令列
ansible all -m ping
2. playbook
ansible-playbook example.yml
主機清單
編輯檔案:/etc/ansible/hosts
即:定義主機名稱,變數等
主機的變數包括什麼: 主機的執行使用者、連線port、password等
相似於 ini 格式的檔案
[test-new-cli]
10.62.60.72
[test-old-cli]
10.62.62.88
上面的樣例:將兩個主機的分為兩組:test-new-cli
和 test-old-cli
主機的變數有這麼些:
ansible_ssh_host
將要連線的遠端主機名.與你想要設定的主機的別名不同的話,可通過此變數設定.ansible_ssh_port
sshport號.假設不是預設的port號,通過此變數設定.ansible_ssh_user
預設的 ssh usernameansible_ssh_pass
ssh password(這樣的方式並不安全,我們強烈建議使用 —ask-pass 或 SSH 金鑰)ansible_sudo_pass
sudo password(這樣的方式並不安全,我們強烈建議使用 —ask-sudo-pass)ansible_sudo_exe (new in version 1.8)
sudo 命令路徑(適用於1.8及以上版本號)ansible_connection
與主機的連線型別.比方:local, ssh 或者 paramiko.ansible_ssh_private_key_file
ssh 使用的私鑰檔案.適用於有多個金鑰,而你不想使用 SSH 代理的情況.ansible_shell_type
目標系統的shell型別.預設情況下,命令的執行使用 ‘sh’ 語法,可設定為 ‘csh’ 或 ‘fish’.ansible_python_interpreter
目標主機的 python 路徑.
看不懂怎麼用:
舉個樣例,你想連線主機 192.168.100.100
, 切換到 root 使用者下執行對應的操作。
假設你直接ssh [email protected]
會要求你輸入username和password。
假如我編輯主機清單使得自己不須要輸入usernamepassword,怎麼操作?
[test-new-cli]
example ansible_ssh_host=192.168.100.100 ansible_ssh_user=username ansible_ssh_pass=root
即配置好192.168.100.100
的主機別名為example
, 主機的username和password為:username/root
Yaml
包括三種類型:
鍵值對:key: value
陣列
純量:整型、字串、布林型
這個非常好理解:假設你熟悉Python, 這三種類型就相當於:map, list, 變數
假設你熟悉golang, 這三種類型就相當於: map, 陣列。 變數
演示樣例:
---
- name: "execute command nodepool node list by { {item.name} }"
shell: "{ {item.cli} } nodepool node list { {item.id} }"
register: result
- name: show result
debug:
msg: "{ {result.stdout_lines} }"
with_items:
- { name: "new-cli", cli: "new-cli", id: "1" }
- { name: "old-cli", cli: "old-cli", id: "1" }
模組
Ad-doc
ansible 命令列式,適合執行單條命令。
# 操作 192.168.100.100 主機。看管理主機是否和192.168.100.100的主機連通
ansible example -m ping
# 操作 192.168.100.100 主機,拷貝管理主機下的/root/opcli/conf 檔案至節點主機/etc/opcli/conf 下
ansible test-new-cli -m copy -a="src=/root/opcli/conf dest=/etc/opcli/conf"
m: 模組
a: 接引數
能夠看出適合執行單條命令
Patterns
假如你的節點主機分組非常多了。Ad-hoc 怎樣選擇特定特徵的節點主機分組呢?
使用類正規表示式。
比方觸發全部節點主機進行動作:
ansible all -m ping
ansible * -m ping
兩者等價,都是選擇全部的節點主機
演示樣例:
1. 主機別名或者IP
one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
2. 一個或多個groups
webservers
webservers:dbservers
3. 排除一個組
webservers:!phoenix
# 隸屬 webservers 組但同一時候不在 phoenix組
4. 兩個組的交集
webservers:&staging
# 同一時候隸屬於 webservers 和 staging 組
5. 列表
webservers[0]
webservers[0-25]
6. 其它
有什麼需求,看官方文件吧。
Playbook
編寫 yaml 檔案。適合執行多步操作的複雜操作。能夠看成是Ad-doc 命令的集合。甚至能夠看成是一門程式語言。
執行:ansible-playbook example.yml
依照 example.yml 檔案中的任務集合按步執行任務。
演示樣例
命令演示樣例,僅舉幾例。有帶引數、有沒帶引數的。
我們終於的目標是:在節點主機上執行這些命令進行比對兩者結果。
新版本號:
命令 | 說明 |
---|---|
command-cli nodepool list | 查詢資源池 |
command-cli nodepool node list | 查詢資源池節點 |
command-cli node list | 查詢節點 |
command-cli node show | 查詢某個節點 |
command-cli task list | 查詢部署任務 |
…
舊版本號:
命令 | 說明 |
---|---|
old-cli nodepool list | 查詢資源池 |
old-cli nodepool node list | 查詢資源池節點 |
old-cli node list | 查詢節點 |
old-cli node show | 查詢某個節點 |
old-cli task list | 查詢部署任務 |
…
資料夾結構:
demo-for-ansible:
---nodepool/nodepool-list.yml
---nodepool/nodepool-node-list.yml
---node/node-list.yml
---node/node-show.yml
---task/task-list.yml
---main.yml
第一步:編寫主機清單
/etc/ansible/hosts
[test_client]
192.168.100.100 ansible_ssh_user=xiewei ansible_ssh_pass=root ansible_connection=ssh
192.168.100.101 ansible_ssh_user=xiewei ansible_ssh_pass=root ansible_connection=ssh
192.168.100.102 ansible_ssh_user=xiewei ansible_ssh_pass=root ansible_connection=ssh
定義主機連線型別、username、password
第二步:編寫 yaml 檔案
主要動作:
在節點主機上建立兩個資料夾:
/etc/client/conf
和/et/client/commands
拷貝管理主機資料夾:
/etc/client/conf
檔案至節點主機:/etc/client/conf
拷貝管理主機二進位制檔案:
/root/gosrc/src/client/command-cli
至節點主機/etc/client/commands
軟連線節點主機二進位制檔案:
/etc/client/commands/command-cli
至節點主機/usr/bin/command-cli
執行上表中查詢命令:nodepool, node, task
main.yml
---
- hosts: test_client
remote_user: root
become: yes
become_user: root
become_method: sudo
tasks:
# 在節點主機上建立資料夾:/etc/client/conf
- name: create /etc/client/conf /etc/client/commands
file:
path: "/etc/client/{ {item} }"
owner: root
group: root
mode: 0755
state: directory
with_items:
- "conf"
- "commands"
# 拷貝管理主機配置檔案/etc/client/conf和二進位制檔案至 /etc/client/conf, /etc/client/commands
- name: copy /etc/client/conf
copy: src="{ { item.src } }" dest="{ { item.dest } }" owner=root group=root mode=0644
with_items:
- { src: "/etc/client/conf", dest: "/etc/client/conf" }
- { src: "/root/gosrc/src/client/command-cli", dest: "/etc/client/commands"}
# 軟連線到 /usr/bin/command-cli
- name: link /etc/client/commands
file: src="/etc/client/commands/command-cli" dest="/usr/bin/command-cli" state=link
# nodePool list
- include_tasks: "nodepool/nodepool-list.yml"
with_items:
- { client: "new client", name: "command-cli"}
- { client: "old client", name: "old-cli"}
# nodePool node list <id>
- include_tasks: "nodepool/nodepool-node-list.yml"
with_items:
- { id: "1", client: "new client", name: "command-cli"}
- { id: "1", client: "old client", name: "old-cli"}
# node list
- include_tasks: "node/node-list.yml"
with_items:
- { client: "new client", name: "command-cli"}
- { client: "old client", name: "old-cli"}
# node show <id>
- include_tasks: "node/node-show.yml"
with_items:
- { client: "new client", name: "command-cli", id: 1}
- { client: "old client", name: "old-cli", id: 1}
# task list
- include_tasks: "task/task-list.yml"
with_items:
- { client: "new client", name: "command-cli"}
- { client: "old client", name: "old-cli"}
task-list.yml
---
- name: execute command task list
shell: "{ {item.name} } task list"
register: result
- name: show result
debug:
msg: "{ {result.stdout_lines} }"
第三步: 檢查語法
兩種方法
ansible-playbook main.yml --syntax-check
先安裝
pip install ansible-lint
ansible-lint main.yml
第四步: 執行
ansible-playbook main.yml
整個的編寫流程大概是這樣。核心是編寫 yml 檔案,呼叫 ansible 支援的各種模組完畢任務。
下一步
熟悉 playbook
熟悉 ansible 模組
熟悉 ansible api
關注你當前須要解決的問題,切入學習,事半功倍。