ansible
是一种基于python开发的自动化运维工具,它只需要在服务端安装ansible
,无需在每个客户端安装客户端程序,通过ssh
的方式来进行客户端服务器的管理,基于模块来实现批量数据配置、批量设备部署以及批量命令执行。
大致的工作原理就是ansible
程序调用读取/etc/ansible/ansible.cfg
(这个是取决于读取配置文件顺序)配置文件,获取主机列表清单hosts
文件,获取所要处理的主机列表,然后查看playbooks
,根据playbooks
生成一个临时的脚本文件,然后将该脚本文件发送给所管理的主机,脚本文件在远程主机上执行完成后返回结果,然后删除本地临时文件。
ansible分为两种工作模式:
adhoc
(点对点模式):此模式相当于对管理主机执行单个shell命令。playbook
(剧本模式):该模式应用较多,该模式是指将一系列任务整合形成一个剧本,以此来达成某种功能(比如部署某个服务,数据备份等)的目的。上述两种模式可类比于一个是用于执行单个shell命令,一个是shell脚本。
本文案例版本:ansible 2.9.27
资源下载:【ansible2.9.27】
# 在线安装
yum -y install epel-release
yum -y install ansible
# 离线安装
# 1、在联网主机下载
yum install --downloadonly --downloaddir=./ epel-release # 先下载epel-release
yum install -y epel-release-7-11.noarch.rpm # 在联网节点安装epel-release
yum install --downloadonly --downloaddir=./ ansible # 下载ansible
# 2、把下载的安装包上传到服务器执行安装
yum install *.rpm
用yum安装之后,会在/etc/ansible/ 下面生成ansible配置文件:
[root@test ~]# ls /etc/ansible/
ansible.cfg hosts roles
因为 ansible 是通过 SSH 连接到目标主机执行配置任务的,所以我们需要先配置 Ansible 控制器到被管理节点的 SSH 免密登录。不然很容易系统报错,无法连接到目标主机。
# 生成密钥并将拷贝密钥至其他主机,包括自己
[root@test ~]# ssh-keygen -t rsa # 生成密钥,默认回车即可
[root@test ~]# ssh-copy-id [email protected]
[root@test ~]# ssh-copy-id [email protected]
[root@test ~] vim /etc/ansible/hosts
[groupA] # 组名可以随便取
192.168.38.13
192.168.38.10
[groupB] # 可以多个组
192.168.38.10
[root@test ~] ansible all -m ping
192.168.38.13 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong" # pong表示在线
}
...
# ansible 是命令,all 表示所有主机,-m ping 表示使用 ping 模块。
# 从结果看,“SUCCESS”表示命令的成功执行,没有发生错误,"changed": false 表示未改变任何东西,"ping": "pong"表示能 ping 通。
# 为了使用 Ansible 命令补全 shell completion 功能,需要安装 Python 的插件 python-argcomplete。
如果没有免密会报错:
[root@test ~] ansible all -m ping 192.168.38.13 | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh: Warning: Permanently added '192.168.38.13' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", "unreachable": true }
ansible_config
变量定义的配置文件./ansible.cfg
文件~/ansible.cfg
文件/etc/ansible/ansible.cfg
文件nventory
:管理的主机清单文件路径library
:ansible的模块存放的目录remote_tmp
:上述工作原理中提到的将脚本发送至对端的临时目录local_tmp
:上述工作原理中提到本地生成脚本存放的临时目录forks
:并发连接数,默认为5sudo_user
:命令执行用户remote_port
:访问管理主机的端口host_key_checking
:设置是否检查SSH主机的密钥,默认为falsetimeout
:ssh连接被管理主机的超时时间log_path
:ansilbe日志文件路径hosts配置文件是ansible管理的主机列表文件,里面记载着管理主机的ip、端口等信息。
其有两种方式:
一是单个主机名或主机ip记录。
二是将某一批主机分组记录,如:
[groupA] # 组名可自定义
192.168.38.10
192.168.38.13
[groupB]
192.168.38.10
当需要对该类主机进行操作时,只要调用dbserver即可调用该分组内所有主机,且此处可支持通配符。
# 语法
[root@test ~]# ansible [-f forks] [-m module_name] [-a args]
# 这次命令对哪些主机生效的
<host-pattern>
group_name # /etc/ansible/hosts中的各组名
ip
all
[-f forks] # 一次处理多少个主机
[-m module_name] # 要使用的模块
[-a args] # 模块特有的参数
# ansible 192.168.10.113 -m command -a 'date'
# ansible groupA -m command -a 'date'
# ansible all -m command -a 'date'
ansible-doc -l
:列出所有模块ansible-doc -s <模块名>
:查看模块的参数信息ansible --version
:查看ansible版本ansible -v
:输出详细信息;-vv
:输出更详细的信息ansible -m
:指定调用的模块名称ansible -a
:调用模块的参数ansilbe -c
:测试命令执行结果,不实际执行ansible -k
:提示输入ssh的密码,而不是基于ssh认证ansible -u
:指定执行命令的用户ansilbe -i
:指定访问的主机列表文件ansilbe -f
:指定并发进程数ansible-doc MODULE_NAME
:查看指定模块用法ansible-doc -s MODULE_NAME
:查看指定模块具体适用模块实际上就是脚本,是ansible调用的对象,主要是用来通过调用它去远程执行某些命令功能。
command
模块和shell
模块都可以用来执行远程命令。它们之间的主要区别是:
command
模块只能运行可执行程序,不能解析shell环境,也就是说,它不会处理变量替换、重定向 (>
, <
, |
, ;
, &&
, etc.) 或者管道等。shell
模块则会传递命令给 /bin/sh -c
在远程节点上执行,所以它可以使用shell特性,如管道、重定向和变量扩展等。另外shell模块会启动shell执行命令,不可以使用shell模块执行交互命令,如vim、top等;command为默认模块,可忽略-m选项;
[root@test ~]# ansible localhost -a 'ps|wc -l' # command模块报错
[root@test ~]# ansible localhost -m shell -a 'ps|wc -l' # shell模块可以
chdir = 目录
:该参数用于切换工作目录。# 在/tmp目录下新建my.txt
[root@test ~]# ansible localhost -m shell -a "chdir=/tmp touch my.txt"
creates = 文件名
:文件存在,不执行shell命令
removes = 文件名
:文件不存在,不执行shell命令
# 如果已经有密钥文件/root/abc文件,则不执行“cat /etc/passwd|head -1”
[root@test ~]# ansible all -m shell -a "cat /etc/passwd|head -1 creates=/root/abc"
# 如果没有/bin/unzip文件,则不执行“unzip xxx.zip”
[root@test ~]# ansible all -m shell "unzip xxx.zip removes=/bin/unzip"
在远程主机上运行ansible服务器上的脚本。脚本不一定非要是shell脚本(也可以是python、perl脚本),可以没有-x权限。
可以将提前编写好的脚本发送给远程主机,批量执行一组命令。注意!脚本执行过程中都必须是非交互式的。
[root@test ~]# cat printIP.sh
#!/bin/bash
echo "This is `hostname -i`"
[root@test ~]# ansible all -m script -a "./printIP.sh"
参数列表:
chdir
: 在运行脚本之前更改到此目录(即 cd chdir
)。executable
: 指定用于执行脚本的程序。例如 /bin/bash
、/usr/bin/python3
等。free_form
: 要执行的本地脚本的路径,被视为模块的主要参数。creates
: 如果此文件或目录存在,则不会运行命令。removes
: 如果此文件或目录不存在,则不会运行命令。decrypt
: (布尔,默认: yes
)是否解密 Vault 加密的脚本。file模块可以创建文件,目录,链接;修改权限和属性等。
# 新建文件[touch]
[root@test ~]# ansible groupB -m file -a "path=/tmp/1.txt state=touch"
# 新建目录[directory]
[root@test ~]# ansible groupB -m file -a "path=/tmp/mydir state=directory"
# 修改文件属性[owner/group]和权限[mode]
[root@test ~]# ansible groupB -m file -a "path=/tmp/1.txt owner=sshd group=adm mode=777"
# 删除目录[absent]
[root@test ~]# ansible groupB -m file -a "path=/tmp/2 state=absent"
# 删除文件[absent]
[root@test ~]# ansible groupB -m file -a "path=/tmp/1.txt state=absent"
# 创建一个软连接[state]
[root@test ~]# ansible groupB -m file -a "src=/etc/hosts path=/tmp/host.txt state=link"
参数列表:
path
: 要管理的文件或者目录的路径。state
: 定义文件或目录应该是什么状态,比如是否存在,是否是目录,是否是软链接等。src
: 当创建软链接时指定源文件。dest
: 当创建软链接时指定目标路径。owner
: 指定文件所有者。group
: 指定文件所属组。mode
: 指定文件权限。将文件拷贝到远程主机,还可以更改文件的权限、所有权或者 SELinux 上下文。
backup=yes
:如果目标主机有同名文件,则先备份。# 将t.sh拷贝到远程的/root目录下
[root@test ~]# ansible groupB -m copy -a "src=~/t.sh dest=/root/ backup=yes"
[root@test ~]# ansible groupB -m copy -a 'src=/etc/fstab dest=/tmp/fstab.ansible owner=root mode=640'
# 通过content可以直接提供文件内容,\n代表回车。
[root@test ~]# ansible groupB -m copy -a "content='hello world\n' dest=/root/hello.txt"
参数列表:
src
: 本地路径(即 Ansible 控制节点的路径)。dest
: 远程路径(即在远程主机上的路径)。content
: 用来复制到目标文件的字符串内容。使用这个参数时,不需要 src
参数。owner
: 指定文件所有者。group
: 指定文件所属组。mode
: 指定文件权限。将远程主机上的文件给拷贝到本地目录。注意!目标路径必须是一个目录。目前不支持目录。
# 将用户组A中所有资产的/etc/hostname拷贝到本地目录
[root@test ~]# ansible groupA -m fetch -a "src=/etc/hostname dest=~/"
192.168.38.13 | CHANGED => {
"changed": true,
"checksum": "d5e8f2dd6bc304e840da365b0a0adac4ccad48f1",
"dest": "/root/192.168.38.13/etc/hostname", # 拷贝到本地的路径
"md5sum": "dc97074d4baad41b91f0c2b380b28499",
"remote_checksum": "d5e8f2dd6bc304e840da365b0a0adac4ccad48f1",
"remote_md5sum": null
}
192.168.38.10 | CHANGED => {
"changed": true,
"checksum": "c136f20c34d4702b89419b397da699fd5c6e6356",
"dest": "/root/192.168.38.10/etc/hostname",
"md5sum": "113134c4b9c2c588b32e9510f07e7ba0",
"remote_checksum": "c136f20c34d4702b89419b397da699fd5c6e6356",
"remote_md5sum": null
}
参数列表:
src
:源文件路径,即在远程主机上的文件路径。dest
:目标目录路径,即在 Ansible 控制节点上的目录路径。 fetched 文件将被存放在这里。flat
:选项决定是否保留源文件的路径结构。如果设置为 yes
,它将把所有源文件放在目标目录下,忽略原始路径信息。如果为 no
(默认值),它将在目标目录下保留源文件的完整路径信息。fail_on_missing
:如果设置为 yes
(默认值),当源文件不存在时,操作将失败。lineinfile 模块:
在修改
单个文件的单行内容时可以使用;它被用于确保文件中的特定行存在或不存在。如果该行不存在,则可以添加;如果该行已经存在但不匹配我们的预期,那么可以替换原有行。
# 在/etc/issue文件中添加一行内容hello world,默认添加到最后
[root@test ~]# ansible groupB -m lineinfile -a "path=/etc/issue line='hello world'"
# 基于幂等原则,重复执行,不会创建多行内容
[root@test ~]# ansible groupB -m lineinfile -a "path=/etc/issue line='hello world'"
# 将内容插入到“Kernel”行的后面,如果存在多个“Kernel”,则插入到最后一个“Kernel”后面
[root@test ~]# ansible groupB -m lineinfile -a "path=/etc/issue line='insert' insertafter='Kernel'"
参数列表:
path
: 需要管理的文件的路径。line
: 要插入的行的内容。regexp
: 用来查找的正则表达式。如果找到匹配的行,那么就会用 line
参数的内容替换该行。state
: 如果为 present
(默认),则确保行存在。如果为 absent
,则确保行不存在。replace 模块:
可以替换
其中某个关键词。(存疑,命令不生效)
[root@test ~]# ansible groupB -m replace -a "path=/etc/issue regexp=hello replace=nihao"
参数列表:
path
: 要操作的文件路径。regexp
: 需要查找并替换的正则表达式。你也可以提供一个简单的字符串,它会被当作一个包含字面量的正则表达式处理(即,任何正则表达式元字符都不具有特殊含义)。replace
: 用来替换找到的匹配项的字符串。backup
: 是否创建一个备份文件,包括时间戳信息以便于你知道修改发生在何时。user模块可以实现linux系统账户管理。
# 创建用户
[root@test ~]# ansible groupB -m user -a "name=tuser1"
# 创建用户、用户id、用户组、家目录
[root@test ~]# ansible groupB -m user -a "name=tuser2 uid=1010 group=adm groups=daemon,root home=/home/tuser2"
# 给用户设置密码,密码要用哈希函数加密
[root@test ~]# ansible groupB -m user -a "name=tuser1 password={{'abc'|password_hash('sha512)}}"
# 修改tuser1账户的附加组
[root@test ~]# ansible groupB -m user -a "name=tuser1 groups=root,daemon"
# 删除账户tuser1
[root@test ~]# ansible groupB -m user -a "name=tuser1 state=absent"
# 删除tuser2账户同时删除家目录、邮箱
[root@test ~]# ansible groupB -m user -a "name=tuser2 state=absent remove=true"
参数列表:
name
: 用户名。password
: 加密过的密码。应使用 openssl passwd
或 mkpasswd
(可选)来创建哈希值。state
: 设置为 present
(默认)表示添加或修改用户,absent
表示删除用户。uid
: 用户的 UID。这是一个可选参数。如果没有提供,系统会自动选择一个可用的 UID。gid
: 用户组标识符。这也是一个可选参数。使用该模块用于在 RHEL/CentOS 类型的系统上添加或删除 Yum 仓库。
[root@test ~]# ansible groupB -m yum_repository -a "name=myyum description=hello baseurl=ftp://192.168.4.254/centos gpgcheck=no"
# 以上命令会新建一个yum源配置文件:/etc/yum.repos.d/myyum.repo
该文件的内容如下:
[root@test ~]# cat /etc/yum.repos.d/myyum.repo
[myyum]
baseurl = ftp://192.168.4.254/centos
gpgcheck = 0
name = hello
# 删除yum源,这里用absent
[root@test ~]# ansible groupB -m yum_repository -a "name=myyum state=absent"
参数列表:
name
: 仓库名称。description
: 仓库描述。默认和 name 相同。file
: 仓库配置文件名称。如果未提供,默认是由 name 参数决定(例如 /etc/yum.repos.d/{{ name }}.repo)。baseurl
: 仓库的 URL。enabled
: 是否启动该仓库。gpgcheck
: 是否校验 GPG 签名。gpgkey
: GPG 密钥的 URL 或文件路径。state
: present(默认)表示添加或修改,absent 表示删除。使用yum模块可以安装、卸载、升级软件包。
# 安装unzip安装包
[root@test ~]# ansible groupB -m yum -a "name=unzip state=present"
# 升级unzip安装包,软件名称可以是*,代表升级所有软件包
[root@test ~]# ansible groupB -m yum -a "name=unzip state=latest"
# 卸载unzip安装包
[root@test ~]# ansible groupB -m yum -a "name=unzip state=absent"
参数列表:
name
:软件包名。可以多个,逗号分隔。state
:软件包应处于的状态。
present
: 安装。latest
: 更新。absent
: 卸载。enablerepo
: 在执行操作时启用的仓库,可以是一个或多个。disablerepo
: 在执行操作时禁用的仓库,可以是一个或多个。list
: 列出一个或多个软件包的信息。管理系统服务(启动、关闭、重启或重新加载服务等)。
# 启动服务
[root@test ~]# ansible groupB -m service -a "name=httpd state=started"
# 停止服务
[root@test ~]# ansible groupB -m service -a "name=httpd state=stopped"
#重启服务
[root@test ~]# ansible groupB -m service -a "name=httpd state=restarted"
# 设置开机启动
[root@test ~]# ansible groupB -m service -a "name=httpd enabled=yes"
参数列表:
name
: 需要管理的服务的名称。state
: 定义服务应该是什么状态,比如 started
、stopped
、restarted
或 reloaded
。enabled
: 如果设置为 yes
,则在启动时启动服务。如果设置为 no
,则在启动时不启动服务。创建、删除卷组(VG),修改卷组大小。
# 安装lvm2软件包
[root@test ~]# ansible groupB -m yum -a "name=lvm2"
# 创建名称为myvg的卷组,该卷组由/dev/sdb1组成
[root@test ~]# ansible groupB -m lvg -a "vg=myvg pvs=/dev/sdb1"
# 修改卷组大小
[root@test ~]# ansible groupB -m lvg -a "vg=myvg pvs=/dev/sdb1,/dev/sdb2"
参数列表:
vg
: 卷组的名称。pvs
:用于创建卷组的物理卷列表,由逗号分隔。vg_options
:在创建或扩展卷组时,要向 vgcreate
或 vgextend
命令传递的附加选项。state
: 如果设置为 “present”,则会创建或扩展卷组;如果设置为 “absent”,则会删除卷组。默认为 “present”。pesize
: 物理区大小,以MB为单位,默认为4MB。创建、删除逻辑卷(LV),修改逻辑卷大小。
# 使用myvg这个卷组创建一个名称为mylv的逻辑卷
[root@test ~]# ansible groupB -m lvol -a "lv=mylv vg=myvg size=2G"
# 修改lv逻辑卷大小
[root@test ~]# ansible groupB -m lvol -a "lv=mylv vg=myvg state=absent force=yes"
# 删除逻辑卷
[root@test ~]# ansible groupB -m lvg -a "vg=myvg state=absent"
参数列表:
vg
: 物理卷属于的卷组的名称。lv
:逻辑卷的名称。size
:逻辑卷的大小。例如:512m、2g 等。state
:如果设置为 “present”,则会创建或调整大小;如果设置为 “absent”,则会删除逻辑卷。默认为 “present”。force
:若设为 ‘yes’,移除逻辑卷时会先取消挂载。默认为 ‘no’。opts
:在创建逻辑卷时,传递给 lvcreate
命令的其他选项。 管理cron
定时任务。
# 每隔10分钟,执行一次/bin/echo hello命令;不写默认都是*,每个任务都必须有一个名字
[root@test ~]# # ansible groupB -m cron -a 'minute="*/10" job="/bin/echo hello" name="test cron job"'
# 查看定时任务
[root@test ~]# # ansible groupB -a 'crontab -l'
# 移除定时任务
[root@test ~]# # ansible groupB -m cron -a 'name="test cron job" state=absent'
参数列表:
name
: 定时任务的名称。这是你创建定时任务的标识。user
: 为指定用户创建定时任务,默认为当前用户。如果你想让特定用户运行该任务,可以在此处指定用户名。job
: 需要定时执行的命令。state
: 如果设置为 “present”,则会创建或更新定时任务;如果设置为 “absent”,则会删除定时任务。默认为 “present”。minute
: 定义任务分钟数(0-59)执行。(*/10
:每隔十分钟;10
:每小时的第十分钟。)hour
: 定义任务小时数(0-23)执行。day
: 定义任务需要在一个月中的哪一天(1-31)执行。month
: 定义任务需要在哪个月份(1-12)执行。weekday
: 定义任务需要在一个星期中的哪一天(0-7, 其中 0 和 7 都表示星期日)执行。setup模块用于收集远程主机的信息,这些信息通常被称为 “facts”。这些 facts 包括但不限于主机名、IP 地址、操作系统版本、内存配置等。
# 获取主机所有信息,列表中信息可以通过filter过滤
[root@test ~]# ansible groupB -m setup
# 获取主机名
[root@test ~]# ansible groupB -m setup -a 'filter=ansible_nodename'
# 获取ip地址
[root@test ~]# ansible groupB -m setup -a 'filter=ansible_default_ipv4'
# 获取内存信息
[root@test ~]# ansible groupB -m setup -a 'filter=ansible_memory_mb'
参数列表:
gather_subset
: 设定要收集哪部分的 facts。可选值包括 ‘all’、‘min’、‘hardware’、‘network’、‘virtual’、‘ohai’ 和 ‘facter’。filter
: 可用于筛选收集的 facts。只有与该参数匹配的 facts 才会被收集。fact_path
: 自定义 fact 文件的路径。用于在远程主机上解压缩文件。它可以处理tar文件(包括gzip、bzip2、xz、lzma压缩格式)以及zip文件。
[root@test ~]# ansible groupB -m unarchive -a 'src=/data/foo.tgz dest=/var/lib/foo'
[root@test ~]# ansible groupB -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777'
[root@test ~]# ansible groupB -m unarchive -a 'src=https://example.com/example.zip dest=/data copy=no'
参数列表:
src
: 需要解压缩的源文件。这可以是在管理主机上的一个文件,也可以是通过HTTP、HTTPS、FTP或者SFTP获取的远程文件。dest
: 文件解压缩的目标路径。所有的文件和目录将会被解压缩到这个指定的目录下。copy
: 如果设置为 “no”,则不会从管理主机复制源文件,而是假定源文件已经位于远程系统上。如果设置为 “yes”,则将源文件从本地管理主机复制到远程系统。默认值是 “yes”。creates
: 一个文件或目录的名称,如果这个文件或目录存在,那么就不执行解压操作。exclude
: 在解压操作中需要排除的文件或目录列表。extra_opts
: 可以传递给解压命令的附加选项数组。用于创建压缩文件。可以处理多种格式,包括tar、gzip、bzip2、xz、zip等。
[root@test ~]# ansible groupB -m archive -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2 owner=wang mode=0600'
参数列表:
path
: 这是一个必需的参数,表示要添加到归档文件中的文件或目录列表。这可以是一个绝对路径,也可以是相对于运行Ansible命令的目录的路径。dest
: 这是将被创建的归档文件的名称和位置。如果省略此选项,归档文件将会在原地创建并使用路径参数中指定的第一个文件或目录的名称。format
: 这定义了归档文件的格式。可能的选择包括 “tar”, “gz”, “bz2”, “xz”, 和 “zip”。owner
: 为归档文件设置一个特殊的所有者。该值可以是用户名或UID。group
: 为归档文件设置一个特殊的组。该值可以是组名或GID。playbook是由一个或多个"play"组成的列表。play的主要功能在于将直线归并为一组的主机装扮实现通过ansible中的task定义好的角色。从根本来讲,所谓的task无非是调用ansible的一个module。将多个play组织在一个playbook内,即可以让它们联动起来按实现编排的机制。
playbook采用YAML语言编写。
在默认情况下,当Ansible运行playbook时,它会首先自动收集一些关于远程主机的系统信息,例如网络接口、操作系统、主机名、硬件、IP地址、MAC地址等。这被称为"fact gathering",这些收集到的信息可以在playbook或者roles中使用。然而,有时候可能不需要这些信息,或者想要跳过这个步骤以加速playbook的执行。在这种情况下,可以在playbook中添加gather_facts: no
来禁用该功能。
inventory #以下操作应用的主机
modules #调用哪些模块做什么样的操作
ad hoc commands #在这些主机上运行哪些命令
playbooks
tasks #任务,即调用模块完成的某操作
variable #变量
templates #模板
handlers #处理器,由某事件触发执行的操作
roles #角色
--- # 这里是语法开头,表示文档开始。开头格式可写可不写
- name: palybook_test1
hosts: 192.168.16.135 # 执行的角色(可以写主机清单里的组名、也可以写被管理端的ip地址、还可以写all代表ansible中所有主机)
gather_facts: yes # 是否收集该主机信息
tasks: # 该角色的任务列表
- name: 启用防火墙
script: /root/firewalld.sh
- name: 关闭selinux
script: /root/selinux.sh
- name: palybook_test2
hosts: 192.168.16.136 #这代表当前使用的角色,可以写主机清单里的组名、也可以写被管理端的ip地址、还可以写all代表ansible中所有主机
gather_facts: yes #是否收集该主机信息
tasks: #该角色的任务列表
- name: 启用防火墙 #在前面的基础上缩进
script: /root/firewalld.sh
- name: 关闭selinux
script: /root/selinux.sh
Ansible 模块执行任务。可以组合一个或多个 Ansible 任务来进行游戏。可以组合两个或多个剧本来创建 Ansible Playbook。Ansible Playbook 是针对主机自动执行的任务列表。主机组构成 Ansible 清单。
Ansible Playbook 中的每个模块都执行特定的任务。每个模块都包含元数据,这些元数据确定执行任务的时间和地点,以及执行任务的用户。还有数以千计的其他 Ansible 模块可以执行各种 IT 任务。
Hosts
:执行的远程主机列表;Tasks
:任务集;Variables
:内置变量或自定义变量在playbook中调用;Templates
:模板,可替换模板中的变量并实现一些简单的逻辑的文件;Handlers
和 notify
:两者结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行;Tags
:标签,用于制定某条任务执行,用户选择运行playbook中的部分代码; hosts
用于指定要执行指定任务的主机,可以是多个组,使用冒号:
或者逗号 ,
来分隔多个组名。
:
)来定义多个主机组时,只有同时在所有指定的组中的主机才会被选中(并集)。,
)来定义多个主机组,在任一指定组中的主机都会被选中(合集)。- hosts: webserver1:webserver2
playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。
Ansible 提供了 become
指令,它可以让用户以其他用户的身份来执行任务。同时,通过 become_method
定义提权的方法(如 sudo, su, pbrun, pfexec, doas, ksu, runas),通过become_user
指定执行任务的用户。
---
- hosts: webservers
remote_user: root # 用root用户身份运行所有的任务。
tasks:
- name: tasks1
ping:
# 为特定的任务设置提权用户执行
become: yes
become_method: sudo
become_user: anotheruser # 用anotheruser运行tasks1
user
参数用于指定在远程主机上执行任务的用户。这个用户应该已经存在,并且具有执行相应任务所需的适当权限。
Tasks 任务集其实就是使用多个ansible支持的模块组合起来的一组任务。可以理解为 ansible-playbook 中,一个name指定的就是一个task任务。各个task按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task。但是也可以使用异步模式。
taks的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的。这意味着多次执行是安全的,因为其结果均一致。
每个task都应该有其name,用于playbook的执行结果输出,建议起一个见名知意的名称。
task的两种格式:一种是key=value
的形式,另一种是key: value
的形式(冒号后有个空格)。
在众多的模块中,只有command和shell模块仅需要给定一个列表而无需使用"key=value"格式。
- hosts: dbsrvs
remote_user: root
tasks:
- name:make sure apache is running
service: name=httpd state=started
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
通常会将变量信息放在/etc/ansible/roles/vars/main.yml
中,格式如下:
EMQXNAME: emq_perf
DEPEND_PKG:
- yum-utils
- device-mapper-persistent-data
- lvm2
- bridge-utils
DOCKER_PKG:
- containerd.io-1.6.6
- docker-ce-20.10.17
- docker-ce-cli-20.10.17
Templates 模板主要使用Jinjia2
模板语言,以 .j2
结尾,里面其实就是一个配置文件,比如:
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-level": "warn",
"log-opts": {
"max-size": "1g",
"max-file": "4"
},
"data-root": "/data/docker",
"storage-driver": "overlay2"
}
这两个通常结合使用,比如某一个服务配置变更后,需要重启,那么就需要在配置变更后设置一个notify
,然后handlers
就会在playbook退出之前执行重启服务的操作。
如果定义了handler
重启服务,而没有定义notify
,那么所有task任务执行完成后,也会触发一次服务重启操作。
notify
这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行执行的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作,在notify
中列出的操作称为handlers
,也即notify
中调用handlers
中定义的操作。
示例一:
---
- name: Verify apache installation
hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: Ensure apache is at the latest version
ansible.builtin.yum:
name: httpd
state: latest
- name: Write the apache config file
ansible.builtin.template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
notify: # 调用handlers中的重启操作
- Restart apache
- name: Ensure apache is running
ansible.builtin.service:
name: httpd
state: started
handlers:
- name: Restart apache
ansible.builtin.service:
name: httpd
state: restarted
示例二:
tasks:
- name: Template configuration file
ansible.builtin.template:
src: template.j2
dest: /etc/foo.conf
notify: # 调用handlers中的重启操作
- Restart apache
- Restart memcached
handlers:
- name: Restart memcached
ansible.builtin.service:
name: memcached
state: restarted
- name: Restart apache
ansible.builtin.service:
name: apache
state: restarted
有些任务可能需要消耗大量的时间来检查其幂等条件是否满足(比如,详细审查一个大型数据库的状态)。如果已经很确定这些任务的状态不会改变,可以给这些任务添加标签,然后使用 --skip-tags
标记来跳过它们,从而加速 playbook 的执行。
tags
:可以单独想运行指定的任务。当在Playbook的任务中定义了tags后,可以通过ansible-playbook
命令的 -t
或者 --tags
参数来运行这些特定的任务。如运行myplaybook.yml
文件:
- hosts: localhost
tasks:
- name: Print a message
debug:
msg: "I am tagged"
tags:
- print_message
- name: This will always run
debug:
msg: "This task will always run."
tags:
- always
# 运行定义了特定tag的任务
[root@test ~]# ansible-playbook myplaybook.yml -t "print_message"
[root@test ~]# ansible-playbook myplaybook.yml --tags "print_message"
在 Ansible 中,有几个特殊的标签,它们有特定的作用和含义:
always
标签的任务。never
标签,它就不会执行。--tags=untagged
,那么所有没有标签的任务将会被执行。untagged
相反。如果在命令行中使用了 --tags=tagged
,那么任何带有至少一个标签的任务都将被执行。没有标签的任务则会被跳过。--skip-tags
参数时,所有带有指定标签的任务将不会被执行。# 只执行带有任意标签的任务
[root@test ~]# ansible-playbook myplaybook.yml --tags=tagged
# 跳过带有标签tagA,tagB的任务
[root@test ~]# ansible-playbook myplaybook.yml --skip-tags="tagA,tagB"
命令格式:ansible-playbook
常见的 options 选项:
-i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY
: 指定存放主机名列表的文件。-C, --check
: 不真正执行任务,只做一个模拟运行(dry run)。-D, --diff
: 当修改(例如:通过模板或者复制一个文件)一个文件时,显示改动前后的差异。-e EXTRA_VARS, --extra-vars=EXTRA_VARS
:设置额外的变量。可以是键值对 (-e "a=b"
),也可以是 YAML 或 JSON 格式的文件名称 (-e "@file.yml"
或 -e "@file.json"
)。-t TAGS, --tags=TAGS
: 只运行带有特定标签的任务。--skip-tags=SKIP_TAGS
: 跳过带有特定标签的任务。-v, -vv, -vvv, -vvvv
: 更详细的输出。使用更多的 “v” 会得到更详尽的输出。--start-at-task=START_AT_TASK
: 从指定的任务开始执行。-l SUBSET, --limit=SUBSET
: 针对特定的主机或者主机组进行操作。--list-tasks
: 列出 playbook 中所有的任务,但不实际执行。--list-hosts
: 列出 playbook 将被执行的主机清单,但不实际执行。--syntax-check
: 检查 playbook 的语法,但不实际执行。示例:
[root@test ~]# ansible-playbook -C myplaybook.yaml