Ansible 学习总结(3)—— Ansible 常用模块与 playbook 实例讲解

皇甫乐
2023-12-01

一、Ansible 安装

下载安装并解压 python 3.7 包

  1. 安装 wget yum -y install wget
  2. 下载 python 文件 wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tgz (离线安装需提前准备压缩包
  3. 解压文件 tar zxvf Python-3.7.0.tgz
  4. 切换目录 cd Python-3.7.0

编译并安装

  1. 编译  ./configure --prefix=/usr/local/bin/python3  
  2. make
  3. make install  

注意:编译的时候可能提示 error: no acceptable C compiler found in $PATH,此时需安装 gcc yum -y install gcc,然后再执行;make install 的时候可能提示 zipimport.ZipImportError: can’t decompress data; zlib not available ,此时需安装 yum -y install zlib*,再执行,如果提示 ModuleNotFoundError: No module named ‘_ctypes’ make: *** [install] Error 1,此时需安装yum install libffi-devel -y,再执行。

修改默认版本

  1. 查看 python 版本 python -V 仍显示 python 2.7
  2. 查看 python3.7 的版本  /usr/local/bin/python3/bin/python3 -V  显示 python 3.7.0
  3. 查看 python 命令的绝对路径 which python 显示 /usr/bin/python
  4. 删除当前软连接 rm -rf /usr/bin/python
  5. 新建 python3 软连接 ln -s /usr/local/bin/python3/bin/python3 /usr/bin/python
  6. 查看效果 python -V 显示 python 3.7.0

恢复 yum

  1. 修改完 python 的默认版本后,yum 命令无法再执行。
  2. vim /usr/bin/yum 将文件第一行改为 /usr/bin/python2.7。(2.7.x也改为2.7)
  3. vim /usr/libexec/urlgrabber-ext-down 将文件第一行改为 /usr/bin/python2.7
  4. 这样 python3.7 就安装在 CentOS 上,同时又能够使用 yum 来安装软件了。

安装 pip

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
//如果离线安装的话可以预先把压缩包准备好
sudo python3 get-pip.py

通过 pip 安装 ansible

python -m pip install ansible

使用 ansible --version 测试安装是否成功

ansible 2.9.6
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.8.5 (default, Jan 27 2021, 15:41:15) [GCC 9.3.0]

二、Ansible 基础

ansible 是基于ssh 隧道进行连接运行的,故只要系统得 ssh 可以使用则 ansible 就可以使用。

配置文件

ansible 在使用配置文件时按照以下顺序优先配置:

export ANSIBLE_CONFIG

./ansible.cfg

~/.ansible.cfg

/etc/ansible/ansible.cfg

如果以上顺序没有找到配置文件 ansible 会自动使用默认配置,可以去 github 上把默认配置拿下来: 

https://raw.githubusercontent.com/ansible/ansible/devel/examples/ansible.cfg。把它放到 /etc/ansible/ 目录,配置文件主要配置:

 # 默认配置项

 [defaults]
 ask_pass:控制 Ansible 剧本 playbook 是否会自动默认弹出密码
 ask_sudo_pass:用户系统开启了sudo 的密码需要开启这个参数
 gather_subset 设置收集的内容

 #要自动化处理的客户端的信息
 remote_port 客户机 ssh 端口
 remote_tmp 客户机目录
 remote_user 客户机目录
 sudo_exe sudo 命令的路径
 sudo_flags sudo 命令的参数
 sudo_user  可以使用 sudo 的用户
 
 # 开发者中心的插件相关功能,开发者可以开发相应的插件完成自己的功能
 action_plugins     激活事件
 callback_plugins     回调
 connection_plugins 连接插件
 lookup_plugins    加载路径
 vars_plugins       任何地方加载
 filter_plugins     过滤器
 forks 最大开辟的子进程数,过大会导致性能耗费高,过小的话并发性低,一般来说是 CPU 核数 * 2
 module_name /usr/bin/ansible 默认模块名
 pattern playbook 要通信的默认主机组
 inventory 存放可通信主机的目录
 library Ansibl e默认搜寻模块路径
 
 #用户权限设置
 [privilege_escalation]
 #paramiko 插件配置(不是所有情况都启用插件) 
 [paramiko_connection]
 
 #ssh连接设置
 [ssh_connection]

添加一台机器

1.编辑 /etc/ansible/hosts,194.168.0.46 将 46 的控制权限添加到列表中;

2.添加控制机的 public SSH key 到被控制机器的 authorized_keys 中,cat .ssh/id_rsa.pub 查看公钥(没有的话:ssh-keygen -t rsa )

 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC39Ob41GSi4Yxuy1BaKnBON1LPUyP9SN4wv4IWi+xJ99aOa5iuafoH3KLIA8RIVw0BY50zFhlghCktqcBtaH6UT7KG27+G7GWOzI7gwKKg1ajGtYRQ+7x+WN123oUk+p1aiaxvYrhukSqwYyomKJFDL74CYXU4H5EfOAg6jhYIDD/K63VYIw6KdEiiyBAR6RqdmRFd9ozxwH/5uLD5PDKlpo753QHyubk4XyKil2WVREWREosZTZ5L5QqQf2kAJTyV09LxBhg6vNXr6pHbPi5mizgd7rmyVpIiJjh+R5Xw54igBMskICePFPiS9+wLITyoO5qptnJdeiJ2LTOvlhvt root@ebb7023

将194.168.0.23 的公钥添加到 194.168.0.64 的 authorized_keys 中。

3.添加本机的私钥到 Ansible(可省略)

4.运行 ansible all -m ping 测试是否添加成功

[root@host ~]# ansible all -m ping
10.1.114.53 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

success 表示了操作的成功与否。这里 changed 为 false 时,表示 ansible 没有进行任何操作,因为当前的被操作主机已经是我们想要达到的目标状态了。changed 为 true 时,表示 ansible 执行了操作,"当前状态"已经被 ansible 改变成了"目标状态"。

简单操作

ansible all -m ping 命令的解读:

ansible 是命令主体,-- ansible/ansible-playbook

被操作的目标及其的正则表达式 --all

指定要使用的模块  -m ping

-a 指定传入的参数

-v 显示检索到的配置文件

-C -D 两个一起使用,检查 hosts 规则文件的修改

-l 限制匹配规则的主机数

--list-hosts 显示所有匹配规则的主机数

-m -M 指定所使用的模块和模块的路径。

--syntax-check 检查语法

举例:

ansible all -a 'ls'

相当于在所有的被控制机上执行命令 ‘ls’ 即将 ls 这个参数传给要使用的模块,让它在被控制机器上执行。

对主机分组

Ansible 可同时操作属于一个组的多台主机,组合主机之间的关系通过 inventory 文件配置,默认的文件路径为 /etc/ansible/hosts

[webservers]
194.168.0.23
194.168.0.46

也就是说,194.168.0.23 和 194.168.0.46 同属于 webservers 组中,当对该组操作时,会同时操作 194.168.0.23 和 194.168.0.46.

 ansible webservers-a 'ls'

如果出现了主机之间端口不一致可以在 host 文件中注明端口号

194.168.0.23:8080

IP 域名起别名(jumper): jumper ansible_ssh_port=5555,ansible_ssh_host=194.168.0.23 (这配置是放在 hosts 文件中)

不想以 root 登录:jumper ansible_ssh_port = 555 ansible_ssh_host=194.168.0.13 ansible_ssh_user=papa ansible_ssh_pass=papa@!123

ansible_ssh_user (用户名)

ansible_ssh_pass (密码)

机器如果有连着的,可以使用以下方式(也支持字母表):

[vim]

194.168.0.[1:50]

分文件管理

/etc/ansible/group_vars/vim

/etc/ansible/group_vars/webservers

/etc/ansible/group_vars/test

vim 文件大致内容:

ntp_server:194.168.0.23

database_server:194.168.0.24

这时的文件名就是组名

ansible payerns

所有机器:all 或者 *

通过域名或者 ip 指定某个机器

指定连续的机器 194.168.0. 开头的: 194.168.0.*

指定不相关的机器: 194.168.0.24:10.2.70.28

通过组名指定:

在组 vim 和组 test 的机器 vim:test

在组 vim 但是不在组 test 的 vim:!test

在组 vim 也在组 test 的 vim:&test

与和非的匹配是从左到右依次匹配

ad-Hoc

如果我们可以使用一些命令去比较快的完成一些事情,而不需要将这些执行命令特别的保存下来,这样的命令就是 ad-hoc,即临时命令。

ansible test -a “/sbin/reboot”-f 10 对 test 组中的所有机器执行 “/sbin/reboot” 命令,执行时 fork 出 10 个子进程 (bash) 并行执行。

ansible test -a “/usr/bin/foo”-u username 通过指定用户 username 执行命令

ansible test -a “/usr/bin/foo”-u username --sudo[-ask-sudo-pass] 通过指定用户 username 执行 sudo 的命令

ansible 中的变量

变量是应用于多个主机的便捷方式; 实际在主机执行之前,变量会对每个主机添加,然后在执行中引用

  • 命令行传递
-e VAR=VALUE
  • 配置文件中针对某个主机或者某个组的变量
 [webservers]
 192.168.1.100 ansible_ssh_user=root hostname=web1
 192.168.1.100 ansible_ssh_user=root hostname=web2
 ​
 [webservers:vars]
 ansible_ssh_user=root hostname=web1
  • 文件存储的变量

Ansible 中的首选做法是不将变量存储在配置文件 (hosts) 中。除了将变量直接存储在配置文件 (hosts) 之外,主机和组变量还可以存储在相对于配置文件 (hosts) 的单个文件中。组变量:

group_vars 存放的是组变量

group_vars/all.yml 表示所有主机有效,等同于 [all:vars]

grous_vars/etcd.yml 表示 etcd 组主机有效,等同于 [etcd:vars]

 # vi /etc/ansible/group_vars/all.yml
 work_dir: /data
 # vi /etc/ansible/host_vars/webservers.yml
 nginx_port: 80

三、ansible 模块

ansible-doc –l 查看所有模块

ansible-doc –s copy 查看模块文档,模块文档:https://docs.ansible.com/ansible/latest/modules/modules_by_category.html

command 模块

command 模块可以帮助我们在远程主机上执行命令

注意:使用 command 模块在远程主机中执行命令时,不会经过远程主机的 shell 处理,在使用 command 模块时,如果需要执行的命令中含有重定向、管道符等操作时,这些符号也会失效,比如 "<", ">", "|", ";" 和 "&" 这些符号,如果你需要这些功能,可以参考后面介绍的 shell 模块,还有一点需要注意,如果远程节点是 windows 操作系统,则需要使用 win_command 模块。

free_form 参数 :必须参数,指定需要远程执行的命令,需要说明一点,free_form 参数与其他参数并不相同,在之前的模块示例中,如果想要使用一个参数,那么则需要为这个参数赋值,举个例子,之前的示例模块中,大多都有path参数,当我们需要指定要操作的文件时,通常需要对 path 参数赋值,比如,path=/testdir/test,表示我们想要操作 /testdir/test 文件,但是 free_form 参数则不同,"free_form" 并不是一个"实际存在"的参数名,比如,当我们想要在远程主机上执行 ls 命令时,我们并不需要写成 "free_form=ls" ,这样写反而是错误的,因为并没有任何参数的名字是 free_form,当我们想要在远程主机中执行 ls 命令时,直接写成ls即可,这就是 free_form 参数的含义,因为 command 模块的作用是执行命令,所以,任何一个可以在远程主机上执行的命令都可以被称为 free_form,如果你还是不明白,看下面的小示例就行了。

chdir 参数 : 此参数的作用就是指定一个目录,在执行对应的命令之前,会先进入到 chdir 参数指定的目录中。

creates 参数 :看到 creates,你可能会从字面上理解这个参数,但是使用这个参数并不会帮助我们创建文件,它的作用是当指定的文件存在时,就不执行对应命令,比如,如果 /testdir/test 文件存在,就不执行我们指定的命令。

removes 参数 :与 creates 参数的作用正好相反,它的作用是当指定的文件不存在时,就不执行对应命令,比如,如果 /testdir/tests 文件不存在,就不执行我们指定的命令,此参数并不会帮助我们删除文件

ansible test -m command -a "ls"
#在 test 主机上执行 ls 命令,因为我使用的是 root 用户,所以默认情况下,ls 出的结果是 test70 主机中 root 用户家目录中的文件列表。
 ​
ansible test -m command -a "chdir=/testdir ls"
#chdir 参数表示执行命令之前,会先进入到指定的目录中,所以如下命令表示查看 test 主机上 /testdir 目录中的文件列表

shell 模块

shell 模块可以帮助我们在远程主机上执行命令,与 command 模块不同的是,shell 模块在远程主机中执行命令时,会经过远程主机上的 /bin/sh 程序处理。

free_form 参数 :必须参数,指定需要远程执行的命令,但是并没有具体的一个参数名叫 free_form,具体解释参考 command 模块。

chdir 参数 : 此参数的作用就是指定一个目录,在执行对应的命令之前,会先进入到 chdir 参数指定的目录中。

creates 参数 :使用此参数指定一个文件,当指定的文件存在时,就不执行对应命令,可参考 command 模块中的解释。

removes 参数 :使用此参数指定一个文件,当指定的文件不存在时,就不执行对应命令,可参考 command 模块中的解释。

executable 参数:默认情况下,shell 模块会调用远程主机中的 /bin/sh 去执行对应的命令,通常情况下,远程主机中的默认 shell 都是 bash,如果你想要使用其他类型的 shell 执行命令,则可以使用此参数指定某种类型的 shell 去执行对应的命令,指定 shell 文件时,需要使用绝对路径。

#使用 shell 模块可以在远程服务器上执行命令,它支持管道与重定向等符号。
ansible test -m shell -a "chdir=/testdir echo test > test"

script 模块

script 模块可以帮助我们在远程主机上执行 ansible 主机上的脚本,也就是说,脚本一直存在于 ansible 主机本地,不需要手动拷贝到远程主机后再执行。

free_form 参数 :必须参数,指定需要执行的脚本,脚本位于 ansible 主机本地,并没有具体的一个参数名叫 free_form,具体解释参考 command 模块。

chdir 参数 : 此参数的作用就是指定一个远程主机中的目录,在执行对应的脚本之前,会先进入到 chdir 参数指定的目录中。

creates 参数 :使用此参数指定一个远程主机中的文件,当指定的文件存在时,就不执行对应脚本,可参考 command 模块中的解释。

removes 参数 :使用此参数指定一个远程主机中的文件,当指定的文件不存在时,就不执行对应脚本,可参考 command 模块中的解释。

如下命令表示 ansible 主机中的 /testdir/atest.sh 脚本将在 test70 主机中执行,执行此脚本之前,会先进入到 test70 主机中的 /opt 目录

#如下命令表示ansible主机中的/testdir/atest.sh脚本将在test主机中执行,执行此脚本之前,会先进入到 test 主机中的 /opt 目录
ansible test -m script -a "chdir=/opt /testdir/atest.sh"

copy 模块

copy 模块的作用就是拷贝文件,它与之前介绍过的 fetch 模块类似,不过,fetch 模块是从远程主机中拉取文件到 ansible 管理主机,而 copy 模块是将 ansible 管理主机上的文件拷贝到远程主机中

src 参数 :用于指定需要 copy 的文件或目录。

dest 参数 :用于指定文件将被拷贝到远程主机的哪个目录中,dest 为必须参数。

content 参数 :当不使用src指定拷贝的文件时,可以使用 content 直接指定文件内容,src 与 content 两个参数必有其一,否则会报错。

force 参数 : 当远程主机的目标路径中已经存在同名文件,并且与 ansible 主机中的文件内容不同时,是否强制覆盖,可选值有 yes 和 no,默认值为 yes,表示覆盖,如果设置为 no,则不会执行覆盖拷贝操作,远程主机中的文件保持不变。

backup 参数 : 当远程主机的目标路径中已经存在同名文件,并且与 ansible 主机中的文件内容不同时,是否对远程主机的文件进行备份,可选值有 yes 和 no,当设置为 yes 时,会先备份远程主机中的文件,然后再将 ansible 主机中的文件拷贝到远程主机。

owner 参数 : 指定文件拷贝到远程主机后的属主,但是远程主机上必须有对应的用户,否则会报错。

group 参数 : 指定文件拷贝到远程主机后的属组,但是远程主机上必须有对应的组,否则会报错。

mode 参数 : 指定文件拷贝到远程主机后的权限,如果你想将权限设置为 ”rw-r--r--“,则可以使用 mode=0644 表示,如果你想要在 user 对应的权限位上添加执行权限,则可以使用 mode=u+x 表示。

ansible test -m copy -a "src=/etc/ansible/hosts  dest=/"
#文件分发:源文件及路径 /etc/ansible/hosts ,目标路径/,目标主机:test 分组的所有主机

file 模块

file 模块以完成创建文件或目录、删除文件或目录、修改文件权限等操作

path 参数 :必须参数,用于指定要操作的文件或目录,在之前版本的 ansible中,使用 dest 参数或者 name 参数指定要操作的文件或目录,为了兼容之前的版本,使用 dest 或 name 也可以。

state 参数 :此参数非常灵活,此参数对应的值需要根据情况设定,比如,当我们需要在远程主机中创建一个目录的时候,我们需要使用 path 参数指定对应的目录路径,假设,我想要在远程主机上创建 /testdir/a/b 目录,那么我则需要设置 path=/testdir/a/b,但是,我们无法从 "/testdir/a/b" 这个路径看出b是一个文件还是一个目录,ansible 也同样无法单单从一个字符串就知道你要创建文件还是目录,所以,我们需要通过 state 参数进行说明,当我们想要创建的 /testdir/a/b 是一个目录时,需要将 state 的值设置为 directory,"directory" 为目录之意,当它与 path 结合,ansible 就能知道我们要操作的目标是一个目录,同理,当我们想要操作的 /testdir/a/b 是一个文件时,则需要将 state 的值设置为 touch,当我们想要创建软链接文件时,需将 state 设置为 link,想要创建硬链接文件时,需要将 state 设置为 hard,当我们想要删除一个文件时(删除时不用区分目标是文件、目录、还是链接),则需要将 state 的值设置为 absent,"absent" 为缺席之意,当我们想让操作的目标"缺席"时,就表示我们想要删除目标。

src 参数 :当 state 设置为 link 或者 hard 时,表示我们想要创建一个软链或者硬链,所以,我们必须指明软链或硬链链接的哪个文件,通过 src 参数即可指定链接源。

force 参数 : 当 state=link 的时候,可配合此参数强制创建链接文件,当 force=yes 时,表示强制创建链接文件,不过强制创建链接文件分为两种情况,情况一:当你要创建的链接文件指向的源文件并不存在时,使用此参数,可以先强制创建出链接文件。情况二:当你要创建链接文件的目录中已经存在与链接文件同名的文件时,将 force 设 置为 yes,回将同名文件覆盖为链接文件,相当于删除同名文件,创建链接文件。情况三:当你要创建链接文件的目录中已经存在与链接文件同名的文件,并且链接文件指向的源文件也不存在,这时会强制替换同名文件为链接文件。

owner 参数 :用于指定被操作文件的属主,属主对应的用户必须在远程主机中存在,否则会报错。

group 参数 :用于指定被操作文件的属组,属组对应的组必须在远程主机中存在,否则会报错。

mode 参数:用于指定被操作文件的权限,比如,如果想要将文件权限设置为 "rw-r-x---",则可以使用 mode=650 进行设置,或者使用 mode=0650,效果也是相同的,如果你想要设置特殊权限,比如为二进制文件设置 suid,则可以使用 mode=4700。

recurse 参数:当要操作的文件为目录,将 recurse 设置为 yes,可以递归的修改目录中文件的属性。

# 在创建文件或目录的时候指定属组或者修改远程主机上的文件或目录的属组。
ansible test -m file -a "path=/testdir/abb state=touch group=zsy"

blockinfile 模块

blockinfile 模块可以在指定的文件中插入一段文本,而且这段文本会被标记,以后的操作可以找到这段文本修改或者删除

path 参数 :必须参数,指定要操作的文件。

block 参数 :此参数用于指定我们想要操作的那"一段文本",此参数有一个别名叫 "content",使用 content 或 block 的作用是相同的。

marker 参数 :假如我们想要在指定文件中插入一段文本,ansible 会自动为这段文本添加两个标记,一个开始标记,一个结束标记,默认情况下,开始标记为 # BEGIN ANSIBLE MANAGED BLOCK,结束标记为 # END ANSIBLE MANAGED BLOCK,我们可以使用 marker 参数自定义"标记",比如,marker=#{mark}test ,这样设置以后,开始标记变成了 # BEGIN test,结束标记变成了 # END test,没错,{mark} 会自动被替换成开始标记和结束标记中的 BEGIN 和 END,我们也可以插入很多段文本,为不同的段落添加不同的标记,下次通过对应的标记即可找到对应的段落。

state 参数 : state 参数有两个可选值,present 与 absent,默认情况下,我们会将指定的一段文本"插入"到文件中,如果对应的文件中已经存在对应标记的文本,默认会更新对应段落,在执行插入操作或更新操作时,state 的值为 present,默认值就是 present,如果对应的文件中已经存在对应标记的文本并且将 state 的值设置为 absent,则表示从文件中删除对应标记的段落。

insertafter 参数 :在插入一段文本时,默认会在文件的末尾插入文本,如果你想要将文本插入在某一行的后面,可以使用此参数指定对应的行,也可以使用正则表达式 (python 正则),表示将文本插入在符合正则表达式的行的后面,如果有多行文本都能够匹配对应的正则表达式,则以最后一个满足正则的行为准,此参数的值还可以设置为 EOF,表示将文本插入到文档末尾。

insertbefore 参数 :在插入一段文本时,默认会在文件的末尾插入文本,如果你想要将文本插入在某一行的前面,可以使用此参数指定对应的行,也可以使用正则表达式 (python 正则),表示将文本插入在符合正则表达式的行的前面,如果有多行文本都能够匹配对应的正则表达式,则以最后一个满足正则的行为准,此参数的值还可以设置为 BOF,表示将文本插入到文档开头。

backup 参数 :是否在修改文件之前对文件进行备份。

create 参数 :当要操作的文件并不存在时,是否创建对应的文件。

#假如,我们想要在 test 的主机中的 /testdir/rc.local 文件尾部插入如下两行
systemctl start mariadb
systemctl start httpd

#可以使用如下命令
ansible test -m blockinfile -a 'path=/testdir/rc.local block="systemctl start mariadb\nsystemctl start httpd" '

lineinfile 模块

lineinfile 模块,用于对文件内容的修改

path 参数 :必须参数,指定要操作的文件。

line 参数 : 使用此参数指定文本内容。

regexp 参数 :使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最后面被匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被删除。

state 参数:当想要删除对应的文本时,需要将 state 参数的值设置为 absent,absent 为缺席之意,表示删除,state 的默认值为 present

backrefs 参数:默认情况下,当根据正则替换文本时,即使 regexp 参数中的正则存在分组,在 line 参数中也不能对正则中的分组进行引用,除非将 backrefs 参数的值设置为 yes,backrefs=yes 表示开启后向引用,这样,line 参数中就能对 regexp 参数中的分组进行后向引用了,这样说不太容易明白,参考下面的示例命令比较直观一点,backrefs=yes 除了能够开启后向引用功能,还有另一个作用,默认情况下,当使用正则表达式替换对应行时,如果正则没有匹配到任何的行,那么 line 对应的内容会被插入到文本的末尾,不过,如果使用了 backrefs=yes,情况就不一样了,当使用正则表达式替换对应行时,同时设置了 backrefs=yes,那么当正则没有匹配到任何的行时,则不会对文件进行任何操作,相当于保持原文件不变,如果没有理解,就按照下面的示例命令,动手操作一下吧,那样更加直观。

insertafter 参数:借助 insertafter 参数可以将文本插入到“指定的行”之后,insertafter 参数的值可以设置为 EOF 或者正则表达式,EOF 为 End Of File 之意,表示插入到文档的末尾,默认情况下 insertafter 的值为 EOF,如果将 insertafter 的值设置为正则表达式,表示将文本插入到匹配到正则的行之后,如果正则没有匹配到任何行,则插入到文件末尾,当使用 backrefs 参数时,此参数会被忽略。

insertbefore 参数:借助 insertbefore 参数可以将文本插入到“指定的行”之前,insertbefore 参数的值可以设置为 BOF 或者正则表达式,BOF 为 Begin Of File 之意,表示插入到文档的开头,如果将 insertbefore 的值设置为正则表达式,表示将文本插入到匹配到正则的行之前,如果正则没有匹配到任何行,则插入到文件末尾,当使用 backrefs 参数时,此参数会被忽略。

backup 参数:是否在修改文件之前对文件进行备份。

create 参数 :当要操作的文件并不存在时,是否创建对应的文件。

举例:

# cat /testdir/test
This is a file
The file is very simple
hello world!

# 如果指定的文本本来就存在于文件中,则不做任何操作,如果不存在,默认在文件的末尾插入这行文本
ansible 194.168.0.46 -m lineinfile -a 'path=/testdir/test line="hello text"'

yum_repository 模块

yum_repository 模块用于管理远程主机上的 yum 仓库

name 参数:必须参数,用于指定要操作的唯一的仓库 ID,也就是 ".repo" 配置文件中每个仓库对应的"中括号"内的仓库 ID

baseurl 参数:此参数用于设置 yum 仓库的 baseurl

description 参数:此参数用于设置仓库的注释信息,也就是 ".repo" 配置文件中每个仓库对应的 "name 字段"对应的内容。

file 参数:此参数用于设置仓库的配置文件名称,即设置 ".repo" 配置文件的文件名前缀,在不使用此参数的情况下,默认以 name 参数的仓库 ID 作为 ".repo" 配置文件的文件名前缀,同一个 '.repo' 配置文件中可以存在多个 yum 源

enabled 参数:此参数用于设置是否激活对应的 yum源,此参数默认值为 yes,表示启用对应的 yum 源,设置为 no 表示不启用对应的 yum 源。

gpgcheck 参数:此参数用于设置是否开启 rpm 包验证功能,默认值为 no,表示不启用包验证,设置为 yes 表示开启包验证功能。

gpgcakey 参数:当 gpgcheck 参数设置为 yes 时,需要使用此参数指定验证包所需的公钥

state 参数:默认值为 present,当值设置为 absent 时,表示删除对应的 yum 源

#在 test 主机上设置 ID 为 aliEpel 的 yum 源,仓库配置文件路径为 /etc/yum.repos.d/aliEpel.repo
ansible test -m yum_repository -a 'name=aliEpel description="alibaba EPEL" baseurl=https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/'

yum 模块

yum 模块可以帮助我们在远程主机上通过 yum 源管理软件包

name 参数:必须参数,用于指定需要管理的软件包,比如 nginx。

state 参数:用于指定软件包的状态 ,默认值为。present,表示确保软件包已经安装,除了。present,其他可用值有 installed、latest、absent、removed,其中 installed 与 present  等效,latest 表示安装 yum 中最新的版本,absent 和 removed 等效,表示删除对应的软件包。

disable_gpg_check 参数:用于禁用对 rpm 包的公钥 gpg 验证。默认值为 no,表示不禁用验证,设置为 yes 表示禁用验证,即不验证包,直接安装。在对应的 yum 源没有开启 gpg 验证的情况下,需要将此参数的值设置为 yes,否则会报错而无法进行安装。

enablerepo 参数:用于指定安装软件包时临时启用的 yum 源。假如你想要从A源中安装软件,但是你不确定A源是否启用了,你可以在安装软件包时将此参数的值设置为 yes,即使 A 源的设置是未启用,也可以在安装软件包时临时启用 A 源。

disablerepo 参数:用于指定安装软件包时临时禁用的 yum 源。某些场景下需要此参数,比如,当多个 yum 源中同时存在要安装的软件包时,你可以使用此参数临时禁用某个源,这样设置后,在安装软件包时则不会从对应的源中选择安装包。enablerepo 参数和 disablerepo 参数可以同时使用。

ansible test -m yum -a"name=acme state = present"
#确认一个软件包已经安装,但是不升级它
 ​
ansible webservers -m yum -a "name=nginx state=latest"
#安装nginx,最新版本,安装过程中的信息会全部输出值屏幕端

unarchive 模块

unarchive  模块用于解压文件

copy:在解压文件之前,是否先将文件复制到远程主机,默认为 yes。若为 no,则要求目标主机上压缩包必须存在。

creates:指定一个文件名,当该文件存在时,则解压指令不执行

dest:远程主机上的一个路径,即文件解压的路径

grop:解压后的目录或文件的属组

list_files:如果为 yes,则会列出压缩包里的文件,默认为 no,2.0版本新增的选项

mode:解决后文件的权限

src:如果 copy 为yes,则需要指定压缩文件的源路径

owner:解压后文件或目录的属主

service 模块

ansible webservers -m service -a "name=nginx enabled=true state=started"
#开启 nginx 服务,并设置成开机自启

四、ansible playbook 概述

Playbook 是一个由一个或多个 play 组成的文件;play 是针对特定主机或主机组执行的一组有序的任务;每个 playbook 必须包含两部分:

hosts: 运行 playbook 的一组主机

tasks: 需要在主机上运行的任务

除了这两个必须选项,还有一些可选项选项,也可能需要包含在 play 中,如:

name: play 的名称,在运行该 play 时,会在运行过程中显示。

become: 与配置文件中的 become 作用一样,用于提权,当配置文件中禁用提权时,你想要某个 play 使用提权的话,你可以在 play 中添加 become。

playbook 以 yaml 格式编写的,通常以 yml 扩展名保存。yaml 格式使用空格缩进,对于空格的数量没有特别要求,但需要注意:

  • 同一级别内的元素必须使用相同的缩进;

  • 对于子项目,缩进必须比父项目多

编写 playbook

it@workstation:~/ansible$ vim test.yml
it@workstation:~/ansible$ cat test.yml
---
- name: Install Apache
  hosts: servera
  tasks:
    - name: Install apache httpd
      apt:
        name: apache2
        state: present
    - name: Copy using inline content
      copy:
        content: Welcome to
        dest: /var/www/html/index.html
    - name: Start apache service
      service:
        name: apache2
        state: started
        enabled: yes

Playbook 以 --- 开头,用于标记文件开始;

第二行的 name 为该 play 的名称;

第三行的 hosts 表示将要运行该 play 的主机;

第四行的 tasks 表示该 play 将要执行的具体任务;

通过缩进,我们可以看出 tasks 一共分为三个部分,也就是三个模块,每个模块由一个 name 开表示该模块的 name,虽然 name 是可选选项,但建议写上,用来作为对该模块执行任务的解释说明,并且 name 的内容会在 playbook 执行此模块时,显示在执行过程中;

name 下面的是模块的名称,在该 play 的 tasks 中一共有三个模块:

apt: 用于安装软件

copy: 用于复制文件或内容

service: 用于操作 service,如启动服务,重启服务等

我们可以通过 ansible-doc 来获取更多关于模块的信息:

我们可以通过 ansible-doc -l 来列出所有模块

t@workstation:~/ansible$ ansible-doc -l
a10_server                                    Manage A10 Networks AX/SoftAX/Thu...
a10_server_axapi3                             Manage A10 Networks AX/SoftAX/Thu...
a10_service_group                             Manage A10 Networks AX/SoftAX/Thu...
a10_virtual_server                            Manage A10 Networks AX/SoftAX/Thu...
aci_aaa_user                                  Manage AAA users (aaa:User)      
... ... ... ...
... ... ... ...

列出的内容太多,我们可以通过 grep 进行筛选:如,我想查找关于 apt  相关的模块

it@workstation:~$ ansible-doc -l | grep apt
apt                                                           Manages apt-packages             
apt_key                                                       Add or remove an apt key         
apt_repo                                                      Manage APT repositories via apt-r...
apt_repository                                                Add and remove APT repositories  
apt_rpm                                                       apt_rpm package manager          
fortios_switch_controller_security_policy_captive_portal      Names of VLANs that use captive p...
na_ontap_qos_adaptive_policy_group                            NetApp ONTAP Adaptive Quality of ...
na_ontap_ucadapter                                            NetApp ONTAP UC adapter configura...
nios_naptr_record                                             Configure Infoblox NIOS NAPTR rec...
skydive_capture                                               Module which manages flow capture...
vmware_guest_network                                          Manage network adapters of specif...                            

通过 ansible-doc Module_Name 获取模块相关的帮助说明

it@workstation:~$ ansible-doc apt
> APT    (/usr/lib/python3/dist-packages/ansible/modules/packaging/os/apt.py)

        Manages `apt' packages (such as for Debian/Ubuntu).

  * This module is maintained by The Ansible Core Team
OPTIONS (= is mandatory):

- allow_unauthenticated
        Ignore if packages cannot be authenticated. This is useful for
        bootstrapping environments that manage their own apt-key setup.
        `allow_unauthenticated' is only supported with state:
        `install'/`present'
        [Default: no]
        type: bool
        version_added: 2.1
... ... ... ...
... ... ... ...

执行 playbook

it@workstation:~/ansible$ ansible-playbook test.yml 
BECOME password: 

PLAY [Install Apache] ******************************************************************************

TASK [Gathering Facts] *****************************************************************************
ok: [servera]

TASK [Install apache httpd] ************************************************************************
changed: [servera]

TASK [Copy using inline content] *******************************************************************
changed: [servera]

TASK [Start apache service] ************************************************************************
ok: [servera]

PLAY RECAP *****************************************************************************************
servera                    : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

由于我们配置了 become,所以在运行的时候会提示输入 become 密码;在这里,我们可以看到前面说的,在执行过程中会显示 play 的名称,告诉你现在执行的是那个 play;每个 play 中会有一个默认的任务,就是获取 facts 信息,在 facts 信息中会保存你计算机的系统信息;然后是三个在 play 中定义的 task,在执行 tasks 时,会显示当前所执行的 task 的名称,以及执行的状态,如果是 ok,则表示系统状态没有任何更改,如果是 changed,则表示系统状态发生了改变;在最后,还有一个关于该 playbook 执行结果的汇总,有多少个 changed,有多少个 failed,有多个 skipped 等等;当我们要安装某个软件并启动时,我们需要很多条命令,以 nginx 为例:

#配置对应的yum源
ansible test -m yum_repository -a 'name=aliEpel description="alibaba EPEL" baseurl=https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/'

#使用yum模块安装nginx
ansible test -m yum -a 'name=nginx disable_gpg_check=yes enablerepo=aliEpel'

#使用service模块启动nginx
ansible test -m service -a "name=nginx state=started"

但是在工作中如果有新机器加入进来,每次用命令显得有些繁琐,如果是一些安装起来较为复杂的软件,环境配置要求很多的情况下会非常麻烦,故 ansible 提供了剧本:playbook,将 ad-hoc 命令按照顺序编写在在一个可执行文件中,语法遵循 yaml 语法。示例:

#原 ad-hoc 命令
#使用 ping 模块去 ping 主机 test70
ansible 194.168.0.46 -m ping

#再用 file 模块在 test70 主机上创建目录
ansible 194.168.0.46 -m file -a "path=/testdir/test state=directory"

#test.yaml
---
- hosts: 194.168.0.46
  remote_user: root
  tasks:
  - name: ping46
  	ping:
  - name: mkdir test
  	file:
  	  path: /testdir/test
  	  state: directory 

在 YAML 语法中:--- 表示文档开始。下面 开头(有空格),表示一个块的节点,host 表明要操作的主机,host 关键字对应值为 194.168.0.22,表示在该主机上操作。下面的 remote_user 表示远程操作时使用的用户,这里我们使用 194.168.0.22 的 root 用户。这行要与 host 对齐,yaml 中不识别 tab,tasts 表示要执行的任务列表,每个 play 包含一系列任务。这些任务按照顺序执行,在 play 中,所有主机都会执行相同的任务指令。play 目的是将选择的主机映射到任务。任务列表的起名比较随意。每个任务以 - 开头,上面的语法中 ping 模块没有指定参数,而使用 file 模块时制定了 path 和 state 的值。

[root@ohost ~]# ansible-playbook test.yml 

PLAY [etcd] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [194.168.0.46]

TASK [ping64] ******************************************************************
ok: [194.168.0.46]

TASK [mkdir test] **************************************************************
changed: [194.168.0.46]

PLAY RECAP *********************************************************************
194.168.0.46                 : ok=3    changed=1    unreachable=0    failed=0  
#检查 yaml 有没有语法错误
ansible-playbook --syntax-check test.yaml

#模拟运行(不会真的运行,只是帮助我们预估该 yml 文件能不能运行,但是如果 yaml 中的任务有前后依赖关系,那模拟执行会失败)
ansible-playbook --check test.yaml

看下面的例子:

 tasks:
 - name: make testfile
   file:
     path: /testdir/testfile
     state: touch
     mode: 0700 #设置权限为0700

也可以编写成如下格式:

 tasks:
 - name: make testfile
   file: path=/testdir/testfile state=touch mode=0700

常用模块的 playbook 语法

该处用到的参数均可在上面的模块介绍中找到,也可以在安装了 ansible 的机器上查看帮助文档。这里以几个常用的模块为例示范对应的 playbook 语法

shell

 - name: 将命令结果输出到指定文件
   shell: somescript.sh >> somelog.txt
 - name: 切换目录执行命令
   shell:
     cmd: ls -l | grep log
     chdir: somedir/
 - name: 编写脚本
   shell: |
       if [ 0 -eq 0 ]; then     # 比较0和0 的值,一致则输出yes到result,否则输出no
          echo yes > /tmp/result
       else
          echo no > /tmp/result
       fi
   args:
     executable: /bin/bash  #用什么执行脚本

copy

 - name: 拷贝文件
   copy:
     src: /srv/myfiles/myfile.conf
     dest: /etc/myfile.conf
     owner: wang
     group: wang
     mode: u=rw,g=r,o=r #相当于命令中的u+rw,g-wx,o-rwx 或者使用mode: '0644'
     backup: yes

file

 - name: 创建目录
   file:
     path: /etc/some_directory
     state: directory
     mode: '0755'
 - name: 删除文件
   file:
     path: /etc/foo.txt
     state: absent
 - name: 递归删除目录
   file:
     path: /etc/foo
     state: absent

yum

 - name: 安装最新版apache
   yum:
     name: httpd
     state: latest
 - name: 安装列表中所有包
   yum:
     name:
       - nginx
       - postgresql
       - postgresql-server
     state: present
 - name: 卸载apache包
   yum:
     name: httpd
     state: absent 
 - name: 更新所有包
   yum:
     name: '*'
     state: latest
 - name: 安装nginx来自远程repo
   yum:
     name: http://nginx.org/packages/rhel/7/x86_64/RPMS/nginx-1.14.0-1.el7_4.ngx.x86_64.rpm
     # name: /usr/local/src/nginx-release-centos-6-0.el6.ngx.noarch.rpm
     state: present
 - name: 安装nginx最新版
   yum: pkg=nginx state=latest

unarchive

 - name: 解压文件/tmp/test.tar.gz 
   unarchive: 
     src: test.tar.gz 
     dest: /tmp/

service

 - name: 服务管理
   service:
     name: etcd
     state: started
     #state: stopped
     #state: restarted
     #state: reloaded
 - name: 设置开机启动
   service:
     name: httpd
     enabled: yes

debug

将上一步任务执行的结果打印出来,在这一步会将 4 台主机的执行结果都返回,不管成功或是失败都会显示出来。

 - hosts: all
   remote_user: root
   tasks:
   - name: 查看root目录下的文件
     shell:
       cmd: ls -l
       chdir: /root/
   - name: 输出的结果
     debug:
       var: result

playbook 中的变量

全局变量/组变量/主机变量

 ---
 - hosts: webservers
   vars: # 这种变量对于hosts组都有效
     http_port: 80
     server_name: www.ctnrs.com

响应变量 接收任务的响应

 tasks:
 - name: 只在192.168.1.100运行任务
   shell: 
     cmd: ls -l | grep log
     chdir: somedir/
     register: result

五、playbook 常用流程控制

条件

 tasks:
 - name: 只在192.168.1.100运行任务
   shell: 
     cmd: ls -l | grep log
     chdir: somedir/
     register: result
   - debug: var=result
   when: ansible_default_ipv4.address == '192.168.1.100'

循环

 tasks:
 - name: 批量创建用户
   user: name={{ item }} state=present groups=wheel
   with_items:
      - testuser1
      - testuser2
 - name: 遍历/temp中所有txt文件的文件名
   copy: src={{ item }} dest=/tmp
   with_fileglob:
     - "*.txt"

常用循环语句:语句描述 with_items 标准循环 with_fileglob 遍历文件名称 with_dict 遍历字典 with_file 遍历文件内容。注意这里 with_file 和 with_fileglob 的区别,如果我们用 debug 输出结果会发现,with_file 中 debug 打出来的是文件内容,而 with_fileglob 打出来的是文件名称。

任务控制

当某个剧本中有很多任务时,可能我们只要执行其中的某个步骤,那么我们可以给它打标签:

   tasks:
   - name: 安装nginx最新版
     yum: pkg=nginx state=latest
     tags: install
   - name: 写入nginx配置文件
     template: src=/srv/httpd.j2 dest=/etc/nginx/nginx.conf
     tags: config
   - name: 批量创建用户
     user: name={{ item }} state=present groups=wheel
     with_items:
        - testuser1
        - testuser2
     tags: adduser

使用如下命令可以只执行打了某个标签的任务,或者跳过某个标签的任务

 ansible-playbook test.yml --tags "install"
 ansible-playbook test.yml --tags "install,config"
 ansible-playbook test.yml --skip-tags "install"

模板

Jinja2 是基于 python 的模板引擎

  vars:
     domain: "www.ctnrs.com"
  tasks:
   - name: 写入nginx配置文件
     template: src=/srv/server.j2 dest=/etc/nginx/conf.d/server.conf
 # server.j2
 {% set domain_name = domain %}
 server {
    listen 80;
    server_name {{ domain_name }};
    location / {
         root /usr/share/html;
    }
 }

在 jinja 里使用 ansible 变量直接 {{ }} 引用。使用 ansible 变量赋值 jinja 变量不用 {{ }} 引用,生成的文件:

 server {
    listen 80;
    server_name www.ctnr.com;
    location / {
         root /usr/share/html;
    }
 }

如果使用程序流程语句:

定义变量:{% set local_ip = inventory_hostname %}

条件和循环:

 {% set list=['one', 'two', 'three'] %}
 {% for i in list %}
     {% if i == 'two' %}
         -> two
     {% elif loop.index == 3 %}
         -> 3
     {% else %}
         {{i}}
     {% endif %}
 {% endfor %}

文件执行结果:

 [root@myhost ~]# vim server.conf 
 ​
                         one
                                 -> two
                                 -> 3

忽略执行出现的错误

ignore_errors: true 是忽略出现的问题 ,不加默认为 false,任务运行出 bug 时不会执行目标主机的后续任务

   - name: 安装nginx最新版
     yum: pkg=nginx state=latest
     tags: install
     ignore_errors: true

六、Docker 安装实例

在 files/ 文件目录放 docker 的二级制包,这是相对于 yml 文件的相对路径

 ---
 #指定安装docker的主机组
 - hosts: docker 
 #安装目录
   vars:
     tmp_dir: '/tmp/docker'
   remote_user: root
   gather_facts: false
   
   tasks:
   
   - name: 创建临时目录放配置文件和二进制包
     file: dest={{ tmp_dir }} state=directory
     
   - name: 分发并解压docker二进制包(去官网随便选个版本下就行了)
     unarchive: src={{ item }} dest={{ tmp_dir }}
     with_fileglob:
       - "files/docker-*.tgz"
 ​
   - name: 移动docker二进制文件
     shell: cp -rf {{ tmp_dir }}/docker/* /usr/bin
 ​
   - name: 分发service文件
     copy: src=files/docker.service dest=/usr/lib/systemd/system/
 ​
   - name: 创建目录
     file: dest=/etc/docker state=directory
 ​
   - name: 配置docker
     copy: src=files/daemon.json dest=/etc/docker/daemon.json
 ​
   - name: 启动docker
     systemd: name=docker state=restarted enabled=yes daemon_reload=yes
 ​
   - name: 查看状态
     shell: docker info
     register: docker 
   - debug: var=docker.stdout_lines

 类似资料: