Ansible剧本-playbook
- 1 playbook基础
- 1.1 简介
- 1.2 playbook的组成结构
- Task 任务列表
- 任务报错,如何继续执行
- 响应事件Handler
- 1.3 常用选项
- 执行playbook
- playbook查询帮助信息
- 校验playbook语法
- 测试playbook能否正常运行
- 2 变量 的定义方式
- 2.1 定义规则
- 2.2 vars 变量
- 2.3 在 主机清单 定义变量
- 2.4 在 主机、主机组目录 定义变量
- 2.5 从 变量文件 引入变量
- 2.6 注册变量 (引用命令返回值)
- 2.7 命令行 临时定义变量
- 2.8 facts 事实变量
- 简介
- 使用setup 收集
- 引用、使用 facts变量
- 开启、禁用facts变量
- 自定义facts
- 使用 set_fact 定义
- 2.9 lookup 生成变量(只用于主控机)
- 2.9.1 说明
- 2.9.2 方法
- file 从文件中获取值
- pipe 获取命令的输出值
- env 获取环境变量的值
- 更多方法
- 2.10 魔法变量 (内置变量)
- hostvars 获取指定主机的变量
- inentory_hostname 显示运行当前任务的主机名
- groups 列出所有主机组
- 更多魔法变量
- 2.11 其他
- 调试变量 debug
- 如何获取 字典 的值
- 3 运算符
- 3.1 比较运算符( >、<、=)
- 3.2 逻辑运算符(and、or)
- 4 判断语句
- 4.1 单次 条件判断 when
- 判断变量
- 判断执行结果
- 根据rc返回值来进行判断task任务是否执行成功
- 判断 一个路径是什么东西
- 判断字符串 大小写
- 判断奇、偶数、整除
- 其他
- 4.2 block 判断多个任务
- 5 异常处理
- 5.1 resuce 报错时执行
- 5.2 always 无论都会执行
- 5.3 fail 满足条件就退出
- 5.4 faild_when 满足条件就退出
- 6 循环语句
- 6.1 with_items 基于列表的循环
- 6.2 with_dict 基于字典的循环
- 6.3 loop循环
- 常用过滤器
- 7 文件管理模块
- 7.1 lineinfile 修改单行
- 7.1.1 选项
- 7.1.2 举例
- 替换行
- 在匹配行 前 添加内容
- 修改 匹配行、文件权限
- 删除 匹配行
- 文件存在则添加一行内容
- 验证 配置文件 修改后是否有效
- 7.2 blockinfile 修改多行
- 7.2.1 选项
- 7.2.2 举例
- 增加多行内容
- 删除多行内容
- 说明
- 删除的内容 有块标记
- 删除的内容 没有块标记
- 8 jinja2
- 8.1 jinja2 模板文件
- 8.1.1 说明
- 8.1.2 jinja2 语法
- if判断
- for循环
- 8.2 template 模块
- 8.2.1 选项
- 8.3 过滤器
- 8.3.1 说明、语法格式
- 8.3.2 字符串操作
- 8.3.3 数字操作
- 8.3.4 列表操作
- 8.4 举例
- jinjia2简单例子
- if、elif 多重判断
- for 循环
- 9 ansible 角色、集合管理
- 9.1 理论
- 角色的背景说明
- 角色的引用语法
- 角色(roles)的目录结构
- 集合(collection)
- role和collection
- galaxy网站、文档
- 9.2 ansible-galaxy 角色、集合管理命令
- 9.2.1 常用命令
- 9.2.2 举例-角色管理
- 初始化角色目录结构
- 安装角色roles
- 查询已安装的角色
- include_tasks 引入task任务文件
- 编写角色 并执行
- 在执行任务前后,先执行指定任务
- 9.2.3 举例-集合管理
- 安装集合
- 10 ansible-vault 加解密文件
- 10.1 选项
- 10.2 例子
- 执行一个 加密的剧本
- 创建 加密文件
- 加密 已存在的文件
- 解密 已经加密的文件
- 修改 加密文件密码
- 查看 加密文件 内容
- 11 ansible-navigator 导航器
- 11.1 说明
- 11.2 选项
- 11.3 举例
- 安装ansible-navigator
- 执行剧本
- 指定默认使用的 EE 镜像
- 查看ee镜像信息
- 查看主机清单的主机
学习RHCE的笔记,仅供参考
1 playbook基础
1.1 简介
ansible的playbook也叫做剧本,是一系列ansible命令的集合,利用yaml语言进行编写;
- 一个 playbook 中可以由 一个play或者多个play 进行组成,
- 每一个play 下面可以有 多个task任务,
- 一个task任务只能使用一个模块,
- 剧本的执行,是通过从上往下的顺序依次执行
- 支持变量、循环、判断、错误纠正等高级操作
1.2 playbook的组成结构
playbook主要有以下 四部分 构成:
- Target section:目标
- 可以定义play的名字
- 可以定义远程操作的被控节点主机
- 可以定义远程操作的用户
- 可以定义提权的相关配置等
- Variable section:变量
- 可以定义playbook运行时需要使用的变量
- Task section:任务
- 可以定义将要在远程主机上执行的任务列表
- Handler section:特殊task任务
- 可以定义task执行完成以后需要调用的任务
- 有条件 有目的的任务,是一个特殊的handler任务,和tasks处于同一个层级;一般情况下handler任务不会执行,只会触发再执行。handler任务是在所有任务执行完成之后才会执行
默认情况下,在一个play中,只要有task执行失败,则play终止,即使是与handler关联的task在失败的task之前运行成功了,handler也不会被执行。如果希望在这种情况下handler仍然能够执行,则需要使用如下配置:force_handlers: yes
说明:如果与handler关联的task还未执行,在其前的task已经失败,整个play终止,则handler未被触发,也不会执行。
# cat user.yml
- name: create user
hosts: all
remote_user: root
gather_facts: false
vars:
user: "test"
tasks:
- name: create user
user: name="{{ user }}"
name
:剧本 的 名字【可选】
hosts
:指定对 哪些被管理机 进行操作;
remote_user
:使用什么用户远程被控机
gather_facts
:指定在执行任务之前,是否先执行setup模块获取主机相关信息,如未用到,可不指定
vars
:定义后续任务中会使用到的变量,如未用到,可不指定
tasks
:定义具体需要执行的任务
name
:任务 的 名字【可选】
user
:调用的模块名
name
:user模块里的一个参数,用于指定创建的用户名称
Task 任务列表
task是playbook的任务列表,所有的任务都定义在tasks下面;
- 任务的执行 ,顺序是从上往下
- playbook 执行时,遇到报错的情况:
- 如果有多个play,task本身 报错
2. 第一个play执行失败,不会影响第二个play的执行 - 如果有多个task任务,执行的主机 报错
- 任务执行失败的主机, 不会再执行后面的task任务
- 其他执行成功的主机,不受影响 会继续执行
- 总结:只会停止错误主机的任务,其他主机的任务不会影响
- 如果有多个play,task本身 报错
- ansible具有幂等性,
- 幂等性:就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用
- 如果任务列表中的任务反复执行,一次执行和多次执行的结果都是一样的如果期望值和执行的任务结果一致,则任务就是执行成功的(ok)
- 例如:原本playbook当中有一个task任务是创建devops用户,再次执行的话不会报错,因为期望值的结果是一致的,如果任务本来就有,多次执行,结果就是OK成功的;
- 如果任务执行的前后,内容修改了,那么后面再次执行这个任务的时候就会发生覆盖;
任务报错,如何继续执行
如果playbook执行失败,导致task任务没有执行,如何解决?
在playbook当中,rc作为命令的返回值,通过判断rc返回值即可知道命令是否执行成功
如果rc返回值为0,则执行成功;如果非0.则执行失败
任务报错后,只会影响运行任务的主机,其他的主机不受影响
- 如果是命令执行模块执行失败
- 使用 || 逻辑或,配置/usr/bin/true 来让rc返回值为0
- 如果是其他ansible模块执行失败
- 使用
ignore_errors: true
如果当前任务执行失败,就跳过当前任务,继续去执行下一个任务
- 使用
- 使用hanler来规避错误(也是一种特殊的tasks,和tasks是并齐的关系)
- 默认情况下:在一个play中,只要有task执行失败,则play终止
- 如果与handler关联的task还 已经执行,但是后面的 task失败了,handler也不会被执行(因为handler是最后才执行的)。
- 这种情况下,如果希望 handler仍然能够执行,则需要使用如下配置:
force_handlers: yes
- 这种情况下,如果希望 handler仍然能够执行,则需要使用如下配置:
- 如果与handler关联的task还 未执行,在其前的task已经失败,整个play终止,则handler未被触发,也不会执行。【配了 force_handlers: yes 也不行】
# 过程:使用`ignore_errors: true` 如果当前任务执行失败,就跳过当前任务,继续去执行下一个任务
# 如果没添加`ignore_errors: true`,任务1报错就结束了,不会再执行任务2
[root@rhel ~]# cat ceshi_ignore.yml
- name: 剧本1
hosts: 10.0.0.23
tasks:
- name: 任务1
# 进去一个不存在的目录,让他报错
shell: cd /root/sksjdfklsj
# 使用`ignore_errors: true` 如果当前任务执行失败,就跳过当前任务,继续去执行下一个任务
ignore_errors: true
- name: 任务2
shell: echo "执行任务2"
[root@rhel ~]#
[root@rhel ~]#
[root@rhel ~]# ansible-playbook ceshi_ignore.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [剧本1] **********************************************************
TASK [Gathering Facts] **********************************************************************
ok: [10.0.0.23]
TASK [任务1] *********************************************************
fatal: [10.0.0.23]: FAILED! => {"changed": true, "cmd": "cd /root/sksjdfklsj", "delta": "0:00:00.007359", "end": "2024-08-26 16:32:51.693584", "msg": "non-zero return code", "rc": 1, "start": "2024-08-26 16:32:51.686225", "stderr": "/bin/sh: 第 1 行:cd: /root/sksjdfklsj: 没有那个文件或目录", "stderr_lines": ["/bin/sh: 第 1 行:cd: /root/sksjdfklsj: 没有那个文件或目录"], "stdout": "", "stdout_lines": []}
...ignoring
TASK [任务2] *********************************************************
changed: [10.0.0.23] => {"changed": true, "cmd": "echo \"执行任务2\"", "delta": "0:00:00.004179", "end": "2024-08-26 16:32:52.339460", "msg": "", "rc": 0, "start": "2024-08-26 16:32:52.335281", "stderr": "", "stderr_lines": [], "stdout": "执行任务2", "stdout_lines": ["执行任务2"]}
PLAY RECAP ***********************************************************
10.0.0.23 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
[root@rhel ~]#
# 默认情况:
[root@rhel ~]# cat ceshi.yml
- name: 剧本1
hosts: 10.0.0.23
# force_handlers: yes
tasks:
- name: 任务1
shell: echo "执行任务1"
notify: handler任务_1
- name: 任务2
# 进去一个不存在的目录,让他报错
shell: cd /root/sksjdfklsij
- name: 任务3
shell: echo "执行任务3"
handlers:
- name: handler任务_1
shell: echo "执行 handler任务_1"
[root@rhel ~]#
[root@rhel ~]# ansible-playbook ceshi.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [剧本1] ******************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [10.0.0.23]
TASK [任务1] ******************************************************************
changed: [10.0.0.23] => {"changed": true, "cmd": "echo \"执行任务1\"", "delta": "0:00:00.004199", "end": "2024-08-26 17:33:58.128032", "msg": "", "rc": 0, "start": "2024-08-26 17:33:58.123833", "stderr": "", "stderr_lines": [], "stdout": "执行任务1", "stdout_lines": ["执行任务1"]}
TASK [任务2] ******************************************************************
fatal: [10.0.0.23]: FAILED! => {"changed": true, "cmd": "cd /root/sksjdfklsij", "delta": "0:00:00.004440", "end": "2024-08-26 17:33:58.743674", "msg": "non-zero return code", "rc": 1, "start": "2024-08-26 17:33:58.739234", "stderr": "/bin/sh: 第 1 行:cd: /root/sksjdfklsij: 没有那个文件或目录", "stderr_lines": ["/bin/sh: 第 1 行:cd: /root/sksjdfklsij: 没有那个文件或目录"], "stdout": "", "stdout_lines": []}
PLAY RECAP ******************************************************************
10.0.0.23 : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
# 配置 force_handlers: yes
# 如果与handler关联的task还 已经执行,但是后面的 task失败了,handler也不会被执行(因为handler是最后才执行的)。
# 如果希望在这种情况下handler仍然能够执行,则需要使用如下配置:`force_handlers: yes`
[root@rhel ~]# cat ceshi.yml
- name: 剧本1
hosts: 10.0.0.23
force_handlers: yes
tasks:
- name: 任务1
shell: echo "执行任务1"
notify: handler任务_1
- name: 任务2
# 进去一个不存在的目录,让他报错
shell: cd /root/sksjdfklsij
- name: 任务3
shell: echo "执行任务3"
handlers:
- name: handler任务_1
shell: echo "执行 handler任务_1"
[root@rhel ~]#
[root@rhel ~]# ansible-playbook ceshi.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [剧本1] ******************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [10.0.0.23]
TASK [任务1] ******************************************************************
changed: [10.0.0.23] => {"changed": true, "cmd": "echo \"执行任务1\"", "delta": "0:00:00.006246", "end": "2024-08-26 17:37:18.555561", "msg": "", "rc": 0, "start": "2024-08-26 17:37:18.549315", "stderr": "", "stderr_lines": [], "stdout": "执行任务1", "stdout_lines": ["执行任务1"]}
TASK [任务2] ******************************************************************
fatal: [10.0.0.23]: FAILED! => {"changed": true, "cmd": "cd /root/sksjdfklsij", "delta": "0:00:00.004290", "end": "2024-08-26 17:37:19.199767", "msg": "non-zero return code", "rc": 1, "start": "2024-08-26 17:37:19.195477", "stderr": "/bin/sh: 第 1 行:cd: /root/sksjdfklsij: 没有那个文件或目录", "stderr_lines": ["/bin/sh: 第 1 行:cd: /root/sksjdfklsij: 没有那个文件或目录"], "stdout": "", "stdout_lines": []}
RUNNING HANDLER [handler任务_1] ***********************************************************************************
changed: [10.0.0.23] => {"changed": true, "cmd": "echo \"执行 handler任务_1\"", "delta": "0:00:00.004095", "end": "2024-08-26 17:37:19.863765", "msg": "", "rc": 0, "start": "2024-08-26 17:37:19.859670", "stderr": "", "stderr_lines": [], "stdout": "执行 handler任务_1", "stdout_lines": ["执行 handler任务_1"]}
PLAY RECAP ******************************************************************
10.0.0.23 : ok=3 changed=2 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
# 如果与handler关联的task还 未执行,在其前的task已经失败,整个play终止,则handler未被触发,也不会执行【配了 force_handlers: yes 也不行】
[root@rhel ~]# cat ceshi.yml
- name: 剧本1
hosts: 10.0.0.23
force_handlers: yes
tasks:
- name: 任务1
shell: echo "执行任务1"
# notify: handler任务_1
- name: 任务2
# 进去一个不存在的目录,让他报错
shell: cd /root/sksjdfklsij
- name: 任务3
shell: echo "执行任务3"
notify: handler任务_1
handlers:
- name: handler任务_1
shell: echo "执行 handler任务_1"
[root@rhel ~]#
[root@rhel ~]# ansible-playbook ceshi.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [剧本1] ******************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [10.0.0.23]
TASK [任务1] ******************************************************************
changed: [10.0.0.23] => {"changed": true, "cmd": "echo \"执行任务1\"", "delta": "0:00:00.003827", "end": "2024-08-26 17:43:55.833754", "msg": "", "rc": 0, "start": "2024-08-26 17:43:55.829927", "stderr": "", "stderr_lines": [], "stdout": "执行任务1", "stdout_lines": ["执行任务1"]}
TASK [任务2] ******************************************************************
fatal: [10.0.0.23]: FAILED! => {"changed": true, "cmd": "cd /root/sksjdfklsij", "delta": "0:00:00.004614", "end": "2024-08-26 17:43:56.506364", "msg": "non-zero return code", "rc": 1, "start": "2024-08-26 17:43:56.501750", "stderr": "/bin/sh: 第 1 行:cd: /root/sksjdfklsij: 没有那个文件或目录", "stderr_lines": ["/bin/sh: 第 1 行:cd: /root/sksjdfklsij: 没有那个文件或目录"], "stdout": "", "stdout_lines": []}
PLAY RECAP ******************************************************************
10.0.0.23 : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
响应事件Handler
Playbook基本语法 - 响应事件(Handler) - 《Ansible入门》 - 书栈网 · BookStack
handler任务,和tasks处于同一个层级;handlers需要在tasks中被调用,才有可能被执行;handler任务
是在 所有任务执行完成之后 才会执行
(所以无论调用多少次,一个handler任务,最终只在 最后 执行一次)【类似函数,你调用了,才可能执行】
在Ansible中,只有在 task的执行状态
为 changed
的时候,才会执行 该task调用 的 handler
,这也是handler与普通的event机制不同的地方
应用场景:什么情况下使用handlers呢?
如果你在tasks中修改了apache的配置文件。需要重起apache。此外还安装了apache的插件。那么还需要重起apache。像这样的应该场景中,重起apache就可以设计成一个handler.
1.3 常用选项
执行playbook
执行playbook的话,使用 ansible-playbook
执行
playbook查询帮助信息
ansible-playbook查询帮助信息
查看使用的ansible配置文件
ansible-playbook user.yml -v
-vv 查看python和ansible的版本
-vvv 查看ssh的连接信息
校验playbook语法
检查yaml文件语法
ansible-playbook test.yml --syntax-check
测试playbook能否正常运行
测试playbook能否正常运行,但不会真的运行【大写的C】
ansible-playbook test.yml -C
[root@rhel ~]# cat test.yml
- name: 剧本1
hosts: 10.0.0.23
tasks:
- name: 任务1:查看文件
file:
path: /root/a.txt
state: file
- name: 任务2:创建用户
user:
name: ansible
state: present
comment: "创建一个名为 ansible 的用户"
[root@rhel ~]#
[root@rhel ~]# ansible-playbook test.yml --syntax-check
playbook: test.yml
[root@rhel ~]# ansible-playbook test.yml -C -v
Using /etc/ansible/ansible.cfg as config file
PLAY [剧本1] ******************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [10.0.0.23]
TASK [任务1:查看文件] ******************************************************************
ok: [10.0.0.23] => {"changed": false, "gid": 0, "group": "root", "mode": "0644", "owner": "root", "path": "/root/a.txt", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 0, "state": "file", "uid": 0}
TASK [任务2:创建用户] ******************************************************************
changed: [10.0.0.23] => {"append": false, "changed": true, "comment": "", "group": 1003, "home": "/home/ansible", "move_home": false, "name": "ansible", "shell": "/bin/bash", "state": "present", "uid": 1003}
PLAY RECAP ******************************************************************
10.0.0.23 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
2 变量 的定义方式
什么情况下会使用变量??例如如果所有的被控节点的用户以及ssh端口不是顺序统一的,例如一个被控节点ssh端口是2222,另外一个ssh端口是9090
所以我们需要使用变量来代替,通过定义变量的方式
2.1 定义规则
变量的约束:
- ansible的变量由
数字、字母、下划线_
组成 - ansible的变量名
不能以数字开头
,可以是字母,也可以是下划线_ - ansible的变量
区别大小写
- ansible自定义变量的时候
尽量不要以 ansible 开头
,因为系统中有ansible开头的内置变量等
2.2 vars 变量
定义变量:使用 vars
定义变量,写在 yml文件里
引用变量:用2个大括号引起来 "{{ 变量名 }} {{ 变量名 }}"
,如果有多个变量、需要添加其他字符串,要用双引号 把外面 引起来。双引号一定要加上
- name: 剧本1
gather_facts: no
hosts: 10.0.0.23
vars:
var1: "变量1"
var2: "变量2"
tasks:
- name: 任务1
# 引用变量
debug:
msg: "这个是 {{ var1 }} {{ var2 }}"
- name: 任务2
debug:
msg: 这个是 "{{ var1 }}"
- name: 任务3
shell: "touch {{ var1 }}.txt"
- name: 任务4
shell: "ls -l {{ var1 }}.txt"
# 过程
[root@rhel ~]# ansible-playbook ceshi.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [剧本1] ****************************************************************************
TASK [任务1] ****************************************************************************
ok: [10.0.0.23] => {
"msg": "这个是 变量1 变量2"
}
TASK [任务2] ****************************************************************************
ok: [10.0.0.23] => {
"msg": "这个是 \"变量1\""
}
TASK [任务3] ****************************************************************************
changed: [10.0.0.23] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": true, "cmd": "touch 变量1.txt", "delta": "0:00:00.004909", "end": "2024-08-27 17:36:11.905528", "msg": "", "rc": 0, "start": "2024-08-27 17:36:11.900619", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [任务4] ****************************************************************************
changed: [10.0.0.23] => {"changed": true, "cmd": "ls -l 变量1.txt", "delta": "0:00:00.006743", "end": "2024-08-27 17:36:12.532251", "msg": "", "rc": 0, "start": "2024-08-27 17:36:12.525508", "stderr": "", "stderr_lines": [], "stdout": "-rw-r--r--. 1 root root 0 8月 27 17:36 变量1.txt", "stdout_lines": ["-rw-r--r--. 1 root root 0 8月 27 17:36 变量1.txt"]}
PLAY RECAP ******************************************************************************
10.0.0.23 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
2.3 在 主机清单 定义变量
在 Inventory主机清单 定义变量。包括 内置主机变量、自定义变量 2种:
- 内置主机变量:
- 自定义变量:
- 我们自己定义的变量
- 包含 主机变量 和 主机组变量
- 主机变量 和 主机组变量 的优先级:
- 主机变量 的 优先级 高
- 主机组变量 的 优先级 低
常用内置主机变量:
# 一般连接
ansible_host # 用于指定被管理的主机的真实IP
ansible_port # 用于指定连接到被管理主机的ssh端口号,默认是22
ansible_user # ssh连接时默认使用的用户名
# 特权升级
ansible_become # 相当于ansible_sudo或者ansible_su,允许强制特权升级
ansible_become_user # 通过特权升级到的用户,相当于ansible_sudo_user或者ansible_su_user
ansible_become_pass # 提升特权时,如果需要密码的话,可以通过该变量指定,相当于ansible_sudo_pass或者ansible_su_pass
ansible_sudo_exec # 如果sudo命令不在默认路径,需要指定sudo命令路径
# 特定ssh连接
ansible_connection # SSH连接的类型:local, ssh, paramiko,默认是ssh
ansible_ssh_pass # ssh连接时的密码
ansible_ssh_private_key_file # 秘钥文件路径,如果不想使用ssh-agent管理秘钥文件时可以使用此选项
ansible_ssh_executable # 如果ssh指令不在默认路径当中,可以使用该变量来定义其路径
主机和主机组 内置变量 示例:
192.168.1.1 ansible_user=admin ansible_port=22 # 定义主机变量
[test]
192.168.1.2
192.168.1.3
[test:vars] # 定义 test主机组 的 内置变量
ansible_user=root
ansible_port=22
主机和主机组 自定义变量 示例:
192.168.1.1 webserver=httpd # 定义主机变量
[test]
192.168.1.2
192.168.1.3
[test:vars] # 定义 test主机组 的 自定义变量
webserver=nginx
2.4 在 主机、主机组目录 定义变量
通过主机(host_vars) 和 主机组(group_vars) 的 目录文件 定义变量
- 前提:需要在
inventory主机清单 所在的目录
创建主机目录、主机组目录
- 主机目录:
- 目录名字为
host_vars
。 - 目录下的
变量文件的名称 以主机名来命名
,其他主机无法使用此变量,只有指定主机可以
- 目录名字为
- 主机组目录:
- 目录名字为
group_vars
。 - 目录下的
变量文件的名称 以主机组来命名
- 目录名字为
- 说明:创建好对应的目录名字就可以用
- 主机目录:
# 示例:
# 主机目录 需要和 主机清单的路径 处于同一个目录下
mkdir /etc/ansible/host_vars
# 只有主机10.0.0.23 才能引用此变量
echo "rhel_name: rhel9" > /etc/ansible/host_vars/10.0.0.23
# 主机组目录 需要和 主机清单的路径 处于同一个目录下
mkdir /etc/ansible/group_vars
# 只有主机组host_group 下面的主机才能引用变量
echo "group_name: itgroup" > /etc/ansible/group_vars/host_group
# 过程
[root@rhel ~]# mkdir /etc/ansible/host_vars
[root@rhel ~]# mkdir /etc/ansible/group_vars
# 只有主机10.0.0.23 才能引用此变量
[root@rhel ~]# echo "rhel_name: rhel9" > /etc/ansible/host_vars/10.0.0.23[root@rhel ansible]#
# 只有主机组host_group 下面的主机才能引用变量
[root@rhel ~]# echo "group_name: itgroup" > /etc/ansible/group_vars/host_group
[root@rhel ~]#
[root@rhel ~]# tree /etc/ansible/
/etc/ansible/
├── ansible.cfg
├── group_vars
│ └── host_group
├── hosts
├── host_vars
│ └── 10.0.0.23
└── roles
3 directories, 4 files
[root@rhel ~]#
# 测试 主机组的变量【这里的 host1 属于 host_group】
[root@rhel ~]# ansible host1 -m debug -a "var=group_name"
host1 | SUCCESS => {
"group_name": "itgroup"
}
[root@rhel ~]#
# 测试 主机的变量
[root@rhel ~]# ansible 10.0.0.23 -m debug -a "var=rhel_name"
10.0.0.23 | SUCCESS => {
"rhel_name": "rhel9"
}
[root@rhel ~]#
# 创个文件测试下
[root@rhel ~]# ansible 10.0.0.23 -m shell -a "touch {{rhel_name}}.txt"
10.0.0.23 | CHANGED | rc=0 >>
[root@rhel ~]# ansible 10.0.0.23 -m shell -a "ls -l {{rhel_name}}.txt"
10.0.0.23 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 0 8月 27 21:00 rhel9.txt
[root@rhel ~]#
# 没有定义的,就用不了
[root@rhel ~]# ansible host1 -m debug -a "var=rhel_name"
host1 | SUCCESS => {
"rhel_name": "VARIABLE IS NOT DEFINED!"
}
[root@rhel ~]#
2.5 从 变量文件 引入变量
使用关键字 vars_files
引入 外部的变量文件
vars_files
的格式:
- 用 列表 表示
- 值 就写 变量文件 的路径。这个变量文件路径,可以是 绝对路径、相对路径
变量文件 的格式:
- 只支持 字典 的格式,不可以是 列表
- 变量的定义格式是成键值对出现的,键值对之间可以嵌套,最终形成一个大字典
# 示例:
- name: 从 变量文件 引入变量
gather_facts: no
hosts: 10.0.0.23
# 使用 `vars_files`引入 外部的变量文件
vars_files:
- /root/vars.yml
tasks:
- name: 任务1
debug:
msg: "user01是: {{ users.user01.name }}"
- name: 任务2
debug:
msg: "user02是: {{ users.user02.name }}"
# 外部变量文件
users:
user01:
name: ZhangSan
age: 11
home_dirs: /home/zhangsan
user02:
name: LiSi
age: 18
home_dirs: /home/lisi
如何获取 字典 的值
# 过程
[root@rhel ~]# ansible-playbook host1.yml
PLAY [从 变量文件 引入变量] ****************************************************
TASK [任务1] *******************************************************************
ok: [10.0.0.23] => {
"msg": "user01是: ZhangSan"
}
TASK [任务2] *******************************************************************
ok: [10.0.0.23] => {
"msg": "user02是: LiSi"
}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
2.6 注册变量 (引用命令返回值)
关键字 register
可以将 某一任务结果 保存为 一个变量【这个变量是个大字典,包括 状态、时间、结果。。】
注册变量的应用场景:
在一台远端的服务器获取一个目录下的一列表的文件,然后下载这些文件
在handler执行之前,发现前面一个task发生了changed,然后执行一个指定的task
获取远端服务器的ssh key的内容,构建出known_hosts文件
# 关于 使用 register 的输出部分 重点说明如下:
login: 变量名,其值为一个字典
changed: ansible基于此来判断是否发生了状态改变
cmd: 被调用的命令
failed: 是否运行失败
delta: 任务执行的时间
rc: 返回值,0代表正常,非0代表异常
stderr: 错误结果输出,输出值是一个字符串
stderr_lines: 错误结果输出,输出值是一个列表
stdout_lines: 正确结果输出,输出值是一个列表
stdout: 正确结果输出,输出值是一个字符串,可以对列表循环取值需要说明的是,通过register注册的变量的结果并不是一成不变的,在不确定返回值的情况下,尽量调试看看输出结果。
# 举例
[root@rhel ~]# cat zhuce.yml
- name: 将whoami命令执行的结果注册到变量login
hosts: host1
tasks:
- name: 任务1
command: whoami
# 通过`register` 将 某一任务结果 保存为 一个变量
register: login
- name: 任务2
debug:
var: login
- name: 任务3
debug:
msg: "输出结果: {{ login.stdout }}"
[root@rhel ~]#
[root@rhel ~]# ansible-playbook zhuce.yml
PLAY [将whoami命令执行的结果注册到变量login] ***********************************
TASK [Gathering Facts] *********************************************************
ok: [host1]
TASK [任务1] *******************************************************************
changed: [host1]
TASK [任务2] *******************************************************************
ok: [host1] => {
"login": {
"changed": true,
"cmd": [
"whoami"
],
"delta": "0:00:00.002698",
"end": "2024-08-27 21:22:16.379132",
"failed": false,
"msg": "",
"rc": 0,
"start": "2024-08-27 21:22:16.376434",
"stderr": "",
"stderr_lines": [],
"stdout": "root",
"stdout_lines": [
"root"
]
}
}
TASK [任务3] *******************************************************************
ok: [host1] => {
"msg": "输出结果: root"
}
PLAY RECAP *********************************************************************
host1 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
2.7 命令行 临时定义变量
如果要定义多个变量,添加参数 -e 或者 --extra-vars
- 临时定义 单个变量,可以直接赋值。比如
变量名1=变量值
- 临时定义 多个变量。比如
"变量名1=变量值 变量名2=变量值"
'{"hosts":"vipers","user":"starbuck"}'
# 使用ad-hoc临时定义变量
ansible node1 -m debug -a 'var=rhel_name' -e rhel_name=rhel9.0
# 使用playboog临时定义变量
ansible-playbook playbook -e rhel_name=rhel9.0
# 示例yml文件 如下:
- hosts: '{{ hosts }}'
remote_user: '{{ user }}'
# 使用命令行的方式定义变量
ansible-playbook release.yml --extra-vars "hosts=vipers user=starbuck"
2.8 facts 事实变量
简介
ansible的 setup模块 会收集被控节点的主机信息,这些 收集到的系统信息叫做 facts。它会把这些收集到的信息 保存到 ansible_facts 这个变量(事实变量,字典的格式,底下包含各种 系统信息的字典)中。
变量包括:主机名、网卡设备、IP地址、磁盘名称和磁盘的存储空间、文件系统bios版本 架构…
使用setup 收集
通过setup模块收集facts数据,常用获取信息如下
关键字 | 说明 |
---|---|
ansible_python_version | python版本 |
ansible_distribution | 显示是什么系统 |
ansible_distribution_major_version | 显示是系统主版本号 |
ansible_devices | 显示磁盘设备信息 |
ansible_lvm | 显示lvm相关信息 |
ansible_memtotal_mb | 显示系统总内存 |
ansible_kernel | 显示内核版本 |
ansible_ens160 | 显示网卡版本 |
ansible_fqdn | 显示主机fqdn |
ansible_hostname | 显示主机名 |
# 查看 所有的fact信息
ansible 10.0.0.23 -m setup
# 查看网卡的信息
ansible 10.0.0.23 -m setup -a 'filter=ansible_ens160'
# 查看主机内存信息
ansible 10.0.0.23 -m setup -a 'filter=ansible_*_mb'
# 导出facts变量到文件
ansible 10.0.0.23 -m setup --tree /opt/setup.txt
ansible 10.0.0.23 -m setup > /opt/setup-node1
# 举例:显示lvm相关信息
[root@rhel ~]# ansible 10.0.0.23 -m setup -a 'filter=ansible_lvm'
10.0.0.23 | SUCCESS => {
"ansible_facts": {
"ansible_lvm": {
"lvs": {
"root": {
"size_g": "17.00",
"vg": "cs"
},
"swap": {
"size_g": "2.00",
"vg": "
引用、使用 facts变量
setup的 filter 参数,也可以用过来过滤 facts变量
- facts比较特殊,它以ansible_facts 作为 键,ansible每次收集后会自动将其注册为变量,所以facts中的数据都可以直接通过变量引用。
- filter 只能过滤 ansible_facts 的下一层级的变量,如果有多个层级,无法进行收集
# 通过指定方式收集信息
# 直接写 ansible_facts下的值
ansible 10.0.0.23 -m setup -a 'filter=ansible_all_ipv4_addresses'
# 如果写 ansible_facts.下的值,就过滤不到
ansible 10.0.0.23 -m setup -a 'filter=ansible_facts.ansible_all_ipv4_addresses'
# 通过通配符收集信息
ansible 10.0.0.23 -m setup -a 'filter=ansible_*addresses'
# 直接写 ansible_facts下的值
[root@rhel ~]# ansible 10.0.0.23 -m setup -a 'filter=ansible_all_ipv4_addresses'
10.0.0.23 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.0.106",
"192.168.122.1",
"10.0.0.23"
],
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false
}
# 如果写 ansible_facts.下的值,就过滤不到
[root@rhel ~]# ansible 10.0.0.23 -m setup -a 'filter=ansible_facts.ansible_all_ipv4_addresses'
10.0.0.23 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false
}
[root@rhel ~]#
开启、禁用facts变量
# 开启facts收集
gather_facts: true
gather_facts: yes
# 关闭facts收集
gather_facts: false
gather_facts: no
# 举例: 在yml文件中 关闭facts收集 `gather_facts: no`
- hosts: node1
gather_facts: no
tasks:
- debug:
# 由于事实变量没有收集,则此地方无法找到变量值
var: ansible_all_ipv4_addresses
如果在playbook中的target section位置,禁用了gather_facts: false ,也可以在tasks中添加模块 setup 进行收集。一般不会这么干
- hosts: node1
gather_facts: no
tasks:
- setup:
- debug:
var: ansible_all_ipv4_addresses
自定义facts
ansible除了能获取到预定义的fact的内容,还支持手动为某个主机定制fact。称之为本地fact。
本地fact默认存放于被控端的 /etc/ansible/facts.d 目录下,如果文件为ini格式或者json格式,ansible会自动识别。以这种形式加载的fact是key为ansible_local的特殊变量。
在ansibler主控端定义一个 ini 格式的 custom.fact 文件内容如下:
[general]
package = httpd
service = httpd
state = started
案例:自定义facts事实变量
- 创建facts变量文件
vim userinfo.fact
[user]
name = zhangsan
age = 18
sex = boy
- 编写playbook,将facts变量文件拷贝到被控节点 /etc/ansible/facts.d 目录下
vim userinfo.yml
- name: use fact
hosts: node1
tasks:
- name: create dir
file:
path: /etc/ansible/facts.d
state: directory
- name: copy
copy:
src: /opt/userinfo.fact
dest: /etc/ansible/facts.d
- 引用facts变量
ansible node1 -m setup -a 'filter=ansible_local'
使用 set_fact 定义
set_fact模块 可以把 facts 里的变量拿出来用,重新组合,自定义成我们要的变量,再拿来用
- hosts: 10.0.0.23
tasks:
- name: set_fact举例
set_fact:
# 把 ansible_distribution 和 ansible_distribution_version 这两个变量的值,拼接起来,并赋值给 version 这个变量
version: "{{ ansible_distribution }}-{{ansible_distribution_version}}"
- name: 输出 version 变量值
debug:
msg: "{{ version }} "
# 过程
[root@rhel ~]# ansible 10.0.0.23 -m setup -a 'filter=ansible_distribution'
10.0.0.23 | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "CentOS",
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false
}
[root@rhel ~]#
[root@rhel ~]# ansible 10.0.0.23 -m setup -a 'filter=ansible_distribution_version'
10.0.0.23 | SUCCESS => {
"ansible_facts": {
"ansible_distribution_version": "9",
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false
}
[root@rhel ~]#
# 执行脚本
[root@rhel ~]# ansible-playbook set_fact
PLAY [10.0.0.23] ***************************************************************
TASK [Gathering Facts] *********************************************************
ok: [10.0.0.23]
TASK [set_fact举例] ************************************************************
ok: [10.0.0.23]
TASK [输出 version 变量值] *****************************************************
ok: [10.0.0.23] => {
"msg": "CentOS-9 "
}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
自定义的facts事实变量,会保存到ansible_local变量中
整合facts变量,让变量拼凑在一块,set_fact模块
- name: usr set_fact
hosts: node1
tasks:
- set_fact:
get_version: "{{ ansible_distribution }}-{{ ansible_distribution_version }}"
- debug:
var: get_version
2.9 lookup 生成变量(只用于主控机)
2.9.1 说明
- 有些时候,我们希望 从诸如 文本文件 或者 .csv文件 中收集数据作为ansible的变量,或者 直接获取某些命令的输出 作为 ansible的变量,这个时候,我们就需要通过 ansible 的 lookup插件 来从这些数据源中读取配置数据,传递给ansbile变量,并在playbook或者模板中使用这些数据。
- 但是
注意 lookup获取的变量来自于 主控端 主控端 主控端
。 - ansible支持一套从不同数据源获取数据的 lookup,包括file, password, pipe, env, template,csvfile, dnstxt, redis_kv, etcd等
2.9.2 方法
写在yml文件里
# 语法
{{ lookup('使用什么方法','参数') }}
# 把文件的内容作为变量的值(file查看的是主控节点的文件)
get_passwd: "{{ lookup('file','/etc/passwd') }}"
# 把命令的结果作为变量的值
key_content: "{{ lookup('file','/root/.ssh/id_rsa.pub')}}"
# 把shell变量的结果作为变量的值
get_env: "{{ lookup('env', 'JAVA_HOME')}}"
file 从文件中获取值
注意 lookup获取的变量来自于 主控端 主控端 主控端
使用file lookup可以从文本文件中获取数据,并在这些数据传递给ansible变量,在task
或者jinja2模板中进行引用。下面是获取ssh公钥并生成变量的示例:
- hosts: node1
tasks:
- name: set facts
set_fact:
key_content: "{{ lookup('file','/root/.ssh/id_rsa.pub')}}"
- name: debug set facts
debug:
msg: "{{ keycontent }}"
pipe 获取命令的输出值
注意 lookup获取的变量来自于 主控端 主控端 主控端
使用pipe lookup可以直接调用外部命令,并将命令执行的结果打印到标准输出,作为ansible变量。下面的例子通过pipe调用date指令拿到一个以时间数字组成的字串。
- hosts: 127.0.0.1
vars:
# 这里'+%Y-%m-%d--%H:%M:%S' 中间要是有空格就会报错,所以用--代替了
aaa: "{{ lookup('pipe', 'date +%Y-%m-%d--%H:%M:%S') }}"
tasks:
- name: "pipe 获取命令的输出值-1"
debug:
var: aaa
- name: "pipe 获取命令的输出值-2"
debug:
msg: "命令的输出:{{ lookup('pipe', 'expr $(date +%s) + 2592000') }}"
[root@hn ~]# ansible-playbook pipe.yml
PLAY [127.0.0.1] ***************************************************************
TASK [Gathering Facts] *********************************************************
ok: [127.0.0.1]
TASK [pipe 获取命令的输出值-1] *************************************************
ok: [127.0.0.1] => {
"aaa": "2024-09-29--16:25:42"
}
TASK [pipe 获取命令的输出值-2] *************************************************
ok: [127.0.0.1] => {
"msg": "命令的输出:1730190342"
}
PLAY RECAP *********************************************************************
127.0.0.1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@hn ~]#
env 获取环境变量的值
注意 lookup获取的变量来自于 主控端 主控端 主控端
env lookup实际就是获取在控制主机上的某个环境变量的值。
- name: 获取 环境变量 $JAVA_HOME 的值
debug:
msg: "{{ lookup('env', 'JAVA_HOME')}}"
更多方法
查看更多的lookup可以使用的值:
ansible-doc -t lookup -l
2.10 魔法变量 (内置变量)
Ansible 默认会提供一些 内置的变量 以实现一些特定的功能,我们称之为魔法变量 (内置变量)。
hostvars 获取指定主机的变量
获取 指定主机 的相关变量。
# 语法
{{ hostvars['主机名/IP'].该主机的变量 }}
举例:有一台web服务器的配置文件中需要指定db服务器的ip地址,我们假定这台db服务器的hostname为db.exmaple.com,ip地址绑定在eth0网卡上,我们可以通过 hostvars方法 在web服务器上调用db服务器的ip地址
{{ hostvars['db.example.com'].ansible_eth0.ipv4.address }}
需要注意:
db.example.com 不能使用ip地址来取代,只能使用主机名,要用引号引起来。
如果一定要写 IP地址,在 主机清单、yml文件的主机 里要有写这个ip地址,才可以引用
# 举例
- hosts: node1,node2
gather_facts: yes
tasks:
- debug:
msg: "{{ hostvars['node1'].ansible_default_ipv4.address }}"
[root@rhel ~]# cat hostvars
- hosts: 10.0.0.23
tasks:
- debug:
msg: "{{ hostvars['10.0.0.23'] }}"
[root@rhel ~]#
[root@rhel ~]# ansible-playbook hostvars
PLAY [10.0.0.23] ******************************
TASK [Gathering Facts] ********************************
ok: [10.0.0.23]
TASK [debug] *****************************
ok: [10.0.0.23] => {
"msg": {
"ansible_all_ipv4_addresses": [
"10.0.0.23",
"192.168.224.140"
],
"ansible_all_ipv6_addresses": [
"fe80::bd94:3643:89aa:4908",
"fe80::20c:29ff:fe25:7f90"
],
。。。。。
inentory_hostname 显示运行当前任务的主机名
inventory_hostname是Ansible所 识别 的 当前正在运行task 的 主机 的主机名
# 举例
- hosts: node1,node2
gather_facts: yes
tasks:
- debug:
var: ansible_hostname
when: inventory_hostname == 'node1'
[root@rhel ~]# cat inentory_hostname
- hosts: 10.0.0.23
tasks:
- debug:
msg: "执行当前任务的主机 的主机名是:{{ ansible_hostname }} "
[root@rhel ~]#
[root@rhel ~]# ansible-playbook inentory_hostname
PLAY [10.0.0.23] ***************************************************************
TASK [Gathering Facts] *********************************************************
ok: [10.0.0.23]
TASK [debug] *******************************************************************
ok: [10.0.0.23] => {
"msg": "执行当前任务的主机 的主机名是:centos "
}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
groups 列出所有主机组
groups是inventory中所有主机组的列表,可用于枚举主机组中的所有主机。
{{ groups }} # 列出 所有的 主机组
{{ groups.test }} # 列出 test组 内的所有主机,可用于循环主机组内的主机(常用于循环)
{{ group_names }} # 列出 当前正在执行task 的 目标主机 位于的 主机组。
# 过程
[root@rhel ~]# cat groups
- hosts: 10.0.0.23
tasks:
- debug:
msg: "{{ groups.group01 }}"
[root@rhel ~]#
[root@rhel ~]# ansible-playbook groups
PLAY [10.0.0.23] ***************************************************************
TASK [Gathering Facts] *********************************************************
ok: [10.0.0.23]
TASK [debug] *******************************************************************
ok: [10.0.0.23] => {
"msg": [
"10.1.0.11",
"10.1.0.25",
"10.1.0.26",
"10.1.0.27",
"10.1.0.28",
"10.1.0.29",
"10.1.0.30",
"xiaoshou1",
"10.0.0.23"
]
}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
更多魔法变量
查看更多的ansible魔法变量:
Special Variables — Ansible Community Documentation
2.11 其他
调试变量 debug
调试变量的方式:
使用debug模块,有2个参数,分别是msg和var(二者无法连用)
msg
:
可以输出 自定义文本 + 变量值,
格式 还是引用变量的格式
var
:
只能打印变量,
格式:只要写个变量名就行
[root@rhel ~]# cat ceshi.yml
- name: 剧本1
gather_facts: no
hosts: 10.0.0.23
vars:
var1: "变量1"
var2: "变量2"
tasks:
- name: 任务1
debug:
msg: "这个是: {{ var1 }}"
- name: 任务2
debug:
var: var2
[root@rhel ~]#
[root@rhel ~]# ansible-playbook ceshi.yml
PLAY [剧本1] ****************************************************************************
TASK [任务1] ****************************************************************************
ok: [10.0.0.23] => {
"msg": "这个是: 变量1"
}
TASK [任务2] ****************************************************************************
ok: [10.0.0.23] => {
"var2": "变量2"
}
PLAY RECAP ******************************************************************************
10.0.0.23 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
如何获取 字典 的值
当我们 定义了一个稍微复杂的字典变量,如果想要获取 字典 里的 字典,可以使用 中括号[]
、点号.
# 获取users 中 bjones用户 的 first_name
{{ users.bjones.first_name }}
# 或者如下写法:
{{ users['bjones']['first_name'] }}
# 说明:中括号引用时,中括号内 可以是 变量,不需要加引号,定义flag变量的值为bjones
可以写成{{ users[flag]['first_name'] }}
3 运算符
3.1 比较运算符( >、<、=)
在ansible中,还支持如下比较运算符:
== # 比较两个对象是否相等,相等 则返回 真。可用于比较 字符串、数字
!= # 比较两个对象是否不等,不等 则为真。
> # 比较两个对象的大小,左边的值大于右边的值,则为真
< # 比较两个对象的大小,左边的值小于右边的值,则为真
>= # 比较两个对象的大小,左边的值大于等于右边的值,则为真
<= # 比较两个对象的大小,左边的值小于等于右边的值,则为真
示例:
when: ansible_machine == "x86_64"
when: max_memory <= 512
3.2 逻辑运算符(and、or)
在Ansible中,除了比较运算符,还支持逻辑运算符
and # 逻辑与,当左边和右边两个表达式同时为真,则返回真
or # 逻辑或,当左右和右边两个表达式任意一个为真,则返回真
not # 逻辑否,对表达式取反
() # 当一组表达式组合在一起,形成一个更大的表达式,组合内的所有表达式都是逻辑与的关系
# 逻辑或
when: ansible_distribution == "RedHat" or ansible_distribution == "Fedora"
# 逻辑与
when: ansible_distribution_version == "8.0" and ansible_kernel == "4.18.0-80.el8.x86_64"
# 组合
when: ( ansible_distribution == "RedHat" and ansible_distribution_major_version == "8" ) or ( ansible_distribution == "Fedora" and ansible_distribution_major_version == "28")
# 逻辑与:使用 and 符号进行连接,所有的条件满足才为真
- hosts: node1,node2
gather_facts: yes
tasks:
- debug:
msg: hello rhce
when: ansible_hostname == 'node1' and ansible_ens160.ipv4.address == '192.168.112.128'
# 逻辑或:使用 or 符号进行连接,只要满足其中一个条件则为真
- hosts: node1,node2
gather_facts: yes
tasks:
- debug:
msg: hello rhce
when: ansible_hostname == 'node2' or ansible_ens160.ipv4.address == '192.168.112.128'
# 逻辑非: 使用 not 进行判断,对表达式进行取反(not应该放到整个的表达式的最前面)
- hosts: node1,node2
gather_facts: yes
tasks:
- debug:
msg: hello rhce
when: not inventory_hostname == 'node1'
# 多个表达式组成一组:使用 () 来表示一组表达式,也就是多个表达式的集合
# 案例:主机名是node1,并且IP地址是192.168.112.128 或者 系统是RedHat,并且大版本是9 则执行任务
- hosts: node1,node2
gather_facts: yes
tasks:
- debug:
msg: hello rhce
when: ( ansible_hostname == 'node1' and ansible_ens160.ipv4.address == '192.168.112.128' ) or ( ansible_os_family == 'RedHat' and ansible_distribution_major_version == '9' )
4 判断语句
4.1 单次 条件判断 when
在ansible中,使用 条件判断 的关键字就是 when。
当 表达式的结果 返回 true
,便会 执行 本次的任务
。
当 表达式的结果 返回 false
,便会 跳过 本次的任务
。
when判断 默认就识别变量名
,所以不需要使用 "{{}}"
括起来
when 是对 单个task任务进行判断,多个任务就要写多个when
判断变量
defined # 判断 变量 是否 已定义,已定义 则返回 真
undefined # 判断 变量 是否 未定义,未定义 则返回 真
none # 判断 变量的值 是否为 空,如果 变量已定义 且 值为空,则返回真
# 举例
- hosts: 10.0.0.23
gather_facts: no
vars:
testvar: "test"
testvar1:
tasks:
- debug:
msg: "testvar 已定义"
when: testvar is defined
- debug:
msg: "testvar2 未定义"
when: testvar2 is undefined
- debug:
msg: "testvar1 已定义 且 值为空"
when: testvar1 is none
判断执行结果
ok # 目标状态与期望值一致,没有发生变更
change 或 changed # 目标发生变更,与期望值一样
sucess 或 succeeded # 目标状态与期望值一致,或者任务执行成功
failure 或 failed # 任务执行失败
skip 或 skipped # 任务被跳过
# 语法
when: 要判断的东西 is 执行结果
# 示例:
- hosts: test
tasks:
- shell: 'cat /testdir/aaa'
register: result
# `ignore_errors: true` 如果当前任务执行失败,就跳过当前任务,继续去执行下一个任务
ignore_errors: true
- debug:
msg: "success 目标状态与期望值一致,或者任务执行成功"
when: result is success
- debug:
msg: "failed 任务执行失败"
when: result is failure
- debug:
msg: "changed 目标发生变更,与期望值一样"
when: result is change
- debug:
msg: "skip 任务被跳过"
when: result is skip
根据rc返回值来进行判断task任务是否执行成功
register 注册变量—>保存task任务的执行信息
- hosts: all
tasks:
- shell: ls /etc/passwd1
register: get_status
ignore_errors: yes
- debug:
var: get_status
- debug:
msg: rc is ok
when: get_status.rc == 0
- debug:
msg: rc is error
when: get_status.rc != 0
判断 一个路径是什么东西
file # 判断 指定路径 是否为 一个文件,是则为真
directory # 判断 指定路径 是否为 一个目录,是则为真
link # 判断 指定路径 是否为 一个软链接,是则为真
mount # 判断 指定路径 是否为 一个挂载点,是则为真
exists # 判断 指定路径 是否 存在,存在则为真
特别注意:关于 路径 的所有判断均 是 判断 主控端 上的路径,而非 被控端 上的路径
# 示例:
- hosts: test
gather_facts: no
vars:
testpath1: "/testdir/test"
testpath2: "/testdir"
tasks:
- debug:
msg: "是 一个文件"
when: testpath1 is file
- debug:
msg: "是 一个目录"
when: testpath2 is directory
判断字符串 大小写
lower # 判断 字符串 中的 所有字母 是否都是 小写,是则为真
upper # 判断 字符串 中的 所有字母 是否都是 大写,是则为真
# 示例:
- hosts: test
gather_facts: no
vars:
str1: "abc"
str2: "ABC"
tasks:
- debug:
msg: "str1 是 小写"
when: str1 is lower
- debug:
msg: "str2 是 大写"
when: str2 is upper
判断奇、偶数、整除
even # 判断 数值 是否为 偶数,是 则为 真
odd # 判断 数值 是否为 奇数,是 则为 真
divisibleby(数字) # 判断 是否 可以整除 指定的数值,是 则为真
# 示例:
- hosts: test
gather_facts: no
vars:
num1: 6
num2: 8
num3: 15
tasks:
- debug:
msg: "判断 数值 是否为 偶数"
when: num1 is even
- debug:
msg: "判断 数值 是否为 奇数"
when: num2 is odd
- debug:
msg: "判断 是否 可以整除 指定的数值"
when: num3 is divisibleby(3)
其他
其他条件测试:
subset # 判断一个list是不是另一个list的 子集:when: a is subset(b)
superset # 判断一个list是不是另一个list的 父集:when: b is superset(a)
in # 判断一个字符串是否存在于另一个字符串中,也可用于判断某个特定的值是否存在于列表中
string # 判断对象是否为一个字符串,是则为真 when: var1 is string
number # 判断对象是否为一个数字,是则为真 when: var3 is number
# in 判断一个字符串是否存在于另一个字符串中,也可用于判断某个特定的值是否存在于列表中
supported_distros:
- RedHat
- CentOS
when: ansible_distribution in supported_distros
# subset 判断一个list是不是另一个list的子集:when: a is subset(b)
# superset 判断一个list是不是另一个list的父集:when: b is superset(a)
- hosts: all
gather_facts: no
vars:
OS:
- rhel
- openeuler
- centos
os:
- rhel
- centos
tasks:
- debug:
msg: ansible ok
when: OS is superset(os)
# in 判断 关键字是否处理列表中
- hosts: all
tasks:
- debug:
msg: ok
when: "'ens224' in ansible_interfaces"
# string 判断是否是字符串
# number 判断是否是数字
- hosts: all
vars:
RHEL_NAME: rhel9
RHEL_NUM: 9
tasks:
- debug:
msg: string ok
when: RHEL_NAME is string
- debug:
msg: num ok
when: RHEL_NUM is number
4.2 block 判断多个任务
when
判断,一次 只能判断 一个task任务,
block
判断,一次 可以判断 多个task任务。
- ansible通过block来包裹多个task任务,直接对block进行when判断,
- 如果 判断成功 则执行block 中所有的task任务。
- hosts: node1
gather_facts: no
tasks:
- block:
- shell: ls /etc/shadow1
- file:
path: /etc/passwd
state: file
when: inventory_hostname == 'node1'
5 异常处理
5.1 resuce 报错时执行
resuce关键字,一般搭配 block块 使用:
- 如果 block中的任务 执行 失败,则 会 执行 resuce 下面的任务;
- 如果 block中的任务 执行 成功,则 不会 执行 resuce 下面的任务
- hosts: node1
gather_facts: no
tasks:
- block:
- shell: ls /etc/shadow
- file:
path: /etc/passwd
state: file
rescue:
- debug:
msg: resuce
when: inventory_hostname == 'node1'
5.2 always 无论都会执行
always关键字,无论block的任务执行是成功还是失败,都要执行always关键字中的task任务
- hosts: node1
gather_facts: no
tasks:
- block:
- shell: ls /etc/shadow1
- file:
path: /etc/passwd
state: file
rescue:
- debug:
msg: resuce
always:
- debug:
msg: always
when: inventory_hostname == 'node1'
5.3 fail 满足条件就退出
fail模块用于终止当前playbook的执行;
通常与条件语句组合使用,当满足条件时,终止当前playbook的运行。
备注:直接用 faild_when 比较方便
# 选项只有一个:
msg:终止前打印出信息
- hosts: all
tasks:
- shell: ls /etc/paaa
ignore_errors: yes
register: get_status
- fail:
msg: playbook exit
when: get_status.rc != 0
- debug:
msg: a
- debug:
msg: b
5.4 faild_when 满足条件就退出
当 fail 和 when组合使用 的时候,还有一个更简单的写法,即 failed_when,
faild_when 当满足条件时,终止当前playbook的运行。
- hosts: all
tasks:
- shell: ls /etc/paaa
ignore_errors: yes
register: get_status
- debug:
msg: playbook exit
failed_when: get_status.rc != 0
- debug:
msg: a
- debug:
msg: b
# 如果在 command_result 存在错误输出,且错误输出中,包含了`FAILED`字串,即返回失败状态:
- hosts: test
tasks:
- name: 此命令失败时打印FAILED
command: /usr/bin/example-command -x -y -z
register: command_result
failed_when: "'FAILED' in command_result.stderr"
6 循环语句
基于列表的循环
基于字典的循环
loop循环
在Ansible 2.5以前,playbook通过不同的循环语句以实现不同的循环,这些语句使用with_作为前缀。这些语法目前仍然兼容,但在未来的某个时间点,会逐步废弃。
6.1 with_items 基于列表的循环
不能使用对象的方式进行循环
第一种方式:利用变量的形式
- hosts: 10.0.0.23
vars:
users:
- zhangsan
- lisi
- wangwu
tasks:
- debug:
msg: "{{ item }}"
with_items: "{{ users }}"
[root@rhel ~]# ansible-playbook with
PLAY [10.0.0.23] ***************************************************************
TASK [debug] *******************************************************************
ok: [10.0.0.23] => (item=zhangsan) => {
"msg": "zhangsan"
}
ok: [10.0.0.23] => (item=lisi) => {
"msg": "lisi"
}
ok: [10.0.0.23] => (item=wangwu) => {
"msg": "wangwu"
}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
第二种方式:直接写列表
- hosts: node1
gather_facts: no
vars:
users:
- zhangsan
- lisi
- wangwu
tasks:
- debug:
msg: "{{ item }}"
with_items:
- zhangsan
- lisi
- wangwu
第三种方式:类似于python的写法,一个行内对象
- hosts: node1
gather_facts: no
vars:
users:
- zhangsan
- lisi
- wangwu
tasks:
- debug:
msg: "{{ item }}"
with_items: ["zhangsan", "lisi", "wangwu"]
6.2 with_dict 基于字典的循环
在字典中是以 key value的格式
- hosts: node1
gather_facts: no
vars:
users:
memeda01:
name: zhangsan
uid: 3030
memeda02:
name: lisi
uid: 4040
tasks:
- debug:
# key 是 memeda01 和memeda02;value是 name:zhangsan 和 uid:3030
msg: "{{ item.value.name}}"
with_dict: "{{ users }}"
- debug:
msg: "{{ item.value.uid}}"
with_dict: "{{ users }}"
6.3 loop循环
在ansible 2.5及以前的版本当中,所有的循环都是使用with_X风格。
但是从2.6版本开始,官方开始推荐使用loop关键字来代替with_X风格的关键字
loop天生适合列表循环,如果要对其循环字典,必须使用jinja2过滤器 dict2items 进行将其转化类型。
- name: 循环列表
gather_facts: no
hosts: 10.0.0.23
vars:
users:
- zhangsan
- lisi
tasks:
- debug:
msg: "{{ item }}"
loop: "{{ users }}"
[root@rhel ~]# ansible-playbook loop_list
PLAY [循环列表] ****************************************************************
TASK [debug] *******************************************************************
ok: [10.0.0.23] => (item=zhangsan) => {
"msg": "zhangsan"
}
ok: [10.0.0.23] => (item=lisi) => {
"msg": "lisi"
}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
# 使用loop配合dict2items过滤器实现 循环字典 功能:
- name: 循环字典
hosts: 10.0.0.23
gather_facts: no
vars:
users:
alice: female
bob: male
tasks:
- debug:
msg: "键是:{{ item.key }} 值是: {{ item.value}}"
loop: "{{users | dict2items }}"
[root@rhel ~]# ansible-playbook loop_dict
PLAY [循环字典] ****************************************************************
TASK [debug] *******************************************************************
ok: [10.0.0.23] => (item={'key': 'alice', 'value': 'female'}) => {
"msg": "键是:alice 值是: female"
}
ok: [10.0.0.23] => (item={'key': 'bob', 'value': 'male'}) => {
"msg": "键是:bob 值是: male"
}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
常用过滤器
dict2items # 将 字典 转化为 列表
password_hash('sha512') # 将 字符串通过sha512进行加密,常常用于用户的密码
defalt('值') # 当变量不存在的适合,使用默认的值
7 文件管理模块
通过此类模块 主要用来修改配置文件,因为有个选项validate
可以 校验配置文件是否正确(copy模块的content 是覆盖文件 而不是修改原有的内容)
lineinfile 修改单行配置内容
blockinfile 修改多行配置内容
7.1 lineinfile 修改单行
修改的是 行内容 而不是 关键字内容
7.1.1 选项
常用参数
path # 要修改的文件 路径
line # 替换/插入 匹配到的 行(如果匹配到多行一样的内容,则修改最后一行内容)
regexp # 查找 行【支持通配符、正则表达式】
backrefs yes|no # 配合regexp、line使用
# backrefs默认是no,如果regexp没有没有匹配到行,line会在最后一行添加上去!!!而不是取消修改(正常是regexp匹配到行,line才执行修改)。所以,backrefs:yes,就是regex如果没有匹配到行,line不会执行替换
insertbefore # 在匹配的行 前面 插入
insertafter # 在匹配的行 后面 插入
create yes|no # 默认是no;如果是yes,当文件不存在则生成文件
state absent|present # 如果是absent删除的话,会将所有匹配的内容都给删除掉
backup # 是否备份文件
validate # 验证配置文件 在 修改之前 和 之后 是否仍然有效【使用的是应用程序本身的验证机制,而不是lineinfile模块】例如 httpd服务,使用httpd -t 验证语法;nginx 服务,使用nginx -t 验证语法
7.1.2 举例
替换行
# 将/etc/selinux/config 中匹配到 以 'SELINUX=' 开头的 行,将其替换为 'SELINUX=disabled'
- hosts: 10.0.0.23
tasks:
- name: 修改匹配行
lineinfile:
path: /etc/selinux/config
regexp: "^SELINUX="
line: "SELINUX=disabled"
# backrefs:yes,就是regex如果没有匹配到行,line不会执行替换
backrefs: yes
在匹配行 前 添加内容
# 在http.conf文件的 Listen 80 前面后面添加一行Listen 8080,task示例如下:
- hosts: 10.0.0.23
tasks:
- name: Ensure the default Apache port is 8080
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^Listen '
insertafter: '^#Listen '
line: Listen 8080
# backrefs:yes,就是regex如果没有匹配到行,line不会执行替换
backrefs: yes
修改 匹配行、文件权限
# 修改/etc/hosts,将以127.0.0.1开头的行 替换为 "127.0.0.1 localhost",并将/etc/hosts的属主和属组都修改为root,权限改为644,如下:
- hosts: 10.0.0.23
tasks:
- name: modify hosts
lineinfile:
dest: /etc/hosts
regexp: '^127\.0\.0\.1'
line: "127.0.0.1 localhost"
owner: root
group: root
mode: 0644
删除 匹配行
删除文件内容
# 修改/etc/sudoers,将以%wheel开头的行删除,如下:
- hosts: 10.0.0.23
tasks:
- name: Make sure group wheel is not in the sudoers configuration
lineinfile:
path: /etc/sudoers
state: absent
regexp: "^%wheel"
文件存在则添加一行内容
# 往文件里添加一行(多次执行,不会重复添加),如果文件不存在,则创建文件
- hosts: 10.0.0.23
tasks:
- name: Add a line to a file if the file does not exist, without passing regexp
lineinfile:
path: /tmp/testfile
line: 192.168.1.99 foo.lab.net foo
create: yes
验证 配置文件 修改后是否有效
validate:验证文件修改的有效性,需要文件自带验证机制
- hosts: 10.0.0.23
gather_facts: no
tasks:
- lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: "^Listen 80"
line: "Listen 9999"
# 验证文件修改的有效性,需要文件自带验证机制
validate: httpd -t -f %s
# backrefs:yes,就是regex如果没有匹配到行,line不会执行替换
backrefs: yes
validate
关键字后面的命令是httpd -t -f %s
,其作用解释如下:
httpd
:这是Apache HTTP服务器的二进制执行文件。-t
:这是测试配置文件的语法是否正确的选项。-f %s
:这是指定配置文件路径的选项,%s
是一个占位符,会被替换为被修改的文件的实际路径(即/etc/httpd/conf/httpd.conf
)。
当lineinfile
模块尝试替换httpd.conf
文件中的Listen 80
行时,Ansible会在 执行替换 之前、之后 用httpd -t -f /etc/httpd/conf/httpd.conf
命令来验证配置文件的语法。
Ansible会在 执行替换 之前、之后 检查配置文件是否正常(2次检查),如果配置文件验证不通过,则报错,不会修改配置文件
graph TB
%% s=start e=end f=fork n=normal
s([validate检查 配置文件 语法 流程图])-->f1{{检查 配置文件 是否 包含语法错误}};
%% 分支点1
f1--语法正常-->f2{{验证 执行替换后的配置文件 能否通过语法}};
f1-->f1_1([语法异常])-->f1_2[报错,取消修改配置文件]-->e([结束]);
%% 分支点2
f2--语法正常-->f2_1[完成替换]-->e;
f2-->f1_1;
# 在被控机上,把httpd的配置文件加上“aaa”,让它配置文件出错
[root@centos conf]# vim httpd.conf
#Listen 12.34.56.78:80
Listen 80
aaa
[root@centos conf]#
# 使用校验命令,可以看到报错的原因
[root@centos conf]# httpd -t -f /etc/httpd/conf/httpd.conf
AH00526: Syntax error on line 48 of /etc/httpd/conf/httpd.conf:
Invalid command 'aaa', perhaps misspelled or defined by a module not included in the server configuration
[root@centos conf]#
# 主控机:Ansible会在 执行替换之前 用`httpd -t -f /etc/httpd/conf/httpd.conf`命令来验证配置文件的语法
[root@rhel ~]# ansible-playbook validate
PLAY [10.0.0.23] ***************************************************************
TASK [lineinfile] **************************************************************
fatal: [10.0.0.23]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "msg": "failed to validate: rc:1 error:AH00526: Syntax error on line 48 of /root/.ansible/tmp/ansible-tmp-1725348932.5288007-26204-126713900772622/tmpo5gj8agj:\nInvalid command 'aaa', perhaps misspelled or defined by a module not included in the server configuration\n"}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
# 被控机,配置文件正常
[root@centos conf]# vim httpd.conf
#Listen 12.34.56.78:80
Listen 80
[root@centos conf]#
# 主控机:我们尝试 改个错误的配置,看下是否会修改、报错【结果在"msg"中提示报错】
[root@rhel ~]# cat validate
- hosts: 10.0.0.23
gather_facts: no
tasks:
- lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: "^Listen 80"
line: "Listen-- 80"
# 验证文件修改的有效性,需要文件自带验证机制
validate: httpd -t -f %s
[root@rhel ~]#
[root@rhel ~]# ansible-playbook validate
PLAY [10.0.0.23] ***************************************************************
TASK [lineinfile] **************************************************************
fatal: [10.0.0.23]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "msg": "failed to validate: rc:1 error:AH00526: Syntax error on line 47 of /root/.ansible/tmp/ansible-tmp-1725353490.8070686-26615-244536184511062/tmpowl_7iii:\nInvalid command 'Listen--', perhaps misspelled or defined by a module not included in the server configuration\n"}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
# 回到被控机查看 配置文件是否发生变化,结果不变
[root@centos conf]# vim httpd.conf
#Listen 12.34.56.78:80
Listen 80
[root@centos conf]#
7.2 blockinfile 修改多行
在Ansible中,blockinfile
模块用于管理文件中的多行文本块。
它允许你确保一个指定的文本块存在于文件中,或者如果该文本块不存在,则将其插入到文件中的特定位置
blockinfile
模块可以用来确保指定的文本块存在于文件中,或者在文件中不存在的情况下,将其插入到指定的位置
7.2.1 选项
# 常用参数 与 lineinfile 类似:
参数说明:
block:要插入的文本内容
marker:指定块标记,"# {mark} ANSIBLE块标记" mark这里是变量,因为块标记 上下各一行,到时候会输出为BEGIN、END
path # 【必须】要操作的文件路径。
block # 【必须】要插入或替换的文本块。
marker # 【可选】指定在文本块前后添加的标记字符串,用于识别文本块。默认为 # BEGIN ANSIBLE MANAGED BLOCK 和 # END ANSIBLE MANAGED BLOCK。
insertafter # 【可选】指定在文件中的哪个行之后插入文本块。可以是一个字符串,也可以是一个正则表达式。
insertbefore # 【可选】指定在文件中的哪个行之前插入文本块。可以是一个字符串,也可以是一个正则表达式。
state # 【可选】指定文本块应该存在 (present) 或不存在 (absent)。默认为 present。
create # 【可选】如果文件不存在,是否 创建文件。默认为 no。
[root@rhel ~]# cat validate
- hosts: 10.0.0.23
gather_facts: no
tasks:
- blockinfile:
path: /etc/httpd/conf/aaa
# 默认插入块,会在 插入块 的上方、下方 各有一行注释
block: |
1-1 : 1
2-1231
33033 3121- aa啊
[root@rhel ~]#
[root@rhel ~]# ansible-playbook validate
PLAY [10.0.0.23] ***************************************************************
TASK [blockinfile] *************************************************************
changed: [10.0.0.23]
PLAY RECAP *********************************************************************
10.0.0.23 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]# ansible 10.0.0.23 -m shell -a 'cat /etc/httpd/conf/aaa'
10.0.0.23 | CHANGED | rc=0 >>
1
2
3
Listen 80
# BEGIN ANSIBLE MANAGED BLOCK
1-1 : 1
2-1231
33033 3121- aa啊
# END ANSIBLE MANAGED BLOCK
[root@rhel ~]#
7.2.2 举例
增加多行内容
- hosts: 10.0.0.23
gather_facts: no
tasks:
- blockinfile:
path: /root/a.txt
create: yes
# 指定块标记。{mark} 这里是变量,因为块标记 上下各一行,到时候 mark会输出为BEGIN、END
marker: "# RHCE {mark} ansible blockinfile"
# 写个 | 表示下面的内容是插入
block: |
name=zhangsan
age=20
sex=boy
block 插入多行内容,marker做标记
# 过程
[root@rhel ~]# cat validate
- hosts: 10.0.0.23
gather_facts: no
tasks:
- name: 添加多行内容,并自义定标记块
blockinfile:
path: /root/a.txt
# 指定块标记
marker: "# RHCE {mark} ansible blockinfile"
block: |
1-1 : 1
2-1231
33033 3121- aa啊
[root@rhel ~]#
[root@rhel ~]# ansible 10.0.0.23 -m shell -a 'cat /root/a.txt'
10.0.0.23 | CHANGED | rc=0 >>
1
2
3
# BEGIN ANSIBLE MANAGED BLOCK
1-1 : 1
2-1231
33033 3121- aa啊
# END ANSIBLE MANAGED BLOCK
[root@rhel ~]#
[root@rhel ~]# ansible-playbook validate
PLAY [10.0.0.23] ***************************************************************
TASK [添加多行内容,并自义定标记块] ********************************************
changed: [10.0.0.23]
PLAY RECAP *********************************************************************
10.0.0.23 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]# ansible 10.0.0.23 -m shell -a 'cat /root/a.txt'
10.0.0.23 | CHANGED | rc=0 >>
1
2
3
# BEGIN ANSIBLE MANAGED BLOCK
1-1 : 1
2-1231
33033 3121- aa啊
# END ANSIBLE MANAGED BLOCK
手动备注:上面的是 是默认的块标记,下面是我指定的 块标记
# RHCE BEGIN ansible blockinfile
1-1 : 1
2-1231
33033 3121- aa啊
# RHCE END ansible blockinfile
[root@rhel ~]#
删除多行内容
说明
- 如果 不指定 marker标记,删除的则是默认创建出来的多行内容,也就是标记为
# BEGIN ANSIBLE MANAGED BLOCK
和# END ANSIBLE MANAGED BLOCK
中间的内容 - 如果 指定 marker标记,则删除的是 mark标记之间 的多行内容
- 删除标记的时候,因为我们用
{mark}
生成了BEGIN、END,所以写删除标记的语句,也要用{mark}
来代表 BEGIN、END - 比如
marker: "# RHCE {mark} ansible blockinfile"
就会匹配以下2个:# BEGIN ANSIBLE MANAGED BLOCK
# END ANSIBLE MANAGED BLOCK
- 删除标记的时候,因为我们用
- 如果有 多个marker标记是一样 的,则删除的是 末尾的marker标记中的内容;
删除的内容 有块标记
- hosts: 10.0.0.23
gather_facts: no
tasks:
- name: 删除多行,内容有 块标记
blockinfile:
path: /root/a.txt
create: yes
# 动作为删除
state: absent
# 指定块标记
marker: "# RHCE {mark} ansible blockinfile"
# 过程
[root@rhel ~]# cat rm_marker
- hosts: 10.0.0.23
gather_facts: no
tasks:
- name: 删除多行,内容有 块标记
blockinfile:
path: /root/a.txt
create: yes
# 动作为删除
state: absent
# 指定块标记
marker: "# RHCE {mark} ansible blockinfile"
[root@rhel ~]#
[root@rhel ~]# ansible 10.0.0.23 -m shell -a 'cat /root/a.txt'
10.0.0.23 | CHANGED | rc=0 >>
1
2
3
# BEGIN ANSIBLE MANAGED BLOCK
1-1 : 1
2-1231
33033 3121- aa啊
# END ANSIBLE MANAGED BLOCK
# RHCE BEGIN ansible blockinfile
1-1 : 1
2-1231
33033 3121- aa啊
# RHCE END ansible blockinfile
[root@rhel ~]#
[root@rhel ~]# ansible-playbook rm_marker
PLAY [10.0.0.23] ***************************************************************
TASK [删除多行,内容有 块标记] *************************************************
changed: [10.0.0.23]
PLAY RECAP *********************************************************************
10.0.0.23 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
[root@rhel ~]# ansible 10.0.0.23 -m shell -a 'cat /root/a.txt'
10.0.0.23 | CHANGED | rc=0 >>
1
2
3
# BEGIN ANSIBLE MANAGED BLOCK
1-1 : 1
2-1231
33033 3121- aa啊
# END ANSIBLE MANAGED BLOCK
[root@rhel ~]#
删除的内容 没有块标记
删除的内容 没有块标记,就需要配合lineinfile来进行使用。手动在 要删除的多行内容 前面、后面 添加上 块标记,然后把整个块标记删掉
- hosts: 10.0.0.23
gather_facts: no
tasks:
- name: 手动在要删除的多行内容 前面 添加上 块标记
lineinfile:
path: /root/a.txt
insertbefore: "2abc"
line: "# 块标记 BEGIN 块标记"
- name: 手动在要删除的多行内容 后面 添加上 块标记
lineinfile:
path: /root/a.txt
insertafter: "5abc"
line: "# 块标记 END 块标记"
- name: 删除多行(块标记内的内容)
blockinfile:
path: /root/a.txt
create: yes
# 动作为删除
state: absent
marker: "# 块标记 {mark} 块标记"
# 过程:删除a.txt文件中 从 2abc到5abc的内容
[root@rhel ~]# ansible 10.0.0.23 -m shell -a 'cat /root/a.txt'
10.0.0.23 | CHANGED | rc=0 >>
1
2abc
3
# BEGIN ANSIBLE MANAGED BLOCK
1-1 : 1
2-1231
33033 3121- aa啊
# END ANSIBLE MANAGED BLOCK
5abc
2
3
[root@rhel ~]#
[root@rhel ~]# ansible-playbook duohang
PLAY [10.0.0.23] ***************************************************************
TASK [手动在要删除的多行内容 前面 添加上 块标记] *******************************
changed: [10.0.0.23]
TASK [手动在要删除的多行内容 后面 添加上 块标记] *******************************
changed: [10.0.0.23]
TASK [删除多行(块标记内的内容)] **********************************************
changed: [10.0.0.23]
PLAY RECAP *********************************************************************
10.0.0.23 : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
[root@rhel ~]# ansible 10.0.0.23 -m shell -a 'cat /root/a.txt'
10.0.0.23 | CHANGED | rc=0 >>
1
2
3
[root@rhel ~]#
8 jinja2
8.1 jinja2 模板文件
8.1.1 说明
Jinja2是基于python的模板引擎
技术背景
如果要写配置文件,不需要大改,只要小改,比如 只要修改 100台被控机 各自的 ip、主机名。
因为 ip、主机名 每台机子都不一样,且绝大部分的配置其实都是相同的,只要修改 部分内容这个时候最好的方式:
用一个通用的配置文件(jinja2 模板文件)来解决所有的问题。
将 所有需要修改的地方 使用 变量替换
如下示例中 redis.conf.j2 文件,写完后我们使用 template 模块 来发送到被控机上,jinja2模版文件传到被控机后,会根据主机对应的 facts 事实变量,来替换变量的内容。过程参考 jinjia2简单例子
# 这是一个jinja2配置文件【需要修改成 被控机上的信息,使用变量来代替】
主机名是:{{ansible_hostname}}
IP地址是:{{ansible_ens160.ipv4.address}}
文件拓展名:*.j2
8.1.2 jinja2 语法
if判断
if判断的格式:
# if 判断语法:(表达式就是利用when判断的条件来判断)
{% if 表达式 %}
执行语句
{% elif 表达式 %}
执行语句
{% else %}
执行语句
{% endif %}
for循环
for循环的格式:
{% for 变量 in 循环体 %}
循环结构(执行语句)
{% endfor %}
8.2 template 模块
playbook使用 template
模块来实现 *.j2
模板文件的分发,
template 用法与copy模块基本相同,唯一的区别是:
- copy模块会将原文件原封不动的复制到被控端,
- template 会将原文件复制到被控端,并且 使用变量的值 将文件中的变量 替换 以生成完整的配置文件。
编写jinja2模板文件的注意事项:
不要关闭facts变量
,因为模板中的变量依赖于facts变量- 变量不需要使用
""
引号 引起来,template会自动识别到变量;
8.2.1 选项
src # 源模板文件路径
dest # 目标文件路径
group # 目标文件属组
mode # 目标文件的权限
owner # 目标文件属主
force # 是否强制覆盖,默认为yes
backup # 如果原目标文件存在,则先备份目标文件
8.3 过滤器
8.3.1 说明、语法格式
说白了就是 内置了不同方法的 命令
语法格式:
"{{ 变量名 | jinja2过滤器 }}"
使用defaul的jinja2过滤器
当变量没有定义值的时候,就会使用默认的值来进行代替
# defaul的jinja2过滤器 举例
[root@rhel ~]# cat defult
- hosts: 10.0.0.23
vars:
users:
- name: zhangsan
home: /opt/zhangsan
- name: lisi
tasks:
- debug:
msg: "name是:{{ item.name }} ,home是:{{ item.home|default('/tmp/defualt') }}"
loop: "{{ users }}"
[root@rhel ~]#
[root@rhel ~]# ansible-playbook defult
PLAY [10.0.0.23] **********************
TASK [debug] ************************
ok: [10.0.0.23] => (item={'name': 'zhangsan', 'home': '/opt/zhangsan'}) => {
"msg": "name是:zhangsan ,home是:/opt/zhangsan"
}
ok: [10.0.0.23] => (item={'name': 'lisi'}) => {
"msg": "name是:lisi ,home是:/tmp/defualt"
}
PLAY RECAP ***************************
10.0.0.23 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
常用的过滤器:
default
password_hash
dict2items
8.3.2 字符串操作
关键字 | 说明 |
---|---|
upper | 将所有字符串 转换为大写 |
lower | 将所有字符串 转换为小写 |
capitalize | 将字符串的首字母大写,其他字母小写 |
reverse | 将字符串倒序排列 |
first | 返回字符串的 第一个字符 |
last | 返回字符串的 最后一个字符 |
trim | 将字符串开头和结尾的空格 去掉 |
center(30) | 将字符串放在中间,并且字符串两边用空格补齐 30位 |
length | 返回字符串的长度 ,与count等价 |
list | 将字符串 转换为 列表 |
shuffle | list 将字符串转换为列表,但是顺序排列,shuffle同样将字符串转换为列表,但是会随机打乱字符串顺序 |
8.3.3 数字操作
关键字 | 说明 |
---|---|
int | 将对应的值转换为整数 |
float | 将对应的值转换为浮点数 |
abs | 获取绝对值 |
round | 小数点四舍五入 |
random | 从一个给定的范围中获取随机值 |
8.3.4 列表操作
关键字 | 说明 |
---|---|
length | 返回 列表长度 |
first | 返回 列表的第一个值 |
last | 返回 列表的最后一个值 |
min | 返回 列表中最小的值 |
max | 返回 列表中最大的值 |
sort | 重新排列列表 ,默认为升序排列,sort(reverse=true)为降序 |
sum | 返回 纯数字非嵌套列表中所有数字的和 |
flatten | 如果列表中包含列表,则flatten可拉平嵌套的列表,levels参数可用于指定被拉平的层级 |
join | 将列表中的元素合并为一个字符串 |
random | 从列表中随机返回 一个元素 |
union | 将两个列表合并 ,如果元素有重复,则只留下一个 |
intersect | 获取两个列表的交集 |
difference | 获取存在于第一个列表中,但不存在于第二个列表中的元素 |
symmetric_difference | 取出两个列表中各自独立的元素,如果重复则只留一个 |
8.4 举例
jinjia2简单例子
- 写 jinja2 模板文件
- 写剧本,把模板文件发到被控机
- 执行剧本
1. 写 jinja2 模板文件
[root@rhel ~]# cat jiaja2_test.j2
# 这是一个jinja2配置文件
主机名是:{{ansible_hostname}}
IP地址是:{{ansible_ens160.ipv4.address}}
[root@rhel ~]#
2. 写剧本,把模板文件发到被控机
[root@rhel ~]# cat j2_juben
- name: 剧本1
gather_facts: on
hosts: 10.0.0.23
tasks:
- name: "任务1: 将 模板文件 发送到被控端"
template:
src: /root/jiaja2_test.j2
dest: /root/jiaja2.conf
- name: "任务2: 查看文件内容"
shell: "cat /root/jiaja2.conf"
# 通过`register` 将 某一任务结果 保存为 一个变量
register: file_j2
- name: "任务3: 打印文件内容"
debug:
var: file_j2.stdout
[root@rhel ~]#
3. 执行剧本
[root@rhel ~]# ansible-playbook j2_juben
PLAY [剧本1] *************************************
TASK [Gathering Facts] ****************************
ok: [10.0.0.23]
TASK [任务1: 将 模板文件 发送到被控端] ***********
changed: [10.0.0.23]
TASK [任务2: 查看文件内容] *****************************
changed: [10.0.0.23]
TASK [任务3: 打印文件内容] **************************
ok: [10.0.0.23] => {
"file_j2.stdout": "# 这是一个jinja2配置文件\n\n主机名是:node01\nIP地址是:192.168.224.140"
}
PLAY RECAP ********************
10.0.0.23 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
if、elif 多重判断
例如:现在有多台主机,都需要跑httpd服务,每一个机器的80端口都是监听到本地的IP地址上,对于这种情况,就案例1:判断,如果被控节点有ens160网卡,那么就监听ens160网卡的IP地址;如果被控节点有ens224网卡,那么就监听ens224网卡的IP地址;如果都有没,则监听所有的IP地址。
{% if ansible_ens160 is defined %}
Listen {{ ansible_ens160.ipv4.address }}:80
{% elif ansible_ens224 is defined %}
Listen {{ ansible_ens224.ipv4.address }}:80
{% else %}
Listen 0.0.0.0:80
{% endif %}
案例2:如果是在node1主机上,则内容为 node1 is ok;如果是在node2主机上,则内容为 node2 is ok
{% if ansible_hostname == 'node1' %}
node1 is ok
{% elif ansible_hostname == 'node2' %}
node2 is ok
{% else %}
error
{% endif %}
for 循环
案例1:在node1主机上,在/etc/hosts中,包含所有主机的IP地址和FQDN(完整域名)和主机名的映射关系
[root@controller tmp]# cat for.j2
{% for i in groups.all %}
{{ hostvars[i].ansible_ens160.ipv4.address }} {{ hostvars[i].ansible_fqdn }} {{ hostvars[i].ansible_hostname }}
{% endfor %}
[root@controller tmp]#
[root@controller tmp]# cat for.yml
# 单独写个剧本,获取所有主机的 facts变量信息,供后面的剧本使用
- hosts: all
- hosts: node1
tasks:
- template:
src: /tmp/for.j2
dest: /opt/for
一定要注意的是,如果只指定node1节点,那么node2节点的facts变量就无法获取,也就无法得到node2节点的IP地址、FQDN、主机名等信息,所以需要 再写个剧本 来先获取其他主机的信息。
ansible__2928">9 ansible 角色、集合管理
参考RH294书籍内容
9.1 理论
角色的背景说明
背景说明
随着开发的 playbook增多,您可能会发现经常可以重用以前编写的 playbook中的代码。或许,您还可以改变 play 的用途,即将其为某个应用配置 MySOL数据库的用途改为为主机名、密码和用户均不同的另一应用配置 MySQL 数据库。但这个 play 可能比较冗长且复杂,有许多包含或导入的文件,以及用于管理各种情况的任务和处理程序。将所有这些代码复制到另- playbook 中可能并非易事。
Ansible角色 可让用户 以通用的方式 更加轻松地 重复利用 Ansible 代码。您可以采用标准化目录结构打包所有任务、变量、文件、模板,以及调配基础架构或部署应用所需的其他资源。通过复制相关的目录,将角色从一个项目复制到另一个项目,然后在 play 中调取该角色。
Ansible 角色具有下列优点(适用场景):
- 角色可以将内容分组在一起,从而与他人轻松共享代码。
- 角色可以定义系统类型的基本要素,如Web服务器、数据库服务器、Git存储库。
- 角色使得较大型项目 更容易管理。
- 角色可以由不同的用户 并行开发。
角色(roles)是一个包含 多个playbook 和 任务 的文件夹结构,它可以被重用
和共享
,从而提高了Ansible的代码组织和可维护性。【也可理解为是一种模块,比如python的包,你只要pip下载下来,引用一下就可以直接用了】
角色的引用语法
roles 的名字怎么看:
放角色目录的 目录名字,就是角色名 。
比如 我一个角色复制2份,改成不同的文件夹名,就可以当做2个角色用
引用的时候,用列表的形式
- name: 剧本1
gather_facts: false
hosts: 10.0.0.23
roles:
- hua
- hua-2
角色(roles)的目录结构
角色目录 底下会生成对应的 文件夹、文件,但并非每个角色都拥有所有这些目录。
子目录 | 功能 |
---|---|
defaults | 此目录中的main.yml 文件包含角色变量的默认值 ,使用角色时可以覆盖这些默认值。这些变量的优先级最低,应该在play中更改和自定义。 |
files | 此目录包含由角色任务引用的静态文件 ,如https证书 等。不要在放模版 |
handlers | 此目录中的main.yml 文件 用于定义角色中 需要调用 的 handlers特殊任务,可通过include引入其他的handlers文件。 |
meta | 此目录中的main.yml 文件包含与 角色相关的信息 ,如作者、许可证、平台和可选的角色依赖项。 |
tasks | 此目录中的main.yml 文件 包含 角色所 要执行的所有任务文件,可以在主文件中通过include的方式引入其他任务文件 |
templates | 此目录包含由角色任务引用的Jinja2模板 。当使用角色相关的模板时,如未明确指定模板路径,则默认使用此目录中的模板 |
tests | 此目录可以包含清单和test.ymlplaybook,可用于测试 角色。 |
vars | 此目录中的main.yml 文件定义角色的变量值 。这些变量通常用于角色内部用途。这些变量的优先级较高,在playbook中使用时不应更改。 |
默认路径:/etc/ansible/roles
通过修改ansible.cfg配置文件可以指定角色路径
[root@hn roles]# pwd
/etc/ansible/roles
[root@hn roles]# ll /etc/ansible/roles/apche/
总用量 4
drwxr-xr-x. 2 root root 22 9月 6 08:58 defaults
drwxr-xr-x. 2 root root 6 9月 6 08:58 files
drwxr-xr-x. 2 root root 22 9月 6 08:58 handlers
drwxr-xr-x. 2 root root 22 9月 6 08:58 meta
-rw-r--r--. 1 root root 1328 9月 6 08:58 README.md
drwxr-xr-x. 2 root root 22 9月 6 08:58 tasks
drwxr-xr-x. 2 root root 6 9月 6 08:58 templates
drwxr-xr-x. 2 root root 39 9月 6 08:58 tests
drwxr-xr-x. 2 root root 22 9月 6 08:58 vars
[root@hn roles]#
集合(collection)
集合 里面包含 role角色、插件、模块
获取集合:
Ansible Galaxy - 集合
使用集合
正常写模块调用就行
role和collection
ansible 版本来说:
ansible 2.9 之前,使用的是roles角色–> 普通文件、task任务、template模板文件、handlers特殊任务、变量文件…
ansible 2.9 之后,使用是集合 collection —> roles角色、plugin插件、module模块
ansible的模块需要额外安装,通过安装集合来得到对应的模块
RHEL9引入了容器运行ansible
role
在早期版本的Ansible中,role
是Ansible社区和组织角色的方式。一个 role
通常是一个文件夹,包含一系列任务、文件、模板、变量和其他与角色相关的文件。这些文件夹通常包含在Ansible的 roles/
目录下。
一个 role
定义了一组用于配置和管理服务器的任务,这些任务可以被重用和共享。例如,你可以创建一个名为 apache
的角色,它包含安装Apache服务器所需的所有任务。
collection
从Ansible 2.8开始,Ansible引入了 collection
概念。collection
是Ansible的新模块和角色组织方式,它取代了传统的 role
。一个 collection
是一个包,包含了多个模块、角色和插件。
与 role
相比,collection
有以下几个优点:
- 模块组织:
collection
可以包含多个模块,而不仅仅是角色。 - 更好的模块管理:
collection
提供了更强大的模块管理功能,包括版本控制和依赖管理。 - 更灵活的命名空间:
collection
允许你创建具有特定命名空间的模块和角色,这有助于避免命名冲突。 - 更强大的搜索功能:
collection
提供了更强大的搜索功能,允许你根据模块的名称、描述和作者进行搜索。
要使用 collection
,你需要安装它们。你可以使用 ansible-galaxy
命令来安装和更新 collection
。
总结
role
和 collection
都是用于组织和分享Ansible模块和角色的概念,但 collection
是Ansible 2.8及更高版本中的新方式,它提供了更多的功能和改进。如果你使用的是Ansible 2.8或更高版本,建议使用 collection
来组织和管理你的Ansible模块和角色。
galaxy网站、文档
Ansible Galaxy - 可以下载角色、集合
角色 — Ansible 社区文档
ansiblegalaxy__3053">9.2 ansible-galaxy 角色、集合管理命令
ansible-galaxy
是 Ansible 提供的命令行工具,它可以管理 角色role
、集合collection
执行各种与角色和集合相关的操作。
collection -- Manage an Ansible Galaxy collection. 管理Ansible Galaxy集合。
role -- Manage an Ansible Galaxy role. 管理Ansible Galaxy角色。
9.2.1 常用命令
官网: https://galaxy.ansible.com/
# --角色管理--
ansible-galaxy role init 角色名 # 初始化一个 角色(roles)的目录结构
ansible-galaxy role search 角色名 # 搜索role
ansible-galaxy role install 角色名 # 从文件、URL、Ansible Galaxy安装角色
-r 指定文件,从文件中下载
-p 指定安装到哪个路径
ansible-galaxy role list # 列出已安装的 roles
ansible-galaxy role info 角色名 # 查看已安装的 roles 信息
ansible-galaxy role remove 角色名 # 卸载roles
# --集合管理--
ansible-galaxy collection init # 使用集合的基本结构 初始化 新集合。
ansible-galaxy collection list # 显示collections_path中安装的每个集合的名称和版本
ansible-galaxy collection install # 从文件、URL、Ansible Galaxy安装集合
ansible-galaxy collection install 集合的url路径 # 在线安装 集合
ansible-galaxy collection install 下载好的集合压缩包 # 从文件 离线安装 集合
9.2.2 举例-角色管理
初始化角色目录结构
角色的名字就是目录的名字,通过ansible-galaxy role init 要生成的角色名
可以 初始化角色目录结构,生成目录和文件
[root@hn roles]# pwd
/etc/ansible/roles
[root@hn roles]# ls
[root@hn roles]#
# 通过`ansible-galaxy role init 要生成的角色名` 可以 初始化角色目录结构
[root@hn roles]# ansible-galaxy role init apche
- Role apche was created successfully
[root@hn roles]#
[root@hn roles]# ls
apche
[root@hn roles]# tree /etc/ansible/roles/apche/
/etc/ansible/roles/apche/
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
8 directories, 8 files
[root@hn roles]#
调用role角色执行任务
[root@controller ansible]# cat roles.yml
- hosts: all
roles:
- apache
安装角色roles
- 通过 galaxy.ansible.com 获取
- Ansible Galaxy - 角色
- 通过本地的软件包,
rhel-system-roles 红帽系统角色
(selinux firewalld chrony时间同步。。。。)- yum install rhel-system-roles -y
- rpm -ql all rhel-system-roles 看释放的文件,看下装在哪
- /usr/share/ansible/roles 安装的角色目录
ansible-galaxy role init 角色名 # 初始化一个 角色(roles)的目录结构
ansible-galaxy role search 角色名 # 搜索role
ansible-galaxy role install 角色名 # 从文件、URL、Ansible Galaxy安装角色
-r 指定文件,从文件中下载
-p 指定安装到哪个路径
ansible-galaxy role list # 列出已安装的 roles
# 安装角色,下载地址放在在一个yml文件中,安装到/etc/ansible/roles这个路径中
[root@controller ansible]# cat nginx.yml
- name: github.nginx
src: https://github.com/noobient/ansible-galaxy-nginx/archive/main.tar.gz
[root@controller ansible]# ansible-galaxy role install -r nginx.yml -p /etc/ansible/roles
- downloading role from https://github.com/noobient/ansible-galaxy-nginx/archive/main.tar.gz
- extracting github.nginx to /etc/ansible/roles/github.nginx
- github.nginx was installed successfully
[root@controller ansible]# ls roles
apache github.nginx jengsala.nginx nginx selinux timesync
# 指定安装目录,安装到/root/mulu1
[root@hn roles]# ansible-galaxy role install MD-SAUBAN-KHAN.dummy-mdsk-ansible-galaxy -p /root/mulu1
Starting galaxy role install process
- downloading role 'dummy-mdsk-ansible-galaxy', owned by MD-SAUBAN-KHAN
- downloading role from https://github.com/MD-SAUBAN-KHAN/dummy-mdsk-ansible-galaxy/archive/main.tar.gz
- extracting MD-SAUBAN-KHAN.dummy-mdsk-ansible-galaxy to /root/mulu1/MD-SAUBAN-KHAN.dummy-mdsk-ansible-galaxy
- MD-SAUBAN-KHAN.dummy-mdsk-ansible-galaxy (main) was installed successfully
[root@hn roles]#
[root@hn roles]# ls /root/mulu1
1.t 2.t 3.t MD-SAUBAN-KHAN.dummy-mdsk-ansible-galaxy
[root@hn roles]#
查询已安装的角色
ansible-galaxy role list # 列出已安装的 roles
ansible-galaxy role info 角色名 # 查看已安装的 roles 信息
# 列出你各个路径下的角色
[root@hn roles]# ansible-galaxy role list
# /usr/share/ansible/roles
- rhel-system-roles.metrics, (unknown version)
- linux-system-roles.ad_integration, (unknown version)
。。。。。
# /etc/ansible/roles
- apche, (unknown version)
- abc, (unknown version)
- bbb, (unknown version)
[WARNING]: - the configured path /root/.ansible/roles does not exist.
[root@hn roles]#
include_tasks 引入task任务文件
类似python,全部代码写一个文件里,就太多了,不好浏览;
我们给他分到不同文件中,再引用,代码就看着比较简洁
include_tasks
是一个模块,它允许你在playbook中 引入(导入) 其他playbook 或 task任务文件。类似于编程中的“导入”概念
使用 include_tasks
模块可以大大提高playbook的可维护性和可重用性。它允许你将 任务 逻辑分离到 不同的文件中,并轻松地在不同的playbook中复用(引用)这些任务。
# 当任务较多时,可以将任务分开写到不同文件
[root@ansible nginx]# tree tasks/
tasks/
├── main.yml
├── nginx1.yml
└── nginx2.yml
# 通过 include_tasks 引入任务
[root@ansible tasks]# cat main.yml
- include_tasks:
file: nginx1.yml
- include_tasks:
file: nginx2.yml
编写角色 并执行
编写一个角色,并执行它【就跟写正常的剧本差不多,只不过更加模块化】
- 初始化角色目录结构
- 在角色目录中编写任务、变量
- 在 tasks 目录里 main.yml 写任务
- 任务1:获取date命令的输出值
- 任务2:打印 获取命令的输出值
- 任务3:打印 vars目录 里定义的变量 var_1
- 任务4:执行引入的外部任务 include_tasks
- 在 vars 目录里 写我们的变量
- 在 tasks 目录里 main.yml 写任务
- 写剧本,引用角色,执行
# 1. 初始化角色目录结构
[root@rhel roles]# ansible-galaxy role init hua
- Role apche was created successfully
[root@rhel roles]#
[root@rhel roles]# tree hua/
hua/
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ ├── main.yml
│ └── task_1.yml # 这里是我后面手动建立的文件
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
8 directories, 9 files
[root@rhel roles]#
# 2. 在角色目录中编写任务、变量
# 2.1. 在 tasks 目录里 main.yml 写任务
[root@rhel roles]# cd hua/
[root@rhel hua]# cat tasks/main.yml
---
# tasks file for hua
- name: 任务1:获取命令的输出值
set_fact:
time_info: "{{ lookup('pipe', 'date +%Y-%m-%d--%H:%M:%S') }}"
- name: 任务2:打印 获取命令的输出值
debug:
msg: "命令的输出:{{ time_info }}"
- name: 任务3:打印 vars目录 里定义的变量 var_1
debug:
msg: "打印 vars目录 里定义的变量 var_1:{{ var_1 }}"
- name: 任务4:执行引入的外部任务(include_tasks)
include_tasks:
file: task_1.yml
[root@rhel hua]#
[root@rhel hua]# cat tasks/task_1.yml
- name: 外部任务1
debug:
msg: "外部任务1"
[root@rhel hua]#
# 2.2. 在 vars 目录里 写我们的变量
[root@rhel hua]# cat vars/main.yml
---
# vars file for hua
var_1: "我是变量var_1"
var_2: "我是变量var_2"
[root@rhel hua]#
# 3. 写剧本,引用角色,执行
[root@rhel ~]# cat role_test
- name: 剧本1
gather_facts: false
hosts: 10.0.0.23
roles:
- hua
[root@rhel ~]# ansible-playbook role_test
PLAY [剧本1] ************************************************************************
TASK [hua : 任务1:获取命令的输出值] ************************************************
ok: [10.0.0.23]
TASK [hua : 任务2:打印 获取命令的输出值] *********************************************
ok: [10.0.0.23] => {
"msg": "命令的输出:2024-09-10--15:36:31"
}
TASK [hua : 任务3:打印 vars目录 里定义的变量 var_1] ********************************
ok: [10.0.0.23] => {
"msg": "打印 vars目录 里定义的变量 var_1:我是变量var_1"
}
TASK [hua : 任务4:执行引入的外部任务(include_tasks)] *******************************
included: /etc/ansible/roles/hua/tasks/task_1.yml for 10.0.0.23
TASK [hua : 外部任务1] **************************************************************
ok: [10.0.0.23] => {
"msg": "外部任务1"
}
PLAY RECAP **************************************************************************
10.0.0.23 : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
在执行任务前后,先执行指定任务
pre_tasks
会在 执行 playbook 之前 执行 pre_tasks 任务,
post_tasks
会在 执行 playbook 之后 执行 post_tasks 任务;
我的实验结果是 pre_tasks
和 post_tasks
任务块是在整个 playbook 执行 之前和之后
执行上面两种特殊task任务的时候,顺序无要求。
ansible playbook play task执行顺序_ansible task 内部执行顺序-CSDN博客
角色的内容就是这个例子的: 编写角色 并执行
# pre_tasks和post_tasks 举例
[root@rhel ~]# cat role_test
- name: 剧本1
gather_facts: false
hosts: 10.0.0.23
# 执行2个角色,第二个是复制第一个的,功能一样。
roles:
- hua
- hua-2
tasks:
- name: 常规任务1
debug:
msg: "常规任务1"
- name: 常规任务2
debug:
msg: "常规任务2"
pre_tasks:
- name: pre_tasks 任务
debug:
msg: "pre_tasks 会在 执行 playbook 之前 执行 pre_tasks 任务"
post_tasks:
- name: post_tasks 任务
debug:
msg: "post_tasks 会在 执行 playbook 之后 执行 post_tasks 任务"
[root@rhel ~]#
[root@rhel ~]#
[root@rhel ~]# ansible --version
ansible [core 2.14.14]
# 执行过程
[root@rhel ~]# ansible-playbook role_test
PLAY [剧本1] ************************************************************************
TASK [pre_tasks 任务] ***************************************************************
ok: [10.0.0.23] => {
"msg": "pre_tasks 会在 执行 playbook 之前 执行 pre_tasks 任务"
}
TASK [hua : 任务1:获取命令的输出值] ************************************************
ok: [10.0.0.23]
TASK [hua : 任务2:打印 获取命令的输出值] *******************************************
ok: [10.0.0.23] => {
"msg": "命令的输出:2024-09-10--16:32:28"
}
TASK [hua : 任务3:打印 vars目录 里定义的变量 var_1] ********************************
ok: [10.0.0.23] => {
"msg": "打印 vars目录 里定义的变量 var_1:我是变量var_1"
}
TASK [hua : 任务4:执行引入的外部任务(include_tasks)] *******************************
included: /etc/ansible/roles/hua/tasks/task_1.yml for 10.0.0.23
TASK [hua : 外部任务1] **************************************************************
ok: [10.0.0.23] => {
"msg": "外部任务1"
}
TASK [hua-2 : 任务1:获取命令的输出值] **********************************************
ok: [10.0.0.23]
TASK [hua-2 : 任务2:打印 获取命令的输出值] *****************************************
ok: [10.0.0.23] => {
"msg": "命令的输出:2024-09-10--16:32:28"
}
TASK [hua-2 : 任务3:打印 vars目录 里定义的变量 var_1] ******************************
ok: [10.0.0.23] => {
"msg": "打印 vars目录 里定义的变量 var_1:我是变量var_1"
}
TASK [hua-2 : 任务4:执行引入的外部任务(include_tasks)] *****************************
included: /etc/ansible/roles/hua-2/tasks/task_1.yml for 10.0.0.23
TASK [hua-2 : 外部任务1] ************************************************************
ok: [10.0.0.23] => {
"msg": "外部任务1"
}
TASK [常规任务1] ********************************************************************
ok: [10.0.0.23] => {
"msg": "常规任务1"
}
TASK [常规任务2] ********************************************************************
ok: [10.0.0.23] => {
"msg": "常规任务2"
}
TASK [post_tasks 任务] **************************************************************
ok: [10.0.0.23] => {
"msg": "post_tasks 会在 执行 playbook 之后 执行 post_tasks 任务"
}
PLAY RECAP **************************************************************************
10.0.0.23 : ok=14 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
9.2.3 举例-集合管理
安装集合
在 Ansible Galaxy - 集合 这个网址里搜要用的 集合、角色等,然后点进去,就会有提示怎么安装
如果要修改 集合的默认安装位置,进/etc/ansible/ansible.cfg
修改collections_path这、行
[root@rhel ansible]# vim ansible.cfg
57 ;collections_path={{ ANSIBLE_HOME ~ "/collections:/usr/share/ansible/collections" }}
安装集合:
ansible-galaxy collection install (集合的URL 或者 集合的tar包) -p 执行路径
# 如果在线安装失败,也可以把包下载下来,进行离线安装,离线安装 直接接上压缩包名就行
[root@rhel ~]# ansible-galaxy collection install community.general.tar.fz
# 过程,在线安装 community.general
[root@rhel ~]# ansible-galaxy collection install community.general
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Downloading https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/community-general-9.3.0.tar.gz to /root/.ansible/tmp/ansible-local-372411hvy0jnl/tmpx3s0hrv1/community-general-9.3.0-dvpjtoc3
Installing 'community.general:9.3.0' to '/root/.ansible/collections/ansible_collections/community/general'
community.general:9.3.0 was installed successfully
翻译后2句
正在将 'community.general:9.3.0' 安装到 '/root/.ansible/collections/ansible_collections/community/general'
community.general:9.3.0已成功安装
[root@rhel ~]#
[root@rhel ~]# ansible-doc -l | grep general | wc -l
595
[root@rhel ~]#
[root@rhel ~]# cd /root/.ansible/collections/ansible_collections/community/general
[root@rhel general]# ls
CHANGELOG.md changelogs docs meta
CHANGELOG.md.license commit-rights.md FILES.json plugins
CHANGELOG.rst CONTRIBUTING.md LICENSES README.md
CHANGELOG.rst.license COPYING MANIFEST.json tests
[root@rhel general]#
ansiblevault__3554">10 ansible-vault 加解密文件
10.1 选项
ansible-vault create 文件名 # 创建 加密 文件【会提示输加密的密码,然后进去修改文件】
ansible-vault decrypt 文件名 # 解密 加密文件
ansible-vault encrypt 文件名 # 加密 已存在的文件
ansible-vault rekey 文件名 # 修改 加密文件密码
ansible-vault view 文件名 # 查看 加密 文件【输完会显示文件内容】
# 指定密码文件【如果密码存在文件里,通过这种方式指定】
--vault-password-file=passwd.txt
10.2 例子
执行一个 加密的剧本
# 执行一个加密的剧本:
# 1. 在命令行直接输入密码 --ask-vault-pass
ansible-playbook debug.yml --ask-vault-pass
# 2. 通过 密码文件执行playbook
ansible-playbook debug.yml --vault-password-file=passwd.txt
创建 加密文件
# 创建 加密 文件【会提示输加密的密码,然后进去修改文件】
[root@rhel ~]# ansible-vault create aaaa
New Vault password:
Confirm New Vault password:
[root@rhel ~]#
加密 已存在的文件
# 1. 在命令行直接输入密码
[root@hn ~]# ansible-vault encrypt 1.txt
New Vault password: 1
Confirm New Vault password: 1
Encryption successful
[root@hn ~]#
[root@hn ~]#
[root@hn ~]# cat 1.txt
$ANSIBLE_VAULT;1.1;AES256
38316337613732356165363239323833393362373865363834626661303464373838383961386434
3737383339653432373435333961。。。。。。。。
解密 已经加密的文件
[root@hn ~]# ansible-vault decrypt 1.txt
Vault password:
Decryption successful
[root@hn ~]#
修改 加密文件密码
# 修改 加密文件密码
[root@rhel ~]# ansible-vault rekey aaaa
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful
[root@rhel ~]#
查看 加密文件 内容
# 查看 加密 文件【输完密码会显示文件内容】
[root@rhel ~]# ansible-vault view aaaa
Vault password:
123456
[root@rhel ~]#
ansiblenavigator__3646">11 ansible-navigator 导航器
11.1 说明
第 1 章 Ansible 内容导航器简介 | Red Hat Product Documentation
第 6 章 使用自动化内容导航器运行 Ansible playbook | Red Hat Product Documentation
Ansible Automation Platform - 用 Ansible Navigator 和 Execution Environment 镜像开发测试 Playbook_ansible-navigator-CSDN博客
新版 Ansible Automation Platform 为 Ansible Playbook 的开发人员提供了 ansible-navigator
命令,它可以替代以前 ansible、ansible-vault、ansible-config、ansible-inventory 等多个命令。原有命令和 ansible-navigator 命令对应关系如下:
ansible 命令 | ansible-navigator 对应命令 |
---|---|
ansible | ansible-navigator exec – ansible |
ansible-builder | ansible-navigator builder |
ansible-config | ansible-navigator config |
ansible-doc | ansible-navigator doc |
ansible-inventory | ansible-navigator inventory |
ansible-galaxy | ansible-navigator exec – ansible-galaxy |
ansible-lint | ansible-navigator lint |
ansible-playbook | ansible-navigator run |
ansible-test | ansible-navigator exec – ansible-test |
ansible-vault | ansible-navigator exec – ansible-vault |
11.2 选项
# 常用选项
--eei # 指定执行的 ee镜像名称(查看的时候会显示默认值)
--eev # 指定 要在执行环境中 绑定装载的卷
-i # 指定 主机清单
-m # 指定 用户界面模式(stdout 命令行输出 |interactive 交互式,就进入到图形化界面)(默认:交互式)
# 常用子命令 Subcommands【首次执行 ansible-navigator 命令 会自动下载 容器运行环境(ee镜像)】
# 使用导航器运行ansible的playbook,无法执行ad-hoc指令
# ---执行剧本---
# 每次执行剧本时,是在容器中执行,同时会在当前目录 生成日志文件;
ansible-navigator run 剧本.yml # 执行剧本
# ---查看---
# 查看所有的主机
ansible-navigator inventory --list -m stdout -i /etc/ansible/hosts
# 可视化模式列出所有的主机
ansible-navigator inventory --list -i /etc/ansible/hosts
ansible-navigator images # 查看 ee镜像(Ansible Execution Environment 可靠的执行环境)
ansible-navigator --version # 显示 ansible-navigator 的版本信息
ansible-navigator config dump # 显示当前的配置信息
ansible-navigator config set # 设置配置选项
ansible-navigator config view # 查看配置文件
# ---帮助---
ansible-navigator --help # 显示帮助信息
ansible-navigator run --help # 显示 run 命令的帮助信息
# ---查看模块文档 【没 ansible-doc 那么方便的 搜索】---
ansible-navigator doc -l # 查看导航器的模块
ansible-navigator doc 模块名 # 查看 Ansible模块 的文档
# 举例:查看 vmware.vmware_rest.vcenter_vm_hardware_cpu_info模块 的帮助信息
ansible-navigator doc vmware.vmware_rest.vcenter_vm_hardware_cpu_info
[root@controller ~]# cat .ansible-navigator.yml
ansible-navigator:
execution-environment:
image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8
pull:
policy: missing
11.3 举例
ansiblenavigator_3752">安装ansible-navigator
- 直接用 pip 指定个国内源,安装 ansible-navigator
- 下载 EE 镜像(Ansible Execution Environment 可靠的执行环境)
- 下载ee镜像后就可以 ansible-navigator 使用了
pip install ansible-navigator -i https://mirrors.aliyun.com/pypi/simple/
ansible-navigator
[root@rhel ~]# pip install ansible-navigator -i https://mirrors.aliyun.com/pypi/simple/
....
[root@rhel ~]#
[root@rhel ~]# ansible-navigator --version
ansible-navigator 24.2.0
[root@rhel ~]#
### images--探索执行环境映像。
### 如果 从红帽仓库中 拉取 ee镜像【要登录、要权限,有开发者订阅可以直接拉取】
### 这里拉取的镜像是 ghcr.io/ansible/creator-ee:v0.22.0
[root@rhel ~]# ansible-navigator imagees
---------------------------------------------------------------------
Execution environment image and pull policy overview
---------------------------------------------------------------------
Execution environment image name: ghcr.io/ansible/creator-ee:v0.22.0
Execution environment image tag: v0.22.0
Execution environment pull arguments: None
Execution environment pull policy: tag
Execution environment pull needed: True
---------------------------------------------------------------------
Updating the execution environment
---------------------------------------------------------------------
Running the command: podman pull ghcr.io/ansible/creator-ee:v0.22.0
Trying to pull ghcr.io/ansible/creator-ee:v0.22.0...
Getting image source signatures
### 安装后(下好了ee镜像)
[root@rhel ~]# ansible-navigator images
Image Tag Execution environment Created Size
0│ansible-navigator-demo-ee latest True 3 years ago 1.35 GB
^b/PgUp page up ^f/PgDn page down ↑↓ scroll esc back [0-9] goto :help help
执行剧本
# 每次执行剧本时,是在容器中执行,同时会在当前目录 生成日志文件;
ansible-navigator run 剧本.yml # 执行剧本
-i # 指定 主机清单
-m # 指定 用户界面模式(stdout 命令行输出 |interactive 交互式,就进入到图形化界面)(默认:交互式)
[root@rhel ~]# ansible-navigator run mok.yml -m stdout
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'
[WARNING]: Could not match supplied host pattern, ignoring: 10.0.0.23
PLAY [剧本1] *******************************************************************
skipping: no hosts matched
PLAY RECAP *********************************************************************
[root@rhel ~]#
# 执行剧本。指定 用户界面模式 stdout 命令行输出
[root@rhel ~]# ansible-navigator run mok.yml -i /etc/ansible/hosts -m stdout
PLAY [剧本1] *******************************************************************
TASK [任务1] *******************************************************************
changed: [10.0.0.23]
TASK [任务2] *******************************************************************
ok: [10.0.0.23] => {
"msg": "输出结果: {'cmd': 'ls ./', 'stdout': '公共\\n模板\\n视频\\n图片\\n文档\\n下载\\n音乐\\n桌面\\nanaconda-ks.cfg\\ninitial-setup-ks.cfg\\ninstall_zabbix_server6.0.sh\\nrhel9.txt', 'stderr': '', 'rc': 0, 'start': '2024-09-07 18:40:47.722297', 'end': '2024-09-07 18:40:47.728229', 'delta': '0:00:00.005932', 'changed': True, 'stdout_lines': ['公共', '模板', '视频', '图片', '文档', '下载', '音乐', '桌面', 'anaconda-ks.cfg', 'initial-setup-ks.cfg', 'install_zabbix_server6.0.sh', 'rhel9.txt'], 'stderr_lines': [], 'ansible_facts': {'discovered_interpreter_python': '/usr/libexec/platform-python'}, 'failed': False}"
}
PLAY RECAP *********************************************************************
10.0.0.23 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@rhel ~]#
# 执行剧本。默认指定 用户界面模式 interactive 交互式,就进入到图形化界面
[root@rhel ~]# ansible-navigator run mok.yml -i /etc/ansible/hosts
剧本名称 确定 更改 无法访问 失败 跳过 忽略 进行中 任务计数 进度
Play name Ok Changed Unreachable Failed Skipped Ignored In progress Task count Progress
0│剧本1 2 1 0 0 0 0 0 2 Complete
^b/PgUp page up ^f/PgDn page down ↑↓ scroll esc back [0-9] goto :help help Successful
# --- 按对应的数字编号。按0,进入查看详细信息
Result Host Number Changed Task Task action Duration
0│Ok 10.0.0.23 0 True 任务1 shell 1s
1│Ok 10.0.0.23 1 False 任务2 debug 0s
# --- 按对应的数字编号,还能进入查看详细信息
Play name: 剧本1:1
Task name: 任务2
Ok: 10.0.0.23 输出结果: {'cmd': 'ls ./', 'stdout': '公共\n模板\n视频\n图片\n文档\n下载\n音乐'
0│--- ▒
1│duration: 0.01563 ▒
2│end: '2024-09-07T10:43:34.252087+00:00' ▒
3│event_loop: null ▒
4│host: 10.0.0.23
5│play: 剧本
6│play_pattern: 10.0.0.23
7│playbook: /root/mok.yml
8│remote_addr: 10.0.0.23
9│res: ▒
10│ _ansible_no_log: false ▒
11│ _ansible_verbose_always: true ▒
12│ changed: false ▒
13│ msg: '输出结果: {''cmd'': ''ls ./'', ''stdout'': ''公共\n模板\n视频\n图片\n文档\n下载\▒
14│ ''stderr'': '''', ''rc'': 0, ''start'': ''2024-09-07 18:43:34.147539'', ''end'': ▒
15│ ''2024-09-07 18:43:34.153046'', ''delta'': ''0:00:00.005507'', ''changed'': True, ▒
16│ ''stdout_lines'': [''公共'', ''模板'', ''视频'', ''图片'', ''文档'', ''下载'', ''音乐17│ ''anaconda-ks.cfg'', ''initial-setup-ks.cfg'', ''install_zabbix_server6.0.sh'', ▒
18│ ''rhel9.txt''], ''stderr_lines'': [], ''ansible_facts'': {''discovered_interpreter_p▒
19│ ''/usr/libexec/platform-python''}, ''failed'': False}' ▒
20│resolved_action: debug ▒
21│start: '2024-09-07T10:43:34.236457+00:00' ▒
22│task: 任务 ▒
23│task_action: debug ▒
24│task_args: '' ▒
25│task_path: /root/mok.yml:9
指定默认使用的 EE 镜像
如果要自定义默认的ee镜像,要在当前用户家目录 中创建内容如下的 .ansible-navigator.yml
文件
cat > ~/.ansible-navigator.yml << EOF
ansible-navigator:
execution-environment:
image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest
EOF
查看ee镜像信息
查看 ee镜像(Ansible Execution Environment 可靠的执行环境)
ansible-navigator images
[root@rhel ~]# ansible-navigator images
Image Tag Execution environment Created Size
0│ansible-navigator-demo-ee latest True 3 years ago 1.35 GB
^b/PgUp page up ^f/PgDn page down ↑↓ scroll esc back [0-9] goto :help help
--- 输入对应数字编号,查看镜像的详细信息
Image: ansible-navigator-demo-ee:latest Description
0│Image information Information collected from image inspection # 镜像信息
1│General information OS and python version information # 操作系统和python版本信息
2│Ansible version and collections Information about ansible and ansible collections # 关于ansible和ansible集合的信息
3│Python packages Information about python and python packages # 关于python和python包的信息
4│Operating system packages Information about operating system packages # 关于操作系统软件包的信息
5│Everything All image information # 所有镜像信息
查看主机清单的主机
# 可视化模式列出所有的主机
# 用数字选择
[root@rhel ~]# ansible-navigator inventory --list -i /etc/ansible/hosts
Title Description
0│Browse groups Explore each inventory group and group members members # 浏览每个库存 组和组成员
1│Browse hosts Explore the inventory with a list of all hosts # 浏览包含 所有主机列表 的资源清册
^b/PgUp page up ^f/PgDn page down ↑↓ scroll esc back [0-9] goto :help help
--- # 浏览每个库存 组和组成员
Name Taxonomy Type
0│host_group all group
1│ungrouped all group
--- # 浏览包含 所有主机列表 的资源清册
Inventory hostname
0│10.0.0.23
1│host1
# 查看所有的主机
[root@rhel ~]# ansible-navigator inventory --list -m stdout -i /etc/ansible/hosts
{
"_meta": {
"hostvars": {
"10.0.0.23": {
"rhel_name": "rhel9"
},
"host1": {
"ansible_host": "10.0.0.23",
"group_name": "itgroup"
}
}
},
"all": {
"children": [
"host_group",
"ungrouped"
]
},
"host_group": {
"hosts": [
"host1"
]
},
"ungrouped": {
"hosts": [
"10.0.0.23"
]
}
}
[root@rhel ~]#