iT邦幫忙

2025 iThome 鐵人賽

DAY 7
0
DevOps

不爆肝學習 Ansible 的短暫30天系列 第 7

Day07 – 用變數讓 Playbook 更聰明

  • 分享至 

  • xImage
  •  

今日目標

  • 了解變數的用途
  • 在 Inventory 中設定變數
  • 在 Playbook 中引用變數

為什麼會需要用變數?

如果你今天要讓 A 機器安裝 htop,B 機器安裝 btop,當然你可以用 host 或是兩份 Playbook 去做到,但如果今天有變數的話,就可以更靈活的去操作任務。

Inventory 設定變數

[web-a]
192.168.56.101

[web-b]
192.168.56.102

[web-a:vars]
package_name=htop

[web-b:vars]
package_name=btop

YAML 形式設定變數

web:
  hosts:
    web-a:
      ansible_host: 192.168.56.101
      package_name: htop
    web-b:
      ansible_host: 192.168.56.102
      package_name: btop

把剛剛的 Playbook 拿來用

---
- name: Install custom package on all servers
  hosts: all
  become: yes
  tasks:
    - name: Install custom package
      package:
        name: "{{ package_name }}"
        state: present

更多變數使用範例

1. 在 Playbook 中定義變數

---
- 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 }};"

2. 使用外部變數檔案

建立 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 }}"

3. 使用 group_vars 和 host_vars

目錄結構:

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 中變數有明確的優先順序,數字越大優先級越高:

  1. group_vars/all - 最低優先級
  2. group_vars/group_name - 群組變數
  3. host_vars/hostname - 主機特定變數
  4. inventory file - inventory 檔案中的變數
  5. playbook vars - playbook 中 vars 區塊的變數
  6. vars_files - 外部變數檔案
  7. task vars - task 層級的變數
  8. command line (-e) - 最高優先級

範例:

# 命令列變數會覆蓋所有其他設定
ansible-playbook site.yml -e "package_name=vim"

💡Tips

變數放置位置選擇建議:

  • inventory: 適合主機或群組的基本設定
  • group_vars/: 適合群組共用設定,便於管理
  • host_vars/: 適合單一主機的特殊設定
  • playbook vars: 適合該 playbook 特有的變數
  • vars_files: 適合複雜的設定檔案,可重複使用
  • command line (-e): 適合覆蓋設定或測試用途

變數命名最佳實務:

  • 使用有意義的變數名稱: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

作業練習時間

作業 1:透過變數試著安裝其他 package

修改 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

作業 2:使用 -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"

作業 3:進階練習

建立一個更複雜的 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 做到更靈活的任務執行!


上一篇
Day06 – 第一個 Playbook:安裝 btop
系列文
不爆肝學習 Ansible 的短暫30天7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言