前言
Ansible 是一款開源的自動化工具,由 Red Hat 維護,專門用於配置管理、應用程式部署、任務自動化以及 IT 協調(Orchestration)。相較於其他組態管理工具如 Puppet、Chef 或 SaltStack,Ansible 具有以下顯著優勢:
- 無代理架構(Agentless):Ansible 不需要在被管理的節點上安裝任何代理程式,僅透過 SSH 協定即可進行管理,大幅降低了部署和維護的複雜度。
- 簡單易學:使用 YAML 格式撰寫 Playbook,語法直觀易懂,即使是初學者也能快速上手。
- 冪等性(Idempotent):執行相同的 Playbook 多次,結果都會保持一致,不會因重複執行而產生副作用。
- 豐富的模組庫:內建超過 3000 個模組,涵蓋系統管理、雲端服務、網路設備等各種應用場景。
- 可擴展性強:支援自訂模組和外掛程式,能夠根據需求進行擴展。
本文將詳細介紹如何在 Ubuntu 22.04 上安裝 Ansible,並涵蓋基本概念、設定檔說明、Playbook 範例以及常見問題排除。
安裝方式
在 Ubuntu 22.04 上安裝 Ansible 有多種方式,以下介紹三種常見的安裝方法:
方式一:透過 APT 套件管理器安裝(最簡單)
這是最簡單直接的安裝方式,使用 Ubuntu 官方套件庫中的 Ansible 版本。
1
2
3
| sudo apt update
sudo apt install ansible -y
ansible --version
|
注意:此方式安裝的版本可能不是最新版,若需要最新功能,建議使用官方 PPA 或 pip 安裝。
方式二:透過官方 PPA 安裝(推薦)
使用 Ansible 官方維護的 PPA(Personal Package Archive),可以獲得較新的穩定版本。
1
2
3
4
5
6
7
8
9
10
11
12
| # 安裝必要的套件
sudo apt update
sudo apt install software-properties-common -y
# 新增 Ansible 官方 PPA
sudo add-apt-repository --yes --update ppa:ansible/ansible
# 安裝 Ansible
sudo apt install ansible -y
# 驗證安裝
ansible --version
|
方式三:透過 pip 安裝(最新版本)
使用 Python 的 pip 套件管理器安裝,可以獲得最新版本的 Ansible,並且便於管理多個版本。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # 安裝 Python 和 pip
sudo apt update
sudo apt install python3 python3-pip -y
# 透過 pip 安裝 Ansible
pip3 install ansible
# 或安裝到使用者目錄(不需要 sudo)
pip3 install --user ansible
# 確認 PATH 包含 pip 安裝路徑
export PATH="$HOME/.local/bin:$PATH"
# 驗證安裝
ansible --version
|
若要安裝特定版本:
1
| pip3 install ansible==8.0.0
|
若要升級到最新版本:
1
| pip3 install --upgrade ansible
|
Ansible 基本概念
在開始使用 Ansible 之前,了解以下核心概念非常重要:
Inventory(清單)
Inventory 是 Ansible 管理的主機清單,定義了要管理的目標伺服器。預設路徑為 /etc/ansible/hosts。
INI 格式範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| # /etc/ansible/hosts 或自訂的 inventory 檔案
# 單一主機
192.168.1.100
# 群組定義
[webservers]
web1.example.com
web2.example.com
192.168.1.101
[dbservers]
db1.example.com
db2.example.com
# 群組變數
[webservers:vars]
ansible_user=ubuntu
ansible_port=22
# 巢狀群組
[production:children]
webservers
dbservers
|
YAML 格式範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # inventory.yml
all:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
vars:
ansible_user: ubuntu
dbservers:
hosts:
db1.example.com:
ansible_port: 2222
db2.example.com:
|
Module(模組)
模組是 Ansible 執行任務的基本單元,每個模組負責執行特定的功能。常用模組包括:
| 模組 | 用途 |
|---|
apt | 管理 Debian/Ubuntu 套件 |
yum | 管理 RHEL/CentOS 套件 |
copy | 複製檔案到遠端主機 |
template | 使用 Jinja2 模板產生檔案 |
file | 管理檔案和目錄屬性 |
service | 管理系統服務 |
user | 管理使用者帳號 |
command | 執行命令(不經過 shell) |
shell | 透過 shell 執行命令 |
git | 管理 Git 儲存庫 |
docker_container | 管理 Docker 容器 |
使用 Ad-hoc 命令測試模組:
1
2
3
4
5
6
7
8
| # 測試連線
ansible all -m ping -i inventory.yml
# 查看主機資訊
ansible all -m setup -i inventory.yml
# 安裝套件
ansible webservers -m apt -a "name=nginx state=present" -i inventory.yml --become
|
Playbook(劇本)
Playbook 是 Ansible 的核心,使用 YAML 格式撰寫,定義了一系列要在目標主機上執行的任務。
基本結構:
1
2
3
4
5
6
7
8
9
10
11
12
| ---
- name: Playbook 名稱
hosts: 目標主機或群組
become: yes # 是否使用 sudo
vars:
變數名稱: 變數值
tasks:
- name: 任務描述
模組名稱:
參數1: 值1
參數2: 值2
|
Role(角色)
Role 是一種將 Playbook 組織成可重用結構的方式,適合管理複雜的部署場景。標準的 Role 目錄結構如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| roles/
└── webserver/
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── nginx.conf.j2
├── files/
│ └── index.html
├── vars/
│ └── main.yml
├── defaults/
│ └── main.yml
└── meta/
└── main.yml
|
設定檔說明(ansible.cfg)
Ansible 的設定檔 ansible.cfg 用於定義 Ansible 的預設行為。Ansible 會依以下順序尋找設定檔:
ANSIBLE_CONFIG 環境變數指定的路徑- 當前目錄下的
ansible.cfg - 使用者家目錄下的
~/.ansible.cfg - 系統預設路徑
/etc/ansible/ansible.cfg
建立專案設定檔
在專案目錄下建立 ansible.cfg:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| [defaults]
# Inventory 檔案路徑
inventory = ./inventory.yml
# 遠端使用者
remote_user = ubuntu
# 私鑰路徑
private_key_file = ~/.ssh/id_rsa
# 停用 SSH 金鑰檢查(僅用於測試環境)
host_key_checking = False
# 平行執行的主機數量
forks = 10
# 重試失敗的任務
retry_files_enabled = True
retry_files_save_path = ./retry
# 日誌檔案路徑
log_path = ./ansible.log
# 角色路徑
roles_path = ./roles
# 連線超時時間(秒)
timeout = 30
# 收集 facts 的行為
gathering = smart
fact_caching = jsonfile
fact_caching_connection = ./facts_cache
fact_caching_timeout = 86400
[privilege_escalation]
# 預設使用 sudo 提權
become = True
become_method = sudo
become_user = root
become_ask_pass = False
[ssh_connection]
# SSH 連線參數優化
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null
|
SSH 無密碼連線設定
Ansible 透過 SSH 連線到遠端主機,設定 SSH 金鑰認證可以避免每次執行都需要輸入密碼。
步驟一:產生 SSH 金鑰對
在 Ansible 控制節點上產生金鑰對:
1
2
3
4
5
| # 產生 RSA 金鑰(4096 位元)
ssh-keygen -t rsa -b 4096 -C "ansible@control-node"
# 或產生 Ed25519 金鑰(更安全、更快速)
ssh-keygen -t ed25519 -C "ansible@control-node"
|
依照提示操作,可以設定密碼短語(passphrase)或直接按 Enter 跳過。
步驟二:複製公鑰到受管理的主機
使用 ssh-copy-id 將公鑰複製到目標主機:
1
2
3
4
5
| # 複製到單一主機
ssh-copy-id -i ~/.ssh/id_rsa.pub user@remote-host
# 如果使用非標準 SSH 埠
ssh-copy-id -i ~/.ssh/id_rsa.pub -p 2222 user@remote-host
|
若有多台主機,可以使用迴圈批次處理:
1
2
3
| for host in web1.example.com web2.example.com db1.example.com; do
ssh-copy-id -i ~/.ssh/id_rsa.pub ubuntu@$host
done
|
步驟三:測試連線
1
2
3
4
5
| # 使用 SSH 測試
ssh ubuntu@remote-host
# 使用 Ansible 測試
ansible all -m ping -i inventory.yml
|
使用 SSH Agent(可選)
如果金鑰有設定密碼短語,可以使用 SSH Agent 避免重複輸入:
1
2
3
4
5
6
7
8
| # 啟動 SSH Agent
eval $(ssh-agent)
# 新增金鑰
ssh-add ~/.ssh/id_rsa
# 查看已載入的金鑰
ssh-add -l
|
Playbook 範例
範例一:安裝並設定 Nginx 網頁伺服器
建立檔案 install_nginx.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| ---
- name: 安裝並設定 Nginx 網頁伺服器
hosts: webservers
become: yes
vars:
nginx_port: 80
server_name: example.com
document_root: /var/www/html
tasks:
- name: 更新 APT 快取
apt:
update_cache: yes
cache_valid_time: 3600
- name: 安裝 Nginx
apt:
name: nginx
state: present
notify: 重啟 Nginx
- name: 建立網站根目錄
file:
path: "{{ document_root }}"
state: directory
owner: www-data
group: www-data
mode: '0755'
- name: 部署首頁
copy:
content: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to {{ server_name }}</title>
</head>
<body>
<h1>Hello from Ansible!</h1>
<p>This page was deployed using Ansible.</p>
</body>
</html>
dest: "{{ document_root }}/index.html"
owner: www-data
group: www-data
mode: '0644'
- name: 確保 Nginx 服務啟動並設定開機自動啟動
service:
name: nginx
state: started
enabled: yes
- name: 開啟防火牆 HTTP 埠
ufw:
rule: allow
port: "{{ nginx_port }}"
proto: tcp
when: ansible_os_family == "Debian"
handlers:
- name: 重啟 Nginx
service:
name: nginx
state: restarted
|
執行 Playbook:
1
| ansible-playbook install_nginx.yml -i inventory.yml
|
範例二:使用者管理
建立檔案 manage_users.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| ---
- name: 管理系統使用者
hosts: all
become: yes
vars:
users:
- name: developer
groups: sudo,docker
shell: /bin/bash
ssh_key: "ssh-rsa AAAAB3NzaC1yc2E... developer@example.com"
- name: deployer
groups: www-data
shell: /bin/bash
ssh_key: "ssh-rsa AAAAB3NzaC1yc2E... deployer@example.com"
tasks:
- name: 建立使用者
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
shell: "{{ item.shell }}"
create_home: yes
state: present
loop: "{{ users }}"
- name: 設定 SSH 授權金鑰
authorized_key:
user: "{{ item.name }}"
key: "{{ item.ssh_key }}"
state: present
loop: "{{ users }}"
- name: 設定 sudo 權限(免密碼)
lineinfile:
path: /etc/sudoers.d/{{ item.name }}
line: "{{ item.name }} ALL=(ALL) NOPASSWD:ALL"
create: yes
validate: 'visudo -cf %s'
loop: "{{ users }}"
when: "'sudo' in item.groups"
|
範例三:系統更新與安全設定
建立檔案 system_hardening.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| ---
- name: 系統安全加固
hosts: all
become: yes
tasks:
- name: 更新所有套件到最新版本
apt:
upgrade: dist
update_cache: yes
cache_valid_time: 3600
- name: 安裝常用安全工具
apt:
name:
- fail2ban
- ufw
- unattended-upgrades
state: present
- name: 設定 SSH - 停用 root 登入
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin no'
notify: 重啟 SSH
- name: 設定 SSH - 停用密碼認證
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PasswordAuthentication'
line: 'PasswordAuthentication no'
notify: 重啟 SSH
- name: 啟用 UFW 防火牆
ufw:
state: enabled
policy: deny
direction: incoming
- name: 允許 SSH 連線
ufw:
rule: allow
port: '22'
proto: tcp
- name: 啟用自動安全更新
copy:
content: |
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
dest: /etc/apt/apt.conf.d/20auto-upgrades
handlers:
- name: 重啟 SSH
service:
name: sshd
state: restarted
|
常見問題排除
問題一:SSH 連線失敗
錯誤訊息:
1
| fatal: [remote-host]: UNREACHABLE! => {"msg": "Failed to connect to the host via ssh..."}
|
解決方案:
確認目標主機的 SSH 服務正在運行:
檢查防火牆設定:
1
2
| sudo ufw status
sudo ufw allow 22/tcp
|
確認 inventory 中的主機資訊正確:
1
| ansible-inventory --list -i inventory.yml
|
使用詳細模式除錯:
1
| ansible all -m ping -i inventory.yml -vvvv
|
問題二:權限不足
錯誤訊息:
1
| fatal: [remote-host]: FAILED! => {"msg": "Missing sudo password"}
|
解決方案:
在執行時提供 sudo 密碼:
1
| ansible-playbook playbook.yml -i inventory.yml --ask-become-pass
|
設定 sudo 免密碼(在目標主機上):
1
| echo "username ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/username
|
在 inventory 中指定密碼(不建議,僅用於測試):
1
2
| [webservers:vars]
ansible_become_pass=your_password
|
問題三:Python 解釋器找不到
錯誤訊息:
1
| fatal: [remote-host]: FAILED! => {"msg": "/usr/bin/python: not found"}
|
解決方案:
在目標主機上安裝 Python:
1
| sudo apt install python3 -y
|
在 inventory 中指定 Python 路徑:
1
2
| [all:vars]
ansible_python_interpreter=/usr/bin/python3
|
或在 ansible.cfg 中設定:
1
2
| [defaults]
interpreter_python=auto_silent
|
問題四:Host Key 驗證失敗
錯誤訊息:
1
| fatal: [remote-host]: UNREACHABLE! => {"msg": "Host key verification failed."}
|
解決方案:
首次連線時接受主機金鑰:
1
| ssh-keyscan remote-host >> ~/.ssh/known_hosts
|
在 ansible.cfg 中停用檢查(僅用於測試環境):
1
2
| [defaults]
host_key_checking = False
|
使用環境變數:
1
2
| export ANSIBLE_HOST_KEY_CHECKING=False
ansible-playbook playbook.yml
|
問題五:模組執行失敗
除錯技巧:
使用詳細輸出模式:
1
2
3
4
| ansible-playbook playbook.yml -v # 基本詳細
ansible-playbook playbook.yml -vv # 更詳細
ansible-playbook playbook.yml -vvv # 連線除錯
ansible-playbook playbook.yml -vvvv # 完整除錯
|
檢查語法:
1
| ansible-playbook playbook.yml --syntax-check
|
試運行(不實際執行):
1
| ansible-playbook playbook.yml --check
|
從特定任務開始執行:
1
| ansible-playbook playbook.yml --start-at-task="任務名稱"
|
逐步執行:
1
| ansible-playbook playbook.yml --step
|
後記:Ansible 靜態分析工具
ansible-lint
ansible-lint 是一個用於檢查 Ansible Playbooks 中潛在問題的命令行工具。它可以靜態分析 Ansible Playbooks 的程式碼,並提供關於可優化、最佳實踐和錯誤的建議。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 使用 pip 安裝
pip3 install ansible-lint
# 檢查單一 Playbook
ansible-lint playbook.yml
# 檢查整個目錄
ansible-lint .
# 顯示所有規則
ansible-lint -L
# 忽略特定規則
ansible-lint -x yaml[line-length] playbook.yml
|
yamllint
用於檢查 YAML 語法的工具:
1
2
| pip3 install yamllint
yamllint playbook.yml
|
ansible-doc
查看模組文件的內建工具:
1
2
3
4
5
6
7
8
| # 查看模組說明
ansible-doc apt
# 列出所有可用模組
ansible-doc -l
# 查看模組範例
ansible-doc apt -s
|
總結
本文介紹了在 Ubuntu 22.04 上安裝 Ansible 的多種方式,以及 Ansible 的核心概念、設定檔、SSH 無密碼連線設定、Playbook 範例和常見問題排除。掌握這些基礎知識後,您就可以開始使用 Ansible 自動化管理您的基礎設施了。
建議的學習路徑:
- 熟悉 Inventory 和 Ad-hoc 命令
- 學習撰寫基本的 Playbook
- 了解變數、條件判斷和迴圈
- 學習使用 Role 組織程式碼
- 探索 Ansible Galaxy 上的社群 Role
- 實作更複雜的自動化場景
更多資訊請參考 Ansible 官方文件。