在Ubuntu 22.04上安裝Ansible

Ubuntu 22.04 Ansible Install

前言

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 會依以下順序尋找設定檔:

  1. ANSIBLE_CONFIG 環境變數指定的路徑
  2. 當前目錄下的 ansible.cfg
  3. 使用者家目錄下的 ~/.ansible.cfg
  4. 系統預設路徑 /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..."}

解決方案:

  1. 確認目標主機的 SSH 服務正在運行:

    1
    
    ssh user@remote-host
    
  2. 檢查防火牆設定:

    1
    2
    
    sudo ufw status
    sudo ufw allow 22/tcp
    
  3. 確認 inventory 中的主機資訊正確:

    1
    
    ansible-inventory --list -i inventory.yml
    
  4. 使用詳細模式除錯:

    1
    
    ansible all -m ping -i inventory.yml -vvvv
    

問題二:權限不足

錯誤訊息:

1
fatal: [remote-host]: FAILED! => {"msg": "Missing sudo password"}

解決方案:

  1. 在執行時提供 sudo 密碼:

    1
    
    ansible-playbook playbook.yml -i inventory.yml --ask-become-pass
    
  2. 設定 sudo 免密碼(在目標主機上):

    1
    
    echo "username ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/username
    
  3. 在 inventory 中指定密碼(不建議,僅用於測試):

    1
    2
    
    [webservers:vars]
    ansible_become_pass=your_password
    

問題三:Python 解釋器找不到

錯誤訊息:

1
fatal: [remote-host]: FAILED! => {"msg": "/usr/bin/python: not found"}

解決方案:

  1. 在目標主機上安裝 Python:

    1
    
    sudo apt install python3 -y
    
  2. 在 inventory 中指定 Python 路徑:

    1
    2
    
    [all:vars]
    ansible_python_interpreter=/usr/bin/python3
    
  3. 或在 ansible.cfg 中設定:

    1
    2
    
    [defaults]
    interpreter_python=auto_silent
    

問題四:Host Key 驗證失敗

錯誤訊息:

1
fatal: [remote-host]: UNREACHABLE! => {"msg": "Host key verification failed."}

解決方案:

  1. 首次連線時接受主機金鑰:

    1
    
    ssh-keyscan remote-host >> ~/.ssh/known_hosts
    
  2. 在 ansible.cfg 中停用檢查(僅用於測試環境):

    1
    2
    
    [defaults]
    host_key_checking = False
    
  3. 使用環境變數:

    1
    2
    
    export ANSIBLE_HOST_KEY_CHECKING=False
    ansible-playbook playbook.yml
    

問題五:模組執行失敗

除錯技巧:

  1. 使用詳細輸出模式:

    1
    2
    3
    4
    
    ansible-playbook playbook.yml -v    # 基本詳細
    ansible-playbook playbook.yml -vv   # 更詳細
    ansible-playbook playbook.yml -vvv  # 連線除錯
    ansible-playbook playbook.yml -vvvv # 完整除錯
    
  2. 檢查語法:

    1
    
    ansible-playbook playbook.yml --syntax-check
    
  3. 試運行(不實際執行):

    1
    
    ansible-playbook playbook.yml --check
    
  4. 從特定任務開始執行:

    1
    
    ansible-playbook playbook.yml --start-at-task="任務名稱"
    
  5. 逐步執行:

    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 自動化管理您的基礎設施了。

建議的學習路徑:

  1. 熟悉 Inventory 和 Ad-hoc 命令
  2. 學習撰寫基本的 Playbook
  3. 了解變數、條件判斷和迴圈
  4. 學習使用 Role 組織程式碼
  5. 探索 Ansible Galaxy 上的社群 Role
  6. 實作更複雜的自動化場景

更多資訊請參考 Ansible 官方文件

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy