目录
ansible是自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括:
(1)、连接插件connection plugins:负责和被监控端实现通信;
(2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
(3)、各种模块核心模块、command模块、自定义模块;
(4)、借助于插件完成记录日志邮件等功能;
(5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
上图中我们看到的主要模块如下:
Ansible:Ansible核心程序。
HostInventory:记录由Ansible管理的主机信息,包括端口、密码、ip等。
Playbooks:“剧本”YAML格式文件,多个任务定义在一个文件中,定义主机需要调用哪些模块来完成的功能。
CoreModules:核心模块,主要操作是通过调用核心模块来完成管理任务。
CustomModules:自定义模块,完成核心模块无法完成的功能,支持多种语言。
ConnectionPlugins:连接插件,Ansible和Host通信使用
Ansible 系统由控制主机对被管节点的操作方式可分为两类,即adhoc
和playbook
:
简单理解就是Ansible在运行时, 首先读取ansible.cfg
中的配置, 根据规则获取Inventory
中的管理主机列表, 并行的在这些主机中执行配置的任务, 最后等待执行返回的结果。
/etc/ansible/ansible.cfg
;.ansible/tmp/XXX/XXX.PY
文件;sleep 0
退出; ansible安装常用两种方式,yum安装
和pip程序安装
。下面我们来详细介绍一下这两种安装方式。
首先,我们需要安装一个python-pip
包,安装完成以后,则直接使用pip
命令来安装我们的包,具体操作过程如下:
yum install python-pip
pip install ansible
yum 安装是我们很熟悉的安装方式了。我们需要先安装一个epel-release
包,然后再安装我们的 ansible 即可。
yum install epel-release -y
yum install ansible –y
安装目录如下(yum安装):
配置文件目录:/etc/ansible/
执行文件目录:/usr/bin/
Lib库依赖目录:/usr/lib/pythonX.X/site-packages/ansible/
Help文档目录:/usr/share/doc/ansible-X.X.X/
Man文档目录:/usr/share/man/man1/
/etc/ansible
/etc/ansible/ansible.cfg
/etc/ansible/hosts
/etc/ansible/roles
/usr/bin/ansible
/usr/bin/ansible-2
/usr/bin/ansible-2.7
/usr/bin/ansible-config
/usr/bin/ansible-connection
/usr/bin/ansible-console
/usr/bin/ansible-console-2
/usr/bin/ansible-console-2.7
/usr/bin/ansible-doc
/usr/bin/ansible-doc-2
/usr/bin/ansible-doc-2.7
/usr/bin/ansible-galaxy
/usr/bin/ansible-galaxy-2
/usr/bin/ansible-galaxy-2.7
/usr/bin/ansible-inventory
/usr/bin/ansible-playbook
/usr/bin/ansible-playbook-2
/usr/bin/ansible-playbook-2.7
/usr/bin/ansible-pull
/usr/bin/ansible-pull-2
/usr/bin/ansible-pull-2.7
/usr/bin/ansible-vault
/usr/bin/ansible-vault-2
/usr/bin/ansible-vault-2.7
ansible与我们其他的服务在这一点上有很大不同,这里的配置文件查找是从多个地方找的,顺序如下:
ANSIBLE_CONFIG
指向的路径文件(export ANSIBLE_CONFIG=/etc/ansible.cfg);~/.ansible.cfg
,检查当前目录下的ansible.cfg配置文件;/etc/ansible.cfg
检查etc目录的配置文件。配置文件
程序:
/usr/bin/ansible 主程序,临时命令执行工具
/usr/bin/ansible-doc 查看配置文档,模块功能查看工具
/usr/bin/ansible-galaxy 下载/上传优秀代码或Roles模块的官网平台
/usr/bin/ansible-playbook 定制自动化任务,编排剧本工具。
/usr/bin/ansible-vault 文件加密工具
/usr/bin/ansible-console 基于console界面与用户交互的执行工具
ansible 的配置文件为/etc/ansible/ansible.cfg
,ansible 有许多参数,下面我们列出一些常见的参数:
inventory = /etc/ansible/hosts #这个参数表示资源清单inventory文件的位置
library = /usr/share/ansible #指向存放Ansible模块的目录,支持多个目录方式,只要用冒号(:)隔开就可以
forks = 5 #并发连接数,默认为5
remote_tmp = $HOME/.ansible/tmp #临时py命令文件存放在远程主机目录
sudo_user = root #设置默认执行命令的用户
remote_port = 22 #指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
host_key_checking = False #设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例
timeout = 60 #设置SSH连接的超时时间,单位为秒
log_path = /var/log/ansible.log #指定一个存储ansible日志的文件(默认不记录日志)
在配置文件中,我们提到了资源清单,这个清单就是我们的主机清单,里面保存的是一些 ansible 需要连接管理的主机列表。我们可以来看看他的定义方式:
1、 直接指明主机地址或主机名:
## green.example.com#
# blue.example.com#
# 192.168.100.1
# 192.168.100.10
2、 定义一个主机组[组名]把地址或主机名加进去
[mysql_test]
192.168.253.159
192.168.253.160
192.168.253.153
需要注意的是,这里的组成员可以使用通配符来匹配,这样对于一些标准化的管理来说就很轻松方便了。
我们可以根据实际情况来配置我们的主机列表,具体操作如下:
[root@server ~]# vim /etc/ansible/hosts
[web]
192.168.37.122
192.168.37.133
/usr/bin/ansible Ansibe AD-Hoc 临时命令执行工具,常用于临时命令的执行
/usr/bin/ansible-doc Ansible 模块功能查看工具
/usr/bin/ansible-galaxy 下载/上传优秀代码或Roles模块 的官网平台,基于网络的
/usr/bin/ansible-playbook Ansible 定制自动化的任务集编排工具
/usr/bin/ansible-pull Ansible远程执行命令的工具,拉取配置而非推送配置(使用较少,海量机器时使用,对运维的架构能力要求较高)
/usr/bin/ansible-vault Ansible 文件加密工具
/usr/bin/ansible-console Ansible基于Linux Consoble界面可与用户交互的命令执行工具
ansible-doc 命令常用于获取模块信息及其使用帮助,一般用法如下:
ansible-doc -l #获取全部模块的信息
ansible-doc -s MOD_NAME #获取指定模块的使用帮助
我们也可以查看一下ansible-doc的全部用法:
[root@server ~]# ansible-doc
Usage: ansible-doc [options] [module...]
Options:
-h, --help show this help message and exit # 显示命令参数API文档
-l, --list List available modules #列出可用的模块
-M MODULE_PATH, --module-path=MODULE_PATH #指定模块的路径
specify path(s) to module library (default=None)
-s, --snippet Show playbook snippet for specified module(s) #显示playbook制定模块的用法
-v, --verbose verbose mode (-vvv for more, -vvvv to enable # 显示ansible-doc的版本号查看模块列表:
connection debugging)
--version show program's version number and exit
我们可以来看一下,以mysql相关的为例:
[root@server ~]# ansible-doc -l |grep mysql
mysql_db Add or remove MySQL databases from a remote...
mysql_replication Manage MySQL replication
mysql_user Adds or removes a user from a MySQL databas...
mysql_variables Manage MySQL global variables
[root@server ~]# ansible-doc -s mysql_user
命令的具体格式如下:
ansible [-f forks] [-m module_name] [-a args]
也可以通过ansible -h
来查看帮助,下面我们列出一些比较常用的选项,并解释其含义:
-a MODULE_ARGS #模块的参数,如果执行默认COMMAND的模块,即是命令参数,如: “date”,“pwd”等等
-k,--ask-pass #ask for SSH password。登录密码,提示输入SSH密码而不是假设基于密钥的验证
--ask-su-pass #ask for su password。su切换密码
-K,--ask-sudo-pass #ask for sudo password。提示密码使用sudo,sudo表示提权操作
--ask-vault-pass #ask for vault password。假设我们设定了加密的密码,则用该选项进行访问
-B SECONDS #后台运行超时时间
-C #模拟运行环境并进行预运行,可以进行查错测试
-c CONNECTION #连接类型使用
-f FORKS #并行任务数,默认为5
-i INVENTORY #指定主机清单的路径,默认为/etc/ansible/hosts
--list-hosts #查看有哪些主机组
-m MODULE_NAME #执行模块的名字,默认使用 command 模块,所以如果是只执行单一命令可以不用 -m参数
-o #压缩输出,尝试将所有结果在一行输出,一般针对收集工具使用
-S #用 su 命令
-R SU_USER #指定 su 的用户,默认为 root 用户
-s #用 sudo 命令
-U SUDO_USER #指定 sudo 到哪个用户,默认为 root 用户
-T TIMEOUT #指定 ssh 默认超时时间,默认为10s,也可在配置文件中修改
-u REMOTE_USER #远程用户,默认为 root 用户
-v #查看详细信息,同时支持-vvv,-vvvv可查看更详细信息
上面我们已经提到过 ansible 是基于 ssh 协议实现的,所以其配置公私钥的方式与 ssh 协议的方式相同,具体操作步骤如下:
#1.生成私钥
[root@server ~]# ssh-keygen
#2.向主机分发私钥
[root@server ~]# ssh-copy-id [email protected]
[root@server ~]# ssh-copy-id [email protected]
这样的话,就可以实现无密码登录,我们的实验过程也会顺畅很多。
注意,如果出现了一下报错:
-bash: ssh-copy-id: command not found
那么就证明我们需要安装一个包:
yum -y install openssh-clientsansible
把包安装上即可。
我们使用ansible web -m ping
命令来进行主机连通性测试,效果如下:
[root@ansible ~]# ansible dbserver -m ping
192.168.245.129 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
这样就说明我们的主机是连通状态的。接下来的操作才可以正常进行。
这里的ping模块不是走的ICMP协议,可以打开关闭ICMP协议测试
关闭ICMP协议(echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all)
打开ICMP协议(echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all)
这个模块可以直接在远程主机上执行命令,并将结果返回本主机。
举例如下:
[root@ansible ~]# ansible web -m command -a "ss -ntl"
192.168.245.130 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
命令模块接受命令名称,后面是空格分隔的列表参数。给定的命令将在所有选定的节点上执行。它不会通过shell进行处理,比如$HOME和操作如"<",">","|",";","&" 工作(需要使用(shell)模块实现这些功能)。注意,该命令不支持| 管道命令
。
下面来看一看该模块下常用的几个命令:
chdir # 在执行命令之前,先切换到该目录
executable # 切换shell来执行命令,需要使用命令的绝对路径
free_form # 要执行的Linux指令,一般使用Ansible的-a参数代替。
creates # 一个文件名,当这个文件存在,则该命令不执行,可以用来做判断,不存在则执行
removes # 一个文件名,这个文件不存在,则该命令不执行,存在则执行。
下面我们来看看这些命令的执行效果:
[root@ansible ~]# ansible web -m command -a "chdir=/tmp/ ls"
192.168.245.131 | CHANGED | rc=0 >>
ansible_command_payload_zKgszH
[root@ansible ~]# ansible web -m command -a "creates=/etc/fstab touch /etc/fstab"
192.168.245.132 | SUCCESS | rc=0 >>
skipped, since /etc/fstab exists
[root@ansible ~]# ansible web -m command -a "creates=/etc/fstabtest touch /etc/fstabtest"
rid of this message.
192.168.245.131 | CHANGED | rc=0 >>
[root@ansible ~]# ansible web -m command -a "ls -l /etc/fstabtest"
192.168.245.131 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 0 12月 7 01:38 /etc/fstabtest
[root@ansible ~]# ansible web -m command -a "removes=/etc/fstab cat /etc/fstab"
192.168.245.133 | CHANGED | rc=0 >>
#
# /etc/fstab
# Created by anaconda on Tue Nov 23 21:29:45 2021
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root / xfs defaults 0 0
UUID=bad63c62-92c6-49ff-9040-28dbc52d1c23 /boot xfs defaults 0 0
/dev/mapper/centos-home /home xfs defaults 0 0
/dev/mapper/centos-var /var xfs defaults 0 0
shell模块可以在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等。
[root@server ~]# ansible web -m shell -a 'cat /etc/passwd |grep "keer"'
192.168.37.122 | SUCCESS | rc=0 >>
keer:x:10001:1000:keer:/home/keer:/bin/sh
192.168.37.133 | SUCCESS | rc=0 >>
keer:x:10001:10001::/home/keer:/bin/sh
这个模块用于将文件复制到远程主机,同时支持给定内容生成文件和修改权限等。
其相关选项如下:
src #被复制到远程主机的本地文件。可以是绝对路径,也可以是相对路径。如果路径是一个目录,则会递归复制,用法类似于"rsync"
content #用于替换"src",可以直接指定文件的值
dest #必选项,将源文件复制到的远程主机的绝对路径
backup #当文件内容发生改变后,在覆盖之前把源文件备份,备份文件包含时间信息
directory_mode #递归设定目录的权限,默认为系统默认权限
force #当目标主机包含该文件,但内容不同时,设为"yes",表示强制覆盖;设为"no",表示目标主机的目标位置不存在该文件才复制。默认为"yes"
others #所有的 file 模块中的选项可以在这里使用
用法举例如下:
① 复制文件:
[root@ansible tmp]# ansible web -m copy -a 'src=/tmp/lsblk.sh dest=/tmp/'
192.168.245.131 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "e1655e430bc0d0bb97dea7e9a7ea8711786279f6",
"dest": "/tmp/lsblk.sh",
"gid": 0,
"group": "root",
"md5sum": "531c25d2ad160eaa4fb01e0cc91a5c97",
"mode": "0644",
"owner": "root",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 37,
"src": "/root/.ansible/tmp/ansible-tmp-1638814130.7-78317-182378212980552/source",
"state": "file",
"uid": 0
}
② 给定内容生成文件,并制定权限,(如果文件存在则直接覆盖)
[root@ansible tmp]# ansible web -m copy -a 'content="I an keer \n" dest=/tmp/lsblk.sh
mode=600 owner=usertest'
192.168.245.132 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "62c6cfacc06b9cb29635c49dfee4cc6d6e8088e6",
"dest": "/tmp/lsblk.sh",
"gid": 0,
"group": "root",
"md5sum": "dad17665841753e7c8ea7fc32f40e467",
"mode": "0644",
"owner": "root",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 11,
"src": "/root/.ansible/tmp/ansible-tmp-1638814262.52-80986-149502365496099/source",
"state": "file",
"uid": 0
}
③ 关于覆盖
我们把文件的内容修改一下,然后选择覆盖备份:
[root@server ~]# ansible web -m copy -a 'content="I am keerya\n" backup=yes dest=/data/name mode=666'
192.168.37.122 | SUCCESS => {
"backup_file": "/data/name.4394.2017-12-06@09:46:25~",
"changed": true,
"checksum": "064a68908ab9971ee85dbc08ea038387598e3778",
"dest": "/data/name",
"gid": 0,
"group": "root",
"md5sum": "8ca7c11385856155af52e560f608891c",
"mode": "0666",
"owner": "root",
"size": 12,
"src": "/root/.ansible/tmp/ansible-tmp-1512438383.78-228128616784888/source",
"state": "file",
"uid": 0
}
该模块主要用于设置文件的属性,比如创建文件、创建链接文件、删除文件等。
下面是一些常见的命令:
force #需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
group #定义文件/目录的属组。后面可以加上mode:定义文件/目录的权限
owner #定义文件/目录的属主。后面必须跟上path:定义文件/目录的路径
recurse #递归设置文件的属性,只对目录有效,后面跟上src:被链接的源文件路径,只应用于state=link的情况
dest #被链接到的路径,只应用于state=link的情况
state #状态,有以下选项:
directory:如果目录不存在,就创建目录
file:即使文件不存在,也不会被创建
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent:删除目录、文件或者取消链接文件
用法举例如下:
创建文件:
# 创建文件
# ansible web -m file -a 'path=/tmp/testfile state=touch mode=600 owner=yzg'
# 创建链接
# ansible web -m file -a 'src=/tmp/testfile path=/tmp/testfile-link state=link'
# 创建文件夹
# ansible web -m file -a 'path=/tmp/dir1 state=directory'
# 删除文件
# ansible web -m file -a 'path=/tmp/testfile state=absent'
# 删除目录
# ansible web -m file -a 'path=/tmp/ state=absent'
该模块用于从远程某主机获取(复制)文件到本地。
有两个选项:
dest:用来存放文件的目录
src:在远程拉取的文件,并且必须是一个file,不能是目录
具体举例如下:
[root@ansible tmp]# ansible all -m fetch -a 'src=/tmp/lsblk.sh dest=/tmp/'
192.168.245.132 | CHANGED => {
"changed": true,
"checksum": "62c6cfacc06b9cb29635c49dfee4cc6d6e8088e6",
"dest": "/tmp/192.168.245.132/tmp/lsblk.sh",
"md5sum": "dad17665841753e7c8ea7fc32f40e467",
"remote_checksum": "62c6cfacc06b9cb29635c49dfee4cc6d6e8088e6",
"remote_md5sum": null
}
我们可以在本机上查看一下文件是否复制成功。要注意,文件保存的路径是我们设置的接收目录下的被管制主机ip
目录下:
[root@ansible tmp]# tree .
.
├── 192.168.245.130
│ └── tmp
│ └── lsblk.sh
该模块适用于管理cron
计划任务的。
其使用的语法跟我们的crontab
文件中的语法一致,同时,可以指定以下选项:
day= #日应该运行的工作( 1-31, *, */2, )
hour= # 小时 ( 0-23, *, */2, )
minute= #分钟( 0-59, *, */2, )
month= # 月( 1-12, *, /2, )
weekday= # 周 ( 0-6 for Sunday-Saturday,, )
job= #指明运行的命令是什么
name= #定时任务描述
reboot # 任务在重启时运行,不建议使用,建议使用special_time
special_time #特殊的时间范围,参数:reboot(重启时),annually(每年),monthly(每月),weekly(每周),daily(每天),hourly(每小时)
state #指定状态,present表示添加定时任务,也是默认设置,absent表示删除定时任务
user # 以哪个用户的身份执行
举例如下:
① 添加计划任务
[root@ansible tmp]# ansible centos8 -m cron -a 'minute=*/5 weekday=0,6 job="/usr/bin/wall cron job " name=testcron'
192.168.245.129 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"envs": [],
"jobs": [
"testcron"
]
}
[root@ansible tmp]# ansible centos8 -m shell -a 'crontab -l'
192.168.245.129 | CHANGED | rc=0 >>
#Ansible: testcron
*/5 * * * 0,6 /usr/bin/wall cron job
② 删除计划任务 如果我们的计划任务添加错误,想要删除的话,则执行以下操作:首先我们查看一下现有的计划任务:
[root@ansible tmp]# ansible centos8 -m shell -a 'crontab -l'
192.168.245.129 | CHANGED | rc=0 >>
#Ansible: testcron
#*/5 * * * 0,6 /usr/bin/wall cron job
# state=absent 删除掉计划任务
# disabled=true 注释掉计划任务,true /false yes/no
[root@ansible tmp]# ansible centos8 -m cron -a 'state=absent minute=*/5 weekday=0,6 job="/usr/bin/wall cron job " name=testcron'192.168.245.129 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"envs": [],
"jobs": [
"testcron"
]
}
[root@ansible tmp]# ansible centos8 -m shell -a 'crontab -l'
192.168.245.129 | CHANGED | rc=0 >>
#Ansible: testcron
#*/5 * * * 0,6 /usr/bin/wall cron job
[root@ansible tmp]# ansible centos8 -m cron -a 'disabled=true minute=*/5 weekday=0,6 job="/usr/bin/wall cron job " name=testcron'
192.168.245.129 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"envs": [],
"jobs": [
"testcron"
]
}
[root@ansible tmp]# ansible centos8 -m shell -a 'crontab -l'
192.168.245.129 | CHANGED | rc=0 >>
#Ansible: testcron
#*/5 * * * 0,6 /usr/bin/wall cron job
顾名思义,该模块主要用于软件的安装。
其选项如下:
name= #所安装的包的名称
state= #present--->安装, latest--->安装最新的, absent---> 卸载软件。
update_cache=yes #强制更新yum的缓存
conf_file #指定远程yum安装时所依赖的配置文件(安装本地已有的包)。
disable_pgp_check= #是否禁止GPG checking,只用于presentor latest。yes or no
disablerepo #临时禁止使用yum库。 只用于安装或更新时。
enablerepo #临时使用的yum库。只用于安装或更新时。
下面我们就来安装一个包试试看:
# 安装软件包
[root@ansible ~]# ansible web -m yum -a 'name=dstat state=present'
192.168.245.133 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"dstat"
]
},
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.ustc.edu.cn\n * extras: mirrors.ustc.edu.cn\n * updates: mirrors.163.com\nResolving Dependencies\n--> Running transaction check\n---> Package dstat.noarch 0:0.7.2-12.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n dstat noarch 0.7.2-12.el7 base 163 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 163 k\nInstalled size: 752 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : dstat-0.7.2-12.el7.noarch 1/1 \n Verifying : dstat-0.7.2-12.el7.noarch 1/1 \n\nInstalled:\n dstat.noarch 0:0.7.2-12.el7 \n\nComplete!\n"
]
}
# 删除软件包
[root@ansible ~]# ansible web -m yum -a 'name=dstat state=absent'
192.168.245.130 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"removed": [
"dstat"
]
},
"msg": "",
"rc": 0,
"results": [
"已加载插件:fastestmirror\n正在解决依赖关系\n--> 正在检查事务\n---> 软件包 dstat.noarch.0.0.7.2-12.el7 将被 删除\n--> 解决依赖关系完成\n\n依赖关系解决\n\n================================================================================\n Package 架构 版本 源 大小\n================================================================================\n正在删除:\n dstat noarch 0.7.2-12.el7 @base 752 k\n\n事务概要\n================================================================================\n移除 1 软件包\n\n安装大小:752 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n 正在删除 : dstat-0.7.2-12.el7.noarch 1/1 \n 验证中 : dstat-0.7.2-12.el7.noarch 1/1 \n\n删除:\n dstat.noarch 0:0.7.2-12.el7 \n\n完毕!\n"
]
}
# 查看是否安装
[root@ansible ~]# ansible web -m shell -a 'rpm -q dstat'
192.168.245.132 | FAILED | rc=1 >>
未安装软件包 dstat non-zero return code
192.168.245.131 | FAILED | rc=1 >>
未安装软件包 dstat non-zero return code
192.168.245.130 | FAILED | rc=1 >>
未安装软件包 dstat non-zero return code
192.168.245.133 | FAILED | rc=1 >>
未安装软件包 dstat non-zero return code
该模块用于服务程序的管理。
其主要选项如下:
arguments #命令行提供额外的参数
enabled #设置开机启动。
name= #服务名称
runlevel #开机启动的级别,一般不用指定。
sleep #在重启服务的过程中,是否等待。如在服务关闭以后等待2秒再启动。(定义在剧本中。)
state #有四种状态,分别为:started--->启动服务, stopped--->停止服务, restarted--->重启服务, reloaded--->重载配置
下面是一些例子:
① 开启服务并设置自启动
# 启动服务
[root@ansible ~]# ansible web -m service -a 'name=httpd state=started enabled=true'
192.168.245.130 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
...
# 查看服务是否启动
[root@ansible ~]# ansible web -m shell -a 'ss -ntl '
192.168.245.131 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 [::]:80 [::]:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
② 关闭服务
# 关闭服务
[root@ansible ~]# ansible web -m service -a 'name=httpd state=stopped'
192.168.245.133 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
...
# 查看端口
[root@ansible ~]# ansible web -m shell -a 'ss -ntl'
192.168.245.131 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
该模块主要是用来管理用户账号。
其主要选项如下:
comment # 用户的描述信息
createhome # 是否创建家目录
force # 在使用state=absent时, 行为与userdel –force一致.
group # 指定基本组
groups # 指定附加组,如果指定为(groups=)表示删除所有组
home # 指定用户家目录
move_home # 如果设置为home=时, 试图将用户主目录移动到指定的目录
name # 指定用户名
non_unique # 该选项允许改变非唯一的用户ID值
password # 指定用户密码
remove # 在使用state=absent时, 行为是与userdel –remove一致,会产出家目录
shell= # 指定默认shell
state # 设置帐号状态,不指定为创建,指定值为absent表示删除
system=yes # 当创建一个用户,设置这个用户是系统用户。这个设置不能更改现有用户
uid # 指定用户的uid
举例如下:
① 添加一个用户并指定其 uid
# 创建用户
[root@ansible ~]# ansible web -m user -a 'name=test1 comment="testuser 1" uid=2000 home=/tmp/test1 group=yzg groups=root,bin'
192.168.245.132 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"comment": "testuser 1",
"create_home": true,
"group": 1000,
"groups": "root,bin",
"home": "/tmp/test1",
"name": "test1",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 2000
}
# 查看用户
[root@ansible ~]# ansible web -m shell -a 'getent passwd test1'
192.168.245.131 | CHANGED | rc=0 >>
test1:x:2000:1000:testuser 1:/tmp/test1:/bin/bash
# 删除用户
[root@ansible ~]# ansible web -m user -a 'name=test1 state=absent'
192.168.245.130 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"force": false,
"name": "test1",
"remove": false,
"state": "absent"
}
该模块主要用于添加或删除组。
常用的选项如下:
gid= #设置组的GID号
name= #指定组的名称
state= #指定组的状态,默认为创建,设置值为absent为删除
system= #设置值为yes,表示创建为系统组
举例如下:
# 创建组
[root@ansible ~]# ansible web -m group -a 'name=grouptest gid=1234'
192.168.245.130 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 1234,
"name": "grouptest",
"state": "present",
"system": false
}
# 查看组
[root@ansible ~]# ansible web -a 'getent group grouptest'
192.168.245.131 | CHANGED | rc=0 >>
grouptest:x:1234:
# 删除组
[root@ansible ~]# ansible web -m group -a 'name=grouptest state=absent'
192.168.245.132 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"name": "grouptest",
"state": "absent"
}
该模块用于将本机的脚本在被管理端的机器上运行。
该模块直接指定脚本的路径即可,我们通过例子来看一看到底如何使用的:
首先,我们写一个脚本,并给其加上执行权限:
[root@server ~]# vim /tmp/df.sh
#!/bin/bash
date >> /tmp/disk_total.log
df -lh >> /tmp/disk_total.log
[root@server ~]# chmod +x /tmp/df.sh
[root@server ~]# ansible web -m script -a '/tmp/df.sh'
192.168.37.122 | SUCCESS => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.37.122 closed.\r\n",
"stdout": "",
"stdout_lines": []
}
该模块主要用于收集信息,是通过调用facts组件来实现的。
facts组件是Ansible用于采集被管机器设备信息的一个功能,我们可以使用setup模块查机器的所有facts信息,可以使用filter来查看指定信息。整个facts信息被包装在一个JSON格式的数据结构中,ansible_facts是最上层的值。
facts就是变量,内建变量 。每个主机的各种信息,cpu颗数、内存大小等。会存在facts中的某个变量中。调用后返回很多对应主机的信息,在后面的操作中可以根据不同的信息来做不同的操作。如redhat系列用yum安装,而debian系列用apt来安装软件。
① 查看信息
我们可以直接用命令获取到变量的值,具体我们来看看例子:
# 查看所有变量
# ansible web -m setup -a
# ansible web -m setup -a 'filter=*hostname*'
# ansible web -m setup -a 'filter=ansible_hostname'
# 显示完整地主机名,如yzg-101.com.cn,ansible_hostname只显示yzg-101,ansible_nodename则可以显示完整主机名。
# ansible web -m setup -a 'filter=ansible_nodename'
# 显示完整地主机名
# ansible web -m setup -a 'filter=ansible_fqdn'
# 查看内存
[root@ansible ~]# ansible web -m setup -a 'filter="*mem*"'
192.168.245.130 | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 1521,
"ansible_memory_mb": {
"nocache": {
"free": 1619,
"used": 223
},
"real": {
"free": 1521,
"total": 1842,
"used": 321
},
"swap": {
"cached": 0,
"free": 0,
"total": 0,
"used": 0
}
},
"ansible_memtotal_mb": 1842,
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
② 保存信息
我们的setup模块还有一个很好用的功能就是可以保存我们所筛选的信息至我们的主机上,同时,文件名为我们被管制的主机的IP,这样方便我们知道是哪台机器出的问题。
我们可以看一看例子:
# 结果保存到facts文件,方便查看
[root@ansible ~]# ansible web -m setup -a 'filter="*mem*"' --tree /tmp/facts
192.168.245.131 | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 1521,
"ansible_memory_mb": {
"nocache": {
"free": 1621,
"used": 221
},
"real": {
"free": 1521,
"total": 1842,
"used": 321
},
"swap": {
"cached": 0,
"free": 0,
"total": 0,
"used": 0
}
},
"ansible_memtotal_mb": 1842,
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
[root@ansible ~]# cat /tmp/facts/192.168.245.132
{"ansible_facts": {"ansible_memfree_mb": 1516, "ansible_memory_mb": {"nocache": {"free": 1616, "used": 226}, "real": {"free": 1516, "total": 1842, "used": 326}, "swap": {"cached": 0, "free": 0, "total": 0, "used": 0}}, "ansible_memtotal_mb": 1842, "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
下载角色
ansible-galaxy
ansible-galaxy collection install nginxinc.nginx_core
ansible-galaxy install geerlingguy.nginx
功能:管理加密解密yml文件
ansible-vault [create|decrypt|edit|encrypt|rekey|view]
# 加密yml文件
ansible-vault encrypt hello.yml
# 解密
ansible-vault decrypt hello.yml
# 查看
ansible-vault view hello.yml
# 编辑加密文件
ansible-vault edit hello.yml
# 修改口令
ansible-vault rekey hello.yml
# 创建新文件
ansible-vault create new.yml
Ansible-console:
2.0+新增,可交互执行命令,支持tab
root@test (2)[f:10] $ 执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$
设置并发数: forks n 例如: forks 10
切换组: cd 主机组 例如: cd web
列出当前组主机列表: list
列出所有的内置命令: ?或help
示例:
root@all (2)[f:5]$ list
root@all (2)[f:5]$ cd appsrvs
root@appsrvs (2)[f:5]$ list
root@appsrvs (2)[f:5]$ yum name=httpd state=present
root@appsrvs (2)[f:5]$ service name=httpd state=started
playbook由YMAL语言编写。YAML( /ˈjæməl/ )参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822,Clark Evans在2001年5月在首次发表了这种语言,另外Ingy döt Net与OrenBen-Kiki也是这语言的共同设计者。
YMAL格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写。首先学习了解一下YMAL的格式,对我们后面书写playbook很有帮助。以下为playbook常用到的YMAL格式:
1、文件的第一行应该以 "---" (三个连字符)开始,表明YMAL文件的开始。
2、在同一行中,#之后的内容表示注释,类似于shell,python和ruby。
3、YMAL中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。
4、同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。
5、play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":"分隔表示,":"后面还要增加一个空格。
下面是一个举例:
---
#安装与运行mysql服务
- hosts: node1
remote_user: root
tasks:
- name: install mysql-server package
yum: name=mysql-server state=present
- name: starting mysqld service
service: name=mysql state=started
我们的文件名称应该以.yml
结尾,像我们上面的例子就是mysql.yml
。其中,有三个部分组成:
host部分:使用 hosts 指示使用哪个主机或主机组来运行下面的 tasks ,每个 playbook 都必须指定 hosts ,hosts也可以使用通配符格式。主机或主机组在 inventory 清单中指定,可以使用系统默认的/etc/ansible/hosts,也可以自己编辑,在运行的时候加上-i选项,指定清单的位置即可。在运行清单文件的时候,–list-hosts选项会显示那些主机将会参与执行 task 的过程中。
remote_user:指定远端主机中的哪个用户来登录远端系统,在远端系统执行 task 的用户,可以任意指定,也可以使用 sudo,但是用户必须要有执行相应 task 的权限。
tasks:指定远端主机将要执行的一系列动作。tasks 的核心为 ansible 的模块,前面已经提到模块的用法。
tasks 包含 name 和要执行的模块,name 是可选的,只是为了便于用户阅读,不过还是建议加上去,模块是必须的,同时也要给予模块相应的参数。
使用ansible-playbook运行playbook文件,得到如下输出信息,输出内容为JSON格式。并且由不同颜色组成,便于识别。一般而言
| 绿色代表执行成功,系统保持原样
| 黄色代表系统代表系统状态发生改变
| 红色代表执行失败,显示错误输出
执行有三个步骤:1、收集facts 2、执行tasks 3、报告结果
Playbook的核心元素:
Hosts:主机组;
Tasks:任务列表;
Variables:变量,设置方式有四种;
Templates:包含了模板语法的文本文件;
Handlers:由特定条件触发的任务;
Playbooks配置文件的基础组件:
Hosts:运行指定任务的目标主机
remoute_user:在远程主机上执行任务的用户;
sudo_user:
tasks:任务列表
格式:
tasks:
– name: TASK_NAME
module: arguments
notify: HANDLER_NAME
handlers:
– name: HANDLER_NAME
module: arguments
模块,模块参数: 格式: (1) action: module arguments (2) module: arguments 注意:shell和command模块后面直接跟命令,而非key=value类的参数列表;
handlers:任务,在特定条件下触发;接收到其它任务的通知时被触发;
(1) 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;
(2) 任务可以通过“tags“打标签,而后可在ansible-playbook命令上使用-t指定进行调用;
举例
[root@ansible ansible]# cat test1.yml
---
- hosts: centos8
remote_user: root
tasks:
- name: install pack
yum:
name: httpd
state: present
- name: start service
service:
name: httpd
state: started
enabled: true
[root@ansible ansible]# cat nginx.yml
---
- hosts: web
remote_user: root
tasks:
- name: install nginx
yum:
name: nginx
state: present
- name: copy nginx.conf
copy:
src: /tmp/nginx.conf
dest: /etc/nginx/nginx.conf
backup: yes
notify: reload #当nginx.conf发生改变时,通知给相应的handlers
tags: reloadnginx #打标签
- name: start nginx service
service:
name: nginx
state: started
tags: startnginx #打标签
handlers: #注意,前面没有-,是两个空格
- name: reload
service:
name: nginx
state: restarted #为了在进程中能看出来
[root@ansible ansible]# ansible-playbook test1.yml --list-hosts
playbook: test1.yml
play #1 (centos8): centos8 TAGS: []
pattern: [u'centos8']
hosts (1):
192.168.245.129
[root@ansible ansible]# ansible-playbook test1.yml --list-tasks
playbook: test1.yml
play #1 (centos8): centos8 TAGS: []
tasks:
install pack TAGS: []
start service TAGS: []
# 指定某台机器执行
ansible-playbook --limit 192.168.245.131 httpd.yml
案例
# 安装httpd ,拷贝配置文件,启动服务
[root@ansible ansible]# cat httpd.yml
---
- hosts: web
remote_user: root
tasks:
- name: install httpd
yum:
name: httpd
- name: copy config
copy:
src: /app/httpd.conf
dest: /etc/httpd/conf/
backup: yes
- name: start httpd
service:
name: httpd
state: started
enabled: yes
是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作。
notify这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。
# 当copy模块发生变化时执行notify任务,hadlers
[root@ansible ansible]# cat httpd.yml
---
- hosts: web
remote_user: root
tasks:
- name: install httpd
yum:
name: httpd
- name: copy config
copy:
src: /app/httpd.conf
dest: /etc/httpd/conf/
backup: yes
notify: restart httpd
- name: start httpd
service:
name: httpd
state: started
enabled: yes
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
remote_root: 可用于host和task中,也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户。
- hosts: web
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yzg
sudu: yes #默认sudo为root
sudo_user: testuser # sudo为testuser
# 如果命令或脚本的退出码不为零,可以使用如下方式替代
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
# 或者使用ignore_errors来忽略错误信息
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
tags标签的使用(标签名可以重复)
[root@ansible ansible]# cat httpd.yml
---
- hosts: web
remote_user: root
tasks:
- name: install httpd
yum:
name: httpd
- name: copy config
copy:
src: /app/httpd.conf
dest: /etc/httpd/conf/
backup: yes
notify: restart httpd
tags: conf
- name: start httpd
service:
name: httpd
state: started
enabled: yes
tags: service
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
# 执行时指定标签,则单独执行标签内的语句
# ansible-playbook -t conf httpd.yml
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量来源:
ansible setup facts 远程主机的所有变量都可直接调用
在/etc/ansible/hosts中定义
普通变量:主机组中主机单独定义,优先级高于公共变量
公共(组)变量:针对主机组中所有主机定义统一变量
通过命令行指定变量,优先级最高
ansible-playbook -e varname-value
在playbook中定义
vars:
- var1: value1
- var2: value2
在role中定义
变量应用
[root@ansible ansible]# cat pack.yml
---
- hosts: web
remote_user: root
tasks:
- name: install package
yum:
name: "{{ pkname }}"
- name: copyfile
copy:
src: /app/{{ filename }}
dest: /app/
# ansible-playbook -e "pkname=vsftpd filename=httpd.conf" pack.yml
[root@ansible ansible]# cat v.yml
---
- hosts: web
remote_user: root
vars:
- username: user1
- groupname: group1
tasks:
- name: create group
group:
name: "{{ groupname }}"
- name: create user
user:
name: "{{ username }}"
group: "{{ groupname }}"
home: /app/{{ username }}dir
#执行
# ansible-playbook v.yml
# ansible web -a 'getent passwd user1'
# ansible web -a 'id user1'
# ansible web -m shell -a 'ls /app/user1dir/'
# 利用setup变量
[root@ansible ansible]# cat file.yml
---
- hosts: web
remote_user: root
tasks:
- name: create file
file:
name: /app/{{ ansible_hostname }}.txt
state: touch
# ansible-playbook file.yml
# cat /etc/ansible/hosts
[web]
192.168.245.130 http_port=80
192.168.245.131 http_port=81
192.168.245.132 http_port=82
192.168.245.133 http_port=83
# ansible web -m hostname -a 'name=web{{ http_port }}'
# cat /etc/ansible/hosts
[web]
192.168.245.130 http_port=80 hname=httpd
192.168.245.131 http_port=81 hname=nginx
192.168.245.132 http_port=82 hname=firefox
192.168.245.133 http_port=83 hname=chrome
[root@ansible ansible]# cat name.yml
---
- hosts: web
remote_user: root
tasks:
- name: set hostname
hostname:
name: '{{ hname }}-{{ http_port }}'
# ansible-playbook name.yml
# vim /etc/ansible/hosts
[web]
192.168.245.130 http_port=80
192.168.245.131 http_port=81
192.168.245.132 http_port=82
192.168.245.133 http_port=83
[web:vars]
hname=web
#定义web组公共变量
[root@ansible ansible]# cat name.yml
---
- hosts: web
remote_user: root
tasks:
- name: set hostname
hostname:
name: '{{ hname }}-{{ http_port }}'
# ansible-playbook name.yml
# 定义和调用变量yml文件
[root@ansible ansible]# cat vars.yml
var1: httpd
var2: nginx
[root@ansible ansible]# cat var1.yml
---
- hosts: web
remote_user: root
vars_files:
- vars.yml
tasks:
- name: create file
file:
name: /app/{{ var1 }}-{{ var2 }}.log
state: touch
mode: 600
owner: yzg
# ansible-playbook var1.yml
# playbook和变量文件在同一个目录内
[root@ansible ansible]# ansible web -m shell -a 'ls /app/'
192.168.245.132 | CHANGED | rc=0 >>
httpd-nginx.log
文本文件,嵌套有脚本(使用模板编程语言编写)
Jinja2语言,使用字面量,有下面形式
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, ...]
元组:(item1, item2, ...)
字典:{key1:value1, key2:value2, ...}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
// 除取整数,** 指数(4**2,4的2次方16 )
比较操作:==, !=, >, >=, <, <=
逻辑运算:and, or, not
流表达式:For If When
templates功能:根据模块文件动态生成对应的配置文件。
templates文件必须存放于templates目录下,且命名为.j2 结尾
yaml/yml 文件需和templates目录平级,目录结构如下:
[root@ansible temp]# tree ./
./
├── templates
│ └── test.conf.j2
└── temptest.yml
实例
# templates 目录里httpd.conf.j2是httpd的配置文件,把配置文件拷贝到web组主机
[root@ansible ansible]# cat temphttpd.yml
---
- hosts: web
remote_user: root
tasks:
- name: template
template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
实例
# cat /etc/ansible/hosts #定义变量,每台机器的端口
[web]
192.168.245.130 http_port=80
192.168.245.131 http_port=81
192.168.245.132 http_port=82
192.168.245.133 http_port=83
# 模板文件配置,进程数根据cpu核心数*2,端口号来自hosts文件定义的变量
[root@ansible ansible]# cat templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus*2 }};
server {
listen {{http_port}};
listen [::]:{{http_port}};
server_name _;
root /usr/share/nginx/html;
...
# 安装、修改配置,启动服务
[root@ansible ansible]# cat temnginx.yml
---
- hosts: web
remote_user: root
#vars:
# - http_port: 8080
tasks:
- name: install
yum:
name: nginx
state: present
- name: copytmp
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags: copytmp
notify: restart nginx
- name: service start
service:
name: nginx
state: started
enabled: yes
handlers:
- name: restart nginx
service:
name: nginx
state: started
条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要做到条件测试,通过when语句实现,在task中使用,jinja2的语句格式。
when语句
在task后添加when字句即可使用条件测试;when语句支持jinja2表达式语法
实例:
# templates 目录里httpd.conf.j2是httpd的配置文件,把配置文件拷贝到web组主机
[root@ansible ansible]# cat temphttpd.yml
---
- hosts: web
remote_user: root
tasks:
- name: template 7
template:
src: httpd_7.conf.j2
dest: /etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version=="7"
- name: template 8
template:
src: httpd_8.conf.j2
dest: /etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version=="8"
- name: start
service:
name: httpd
state: started
迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为“item”
要在task中使用with_items给定要迭代的元素列表
列表格式:
字符串
字典
# 实例:
# 创建用户,复制文件
---
- hosts: web
remote_root: root
tasks:
- name: add users
user:
name: {{ item }}
state: present
groups: wheel
with_items:
- testuser1
- testuser2
- name: copyfile
copy:
src: /app/{{ item }}
dest: /etc/{{ item }}
with_items:
- file1
- file2
- name: copyfile2
copy:
src: {{ item }}
dest: /app/
with_items:
- /app/file1
- /app/file2
- name: install
yum:
name: {{ item }}
state: present
with_items:
- httpd
- vsftpd
- apr
# 等同于下面的语句
- name: add users
user:
name: testuser1
state: present
groups: wheel
- name: add users
user:
name: testuser2
state: present
groups: wheel
- name: copyfile1
copy:
src: /app/file1
dest: /etc/file1
- name: copyfile2
copy:
src: /app/file2
dest: /etc/file2
# 实例
---
- hosts: web
remote_user: root
tasks:
- name: create groups
group:
user: {{ item }}
with_items:
- newgoups1
- newgoups2
- newgoups3
- name: create user
user:
name: {{ item.newuser }}
group: {{ item.groups }}
with_items:
- {newuser:'newuser1',groups:'newgroups1'}
- {newuser:'newuser2',groups:'newgroups2'}
- {newuser:'newuser3',groups:'newgroups3'}
# Playbook中template for if
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen | default('80 default_server') }};
{% endfor %}
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }};
{% endif %}
{% if vhost.root is defined %}
root {{ vhost.root }};
{% endif %}
# 实例
[root@ansible ansible]# cat templates/for1.conf.j2
{%for port in ports%}
server{
listen {{ port }};
}
{%endfor%}
[root@ansible ansible]# cat for1.yml
---
- hosts: web
remote_user: root
vars:
ports:
- 81
- 82
- 83
- 84
tasks:
- name: test for1
template:
src: for1.conf.j2
dest: /app/for1.conf
[root@ansible ansible]# cat templates/for2.conf.j2
{%for vhost in vhosts%}
server{
listen {{ vhost.port }};
servername {{ vhost.name }};
rootdir {{ vhost.root }};
}
{%endfor%}
[root@ansible ansible]# cat for2.yml
---
- hosts: web
remote_user: root
vars:
vhosts:
- web1:
port: 82
name: web1.yzg.com
root: /app/webroot1
- web2:
port: 83
name: web3.yzg.com
root: /app/webroot3
- web3:
port: 84
name: web4.yzg.com
root: /app/webroot4
tasks:
- name: test for2
template:
src: for2.conf.j2
dest: /app/for2.conf
[root@ansible ansible]# cat templates/for3.conf.j2
{%for vhost in vhosts%}
server{
listen {{ vhost.port }};
# 判断vhost.name的值是否被定义,如果定义了就引用,没定义就不管
{%if vhost.name is defined%}
servername {{ vhost.name }};
{%endif%}
rootdir {{ vhost.root }};
}
{%endfor%}
[root@ansible ansible]# cat for3.yml
---
- hosts: web
remote_user: root
vars:
vhosts:
- web1:
port: 82
root: /app/webroot1
- web2:
port: 83
root: /app/webroot3
- web3:
port: 84
name: web4.yzg.com
root: /app/webroot4
tasks:
- name: test for2
template:
src: for3.conf.j2
dest: /app/for3.conf
ansilbe自1.2版本引入的新特性,用于层次性、结构化地组织playbook。
roles能够根据层次型结构自动装载变量文件、 tasks以及handlers等。
要使用roles只需要在playbook中使用 import_tasks指令即可。
简单来讲,roles就是通过分别将变量、文件 、任务、模板及处理器放置于单独的目录中,并可以便捷地 include它们的一种机制。
角色一般用于基于主机构建服务的场 景中,但也可以是用于构建守护进程等场景中
复杂场景:建议使用roles,代码复用度高
变更指定主机或主机组
如命名不规范维护和传承成本大
某些功能需多个Playbook,通过Includes即可实现
角色(roles):角色集合
roles/
mysql/
httpd/
nginx/
memcached/
# 每个角色,以特定的层级目录结构进行组织
# roles目录结构:
playbook.yml
roles/
project/
tasks/
files/
vars/ #不常用
default/ #不常用
templates/
handlers/
meta/ #不常用
实例
# roles目录结构
[root@ansible ansible]# tree
.
├── filecopy_roles.yml
├── nginx_roles.yml
├── roles
│ ├── filecopy
│ │ ├── files
│ │ │ └── fstab
│ │ └── tasks
│ │ └── main.yml
│ ├── memcached
│ └── nginx
│ ├── tasks
│ │ ├── groupadd.yml
│ │ ├── install.yml
│ │ ├── main.yml
│ │ ├── start.yml
│ │ ├── stop.yml
│ │ └── useradd.yml
│ ├── templates
│ └── vars
└── roles-tags.yml
[root@ansible ansible]# cat roles/nginx/tasks/groupadd.yml
- name: add group
group:
name: nginx
[root@ansible ansible]# cat roles/nginx/tasks/install.yml
- name: install pack
yum:
name: nginx
[root@ansible ansible]# cat roles/nginx/tasks/start.yml
- name: install service
service:
name: nginx
state: started
enabled: yes
[root@ansible ansible]# cat roles/nginx/tasks/stop.yml
- name: stop service
service:
name: nginx
state: stopped
[root@ansible ansible]# cat roles/nginx/tasks/useradd.yml
- name: add user
user:
name: nginx
group: nginx
system: yes
shell: /sbin/nologin
# 按执行顺序写
[root@ansible ansible]# cat roles/nginx/tasks/main.yml
- import_tasks: groupadd.yml
- import_tasks: useradd.yml
- import_tasks: install.yml
- import_tasks: stop.yml
- import_tasks: start.yml
# 这里拷贝和创建文件写在一起了,拷贝的文件放在files文件夹内,src可以不写具体路径。
[root@ansible ansible]# cat roles/filecopy/tasks/main.yml
- name: filecopy
copy:
src: fstab
dest: /app/
- name: create file
file:
name: /app/testfile
mode: '600'
state: touch
# 这里是在filecopy角色中调用了nginx的stop任务。跨角色调用
- import_tasks: roles/nginx/tasks/stop.yml
[root@ansible ansible]# cat nginx_roles.yml
---
- hosts: web
remote_user: root
roles:
- role: nginx
- role: filecopy # 这里还可以调用多个roles角色
[root@ansible ansible]# cat filecopy_roles.yml
---
- hosts: web
remote_user: root
roles:
- role: filecopy
# 给角色打标签,每个角色可以打多个标签,执行的时候可以写多个角色。
[root@ansible ansible]# cat roles-tags.yml
---
- hosts: web
remote_user: root
roles:
- { role: nginx, tags: ['nginx','web'] }
- { role: httpd, tags: ['httpd','web'] }
- { role: memcached, tags: 'cache' }
- { role: mysql, tags: 'db' }
# 短格式写法
roles:
- role: nginx
tags: '"nginx" "web"'
- role: httpd
tags: '"httpd" "web"'
- role: memcached
tags: cache
- role: mysql
tags: db
#
# 执行web标签角色,会执行nginx角色和httpd角色。
ansible-playbook -C -t web roles-tags.yml
#
ansible-playbook -C -t "web,db" roles-tags.yml
roles案例
# 安装nginx服务,拷贝模板、启动
# 目录结构
[root@ansible ansible]# tree roles/nginx/
roles/nginx/
├── handlers
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
│ └── nginx.conf.j2
└── vars
[root@ansible ansible]# cat roles/nginx/tasks/main.yml
- name: install package
yum:
name: nginx
- name: template
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart service
tags: tempfile # 给任务加标签 ,执行标签任务ansible-playbook -t tempfile test_roles.yml
- name: start service
service:
name: nginx
state: started
#
[root@ansible ansible]# cat roles/nginx/handlers/main.yml
- name: restart service
service:
name: nginx
state: restarted
# 模板这里进程数引用ansible的变量来获取并乘以2
[root@ansible ansible]# cat roles/nginx/templates/nginx.conf.j2 | grep ansible
worker_processes {{ ansible_processor_vcpus*2}};
# 执行测试验证
ansible-playbook test_roles.yml
ansible web -m shell -a 'ps aux | grep nginx'
ansible web -m shell -a 'ss -ntlp'
# 加入变量测试
[root@ansible ansible]# cat roles/nginx/vars/main.yml
http_port: 8080
[root@ansible ansible]# cat roles/nginx/templates/nginx.conf.j2 | grep -C3 listen
include /etc/nginx/conf.d/*.conf;
server {
listen {{ http_port }};
listen [::]:{{ http_port }};
server_name _;
root /usr/share/nginx/html;3
[root@ansible ansible]# cat test_roles.yml
- hosts: web
remote_user: root
roles:
- role: nginx
# 执行测试验证
ansible-playbook test_roles.yml
ansible web -m shell -a 'ps aux | grep nginx'
ansible web -m shell -a 'ss -ntlp'
# 加入条件判断,只有centos7版本才执行
[root@ansible ansible]# cat test_roles.yml
- hosts: all
remote_user: root
roles:
- role: nginx
when: ansible_distribution_major_version=='7'
http_port: 9090 # 这里还可以定义变量,会替代vars里定义的变量
# 执行测试验证
ansible-playbook test_roles.yml
# 执行多个角色
[root@ansible ansible]# cat test_roles.yml
- hosts: all
remote_user: root
roles:
- role: nginx
when: ansible_distribution_major_version=='7'
http_port: 9090
- role: filecopy
when: ansible_nodename=='yzg_01' #条件为主机名为yzg_01才执行filecopy角色
实例:安装memcached
[root@ansible roles]# tree memcached/
memcached/
├── tasks
│ └── main.yml
└── templates
└── memcached.j2
[root@ansible roles]# cat memcached/tasks/main.yml
- name: install package
yum:
name: memcached
- name: template
template:
src: memcached.j2
dest: /etc/sysconfig/memcached
- name: start service
service:
name: memcached
state: started
enabled: yes
# 模板文件,缓存大小调整为内存大小的四分之一,取整
[root@ansible roles]# cat memcached/templates/memcached.j2
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ ansible_memtotal_mb//4 }}"
OPTIONS=""
[root@ansible ansible]# cat test_roles1.yml
- hosts: all
remote_user: root
roles:
- role: memcached
when: ansible_distribution_major_version=='7'