Ansible 变量管理 #

变量概述 #

Ansible 变量用于存储和管理配置数据,可以在不同位置定义,具有不同的优先级和作用域。

text
┌─────────────────────────────────────────────────────────────┐
│                      变量来源                                │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  命令行          清单文件          Playbook                  │
│  ──────────     ──────────        ──────────                │
│  -e var=value   host_vars        vars:                      │
│                 group_vars       vars_files:                │
│                                                              │
│  Facts          注册变量          魔法变量                   │
│  ──────────     ──────────        ──────────                │
│  ansible_facts  register         inventory_hostname         │
│                 result           hostvars                   │
│                                  groups                     │
│                                                              │
└─────────────────────────────────────────────────────────────┘

变量定义位置 #

1. 命令行变量 #

bash
# 单个变量
ansible-playbook site.yml -e "app_name=myapp"

# 多个变量
ansible-playbook site.yml -e "app_name=myapp app_port=8080"

# 变量文件
ansible-playbook site.yml -e @vars.yml

# JSON 格式
ansible-playbook site.yml -e '{"app_name": "myapp", "app_port": 8080}'

2. Inventory 变量 #

ini
# inventory/hosts

# 主机变量
web1 ansible_host=192.168.1.100 app_port=8080

# 组变量
[webservers:vars]
nginx_port=80
document_root=/var/www/html

# 全局变量
[all:vars]
ansible_python_interpreter=/usr/bin/python3

3. group_vars 和 host_vars #

text
inventory/
├── hosts
├── group_vars/
│   ├── all.yml              # 所有主机的变量
│   ├── webservers.yml       # webservers 组的变量
│   └── databases.yml        # databases 组的变量
└── host_vars/
    ├── web1.yml             # web1 主机的变量
    └── db1.yml              # db1 主机的变量
yaml
# inventory/group_vars/all.yml
---
ntp_servers:
  - 0.pool.ntp.org
  - 1.pool.ntp.org
timezone: UTC

# inventory/group_vars/webservers.yml
---
nginx_port: 80
nginx_worker_processes: auto
document_root: /var/www/html

# inventory/host_vars/web1.yml
---
ansible_host: 192.168.1.100
nginx_server_name: web1.example.com
ssl_enabled: true

4. Playbook 变量 #

yaml
---
- name: Use playbook variables
  hosts: webservers
  
  vars:
    app_name: myapp
    app_port: 8080
  
  vars_files:
    - vars/app.yml
    - vars/secrets.yml
  
  vars_prompt:
    - name: db_password
      prompt: "Enter database password"
      private: yes
  
  tasks:
    - name: Use variables
      debug:
        msg: "App {{ app_name }} on port {{ app_port }}"

5. Role 变量 #

text
roles/
└── nginx/
    ├── defaults/
    │   └── main.yml       # 默认变量(最低优先级)
    └── vars/
        └── main.yml       # 角色变量(较高优先级)
yaml
# roles/nginx/defaults/main.yml
nginx_port: 80
nginx_user: www-data
nginx_worker_processes: auto

# roles/nginx/vars/main.yml
nginx_config_dir: /etc/nginx
nginx_log_dir: /var/log/nginx

变量优先级 #

优先级顺序(从低到高) #

text
1.  role defaults                    (roles/x/defaults/main.yml)
2.  inventory 文件或脚本              (inventory/hosts)
3.  inventory group_vars/all         (inventory/group_vars/all.yml)
4.  inventory group_vars/*           (inventory/group_vars/webservers.yml)
5.  inventory host_vars/*            (inventory/host_vars/web1.yml)
6.  inventory host_vars/*            (inventory/host_vars/web1.yml)
7.  host facts
8.  play vars
9.  play vars_prompt
10. play vars_files
11. role vars                        (roles/x/vars/main.yml)
12. block vars
13. task vars
14. include_vars
15. role (and include_role) params
16. set_facts
17. registered vars
18. extra vars                       (命令行 -e)

优先级示例 #

yaml
# roles/nginx/defaults/main.yml
nginx_port: 80

# inventory/group_vars/webservers.yml
nginx_port: 8080

# site.yml
- hosts: webservers
  vars:
    nginx_port: 9000
  tasks:
    - debug:
        msg: "{{ nginx_port }}"    # 输出 9000

# 使用命令行
ansible-playbook site.yml -e "nginx_port=10080"
# 最终 nginx_port = 10080(最高优先级)

变量类型 #

基本类型 #

yaml
vars:
  # 字符串
  app_name: myapp
  app_path: /var/www/app
  
  # 数字
  app_port: 8080
  max_connections: 100
  
  # 布尔值
  ssl_enabled: true
  debug_mode: false
  
  # 列表
  packages:
    - nginx
    - git
    - curl
  
  # 字典
  database:
    host: localhost
    port: 3306
    name: myapp
    user: appuser

使用变量 #

yaml
tasks:
  # 字符串
  - name: Use string variable
    debug:
      msg: "App name is {{ app_name }}"
  
  # 数字
  - name: Use number variable
    debug:
      msg: "Port is {{ app_port }}"
  
  # 布尔值
  - name: Use boolean variable
    debug:
      msg: "SSL is {{ 'enabled' if ssl_enabled else 'disabled' }}"
  
  # 列表
  - name: Use list variable
    debug:
      msg: "Package: {{ item }}"
    loop: "{{ packages }}"
  
  # 字典
  - name: Use dictionary variable
    debug:
      msg: "Database: {{ database.host }}:{{ database.port }}"
  
  # 字典键访问
  - name: Access dictionary key
    debug:
      msg: "Database name: {{ database['name'] }}"

Facts #

什么是 Facts? #

Facts 是 Ansible 自动收集的被管理节点信息。

yaml
tasks:
  - name: Show all facts
    debug:
      var: ansible_facts

常用 Facts #

yaml
# 系统 Facts
ansible_facts['hostname']              # 主机名
ansible_facts['fqdn']                  # 完全限定域名
ansible_facts['os_family']             # 系统家族 (Debian, RedHat)
ansible_facts['distribution']          # 发行版 (Ubuntu, CentOS)
ansible_facts['distribution_version']  # 版本号
ansible_facts['distribution_major_version']  # 主版本号
ansible_facts['kernel']                # 内核版本

# 网络 Facts
ansible_facts['default_ipv4']['address']  # IPv4 地址
ansible_facts['default_ipv4']['gateway']  # 网关
ansible_facts['default_ipv4']['interface']  # 网络接口
ansible_facts['interfaces']            # 所有网络接口列表

# 硬件 Facts
ansible_facts['memtotal_mb']           # 总内存 (MB)
ansible_facts['processor_cores']       # CPU 核心数
ansible_facts['processor_count']       # CPU 数量
ansible_facts['processor_vcpus']       # 虚拟 CPU 数
ansible_facts['mounts']                # 挂载点信息

# 时间 Facts
ansible_facts['date_time']['date']     # 日期
ansible_facts['date_time']['time']     # 时间
ansible_facts['date_time']['iso8601']  # ISO 格式时间

使用 Facts #

yaml
tasks:
  - name: Install based on OS
    apt:
      name: nginx
      state: present
    when: ansible_facts['os_family'] == "Debian"
  
  - name: Install based on memory
    debug:
      msg: "This server has plenty of RAM"
    when: ansible_facts['memtotal_mb'] > 8192
  
  - name: Configure based on CPU cores
    lineinfile:
      path: /etc/nginx/nginx.conf
      line: "worker_processes {{ ansible_facts['processor_vcpus'] }};"

自定义 Facts #

yaml
# 在被管理节点创建自定义 Facts
# /etc/ansible/facts.d/custom.fact
[general]
role = web
environment = production

# 使用自定义 Facts
tasks:
  - name: Use custom fact
    debug:
      msg: "Server role is {{ ansible_facts['ansible_local']['custom']['general']['role'] }}"

收集特定 Facts #

yaml
- hosts: all
  gather_facts: no    # 禁用自动收集
  
  tasks:
    - name: Gather only network facts
      setup:
        gather_subset:
          - network
      register: network_facts
    
    - name: Gather only hardware facts
      setup:
        gather_subset:
          - hardware
    
    - name: Gather minimal facts
      setup:
        gather_subset:
          - min

注册变量 #

基本使用 #

yaml
tasks:
  - name: Run command
    command: uptime
    register: uptime_result
  
  - name: Show result
    debug:
      msg: "Uptime: {{ uptime_result.stdout }}"
  
  - name: Show all result data
    debug:
      var: uptime_result

注册变量结构 #

yaml
tasks:
  - name: Run command
    command: ls -la /tmp
    register: result
  
  # result 包含:
  # result.stdout      - 标准输出
  # result.stderr      - 标准错误
  # result.rc          - 返回码
  # result.changed     - 是否变更
  # result.failed      - 是否失败
  # result.cmd         - 执行的命令
  # result.start       - 开始时间
  # result.end         - 结束时间
  # result.delta       - 耗时

使用注册变量 #

yaml
tasks:
  - name: Check if file exists
    stat:
      path: /etc/nginx/nginx.conf
    register: file_stat
  
  - name: Backup file if exists
    copy:
      src: /etc/nginx/nginx.conf
      dest: /etc/nginx/nginx.conf.bak
    when: file_stat.stat.exists
  
  - name: Check service status
    command: systemctl is-active nginx
    register: service_status
    changed_when: false
    failed_when: false
  
  - name: Start service if not running
    service:
      name: nginx
      state: started
    when: service_status.rc != 0

循环中的注册变量 #

yaml
tasks:
  - name: Loop with register
    command: "echo {{ item }}"
    loop:
      - one
      - two
      - three
    register: loop_result
  
  - name: Show loop results
    debug:
      msg: "{{ item.stdout }}"
    loop: "{{ loop_result.results }}"

魔法变量 #

inventory_hostname #

yaml
tasks:
  - name: Show inventory hostname
    debug:
      msg: "Inventory hostname: {{ inventory_hostname }}"
  
  - name: Show inventory hostname short
    debug:
      msg: "Short name: {{ inventory_hostname_short }}"

hostvars #

访问其他主机的变量:

yaml
tasks:
  - name: Access another host's variables
    debug:
      msg: "web1 IP: {{ hostvars['web1']['ansible_facts']['default_ipv4']['address'] }}"
  
  - name: Access all hosts
    debug:
      msg: "Host: {{ item }}"
    loop: "{{ groups['all'] }}"
  
  - name: Get first web server IP
    debug:
      msg: "First web server: {{ hostvars[groups['webservers'][0]]['ansible_facts']['default_ipv4']['address'] }}"

groups #

yaml
tasks:
  - name: Show all groups
    debug:
      var: groups
  
  - name: Show webservers group
    debug:
      msg: "Webservers: {{ groups['webservers'] }}"
  
  - name: Loop through group
    debug:
      msg: "Host: {{ item }}"
    loop: "{{ groups['webservers'] }}"

group_names #

yaml
tasks:
  - name: Show groups this host belongs to
    debug:
      msg: "{{ inventory_hostname }} is in groups: {{ group_names }}"
  
  - name: Check if in production group
    debug:
      msg: "This is a production server"
    when: "'production' in group_names"

play_hosts / ansible_play_hosts #

yaml
tasks:
  - name: Show hosts in current play
    debug:
      msg: "Play hosts: {{ ansible_play_hosts }}"
  
  - name: Show hosts that succeeded
    debug:
      msg: "Successful hosts: {{ ansible_play_hosts_all_success }}"

其他魔法变量 #

yaml
tasks:
  # Playbook 目录
  - name: Show playbook directory
    debug:
      msg: "Playbook dir: {{ playbook_dir }}"
  
  # Inventory 目录
  - name: Show inventory directory
    debug:
      msg: "Inventory dir: {{ inventory_dir }}"
  
  # Ansible 版本
  - name: Show Ansible version
    debug:
      msg: "Ansible version: {{ ansible_version }}"
  
  # 角色名称
  - name: Show role name
    debug:
      msg: "Role: {{ role_name }}"
    when: role_name is defined

变量过滤器 #

字符串过滤器 #

yaml
vars:
  my_string: "Hello World"

tasks:
  - debug:
      msg: "{{ my_string | upper }}"           # HELLO WORLD
  - debug:
      msg: "{{ my_string | lower }}"           # hello world
  - debug:
      msg: "{{ my_string | capitalize }}"      # Hello world
  - debug:
      msg: "{{ my_string | replace('World', 'Ansible') }}"  # Hello Ansible
  - debug:
      msg: "{{ my_string | split(' ') }}"      # ['Hello', 'World']
  - debug:
      msg: "{{ my_string | truncate(5) }}"     # He...

列表过滤器 #

yaml
vars:
  my_list:
    - 1
    - 2
    - 3
    - 4
    - 5

tasks:
  - debug:
      msg: "{{ my_list | min }}"               # 1
  - debug:
      msg: "{{ my_list | max }}"               # 5
  - debug:
      msg: "{{ my_list | sum }}"               # 15
  - debug:
      msg: "{{ my_list | join(',') }}"         # 1,2,3,4,5
  - debug:
      msg: "{{ my_list | first }}"             # 1
  - debug:
      msg: "{{ my_list | last }}"              # 5
  - debug:
      msg: "{{ my_list | length }}"            # 5
  - debug:
      msg: "{{ my_list | random }}"            # 随机元素

字典过滤器 #

yaml
vars:
  my_dict:
    name: John
    age: 30
    city: Beijing

tasks:
  - debug:
      msg: "{{ my_dict | dict2items }}"        # 转换为列表
  - debug:
      msg: "{{ my_dict.keys() | list }}"       # 键列表
  - debug:
      msg: "{{ my_dict.values() | list }}"     # 值列表

类型转换 #

yaml
vars:
  number: 100
  string: "200"

tasks:
  - debug:
      msg: "{{ number | string }}"             # "100"
  - debug:
      msg: "{{ string | int }}"                # 200
  - debug:
      msg: "{{ string | float }}"              # 200.0
  - debug:
      msg: "{{ number | to_json }}"            # JSON 字符串
  - debug:
      msg: "{{ number | to_yaml }}"            # YAML 字符串

默认值 #

yaml
vars:
  defined_var: "value"
  # undefined_var 未定义

tasks:
  - debug:
      msg: "{{ defined_var | default('default') }}"      # value
  - debug:
      msg: "{{ undefined_var | default('default') }}"    # default
  - debug:
      msg: "{{ undefined_var | default(omit) }}"         # 省略参数

set_fact 和 include_vars #

set_fact #

动态设置变量:

yaml
tasks:
  - name: Set a fact
    set_fact:
      app_version: "1.0.0"
      app_config:
        port: 8080
        debug: false
  
  - name: Use the fact
    debug:
      msg: "Version: {{ app_version }}"
  
  - name: Set fact from command
    shell: cat /etc/os-release | grep VERSION_ID | cut -d'"' -f2
    register: os_version
  
  - name: Set fact from result
    set_fact:
      os_version: "{{ os_version.stdout }}"

include_vars #

动态加载变量文件:

yaml
tasks:
  - name: Load variables
    include_vars:
      file: vars/{{ environment }}.yml
      name: env_vars
  
  - name: Use loaded variables
    debug:
      msg: "DB Host: {{ env_vars.db_host }}"
  
  - name: Load all vars from directory
    include_vars:
      dir: vars/
      extensions: ['yml', 'yaml']

变量最佳实践 #

1. 使用有意义的变量名 #

yaml
# 好的命名
app_name: myapp
nginx_port: 80
database_host: localhost

# 不好的命名
n: myapp
p: 80
h: localhost

2. 分离敏感变量 #

yaml
# 使用 Vault 加密敏感变量
# vars/secrets.yml (加密)
db_password: "{{ vault_db_password }}"
api_key: "{{ vault_api_key }}"

3. 使用默认值 #

yaml
# roles/nginx/defaults/main.yml
nginx_port: 80
nginx_user: www-data
nginx_worker_processes: auto

4. 组织变量文件 #

text
inventory/
├── group_vars/
│   ├── all.yml           # 全局变量
│   ├── webservers.yml    # Web 服务器变量
│   └── databases.yml     # 数据库变量
└── host_vars/
    ├── web1.yml          # 特定主机变量
    └── db1.yml

5. 文档化变量 #

yaml
# vars/app.yml
---
# Application Configuration
# Author: DevOps Team
# Updated: 2024-01-15

app:
  name: myapp                    # Application name
  version: 1.0.0                 # Application version
  port: 8080                     # Application port
  debug: false                   # Debug mode (set to true in development)

database:
  host: localhost                # Database host
  port: 3306                     # Database port
  name: "{{ app.name }}_db"      # Database name
  user: "{{ app.name }}"         # Database user
  password: "{{ vault_db_password }}"  # Database password (encrypted)

下一步 #

现在你已经掌握了变量管理,接下来学习 Jinja2 模板 了解如何使用模板生成配置文件!

最后更新:2026-03-29