如果你今天要讓 A 機器安裝 htop,B 機器安裝 btop,當然你可以用 host 或是兩份 Playbook 去做到,但如果今天有變數的話,就可以更靈活的去操作任務。
[web-a]
192.168.56.101
[web-b]
192.168.56.102
[web-a:vars]
package_name=htop
[web-b:vars]
package_name=btop
web:
hosts:
web-a:
ansible_host: 192.168.56.101
package_name: htop
web-b:
ansible_host: 192.168.56.102
package_name: btop
---
- name: Install custom package on all servers
hosts: all
become: yes
tasks:
- name: Install custom package
package:
name: "{{ package_name }}"
state: present
---
- name: Configure web servers
hosts: web
become: yes
vars:
web_port: 80
web_user: www-data
config_path: /etc/nginx/sites-available/default
tasks:
- name: Create web user
user:
name: "{{ web_user }}"
system: yes
- name: Configure nginx port
lineinfile:
path: "{{ config_path }}"
regexp: 'listen'
line: " listen {{ web_port }};"
建立 vars.yml
:
# vars.yml
database:
host: localhost
port: 5432
name: myapp
user: dbuser
app:
version: "1.2.3"
environment: production
在 Playbook 中引用:
---
- name: Deploy application
hosts: app_servers
vars_files:
- vars.yml
tasks:
- name: Configure database connection
template:
src: config.j2
dest: /opt/app/config.yml
vars:
db_host: "{{ database.host }}"
db_port: "{{ database.port }}"
目錄結構:
inventory/
├── hosts
├── group_vars/
│ ├── web.yml
│ └── db.yml
└── host_vars/
├── web1.yml
└── db1.yml
group_vars/web.yml
:
nginx_version: "1.20"
ssl_enabled: true
max_connections: 1024
host_vars/web1.yml
:
server_id: 1
memory_limit: "2G"
Ansible 中變數有明確的優先順序,數字越大優先級越高:
範例:
# 命令列變數會覆蓋所有其他設定
ansible-playbook site.yml -e "package_name=vim"
web_port
而非 port
package_name
而非 packagename
nginx_version
, mysql_root_password
# 使用 Ansible Vault 加密敏感變數
ansible-vault create group_vars/db/vault.yml
ansible-vault edit group_vars/db/vault.yml
# 執行時提供密碼
ansible-playbook site.yml --ask-vault-pass
修改 inventory 檔案,為不同主機設定不同的套件:
[web-servers]
192.168.56.101 package_name=nginx
192.168.56.102 package_name=apache2
[monitoring]
192.168.56.103 package_name=htop
執行安裝:
ansible-playbook -i inventory install-package.yml
-e
去覆蓋變數值測試變數優先順序:
# 安裝 vim(會覆蓋 inventory 中的設定)
ansible-playbook -i inventory install-package.yml -e "package_name=vim"
# 批次安裝多個套件
ansible-playbook -i inventory install-package.yml -e "package_name=curl,wget,git"
建立一個更複雜的 playbook,使用條件判斷:
---
- name: Install packages based on OS
hosts: all
become: yes
vars:
packages:
Ubuntu: [vim, htop, curl]
CentOS: [vim, htop, curl, yum-utils]
tasks:
- name: Install packages on Ubuntu
package:
name: "{{ packages.Ubuntu }}"
state: present
when: ansible_distribution == "Ubuntu"
- name: Install packages on CentOS
package:
name: "{{ packages.CentOS }}"
state: present
when: ansible_distribution == "CentOS"
1. 變數未定義錯誤
TASK [Install package] *********************************************************
fatal: [192.168.56.101]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'package_name' is undefined"}
解決方案:
default
過濾器:{{ package_name | default('vim') }}
2. 變數格式錯誤
# 錯誤:缺少引號
- debug: msg={{ message }}
# 正確:變數需要引號
- debug: msg="{{ message }}"
3. 變數作用域問題
檢查變數值的實用指令:
# 檢視主機的所有變數
ansible -i inventory hostname -m setup
# 檢視特定變數
ansible -i inventory hostname -m debug -a "var=package_name"
# 列出所有變數(包含預設系統變數)
ansible -i inventory hostname -m debug -a "var=hostvars[inventory_hostname]"
4. YAML 語法錯誤
# 檢查 YAML 語法
ansible-playbook --syntax-check playbook.yml
# 執行 dry-run mode 檢查
ansible-playbook --check playbook.yml
明天我們來玩玩怎麼使用 when 加上 loop 做到更靈活的任務執行!