在管理現代 IT 基礎架構的過程中,自動化已成為不可或缺的一環。隨著系統規模不斷擴大,手動設定與維護不僅耗時費力,更容易引入人為錯誤。作為一名資深系統架構師,我見證了 Ansible 如何徹底改變系統管理的方式,讓複雜的佈署流程變得簡單與可靠。
Ansible 作為一款強大的自動化工具,以其簡單易用的特性在 DevOps 領域中脫穎而出。不同於其他組態管理工具,Ansible 採用無代理(Agentless)架構,只需要 SSH 連線和 Python 環境,就能輕鬆管理各種系統。這種設計不僅降低了佈署門檻,也大幅減少了維護成本。
在本文中,我將探討 Ansible 的核心概念、實用技巧以及最佳實踐,幫助你建立高效的自動化工作流程。無論你是初學者還是有經驗的系統管理員,都能從中獲得實用的知識與見解。
Ansible 核心架構與設計理念
無代理架構的優勢
Ansible 最顯著的特色是其「無代理」(Agentless) 架構。這意味著不需要在目標主機上安裝任何特殊軟體,只要目標系統支援 SSH 連線和 Python 環境,就能被 Ansible 管理。這種設計帶來了幾個關鍵優勢:
- 簡化佈署流程:無需在每台伺服器上安裝和維護代理程式
- 降低資源消耗:不會在被管理主機上持續執行背景程式
- 提高安全性:減少潛在的安全漏洞攻擊面
- 增強相容性:幾乎適用於所有支援 SSH 的系統
Ansible 的工作流程相當直觀:控制節點透過 SSH 連線到目標主機,將執行所需的 Python 程式碼傳送過去,在目標主機上執行,然後收集結果回傳。這種設計使得 Ansible 特別適合 Linux 環境,因為幾乎所有 Linux 發行版都預設支援 SSH 和 Python。
Ansible 的三大核心元素
1. 模組 (Modules)
模組是 Ansible 的功能單位,每個模組負責特定任務。例如:
ansible.builtin.apt
- 在 Debian/Ubuntu 系統上管理套件ansible.builtin.yum
- 在 RHEL/CentOS 系統上管理套件ansible.builtin.service
- 管理系統服務ansible.builtin.copy
- 複製檔案到遠端主機
在我的自動化工作流程中,我常組合使用不同模組來完成複雜任務。例如,先使用 copy
模組佈署設定,再用 service
模組重啟相關服務,最後用 uri
模組驗證服務是否正常執行。
2. 外掛 (Plugins)
外掛擴充套件 Ansible 的核心功能,包括:
- Callback Plugins - 自訂輸出格式和通知方式
- Connection Plugins - 定義如何連線到目標主機
- Inventory Plugins - 從不同來源動態生成主機清單
- Filter Plugins - 處理和轉換範本中的資料
我特別喜歡使用 Callback Plugins 來自訂輸出格式,讓執行結果更易於閱讀和分析,尤其是在處理大量主機時。
3. 集合 (Collections)
Ansible 2.9 版本後引入的概念,將相關模組、角色和外掛封裝成一個整體。使用集合可以更方便地管理和分享 Ansible 內容。安裝集合的方式:
ansible-galaxy collection install community.general
檢視已安裝的模組列表:
ansible-doc -l
檢視特定模組的詳細說明:
ansible-doc ansible.builtin.copy
這些指令在撰寫複雜 Playbook 時非常有用,可以快速查閱模組的引數和用法,避免反覆查閱檔案。
Ansible 環境建置與設定最佳化
各主要 Linux 發行版的安裝方法
Debian/Ubuntu 系統
sudo apt update
sudo apt install ansible
RHEL/CentOS/Fedora 系統
在 RHEL 8/CentOS 8/Fedora 系統上,使用 dnf 安裝:
sudo dnf install ansible
對於 RHEL 7/CentOS 7,則使用 yum:
sudo yum install epel-release
sudo yum install ansible
使用 pip 安裝 Ansible 的優勢
使用 pip 安裝 Ansible 的主要優勢是可以安裝最新版本,並且能夠在不同的 Python 虛擬環境中安裝不同版本的 Ansible。
# 檢查 Python 版本
python3 --version
# 安裝 pip(如果尚未安裝)
sudo apt install python3-pip # Debian/Ubuntu
sudo dnf install python3-pip # RHEL/CentOS 8/Fedora
# 使用 pip 安裝 Ansible
pip3 install ansible
# 建立虛擬環境
python3 -m venv ~/ansible_env
# 啟動虛擬環境
source ~/ansible_env/bin/activate
# 在虛擬環境中安裝 Ansible
pip install ansible
使用虛擬環境的另一個好處是可以為不同專案建立獨立的 Ansible 環境,避免版本衝突。
Ansible 設定的關鍵設定
Ansible 的設定通常位於 /etc/ansible/ansible.cfg
,但也可以放在專案目錄中的 ansible.cfg
或使用者主目錄的 .ansible.cfg
。Ansible 會按照以下順序尋找設定:
- 環境變數
ANSIBLE_CONFIG
指定的檔案 - 當前目錄中的
ansible.cfg
- 使用者主目錄中的
.ansible.cfg
/etc/ansible/ansible.cfg
以下是一些重要的設定選項:
[defaults]
# 主機清單檔案位置
inventory = ./inventory
# 平行執行的任務數
forks = 20
# SSH 連線超時時間(秒)
timeout = 30
# 是否顯示任務執行時間
callback_whitelist = profile_tasks
# 停用 SSH 主機金鑰檢查(僅用於測試環境)
host_key_checking = False
# 設定模組路徑
library = ./library
# 設定角色路徑
roles_path = ./roles
[privilege_escalation]
# 是否預設使用 sudo
become = True
# sudo 使用的使用者
become_user = root
# 提權方式(sudo, su, pbrun, pfexec, doas, dzdo, ksu, runas)
become_method = sudo
# 是否詢問 sudo 密碼
become_ask_pass = False
在實際工作中,我會根據不同專案的需求調整這些設定。例如,在管理大量伺服器時,會增加 forks
值以提高平行執行效率;在處理敏感環境時,會確保 host_key_checking = True
以增強安全性。
Ansible 指令操作:從基礎到進階
Ansible 指令基本結構與常用選項
Ansible 指令的基本結構如下:
ansible [主機或群組] -m [模組名稱] -a "[模組引數]" [其他選項]
常用選項包括:
-i, --inventory
:指定主機清單檔案-u, --user
:指定連線使用者-k, --ask-pass
:提示輸入 SSH 密碼-b, --become
:使用許可權提升(如 sudo)-K, --ask-become-pass
:提示輸入許可權提升密碼-C, --check
:模擬執行,不實際變更系統-D, --diff
:顯示檔案變更的差異-v, --verbose
:增加輸出詳細程度(-v, -vv, -vvv)
主機清單(Inventory)設定與管理
主機清單是 Ansible 管理的目標系統列表,可以是靜態檔案或動態指令碼。以下是一個靜態主機清單範例:
# 基本主機群組
[webservers]
web1.example.com
web2.example.com ansible_host=192.168.1.102
# 資料函式庫伺服器
[dbservers]
db1.example.com ansible_host=192.168.1.201
db2.example.com ansible_host=192.168.1.202
# 使用範圍表示法
[workers]
worker[01:20].example.com
# 群組的群組
[production:children]
webservers
dbservers
# 群組變數
[webservers:vars]
http_port=80
proxy_env={'http_proxy':'http://proxy.example.com:8080'}
# 主機特定變數
[all:vars]
ansible_user=deploy
ansible_ssh_private_key_file=/home/deploy/.ssh/id_rsa
在管理大型基礎設施時,我通常會使用動態清單指令碼從雲端平台或 CMDB 系統取得主機資訊。這樣可以確保 Ansible 總是使用最新的主機資訊,避免手動維護主機清單的麻煩。
使用 ansible 指令測試連線與執行簡單任務
連線測試是使用 Ansible 的第一步。使用 ping
模組可以快速檢查是否能夠連線到目標主機:
ansible all -m ping -i inventory
成功的輸出應該類別似:
web1.example.com | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
如果連線失敗,可能需要調整 SSH 設定或檢查網路連線。
執行簡單的系統指令:
# 檢查系統資訊
ansible webservers -m command -a "uname -a" -i inventory
# 檢查磁碟空間
ansible all -m shell -a "df -h" -i inventory
# 檢查記憶體使用情況
ansible dbservers -m shell -a "free -m" -i inventory
command
和 shell
模組的主要區別在於,command
模組直接執行指令而不透過 shell,因此不支援 shell 特性如管道、重定向等;而 shell
模組則透過 /bin/sh
執行指令,支援完整的 shell 功能。
檔案管理與許可權控制
Ansible 提供了多種模組來管理檔案和許可權:
# 複製檔案到遠端主機
ansible webservers -m copy -a "src=/local/path/file.conf dest=/etc/service/file.conf owner=root group=root mode=0644" -i inventory
# 建立目錄
ansible all -m file -a "path=/opt/data state=directory mode=0755 owner=app group=app" -i inventory
# 修改檔案許可權
ansible dbservers -m file -a "path=/var/lib/mysql state=directory mode=0700 owner=mysql group=mysql recurse=yes" -i inventory
# 下載檔案
ansible webservers -m get_url -a "url=https://example.com/archive.tar.gz dest=/tmp/archive.tar.gz checksum=sha256:3733cd..." -i inventory
# 解壓縮檔案
ansible webservers -m unarchive -a "src=/tmp/archive.tar.gz dest=/opt/app remote_src=yes" -i inventory
在實際工作中,我發現 template
模組特別有用,它可以根據 Jinja2 範本生成設定:
ansible webservers -m template -a "src=templates/nginx.conf.j2 dest=/etc/nginx/nginx.conf" -i inventory
這使得設定管理變得更加靈活,可以根據不同環境的變數生成相應的設定。
套件管理與服務控制
Ansible 可以輕鬆管理各種 Linux 發行版的套件和服務:
# 在 Debian/Ubuntu 系統上安裝套件
ansible webservers -m apt -a "name=nginx state=present update_cache=yes" -i inventory
# 在 RHEL/CentOS 系統上安裝套件
ansible dbservers -m yum -a "name=mariadb-server state=latest" -i inventory
# 管理服務狀態
ansible webservers -m service -a "name=nginx state=started enabled=yes" -i inventory
# 重啟服務
ansible dbservers -m service -a "name=mariadb state=restarted" -i inventory
使用 Ansible 的套件管理模組,可以確保所有系統上安裝的軟體版本一致,減少因版本差異導致的問題。
Ansible Playbook:自動化工作流程的藝術
Playbook 基本結構與語法
Playbook 由一個或多個 play 組成,每個 play 定義要在特定主機上執行的任務集合。以下是一個基本的 Playbook 結構:
---
- name: 安裝並設定 Web 伺服器
hosts: webservers
become: true
vars:
http_port: 80
max_clients: 200
tasks:
- name: 安裝 Nginx
apt:
name: nginx
state: present
update_cache: yes
- name: 佈署 Nginx 設定
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: 重啟 Nginx
- name: 確保 Nginx 服務啟動
service:
name: nginx
state: started
enabled: yes
handlers:
- name: 重啟 Nginx
service:
name: nginx
state: restarted
這個 Playbook 包含了以下元素:
- Play 定義:指定目標主機群組和執行環境
- 變數:定義可在任務中使用的值
- 任務:按順序執行的操作
- 處理程式:僅在被通知時執行的特殊任務
變數、條件與迴圈:增強 Playbook 彈性
變數使 Playbook 更具彈性,可以適應不同環境和需求:
---
- name: 安裝資料函式庫伺服器
hosts: dbservers
become: true
vars:
db_name: myapp
db_user: appuser
db_password: "{{ vault_db_password }}" # 使用 Ansible Vault 加密的變數
tasks:
- name: 安裝 MariaDB
yum:
name:
- mariadb-server
- python3-PyMySQL
state: present
- name: 啟動 MariaDB 服務
service:
name: mariadb
state: started
enabled: yes
- name: 建立資料函式庫
mysql_db:
name: "{{ db_name }}"
state: present
login_unix_socket: /var/lib/mysql/mysql.sock
- name: 建立資料函式庫使用者
mysql_user:
name: "{{ db_user }}"
password: "{{ db_password }}"
priv: "{{ db_name }}.*:ALL"
host: '%'
state: present
login_unix_socket: /var/lib/mysql/mysql.sock
條件陳述式允許根據特定條件執行任務:
- name: 安裝 Web 伺服器
apt:
name: apache2
state: present
when: ansible_distribution == 'Ubuntu'
- name: 安裝 Web 伺服器
yum:
name: httpd
state: present
when: ansible_distribution == 'CentOS'
迴圈可以對多個專案執行相同的任務:
- name: 建立多個使用者
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
shell: /bin/bash
loop:
- { name: 'john', groups: 'admin' }
- { name: 'jane', groups: 'developer' }
- { name: 'bob', groups: 'support' }
在實際工作中,我經常結合使用條件和迴圈來處理不同環境的差異。例如,根據伺服器角色安裝不同的套件,或者根據環境(開發、測試、生產)應用不同的設定。
Handlers:優雅處理設定變更
Handlers 是一種特殊的任務,只有在被通知時才會執行。這對於處理設定變更特別有用,例如只在設定變更時重啟服務:
tasks:
- name: 佈署 Apache 設定
template:
src: templates/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify: 重啟 Apache
- name: 佈署虛擬主機設定
template:
src: templates/vhost.conf.j2
dest: /etc/httpd/conf.d/vhost.conf
notify: 重啟 Apache
handlers:
- name: 重啟 Apache
service:
name: httpd
state: restarted
即使多個任務都通知同一個 handler,該 handler 也只會在 play 結束時執行一次。這避免了不必要的服務重啟,提高了效率和可靠性。
角色 (Roles):模組化 Playbook
隨著 Playbook 變得越來越複雜,將相關任務組織成角色可以提高程式碼的可重用性和可維護性。角色是一種預定義的目錄結構,包含任務、處理程式、變數、檔案和範本:
roles/
webserver/
tasks/
main.yml
handlers/
main.yml
templates/
nginx.conf.j2
files/
index.html
vars/
main.yml
defaults/
main.yml
meta/
main.yml
使用角色的 Playbook 範例:
---
- name: 設定 Web 伺服器
hosts: webservers
become: true
roles:
- common
- webserver
- name: 設定資料函式庫伺服器
hosts: dbservers
become: true
roles:
- common
- database
在我的自動化專案中,我通常會建立以下角色:
- common:適用於所有伺服器的基本設定(安全性、監控、日誌等)
- webserver:Web 伺服器特定設定
- database:資料函式庫伺服器特定設定
- application:應用程式佈署和設定
這種模組化方法使得維護和擴充套件自動化工作流程變得更加容易。
Ansible 模組:自動化工具箱
系統管理模組
這些模組用於管理系統基本功能:
ping 模組
測試目標主機的連線狀態:
- name: 測試連線
ping:
command 和 shell 模組
在遠端主機上執行指令:
- name: 執行簡單指令
command: ls -la /var/log
register: command_output
- name: 使用 shell 特性
shell: find /var/log -name "*.log" | grep error
register: shell_output
- name: 顯示結果
debug:
var: command_output.stdout_lines
command
模組不支援 shell 特性(如管道、重定向),但更安全;shell
模組則支援完整的 shell 功能。
file 模組
管理檔案、目錄和符號連結:
- name: 建立目錄
file:
path: /opt/application
state: directory
mode: '0755'
owner: app
group: app
- name: 建立符號連結
file:
src: /opt/application/current
dest: /var/www/html
state: link
force: yes
- name: 刪除檔案
file:
path: /tmp/temp_file
state: absent
copy 和 template 模組
管理檔案內容:
- name: 複製靜態檔案
copy:
src: files/ntp.conf
dest: /etc/ntp.conf
owner: root
group: root
mode: '0644'
backup: yes
- name: 使用範本生成設定
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
validate: 'nginx -t -c %s'
template
模組使用 Jinja2 範本引擎,可以根據變數生成動態設定。這在管理不同環境的設定時特別有用。
套件管理模組
不同 Linux 發行版使用不同的套件管理系統,Ansible 提供了相應的模組:
apt 模組 (Debian/Ubuntu)
- name: 更新套件快取
apt:
update_cache: yes
cache_valid_time: 3600
- name: 安裝多個套件
apt:
name:
- nginx
- postgresql
- python3-psycopg2
state: present
- name: 移除套件
apt:
name: apache2
state: absent
purge: yes
yum/dnf 模組 (RHEL/CentOS/Fedora)
- name: 安裝最新版本的套件
yum:
name: httpd
state: latest
- name: 從特定儲存函式庫安裝套件
yum:
name: nginx
enablerepo: epel
state: present
- name: 安裝特定版本的套件
dnf:
name: python3-3.9.5
state: present
服務管理模組
service 模組
管理系統服務的狀態:
- name: 啟動服務
service:
name: nginx
state: started
enabled: yes
- name: 重啟服務
service:
name: postgresql
state: restarted
- name: 停止服務
service:
name: httpd
state: stopped
enabled: no
systemd 模組
專門用於管理 systemd 服務:
- name: 啟動並啟用 systemd 服務
systemd:
name: mariadb
state: started
enabled: yes
daemon_reload: yes
- name: 重啟服務並等待完成
systemd:
name: docker
state: restarted
daemon_reload: yes
使用者和群組管理模組
user 模組
管理系統使用者:
- name: 建立使用者
user:
name: deploy
comment: "Deployment User"
shell: /bin/bash
groups: sudo
append: yes
create_home: yes
generate_ssh_key: yes
ssh_key_bits: 4096
- name: 刪除使用者
user:
name: temp_user
state: absent
remove: yes
group 模組
管理系統群組:
- name: 建立群組
group:
name: developers
state: present
gid: 1005
- name: 刪除群組
group:
name: old_group
state: absent
資料函式倉管理模組
Ansible 提供了多種資料函式倉管理模組,例如 mysql_db
、postgresql_db
等:
- name: 確保 MySQL 套件已安裝
apt:
name:
- mysql-server
- python3-mysqldb
state: present
- name: 建立 MySQL 資料函式庫
mysql_db:
name: webapp
state: present
login_unix_socket: /var/run/mysqld/mysqld.sock
- name: 建立資料函式庫使用者
mysql_user:
name: webapp_user
password: "{{ db_password }}"
priv: "webapp.*:ALL"
host: '%'
state: present
login_unix_socket: /var/run/mysqld/mysqld.sock
- name: 匯入資料函式庫結構
mysql_db:
name: webapp
state: import
target: /tmp/schema.sql
login_unix_socket: /var/run/mysqld/mysqld.sock
Ansible 實戰案例:從開發到生產
案例一:自動化 LAMP 堆積積疊佈署
這個案例展示如何使用 Ansible 自動佈署 LAMP (Linux, Apache, MySQL, PHP) 堆積積疊:
---
- name: 佈署 LAMP 堆積積疊
hosts: webservers
become: true
vars:
mysql_root_password: "{{ vault_mysql_root_password }}"
app_db_name: myapp
app_db_user: myapp_user
app_db_password: "{{ vault_app_db_password }}"
tasks:
- name: 更新套件快取
apt:
update_cache: yes
cache_valid_time: 3600
- name: 安裝 LAMP 套件
apt:
name:
- apache2
- mysql-server
- php
- php-mysql
- libapache2-mod-php
- python3-pymysql
state: present
- name: 啟動並啟用 Apache 服務
service:
name: apache2
state: started
enabled: yes
- name: 啟動並啟用 MySQL 服務
service:
name: mysql
state: started
enabled: yes
- name: 設定 MySQL root 密碼
mysql_user:
name: root
password: "{{ mysql_root_password }}"
login_unix_socket: /var/run/mysqld/mysqld.sock
state: present
- name: 建立應用程式資料函式庫
mysql_db:
name: "{{ app_db_name }}"
state: present
login_unix_socket: /var/run/mysqld/mysqld.sock
- name: 建立應用程式資料函式庫使用者
mysql_user:
name: "{{ app_db_user }}"
password: "{{ app_db_password }}"
priv: "{{ app_db_name }}.*:ALL"
host: localhost
state: present
login_unix_socket: /var/run/mysqld/mysqld.sock
- name: 佈署 PHP 測試頁面
copy:
content: |
<?php
phpinfo();
?>
dest: /var/www/html/info.php
owner: www-data
group: www-data
mode: '0644'
- name: 設定 Apache 虛擬主機
template:
src: templates/vhost.conf.j2
dest: /etc/apache2/sites-available/000-default.conf
notify: 重啟 Apache
handlers:
- name: 重啟 Apache
service:
name: apache2
state: restarted
這個 Playbook 完成了以下任務:
- 安裝所有必要的 LAMP 套件
- 設定 MySQL 資料函式庫和使用者
- 佈署測試頁面
- 設定 Apache 虛擬主機
案例二:系統安全強化
這個案例展示如何使用 Ansible 自動化系統安全強化:
---
- name: 系統安全強化
hosts: all
become: true
vars:
ssh_port: 22022
allowed_users:
- admin
- deploy
tasks:
- name: 更新所有套件
apt:
upgrade: dist
update_cache: yes
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian'
- name: 安裝安全相關套件
apt:
name:
- fail2ban
- ufw
- unattended-upgrades
state: present
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian'
- name: 設定自動更新
template:
src: templates/20auto-upgrades.j2
dest: /etc/apt/apt.conf.d/20auto-upgrades
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian'
- name: 設定 SSH 伺服器
template:
src: templates/sshd_config.j2
dest: /etc/ssh/sshd_config
notify: 重啟 SSH 服務
- name: 設定防火牆規則
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- "{{ ssh_port }}"
- 80
- 443
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian'
- name: 啟用防火牆
ufw:
state: enabled
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian'
- name: 設定 fail2ban
template:
src: templates/jail.local.j2
dest: /etc/fail2ban/jail.local
notify: 重啟 fail2ban
- name: 停用 root 登入
user:
name: root
password_lock: yes
- name: 設定密碼策略
lineinfile:
path: /etc/pam.d/common-password
regexp: '^password\s+requisite\s+pam_pwquality.so'
line: 'password requisite pam_pwquality.so retry=3 minlen=12 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 reject_username enforce_for_root'
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian'
handlers:
- name: 重啟 SSH 服務
service:
name: sshd
state: restarted
- name: 重啟 fail2ban
service:
name: fail2ban
state: restarted
這個 Playbook 實作了多項安全強化措施:
- 更新系統套件
- 安裝和設定安全工具(fail2ban、防火牆)
- 強化 SSH 設定
- 設定密碼策略
- 停用 root 登入
案例三:自動化備份與還原
這個案例展示如何使用 Ansible 自動化資料函式庫備份與還原:
---
- name: 資料函式庫備份
hosts: dbservers
become: true
vars:
backup_dir: /var/backups/mysql
remote_backup_server: backup.example.com
remote_backup_user: backup
remote_backup_path: /data/backups
databases:
- name: webapp
tables: all
- name: analytics
tables:
- users
- events
tasks:
- name: 確保備份目錄存在
file:
path: "{{ backup_dir }}"
state: directory
mode: '0750'
owner: mysql
group: mysql
- name: 備份完整資料函式庫
mysql_db:
state: dump
name: "{{ item.name }}"
target: "{{ backup_dir }}/{{ item.name }}_{{ ansible_date_time.date }}.sql"
login_unix_socket: /var/run/mysqld/mysqld.sock
loop: "{{ databases | selectattr('tables', 'equalto', 'all') | list }}"
- name: 備份特定資料表
mysql_db:
state: dump
name: "{{ item.0.name }}"
target: "{{ backup_dir }}/{{ item.0.name }}_{{ item.1 }}_{{ ansible_date_time.date }}.sql"
tables: "{{ item.1 }}"
login_unix_socket: /var/run/mysqld/mysqld.sock
with_subelements:
- "{{ databases | rejectattr('tables', 'equalto', 'all') | list }}"
- tables
- name: 壓縮備份檔案
archive:
path: "{{ backup_dir }}/*.sql"
dest: "{{ backup_dir }}/mysql_backup_{{ ansible_date_time.date }}.tar.gz"
format: gz
remove: yes
- name: 將備份傳輸到遠端伺服器
synchronize:
src: "{{ backup_dir }}/mysql_backup_{{ ansible_date_time.date }}.tar.gz"
dest: "{{ remote_backup_path }}/"
mode: push
delegate_to: "{{ inventory_hostname }}"
- name: 清理舊備份檔案
find:
paths: "{{ backup_dir }}"
patterns: "mysql_backup_*.tar.gz"
age: 7d
register: old_backups
- name: 刪除舊備份檔案
file:
path: "{{ item.path }}"
state: absent
loop: "{{ old_backups.files }}"
這個 Playbook 實作了完整的資料函式庫備份流程:
- 備份指定的資料函式庫或資料表
- 壓縮備份檔案
- 將備份傳輸到遠端備份伺服器
- 自動清理過期的備份檔案
Ansible 進階技巧與最佳實踐
Ansible Vault:安全管理敏感資料
在自動化過程中,我們經常需要處理敏感資料,如密碼、API 金鑰等。Ansible Vault 提供了一種安全的方式來加密這些敏感資訊:
# 建立加密檔案
ansible-vault create secrets.yml
# 編輯加密檔案
ansible-vault edit secrets.yml
# 加密現有檔案
ansible-vault encrypt vars/credentials.yml
# 解密檔案
ansible-vault decrypt vars/credentials.yml
# 檢視加密檔案內容
ansible-vault view secrets.yml
# 修改密碼
ansible-vault rekey secrets.yml
在 Playbook 中使用加密變數:
---
- name: 使用加密變數的範例
hosts: webservers
vars_files:
- vars/secrets.yml
tasks:
- name: 設定資料函式庫連線
template:
src: templates/db_config.j2
dest: /etc/app/db_config.php
vars:
db_host: localhost
db_name: myapp
db_user: "{{ vault_db_user }}"
db_password: "{{ vault_db_password }}"
執行使用加密檔案的 Playbook:
ansible-playbook playbook.yml --ask-vault-pass
# 或使用密碼檔案
ansible-playbook playbook.yml --vault-password-file ~/.vault_pass.txt
在團隊協作中,我通常會將 Vault 密碼儲存在安全的密碼管理系統中,並確保所有團隊成員都能安全地存取它。
動態庫存:管理雲端環境
在雲端環境中,伺服器可能會動態建立和銷毀,手動維護庫存檔案變得不切實際。Ansible 提供了動態庫存功能,可以從雲端提供商或 CMDB 系統取得最新的主機資訊。
以 AWS 為例,首先安裝 boto3 函式庫:
pip install boto3
然後設定 AWS 動態庫存指令碼:
# 下載 AWS 動態庫存指令碼
wget https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/aws_ec2.py
chmod +x aws_ec2.py
# 建立設定
cat > aws_ec2.yml << EOF
---
plugin: aws_ec2
regions:
- ap-northeast-1
keyed_groups:
- key: tags.Role
prefix: role
- key: tags.Environment
prefix: env
filters:
instance-state-name: running
EOF
使用動態庫存執行 Playbook:
ansible-playbook -i aws_ec2.yml playbook.yml
這樣,Ansible 會自動取得 AWS 中所有執行中的 EC2 例項,並根據標籤將它們分組。例如,標記為 Role: webserver
的例項會被分到 role_webserver
組中。
使用 Ansible Galaxy 分享和重用角色
Ansible Galaxy 是一個分享、下載和評價 Ansible 角色的平台。使用 Galaxy 可以避免重複造輪子,利用社群的力量提高自動化效率。
搜尋角色:
ansible-galaxy search nginx
安裝角色:
ansible-galaxy install geerlingguy.nginx
在 Playbook 中使用安裝的角色:
---
- name: 設定 Web 伺服器
hosts: webservers
become: true
roles:
- geerlingguy.nginx
建立自己的角色:
ansible-galaxy init my_custom_role
這會建立一個標準的角色目錄結構,可以根據需要進行自定義。
使用標籤 (Tags) 提高靈活性
標籤允許選擇性地執行 Playbook 中的特定任務,這在處理大型 Playbook 時特別有用:
---
- name: 設定 Web 應用程式
hosts: webservers
become: true
tasks:
- name: 安裝套件
apt:
name:
- nginx
- php-fpm
state: present
tags:
- packages
- nginx
- name: 設定 Nginx
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: 重啟 Nginx
tags:
- config
- nginx
- name: 佈署應用程式
git:
repo: https://github.com/example/webapp.git
dest: /var/www/webapp
version: master
tags:
- deploy
- webapp
handlers:
- name: 重啟 Nginx
service:
name: nginx
state: restarted
tags: nginx
執行特定標記的任務:
# 只執行標記為 nginx 的任務
ansible-playbook playbook.yml --tags nginx
# 執行多個標籤
ansible-playbook playbook.yml --tags "config,deploy"
# 跳過特定標籤
ansible-playbook playbook.yml --skip-tags packages
在大型專案中,我通常會為不同型別的任務設定標籤,如 setup
、config
、deploy
、backup
等,這樣可以根據需要選擇性地執行特定部分。
使用 Ansible 回呼外掛自訂輸出
Ansible 回呼外掛可以自訂任務執行的輸出格式,使結果更易於閱讀和分析:
# ansible.cfg
[defaults]
callback_whitelist = profile_tasks, timer, mail
常用的回呼外掛包括:
- profile_tasks:顯示每個任務的執行時間
- timer:顯示 Playbook 總執行時間
- mail:透過電子郵件傳送執行結果
- slack:將執行結果傳送到 Slack 頻道
在大型佈署中,我經常使用 profile_tasks
外掛來識別耗時的任務,然後針對這些任務進行最佳化。