Ansible的简介及安装
Ansible的介绍
ansible是一个自动化工具(ansible引擎)使用python进行开发,高度依赖python通过GPLv2进行开源,帮助系统管理完成系统的批量配置、软件包的部署、更新、以及对复杂逻辑任务的批量处理
举例: 如果需要使用ansible来完成一套企业网站业务部署,ansible可以完成那些操作???
1
基础架构(机房、服务器、网络设备、空调、带宽...) X
2
服务器安装操作系统 X
3
做操作系统的初始化配置(配置防火墙、SElinux的策略、配置内核参数等....) √
4
安装web软件(Nginx/Apache) √
5
安装各种中间件(mysql、redis) √
6
调试web软件和中间件 √
7
安装脚本程序(php、java) √
8
发布网站的源码 √
9
测试并访问网站 √
ansible的特点:
1
ansible没有任何服务需要启动,是一个命令行工具,任何系统用户都可以使用该工具
2
ansible没有任何客户端程序去安装到被控端,全部都是基于应用原生的方式来对应用本身进行管理
windows ——> winrm(remote manager) windows的远程管理 进行管理
Linux ——> ssh 进行管理
网络设备(路由器、交换机) ———> snmp简单的网络管理协议进行管理
存储 ——> 通过存储本身的api接口来进行管理
虚拟化 ——> vmware通过api接口进行管理 kvm通过libvirt+ssh进行管理
openstack/公有云 ——> 通过云的API来进行管理
3
Ansible 通过模块来完成任务的执行,ansible的模块可以使用任意的语言进行开发,甚至可以使用shell来开发模块 ansible2.9版本中有3000+以上的模块
4
Ansible支持在各种复杂环境中的部署 可以部署在单机上、容器上、云上
5
Ansible可以兼容主流的操作系统(Linux、windows、MAc OS)甚至是云系统,但是只有Linux能作为主控节点
6
Ansible通过两个方式来执行任务;ansible使用ad-hoc(临时命令)来执行简单的任务、使用playbook(剧本)来执行复杂的任务(也就是使用临时命令执行简单任务、剧本执行复杂任务)
ansible的架构
Ansible的核心:ansible的主程序
inventory: 主机清单(定义是被管理的对象,可以是服务器、网络设备、云等都称为主机)
playbook:剧本 是一系列任务的集合,所有想要执行的任务都可以在playbook中定义(剧本是ansible的灵魂)
核心Modules: ansible常用的模块 在ansible2.9以前会自带大量常用任务模块,在2.10开始ansible只会携带非常核心模块
扩展Modules: 扩展模块是为了弥补核心模块的不足,通常这一类模块都是特定厂商独立开发
Connection Plugin: 连接插件 ,连接插件定义ansible连接到远程主机的方式(也就是连接到被控的方式)
Plugin: 专门用来弥补模块功能的不足,例如对变量进行转换,记录日志等
Ansible的工作流程:
Ansible 根据用户在playbook中定义的任务和主机,在主机清单中选择相应的主机通过连接插件连接到被控端、然后将playbook中的定义的任务选择相应的模块,将模块通过连接插件推送到被控端,在被控端上执行模块的任务,然后删除模块,因此可以通过版本管理系统例如svn/git等,对ansible的playbook进行版本的跟踪管理维护,最大限度重复利用palybook 进行自动化
解析Inventory文件:在Ansible执行任何任务之前,需要先解析Inventory文件以确定被管理节点的位置和角色。Inventory文件是一个文本文件,它描述了被管理节点的名称、IP地址、主机组信息等。
SSH连接到被管理节点:Ansible使用SSH协议或WinRM协议连接到被管理节点,这取决于节点操作系统的不同。在连接时,Ansible会验证SSH密钥并启动一个临时的SSH连接进程。
执行任务:连接建立后,Ansible通过模块执行任务。模块是Ansible执行每个任务的工具,如文件操作、软件包安装、服务启动等。Ansible会将任务分发给所有被管理节点,并在这些节点上执行相应的操作。当任务执行完成后,Ansible会收集任务执行结果并返回给控制节点。
关闭连接:任务执行完成后,Ansible会关闭与被管理节点的连接,并停止SSH连接进程。
Ansible的安装
通过发行版安装:
RHEL系: RPM包
ubuntu 系: Deb 包
获取商业发行版安装的地址:
1
通过厂商获取 (通过红帽获取自己注册红帽订阅,使用yum install ansible -y)就可以安装
2
通过ansible官方
rpm包地址:https://releases.ansible.com/ansible/rpm/release 仅支持RHEL6/RHEL7
从RHEL8/CentOS8开始只能安装ansible-core这个版本
3
通过第三方的镜像仓库来获取特定发行版本的包
....
通过源码包编译安装:
获取地址:
ansible 2.9 以前:
ansible 2.10 开始:
https://github.com/ansible/ansible/archive/refs/tags/v2.9.0.zip
可以通过通过代理https://kkgithub.com/ansible/ansible/archive/refs/tags/v2.9.0.zip 下载
编译步骤:
1
安装所需依赖包
dnf install -y gcc libffi-devel openssl-devel python3 python3-devel python3-cryptography -y
2
开始安装
unzip v2.9.0.zip 解压源码包
cd ansible-2.9.0
python3.6 setup.py build 构建安装包
python3.6 setup.py install 安装包
- 生成配置文件并测试验证
从源码包中将配置文件拷贝到ansible的指定目录
mkdir /etc/ansible
cp 源码包路径/examples/ansible.cfg /etc/ansible/ansible.cfg
通过pip源进行安装:
1
安装软件包依赖
yum install rust cargo python3-cryptography -y
2
通过pip源进行安装
pip3 install ansible==2.9.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
清华大学开源pip仓库 https://pypi.tuna.tsinghua.edu.cn/simple
ansible == 2.9.0 指定ansible的版本
3
生成配置文件并验证版本
mkdir /etc/ansible 创建ansible的配置文件目录
从github或者是其他已经安装ansible的机器拷贝(pip源默认不带配置文件)
wget https://github.com/ansible/ansible/blob/v2.9.0/examples/ansible.cfg
注意: 在pip的安装方式中,默认不会安装sshpass软件包,该软件包用来给ansible提供密码验证被控端,因此如果在执行ansible的命令时需要输入ssh的密码,则需要该软件包,该软件包通过yum install -y sshpass
Ansible的主机清单
主机清单的介绍
ansible的主机指的是ansible所有被管理的对象都称为主机(网络设备、Linux、windows等),且ansible只能管理清单中的主机,定义ansible管理主机的配置文件将其称为主机清单,默认ansible的主机清单在/etc/ansible/hosts
定义主机的方式
- 使用IP地址定义主机
- 通过主机名进行定义(如果使用主机名来定义必须主机名要可以被解析成IP)
- 通过主机组来定义主机 [主机组的名称] 示例: [webserver] 组内的成员 web1
web2
- 通过嵌套组来定义主机
[组名称:children] 示例: [allcluster]
组内的成员(也就是其他主机组的名称) webserver - 通过通配符批量定义主机
[1:100] 表示连续匹配1-100台主机 示例 172.16.0.[1:100] 或者是node[1:100]
[a:z] 表示连续匹配a-z的26台主机 示例:db-[a:d].example.com
注意点: 如果在清单中同时出现主机和主机组,一定要将主机定义在主机组的前面,否则主机将成为主机组的成员
选择主机的方式
- 选择所有的主机
ansible all --list-hosts - 选择单台主机
ansible web01 --list-hosts - 选择单个主机组
ansible group3 --list-hosts - 选择多个主机或者是多个主机组
ansible 'web01,node1' --list-hosts
ansible 'group1,group2' --list-hosts - 选择不属于任何组的主机(也就是没有主机组的主机)
ansible ungrouped --list-hosts ungrouped 属于一个特殊的组,所有没有主机组的主机都存放在这个组中 - 通过通配符选择主机
ansible 'node *' --list-hosts 匹配以node开头的任意主机
ansible ' *.com' --list-hosts 匹配以.com结尾的主机 - 通过逻辑组合条件选择主机
,逗号表示或者的意思 & 表示与的意思 ! 表示取反的意思
逗号是并集, &是交集
ansible 'group1,group2,&group3' --list-hosts 在group1或者在group2但是必须在group3中的主机
ansible 'group1,&group4' —list-hosts 同时在group1且在group4的主机
ansible 'node *,!node3,!node4' --list-hosts 选择所有node开头的主机,但是不选中node3和node4 - 通过正则表达式来匹配主机
ansible '~(w|n) *' --list-hosts
~ 表示后面是一个正则表达式 - 通过limit来明确指定所选择的主机
ansible all --limit nodec.example.com --list-hosts 通过limit来明确指定
ansible all --limit @host_test --list-hosts 通过文件来指定,将所有要选择的主机定义在文件中,@ 符号后接的是文件
Ansible的配置文件
ansible配置文件的位置
- ansible默认的配置文件 在 /etc/ansible/ansible.cfg (全局默认位置)
- 当前的工作目录ansible.cfg
- 当前用户家目录下的.ansible.cfg (注意是以点开头的隐藏文件)
- 当前系统的ANSIBLE_CONFIG的环境变量
优先级的顺序: ANSIBLE_CONFIG —> 当前工作目录下的ansible.cfg ——> 当前用户的家目录下.ansible.cfg的隐藏文件 ——> 全局的默认配置文件 /etc/ansible/ansible.cfg
优先级是从高到低
ansible配置文件的项目
配置文件详解:
[defaults] 通用配置项 配置远程的用户,连接的密码、主机清单的位置等
[inventory] 主机清单的配置段落,可以配置主机清单使用的插件
[privilege_escalation] 提权的配置,是否启用提权以及提权的到那个用户
[paramiko_connection] 早期在RHEL6中使用的连接插件,现在默认使用ssh进行连接
[ssh_connection] ssh的连接配置项
[persistent_connection] 持久连接项 连接的超时时间、命令的超时时间
[accelerate] 连接加速项
[selinux] 配置selinux的选项,用来配置ansible支持特定的文件系统驱动以及lxc的容器配置
[colors] ansible输出的颜色 定义错误或者是任务执行成功输出的颜色
[diff] 打印任务执行前后的差异
ansible配置案例
手动配置:
管理远程主机node1和node2
机器三台,一台master 安装ansible主控,两台node作为被控
被控上的操作:
useradd zhangsan
echo redhat|passwd —stdin zhangsan
vim /etc/sudoers.d/zhangsan
zhangsan ALL=(ALL) NOPASSWD:ALL
主控上的操作:
cp /etc/ansible/ansible.cfg /opt/ansible.cfg
vim /opt/ansible.cfg
[defaults]
inventory = /opt/hosts 配置主机清单的位置
remote_user = zhangsan 配置远程的用户
ask_pass = false 配置连接时不需要验证密码即秘钥认证
interpreter_python = auto_legacy_silent 屏蔽python的多版本警告信息
#ansible_python_interpreter= /usr/bin/python3.9 指定被控端上python的解释器
[privilege_escalation]
become=True 启用提权
become_method=sudo 提权的方式为sudo
become_user=root 提权到root用户
become_ask_pass=False 提权不需要密码
[ssh_connection]
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s 配置ssh的连接加速选项
vim /opt/hosts
node1
node2
注意:node1和node2需要提前配置主机名和IP地址的绑定关系在/etc/hosts中
ssh-keygen 生成ssh免密认证的公私钥
ssh-copy-id zhangsan@node1 发送公钥到被控端
ssh-copy-id zhangsan@node2
ansible all -m ping 测试主控到被控的连通性
自动将被控端纳入到主控进行管理
全程都只在ansible的主控节点上操作,被控端不需要做任何操作
ansible all -m shell -a 'useradd devops' -u root -k 在所有被控上创建devops这个远程用户
all 表示所有的主机
-m 指定ansible使用的模块
-a 指定模块的参数(也就是这个模块要干什么)
-u 指定远程的用户(ansible的参数)
-k 在连接时验证ssh的密码
ansible all -m shell -a 'mkdir /home/devops/.ssh;chown devops:devops /home/devops/.ssh;chmod 700 /home/devops/.ssh' -u root -k 为devops用户配置存放免密公钥的目录
ansible all -m shell -a 'echo "免密公钥文件的内容" >> /home/devops/.ssh/authorized_keys;chown devops:devops /home/devops/.ssh/authorized_keys;chmod 600 /home/devops/.ssh/authorized_keys' -u root -k 为devops用户注入免密的公钥,注入完成后免密登录测试
ansible all -m shell -a 'echo "devops ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/devops' -u root -k 为devops用户配置sudo提权
最后进行连通性测试
ansible all -m ping
Ansible的Ad-hoc与命令模块
ad-hoc:
所谓的ad-hoc(临时命令),就是使用ansible模块来完成自动化任务,每一次只能使用一个模块,来完成一个任务,因此将ad-hoc称为ansible的临时命令
ad-hoc的语法:
格式: ansible 选择的主机 -m 模块名 -a '模块的参数' ansible的参数
示例: ansible all -m shell -a 'useradd devops' -u root -k
all 所有主机
shell 模块
useradd devops 模块的参数
-u root -k ansible的参数 -u 指定远程用户 -k 连接时验证ssh密码
ansible的模块:
ansible的模块 是ansible功能的重要实现,所有的自动化任务都高度依赖于模块
模块的查询:
ansible-doc -l 列出当前主机上所有ansible支持的模块
模块参数的查询:
ansible-doc -s 模块名 示例 ansible-doc -s user
模块用法例子查询:
ansible-doc 模块名 使用/EXAMPLE 搜索模块帮助中的例子
命令模块
所谓的命令模块,也就是Ansible在Linux主机上可以执行Linux指令的模块
在ansible中有四个模块通常用来在Linux主机上执行命令
command:相当于在被控端本机上执行Linux的指令,但是有四个符号例外"|、>、<、&",当出现以上四种符号时command将无法处理该指令
shell: 相当于在被控端本机上执行Linux的指令
raw:在主机上执行命令,不支持Linux指令的高阶参数
不支持的高阶参数:
chdir: 在执行命令前切换到指定的目录(默认执行命令在ansible远程用户的家目录下执行)
ansible node1 -m shell -a 'chdir=/opt touch rhca11111.txt' 文件创建在/opt目录下
ansible node1 -m raw -a 'chdir=/opt touch 2222.txt' 文件创建在devops用户家目录下不支持chdir参数
creates:文件存在命令不执行,反之文件不存在则命令执行
removes:文件不存在命令不执行,文件存在则命令执行
ansible node1 -m shell -a 'removes=/opt/rhca1111111111111.txt rm -rf /opt/ *' 文件不存在命令不执行
ansible node1 -m shell -a 'creates=/opt/rhca.txt rm -rf /opt/ *' 文件存在命令不执行
script:将主控端shell复制到被控端执行,接的是一个脚本文件,该文件不需要任何执行权限
ansible的 script模块是将文件中的内容通过shell的防水复制到被控端执行,因此和文件的权限没有关系
示例:
[root\@master opt]# cat test.sh
#!/bin/bash
id -un
ifconfig
pwd
ansible node1 -m script -a 'test.sh'
注意: 在ansible中可以直接执行Linux的命令,模块可以省略
当Ansible省略模块时,默认使用配置文件ansible.cfg中defaults段落的module_name = command参数所配置的模块,默认配置为command模块,因此省略模块默认使用command模块
Ansible的常用模块
用来操作远程主机上的文件
ansible node1 -m file -a 'path=/opt/rhca111.txt state=file'
ansible node1 -m file -a 'path=/opt/do374 state=directory'
ansible node1 -m file -a 'path=/opt/do374.txt state=touch owner=zhangsan group=devops mode=777'
ansible node1 -m file -a 'src=/opt/0000.txt dest=/opt/1111.txt state=link force=yes' 当连接文件的源不存在时,使用force=yes 强制创建
Øcopy模块
用来复制主控端的文件到被控端
ansible node1 -m copy -a 'src=/opt/test.sh dest=/opt/ owner=devops group=zhangsan mode=666'
ansible node1 -m copy -a 'content="hello rhca for do374\n" dest=/opt/123.txt' 会覆盖文件的内容
默认情况下copy模块拷贝文件时,如果源和目标文件内容不一致,则源文件覆盖目标文件,可以使用
ansible node1 -m copy -a 'src=/opt/test.sh dest=/opt/ force=no' force=no时不覆盖目标端文件,默认为yes强制覆盖,还可以通过backup=yes参数来在覆盖前备份目标文件
copy模块在远程主机上进行复制: remote_src=yes 参数 指定从被控查找源文件
ansible node1 -m copy -a 'src=/etc/hosts dest=/opt/hosts remote_src=yes'
Øyum_repository模块
配置软件仓库
ansible node1 -m yum_repository -a 'file=dvd name=BaseOS description=RHEL8_BASEOS baseurl=file:///mnt/BaseOS enabled=yes gpgcheck=no'
ansible node1 -m yum_repository -a 'file=dvd name=AppStream description=RHEL8_AppStream baseurl=file:///mnt/AppStream enabled=yes gpgcheck=no'
mount模块
ansible node1 -m mount -a 'path=/mnt src=/dev/cdrom fstype=iso9660 state=mounted' 将光盘挂载到/mnt目录
Øyum模块
安装软件包和卸载软件包
ansible node1 -m yum -a 'name=vsftpd state=installed'
ansible node1 -m yum -a 'name=vsftpd state=absent'
Øsystemd模块
管理服务
ansible node1 -m systemd -a 'name=vsftpd state=started'
ansible node1 -m systemd -a 'name=vsftpd state=stopped'
ansible node1 -m systemd -a 'name=vsftpd state=started enabled=yes' enabled设置为开机自启
Øcron模块
计划任务的配置模块
ansible node1 -m cron -a 'name="ansible cron test" minute=" */2" job="echo hello >> /tmp/hello.txt" state=present'
ansible node1 -m cron -a 'name="ansible cron test" state=absent'
Øuser模块
ansible node1 -m user -a 'name=bob uid=2000 group=zhangsan groups=devops comment="ansible user" home=/data/bob shell=/sbin/nologin create_home=yes'
ansible node1 -m user -a 'name=bob password="6vqeIBFMkxmdjKnRR$TUXSHs02Y5oGn.kaiGgQTnrhY/VPfVMvGrjZzCSCtYfpInyULFPe/etNwOqt97MSj1v5CvFdrfcTeppmtTaaI1"'
使用password参数设置密码时,输入的密码应该是手动加密后的密文
使用openssl passwd -6 redhat 生成redhat密码的密文
ansible node1 -m user -a 'name=bob remove=yes state=absent' 删除bob用户
Øgroup模块
用户组的管理模块
ansible node1 -m group -a 'name=itgroup gid=3000 state=present'
ansible node1 -m group -a 'name=itgroup state=absent'
Øfetch模块
复制被控端的文件到主控端,默认会以被控的主机名作为收集文件的存放目录;用在巡检类型的项目中
ansible node1 -m fetch -a 'src=/etc/hostname dest=/opt/ flat=yes'
使用flat=yes 表示直接将被控的文件复制到主控,如果为no则在复制文件时,以被控主机名创建目录结构来存放文件,默认该值为no ,为no时复制的是目录dest的参数可以不用/结尾,但是为yes时,表示复制文件,需要以/结尾
Øget_url 模块
专门用来下载文件
ansible node1 -m get_url -a 'url=https://mirrors.163.com/centos/8-stream/virt/x86_64/ovirt-45/Packages/a/apache-commons-io-2.8.0-5.2.el8s.noarch.rpm dest=/opt mode=777'
url 是下载的地址 dest 下载的存放目录 mode 权限
Øunarchive模块
用来将主控的压缩文件解压到被控端
ansible node1 -m unarchive -a 'src=/tmp/opt.tar.gz dest=/opt'
ansible node1 -m unarchive -a 'src=/opt/opt/etc.tar.gz dest=/tmp remote_src=yes'
注意:默认src是主控端的压缩文件,如果使用remote_src=yes的参数则为远程的文件,默认该值为no
Øsynchronize模块
专门用来实现文件同步,对于ansible大文件的传输推荐使用该模块,小文件可以使用copy进行拷贝;该模块的原理使用的就是Linux中的rsync工具,因此该模块支持rsync的选项,例如同步中的文件压缩、权限、时间戳等都支持
mode 模式: pull src = 远程主机(被控) 被控端向主控端同步文件 ——> 下载文件到主控
push src = 本地主机(主控) 主控端向被控端同步文件 ——> 上传文件到被控
src的参数是否以斜杠结尾意义不同: 如果src不以斜杠结尾,则表示同步该目录文件(也就是同步这个目录下的文件,并包含目录本身)
如果src以斜杠结尾表示仅同步目录下的文件,不包含目录本身
ansible node1 -m synchronize -a 'src=/opt dest=/tmp' 同步/opt目录到被控的/tmp 目录下
ansible node1 -m synchronize -a 'src=/opt/ dest=/tmp' 同步/opt目录下的内容到被控的/tmp 目录下
Ansible的Playbook(剧本)
ansbile-playbook是一系列ansible命令的集合,利用yaml语言编写。playbook命令根据自上而下的顺序依次执行。同时,playbook开创了很多特性,它可以允许你传输某个命令的状态到后面的指令,如你可以从一台机器的文件中抓取内容并附为变量,然后在另一台机器中使用,这使得你可以实现一些复杂的部署机制,这是ansible命令无法实现的。
yaml 的数据类型
yaml 是专门用来编写配置文件的一种语言; 在ansible中专门用来编写playbook
格式要求:
- 严格区分大小写
- 使用缩进来表示元素的层级关系,相同的元素向左对齐
- 缩进只能使用空格缩进,不能使用tab键来进行缩进(在RHEL8.5以后的版本中VIM的版本较高,检测到yaml类型的文件,会自动将tab转为空格,因此在RHEL8.5以后可以使用tab键,但是这由vim的版本决定)
- 使用#号来作为注释符号,注释一整行内容,可以用来在playbook对语句编写注释
数据类型:
纯量: 单个变量 不可再分值(最小的数据单位) 类似与Python的单个变量
数组: 一组有次序的值 列表/序列
使用 - 来表示列表
对象: 键值对的集合 key=value 哈希/字典/映射
格式:
键:空格 值 ——> 字典结构
pkgs: vsftpd
yaml示例:
#用来描述TOM的一家
name: Tom #字典结构
age: 27
wife: #嵌套字典结构
name: Jerry
age: 25
children:
- name: Jack #列表
age: 15
- name: Bob
age: 14
name: Tom
age: 27
wife:
name: Jerry
age: 25
children:
- name: Jack
age: 15 - name: Bob
age: 14
Playbook的结构
格式:
约定: ansible的playbook使用.yml 来作为文件的后缀名
组成部分: 一个playbook 由多个play组成,每一个play中都包含以下段落
- ansible target段落(在该段落中定义 ansible工作的主机,以及ansible的参数等)
- vars段落 (用来定义剧本中的使用的变量)
- tasks 段落 (剧本中的任务列表,所有剧本中要执行的任务在此定义)
- handler 段落 (特定任务段落,这个段落的任务默认不执行,只有在满足条件的情况下hander中的任务才会执行)
一个playbook(也就是一个剧本由多个play组成),playbook是对play的编排,按照一定执行顺序和逻辑将playbook组合在一起
例子说明: playbook可以想象成一个长篇电视剧的剧本;play可以想象成这个剧本中每一集,而play中的name相当于每一集的小标题,paly中的hosts相当于每一集的演员,play中的tasks相当于演员的台词
playbook用来创建用户的例子
cat user.yml
- name: create user #play的名称,可以简单理解为剧本的名称
hosts: all #hosts表示该剧本要在哪些主机上工作
remote_user: root #使用哪一个用户进行远程连接
gather_facts: false #不收集被控端的事实变量(所谓的事实变量指的就是被控端的信息)
vars: #定义剧本中变量的段落
user:"test" # 定义了一个名为user的变量且值为test
tasks: #定义剧本中执行任务的段落
- name: create user #任务的名称
user: name="{{ user }}" #任务用到的模块以及参数
#定义任务还有另外一种写法:
- name: create user
user:
name: "{{ test }}"
state: present
使用ansible-playbook user.yml 来执行剧本
palybook的段落(也就是play的段落):
target段落: 用来定义ansible的一些的工作参数,在剧本中不可以省略
hosts: 定义play在哪些主机上工作
remote_user: 定义play使用哪一个用户来进行远程
gather_facts: 定义是否收集事实变量
..........
注意在target段落定义的参数可以是ansible.cfg中出现参数,如果没有定义则使用ansible.cfg中的默认参数(ansible.cfg中的defaults段落都可以在此定义)
vars段落:用来定义变量,在剧本中可以省略
支持在该段落下直接定义变量,也支持通过第三方的文件引入变量
直接定义变量:
变量名: 空格值
tasks段落: 用来定义任务,在剧本中可以省略
在剧本中默认存在一个名为facts的任务,该任务是收集被控端的事实变量,在target段落通过gather_facts: false 来停用该任务
- name: 任务的描述信息
模块名:
模块的参数: 参数1
模块的参数: 参数2
playbook的例子:
- 在node1上创建/opt/file.txt,并向file.txt中写入内容为 hello ansible
- name: create file.txt
hosts: node1
tasks:
- name: create file
file:
path: /opt/file.txt
state: touch - name: modify file
copy:
content: "hello ansible\n"
dest: /opt/file.txt
- 在node2上配置baseos的软件仓库,将光盘挂载到/mnt 下并配置一个名为dvd.repo的本地源,通过这个源安装一个nfs-utils的软件包
- name: configure repo and install pkgs
hosts: node2
tasks:
- name: mount cdrom
mount:
path: /mnt
src: /dev/cdrom
fstype: iso9660
state: mounted - name: configure repo file for BaseOS
yum_repository:
name: BaseOS
description: RHEL8_BaseOS
baseurl: file:///mnt/BaseOS
file: dvd
enabled: yes
gpgcheck: no - name: configure repo file for AppStream
yum_repository:
name: AppStream
description: RHEL8_BaseOS
baseurl: file:///mnt/AppStream
file: dvd
enabled: yes
gpgcheck: no - name: install pkgs for vsftpd
yum:
name: vsftpd
state: present
ansible-playbook的选项
查看执行的情况:
-v 来查看playbook运行的详情 v越多信息越详细
v 可以看到ansible使用的配置文件以及任务的执行结果
vv 可以看到ansible的版本、以及执行过程中的每一行内容、python的版本等信息
vvv 可以看到ansible模块对py文件的传输过程,以及被控端ssh连接的过程
校验playbook的语法格式:
ansible-playbook --syntax-check demo1.yml 只能检查yaml的格式是否有问题,ansible的错误不会检查,如果发现报错的行,没有格式错误,通常检查该行的下一个层级
空跑playbook(也就是测试playbook能否运行,但是不对对方主机造成影响,也就是不会改变对方主机的状态)
ansible-playbook -C(--check) file.yml 仅会执行playbook但是不会改变对方主机的状态
Ansible handlers
触发器,是一类特定任务,这类任务只在被触发时执行(handlers只会在任务的状态被改变时触发,也就是任务的状态必须为changed才会执行handlers)
notify 是handler的监听关键字,关键字用来触发指定的任务
基本配置
- name: demo4 test
hosts: node1
tasks:
- name: install pkgs
yum:
name: vsftpd
state: present
notify: restart_service #监听的关键字
handlers:
- name: restart_service #要执行的handler的任务
systemd:
name: vsftpd
state: started
enabled: true
- name: bbb
systemd:
name: sshd
state: restarted
当notify监听的任务状态为changed时,playbook中的handler里面对应的任务名的任务被执行
handler会不会被重复执行 ???
handler不会被重复执行
当notify使用同一个关键字监听多个任务,多个任务状态都发生改变时,handler仅会执行一次;是因为handler在整个剧本中的任务最后结束后执行,因此不管notify被触发多少次,最终handler中的任务都只会执行一次
解决handler的异常问题
- 当handler的触发的任务还来不及执行,剧本中因其他的出错导致剧本停止执行,如何强制执行handler
- name: demo4 test
hosts: node1
gather_facts: false
force_handlers: true ## 增加该关键字 无论playbook中的任务是否执行成功或者失败
(也就是无论剧本是否成功失败,只要handler被触发就一定会执行) 强制执行handlers
tasks:
- name: install pkgs
yum:
name: vsftpd
state: present
notify: restart_service
- name: create file
file:
path: /opt/file.txt
state: file
- name: task1
file:
path: /opt/task1
state: touch
handlers:
- name: restart_service
systemd:
name: vsftpd
state: started
- name: demo4 test
hosts: node1
gather_facts: false
force_handlers: true
tasks:
- name: create file
file:
path: /opt/file.txt
state: touch
notify: create_file
handlers:
- name: aaaaa
debug:
msg: "test1"
- name: create_file ## 仅会执行test2的任务,test3不会向下匹配
debug:
msg: "test2"
- name: create_file
debug:
msg: "test3"
- 当一个notify想要触发多个handler中的任务时,使用listen 来作为监听的关键字,此时handler中任务的名称可以与notify不一致,通过listen来进行匹配
- name: demo4 test
hosts: node1
gather_facts: false
force_handlers: true
tasks:
- name: create file
file:
path: /opt/file.txt
state: touch
notify: create_file
handlers:
- name: task1
listen: create_file ##当使用listen来作为匹配的关键字时,name的名称可以与notify不一致
debug:
msg: "test1"
- name: task2
listen: create_file
debug:
msg: "test2"
- name: task3
listen: create_file
debug:
msg: "test3"
playbook中的异常情况:
playbook中的任务执行失败会不会导致剧本退出???
当剧本中的任务在某个主机上执行失败时,接下来所有的任务都不会在该主机上执行,也就是主机从play中退出(换一句当主机上的任务执行失败时,主机退出play的执行)
ansible的 playbook是在失败时停止执行,当修复play中的错误后在失败的地方继续执行
幂等性: 所谓的幂等性 指的是使用的同样的条件和方法,一次执行和多次重复执行对系统的影响是一致的
Ansible的变量
变量的格式说明:
变量名 变量值
- 在命令行中或者是inventory中 使用等于号分隔 变量名=变量值
- 在yaml中 使用冒号来分隔 变量名: 变量值
变量名称的要求:
a. 严格区分大小写
b. 尽量不要和ansible已经存在的变量重名,这会导致新的变量覆盖旧的变量(特别是不要和ansible的内置变量冲突,通常只要变量不以ansible开头则不会冲突)
c. 变量名称可以使用数字、字母和下划线组成,但是只能以字母开头
变量的调试与引用:
变量的引用:
单个变量 "{{ 变量名 }}"
多个变量 "{{ 变量1}} {{ 变量2 }}"
变量的类型: 定义变量时不要随便给变量加引号
通过type_debug 过滤器查看变量的类型
- hosts: node1
gather_facts: no
vars:
var_test:
- redhat
- suse
- openEuler
var_rhca: "for RHCA"
tasks:
- name: debug info
debug:
msg: "{{ var_test|type_debug }}"
AnsibleUnicode / String 字符串类型
int 整型
float 浮点数
list 列表
......
变量的调试模块:
debug模块:
var: 直接打印变量的内容
msg: 输出一段文本
var和msg不能同时共用,只能使用一个参数
- hosts: node1
gather_facts: no
vars:
var_test:
- redhat
- suse
- openEuler
var_rhca: "for RHCA"
tasks:
- name: debug info
debug:
#var: var_rhca 两个参数不能同时共用
msg: "{{ var_rhca }}"
定义变量的方式:
在主机清单中定义变量
连接的变量
ansible_host 指定清单中主机的真实IP地址
ansible_port 指定清单中主机的端口
ansible_user 指定清单中主机的连接用户
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命令路径
ansible_connection #SSH连接的类型:local, ssh, paramiko,默认是ssh
ansible_ssh_pass #ssh连接时的密码
ansible_ssh_private_key_file #秘钥文件路径,如果不想使用ssh-agent管理秘钥文件时可以使用此选项
ansible_ssh_executable #如果ssh指令不在默认路径当中,可以使用该变量来定义其路径
自定义变量
对单个主机自定义变量:
主机名 变量名=值
example: node1 webserver=nginx
对主机组自定义变量:
node1 ansible_port=2222 ansible_user=zhangsan webserver=nginx
node2 webserver=apache
[group1]
node2
[group1:vars] # 给主机定义变量 需要使用vars的关键字来进行定义
dbserver=mysql
webserver=tomcat #当主机组的变量和主机的变量冲突时,主机的变量优先级更高
通过vars的关键字定义变量
vars可以出现在很多地方,不一定是在playbook中
vars如何定义变量:
简单的变量:
os_type: RHEL9
复杂的变量:
hosts: node1
gather_facts: no
vars:
os_type:
redhat:
latest: rhel9
openeuler:
latest: oe24.03LTS
tasks:
- debug:
var: os_type.redhat.latest #有多级变量时使用点来进行分隔 (用点来表示多个层级)
有层级的变量(嵌套的变量):
hosts: node1
gather_facts: no
vars:
os_type:
redhat:
latest: rhel9
openeuler:
latest: oe24.03LTS
tasks:
- debug:
var: os_type.redhat.latest #有多级变量时使用点来进行分隔 (用点来表示多个层级)
通过vars_files 外部文件引入变量
vars_files 将变量定义到单独的文件中进行引用
注意:所引入的文件格式为yaml格式,文件的路径可以是一个绝对路径或者是一个相对路径
#变量文件
vim test_vars.yml
os_type:
redhat:
latest: rhel9
openeuler:
latest: oe24.03LTS
#playbook
vim demo7.yml
- hosts: node1
gather_facts: no
vars_files:
- test_vars.yml #引入文件,不管是一个文件还是多个文件,都需要- 开头,此处定义的是一个文件列表
tasks:
- debug:
var: os_type.redhat.latest
通过主机目录和主机组目录定义变量
通常在一个ansible的项目中,会包含ansible的配置文件、主机清单、以及ansible的角色和内容集合,除此以外还会存在ansible主机和主机组的两个特殊目录,一个是主机的变量目录(host_vars)、一个是主机组的变量(group_vars)
使用主机目录定义主机变量
#在ansible.cfg的项目目录中创建host_vars目录
mkdir host_vars #该目录用来存放主机的变量
vim host_vars/node1 #在主机变量目录使用清单中的主机名创建一个同名的文件,该文件作为主机的变量文件
test: rhel9 #定义一个名为test的变量其值为rhel9
#测试验证
ansible node1 -m debug -a 'var=test'
使用主机组目录定义主机组变量
#在ansible.cfg的项目目录中创建group_vars目录
mkdir group_vars
vim group_vars/group1
rhca: do374
ansible group1 -m debug -a 'var=rhca'
注意: 当主机的变量和主机组的变量冲突时,主机的变量优先级更高
注册变量
所谓的注册变量,就是在playbook中将一个任务的执行结果保留下来作为变量
通过register 将任务的执行结果注册到一个指定的关键字作为变量
注册变量的应用场景:
- 获取远程主机特定目录下的文件列表
- 根据任务的执行结果判断是否执行指定的任务
- 构造known_hosts 主机公钥文件
- hosts: node1
gather_facts: false
tasks:
- name: test file
file:
path: /opt/file.txt
state: file
register: get_file #将任务的执行结果保留到名为get_file的变量中
- name: debug info
debug:
var: get_file
通过命令行设置变量
在命令行定义变量,适用于playbook中对特定任务进行判断,通过不同的变量来执行不同的任务
ansible node1 -m debug -a 'var=a1' -e a1=hello
ansible node1 -m debug -a 'var=a1' -e '{"a1":"hello"}'
### playbook同样支持命令行定义变量
vim demo9.yml
- hosts: node1
gather_facts: false
tasks:
- name: test1
debug:
msg: hello1
when: a1 == "hello1"
- name: test2
debug:
msg: hello2
when: a1 == "hello2"
ansible-playbook demo9.yml -e a1=hello1
ansible facts 变量
facts变量被称为ansible的事实变量,所谓的事实变量指的是ansible收集到的被控主机的信息
#ansible通过setup模块收集被控主机的事实变量
ansible node1 -m setup
#查看特定的事实变量
通过filter参数对指定的事实变量进行过滤
ansible node1 -m setup -a 'filter=ansible_all_ipv4_addresses'
通过filter参数使用通配符进行过滤
ansible node1 -m setup -a 'filter=ansible_*_addresses'
ansible node1 -m setup -a 'filter=ansible*bios*'
ansible node1 -m setup -a 'filter=*bios*'
ansible node1 -m setup -a 'filter=*mb*'
通过filter参数过滤时,只能过滤到ansible_facts的下一个层级,也就是通常以ansible开头的变量信息
导出facts变量到文件,手动查找所需的变量
ansible node1 -m setup --tree /tmp/test 将指定主机的facts变量保存到指定目录下的主机名命名的文件中
ansible node1 -m setup >> /tmp/node1.txt 将facts重定向保存到文件中
facts常用的变量
facts变量的引用
引用facts的变量不能以ansible_facts作为顶级key(也就是第一个层级);原因是ansible将ansible_facts下的内容自动注册为变量,因此ansible_facts在系统中是不存在顶级key的
playbook 中facts的开关
gather_facts的参数, 值为true 收集facts变量,值为false不收集facts变量
如果值为true(该参数的值默认为true)时,在执行playbook时,会先执行默认的facts任务,也就是playbook的默认任务
自定义facts变量
第一种,使用现有的facts变量拼凑在一起形成新的变量
第二种,在不同主机上通过文件自定义facts变量
示例:
第一种: 通过set_fact模块来形成新的变量
- hosts: node1
gather_facts: true
tasks:
- name: create vars
set_fact:
name_ip: "{{ ansible_hostname }} {{ ansible_ens160.ipv4.address }}"
- name: prient ip address
debug:
var: name_ip
# 在被控端主机上创建一个存放facts变量的目录
mkdir /etc/ansible/facts.d -p
#编写预定义的facts变量文件(变量文件的类型支持yaml,json、ini等格式)
vim /etc/ansible/facts.d/test.fact #注意自定义的facts文件必须以fact结尾
#以ini格式为例
[rhca]
rh=442
do=374
cl=260
pkgs=vsftpd
vim demo9.yml
- hosts: node1
gather_facts: true
tasks:
- name: prient ip address
debug:
var: ansible_local.test.rhca.pkgs
使用template模块将变量渲染成具体的值
在大批量的服务配置文件修改场景下,如何快速解决服务的差异化配置,通过template的模块可以对服务进行模板化的批量部署,也就是通过一个服务的模板文件来自定义服务所需的配置
将template模块使用的模板文件称为jinja2的模板,模板文件通常以j2结尾表示是模板文件
示例: 在node1和node2上安装apache的web服务器,并将apache的80端口监听在node1和node2的IP地址上
- hosts: all
tasks:
- name: install httpd
yum:
name: httpd
state: present
- name: copy httpd conf
copy:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
- name: start service
systemd:
name: httpd
state: started
使用外部数据源作为变量
通过lookup插件将外部的数据源作为变量
ansible-doc -t lookup -l 列出lookup支持外部数据源的方法
ansible-doc -t lookup file 查询lookup插件的file方法的例子
lookup常用的方法:
file 将文件的内容作为变量
env 将环境变量作为变量
pipe 将命令的执行结果作为变量
### 数据源所执行命令,引用的文件以及环境变量,全部都来自于主控(lookup获取的变量都来自于主控)
lookup的格式
lookup变量使用lookup(‘方法’,’内容’)
example: {{ lookup(‘file’,’/etc/ansible/ansible.cfg’)}}
ansible的魔法变量
所谓的ansible魔法变量实际上就是一些具有特定用途的事实变量,这些变量通常用来做某个特定的操作,将其称为魔法变量
魔法变量的查询地址:https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html#magic-variables
常用的魔法变量:
- hostvars 获取指定主机的facts变量
- hosts: node2
- hosts: node1
gather_facts: no
tasks:
- name: test
shell: echo "{{ hostvars['node2'].ansible_ens160.ipv4.address }} {{ hostvars['node2'].ansible_fqdn }} {{ hostvars['node2'].ansible_hostname }}" >> /etc/hosts
- hosts: node1,node2
gather_facts: no
tasks:
- name: debug info
debug:
var: inventory_hostname
when: inventory_hostname == "node1"
- hosts: all
- hosts: node1
gather_facts: no
tasks:
- name: debug info
debug:
var: hostvars[item].ansible_ens160.ipv4.address
loop: "{{ groups.all }}"
ansible变量的优先级
优先级是从高到低
#命令行设置的变量优先级最高
#playbook中定义的变量其次
#host_vars和group_vars的变量
#inventory变量 优先级要大于role中的default变量
#role中的vars变量优先级要大于inventory中的变量
#facts变量
#ansible的内置变量
# 命令行 > playbook > inventory > role > facrs > 内置变量
变量名相同,高优先级会覆盖低优先级变量
变量名相同,主机变量会覆盖主机组变量
变量名相同,子组覆盖嵌套组的变量
Ansible Roles
ansible的roles称为ansible的角色,所谓的角色其实就是一个playbook的集合,ansible将一个复杂的playbook拆分成多个文件,来进行大型项目管理,例如开发团队专门编写开发相关的play,测试团队编写测试相关的play,通常一个角色就是一个项目
得到角色
- 通过红帽得到ansible的 roles
yum install rhel-system-roles 红帽专门为rhel的操作系统编写的roles包 - 通过ansible hub仓库得到roles
https://galaxy.ansible.com/ 直接搜索开源的roles  - 红帽的官方仓库下载role(需要收费)
console.redhat.com 获取认证的内容集合和role
使用角色
所有的roles 想要被使用都需要通过playbook来调用
- 指定角色存放的位置
如果在ansible.cfg中定义了 roles\_path参数,则存放在指定路径下
如果没有定义roles的存放路径,则默认存放在使用ansible工具用户的家目录下\~/.ansible/roles 目录中 - playbook中调用角色的语法
- hosts: node1
gather_facts: yes
roles: #通过roles关键字调用role
- timesync # timesync 是角色的名称,角色的名称就是角色的目录名
# 角色要不和调用的playbook存放在同一级目录下,要不存放在roles_path指定的路径下
编写角色
- 初始化一个角色的目录结构
ansible-galaxy init nginx - 理解角色各个目录的作用
defaults 角色中变量的存放目录,该目录下的变量优先级是最低的(因此又将其称为默认变量)
files 角色中需要使用的文件,例如copy模块需要拷贝的文件都存放在该目录下(普通文件)
handlers 角色中需要调用的handler存放的目录
meta 存放角色的作者信息以及角色的描述、开源协议和角色依赖
README.md 帮助说明文件,通常用来告诉用户如何使用该角色
tasks 角色中需要执行的任务存放在此
templates 角色中需要使用的jinja2的模板存放路径(模板文件)
tests 测试用例
vars 角色中定义变量的位置 
Nginx的角色需求:
a. 安装Nginx
b. 配置Nginx
c. 发布网站主页
d. 测试访问
[root@master nginx]# ls files/
index.html
[root@master nginx]# ls handlers/
main.yml
[root@master nginx]# ls tasks/
main.yml
# tasks file for nginx
- name: install nginx
yum:
name: "{{ pkgs }}"
state: present
- name: copy file nginx conf
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
backup: yes
notify: get_service
- name: copy index.html
copy:
src: index.html
dest: /usr/share/nginx/html/index.html
[root@master nginx]# ls templates/
nginx.conf.j2
[root@master nginx]# ls vars/
main.yml
[root@master nginx]#
### 当在角色目录中有非常多的任务时或者需求比较复杂,可以将main.yml的文件拆开写成多个子文件
举例 tasks目录为例
[root@master tasks]# cat install_nginx.yml
- name: install nginx
yum:
name: "{{ pkgs }}"
state: present
[root@master tasks]# cat copy_index_html.yml
- name: copy index.html
copy:
src: index.html
dest: /usr/share/nginx/html/index.html
[root@master tasks]# cat copy_nginx_conf.yml
- name: copy file nginx conf
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
backup: yes
notify: get_service
------------------------------------------
# tasks file for nginx
- include_tasks:
file: install_nginx.yml
- include_tasks:
file: copy_nginx_conf.yml
- include_tasks:
file: copy_index_html.yml
- hosts: node1
gather_facts: yes
roles:
- nginx 调用的角色名
- mysql 可以同时调用多个角色
- hosts: node1
gather_facts: yes
pre_tasks:
- name: debug info
debug:
msg: "hello ansible pre task"
roles:
- nginx 调用的角色名
- mysql 可以同时调用多个角色
post_tasks:
- name: debug info
debug:
msg: "hello ansible post tasks"
角色的常用操作:
1、通过ansible-galaxy初始化一个roles的目录结构,方法如下:
ansible-galaxy init my_new_role
2、搜索role
ansible-galaxy search myrole
3、安装别人写好的roles:
ansible-galaxy install myrole -p /tmp
4、列出已安装的roles:
ansible-galaxy list
5、查看已安装的roles信息:
ansible-galaxy info myrole
6、卸载roles:
ansible-galaxy remove myrole
Ansible 加密
- 为什么在ansible中需要加密
用户的敏感数据都需要加密,例如主机的连接密码、用户的数据账号密码等都需要加密 - 在ansible中有哪些文件是可以加密的
主机清单 ——> 可以加密
变量文件 ——> 可以加密
playbook ——> 可以加密 - ansible加密的常用操作
创建加密文件
ansible-vault create filename
加密存在的文件
ansible-vault encrypt filename
解密一个加密的文件
ansible-vault decrypt filename
查看一个加密的文件
ansible-vault view filename
编辑一个加密的文件
ansible-vault edit filename - ansible加密文件的使用
手动指定加密文件的密码
ansible-playbook demo12.yml --ask-vault-pass
将密码放在文件中进行加载
vim /opt/pass.txt
redhat
ansible-playbook demo12.yml --vault-password-file /opt/pass.txt
rhaap2介绍
红帽ansible自动化平台2(Red Hat Ansible Automation Platform 2)
rhaap2的特点
- 综合性平台:
- RHAAP2是一个综合性的自动化平台,不仅提供了Ansible引擎的功能,还包括了一系列周边工具和功能,如Tower(现为Ansible Automation Platform)管理控制台、自动化Hub、内容流水线等,这些功能使得RHAPP2更加完整且适合企业级的自动化需求。
- 企业级支持:
- RHAAP2提供了企业级的支持和服务,包括技术支持、咨询等,帮助企业更好地实施和管理自动化解决方案,确保系统的稳定性和安全性。
- 安全性和权限控制:
- RHAAP2提供了更加灵活和强大的安全性和权限控制机制,可以根据用户角色和权限来管理对资源和任务的访问和操作,确保系统的安全性和合规性。
- 多云管理和集成:
- RHAAP2提供了更深度的多云管理和集成能力,可以与各种云平台、容器平台、存储平台等进行无缝集成,实现跨平台的自动化操作和管理。
- 报告和监控功能:
- RHAAP2提供了更丰富和实用的报告和监控功能,可以实时监控任务的执行情况、性能指标等,并生成详细的报告和日志,帮助用户更好地管理和优化自动化流程。
- 内容和资源丰富度:
- RHAAP2提供了丰富的内容和资源,包括官方和社区贡献的模块、剧本、角色等,用户可以通过自动化Hub获取并共享这些资源,加速自动化的实施过程。
rhaap2组件
Ansible Core
Ansible Core(ansible核心引擎) 提供⽤于运⾏ Ansible Playbook 的基本功能。 它定义了⽤于在 YAML ⽂本⽂件中编写 Ansible Playbook 的⾃动化语⾔。 它提供了⾃动化代码所需的关键功能,如循环、条件和其他Ansible 命令。 还提供了驱动⾃动化所需的框架和基本命令⾏⼯具。
红 帽 Ansible ⾃动化平台 2.2 提供了 Ansible Core 2.13,其 ansible-core 位于 RPM 软件包内
Ansible 内容集合
在ansible2.9以前的版本中,ansible自带大量模块,这种模式将其称为ansible“自带电池”;从ansible2.10开始引入ansible collection(ansible内容集合),实现了ansible引擎与ansible模块的解耦,ansible内容集合包含ansible模块、插件和角色构成;从ansible2.10 core开始仅自带ansible builtin内容集合,该集合始终集成在ansible core的版本中,因此用户可以根据自身需求安装不同的内容集合,以获得功能模块和插件以及角色
自动化内容导航器
rhaap2中新的自动化工具,即自动化内容导航器 (ansible-navigator);来开发和测试ansible的playbook该工具可以取代或扩展多个ansible之前的命令包括,ansible-playbook、ansible-inventory,ansible-config等,自动化内容导航器通过容器来运行playbook,将ansible的执行环境与ansible的控制节点隔离开,避免因环境差异导致任务的执行失败,如果主机的python环境等问题
自动化执行环境
自动化执行环境是一种容器镜像,该镜像中包括(ansible core、ansible collection、以及运行playbook所需的任何python库或其他依赖性)运行playbook所需的环境;Ansible ⾃动化平台 2 提供的新⼯具 ansible-builder 来自行创建新的执行环境
自动化控制器
Automation Controller自动化控制器以前被称为ansible-tower(开源版本为awx)红帽企业级平台自动化,ansible-tower提供WebUI和RESET API来运行和配置自动化任务,在tower中系统既是控制节点还是自动化执行环境,playbook需要与系统上的python版本进行兼容,甚至还需单独配置python的虚拟环境,管理和分发难度大,扩展性不强
新的自动化控制器通过将控制节点(提供WebUI和API)与自动化执行环境(如今在容器中运行)分离,在新的自动化控制器中,只需要从容器仓库拉取自动化执行环境,在web UI上选中新的执行即可执行playbook
自动化中心
ansible hub 可以理解为自动化仓库,自动化中心提供ansible内容集合(模块、插件、角色)的托管服务,在hub中获取内容集合用来扩展ansible core的功能,用户还可以自建私有ansible hub
ansible内容导航器
ansible-navigator是 ansible的内容导航器是红帽RHAAP2 平台中用来执行playbook的工具,除了playbook以外还可以管理主机清单,可以查询ansible的模块帮助等,是一个新的ansible的自动化工具,用来代替原来ansible指令
安装导航器的方式
通过红帽订阅来进行安装
- 将系统注册到红帽
subscription-manager register --auto-attach (需要红帽账号可以使用订阅)
2.在系统中添加红帽的RHAAP2的软件源
subscription-manager repos --enable ansible-automation-platform-2.2-for-rhel-8-x86_64-rpms
- 安装导航器
yum install ansible-navigator -y
通过开源的软件包进行安装
- 在github上拉取源码进行编译安装
https://github.com/ansible/ansible-navigator - 通过pip的源进行安装
安装python3.9 因为导航器2.2依赖3.9的版本
yum install python39 -y
使用pip源安装导航器
pip3.9 install ansible-navigator==2.2.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
导航器中ansible的配置文件
- 配置导航器中的ansible.cfg 配置文件
将导航器中的配置文件导出
ansible-navigator config dump -m stdout
搜索配置项
:filter host (:f host)搜索主机清单相关的配置 - 配置文件详解
Name 配置项的名称 (此处配置项和ansible.cfg中的名称有差异)
Default 该项是不是默认的配置 (如果是默认的配置为true,如果是修改后的配置为false且颜色为黄色;通过颜色可以区分,如果该项是黄色表示有更改,是绿色为默认配置)
Source 配置项的定义方式 如果该项是是一个文件的路径表示,该项的配置来自于文件;如果该项为env表示来源于环境变量,如果为default表示默认来源配置
Current 参数的值 - 配置文件的优先级
- 当前工作目录下的ansible.cfg
- ansible-navigator 挂载的配置文件
ansible-navigator config dump --eev /opt/ansible.cfg:/etc/ansible/ansible.cfg - 将ANSIBLE_CONFIG的环境变量注入到执行环境中
export ANSIBLE_CONFIG=/opt/ansible.cfg 指定环境变量
ansible-navigator config dump --eev /opt:/opt 将环境变量指定的配置文件所在目录挂载到导航器中
- 导航器运行playbook的方式
ansible-navigator run test.yml -m stdout
run 来运行一个playbook
-m 指的是ansible-navigator的运行模式, 交换模式/stdout 免交换模式(默认是交换模式) - 导航器和ansible的常用命令差异
ansible-playbook ——> ansible-navigator run 执行playbook
ansible-doc ——> ansible-navigator doc 查询帮助
ansible-inventory ——> ansible-navigator inventory 查询主机
ansible-config ——> ansible-navigator config 查询配置 - 导航器的操作项
ansible-navigator
collections 内容集合
config 配置项(ansible.cfg的配置)
doc 查询帮助(模块、插件)
images 查询导航器的镜像
inventory 主机
log 日志
replay 重播 查询上一次执行playbook的记录
run 运行playbook
settings 配置项(ansible-navigator.yml的配置) - 配置导航器的配置文件
ansible-navigator 的配置文件支持json和yaml两种格式的文件后缀
ansible-navigator.json 或者是ansible-navigator.yml /ansible-navigator.yaml
导出ansible-navigator的配置项:
ansible-navigator settings --sample -m stdout 导出导航器的示例配置(也就是模板)
ansible-navigator settings --effective -m stdout 导出导航器当前生效的配置(正在使用的配置项) - ansible-navigator.yml配置项重点
execution-environment: #ansible自动化执行环境
container-engine: podman #默认的容器引擎
enabled: true # 是否将该执行环境设置为默认环境
image: quay.io/ansible/creator-ee:v0.9.1 #执行导航器默认使用的镜像
policy: tag 镜像的拉取策略 #tag 表示拉取指定的版本
#never 表示从不进行拉取 也就是使用本地的版本
#latest 每一次都拉取最新的版本
#always 无论如何都要拉取
logging: #日志记录
append: true # 开启日志记录
file: /data/ansible-navigator.log #日志文件的位置,默认是当前的工作目录
level: warning #日志的记录级别 error、info、debug
mode: stdout 导航器的工作模式 # stdout表示非交互模式
#interactive 交换模式
playbook-artifact: #playbook 工件 或者叫 制品
enable: true #true=是打包为工件 false 是禁止打包,如果需要接受用户输入的密码则为false
save-as: '{playbook_dir}/{playbook_name}-artifact-{time_stamp}.json'
#重播文件 存放的是playbook的执行记录 需要enable为true时生成
- ansible-navigator.yml的配置文件存放位置
- 当前的工作目录下
- 在当前用户的家目录下~/.ansible-navigator.yml的文件
- 环境变量ANSIBLE_NAVIGATOR_CONFIG
- ansible的自动化执行环境
ansible的执行环境指的就是导航器所使用的容器镜像
容器镜像中包含: ansible-core的引擎、ansible的内容集合、python的插件和依赖库以及playbook执行所需的环境
registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest 收费红帽支持版
quay.io/ansible/creator-ee:v0.9.1 免费开源版(ansible-core 2.13)
红帽推荐使用的导航器镜像:
ee-minimal-rhel8:latest ansible-core 2.13 最小化的执行环境
ee-supported-rhel8:latest ansible-core 2.13 最小化的执行环境以及红帽认证的内容集合(标准版) 商业支持的
ee-29-rhel8:latest ansible2.9 兼容执行环境(也就是为了兼容执行ansible 2.10以前的playbook)
容器镜像的拉取地址:
registry.redhat.io/ansible-automation-platform-22/ee-minimal-rhel8:latest
registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest
registry.redhat.io/ansible-automation-platform-22/ee-29-rhel8:latest - 选择导航器的执行环境
a. 在ansible-navigator.yml的配置文件中手动指定导航器用的镜像
b. 在执行导航器是手动指定镜像
ansible-navigator --eei registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest - 内容集合的获取方式
- 通过红帽的自动化中心进行获取内容集合
https://console.redhat.com/ansible/automation-hub/ - 通过ansible galaxy来获取内容集合
galaxy.ansible.com 来获取集合 并可以通过文件同时安装多个集合 c. 多种方式同时安装集合 vim test.yml
collections:
- name: url地址是集合的压缩包文件 ansible-galaxy collection install -r test .yml -p 安装的路径位置
- 查询内容集合
在本机上的查询方式
ansible-galaxy collection list
在执行环境上查询
ansible-navigator collections list - 定义内容集合的位置
ansible.cfg中进行定义
collections_path=/opt/test:/usr/share/ansible/collections
如果存在多个内容集合的目录则使用冒号分隔,默认的内容集合在当前用户家目录下.ansible的目录中
/usr/share/ansible/collections 如果该路径不指定,则宿主机上的内容集合路径将覆盖容器内的内容集合路径,导致容器自身携带的集合无法使用
- 内容集合中模块的使用
在ansible的内容集合中,如果模块的名称具有唯一性,则可以不使用命名空间.内容集合.模块的方式在playbook中定义模块的用法,如果多个命名空间中具有相同名称的模块,则必须使用内容集合的方式来指定模块 - ansible hub的使用(自动化中心)
配置ansible hub的方式
ansible.cfg
公共仓库的配置
[galaxy] 定义可以使用那些仓库
server_list=redhat_hub,ansible_hub 仓库的名称,多个仓库用逗号分隔,按照顺序来下载集合
[galaxy_server.redhat_hub] 指定仓库的配置
url=https://console.redhat.com/api/automation-hub/content/published/ 集合地址
auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token 认证地址
token=eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0NzQzYTkzMC03YmJiLTRkZGQtOTgzMS00ODcxNGRlZDc0YjUifQ.eyJpYXQiOjE3MTU2MDI2OTIsImp0aSI6IjZjZDUxYzk0LTNhODEtNDg2ZC04NDVmLTRlZGRmMDM5ZmU4ZiIsImlzcyI6Imh0dHBzOi8vc3NvLnJlZGhhdC5jb20vYXV0aC9yZWFsbXMvcmVkaGF0LWV4dGVybmFsIiwiYXVkIjoiaHR0cHM6Ly9zc28ucmVkaGF0LmNvbS9hdXRoL3JlYWxtcy9yZWRoYXQtZXh0ZXJuYWwiLCJzdWIiOiJmOjUyOGQ3NmZmLWY3MDgtNDNlZC04Y2Q1LWZlMTZmNGZlMGNlNjppam9rZXMiLCJ0eXAiOiJPZmZsaW5lIiwiYXpwIjoiY2xvdWQtc2VydmljZXMiLCJub25jZSI6ImZmZTJkNzFiLTU1YjctNDgyOS04NmY4LTBhZjEyNjQyNWQzMyIsInNlc3Npb25fc3RhdGUiOiI1NzM0ZTIyZS03OTcwLTRjYjYtYTNlNC02ZTkwNWFiOWM3NzciLCJzY29wZSI6Im9wZW5pZCBhcGkuaWFtLnNlcnZpY2VfYWNjb3VudHMgcm9sZXMgd2ViLW9yaWdpbnMgb2ZmbGluZV9hY2Nlc3MiLCJzaWQiOiI1NzM0ZTIyZS03OTcwLTRjYjYtYTNlNC02ZTkwNWFiOWM3NzcifQ.mDbXEOUkG_v5tFK2C3Ofoy0S-8MTP5fcDQYKUkpLnC5naBduIpcKdVNtbwJmiJpsnrMzIPIule169ugxi8WSOQ
[galaxy_server.ansible_hub]
url=https://galaxy.ansible.com
token可以通过环境变量的方式临时指定并加载
**ANSIBLE_GALAXY_SERVER_仓库名(需要大写)_TOKEN=
**xxxxx
示例:**ANSIBLE_GALAXY_SERVER_
REDHAT_HUB_TOKEN=
**eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0NzQzYTkzMC03Y
私有仓库配置
[galaxy_server.test_hub] 指定仓库的配置
url=https://hub.lab.example.com 集合地址
token=
从仓库拉取集合
ansible-galaxy collection install community.mysql (根据server_list中的顺序从仓库拉取)
动态主机清单
Ansible记录被管理对象的文件将其称为主机清单,默认ansible使用ini格式的文本文件来记录主机信息
从ansible2.4 开始支持使用不同的插件来获取主机清单
根据清单的类型不同将将清单分成动态主机清单和静态主机清单
静态清单:指将主机列表写在一个文件中,通常是一个 INI 风格的文本文件,其中包含主机名、IP 地址、变量等信息。这个文件需要手动维护,并且是固定不变的。Ansible 将根据静态主机清单来管理主机。
动态清单:使用插件从外部数据源动态生成主机列表。这些数据源可以是虚拟化平台、云提供商或配置管理数据库等,例如 AWS EC2 实例、VMware 虚拟机或 DNS 解析等。与静态主机清单不同,动态主机清单可以随时更新,并根据实际情况自动添加或删除主机
所谓的动态主机清单指的是,被管理的主机来自于外部的数据插件进行生成,是一个动态变化的主机清单;
主机清单的分类:
早期ansible定义主机的方式 在inventory文件中,一行一个主机就是 静态的主机清单
现在ansible通过指定的主机清单插件,可以在脚本中、外部数据源、yaml中获取主机清单
- 主机清单支持的方式:
host_list:Ansible 支持多种主机清单类型,其中之一就是 host_list。它是 Ansible 默认的主机清单类型,使用纯文本文件格式,每行一个主机/IP地址。
script:指的是在 Ansible 主机清单中通过执行脚本来动态生成主机列表。这需要用户编写自定义脚本来生成主机清单。
auto:指的是 Ansible 动态清单插件,它允许您从外部数据源(如 EC2、GCE、VMware 等)获取主机清单信息,这样可以动态地生成主机清单并保持其时刻更新。
yaml:指的是一种主机清单格式,使用 YAML 文件格式存储主机清单。与 INI 格式类似,YAML 也支持将主机分组,并且更加易于阅读和管理。
ini:指的是一种主机清单格式,使用 INI 文件格式存储主机清单。主机可以进行分组,并按照组别执行任务。
toml:指的是一种主机清单格式,使用 TOML 文件格式存储主机清单。TOML 文件具有易于编写和阅读的语法,与 YAML 和 INI 类似,支持主机分组
- 使用主机清单的插件
[inventory] enable_plugins=ini, script, auto, yaml, toml
在ansible执行任务时,会根据主机清单插件的顺序来加载主机
- 华为公有云ECS ansible自动化实例
3.1 获取并安装华为云sdk
pip3.8 install -r requirements-inventory.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
ln -s /usr/bin/python3.8 /usr/bin/python
3.2 下载华为云的动态主机清单脚本
chmod +x ./hwc_ecs.py
3.3 配置脚本的认证方式
下载配置文件
修改配置文件:
配置鉴权信息AK、SK
获取方式在华为云后台选中右上角的用户头像选择《我的凭证》即可申请ak,sk
永久生效配置(生产环境多人使用不推荐)
修改hwc_ecs.ini
access_key=“AK"
secret_key=“SK"
project_id=“项目ID“ 在华为云后台我的凭据中API处获取
region=“地域“ 资源所在地域 同样在API处获取
3.4 测试连通性
测试inventory文件的正确性 能否获取到清单
./hwc_ecs.py --list 所有动态脚本都需要支持两个参数 --list 所有主机 --host 指定主机信息
3.5 使用动态清单
查询账户内所有ECS主机
ansible all -i hwc_ecs.py --list-hosts
批量测试主机连通性
ansible -i hwc_ecs.py all -m ping -u root -k 所有主机
ansible -i hwc_ecs.py ecs-xxx -m ping -u root -k 单台主机
自定义动态主机清单
约束:
- 无论你的主机清单使用什么语言开发,python、go、java、shell ... 支持两个参数 一个是-- list 列出所有的主机;另外一个是--host 查询单台主机
- 无论如何获取主机,最终输出的格式最好是json(ini和yaml)
使用yaml定义主机清单
所有主机:
主机组:
单台主机
第一种方式:
all:
hosts:
node1:
node2:
第二种方式:
all:
children:
ungrouped:
hosts:
node1:
node2:
node3:
all:
children:
group1:
hosts:
node1:
node2:
node3:
###嵌套组
两种方式定义:
1.通过children指定定义
all:
children:
group1:
hosts:
node1:
node2:
node3:
group2:
children:
group1:
2. 在主机组中直接定义
all:
children:
group2:
children:
group1:
hosts:
node1:
node2:
node3:
定义单个主机变量:
all:
children:
ungrouped:
hosts:
servera:
web: nginx
定义主机组变量:
all:
children:
webserver:
hosts:
serverc:
serverd:
vars:
web: nginx
PS:如果主机组和主机变量名称相同,则主机覆盖主机组的变量
将现有的INI格式的主机清单转成yaml格式清单
ansible-inventory --yaml -i hosts --list --output /data/inventory_v1.yaml
--yaml 指定输出的格式
-i 指定主机清单文件的路径
--list 列出所有的主机
--output 输出到文件
ansible-inventory -i test.yml --graph 按照图表的方式输出
高级提权与任务执行
在ansible执行任务的过程,涉及到高风险的操作,往往需要提权;但是在一个项目并非所有的操作都需要提权
ansible中提权的位置:
- playbook
- roles
- block
- task
- hosts
提权的配置项:
pbecome: True 开启提权
pbecome_user 提权到的用户
pbecome_method 提权的方式(sudo、su、pbrun、dzdo 等取决于目标主机使用何种方式配置权限)
pbecome_ask_pass 提权是否需要验证密码 become_password 直接指定密码已在 2.5版本废弃
n如需指定密码在主机中使用ansible_become_pass 变量或者使用外部加密的文件
pbecome_flags 提权的参数
nbecome_flags: -H:将 -H 标志传递给 sudo 命令,表示在切换用户时保持环境变量
nbecome_flags: -r:将 -r 标志传递给 su 命令,表示以登录方式切换到目标用户
- playbook提权
- hosts: node2
gather_facts: no
become: true
tasks:
- shell: touch /opt/aaa.txt
- roles提权
- hosts: node2
gather_facts: no
roles:
- role: testroles
become: true
- role: role1
- block提权
- hosts: node2
gather_facts: no
tasks:
- block:
- shell: touch /opt/block.txt
become: true
- name: test file
shell: touch /opt/shell.txt
- task提权
- hosts: node2
gather_facts: no
tasks:
- block:
- shell: touch /opt/block.txt
become: true
- name: test file
shell: touch /opt/shell.txt
become: true
- hosts提权
vim hosts
node2 ansible_become=true
ansible的任务执行
- 任务的执行顺序
默认是根据playbook中任务编写的顺序执行(任务并非是从上到下执行)
pre_tasks
pre_tasks 中触发的handler
roles
task
roles和task中触发的handler
post_tasks
post_tasks中触发的handler
pre roles和tasks post
- 对ansible中的任务进行标记
当用户对ansible中的playbook进行任务标记后,也就是对任务或者是role打tag;通过tag可以有选择的执行任务;可以执行指定tag的任务或者是跳过指定tag的任务
标记tag的方式:
#单个任务进行tag
- hosts: servera
gather_facts: no
tasks:
- name: debug1
debug:
msg: "hello1"
tags: hello1 添加单个tag
- name: debug2
debug:
msg: "hello2"
tags: 添加多个tag
- hello1
- hello2
- name: debug3
debug:
msg: "hello3"
tags: hello3
#对任务文件进行tag
vim task_file.yml
- name: debug1
debug:
msg: "hello1"
- name: debug2
debug:
msg: "hello2"
- name: debug3
debug:
msg: "hello3"
tags: a1
vim a1.yml
- hosts: servera
gather_facts: no
tasks:
- include_tasks: task_file.yml
tags: a1
- debug:
msg: "hello task........."
ansible-playbook a1.yml --tags=a1
PS: 仅会执行任务文件中任务的tag和任务文件tag相同的任务,如果任务文件中的任务不具备tag则不执行
#对roles进行tag
- hosts: node2
gather_facts: no
roles:
- role: role1
tags: role1
- role: testroles
tags: testroles
#对play进行tag
- hosts: servera
tags: play1
gather_facts: no
tasks:
- debug:
msg: "hello play1........."
- hosts: serverb
tags: play2
gather_facts: no
tasks:
- debug:
msg: "hello play2..........."
- hosts: serverc
tags: play3
gather_facts: no
tasks:
- debug:
msg: "hello play3..........."
#对block进行tag
- name: play1
hosts: serverc
tasks:
- block:
- debug:
msg: "hello1"
- debug:
msg: "hello2"
- debug:
msg: "hello3"
tags: hello
- debug:
msg: "hello4"
tag的万能标签
编辑时的标签
always 只要任务打上该标签则,无论执行playbook时指定的标签是否匹配都会执行(一直执行;永远都会执行的任务)
never 只要任务打上该标签,则任务永远不会执行,但是如果手动指定该标签则执行(从不执行的任务)
执行时的标签
ansible-playbook a2.yml --tags=all 执行所有的标签,但是never 不会执行(默认就是该项)
ansible-playbook a2.yml --tags=tagged 执行所有的标签,但是never 不会执行
ansible-playbook a2.yml --tags=untagged 执行所有没有打标签的任务,但是always会执行
执行剧本的方式:
执行指定tags的任务 ansible-playbook filename.yml --tags tagname
执行多个tags的任务 ansible-playbook filename.yml --tags tagname1,tagname2
跳过指定tags的任务 ansible-playbook filename.yml --skip-tags tagname
跳过多个tags的任务 ansible-playbook filename.yml --skip-tags tagname1,tagname2
列出剧本中所有存在标签的任务 ansible-playbook filename.yml --list-tags
Ansible的条件语句
一、使用场景
条件语句在Ansible中的使用场景:
在目标主机上定义了一个硬限制,比如目标主机的最小内存必须达到多少,才能执行该task
捕获一个命令的输出,根据命令输出结果的不同以触发不同的task
根据不同目标主机的facts,以定义不同的task
根据目标机的cpu的大小,以调优相关应用性能
用于判断某个服务的配置文件是否发生变更,以确定是否需要重启服务
二、条件表达式
#比较运算符
==:比较两个对象是否相等,相等则返回真。可用于比较字符串和数字
!=:比较两个对象是否不等,不等则为真。
>:比较两个对象的大小,左边的值大于右边的值,则为真
<:比较两个对象的大小,左边的值小于右边的值,则为真
>=:比较两个对象的大小,左边的值大于等于右边的值,则为真
<=:比较两个对象的大小,左边的值小于等于右边的值,则为真
when: ansible_machine == "x86_64"
when: max_memory <= 512
#逻辑运算符
and:逻辑与,当左边和右边两个表达式同时为真,则返回真
or:逻辑或,当左右和右边两个表达式任意一个为真,则返回真
not:逻辑否/非,对表达式取反
():当一组表达式组合在一起,形成一个更大的表达式,组合内的所有表达式都是逻辑与的关系
when: ansible_hostname == "servera" and ansible_fqdn == "servera.lab.example.com"
when: ansible_hostname == "servera" or ansible_fqdn == "serverb.lab.example.com"
when: not ansible_hostname == "servera"
when: (ansible_hostname == "servera" and ansible_machine == "x86_64") or (ansible_hostname == "serverb" and ansible_memtotal_mb <= 809)
#路径判断条件
注意: 所有针对路径的判断,所判断的路径都是来自于主控而不是被控
file:判断指定路径是否为一个文件,是则为真
directory:判断指定路径是否为一个目录,是则为真
link:判断指定路径是否为一个软链接,是则为真
mount:判断指定路径是否为一个挂载点,是则为真
exists:判断指定路径是否存在,存在则为真
- hosts: all
vars:
get_path: /etc/ansible
tasks:
- name: debug info
debug:
msg: "hello severa"
when: get_path is file
#变量的判断条件
defined:判断变量是否已定义,已定义则返回真
undefined:判断变量是否未定义,未定义则返回真
none:判断变量的值是否为空,如果变量已定义且值为空,则返回真
when: get_path is defined
when: get_path is none
when: get_path is undefined
#执行结果的判断条件
ok:目标状态与期望值一致,没有发生变更 #在core 2.11中没有生效
change或changed:目标发生变更,与期望值一样
sucess或succeeded:目标状态与期望值一致,或者任务执行成功
failure或failed:任务执行失败
skip或skipped:任务被跳过
- hosts: servera
tasks:
- name: hello1
file:
path: /etc/hostname
state: file
register: get_file
- name: debug info2
debug:
msg: " task exec Ok"
when: get_file is changed
#字符串的判断条件
lower:判断字符串中的所有字母是否都是小写,是则为真
upper:判断字符串中的所有字母是否都是大写,是则为真
- hosts: servera
vars:
up: REDHAT
le: rhca
tasks:
- name: debug info2
debug:
msg: " String1 Ok"
when: up is upper
- name: debug info3
debug:
msg: " String2 Ok"
when: le is lower
#整除判断条件
even:判断数值是否为偶数,是则为真
odd:判断数值是否为奇数,是则为真
divisibleby(num):判断是否可以整除指定的数值,是则为真
- hosts: servera
gather_facts: no
vars:
n1: 6
n2: 8
n3: 15
tasks:
- name: debug info1
debug:
msg: "hello1"
when: n1 is even
- name: debug info2
debug:
msg: "hello2"
when: n2 is odd
- name: debug info3
debug:
msg: "hello3"
when: n3 is divisibleby(5)
方式二:
- name: debug info1
debug:
msg: "hello1"
when: n2%2 == 0
- name: debug info2
debug:
msg: "hello2"
when: n2%2 == 1
#比较指定的版本条件
version(“版本号”,“比较运算符”)
大于: >, gt
大于等于: >=, ge
小于: <, lt
小于等于: <=, le
等于: =, ==, eq
不等于: !=, <>, ne
- hosts: servera
gather_facts: no
tasks:
- name: debug
debug:
var: ansible_version.full
when: ansible_version.full is version("2.13.4","eq")
#其他条件测试,非常用
集合的判断
子集 subset
父集
- hosts: servera
gather_facts: no
vars:
os_type:
- rhel
- fedora
- centos
- openeuler
- ubuntu
get_os:
- centos
- rhel
tasks:
- name: debug
debug:
msg: "test ok"
# when: get_os is subset(os_type)
# when: os_type is superset(get_os)
字符串的包含条件
in
- hosts: servera
gather_facts: no
vars:
os_type:
- rhel
- fedora
- centos
- openeuler
- ubuntu
get_os: rhel
tasks:
- name: debug
debug:
msg: "test ok"
when: get_os in os_type
#数字和字符串的判断条件
string 判断对象是否为一个字符串
number 判断对象是否为一个数字
- hosts: servera
gather_facts: no
vars:
version: 10
get_os: rhel
tasks:
- name: debug
debug:
msg: "test ok"
#when: get_os is string
when: version is number
nsible_version.full is version("2.13.4","eq")
多个任务使用同一个条件如何进行判断
- 多个任务使用同一个条件进行判断在block中
block 是将多个任务包含在一个区块中,通过对区块进行判断,达到判断所有任务的用途
- hosts: all
tasks:
- name: block use
block: #只需要对block进行一次判断就可以实现所有的任务复用条件,多个任务使用同一个条件通过block来完成
- name: debug info1
debug:
msg: "hello servera for debug info1"
- name: debug info1
debug:
msg: "hello servera for debug info1"
- name: debug info1
debug:
msg: "hello servera for debug info1"
- name: debug info1
debug:
msg: "hello servera for debug info1"
when: ansible_hostname == "servera"
- block中的任务具有修复性
如果block中的任务出现了错误,则直接rescue段落中的任务
rescue 修复段落,一定要block中的任务报错,才会执行该段落
#当文件不存在,通过rescue执行创建文件的任务,文件存在则不执行创建任务
- hosts: servera
tasks:
- name: block use
block:
- name: get file
file:
path: /opt/rhca.txt
state: file
rescue:
- name: create file
file:
path: /opt/rhca.txt
state: touch
- always是无论如何都需要执行的任务
always的任务,不会受到block中任务的错误影响,一直会执行
- hosts: servera
tasks:
- name: block use
block:
- name: get file
file:
path: /opt/rhca.txt
state: file
rescue:
- name: create file
file:
path: /opt/rhca.txt
state: touch
always: # 不管block中的任务是否出错,always的任务一直都会执行
- name: debug info
debug:
msg: "hello do374"
剧本退出与有条件的退出
fail 模块在playbook中用来终止playbook的执行
- hosts: servera
tasks:
- name: get file
file:
path: /opt/rhca.txt
state: file
- name: exit playbook
fail:
msg: "exit playbook"
- name: debug info
debug:
msg: "hello do374"
带有条件的退出剧本
failed_when 直接根条件,条件成立则剧本退出
- hosts: servera
tasks:
- name: debug info
debug:
msg: "exit playbook"
failed_when: ansible_version.full != "2.13.4"
- name: debug info
debug:
msg: "hello do374"
Ansible的循环语句
在ansible的playbook中有许多循环的场景,例如循环创建用户,批量进行配置;以及循环安装软件包(如果使用yum、pkgs等模块是不需要循环的)
循环的对象:
列表: with\_items 
循环的方式:
方式一,通过变量进行循环
- hosts: servera
vars:
user_list:
- bob
- tom
- john
- alice
tasks:
- name: create user
user:
name: "{{ item }}"
state: present
with_items: "{{ user_list }}"
方式二:
- hosts: servera
tasks:
- name: create group
group:
name: "{{ item }}"
state: present
with_items:
- itgroup
- sagroup
方式三:
- hosts: servera
gather_facts: no
tasks:
- name:
group:
name: "{{ item }}"
state: present
with_items:
["group1","group2","group3"]
使用with\_dict 做基于字典的循环
- hosts: servera
vars:
user_list:
ituser1:
name: ituser1
uid: 3000
home: /data/ituser1
ituser2:
name: ituser2
uid: 4000
home: /data/ituser2
tasks:
- name: create user
user:
name: "{{ item.value.name }}"
#item 就是循环的变量也就是user_list,value是是user_list的值,因此value是ituser1和ituser2
uid: "{{ item.value.uid }}"
home: "{{ item.value.home }}"
state: present
with_dict: "{{ user_list }}"
使用loop进行循环统一
loop本身是循环列表的,在ansible2.5以后开始使用,通过过滤器dict2items (将字典结构转换成列表)来循环字典结构
- hosts: servera
tasks:
- user:
name: "{{ item }}"
state: present
loop:
- user1
- user2
- user3
--------------------------------------------
- hosts: servera
vars:
user_list:
ituser1:
name: ituser1
uid: 3000
home: /data/ituser1
ituser2:
name: ituser2
uid: 4000
home: /data/ituser2
tasks:
- name: create user
user:
name: "{{ item.value.name }}"
uid: "{{ item.value.uid }}"
home: "{{ item.value.home }}"
state: present
loop: "{{ user_list|dict2items }}" #将字典转化成列表
Ansible滚动更新
1. 任务委派
所谓的任务委派就是将原本被控节点所运行的任务,交给特定的节点来执行;通常是为了让剧本中的特定任务可以执行成功而做的准备工作,哪怕被委派的节点不在主机清单中,只要控制节点可以远程管理,则该主机成功执行任务
跳转主机: 当需要在一个主机上执行任务,但又需要依赖于另一个主机上的数据或配置时,可以使用任务委派。通过将任务委派到拥有所需数据或配置的主机,可以在目标主机上获取必要的信息,并将其传递回控制节点。
异构环境: 在管理具有不同操作系统、不同配置等异构性的环境时,任务委派非常有用。可以将某些任务委派给针对特定类型主机进行优化的专门主机,以提高执行效率。
无法直接访问的网络设备: 对于无法直接访问的网络设备,比如交换机、路由器和防火墙等,可以使用任务委派来执行特定的网络操作,如配置更改或设备重启。
配置收集: 通过将任务委派到已经在网络中部署的代理主机或其他可访问资源,可以收集有关网络中各个主机的配置信息。这样可以快速获取各个设备或主机的配置状态。
特定环境操作: 可以使用任务委派进行一些特定环境下的操作,如容器管理、Kubernetes 节点配置、云服务 API 调用等
示例:
#就是在serverc部署需要下载的文件,并下载到servera和severb
- hosts: servera,serverb
tasks:
- name: install httpd
yum:
name: httpd
state: present
delegate_to: serverc #将任务委派给serverc
- name: start service
systemd:
name: httpd
state: started
delegate_to: serverc
- name: stop service
systemd:
name: firewalld
state: stopped
delegate_to: serverc
- name: touch file
file:
path: /var/www/html/file.txt
state: touch
delegate_to: serverc
- name: get file
get_url:
url: http://serverc.lab.example.com/file.txt
dest: /opt/file.txt
2.事实委派
事实委派是将指定主机的事实变量委派给剧本来进行使用,如果使用delegate_to 将setup的任务交给指定远程主机来执行,则可以获取指定的主机事实变量,但是事实变量仅限获取到远程主机使用,如果不进行委派则剧本无法使用
使用场景:
局部收集事实:有时候你可能只需要在某个特定的主机上收集事实数据,而不是在所有主机上都执行 setup 模块。使用事实委派功能,你可以选择性地在特定的主机上收集事实数据,并将其传递到控制节点,以便后续任务处理
动态主机:当你使用动态主机清单(Dynamic Inventory)时,可能会遇到需要在每个新加入的主机上收集事实数据的情况。使用事实委派,在动态添加的主机上收集事实数据并将其传递到控制节点,以便后续任务使用
分布式环境:在分布式环境中,你可能需要在不同的主机群组中执行任务,并将结果传递到控制节点。通过将事实委派给其他主机,你可以在不同的主机群组上执行任务,并将其结果传递到一个集中的位置
- hosts: servera
gather_facts: no
tasks:
- name: get servera facts
setup:
delegate_facts: true
delegate_to: serverb
- name: set ip info
shell: echo "{{ hostvars['serverb'].ansible_eth0.ipv4.address }}" >> /opt/ip.txt
3.事实变量缓存
缓存的目的: 就是的为了playbook的执行加速,不需要每次运行playbook都进行一次事实收集
缓存的方式有三种:
jsonfile ——> 本地缓存
memcached ——> 在数据库中进行缓存
redis ——> 支持redis加速缓存
- 开启缓存
在ansible.cfg的defaults段落中
gathering = 指定事实变量获取的方式
#smart
智能收集 如果本地存在缓存,则使用缓存;如果本地不存在缓存,则收集事实变量并缓存
#implicit
一直收集事实变量(收集)
#explicit
从不收集事实变量,除非在playbook中手动指定gather_facts:true 才会进行收集
fact_caching_timeout = 86400 缓存的有效期,超时后重新进行缓存;单位为秒
fact_caching = #指定缓存的方式,也就是 jsonfile、memcached、redis三选一
jsonfile配置示例
[defaults]
gathering = smart
fact_caching_timeout = 86400
fact_caching = jsonfile
fact_caching_connection = ./facts_cache
memcached示例:
[defaults]
gathering = smart
fact_caching_timeout = 86400
fact_caching = memcached
fact_caching_connection = 127.0.0.1:11211
redis示例
[defaults]
gathering = smart
fact_caching_timeout = 86400
fact_caching = redis
fact_caching_connection = 127.0.0.1:6379:0
4.ansible滚动更新
所谓的滚动更新就是使得主机按照指定的批次来执行任务;而不是让所有的主机都全部参与任务,如果任务失败,则所有的主机更新失败,将会导致所有的主机都无法提供服务,因此滚动更新,按照批次执行非常重要
在ansible中serial 将主机分批来执行任务,如果一批中太多主机失败了,则可以终止剧本的执行
serial 支持设置
–批量固定大小
–批量百分比大小
–批量大小可更改
示例: 固定批次执行
- hosts: all
serial: 2 #每次选择两台主机执行
tasks:
- debug:
var: ansible_hostname
示例: 百分比大小
serial 的值为 25%,则无论 all中包含 20 台主机还是 200 台主机,都需要 4 批完成所有主机的play
Ansible 将该百分比应用于主机组中主机的总数量。如果结果值不是主机的整数数量,那么该值将被截断 (四舍五入)到最接近的整数。其余的主机以较小的批处理运行。批处理大小不能为零主机。如果截断的值为零,Ansible 将批处理大小更改为一个主机
- hosts: all
serial: 25%
tasks:
- debug:
var: ansible_hostname
示例: 可变批次大小
- name: get file
hosts: all
serial:
- 1 第一批处理一台
- 10% 第二批处理all主机的10%
- 30% 第三批处理all主机的30%,第三批后剩余部分按all主机的30%处理,直至处理完所有主机
tasks:
- name: get /opt/ansible.txt
debug:
msg: "hello ansible"
5. 控制滚动更新的批次失败主机数量
也就是在一个批次中允许多少台主机失败
max_fail_percentage 当该值为0 时 只要有主机失败则立即结束剧本运行
max_fail_percentage 设置一个批次中允许最大失败的主机数量百分比,如果一个批次中所有的主机都失败,默认情况下playbook停止执行
- hosts: all 只有三台主机 ,因此允许一个批次中故障一台,故障两台则playbook停止执行
serial: 3
max_fail_percentage: 50%
tasks:
- file:
path: /opt/abc.txt
state: file
6.一次性任务
仅执行一次委派任务(无论清单中有多少主机,委派的任务都只在第一台主机上委派执行一次)
- hosts: servera,serverb
tasks:
- file:
path: /opt/do374.txt
state: touch
delegate_to: serverc
run_once: true #仅执行一次
在play中的第一台主机上执行
- hosts: servera,serverb
tasks:
- file:
path: /opt/do374.txt
state: touch
run_once: true
每一个批次的第一台主机上执行
- hosts: all
serial: 3
tasks:
- file:
path: /opt/do374.txt
state: touch
run_once: true
when: inventory_hostname == ansible_play_hosts[0] 仅在第一批的第一台主机上执行
如果没有when的条件则,在每一个批次的第一台主机上执行
剧本交互的方式
通过vars_pormpt 变量来接收用户输入的内容
- name: create user
hosts: servera
vars_prompt:
- name: get_user 定义接收用户输入的用户名
prompt: "请输出用户名:" 输出用户看到提示信息
default: john 定义变量的默认值,也就是用户不输入默认为该值
private: no 定义用户的输入是否可见,如果是该项为no则可见,yes不可见
- name: get_pass
prompt: "请输入密码:"
default: redhat
private: yes
tasks:
- user:
name: "{{ get_user }}"
password: "{{ get_pass|password_hash('sha512') }}"
state: present
定义任务执行所需的环境变量
- hosts: servera
tasks:
- name: exec openstack cli get server list
shell: echo $endpoint_url $username_auth $userpassword >> /opt/osp.txt
environment: #定义任务执行,在被控端所需要的环境变量
endpoint_url: http://example.com:6443
username_auth: admin
userpassword: redhat
剧本中的任务等待
剧本中任务执行的过程中可能需要等待某一些应用或者主机的响应然后再继续向下执行任务。比如某一台主机或者应用刚刚重启,我们需要需要等待它上面的某个端口开启,此时就需要将正在运行的任务暂停,直到其状态满足要求
wait_for的模块参数:
connect_timeout 指定等待期间尝试建立连接的最大时间,单位为秒。如果超过指定的时间仍然无法连接到目标主机,则会引发连接超时错误。
timeout 模块的超时时间 默认为300秒
delay 多少秒检查一次,不指定在300秒内一直轮训检查到满足条件为止
host 等待主机的地址 默认为127.0.0.1
port 等待主机的端口
path 文件的路径,当文件存在时,下一个任务继续执行,等待文件创建成功
state 等待的状态 当文件或端口达到指定的状态,继续向下执行任务
当对象为端口时 started端口开启 stoped 端口关闭
当对象为文件时 present或者started创建 absent 删除
当对象为连接时 drained 连接未建立
ansible中wait_for模块专门用来在剧本执行的过程等待被控端主机达到满足的条件
等待的三种方式:
等待端口被监听
- hosts: servera
tasks:
- wait_for:
host: serverc
port: 80
state: started
timeout: 10
- name: download file
get_url:
url: http://serverc.lab.example.com/file.txt
dest: /opt/test.txt
- hosts: servera
tasks:
- wait_for:
path: /opt/374.txt ### 该文件来自于servera的被控端
state: present
delay: 3
- name: download file
get_url:
url: http://serverc.lab.example.com/file.txt
dest: /opt/test.txt
- hosts: servera
tasks:
- wait_for:
host: 172.25.250.10 ## 该地址是被控端的IP地址
state: drained
port: 22 #监听被控端的22端口
exclude_hosts: 172.25.250.9 #忽略来自于主控的22端口连接
- name: download file
get_url:
url: http://serverc.lab.example.com/file.txt
dest: /opt/test.txt
配置管理与jinja高级用法
ansible中的配置文件修改的模块
——> 配置文件指的是我们在生产中需要修改或者是变更的配置
三大模块专门用来在ansible中进行配置修改:
lineinfile: 主要用来修改文件的单行内容
blockinfile: 修改文件的多行内容(新增或者是删除)
replace: 用来修改单行内容
单行配置文件修改:
lineinfile的常用参数:
path: 修改文件的路径
regexp:正则表达式匹配要修改的行
line:修改或者插入行的内容
insertbefore:在匹配的行前面插入
insertafter:在匹配的行后面插入
backup:是否备份文件
create:文件不存在则创建文件
validate:验证文件修改的有效性,需要文件自带验证机制(ansible无法验证配置文件是否正确)
文件自带的验证机制:
nginx -t 或 httpd -t 通过应用程序本身携带的验证机制来校验配置文件的格式或语法是否有错误
sudo 就是用visudo来验证
PS: 注意点
lineinfile 如果所查找的内容在文件中无法找到则在文件的末尾新增一行
通过backrefs 来调整关键字不存在时是否修改配置文件
backrefs 默认为no ,也就是关键字找不到则新增配置
backrefs 设置为yes ,则关键字找不到配置文件不发生修改,也就是不修改配置文件(也不新增)
简单示例:
将系统的selinux设置为disabled
ansible servera -m lineinfile -a 'path=/etc/sysconfig/selinux regexp="^SELINUX=" line="SELINUX=disabled"'
将系统的selinux模式增加一个配置说明
ansible servera -m lineinfile -a 'path=/etc/sysconfig/selinux insertbefore="^SELINUX=" line="#SELINUX MODE"'
ansible servera -m lineinfile -a 'path=/etc/sysconfig/selinux regexp="^SELINUX=" line="SELINUX=enforcing" backup=yes'
通过配置文件自带的校验机制,在ansible中进行配置修改,如果有误则不修改,如果正确则修改
ansible servera -m lineinfile -a 'path=/etc/sudoers insertbefore="^root" line="john ALL=(ALL) NOPASSWD:ALL" validate="visudo -cf %s"' ——>%S匹配文件的路径
删除某一行配置
ansible servera -m lineinfile -a 'path=/opt/do374.txt regexp="aaaa" state=absent'
blockinfile对配置进行多行操作
多行操作:
新增段落
删除段落
blockinfile常用参数:
path: 操作文件的路径
block: 要操作的区块(也就是段落的内容)
state:
present 新增
absent 删除
marker: 标记(段落标记—> 指的是文件中段落开始和结束的位置符号)
注意: blockinfile 模块只能操作自己标记的内容 marker 通过变量{mark}
{mark} 指代的开始和结束
示例:
- hosts: servera
tasks:
- name: modify file content
blockinfile:
path: /opt/do374.txt
marker: "# test {mark}" #号可以是任何符号,只要是配置文件中的注释符
block: |
hello test
hello rhel
state: present
do374文件的示例:
hello abc
# test BEGIN
hello test
hello rhel
# test END
jinja2的高级用法
jinja2是python的模板引擎,在ansible最基础的用法是在jinja2模板中的变量通过template模板将其渲染成具体的值
jinja 还可以支持条件语句、循环语句、以及各种过滤器
条件语法:
jinja2的判断
if 单分支:
{% if 条件表达式 %}
输出满足条件内容
{% endif %}
示例:
{% if test_vars is defined %} 当test_vars 变量定义时,表达式成立则写入内容
hello ansible
{% endif %}
if 双分支
{% if test_vars is defined %} 条件成立时执行
hello test
{% else %} 条件不成立时执行
hello ansible
{% endif %}
if 多分支
{% if ansible_eth0 is defined %}
web ip: {{ ansible_eth0.ipv4.address }}
{% elif ansible_ens224 is defined %}
web ip: {{ ansible_ens224.ipv4.address }}
{% else %}
web ip: 0.0.0.0
{% endif %}
{% for 变量名 in items %}
输出每个 item
{% endfor %}
例子: 生成集群内主机名和IP的映射关系文件
{% for host in groups.all %}
{{ hostvars[host].ansible_eth0.ipv4.address }} {{ hostvars[host].ansible_fqdn }} {{ hostvars[host].ansible_hostname }}
{% endfor %}
jinja2的过滤器
jinja2的过滤器主要用来对jinja2模板和playbook中的变量进行处理
格式:
{{ 变量名|过滤器 }}
常用的过滤器:
default过滤器 当变量不存在时给变量赋一个默认的值
{{ test1|default('hello') }} 当test1 变量不存在时赋值hello
字符串过滤器
https://gitee.com/yflinux/playbook_demo/blob/master/filter_str.yml
数字过滤器
https://gitee.com/yflinux/playbook_demo/blob/master/filter_number.yml
列表过滤器:
https://gitee.com/yflinux/playbook_demo/blob/master/filter_list.yml
注册变量过滤器(ansible2.9中废弃)
https://gitee.com/yflinux/playbook_demo/blob/master/filter_var.yml
文件相关过滤器(只会对文件的定义变量进行调用,不关注文件本身是否存在)
https://gitee.com/yflinux/playbook_demo/blob/master/filter_file.yml
加解密相关的过滤器:
https://gitee.com/yflinux/playbook_demo/blob/master/filter_pass.yml
查找替换的过滤器:
https://gitee.com/yflinux/playbook_demo/blob/master/filter_replace.yml
字典过滤器
https://gitee.com/yflinux/playbook_demo/blob/master/filter_dict.yml
Ansible性能优化
Ansible的调优 可以调哪些项???
剧本的执行速度?
任务的模块选择?
执行的主机数量?
ssh的连接?
.....
ansible 的任务优化 ansiblede 连接优化
ansible的调试
- 执行前检查
ansible-playbook --check b1.yml 仅测试运行不会真正执行 - 检查特定任务在主机上的变化
--limit 限制任务在特定主机上执行
--diff 比较任务前后执行的差异 通常用在配置文件修改的变化上 - 多用debug模块打印调试信息
- 中断剧本调试
assert模块 来对剧本进行中断(条件不成立时剧本自动终止)
参数:
that 条件判断(that后的判断语句不需要引号和括号括起来)
success_msg: 条件满足
fail_msg:条件不满足 则输出错误内容且中断剧本 - 运行指定剧本中指定的任务以及该任务后的所有任务
--start-at-task 任务名称或者模块名 将会从指定的任务开始执行,如果名称和模块有重复。在一个剧本中,则ansible根据剧本从上到到下的顺序找到的第一个任务开始执行 - 有选择的执行任务
--step
y 执行任务
n 跳过任务
c 执行接下来的所有任务而不再询问
ansible的回调插件
通过ansible的回调插件可以跟踪到ansible在执行任务时,所消耗的时间以及ansible所占用的cpu和内存
callback_whitelist ——> 从ansible-core 2.15开始使用callback_enabled进行替代
ansible-doc -t callback -l 查询回调插件支持的方法
常用的支持方式:
timer 显示剧本执行的时间
profile_tasks显示任务开始的时间和任务使用的时间(根据降序来进行排列)
profile_roles 显示角色开始的时间和使用的时间
cgroup_perf_recap 通过cgroup来记录任务所用的cpu和内存以及pid数量
cgcreate -a root:root -t root:root -g cpuacct,memory,pids:ansible_profile
cgcreate 创建资源组 该工具在libcgroup-tools 包中,如果没有需要通过yum安装包
-t 指定cgroup的拥有人和拥有组
-a group:user 指定了授权访问该 cgroup 的用户组和用户
-g cpuacct,memory,pids 指定在 cgroup 中启用控制器
cpuacct ——>CPU控制器
memory ——> 内存控制器
pids ——> 进程控制器
ansible_profile 是指控制组的名称
ansible的配置示例:
ansible.cfg
callbacks_enabled = timer,profile_tasks,cgroup_perf_recap
[callback_cgroup_perf_recap]
control_group=ansible_profile 控制组的名称
任务的优化:
避免无效循环,使用模块原生支持的多参数
例如yum模块可以接收多个参数装包,而无需使用循环
减少lineinfile模块使用,通过jinja2部署模板到配置文件
lineinfile消耗资源更多,而jinja2模板可以直接传输配置文件
文件传输应尽量使用rsync的方式进行而不应该使用copy
传输文件比拷贝文件效率更高
连接的优化
- SSH的多路复用
因为ansible需要在一台主机上执行多个任务,每一个任务的执行都需要进行一次ssh的连接,如果有多个任务,就会导致连接的TCP套接字反复创建
所谓的多路复用指的就是,通过一次ssh的连接完成多个任务的执行
[ssh_connection] 在ansible.cfg中配置 ;在ansible-core已经自动配置好
ssh_args = ‐C ‐o ControlMaster=auto ‐o ControlPersist=60s
ControlMaster:启用ssh multiplexing,auto用于告诉ssh在主连接和控制套接字不存在的情况下,自动创建它们
ControlPersist:在主连接和控制套接字创建后的多长时间内,如果一直没有ssh连接,就关闭它们 - 任务流水线
所谓的任务流水线指的就是 将ansible的文件复制以及文件的执行合并到一步ssh来进行完成;
因为ansible是根据playbook中用户编写的任务参数,使用指定模块将任务参数封装成一个python脚本的文件,然后将这个脚本推送到被控端上去执行;那么此时需要进行至少两次ssh的连接,第一次是做文件的复制,第二次是做脚本的执行,通过流水线管道将两个任务一次ssh来完成执行
在ansible.cfg的defaults段落中开启pipelining = True - forks 同时在多个主机上进行并发执行
所谓的并发指的是同一个任务同时在多个主机上执行
forks = 100 主机数 即可同时在多个主机上执行 要根据业务场景调整合适的大小 - 设置并发的超时时间
async 将任务放到后台去执行,并且设置任务的超时时间,如果有poll 则会设置检测的时间
- hosts: all
tasks:
- copy:
src: fork.sh
dest: /opt/fork.sh
mode: 777
- shell: /opt/fork.sh
async: 10 将超时的时间设置为10s
poll: 0 多少秒检查一次 当值为0 时不等待超时,直接执行下面的任务
- debug:
msg: "hello ansible"
高并发的异步场景:
优先考虑高并发完成
某个任务需要很长的运行时间才能完成,并且容易超时
某个任务需要在大量的主机上执行
某个任务执行后不需要等待它的执行状态完成
不建议使用并发完成
某个任务的执行状态决定了后续任务能否执行(例如有判断)
任务很快就能执行完成
GIT的版本管理与自动化平台集成
git 是一个分布式版本管理系统
版本管理系统中:
集中式: 修改中央服务器的文件
分布式:每一个用户都有一份独立的副本,独立的副本不受到用户间的影响(如何解决版本的互认)
git的仓库:
github 全球最大的代码托管平台
gitlab 社区级企业代码托管平台(自建)(gitlab-ee 企业级收费版 gitlab-ce 开源社区版)
gitee 国内的代码托管平台
工作区 ——> 暂存区 ——>远程仓库
ansible自动化平台的发展史
awx ——> tower ——> automation自动化控制器
awx 开源 自动化平台
tower 红帽企业级自动化平台 ——> 平台本身即是控制节点也是执行节点(安装tower的节点本身是管理平台又是ansible引擎的执行节点) tower + ansible才具备自动化能力
automation 红帽的自动化控制器(将控制节点与执行节点解耦)
automation 控制器安装(单节点示例)
单节点: 将数据库和自动化平台安装在一台主机上
集群部署:
- 下载得到安装介质(离线安装包)
https://access.redhat.com/downloads/content/480/ver=2.4/rhel---9/2.4/x86_64/product-software
- 将包解压 tar -xzf ansible-automation-platform-setup-bundle-2.4-6.2-x86_64.tar.gz
- 编辑inventory的文件
[automationcontroller]
172.18.0.214 配置ansible自动化控制器的安装节点 (该节点需要免密)
[all:vars]
admin_password='redhat' 将平台的管理员账号设置为redhat
pg_password='redhat' 设置数据库的密码
- 执行安装脚本
./setup.sh
automation平台的操作
一、如何在平台上执行ad-hoc
- 主机清单(被控节点)
在ansible tower 中有静态主机清单和动态主机清单(智能清单)
在ansibleautomation 中主机清单(静态和动态清单)、智能清单(可以够已知的清单中根据标签来过滤出一组主机)、构建清单(通过外部的api接口来获取主机) - 认证的凭据(连接到被控的密码或者是秘钥)
在凭据中——> 添加机器的凭据 (也就是为被控配置远程连接的用户和密码)
- 通过清单中的主机来执行任务
二、如何在平台上执行playbook
- playbook的存放位置 ——>对应平台的项目这个栏位
- 存放在外部的gitlab版本管理的仓库中
- 手动在/var/lib/awx/projects 中创建一个子目录作为项目
- playbook的执行方式——> 对应平台上的模板栏位
作业模板 ——> 指的是可以执行单一的playbook任务
工作流模板 ——> 指的是可以将多个单一的playbook的任务按照一定逻辑条件组合在一起形成工作流——> 也就是一次执行多个playbook(作业模板)
工作流中的:
节点类型: 节点具体是做什么操作(可以运行任务、同步项目、同步主机...)
收敛节点: all any
ALL:当所有的父节点都满足状态时,当前节点执行
ANY:当所有的父节点有一个节点满足状态时,当前节点执行
节点别名: 节点的人为命名——>标识符
三、平台的高级特性
- 权限管理
组织 全局唯一标识符
团队 团队是一组用户的集合(用户可以没有团队)
用户 (用户 必须要属于一个组织)
在平台上的资源都可以分配权限,并且可以通过给组织或者是team分配权限来达到对用户的集中分配 - 执行环境管理
执行节点
节点的类型: 混合节点: 即是自动化平台又是任务的执行节点
执行节点 仅是任务的执行节点(也就是该节点只会运行自动化的执行环境)
控制节点 仅负责自动化的平台运行
跃点节点 跳板机
自定义内容集合和执行环境
一、自定义内容集合
创建内容集合的流程:
内容集合的组成: 命名空间.集合名称(用点分隔)
内容集合是有ansible的版本要求: 并非所有的版本都支持内容集合,也就是ansible2.8以前的版本是不支持内容集合的,仅支持roles的角色
- 初始化内容集合的目录结构
ansible-galaxy collection init 命名空间.集合名称
目录的作用:
docs 目录用于存储其他文档。您可以使用它来提供有关模块和插件的详细文档
galaxy.yml 文件中包含构建和发布集合所需的信息
plugins 存放模块和插件的文件以及过滤器
README.md 在自动化中心中页面上的描述信息,它通常提供一些安装说明并列出所需的依赖项。Ansible Galaxy 等分发平台或私有自动化中心使用该文件作为集合的首页。
roles 存放集合中的角色
requirements.txt 指定python的依赖性(可选 默认不创建该文件)python依赖包
bindep.txt 指定执行环境中安装的软件包(可选 默认不创建该文件) rpm依赖包
meta/runtime.yml 如果制作的集合要发布到自动化中心上,就必须要在runtime中指定ansible的版本,只有特定的版本才能运行这个集合 - 在集合中添加模块和插件以及过滤器 和角色
在集合的根目录下plugins/
action: 这个目录包含了用于执行任务的动作插件,比如复制文件、执行命令等
become: 这个目录包含了用于特权提升(比如通过sudo或su)的插件。
cache: 该目录包含缓存插件,用于在不同的执行中存储数据以提高性能。
callback: 这个目录包含了用于处理任务执行结果的回调插件,比如生成不同格式的输出或者发送通知。
cliconf: 这个目录包含用于配置CLI(命令行界面)的插件。
connection: 这个目录包含了用于不同连接类型的插件,比如SSH、WinRM等。
filter: 这个目录包含了用于数据筛选和处理的插件。
httpapi: 该目录包含用于与HTTP API交互的插件。
inventory: 这个目录包含了用于动态生成主机清单的插件,比如从云提供商获取主机列表。
lookup: 这个目录包含了用于在Ansible中查找数据的插件。
module_utils: 这个目录包含了用于编写模块的工具和辅助函数。
modules: 这个目录包含了Ansible的核心模块,用于执行各种任务,比如管理文件、安装软件等。
netconf: 这个目录包含了用于与网络设备通信的插件。
shell: 这个目录包含了用于执行本地Shell命令的插件。
strategy: 这个目录包含了用于执行任务的不同策略的插件,比如并行执行、顺序执行等。
terminal: 这个目录包含了用于控制终端的插件。
test: 这个目录包含了用于测试Ansible的插件。
vars: 这个目录包含了用于定义变量的插件,比如从外部数据源获取变量
- 配置集合的元数据 galaxy.yml
namespace: mynamespace 命名空间
name: mycollection 集合名
version: 1.0.0 版本
readme: README.md 说明文件
authors:
- your name <example@domain.com> 作者和邮箱
description: Ansible modules to manage my company‘s custom software 描述
license: 开源协议
- GPL-3.0-or-later
repository: https://git.example.com/training/my-collection git仓库地址 (必须包含仓4库地址)
# The URL to any online docs
documentation: https://git.example.com/training/my-collection/tree/main/docs 使用文档
# The URL to the homepage of the collection/project
homepage: https://git.example.com/training/my-collection 集合介绍页
# The URL to the collection issue tracker 集合issue地址
issues: https://git.example.com/training/my-collection/issues
dependencies: 集合依赖 ansible.builtin 默认集合依赖无需声明
community.general: '>=1.0.0'
ansible.posix: '>=1.0.0'
- 配置集合的依赖(所有的文件都放在集合根目录下)
python的依赖 requirements.txt
示例格式:
botocore>=1.18.0
boto3>=1.15.0
boto>=2.49.0
执行环境的依赖(也就是系统的依赖 )bindep.txt
rsync [platform:centos-8 platform:rhel-8] ——> 针对特定发行版
rsync [platform:rpm] ——> 针对特定包管理器
ansible的依赖 meta/runtime.yml
requires_ansible: ">=2.10" 指定ansible的版本 - 构建集合
在集合的目录下进行构建
ansible-galaxy collection build
- 发布集合
WEB UI 图形化发布
创建命名空间
上传集合检测
同意发布
命令行发布
创建命令空间,配置该命名空间的私有仓库地址
[galaxy]
server_list = yutian,rh-certified_repo
[galaxy_server.yutian]
url=https://hub.lab.example.com/api/galaxy/content/inbound-yutian
token=d7e887eddd7aa846e1b47a17099be095203adc61
ansible-galaxy collection publish collection.tar.gz
二、自定义执行环境
自定义执行环境就是将内容集合放到容器镜像中
默认在构建的过程中需要联网
- 自动化执行环境的构建
构建工具 ansible-build
构建镜像 registry.redhat.io/ansible-automation-platform-22/ansible-builder-rhel8:latest 专门用在将自定义的内容集合放到执行环境中
基础镜像 registry.redhat.io/ansible-automation-platform-22/ee-minimal-rhel8:latest 基础镜像中包含ansible-core以及ansible所需要的执行环境 - 自动化执行环境的配置文件
execution-environment.yml
version: 1 #版本号
build_arg_defaults: 构建参数
EE_BASE_IMAGE: hub.lab.example.com/ee-minimal-rhel8:latest #基础镜像
EE_BUILDER_IMAGE: hub.lab.example.com/ansible-builder-rhel8:latest #构建镜像
ansible_config: ansible.cfg #ansible.cfg配置文件 #如果安装的集合无需身份验证,则无需配置此项
dependencies: #依赖性
galaxy: requirements.yml #声明内容集合
python: requirements.txt #声明python软件包
system: bindep.txt #声明执行环境中要安装的rpm包
dependencies: #依赖性
- 自动化执行环境参数配置
配置内容集合、配置python的依赖、配置系统的依赖 - 构建自动化执行环境
直接构建
ansible-builder build --tag ee-demo:v1.0
高级构建(先生成Containerfile,然后在通过containerfile构建容器镜像)
ansible-builder create 生成构建的Containfiler
可以将一些外部的文件通过Containerfile的指令拷贝到容器镜像,例如仓库的ca证书(SSL证书文件),或者是ssh的私钥可以拷贝到容器镜像中
podman build -f context/Containerfile -t demo:v1 context
EX374集训
准备工作:
- 配置f0可以访问外部网络
- 将git的材料配置好
解题思路:
- 配置git的用户
- git的用户名
- git的邮箱
- git的推送策略
- git的缓存
- git config -l 查看验证git的配置
- 创建用户
- 在清单中增加serverc的主机
- 在用户的变量列表文件中增加一个用户
- 安装并配置ansible的导航器,以及导航器的配置文件
- 使用导航器测试用户的剧本
- 测试通过没有问题,使用git提交更改到仓库
- 管理web服务器
- 在剧本中增加一个notify的关键字监听任务
- 在剧本中编写一个handler的任务来重启服务
- 导航器执行剧本
- 没有问题 更改提交
- 管理网站内容
- 在剧本中添加一个copy的任务,该任务使用不同的标签定义两次
- 使用标签测试任务的运行
- 测试通过 提交到仓库
- ansible性能调优
- 在ansible.cfg 中增加forks=45,增加 gathering = explicit
- 提交更改
- 从列表创建用户
- 编写创建用户的剧本,该剧本使用loop循环用户的变量文件
- 用户的密码和描述信息是考点,用户的密码使用lookup插件的password方法获得
- 用户的描述信息 使用首字母大写的过滤器来定义capitalize
- 测试剧本,没有问题提交更改
- 安装collection的集合
- 在hub上下载集合
- 将下载的集合传输到虚拟机
- 在虚拟机中创建集合目录并安装集合
- 创建自定义Collection
- 拉取项目后初始化一个集合的目录结构
- 在集合的角色目录中创建newuser的角色
- 将项目中的文件拷贝集合的角色目录
- 在集合根目录下创建meta/runtime.yml的文件并指定ansible的版本
- 构建集合并上传到hub(在hub中新建命名空间并上传集合,考试时命名空间已经创建)
- 自定义执行环境1
- 创建工作目录
- 配置执行环境的配置文件
- 定义配置文件中的基础镜像 构建镜像以及集合的配置文件
- 编写集合的配置文件requirements.yml
- 生成构建镜像的Containerfile
- 将集合的压缩包拷贝到context/_build的目录中
- 开始构建镜像
- 上传镜像到hub
- 自定义执行环境2
- 创建工作目录
- 配置执行环境的配置文件
- 定义配置文件中的基础镜像 构建镜像以及系统软件包的配置文件
- 编写系统软件包的配置文件bindep.txt
- 生成构建镜像的Containerfile
- 开始构建镜像
- 上传镜像到hub
- 在执行环境中运行剧本
- 编写main.yml剧本,该剧本使用testing主机组,创建一个文件
- 编写main.sh的脚本,脚本使用导航器加动态清单加指定的执行环境来运行剧本
- 给main.sh和ldap-freeapi.py添加执行权限
- 运行main.sh
- 提交更改
- 在剧本中使用变量
- 编写剧本 使用copy写入一个内容到文件
- 剧本中有五次判断,分别判断 目录存在、目录不存在、目录和文件以及内容存在、目录和内容存在且文件不存在、目录和文件存在且内容不存在
- 使用导航器接剧本的变量测试
- 没有问题提交更改
- 创建剧本
- 编写ansible.cfg的内容集合仓库
- 安装指定的内容集合到指定目录
- 编写剧本使用集合中的角色
- 执行剧本但不要使用执行环境执行
- 验证剧本执行后有没有创建用户
- 验证通过,提交更改
- 配置项目
- 创建git的凭据
- 创建两个项目使用该凭据从git上拉取项目
- 配置清单
- 配置静态清单,并在清单中创建两个主机组,每个主机组中有一台主机
- 配置动态清单,清单来自于一个项目,每一次运行清单都会从git上来取项目,使用项目中的inventory.py作为清单文件
- 为自动化控制器配置执行环境
- 添加执行环境
- 选择默认凭据
- 配置模板
- 创建一个静态清单的模板,使用copy file的项目
- 创建一个动态清单的模板,使用copy file的项目
- 创建一个使用特定执行环境的模板