ansible学习之旅(facts变量)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: ansible学习之旅(facts变量)

Ansible Register

Register简介

register 可以将 task 执行的任务结果存储至某个变量中,便于后续的引用


Register场景示例

使用 Register 获取被控节点的端口信息

正常在playbook中执行shell是不会有结果输出的  

[root@k81 an]# cat register1.yaml 
---
- hosts: centos
  tasks:
  - name: Get port listen info
    shell: netstat -lntp 
    register: Ports
  - name: Debug
    debug:
      msg:    # 下面是将变量格式化一下,否则会输出很多东西很乱
      - "执行的命令为: {{ Ports.cmd }}" 
      - "输出的结果为: "
      - " {{ Ports.stdout_lines }}"
## 测试
[root@k81 an]# ansible-playbook register1.yaml
......
TASK [Get port listen info] **************************************************************************************************
changed: [c2]
changed: [c1]
TASK [Debug] *****************************************************************************************************************
ok: [c1] => {
    "msg": [
        "执行的命令为: netstat -lntp", 
        "输出的结果为: ", 
        " [u'Active Internet connections (only servers)', u'Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    ', u'tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      630/rpcbind         ', u'tcp        0      0 192.168.122.1:53        0.0.0.0:*               LISTEN      1628/dnsmasq        ', u'tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1471/sshd           ', u'tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      1024/cupsd          ', u'tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1256/master         ', u'tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN      1029/zabbix_agentd  ', u'tcp6       0      0 :::111                  :::*                    LISTEN      630/rpcbind         ', u'tcp6       0      0 :::22                   :::*                    LISTEN      1471/sshd           ', u'tcp6       0      0 ::1:631                 :::*                    LISTEN      1024/cupsd          ', u'tcp6       0      0 ::1:25                  :::*                    LISTEN      1256/master         ']"
    ]
}
ok: [c2] => {
    "msg": [
        "执行的命令为: netstat -lntp", 
        "输出的结果为: ", 
        " [u'Active Internet connections (only servers)', u'Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    ', u'tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN      1032/zabbix_agentd  ', u'tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      642/rpcbind         ', u'tcp        0      0 192.168.122.1:53        0.0.0.0:*               LISTEN      1630/dnsmasq        ', u'tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1488/sshd           ', u'tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      1026/cupsd          ', u'tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1273/master         ', u'tcp6       0      0 :::111                  :::*                    LISTEN      642/rpcbind         ', u'tcp6       0      0 :::22                   :::*                    LISTEN      1488/sshd           ', u'tcp6       0      0 ::1:631                 :::*                    LISTEN      1026/cupsd          ', u'tcp6       0      0 ::1:25                  :::*                    LISTEN      1273/master         ']"
    ]
}


批量修改随机200台主机名称

[root@k81 an]# cat register2.yaml 
---
- hosts: all
  tasks:
  - name: define random
    shell: echo $RANDOM |md5sum |cut -c 2-5
    register: HOSTNAME
  - name: check vars
    debug: msg="{{ HOSTNAME }}"
  - name: change hostname 
    hostname: name="host-{{ HOSTNAME.stdout }}"
## 测试
[root@k81 an]# ansible-playbook register2.yaml 
## 查看结果
[root@k81 an]# ansible centos -m shell -a 'hostname '
c1 | CHANGED | rc=0 >>
host-0a79
c2 | CHANGED | rc=0 >>
host-9d33


使用 register 关键字完成某些tocken的创建

[root@k81 an]# cat register3.yaml 
#比如k8s中生成token.csv
#[root@k8s-master ~]# head -c 16 /dev/urandom | od -An -t x | tr -d ' '
#b870778a2a9e4175d09af21a83c8963a
---
- hosts: c1
  tasks:
  - name: Output token.csv
    shell: head -c 16 /dev/urandom | od -An -t x | tr -d ' '
    register: urandom_str
  - name: check token.csv
    debug: msg={{ urandom_str.stdout }}
## 测试
[root@k81 an]# ansible-playbook register3.yaml
......
TASK [check token.csv] **********************************************************************************************************************************************************************************************
ok: [c1] => {
    "msg": "9659bcaf9f0a4aeb45c7ce77f590f892"
}
PLAY RECAP **********************************************************************************************************************************************************************************************************
c1                         : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
......  


Ansible FactsVariables

facts介绍

Ansible facts 变量主要用来自动采集被控端主机自身的状态信息。

比如:被动端的,主机名、IP地址、系统版本、CPU数量、内存状态、磁盘状态等等。

默认每次执行playbook都会有如下task  

PLAY [centos] *******************************************************************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************************************************************
ok: [c2]
ok: [c1] 


本质上是通过setup模块获取的

[root@k81 an]# ansible c1 -m setup
# 输出的信息很多,可以需要提前的时候先grep过滤出变量关键字
[root@k81 an]# ansible localhost -m setup -a 'filter=ansible_eth*’
# 或者指定过滤哪些信息
[root@k81 an]# cat fact1.yaml 
---
- hosts: centos
  tasks:
  - name: Print IP
    debug:
      msg: "this host fqdn is {{ ansible_fqdn }}, this host ip is {{ ansible_eth0.ipv4.address }}"
 ## 测试结果
[root@k81 an]# ansible-playbook fact1.yaml 
TASK [Print IP] *****************************************************************************************************************************************************************************************************
ok: [c1] => {
    "msg": "this host fqdn is host-0a79, this host ip is 10.10.21.196"
}
ok: [c2] => {
    "msg": "this host fqdn is host-9d33, this host ip is 10.10.21.197"
}
PLAY RECAP **********************************************************************************************************************************************************************************************************
c1                         : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
c2                         : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0    

实际上每次执行playbook的时候都去获取被控端信息会很浪费时间,因此我们在优化play执行速度的时候可以将这项关闭  

[root@k81 an]# cat fact2.yaml 
---
- hosts: centos
  gather_facts: no
  tasks:
  - name: Print IP
    debug:
      msg: "this host fqdn is {{ ansible_fqdn }}, this host ip is {{ ansible_eth0.ipv4.address }}"
 ## 测试结果
[root@k81 an]# ansible-playbook fact2.yaml 
PLAY [centos] *******************************************************************************************************************************************************************************************************
TASK [Print IP] *****************************************************************************************************************************************************************************************************
fatal: [c1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible_fqdn' is undefined\n\nThe error appears to be in '/an/fact2.yaml': line 5, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n  - name: Print IP\n    ^ here\n"}
fatal: [c2]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible_fqdn' is undefined\n\nThe error appears to be in '/an/fact2.yaml': line 5, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n  - name: Print IP\n    ^ here\n"}
PLAY RECAP **********************************************************************************************************************************************************************************************************
c1                         : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
c2                         : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0 
## 会提示变量未定义
## 测试是否有 gather_facts时候playbook执行时间
[root@k81 an]# cat fact-no.yaml 
- hosts: centos
  gather_facts: no
  tasks:
  - name: test
    shell: sleep 3
[root@k81 an]# cat fact-yes.yaml 
- hosts: centos
  gather_facts: yes
  tasks:
  - name: test
    shell: sleep 3
## 开始测试
[root@k81 an]# time ansible-playbook fact-no.yaml 
......
real  0m3.910s
user  0m0.672s
sys 0m0.204s
[root@k81 an]# time ansible-playbook fact-yes.yaml
real  0m39.800s
user  0m2.281s
sys 0m0.372s 


facts使用场景

通过facts变量检查被控端硬件CPU信息,从而生成不同的Nginx配置文件(获取cpu数量)。  

# {{ ansible_processor_cores }}  核心数 ( 每颗物理CPU的核心数)
# {{ ansible_processor_count }}  颗数 (有几个CPU )
# {{ ansible_processor_vcpus }} 8 总核心数 

通过facts变量检查被控端内存状态信息,从而生成不同的memcached的配置文件。

# 根据内存状态生成不同的配置(支持+-*/运算)
# CACHESIZE="{{ ansible_memtotal_mb //2 }}"# 总内存/2
# CACHESIZE="{{ ansible_memtotal_mb * 0.8 }}" # 使用内存80% 

通过facts变量检查被控端主机名称信息,从而生成不同的Zabbix配置文件。

# {{ ansible_hostname }} 被控端主机名称 

通过facts变量检查被控端主机IP地址信息,从而生成不同的redis配置文件(获取需要bind的IP地址)。

# {{ ansible_eth1.ipv4.address }} 被控端IP地址 


facts语法示例

利用变量在不同的机器上起redis

[root@k81 an]# cat redis.conf.j2
......
bind 127.0.0.1 {{ ansible_eth0.ipv4.address }}  # 用变量
......
[root@k81 an]# cat fact-redis.yaml 
- hosts: centos 
  tasks:
  - name: Config epel
    yum: name=epel-release
  - name: Installed Redis Server
    yum:
      name: redis
      state: present
      enablerepo: epel
  - name: Configure Redis Server
    template:
      src: ./redis.conf.j2
      dest: /etc/redis.conf
    notify: Restart Redis Server
  - name: Started Redis Server
    systemd:
      name: redis
      state: started
      enabled: yes
  handlers:
  - name: Restart Redis Server
    systemd:
      name: redis
      state: restarted
## 测试
[root@k81 an]# ansible-playbook fact-redis.yaml
[root@k81 an]# redis-cli -h 10.10.21.196
10.10.21.196:6379> set name zs
OK
10.10.21.196:6379> keys *
1) "name"
10.10.21.196:6379> get name
"zs"
10.10.21.196:6379> exit
[root@k81 an]# redis-cli -h 10.10.21.197
10.10.21.197:6379> set name ls
OK
10.10.21.197:6379> keys *
1) "name"
10.10.21.197:6379> get name
"ls"
10.10.21.197:6379> exit

修改被控机器名字且后缀带上机器IP的最后一截

[root@k81 an]# cat f1.yaml 
---
- hosts: centos
  tasks: 
  - name: check msg
    debug: msg={{ ansible_eth0.ipv4.address.split('.')[-1] }}   # 这里用的python中字符串的切割,切完了之后变成列表然后取出来列表最后一个值
  - name: change hostname
    hostname: name=host-{{ ansible_eth0.ipv4.address.split('.')[-1] }}
## 测试修改结果
[root@k81 an]# ansible centos -m shell -a 'hostname '
c2 | CHANGED | rc=0 >> 


facts变量性能优化

前面我们看到了如果不获取被控端的变量会快很多,但是有些时候又必须得获取,那么我们可以想办法获取之后将这些信息临时存储起来,一段时间不去被控端再次获取(为了防止被控端配置改变,我们可以设置数据过期时间)


既想用 facts 信息,又希望能提高 playbook 的效率的话,可以采用 facts 缓存来实现。

facts 缓存支持多种方式:json 文件方式,redis 方式,memcache 方式等。各种方式的配置都是在 ansible.cfg 中配置。


json文件方法

设置ansible.cfg

gathering=smart
fact_caching_timeout=86400
# 这里是数据过期时间,单位是s,这里设置的是一天
fact_caching=jsonfile
fact_caching_connection=/opt/fact_cache
# 这里是需要缓存的路径 

在设置完成之后我们再来测试之前的fact-yes.yaml的playbook执行时间

[root@k81 an]# time ansible-playbook fact-yes.yaml
...
real  0m45.958s
user  0m2.507s
sys 0m0.421s
...
[root@k81 an]# time ansible-playbook fact-yes.yaml  # 第二次获取的是本地的信息
...
real  0m3.827s
user  0m0.666s
sys 0m0.181s
...
# 同时在设置的目录里面是会生成对应文件的
[root@k81 an]# ls /opt/fact_cache/
c1  c2
# 如果打开对应文件就可以看到内容是setup获取的内容


redis方法

设置ansible.cfg

注: 这种方法需要python安装redis连接模块

gathering=smart
fact_caching_timeout=86400
fact_caching=redis
fact_caching_connection: localhost:6379
# 如果连接其他的redis这里应该写具体的IP地址+端口,如果redis中有多个库,也可以在地址的最后面写上 :0类似的字样来声明库,如 192.168.123.230:6379:1  这里的1就是指的 1 库

设置完成之后可以进行测试

yum -y install python-pip
pip install --upgrade pip
pip install redis 
然后和上面一样,可以用time命令测试时间 


memcache方法

设置ansible.cfg

注: 这种方法需要python安装memcache连接模块

gathering=smart
fact_caching_timeout=86400
fact_caching=memcached  


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
4月前
|
运维 关系型数据库 Shell
小白带你学习linux自动化运维ansible
小白带你学习linux自动化运维ansible
136 0
小白带你学习linux自动化运维ansible
|
8月前
|
缓存 运维 监控
【运维知识进阶篇】Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
【运维知识进阶篇】Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
116 0
|
9月前
|
存储 JSON 数据安全/隐私保护
ansible定义变量和管理事实
ansible定义变量和管理事实
124 0
|
10月前
|
应用服务中间件 网络安全 开发工具
学习ansible常用模块这篇就够了(剧本)(二)
学习ansible常用模块这篇就够了(剧本)
106 0
|
10月前
|
运维 应用服务中间件 Shell
学习ansible常用模块这篇就够了(剧本)(一)
学习ansible常用模块这篇就够了(剧本)
191 0
|
10月前
Ansible 自定义变量与 role 默认变量的合并方法
如果你遇到 failed to combine variables, expected dicts but got a 'NoneType' and a 'dict' 这样的报错,你可以看看本文。
219 0
|
10月前
|
Shell 网络安全 开发工具
|
10月前
|
运维 Shell 网络安全
|
11月前
|
数据安全/隐私保护 Memcache
ansible学习之旅(其它特性)
ansible学习之旅(其它特性)
56 0
|
11月前
|
Kubernetes 负载均衡 Docker
ansible学习之旅(ansible依托kubeadm安装一个简单的k8s集群)
ansible学习之旅(ansible依托kubeadm安装一个简单的k8s集群)
119 0