Ansible 使用变量

Ansible 使用变量

Ansible 可以通过变量来提高 Playbook 的编写效率。例如:通过 Ansible 安装软件包,可以将软件包写入到一个变量,然后在 Playbook 中调用变量,这样在修改需要安装的软件包时,不需要修改 Playbook,只需要修改变量的值就可以。

Ansible 也有一些自带的变量。可以看后边的事实变量和魔法变量。

设置变量

设置变量有多种方式,最简单的是在 Playbook 上设置:

- name: var
  hosts: all
  vars:
    list_var:
    - servera
    - serverb
    dict_var:
      servera_info:
        username: root
        password: redhat
      serverb_info:
        username: admin
        password: redhat

list_var 是列表变量,dict_var 是字典变量。

上边是设置全局变量,也可以在单个 tasks 下设置:

- name: print var
  ansible.builtin.debug:
    var: test_var
  vars:
    test_var: "Hello World!"

也可以用文件设置,假设 Playbook 所在目录有一个文件 vars/vars.yml

- name: var
  hosts: all
  vars_files:
  - vars/vars.yml

vars/vars.yml 文件内容:

list_var2:
- var1
- var2
dict_var2:
  ssh_username: root
  ssh_password: redhat

也可以在命令行设置变量:

[root@study ansible]# ansible localhost -m debug -a 'var=username' \
    --extra-vars '{"username":"root","password":"redhat"}'
localhost | SUCCESS => {
    "username": "root"
}

# 如果变量涉及很多特殊符号,建议通过文件设置并引用
[root@study ansible]# cat vars/vars.yml
list_var2:
- var1
- var2
dict_var2:
  ssh_username: root
  ssh_password: redhat
[root@study ansible]# ansible localhost -m debug -a 'var=list_var2' \
    -e '@vars/vars.yml'
localhost | SUCCESS => {
    "list_var2": [
        "var1",
        "var2"
    ]
}

引用变量

在 Playbook 中使用变量

引用变量只需要用 { } 将变量扩起来,以下是利用已有变量设置新变量的 Playbook:

vars:
  list_var:
  - servera
  - serverb
  dict_var:
    servera_info:
      username: root
      password: redhat
    serverb_info:
      username: admin
      password: redhat
  servera_ssh_info: "username: {{ dict_var.servera_info.username }}, password: {{ dict_var.servera_info.password }}"

打印变量

可以通过 ansible.builtin.debug 打印变量:

tasks:
- name: print var
  ansible.builtin.debug:
    var: list_var[1]
- name: print var
  ansible.builtin.debug:
    var: dict_var['servera_info']

list_var[1] 是打印列表变量的第二项,dict_var['servera_info'] 打印 dict_var 变量中 KEYservera_info 的字典变量。

字典变量引用的时候支持嵌套变量,dict_var['servera_info'] 里的单引号表示 server_info 是一个普通字符串。如果不加单引号(dict_var[servera_info]),servera_info 表示一个变量名,实际引用的是会有所区别,详见下边示例。

这是一个变量嵌套的例子:

- name: var
  hosts: all
  gather_facts: false
  vars:
    servera_info: servera
    dict_var:
      servera:
        username: redhat
        password: redhat
  tasks:
  - name: print var
    ansible.builtin.debug:
      var: dict_var[servera_info]

servera_info 的值是 servera,然后通过 dict_var[servera_info] 获取 dict_var['servera'] 变量的值。

注册变量

和设置变量不同,注册变量是将模块的执行结果注册到一个变量中,以便后续引用。

注册变量使用 register

下边是一个注册变量的例子:

- name: register
  hosts: localhost
  gather_facts: false
  tasks:
  - name: register
    ansible.builtin.command: ls /tmp
    register: get_tmp
    changed_when: false
  - name: print register var
    ansible.builtin.debug:
      var: get_tmp
  - name: if testfile not in /tmp, create /tmp/testfile
    ansible.builtin.file:
      path: /tmp/testfile
      state: touch
    when: "'testfile' not in get_tmp.stdout_lines"

这个 Playbook 的第一个 tasks 会在被控节点执行 ls /tmp,并将结果注册到名为 get_tmp 的变量中,第二个 tasks 可以输出 get_tmp 变量的内容,第三个 tasks 回去判断 /tmp 下是否有 testfile 文件,如果没有就创建,有就跳过这个 tasks

通过 Jinja2 引用变量

Jinja2 是一个 Python 的模板引擎,用于在文本中插入动态内容,最常用于 生成 HTML、配置文件、YAML、Shell 脚本等。它常用于跟 ansible.builtin.template 配合。

举个例子,配置 HTTP 服务器。如果 HTTP 服务器只是单节点提供服务,那么监听端口就是 80 端口,如果是多节点做负载均衡,那么监听端口设置为 8080,如果都不符合就使用 8443。如果使用 Jinja2 的话就可以写一个判断,内容如下(片段):

{% if NODE_TYPE == 'SINGLE' %}
Listen 80
{% elif NODE_TYPE == 'LOAD_BALANCING' %}
Listen 8080
{% else %}
Listen 8443
{% endif %}

这里的 NODE_TYPE 是个变量,需要在主机清单或者 Playbook 里设置。

上边使用的是判断,Jinja2 还支持循环和变量。下边写一个循环的例子:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

{% for host in groups['all'] %}
{{ hostvars[host]['ansible_ssh_host'] }}        {{ hostvars[host]['ansible_facts']['fqdn'] }}   {{ hostvars[host]['ansible_facts']['hostname'] }}
{% endfor %}

这里边不光使用了循环,还是用了变量,Jinja2 支持使用 Ansible 的事实变量、魔法变量和自定义变量。

上边这个 Jinja2 文件复制过去实现的效果如下:

[root@ansible-controller ansible-navigator]# cat templates/hosts.j2
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

{% for host in groups['all'] %}
{{ hostvars[host]['ansible_ssh_host'] }}        {{ hostvars[host]['ansible_facts']['fqdn'] }}   {{ hostvars[host]['ansible_facts']['hostname'] }}
{% endfor %}

[root@ansible-controller ansible-navigator]# cat template.yml
---
- name: template
  hosts: all
  tasks:
  - name: template
    ansible.builtin.template:
      src: ./templates/hosts.j2
      dest: /etc/hosts

[root@ansible-controller ansible-navigator]# ansible-navigator run --ep template.yml -- -b -K
BECOME password:
...outpu omitted...

[root@ansible-controller ansible-navigator]# ansible-navigator exec -- ansible all -m command -a 'cat /etc/hosts'
master1 | CHANGED | rc=0 >>
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.221.142 master1.example.com     master1
192.168.221.143 worker1.example.com     worker1
worker1 | CHANGED | rc=0 >>
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.221.142 master1.example.com     master1
192.168.221.143 worker1.example.com     worker1

创建 Jinja2 文件时,建议结尾使用 .j2 后缀。(如 hosts.j2

Ansible 事实变量

查看 Ansible 事实变量

Ansible 可以收集被控主机的信息并将其注册为事实变量,变量名为 ansible_facts ,可以通过 ansible.builtin.debug 模块打印被控主机的事实变量:

- name: Print all available facts
  ansible.builtin.debug:
    var: ansible_facts

Ansible 事实变量能够查看很多信息:

  • 硬件:CPU、内存、主板等
  • 软件:地址、主机名、文件系统挂载等

Ansible 事实变量输出参考:https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_vars_facts.html#ansible-facts

除了通过 ansible_facts 获取事实变量以外,还可以通过 hostvars['servera']['ansible_facts'] 的方式获取特定主机的事实变量。

这个方法只能在 Playbook 中使用。

缓存 Ansible 事实变量

Ansible 默认在执行 Playbook 时收集事实变量并保存在内存中,Playbook 执行结束后清理收集的事实变量,可以将变量缓存到一个文件或特定数据库中,这里介绍两种缓存方式:

  • 缓存到文件
  • 缓存到 Redis

缓存到文件

修改 Ansible 配置文件的如下几行

# (string) Chooses which cache plugin to use, the default 'memory' is ephemeral.
fact_caching=jsonfile

# (string) Defines connection or path information for the cache plugin.
fact_caching_connection=./cache

# (string) Prefix to use for cache plugin files/tables.
fact_caching_prefix=ansible_facts_

# (integer) Expiration timeout for the cache plugin data.
fact_caching_timeout=86400

这几行表示将事实变量以 JSON 的方式缓存到文件中,文件保存到 ./cache 目录中,文件名以 ansible_facts_ 为前缀,缓存有效时间 86400 秒。

这里说下缓存过期,如果是缓存到文件,Ansible 在执行 Playbook 的时候会去判断缓存是否在有效期内,不在有效期内就不会使用缓存。

测试缓存:

[root@study ansible]# ls cache/
ls: cannot access 'cache/': No such file or directory
[root@study ansible]# ansible localhost -m setup &> /dev/null
[root@study ansible]# ls cache/
ansible_facts_localhost
[root@study ansible]# cat ansible_facts_cache.yml
- name: test ansible facts cache
  hosts: localhost
  gather_facts: false
  tasks:
  - name: Print ansible facts
    ansible.builtin.debug:
      var: ansible_facts['hostname']
[root@study ansible]# ansible-playbook ansible_facts_cache.yml

PLAY [test ansible facts cache] ***********************************************************************************************************************************

TASK [Print ansible facts] ****************************************************************************************************************************************
ok: [localhost] => {
    "ansible_facts['hostname']": "study"
}

PLAY RECAP ********************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

缓存到 Redis

要将事实变量缓存到 Redis 需要安装 community.general 集合,执行 ansible-galaxy collection install community.general 安装集合。

查看新装的缓存插件:

[root@study ansible]# ansible-doc -t cache -l
ansible.builtin.jsonfile    JSON formatted files
ansible.builtin.memory      RAM backed, non persistent
community.general.memcached Use memcached DB for cache
community.general.pickle    Pickle formatted files
community.general.redis     Use Redis DB for cache
community.general.yaml      YAML formatted files

安装并启动 Redis:

# 安装 Redis
[root@study ansible]# dnf install -y redis

# 启动 Redis
[root@study ansible]# systemctl start redis
[root@study ansible]# ss -ntlp | grep 6379
LISTEN 0      511        127.0.0.1:6379       0.0.0.0:*    users:(("redis-server",pid=45313,fd=6))

# 检查 Redis 数据
[root@study ansible]# redis-cli
127.0.0.1:6379> KEYS *
(empty list or set)
127.0.0.1:6379> exit

谨慎使用 KEYS *

修改 Ansible 配置文件:

# (string) Chooses which cache plugin to use, the default 'memory' is ephemeral.
fact_caching=redis

# (string) Defines connection or path information for the cache plugin.
fact_caching_connection=127.0.0.1:6379:0

# (string) Prefix to use for cache plugin files/tables.
fact_caching_prefix=ansible_facts_

# (integer) Expiration timeout for the cache plugin data.
fact_caching_timeout=86400

这里到期的话 Redis 里的信息就会删除。

收集事实变量,检查缓存:

[root@study ansible]# ansible localhost -m setup &> /dev/null
[root@study ansible]# redis-cli
127.0.0.1:6379> KEYS *
1) "ansible_facts_localhost"
2) "ansible_cache_keys"
127.0.0.1:6379> exit
[root@study ansible]#

这里多说一下,因为 Redis 可以设置密码,也支持加密,所以 fact_caching_connection 的配置可以去查看 community.general.redis 的帮助文档:

[root@study ansible]# ansible-doc -t cache community.general.redis
...output omitted...
= _uri
        A colon separated string of connection information for Redis.
        The format is `host:port:db:password', for example `localhost:6379:0:changeme'.
        To use encryption in transit, prefix the connection with `tls://', as in `tls://localhost:6379:0:changeme'.
        To use redis sentinel, use separator `;', for example `localhost:26379;localhost:26379;0:changeme'. Requires redis>=2.9.0.
        set_via:
          env:
          - name: ANSIBLE_CACHE_PLUGIN_CONNECTION
          ini:
          - key: fact_caching_connection
            section: defaults
        type: string

禁用 Ansible 事实变量

Ansible 在执行 Playbook 时默认收集事实变量,如果明确不使用事实变量,可以通过 gather_facts: false 禁用事实变量收集来提高执行效率。

- hosts: whatever
  gather_facts: false

添加自定义事实

在被控节点的 /etc/ansible/facts.d 目录下可以添加自定义事实变量。

下边是自定义变量的定义和查看:

[root@study ansible]# cat /etc/ansible/facts.d/local_var.fact
[webserver_vars]
linux = true
webserver_port = 80
dbserver_port = 3306
[root@study ansible]# ansible localhost -m setup -a 'filter=ansible_local'
localhost | SUCCESS => {
    "ansible_facts": {
        "ansible_local": {
            "local_var": {
                "webserver_vars": {
                    "dbserver_port": "3306",
                    "linux": "true",
                    "webserver_port": "80"
                }
            }
        }
    },
    "changed": false
}

local_varwebserver_varswebserver_port 都对应不同的 KEY 的名字。

下边是调用本地事实的方式:

- name: Print custom facts
  ansible.builtin.debug:
    var: ansible_facts.ansible_local

事实变量的 KEY 会将大写的 KEY 名转化成小写的,比方说 WebServer_Port = 80 会转化成 webserver_port = 80

Ansible 魔法变量

调用魔法变量

和事实变量不同,魔法变量不需要去被控主机收集信息,它主要有两个来源:

  • 通过主机清单设置的变量,变量可以是设置的新变量(就是在主机清单中添加的自定义变量),也可以是 Anisble 的内置变量(连接变量:ansible_ssh_useransible_ssh_password
  • Playbook 执行过程中附加的变量

以下是一些常用魔法变量:

  • hostvars
  • groups
  • group_names
  • inventory_hostname

上边这几个变量其实都包含在 hostvars,可以用 ansible.builtin.debug 模块查看(ansible localhost -m debug -a 'var=hostvars'

以下是一些魔法变量的使用方法:

获取特定主机的变量信息

{{ hostvars['test.example.com']['ansible_facts']['distribution'] }}

循环主机组

{% for host in groups['app_servers'] %}
   {{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }}
{% endfor %}

判断主机 servera 在 webserver 组内

{% if 'servera' in groups['webserver'] %}
   {{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }}
{% endif %}

除了 hostvars 看到的变量之外,还有如下几个变量:

  • ansible_play_hosts
  • ansible_play_batch
  • role_path(包含当前角色的路径名,并且仅在角色内工作。)

调用魔法变量的案例

现在假设有一批主机(主机名和 IP 地址已配置,IP 地址统一配置在 eth0 网卡),那么就可以通过如下 Playbook 配置 /etc/hosts 文件:

[root@study ansible]# cat set_hosts.yml
- name: set all hosts
  hosts: all
  gather_facts: true
  tasks:
  - name: Configure the hosts file with the template
    ansible.builtin.template:
      src: ./templates/hosts.j2
      dest: /etc/hosts
      owner: root
      group: root
      mode: '0644'

[root@study ansible]# cat templates/hosts.j2
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

{% for host in groups['all'] %}
{{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }}        {{ hostvars[host]['ansible_facts']['hostname'] }}
{% endfor %}

这个是通过 JinJa2 模板和 ansible.builtin.template 模块来配置 /etc/hosts

  1. ./templates/hosts.j2 文件是 JinJa2 模板,它循环 all 主机组,将组内所有主机 eth0 网卡的 IP 地址和主机名按行打印出来
  2. 然后 Ansible 通过 ansible.builtin.template 模块来调用这个 JinJa2 模板对 all 主机组执行。
Ansible 使用变量
https://www.linuxstudynotes.com/2025/07/16/ansible/ansible-%e4%bd%bf%e7%94%a8%e5%8f%98%e9%87%8f/
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇