ansible 官网:https://www.ansible.com/
ansible 官网文档参考:https://docs.ansible.com/
ansible 中文参考指南:http://www.ansible.com.cn/index.html
Ansible是一个开源配置管理工具,可以使用它来自动化任务,部署应用程序实现IT基础架构。Ansible可以用来自动化日常任务,比如,服务器的初始化配置、安全基线配置、更新和打补丁系统,安装软件包等。Ansible架构相对比较简单,仅需通过SSH连接客户机执行任务即可。
因为 Ansible 是通过 ssh 登陆机器的,所以它可以管理的机器如下:
常见使用场景
只要能通过 ssh 协议登陆的机器,就可以完成 ansible 自动化部署
ansible 优势
与其他自动化工具相比,Ansible是无客户端Agent的,所以无需在客户机上安装或配置任何程序,就可以运行Ansible任务。由于Ansible不会在客户机上安装任何软件或运行监听程序,因此消除了许多管理开销,我们使用Ansible管理服务器,同时Ansible的更新也不会影响任何客户机。使用 yaml 配置文件语法,功能强大,便于维护。
ansible 是基于 python 语言开发的,主要有 python 的两个 ssh 处理模块 paramiko
以及 PyYAML
模块
注意事项
写在最后:ansible 其实就是一个使用工具,他更多的则是去调用一些模块去完成任务内容,所以与其说我们在学习 ansible ,不如说是在学习 ansible 的模块。
Host Inventory:主机群,主机清单,定义ansible管理的主机,还可以存放一下针对不同主机的变量,也可以写入主机的用户名和密码
Playbooks:ansible的任务配置文件,将多个任务定义在剧中本,由ansible自动执行
Core Modules:核心模块,Ansible自带的模块。
Custom Modules:自定义模块,如果核心模块不足以完成某种功能,可以自行添加自定义模块(支持现在主流的大部分编程语言,甚至于shell)
Plugins:插件,支持使用插件的方式对ansible本身的功能进行扩展,模块是用来实现任务的,增强ansible平台自己的功能就需要使用插件(loggin插件记录日志,email插件发送邮件),其中最常用的是:连接插件(Connectionr Plugins)ansible基于连接插件连接到各个主机上,虽然默认情况下ansible使用ssh连接到各个主机上,但它还支持其它的连接方法。
访问执行顺序
这里准备三台测试机器
IP | 主机名 | 角色 |
---|---|---|
192.168.169.150 | master | 安装 ansible |
192.168.169.151 | node01 | 被管理机器 |
192.168.169.152 | node02 | 被管理机器 |
# 安装 epel 源
yum install epel-release -y
# 管理节点安装 ansible
yum install ansible -y
# 安装完成之后我们可以首先将 log 日志开启,便于后期查看日志信息。默认是注释的,我们可以将注释取消,也可以自定义日志文件目录信息
vim /etc/ansible/ansible.cfg
log_path = /var/log/ansible.log
# 如果托管节点开启了SElinux,需要安装libselinux-python,如果没有开启则不需要安装
yum install libselinux-python -y
rpm -qi ansible #查看ansible版本信息
rpm -qa ansible #查看ansible包名称
rpm -ql ansible #查看ansible安装目录
[root@master01 etc]# ansible --version
ansible 2.9.27 # 版本信息
config file = /etc/ansible/ansible.cfg # 主要配置文件地址
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] # 模块地址
ansible python module location = /usr/lib/python2.7/site-packages/ansible # python 模块信息
executable location = /usr/bin/ansible # 可执行文件地址
python version = 2.7.5 (default, Oct 14 2020, 14:45:30) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] # python 版本信息
/etc/ansible #ansible主目录
/etc/ansible/ansible.cfg #ansible主配置文件
/etc/ansible/hosts #ansible主机清单
/etc/ansible/roles #ansible角色目录
/usr/bin/ansible #ansible主程序目录
/usr/bin/ansible-connection #ansible连接工具
/usr/bin/ansible-console #ansible控制台
/usr/bin/ansible-doc #ansible文档工具
/usr/bin/ansible-galaxy #ansible galaxy
/usr/bin/ansible-inventory #ansible资产
/usr/bin/ansible-playbook #ansible playbook剧本工具
/usr/bin/ansible-pull #ansible pull是指在客户端组件基于ansible pull的方式从服务器上拉取文件
ansible 配置文件 /etc/ansible/ansible.cfg (一般默认此目录下)
[default]
inventory = /etc/ansible/hosts #被控端主机清单文件
library = /usr/share/my_modules/ #指定ansible搜索模块位置,如果需要自定ansible模块,需要放到 library 所指定的目录下
remote_tmp = ~/.ansible/tmp #临时文件远程主机存放目录
local_tmp = ~/.ansible/tmp #临时文件本地主机存放目录
forks = 5 #ansible在执行工作时进程数量
poll_interval = 15 #默认轮询间隔时间,单位秒
sudo_user = root #被控端默认执行sudo命令所切换的用户
ask_sudo_pass = True #每次执行sudo命令时是否询问sudo到目标用户的密码
ask_pass = True #每次执行ansible命令是否询问ssh密码
transport = smart #通信机制
remote_port = 22 #远程连接被控端的ssh端口
module_lang = C #模块和系统之间通信的语言,默认为C语言
gathering = implicit #控制默认facts收集,远程系统变量
roles_path = /etc/ansible/roles #角色存储路径
host_key_checking = False #是否检查远程主机密钥
sudo_exe = sudo #sudo远程执行命令
sudo_flags = -H -S -n #传递sudo之外的参数
timeout = 10 #SSH超时时间
remote_user = root #指定默认的远程连接用户
log_path = /var/log/ansible.log #ansible日志文件,执行ansible的用户需要对日志文件具有写入权限
module_name = command #ansible默认执行的模块
executable = /bin/sh #执行的shell环境,用户shell模块
hash_behaviour = replace #如果变量重叠,优先级更高的一个是替换优先级低得还是合并在一起,默认为替换
private_role_vars = yes #默认情况下,角色中的变量将在全局变量范围中可见。 为了防止这种情况,可以启用以下选项,只有tasks的任务和handlers得任务可以看到角色变量
private_key_file = /path/to/file #私钥文件存储位置
command_warnings = False #command模块Ansible默认发出警告
nocolor = 1 #ansible输出带上颜色区别,0表示开启,1表示关闭
pipelining = False #开启pipe ssh通道优化
[inventory]
[privilege_escalation]
#出于安全角度考虑,部分公司不希望直接以root的高级管理员权限直接部署应用,往往会开放普通用户权限并给予sudo的权限,该部分配置主要针对sudo用户提权的配置
become=True #是否sudo
become_method=sudo #sudo方式
become_user=root #sudo后变为root用户
become_ask_pass=False #sudo后是否需要验证密码
[paramiko_connection]
pty=False #是否禁用sudo功能
[ssh_connection]
#Ansible默认使用SSH协议连接对端主机,该部署是主要是SSH连接的一些配置,但配置项较少,多数默认即可
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s #ssh连接时的参数
pipelining = False #SSH pipelining 是一个加速 Ansible 执行速度的简单方法。ssh pipelining 默认是关闭,之所以默认关闭是为了兼容不同的 sudo 配置,主要是 requiretty 选项。如果不使用 sudo,建议开启。打开此选项可以减少 ansible 执行没有传输时 ssh 在被控机器上执行任务的连接数。不过,如果使用 sudo,必须关闭 requiretty 选项
scp_if_ssh = smart #该项为True时,如果连接类型是ssh,使ansible使用scp,为False是,ansible使用sftp。默认为smart,smart为先尝试sftp,然后尝试scp
[persistent_connection] #持续连接
connect_timeout = 30 #ansible如果在30秒内没有收到请求,则关闭连接,默认为30秒
command_timeout = 30 #ansible执行命令如果在30秒内没有收到回应则认为命令超时
[accelerate] #缓存加速
accelerate_port = 5099 #加速连接端口5099
accelerate_timeout = 30 #命令执行超时时间
ccelerate_connect_timeout = 5.0 #连接超时时间,单位为秒
accelerate_daemon_timeout = 30 #上一个活动连接的时间,单位为分钟
accelerate_multi_key = yes #允许多个私钥被加载到daemon
[selinux]
special_context_filesystems=nfs,vboxsf,fuse,ramfs,9p #文件系统在处理安全上下文时需要特殊处理,定义复制现有上下文的文件系统
libvirt_lxc_noseclabel = yes #将此设置为yes,以允许libvirt_lxc连接在没有SELinux的情况下工作
[colors]
#Ansible对于输出结果的颜色也进行了详尽的定义且可配置,该选项对日常功能应用影响不大,几乎不用修改,保持默认即可。
highlight = white
verbose = blue
warn = bright purple
error = red
debug = dark gray
deprecate = purple
skip = cyan
unreachable = red
ok = green
changed = yellow
diff_add = green
diff_remove = red
diff_lines = cyan
[diff]
always = no
context = 3
ansible --help
Usage: ansible <host-pattern> [options]
选项:
-a MODULE_ARGS, --args=MODULE_ARGS #指定模块的参数
--ask-vault-pass #询问账号的密码
-B SECONDS, --background=SECONDS #异步运行,在指定秒后异步运行失败
-C, --check #不做出任何改变,只是进行测试检查
-D, --diff #当更改(小)文件和模板时,显示这些文件中的差异
-e EXTRA_VARS, --extra-vars=EXTRA_VARS #将其他变量设置为key=value或YAML/JSON,如果文件名前面有@
-f FORKS, --forks=FORKS #指定要使用的并行进程数,例如100台机器,-f指定每次运行几台,默认每次运行5台
-i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY #指定主机列表路径,如果不指定,默认为/etc/ansible/ansible.cfg中指定的hosts
-l SUBSET, --limit=SUBSET #将选定的主机限制为附加模式。
--list-hosts #列出清单中的主机列表,不进行任何操作
-m MODULE_NAME, --module-name=MODULE_NAME #指定要执行的模块名称,默认为 command 模块
-M MODULE_PATH, --module-path=MODULE_PATH #指定要执行模块的路径,默认模块路径为~/.ansible/plugins/modules:/usr/share/ansible/plugins
-o, --one-line #浓缩输出
--playbook-dir=BASEDIR #指定playbook文件目录
-P POLL_INTERVAL, --poll=POLL_INTERVAL #指定轮训间隔时间,默认为15
--syntax-check #如果使用了playbook则执行--syntax-check对剧本进行check
-t TREE, --tree=TREE #将ansible输出记录到指定目录
--vault-id=VAULT_IDS the vault identity to use
--vault-password-file=VAULT_PASSWORD_FILES
vault password file
-v, --verbose #详细模式(-VVV更多,-VVVV可启用连接调试)
--version #显示程序的版本号、配置文件位置、配置模块搜索路径、模块位置、可执行位置和退出
特权提升选项:
-b, --become #临时使用--become-method指定的提取方法
--become-method=BECOME_METHOD #使用权限提升方法(默认值=sudo)
--become-user=BECOME_USER #以该用户的身份运行操作(默认值=root)
-K, --ask-become-pass #请求权限提升密码
连接选项:
-k, --ask-pass #请求连接密码
--private-key=PRIVATE_KEY_FILE, --key-file=PRIVATE_KEY_FILE #指定私钥文件进行登录
-u REMOTE_USER, --user=REMOTE_USER #指定连接用户,默认不指定则为hosts文件中用户
-c CONNECTION, --connection=CONNECTION #连接方式,默认为smart,还有ssh和sftp
-T TIMEOUT, --timeout=TIMEOUT #ansible连接超时时间,默认为10s
--ssh-common-args=SSH_COMMON_ARGS #指定要传递到SFTP/SCP/SSH的常见参数(例如ProxyCommand)
--sftp-extra-args=SFTP_EXTRA_ARGS #指定要传递到SFTP的额外参数(例如-f、-l)
--scp-extra-args=SCP_EXTRA_ARGS #指定要传递到SCP的额外参数(例如-1)
--ssh-extra-args=SSH_EXTRA_ARGS #指定只传递给ssh的额外参数(例如-R)
配置介绍
ansible_ssh_host=172.26.3.58 #目标主机地址
ansible_ssh_port=22 #目标端口,默认为ansible.cfg中配置的端口
ansible_ssh_user=test #连接目标主机的用户
ansible_ssh_pass=123456 #连接目标主机的用户密码
ansible_ssh_private_key_file=/root/.ssh/id_rsa #连接目标主机的用户密钥,密钥和密码二选一即可
ansible_sudo_ssh=123456 #sudo到ansible.cfg配置中指定用户的密码
ansible_python_interpreter=/bin/python2.7 #指定python解释器
[axxl]
app_node1 ansible_ssh_host=172.26.3.57 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=123456
app_node2 ansible_ssh_host=172.26.3.58 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=123456
#分组名称为 [axxl]
app_node:为主机的别名,如果使用ansible_ssh_host参数就必须要指定别名
ansible_ssh_host:指定主机地址
ansible_ssh_port:指定主机端口
ansible_ssh_user:指定连接用户
ansible_ssh_pass:指定连接密码
[mbxy]
172.26.3.[81:82] ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_private_key_file=/root/.ssh/id_rsa
#分组名称为 [mbxy]
172.26.3.[81:82]:目标主机地址, [81:82]使用表达式来匹配同网段主机,可以多写一些,例如:172.26.3.[81:100],则执行81-100之内的所有地址
ansible_ssh_private_key_file:明文密码写入hosts文件不安全,可以通过私钥来进行连接
[ybx]
172.26.3.84
172.26.3.85
[ybx:vars]
ansible_ssh_port=22
ansible_ssh_user=root
ansible_ssh_pass=123456
#分组名称为 [ybx]
[ybx:vars]:只针对 [ybx]分组内的机器使用该变量
[nginx]
172.26.3.62
[mbkz]
172.26.3.81
[all:vars]
ansible_ssh_port=22
ansible_ssh_user=root
ansible_ssh_pass=123456
#多个分组 [nginx] [mbkz]
[all:vars]:对hosts文件内所有的分组应用此变量
[dbservers]
db01.intranet.mydomain.net
db02.intranet.mydomain.net
#主机名
如果目标地址的主机名本机可以解析,那么也可以添加主机名
db-[99:101]-node.example.com
#域名或主机名的正则表达式匹配
ansible 批量管理主机的方式主要有两种
# 配置好 ansible 配置文件,添加被管理主机 ip 或者主机名
# 备份现有文件
cd /etc/ansible/
cp hosts hosts.bak
# 或者使用如下命令备份
cp /etc/ansible/hosts{,.bak}
命令解析:
{} 固定格式
, 获取文件之前的目录信息
.bak 添加到文件之后的信息
vim /etc/ansible/hosts
# 在最后添加入下信息
[demo] # 自定义一个名称
192.168.169.151 # 被管理主机的IP地址
192.168.169.152 # 被管理主机的IP地址
# 我们可以通过 --list-hosts 参数获取管理组中的机器
[root@master ~]# ansible dong --list-hosts
hosts (2):
192.168.169.161
192.168.169.162
1️⃣ 使用 ssh 密码认证方式管理机器
ansible 是直接利用 linux 本地的 ssh 服务,以及一些远程的 ssh 操作,一般情况下客户端的 ssh 服务都是默认开启的,无需额外管理
示例:
# 在 node01 上执行如下命令
# 语法
ansible 主机列表 -m command -a 'hostname' -k -u root
参数解析:
主机列表 就是在配置文件中自定义的名称 demo
-m 指定功能模块,默认情况下就是使用 command(即不使用 -m 参数,默认也是使用 command 模块)
-a 告诉模块需要执行的参数
-k 询问密码验证
-u 指定远程主机运行的用户
# 实际命令如下
ansible demo -m command -a 'hostname' -k -u root
[root@master01 ~]# ansible demo -m command -a 'hostname' -k -u root
SSH password:
192.168.169.151 | FAILED | rc=-1 >>
Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host.
192.168.169.152 | FAILED | rc=-1 >>
Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host.
正常如果在 ~/.ssh 下没有文件,说明这台机器还没有使用 ssh 方式连接过其他主机
ssh [email protected]
# 152 也是同样的操作
ssh [email protected]
# 找到如下内容,将注释取消
# uncomment this to disable SSH key host checking
host_key_checking = False
ansible demo -m command -a 'hostname' -k -u root
2️⃣ 配置免密登陆
每次执行 ansible 命令时,都需要输入 ssh 认证密码,如果是不同主机密码不一样,那么还要输入多次,就很不方便。
因此我们可以配置如下的快捷登陆方式:
ansible 自带的密码认证参数
# 可以在 /etc/ansible/hosts 文件中定义好密码即可实现快速的认证,远程管理主机
参数:
ansible_ssh_host=172.26.3.58 #目标主机地址
ansible_ssh_port=22 #目标端口,默认为ansible.cfg中配置的端口
ansible_ssh_user=test #连接目标主机的用户
ansible_ssh_pass=123456 #连接目标主机的用户密码
测试发现 ansible_ssh_user 和 ansible_user 使用效果是一样的,不知道其他的是不是也是这种情况
# 示例:
vim /ect/ansible/hosts
[demo]
193.168.169.151 ansible_ssh_user=root ansible_ssh_pass=0
192.168.169.152 ansible_ssh_user=root ansible_ssh_pass=0
此时就可以不用手动输入密码了,但是这样也有个问题就是将其他机器的密码以明文的方式在配置文件中暴露出来了
ansible demo -m command -a 'hostname'
使用 ssh 秘钥方式批量管理主机,这个方式比起 hosts 文件中配置密码参数更加安全
# 在 master 主机上配置 ssh 密钥对
ssh-keygen -f ~/.ssh/id_rsa -P "" >/dev/null 2>&1
# 检查公私钥文件
[root@master01 ~]# cd .ssh/
[root@master01 .ssh]# ls
id_rsa id_rsa.pub known_hosts
[root@master01 .ssh]#
#!/bin/bash
rm -rf ~/.ssh/id_rsa*
ssh-keygen -f ~/.ssh/id_rsa -P "" >/dev/null 2>&1
SSH_Pass=0
Key_Path=~/.ssh/id_rsa.pub
for i in 151 152
do
sshpass -p$SSH_Pass ssh-copy-id -i $Key_Path "-o StrictHostKeyChecking=no" 192.168.169.$i
done
# 非交互式分发公钥命令需要用 sshpass 指定 SSH 密码,通过 -o StrictHostKeyChecking=no 跳过 SSH 连接确认信息
# 执行脚本
[root@master01 sshpass]# sh ssh_send.sh
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -o ' StrictHostKeyChecking=no' '192.168.169.151'"
and check to make sure that only the key(s) you wanted were added.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -o ' StrictHostKeyChecking=no' '192.168.169.152'" # 这里提示可以尝试登陆
and check to make sure that only the key(s) you wanted were added.
[root@master01 ~]# ssh -o ' StrictHostKeyChecking=no' '192.168.169.152'
Last login: Sat Jul 9 21:37:15 2022 from maste01
[root@node02 ~]# exit
登出
Connection to 192.168.169.152 closed.
[root@master ~]# ansible dong -m command -a 'hostname'
192.168.169.161 | CHANGED | rc=0 >>
node01
192.168.169.162 | CHANGED | rc=0 >>
node02
在生产环境中,ansible 的连接方式二选一即可,最好是选择配置 ssh 公私钥免密登陆。
如果生产环境要求更高,可以使用普通用户去执行,在使用 sudo 进行提权操作。
可以禁止外网 ssh 登陆,使用 VPN 连接内网操作。
ansible 实现批量化主机管理的模式主要有两种:
ad-hoc
模式playbook
剧本来实现批量化管理,即 playbook
剧本模式ansible 的 ad-hoc 模式就是 ansible 的命令行形式,也就是处理一些临时的,简单的任务,可以利用 ansible 的命令行来操作。
应用场景:
--version # 显示版本号
-m module # 指定模块,默认是 command
-v # 显示详细过程,-vv -vvv 会更加详细
--list-hosts # 显示主机列表,可以简写成 --list
-k, --ask-pass # 提示输入 ssh 密码验证,默认 key 验证
-C, --check # 不做出任何改变,只是进行测试检查
-T, --timeout=TIMEOUT # 执行命令的超时时间,默认是 10s
-u, --user=REMOTE_USER # 执行远程命令的用户
-b, --become # 替代旧版的 sudo 切换
--become-user=USERNAME # 指定 sudo 的 runas 用户,默认是 root
-K, --ask-become-pass # 提示输入 sudo 时的口令
示例:
[root@master ~]# ansible dong -m command -a 'hostname'
192.168.169.162 | CHANGED | rc=0 >>
node02
192.168.169.161 | CHANGED | rc=0 >>
node01
ad-hoc 命令解析:
ansible ansible 自带的命令
dong /etc/ansible/hosts 中定义的主机组(其他写法可参考本文 [4.5 章节内容]
-m command -m 是 ansible 指定模块的参数,-m command 即是指定了 ansible 处理任务的模块
-a 'hostname' -a 指定给 command 模块的参数,即让 command 模块执行的任务是什么
# 查看配置文件中被管理机器信息
[root@master ~]# ansible dong --list-hosts
hosts (2):
192.168.169.161
192.168.169.162
或者查看全部
[root@master ~]# ansible "*" --list-hosts
hosts (2):
192.168.169.161
192.168.169.162
192.168.169.160
或者
[root@master ~]# ansible all --list-hosts
hosts (2):
192.168.169.161
192.168.169.162
192.168.169.160
* 和 all 是等价的
ansible "*" --list-hosts
ansible "*" -m ping
ansible "192.168.169.*" -m ping
# 在配置文件中定义的两个主机组,使用 ':' 判断“或”关系,判断一个主机或者在 dong 这个里面,或者是在 local 这个里面
ansible "dong:local" -m ping
# 两个不同主机之间
ansible "192.168.169.160:192.168.169.162" -m ping
# 判断即在 dong 这个主机组里也在 local 这个主机组里
ansible "dong:&local" -m ping
# 在 dong 这个组里,但是不在 local 这个组里
# 注意这里使用的是 单引号
ansible 'dong:!local' -m ping
# 以下为示例格式,实际具体逻辑具体判断
ansible 'demo:dong:&dong:!local' -m ping
# 以下为示例说明可以使用正则表达式,具体逻辑具体判断
ansible "~(web|db).*\.magedu\.com" -m ping
/etc/ansible/ansible.cfg
-m ping
ansible
将模块或者命令生成对应的临时 py 文件
,并将该文件传输至远程服务器的对应执行用户 $HOME/.ansible/tmp/ansible-tmp-数字/xxx.PY
文件py文件
,退出示例:
# 我们可以通过 -v 参数观察执行过程
ansible dong -m ping -vvv
# 或者使用 watch tree 观察执行过程,通过 watch tree 可以看到文件内容的变化,但是也不会保存下来
[root@master ~]# cd .ansible/
[root@master .ansible]# ls
cp tmp
[root@master .ansible]# watch tree
Every 2.0s: tree Sun Jul 10 22:06:13 2022
.
├── cp
└── tmp
2 directories, 0 files
ansible-doc是插件文档工具
ansible-doc -h
Usage: ansible-doc [-l|-F|-s] [options] [-t <plugin type> ] [plugin]
Options:
-j, --json #仅用于内部测试,为所有插件转储json元数据
-l, --list #列出ansible内置的所有模块
-F, --list_files #在没有摘要的情况下显示插件名及其源文件(暗示-列表)
-M MODULE_PATH, --module-path=MODULE_PATH #模块路径,默认为 ~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
-s, --snippet #显示指定插件的参数等,用法 ansible-doc -s module_name
-t TYPE, --type=TYPE #选择插件类型,默认为模块
# 查看 ansible 支持的模块,这里就不展开看了,太多了
[root@master ~]# ansible-doc -l | wc -l
3387
# 查看 ansible 模块信息,如果不使用 -s 参数,则显示信息过多
[root@master ~]# ansible-doc -s ping
- name: Try to connect to host, verify a usable python and return `pong' on success
ping:
data: # Data to return for the `ping' return value. If this parameter is set to `crash', the module will
cause an exception.
“Ansible Galaxy” 指的是一个网站共享和下载 Ansible 角色,也可以是帮助 roles(playbook 类似于脚本,roles 就相当于这些脚本的集合) 更好的工作的命令行工具。
此工具会连接 https://galaxy.ansible.com/ 下载相应的
roles
,下载完成之后我们可以直接使用或者修改成更加合适自己的脚本
[root@master ~]# ansible-galaxy install geerlingguy.mysql
- downloading role 'mysql', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-mysql/archive/3.5.0.tar.gz
- extracting geerlingguy.mysql to /root/.ansible/roles/geerlingguy.mysql
- geerlingguy.mysql (3.5.0) was installed successfully
# 查看我们使用 ansible-galaxy 下载过那些内容
[root@master ~]# ansible-galaxy list
# /root/.ansible/roles
- geerlingguy.mysql, 3.5.0
# /usr/share/ansible/roles
# /etc/ansible/roles
# 删除下载内容,或者直接删除文件夹也是一样的
[root@master ~]# ansible-galaxy remove geerlingguy.mysql
- successfully removed geerlingguy.mysql
# 查看下载解压内容
[root@master]#cd /root/.ansible
[root@master .ansible]# tree
.
├── cp
├── galaxy_token
├── roles
│ └── geerlingguy.mysql
│ ├── defaults
│ │ └── main.yml
│ ├── handlers
│ │ └── main.yml
│ ├── LICENSE
│ ├── meta
│ │ └── main.yml
│ ├── molecule
│ │ └── default
│ │ ├── converge.yml
│ │ └── molecule.yml
│ ├── README.md
│ ├── tasks
│ │ ├── configure.yml
│ │ ├── databases.yml
│ │ ├── main.yml
│ │ ├── replication.yml
│ │ ├── secure-installation.yml
│ │ ├── setup-Archlinux.yml
│ │ ├── setup-Debian.yml
│ │ ├── setup-RedHat.yml
│ │ ├── users.yml
│ │ └── variables.yml
│ ├── templates
│ │ ├── my.cnf.j2
│ │ ├── root-my.cnf.j2
│ │ └── user-my.cnf.j2
│ └── vars
│ ├── Archlinux.yml
│ ├── Debian-10.yml
│ ├── Debian-11.yml
│ ├── Debian.yml
│ ├── RedHat-7.yml
│ └── RedHat-8.yml
└── tmp
12 directories, 27 files
ansible 的 playbook 模式主要针对比较具体,且比较大的任务,那就需要提前写好 playbook 剧本
应用场景:
此工具用于执行编辑好的 playbook 任务
简单示例:
[root@master yml]# cat hello.yml
---
# hello world yml file
- hosts: dong
remote_user: root
tasks:
- name: hello world
command: /usr/bin/wall hello world
此工具用于加密解密 yml 文件
格式:
ansible-vault [create|decrypt|edit|encrypt|rekey|view] xxx.yml
示例:
# 加密 hello.yml 文件,加密之后在查看就会是一个加密后的内容
[root@master ~]# ansible-vault encrypt /root/yml/hello.yml
New Vault password:
Confirm New Vault password:
Encryption successful
# 解密,解密之后就可以正常查看文件内容
[root@master ~]# ansible-vault decrypt /root/yml/hello.yml
Vault password:
Decryption successful
# 查看,输入密码之后我们就可以正常查看文件内容
[root@master ~]# ansible-vault view /root/yml/hello.yml
Vault password:
---
# hello world yml file
#
- hosts: dong
remote_user: root
tasks:
- name: hello world
command: /usr/bin/wall hello world
# 编辑加密文件,输入密码之后就可以直接编辑文件内容
[root@master ~]# ansible-vault edit /root/yml/hello.yml
Vault password:
# 修改口令
[root@master ~]# ansible-vault rekey /root/yml/hello.yml
Vault password: # 输入密码验证
New Vault password: # 输入新的密码
Confirm New Vault password: # 再次输入新的密码
Rekey successful
# 创建新文件,输入新文件的密码,就可以创建新的 yml 文件
[root@master ~]# ansible-vault create new.yml
New Vault password:
Confirm New Vault password:
ansible 学习的两个核心内容就是
ansible模块
学习以及playbook
剧本模式编写我们可以使用
ansible-doc -l
列出 ansible 所支持的所有模块
作用:在远程节点上执行一个命令
我们可以使用 ansible-doc -s command
查看该模块支持的参数,command 是默认模块,可忽略 -m 选项。我们也可以修改默认模块,在 /etc/ansible/ansible.cfg
中修改默认参数
# default module name for /usr/bin/ansible
#module_name = command
[root@master ~]# ansible-doc -s command
- name: Execute commands on targets
command:
argv: # Passes the command as a list rather than a string. Use `argv' to avoid quoting values that would
otherwise be interpreted incorrectly (for example "user name"). Only
the string or the list form can be provided, not both. One or the
other must be provided.
chdir: # Change into this directory before running the command.
cmd: # The command to run.
creates: # A filename or (since 2.0) glob pattern. If it already exists, this step *won't* be run.
free_form: # The command module takes a free form command to run. There is no actual parameter named 'free form'.
removes: # A filename or (since 2.0) glob pattern. If it already exists, this step *will* be run.
stdin: # Set the stdin of the command directly to the specified value.
stdin_add_newline: # If set to `yes', append a newline to stdin data.
strip_empty_ends: # Strip empty lines from the end of stdout/stderr in result.
warn: # Enable or disable task warnings.
参数解析:
参数 | 说明 |
---|---|
chdir | 在执行命令之前,通过 cd 进入到该参数指定的目录 |
creates | 在创建一个文件之前,先判断文件是否存在,如果存在则跳过前面的东西,如果不存在则执行前面的动作 |
free_form | 该参数即为输入的 linux 系统命令,实现远程执行和管理 |
removes | 判断一个文件是否存在,如果存在则执行前面的动作,如果不存在则跳过前面的内容(和上面的 creates 是相反的) |
warn | 是否提供告警信息 |
注意:
$name
,也不得使用特殊符号 > < | ; &
等,如果需要使用前面的特殊符号则可以使用 shell
模块来实现案例:
[root@master ~]# ansible dong -m command -a "uptime"
192.168.169.162 | CHANGED | rc=0 >>
12:00:51 up 1:17, 2 users, load average: 0.03, 0.04, 0.05
192.168.169.161 | CHANGED | rc=0 >>
12:00:51 up 1:18, 2 users, load average: 0.20, 0.06, 0.05
[root@master ~]# ansible dong -m command -a "pwd" # 先看下默认工作目录是什么
192.168.169.161 | CHANGED | rc=0 >>
/root
192.168.169.162 | CHANGED | rc=0 >>
/root
[root@master ~]# ansible dong -m command -a "pwd chdir=/tmp"
192.168.169.162 | CHANGED | rc=0 >>
/tmp
192.168.169.161 | CHANGED | rc=0 >>
/tmp
[root@master ~]#
该参数的作用是在创建一个文件之前,先判断文件是否存在,如果存在则跳过前面的东西,如果不存在则执行前面的动作
# 判断 /dong 文件是否存在,存在则不执行前面的 pwd 命令,不存在则执行 pwd 命令
[root@master ~]# ansible 192.168.169.161 -m command -a "pwd creates=/dong"
192.168.169.161 | CHANGED | rc=0 >>
/root
[root@master ~]# ansible 192.168.169.161 -m command -a "pwd creates=/opt"
192.168.169.161 | SUCCESS | rc=0 >> # 返回命令执行成功
skipped, since /opt exists # 提示命令跳过,/opt 目录已经存在
# 使用 cp 命令拷贝文件
[root@master ~]# ansible dong -a "cp /etc/passwd /root creates=/root/passwd"
192.168.169.162 | CHANGED | rc=0 >>
192.168.169.161 | CHANGED | rc=0 >>
判断一个文件是否存在,如果存在则执行前面的动作,如果不存在则跳过前面的内容(和上面的 creates 是相反的)
[root@master ~]# ansible 192.168.169.161 -m command -a "pwd removes=/dong"
192.168.169.161 | SUCCESS | rc=0 >>
skipped, since /dong does not exist
[root@master ~]# ansible 192.168.169.161 -m command -a "pwd removes=/opt"
192.168.169.161 | CHANGED | rc=0 >>
/root
是否提供告警信息
# 没有使用 warn 参数,在使用一些命令时(例如:chmod),系统会提示一些告警信息
[root@master ~]# ansible dong -a "chmod u+x /root/passwd"
[WARNING]: Consider using the file module with mode rather than running 'chmod'. If you need to use command because file is
insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this
message.
192.168.169.161 | CHANGED | rc=0 >>
192.168.169.162 | CHANGED | rc=0 >>
# 使用 warn=false 参数后则没有告警信息显示了
[root@master ~]# ansible dong -a "chmod u+x /root/passwd warn=false"
192.168.169.162 | CHANGED | rc=0 >>
192.168.169.161 | CHANGED | rc=0 >>
官网参考地址:https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html
切换到某个 shell 执行指定的指令,与 command 不同的是,此模块可以支持命令管道,同时还有另一个模块也具备此功能:raw
了解模块用法的渠道:
[root@master ~]# ansible-doc -s shell
- name: Execute shell commands on targets
shell:
chdir: # Change into this directory before running the command.
cmd: # The command to run followed by optional arguments.
creates: # A filename, when it already exists, this step will *not* be run.
executable: # Change the shell used to execute the command. This expects an absolute path to the executable.
free_form: # The shell module takes a free form command to run, as a string. There is no actual parameter named 'free form'. See the examples on how to use this module.
removes: # A filename, when it does not exist, this step will *not* be run.
stdin: # Set the stdin of the command directly to the specified value.
stdin_add_newline: # Whether to append a newline to stdin data.
warn: # Whether to enable task warnings.
参数解析:
参数 | 说明 |
---|---|
chdir | 在执行命令之前,通过 cd 进入到该参数指定的目录 |
creates | 在创建一个文件之前,先判断文件是否存在,如果存在则跳过前面的东西,如果不存在则执行前面的动作 |
free_form | 该参数即为输入的 linux 系统命令,实现远程执行和管理 |
removes | 判断一个文件是否存在,如果存在则执行前面的动作,如果不存在则跳过前面的内容(和上面的 creates 是相反的) |
warn | 是否提供告警信息 |
查看被管理机器上的进程信息
[root@master ~]# ansible dong -m shell -a "ps -ef | grep ssh | grep -v grep"
192.168.169.162 | CHANGED | rc=0 >>
root 900 1 0 10:42 ? 00:00:00 /usr/sbin/sshd -D
root 1014 900 0 10:44 ? 00:00:00 sshd: root@pts/0
root 1021 900 0 10:44 ? 00:00:00 sshd: root@notty
root 1035 1021 0 10:44 ? 00:00:00 /usr/libexec/openssh/sftp-server
root 10856 900 3 14:05 ? 00:00:00 sshd: root@pts/1
192.168.169.161 | CHANGED | rc=0 >>
root 899 1 0 10:42 ? 00:00:00 /usr/sbin/sshd -D
root 1011 899 0 10:45 ? 00:00:00 sshd: root@pts/0
root 1014 899 0 10:45 ? 00:00:00 sshd: root@notty
root 1032 1014 0 10:45 ? 00:00:00 /usr/libexec/openssh/sftp-server
root 11454 899 0 14:05 ? 00:00:00 sshd: root@pts/1
批量远程执行脚本,需要执行的脚本要求必须在客户端存在,否则会报错文件不存在。这个是 shell 模块的特点,是因为还有另外一个专门执行脚本的 script 模块
操作步骤:
1.创建文件夹
2.创建 shell 脚本,写入内容
3.赋予脚本可执行权限
4.执行脚本
5.忽略 warning 信息
以上操作均需要在管理机器上操作,类似这种比较复杂的命令可以使用 playbook 剧本模式去编写
[root@master ~]# ansible dong -m shell -a "mkdir /data;echo 'hostname' > /data/hostname.sh;chmod u+x /data/hostname.sh;sh /data/hostname.sh warn=false creates=/data"
192.168.169.161 | CHANGED | rc=0 >>
node01
192.168.169.162 | CHANGED | rc=0 >>
node02
指定本地的脚本文件,到远程主机运行一次
注意:和 shell 模块的不同,shell 模块是要求客户端上有这个脚本才能执行;script 是要求 ansible 服务端有这个脚本就可以了,执行的时候是不会拷贝这个脚本到客户端的。
[root@master ~]# ansible-doc -s script
- name: Runs a local script on a remote node after transferring it # 运行一个本地的脚本在远程的机器上
script:
chdir: # 此参数的作用就是指定一个远程主机中的目录,在执行对应的脚本之前,会先进入到 chdir 参数指定的目录中
cmd: # Path to the local script to run followed by optional arguments.
creates: # 使用此参数指定一个远程主机中的文件,当指定的文件存在时,就不执行对应脚本,可参考 command 模块中的解释。
decrypt: # This option controls the autodecryption of source files using vault.
executable: # Name or path of a executable to invoke the script with.
free_form: # Path to the local script file followed by optional arguments.
removes: # 使用此参数指定一个远程主机中的文件,当指定的文件不存在时,就不执行对应脚本,可参考 command 模块中的解释。
参数含义和 shell 中类似
free_form= # 必须参数,指定需要执行的脚本,脚本位于 ansible 管理主机本地,并没有具体的一个参数名叫 free_form,具体解释请参考 command 模块。
# 在本地准备一个测试脚本
[root@master ~]# echo -e "pwd\nhostname" > /root/test.sh
[root@master ~]# cat test.sh
pwd
hostname
# 使用 ansible 测试使用本地脚本在远端机器上执行,此时的脚本是不需要在远程机器上存在的
[root@master ~]# ansible dong -m script -a "/root/test.sh"
192.168.169.161 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.169.161 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.169.161 closed."
],
"stdout": "/root\r\nnode01\r\n",
"stdout_lines": [
"/root",
"node01"
]
}
192.168.169.162 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.169.162 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.169.162 closed."
],
"stdout": "/root\r\nnode02\r\n",
"stdout_lines": [
"/root",
"node02"
]
}
[root@master ~]# ansible-doc -s ping
- name: Try to connect to host, verify a usable python and return `pong' on success
ping:
data: # Data to return for the `ping' return value. If this parameter is set to `crash', the module willcause an exception.
[root@master ~]# ansible dong -m ping
192.168.169.161 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.169.162 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
setup 模块用于收集远程主机的一些基本信息。常用参数 filter
,使用 setup
常搜集的信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机较多,会影响执行速度,可以使用 gather_facts: no
来禁止 Ansible 收集 facts 信息
filter=
ansible_all_ipv4_addresses: 仅显示ipv4的信息。
ansible_devices: 仅显示磁盘设备信息。
ansible_distribution: 显示是什么系统,例:centos,suse等。
ansible_distribution_major_version: 显示是系统主版本。
ansible_distribution_version: 仅显示系统版本。
ansible_machine: 显示系统类型,例:32位,还是64位。
ansible_eth0: 仅显示eth0的信息。
ansible_hostname: 仅显示主机名。
ansible_kernel: 仅显示内核版本。
ansible_lvm: 显示lvm相关信息。
ansible_memtotal_mb: 显示系统总内存。
ansible_memfree_mb: 显示可用系统内存。
ansible_memory_mb: 详细显示内存情况。
ansible_swaptotal_mb: 显示总的swap内存。
ansible_swapfree_mb: 显示swap内存的可用内存。
ansible_mounts: 显示系统磁盘挂载情况。
ansible_processor: 显示cpu个数(具体显示每个cpu的型号)。
ansible_processor_vcpus: 显示cpu个数(只显示总的个数)。
ansible 192.168.169.161 -m setup
192.168.169.161 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.169.161"
],
"ansible_all_ipv6_addresses": [
"fe80::7d00:28cc:f94f:a06a",
"fe80::ad67:cf07:7fc:c440"
],
"ansible_apparmor": {
"status": "disabled"
},
........
[root@master ~]# ansible dong -m setup --tree /root/masterInfo
[root@master ~]# cd masterInfo/
[root@master masterInfo]# ls
192.168.169.161 192.168.169.162
或者直接使用
[root@master ~]# ansible dong -m setup > /root/masterInfo.txt
[root@master ~]# ansible 192.168.169.161 -m setup -a "filter=ansible_*_mb"
192.168.169.161 | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 694,
"ansible_memory_mb": {
"nocache": {
"free": 801,
"used": 175
},
"real": {
"free": 694,
"total": 976,
"used": 282
},
"swap": {
"cached": 0,
"free": 1023,
"total": 1023,
"used": 0
}
},
"ansible_memtotal_mb": 976,
"ansible_swapfree_mb": 1023,
"ansible_swaptotal_mb": 1023,
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
[root@master ~]# ansible dong -m setup -a "filter=ansible_kernel"
192.168.169.162 | SUCCESS => {
"ansible_facts": {
"ansible_kernel": "3.10.0-693.el7.x86_64",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
192.168.169.161 | SUCCESS => {
"ansible_facts": {
"ansible_kernel": "3.10.0-693.el7.x86_64",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
[root@master ~]# ansible 192.168.169.161 -m setup -a 'filter=ansible_ens*'
192.168.169.161 | SUCCESS => {
"ansible_facts": {
"ansible_ens33": {
"active": true,
"device": "ens33",
"features": {
"busy_poll": "off [fixed]",
"fcoe_mtu": "off [fixed]",
"generic_receive_offload": "on",
"generic_segmentation_offload": "on",
"highdma": "off [fixed]",
"hw_tc_offload": "off [fixed]",
"l2_fwd_offload": "off [fixed]",
"large_receive_offload": "off [fixed]",
"loopback": "off [fixed]",
"netns_local": "off [fixed]",
"ntuple_filters": "off [fixed]",
"receive_hashing": "off [fixed]",
"rx_all": "off",
"rx_checksumming": "off",
"rx_fcs": "off",
"rx_vlan_filter": "on [fixed]",
"rx_vlan_offload": "on",
"rx_vlan_stag_filter": "off [fixed]",
"rx_vlan_stag_hw_parse": "off [fixed]",
"scatter_gather": "on",
"tcp_segmentation_offload": "on",
"tx_checksum_fcoe_crc": "off [fixed]",
"tx_checksum_ip_generic": "on",
"tx_checksum_ipv4": "off [fixed]",
"tx_checksum_ipv6": "off [fixed]",
"tx_checksum_sctp": "off [fixed]",
"tx_checksumming": "on",
"tx_fcoe_segmentation": "off [fixed]",
"tx_gre_csum_segmentation": "off [fixed]",
"tx_gre_segmentation": "off [fixed]",
"tx_gso_partial": "off [fixed]",
"tx_gso_robust": "off [fixed]",
"tx_ipip_segmentation": "off [fixed]",
"tx_lockless": "off [fixed]",
"tx_mpls_segmentation": "off [fixed]",
"tx_nocache_copy": "off",
"tx_scatter_gather": "on",
"tx_scatter_gather_fraglist": "off [fixed]",
"tx_sctp_segmentation": "off [fixed]",
"tx_sit_segmentation": "off [fixed]",
"tx_tcp6_segmentation": "off [fixed]",
"tx_tcp_ecn_segmentation": "off [fixed]",
"tx_tcp_mangleid_segmentation": "off",
"tx_tcp_segmentation": "on",
"tx_udp_tnl_csum_segmentation": "off [fixed]",
"tx_udp_tnl_segmentation": "off [fixed]",
"tx_vlan_offload": "on [fixed]",
"tx_vlan_stag_hw_insert": "off [fixed]",
"udp_fragmentation_offload": "off [fixed]",
"vlan_challenged": "off [fixed]"
},
"hw_timestamp_filters": [],
"ipv4": {
"address": "192.168.169.161",
"broadcast": "192.168.169.255",
"netmask": "255.255.255.0",
"network": "192.168.169.0"
},
"ipv6": [
{
"address": "fe80::7d00:28cc:f94f:a06a",
"prefix": "64",
"scope": "link"
},
{
"address": "fe80::ad67:cf07:7fc:c440",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "00:0c:29:6d:e4:70",
"module": "e1000",
"mtu": 1500,
"pciid": "0000:02:01.0",
"promisc": false,
"speed": 1000,
"timestamping": [
"tx_software",
"rx_software",
"software"
],
"type": "ether"
},
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
主要用于将管理主机上的数据信息拷贝给多台主机
官方文档:https://docs.ansible.com/ansible/latest/modules/copy_module.html#copy-module
参数 | 选项默认值 | 说明 |
---|---|---|
src | 指定将本地管理主机的数据信息进行远程复制 | |
backup | no* yes | 默认数据复制到远程主机,会覆盖原有文件(yes 将源文件进行备份) |
content | 在文件中添加信息 | |
dest(required) | 将数据复制到远程节点的路径信息 | |
group | 文件数据复制到远程主机,设置文件属组用户信息 | |
mode | 文件数据复制到远程主机,设置数据的权限 eg 0644 0755 | |
owner | 文件数据复制到远程主机,设置文件属主用户信息 | |
remote_src | no* yes | 如果设置为yes,表示将远程主机上的数据进行移动操作。如果设置为no, 表示将管理主机上的数据进行分发操作 |
注:(required)为必须使用的参数为默认参数,copy模块在复制数据时,如果数据为软链接文件,会将链接指定源文件进行复制
修改权限时候 需要加0 例如:chmod 0644 0755
示例:
owner
)、权限(mode
),将原本目录下存在的同名文件备份(backup
),如果文件内容相同则不会备份[root@master ~]# ansible dong -m copy -a "src=/root/test.txt dest=/root owner=dong group=dong mode=600 backup=yes"
参数解析:
src=/root/test.txt 本地文件路径
dest=/root 远程服务器文件路径
owner=dong 用户
group=dong 用户组
mode=600 设置权限
backup=yes 是否备份(yes是备份,no是不备份,同名文件,内容不同则备份)
ansible dong -m copy -a "content='test line1\ntest lin2' dest=/root/123.txt"
参数解析:
content 添加文件内容,将内容写入远程机器文件
dest 定义远程服务器文件路径
从远程主机提取文件到 ansible 的主控端,和 copy 相反,但是目前不支持目录传输(命令帮助里面解释以后可能会支持)
官方文档:https://docs.ansible.com/ansible/latest/modules/fetch_module.html#fetch-module
参数 | 说明 |
---|---|
src (required) | 远程机器上的文件路径,注意是文件,不可以是目录 |
dest | 本地用于保存文件的路径 |
示例:
[root@master ~]# ansible dong -m fetch -a "src=/root/test.txt dest=/root"
功能:实现创建、删除信息。对数据权限进行修改
官方文档:https://docs.ansible.com/ansible/latest/modules/file_module.html#file-module
参数 | 选项/默认值 | 说明 |
---|---|---|
path/dest/name(required) | **path参数 :**必须参数,用于指定要操作的文件或目录,在之前版本的ansible中,使用dest参数或者name参数指定要操作的文件或目录,为了兼容之前的版本,使用dest或name也可以。 | |
group | 文件数据复制到远程主机,设置文件属组用户信息 | |
mode | 文件数据复制到远程主机,设置数据的权限 eg 0644 0755(或者 ‘644’ ‘755’) | |
owner | 文件数据复制到远程主机,设置文件属主用户信息 | |
src | 当state设置为link或者hard时,表示我们想要创建一个软链或者硬链,所以,我们必须指明软链或硬链链接的哪个文件,通过src参数即可指定链接源。 | |
force | force参数 : 当state=link的时候,可配合此参数强制创建链接文件,当force=yes时,表示强制创建链接文件。不过强制创建链接文件分为三种情况。 情况一:当要创建的链接文件指向的源文件并不存在时,使用此参数,可以先强制创建出链接文件。 情况二:当要创建链接文件的目录中已经存在与链接文件同名的文件时,将force设置为yes,会将同名文件覆盖为链接文件,相当于删除同名文件,创建链接文件。 情况三:当要创建链接文件的目录中已经存在与链接文件同名的文件,并且链接文件指向的源文件也不存在,这时会强制替换同名文件为链接文件。 |
|
recurse | yes | 当要操作的文件为目录,将 recurse 设置为 yes ,可以递归的修改目录中文件的属性。 |
state | state参数 :此参数非常灵活,其对应的值需要根据情况设定。比如,我们想要在远程主机上创建/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”为缺席之意,当我们想让操作的目标”缺席”时,就表示我们想要删除目标。 | |
state= | absent | 如果是absent 那么目录将会被递归删除,如果是文件和软连接将会被取消 |
state= | directory | 创建一个空目录信息 |
state= | file | 查看指定目录信息是否存在 |
state= | touch | 创建一个空文件信息 |
state= | hard/link | 创建链接文件 |
示例:
state=directory
在远程主机上创建一个名为 data 的目录,如果存在则不会做操作。[root@master ~]# ansible dong -m file -a "path=/root/data state=directory"
state=touch
在远程主机上创建一个名为 testfile1 的文件,如果 testfile1 文件已经存在并且文件内有内容,则只会更新文件的时间戳,与 touch 命令的作用相同。[root@master ~]# ansible dong -m file -a "path=/root/data/testfile1 state=touch"
state=link
在远程主机上为 testfile1 文件创建软链接文件,软链接名为 linkfile1。[root@master ~]# ansible dong -m file -a "path=/root/data/linkfile1 state=link src=/root/data/testfile1"
state=hard
在远程主机上上为 testfile1 文件创建硬链接文件,硬链接名为 hardfile2(类似于复制)。[root@master ~]# ansible dong -m file -a "path=/root/data/linkfile2 state=hard src=/root/data/testfile1"
[root@master ~]# ansible dong -m file -a "path=/root/data/linkfile3 state=link src=/root/data/123 force=yes"
[WARNING]: Cannot set fs attributes on a non-existent symlink target. follow should be set to False to avoid this.
192.168.169.161 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/root/data/linkfile3",
"src": "/root/data/123"
}
192.168.169.162 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/root/data/linkfile3",
"src": "/root/data/123"
}
state=absent
删除远程机器上的指定文件或目录。[root@master ~]# ansible dong -m file -a "path=/root/data state=absent"
owner
在创建文件或目录的时候指定属主,或者修改远程主机上的文件或目录的属主。[root@master ~]# ansible dong -m file -a "path=/root/testfile state=touch owner=dong"
# 修改文件或目录所属用户
[root@master ~]# ansible dong -m file -a "path=/root/testfile owner=demo"
# 新建一个目录并设置用户和组
[root@master ~]# ansible dong -m file -a "path=/root/data state=directory owner=dong group=dong"
mode
在创建文件或目录的时候指定权限,或者修改远程主机上的文件或目录的权限[root@master ~]# ansible dong -m file -a "path=/root/testfile1 state=touch mode=755"
# 修改文件权限
[root@master ~]# ansible dong -m file -a "path=/root/testfile1 mode=600"
[root@master ~]# ansible dong -m file -a "path=/data/test/demo state=directory owner=dong group=dong recurse=yes"
功能:解包解压缩
有两种实现方法:
主要差异为压缩包所在位置不同,一个是在 ansible 主控端上,一个是在远程主机上
ansible
主机上的压缩包传到远程主机后解压缩至特定目录,使用 copy=yes
参数copy=no
参数常见参数:
参数 | 说明 |
---|---|
creates | 在创建一个文件之前,先判断文件是否存在,如果存在则跳过前面的东西,如果不存在则执行前面的动作 |
copy | 默认为 copy=yes ,拷贝的文件从 ansible 主机复制到远程主机,copy=no 表示在远程主机上寻找src源文件解压 |
src | tar 源路径,可以是 ansible 主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需设置 copy=no |
dest | 远程主机上的目标绝对路径 |
mode | 设置解压缩后的文件权限 |
exec | 列出需要排除的目录和文件 |
remote_src | 和 copy 功能一样且互斥,设置 remote_src=yes 表示文件在远程主机上,设置为 remote_src=no 表示文件在 ansible 主机上 。对于Windows目标,改用win_unzip模块。 |
owner | 解压后文件或目录的属主 |
group | 解压后的目录或文件的属组 |
示例:
[root@master ~]# ansible dong -m unarchive -a "src=/root/yml.tar.gz dest=/root owner=dong group=dong"
或者
[root@master ~]# ansible dong -m unarchive -a "src=/root/yml.tar.gz dest=/root owner=dong group=dong remote_src=no"
copy=no
)[root@master ~]# ansible dong -m unarchive -a "src=/root/yml.tar.gz dest=/root copy=no"
或者
[root@master ~]# ansible dong -m unarchive -a "src=/root/yml.tar.gz dest=/ remote_src=yes"
功能:打包压缩
常用参数:
参数 | 说明 |
---|---|
path | required(必须)远程主机上需要被打包/压缩的源文件(可以是文件列表,支持glob模式) |
dest | 打包/压缩后的包文件路径(包文件的父目录必须存在);如果包文件已存在,则会被覆盖。 |
format | 指定压缩类型,包括:bz2、gz(默认)、tar、xz、zip |
owner | 指定属主 |
group | 指定属组 |
mode | 指定权限 |
remove | yes |
示例:
tar.gz
格式[root@master ~]# ansible dong -m archive -a "path=/root/yml/ dest=/root/yml.tar.gz format=zip"
功能:管理主机名
示例:
[root@master ~]# ansible 192.168.169.161 -m hostname -a "name=demo"
功能:用来管理 crontab
的,包括添加、删除、更新操作系统的 crontab
任务计划
常用参数:
参数 | 说明 |
---|---|
name | 计划任务名称 |
job | 指定计划的任务中需要实际执行的命令或者脚本 |
user | 指定计划任务属于哪个用户,默认是root用户 |
state | 指定状态,prsent 表示添加定时任务,也是默认设置,absent 表示删除定时任务 |
backup | 对已有的任务修改或删除时,是否保存 |
disabled | 当计划任务有名称时,根据计划任务名称关闭(注释)对应的计划任务 |
minute | 分钟,取值范围(0-59,*, */2) |
hour | 小时,取值范围(0-23,,/2) |
day | 天,取值范围(1-31,,/2) |
mouth | 月,取值范围(1-12,,/2) |
weekday | 设置计划任务中周几设定位的值,取值范围(0-6 for Sunday-Saturday, *) |
cron_file | 如果指定, 使用这个文件cron.d,而不是单个用户crontab |
示例:
[root@master ~]# ansible dong -m cron -a "name='ntpdate' minute=5 hour=1 job='ntpdate ntp.aliyun.com'"
[root@master ~]# ansible dong -m shell -a "crontab -l"
disabled=yes
关闭之前创建的任务[root@master ~]# ansible dong -m cron -a "name='ntpdate' minute=5 hour=1 job='ntpdate ntp.aliyun.com' disabled=yes"
建议:删除和关闭计划任务的时候,把backup=yes一起加上,即使操作错了还有备份
[root@master ~]# ansible dong -m cron -a "name='ntpdate' minute=5 hour=1 job='ntpdate ntp.aliyun.com' state=absent backup=yes"
192.168.169.162 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"backup_file": "/tmp/crontabh5DeZQ", # 备份文件路径
"changed": true,
"envs": [],
"jobs": []
}
192.168.169.161 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"backup_file": "/tmp/crontabP7HnJE", # 备份文件路径
"changed": true,
"envs": [],
"jobs": []
}
[root@master ~]# ansible 192.168.169.162 -m shell -a "cat /tmp/crontabh5DeZQ"
192.168.169.162 | CHANGED | rc=0 >>
#Ansible: ntpdate
#5 1 * * * ntpdate ntp.aliyun.com
disabled=no
启用定时任务[root@master ~]# ansible dong -m cron -a "name='ntpdate' minute=5 hour=1 job='ntpdate ntp.aliyun.com' disabled=no"
功能:使用yum软件包管理器安装,升级,降级,删除和列出软件包和组。
官方文档:https://docs.ansible.com/ansible/latest/modules/yum_repository_module.html#yum-repository-module
常用参数:
参数 | 参数选项 | 说明 |
---|---|---|
conf_file | 指定远程主机yum源位置 | |
name | 指定要安装的包,如果有多个版本需要指定版本,否则安装最新的包 | |
disable_gpg_check | 关闭gpg_check | |
disablerepo | 禁用某个yum源 | |
enablerepo | 启用某个yum仓库 | |
state | 安装状态 | |
state= | latest | 如果安装的软件存在则进行更新,如果不存在则安装最新版 |
state= | present | 如果安装的软件存在则不进行安装,如果不存在则安装 |
state= | install | 正常安装 |
state= | absent | 删除软件包 |
state= | removed | 卸载软件包 |
示例:
[root@master ~]# ansible dong -m yum -a "name=httpd state=present"
[root@master ~]# ansible dong -m yum -a "name=httpd state=removed"
[root@master ~]# ansible dong -m yum -a "name=httpd state=absent"
功能:系统服务管理
官方文档:https://docs.ansible.com/ansible/latest/modules/service_module.html#service-module
常用参数:
参数 | 选项/默认值 | 说明 |
---|---|---|
name(required) | 设置启停服务名称 | |
enabled | yes/no | 设置服务是否开机自启动 如果参数不指定,原有服务开机自启动状态进行保留 |
sleep | 如果执行了restarted,则在stop和start之间沉睡几秒钟 | |
state | 需要对当前服务执行的动作 | |
state= | reloaded | 平滑重启 |
state= | restarted | 重启 |
state= | started | 启动 |
state= | stopped | 停止 |
示例:
[root@master ~]# ansible dong -m service -a "name=httpd state=started"
[root@master ~]# ansible dong -m shell -a "systemctl status httpd"
功能:系统用户管理
官方文档:https://docs.ansible.com/ansible/latest/modules/user_module.html#user-module
常用参数:
参数 | 选项/默认值 | 说明 |
---|---|---|
password | 输入密码信息(password设置密码时不能使用明文方式,只能使用密文方式,可以给用户设置密码 还可以给用户修改密码) | |
name | 指定用户名 | |
system | yes/no | 创建一个用户并设置这个用户为系统用户,这个设置不能更改现在的用户 |
uid | 指定用户 uid 信息 | |
group | 指定用户所属组 | |
groups | 指定用户所属附加组 | |
shell | /bin/bash或/sbin/nologin | 指定用户是否可以登陆 |
create_home | yes/no | 是否创建家目录 |
move_home | yes/no | 假如此用户已经存在,yes为覆盖家目录,no为创建为此用户创建另外一个家目录,两个家目录通过uid区分 |
home | 指定家目录创建在什么路径 默认/home | |
state | 指定用户状态 | |
state= | present | present 为创建 |
state= | absent | absent 为删除 |
remove | yes/no | remove=yes 则表示在删除(state=absent)用户时同时删除用户家目录,remove=no 则表示不删除 |
generate_ssh_key=yes | 创建用户的同时是否为此用户创建ssh密钥文件 |
password 密码加密方式:
参考官网地址:https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#how-do-i-generate-encrypted-passwords-for-the-user-module
# 安装 python 工具
[root@master ~]# yum -y install python-pip
[root@master ~]# pip install --upgrade pip
[root@master ~]# pip install passlib
[root@master ~]# python -c "from passlib.hash import sha512_crypt; import getpass; print(sha512_crypt.using(rounds=5000).hash(getpass.getpass()))"
Password:
$6$i36wkjavj/M/K/2T$EUFdeExIDsZgCzWH3ckYNKoau0BFr3FZ.8g9tjq/A8unFThrpS1iBJ0Ou3ikjl0KgozKA12GDGqdLH06bCIPR/
注意:这里的 $ 符在使用时需要使用 \$ 转义
示例:
[root@master ~]# ansible dong -m user -a "name=123 password=\$6\$i36wkjavj/M/K/2T\$EUFdeExIDsZgCzWH3ckYNKoau0BFr3FZ.8g9tjq/A8unFThrpS1iBJ0Ou3ikjl0KgozKA12GDGqdLH06bCIPR/ create_home=yes home=/data shell=/sbin/nologin"
[root@master ~]# ansible dong -m user -a "name=123 state=absent remove=yes"
功能:系统用户组管理
官方文档:https://docs.ansible.com/ansible/latest/modules/group_module.html#group-module
常用参数:
参数 | 选项/默认值 | 说明 |
---|---|---|
gid | 指创建的组ID信息 | |
name | 指创建组名称信息 | |
system | yes/no | system=yes 则表示创建系统组 |
state | 指定组状态 | |
state= | present(默认) | 创建指定的用户组 |
state= | absent | 删除指定的用户组 |
示例:
[root@master ~]# ansible dong -m group -a "gid=1022 name=123"
# 查看创建结果
[root@master ~]# ansible dong -m shell -a "cat /etc/group | grep 123"
192.168.169.161 | CHANGED | rc=0 >>
123:x:1022:
192.168.169.162 | CHANGED | rc=0 >>
123:x:1022:
[root@master ~]# ansible dong -m group -a "name=123 state=absent"
ansible
在使用sed
进行替换时,经常会遇到需要转义的问题,而且ansible
在遇到特殊符号进行替换时,存在问题,无法正常进行替换 。其实在ansible
自身提供了两个模块:ineinfile
模块和replace
模块,可以方便的进行替换功能:相当于
sed
,可以修改文件内容官网地址:https://docs.ansible.com/ansible/latest/collections/ansible/builtin/lineinfile_module.html
常用参数:
参数 | 选项/默认值 | 说明 |
---|---|---|
path/dest | 目标文件绝对路径+文件名,必须参数 | |
line | 替换/插入的内容 | |
regexp | 待匹配内容 | |
insertbefore | 匹配行前面插入 | |
insertafter | 匹配行面插入 | |
state | present / absent | 删除匹配行,需要将值设为 absent , 默认值 present |
backup | yes / no | 是否在修改文件之前对文件进行备份。 yes/no |
create | yes / no | 当要操作的文件并不存在时,是否创建对应的文件。yes/no |
backrefs | 常和正则表达一起使用,如果正则表达不匹配,不做任何改变,如果匹配则替换匹配的内容 | |
backrefs= | no | backrefs 为 no 时,如果没有匹配,则添加一行line。如果匹配了,则把匹配内容替被换为line内容 |
backrefs= | yes | backrefs 为 yes 时,如果没有匹配,则文件保持不变。如果匹配了,把匹配内容替被换为line内容。 |
示例:
[root@master ~]# ansible dong -m lineinfile -a "dest=/root/test state=absent regexp='^#'"
这里有个疑问?如果匹配格式为 “aaa.bbb.ccc” 我想要匹配 “aaa” 并修改,要怎么操作?参考下面的
replace
模块
[root@master ~]# ansible dong -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=disabled'"
该模块有点类似于sed命令,主要也是基于正则进行匹配和替换
常用参数:
参数 | 说明 |
---|---|
path | 必须参数,指定要修改的文件,2.3版本之前,这个参数叫dest、destfile、name;现在这三个名称是path参数的别名 |
regexp | 必须参数,指定一个正则表达式,可以是python正则 |
replace | 替换regexp参数匹配到的字符串, |
owner | 结果文件或目录的所属用户名,相当于chown命令修改 |
group | 结果文件或目录的所属组名,相当于chown命令修改 |
mode | 结果文件或目录的权限,与chmod命令不一致的是,replace模块的mode参数需要添加前导零,以便ansible的YAML解析器知道它是八进制;1.8版本后可以设置为符号模式(u+rwx或u=rw),2.6版本后可以是特殊字符串(preserve),当设置为’preserve’时,文件将被赋予与源文件相同的权限。 |
others | 可以指定 file 模块的所有参数 |
encoding | 用于读取和写入文件的字符编码 |
before | 如果指定,则仅替换/删除此匹配之前的内容,可以和after参数结合使用 |
after | 如果指定,则仅替换/删除此匹配之后的内容,可以和before参数结合使用 |
attributes | 结果文件或目录的特殊属性,相当chattr,默认使用=运算符,指定文件或目录的某项属性 |
backup | 修改源文件前创建一个包含时间戳信息的备份文件 |
示例:
# 文件内容为 aaa.bbb.fff.vvv.fff.ggg 匹配 fff 并修改为 qqq
[root@master ~]# ansible dong -m replace -a "path=/root/test regexp='fff' replace='qqq'"
# 匹配到任意一个或多个开头的行增加注释
[root@master ~]# ansible dong -m replace -a "path=/root/passwd regexp='^(.*)' replace='#\1'"
# 取消注释
[root@master ~]# ansible dong -m replace -a "path=/root/passwd regexp='^#(.*)' replace='\1'"
# 匹配以 p 开头的后面有一个或者多个字符的行,并在前面添加 # 注释
[root@master ~]# ansible dong -m replace -a "path=/root/passwd regexp='^(p.*)' replace='#\1'"
playbook 实际上就是一个文本文件,它是由 yuml 语言实现的。它里面定义了各种模块的调用,并且规定了执行的先后顺序,按照一定的次序来调用,
playbook 剧本是由一个或多个“play”组成的列表
play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作
Playbook 文件是采用YAML语言编写的
YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。Clark Evans在2001年在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者,目前很多软件中采有此格式的文件,如:ubuntu,anisble,docker,k8s等
YAML:YAML Ain’t Markup Language,即YAML不是XML。不过,在开发的这种语言时,YAML的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)
YAML 官方网站:http://www.yaml.org
- YAML的可读性好
- YAML和脚本语言的交互性好
- YAML使用实现语言的数据类型
- YAML有一个一致的信息模型
- YAML易于实现
- YAML可以基于流来处理
- YAML表达能力强,扩展性好
- 在单一文件第一行,用连续三个连字号“-” 开始,还有选择性的连续三个点号( … )用来表示文件的结尾
- 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
- 使用#号注释代码
- 缩进必须是统一的,不能空格和tab混用
- 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的,YAML文件内容是区别大小写的,key/value的值均需大小写敏感
- 多个key/value可同行写也可换行写,同行使用 ,(逗号)分隔
- v 可是个字符串,也可是另一个列表
- 一个完整的代码块功能需最少元素需包括 name 和 task
- 一个name只能包括一个task,一个 task 对应一个模块
- YAML文件扩展名通常为yml或yaml
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-“来代表,Map里的键值对用”:"分隔,下面介绍两种常见的数据结构。
列表由多个元素组成,每个元素放在不同行,且元素前均使用“-”打头,或者将所有元素用 [ ] 括起来放在同一行
范例:
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango
或者放在一个 [ ] 里
[Apple,Orange,Strawberry,Mango]
字典由多个key与value构成,key和value之间用 :分隔,所有k/v可以放在一行,或者每个 k/v 分别放在不同行
范例:
# An employee record
name: Example Developer
job: Developer
skill: Elite
也可以将key:value放置于{}中进行表示,用,分隔多个key:value
# An employee record
{name: “Example Developer”, job: “Developer”, skill: “Elite”}
范例:
name: John Smith
age: 41
gender: Male
spouse:
name: Jane Smith
age: 37
gender: Female
children:
- name: Jimmy Smith
age: 17
gender: Male
- name: Jenny Smith
age 13
gender: Female
可以用工具互相转换,参考网站:
https://www.json2yaml.com/
http://www.bejson.com/json/json2yaml/
参数 | 说明 |
---|---|
Hosts | 执行的远程主机列表(应用在哪些主机上) |
Tasks | 任务集,具体要调用的模块 |
Variables | 内置变量或自定义变量在playbook中调用 |
Handlers / notify | Handlers和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行 |
tags | 指定某条任务执行,用于选择运行playbook中的部分代码。 ansible具有幂等性,因此会自动跳过没有变化的部分, 即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。 此时,如果确信其没有变化,就可以通过tags跳过此些代码片断 ansible-playbook -t tagsname useradd.yml |
Templates | 模板可替换模板文件中的变量并实现一些简单逻辑的文件 |
Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中。
Websrvs:dbsrvs #或者,两个组的并集
Websrvs:&dbsrvs #与,两个组的交集
webservers:!phoenix #在websrvs组,但不在dbsrvs组
案例:
# 属于 webservers 或者 appservs
- hosts: websrvs:appsrvs
remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: websrvs
remote_user: root # 指定使用远程主机的 root 来执行,不写也可以,默认就是root
tasks:
- name: test connection
ping:
remote_user: magedu
sudo: yes #默认sudo为root
sudo_user:wang #sudo为wang,不过不常用
play的主体部分是 task list,task list 中有一个或多个 task ,各个 task 按次序逐个在 hosts 中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个 task
task 的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致
每个 task 都应该有其 name,用于 playbook 的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供 name,则 action 的结果将用于输出
task两种格式:
(1) action: module arguments
(2) module: arguments 建议使用
注意:shell 和 command 模块后面跟命令,而非 key=value
示例:
---
- hosts: dong
remote_user: root
tasks:
- name: install httpd # name 就是一些描述信息
yum: name=httpd # 调用 yum 模块安装 httpd 服务
-name: start httpd
service: name=httpd state=started enabled=yes # 调用 service 模块启动 httpd 并设置为开机自启
# SHELL脚本实现
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp /tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl enable --now httpd
# playbook 实现
---
- hosts: dong
remote_user: root
tasks:
- name: "安装 Apache"
yum: name=httpd
- name: "复制配置文件"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf # 这里的 copy 是指将 ansible 机器上的文件复制到远程主机上
- name: "启动 Apache 并设置开机启动"
service: name=httpd state=started enabled=yes
格式:
ansible-playbook <filename.yml> .. [options]
常见选项:
参数 | 说明 |
---|---|
-C --check | 只检测可能发生的改变,但不真正执行操作 |
–list-hosts | 列出运行任务的主机 |
–list-tags | 列出 tag |
–list-tasks | 列出 task |
–limit 主机列表 | 假如在 playbook 中写的是全部主机,这时只想执行一部分特定的主机,就可以使用 --limit 后面加上想要执行的主机列表 |
-v -vv -vvv | 显示过程,一级比一级详细 |
示例:
ansible-playbook file.yml # 直接 执行
ansible-playbook file.yml --check # 只做检测
ansible-playbook file.yml --limit dong # 只执行 dong 这个分组里的主机
---
# create mysql user and group
- hosts: dbserver
remote_user: root
gather_facts: no # 在执行的时候不去使用 setup 手机主机信息,提高速度
tasks:
- {name: create group, group: name=mysql system=yes gid=306} # 这是一种编写格式,可以卸载一行里,不常用
- name: create user
user: name=mysql system=yes uid=306 create_home=no home=/home/mysql group=mysql shell=/sbin/nologin
# 检查 yml 文件是否有语法错误
[root@master ansible]# ansible-playbook create_mysql.yml -C
# 执行 yml 文件
[root@master ansible]# ansible-playbook create_mysql.yml
# 查看是否创建成功
[root@master ansible]# ansible dbserver -m shell -a "getent passwd mysql"
192.168.169.162 | CHANGED | rc=0 >>
mysql:x:306:306::/home/mysql:/sbin/nologin
192.168.169.161 | CHANGED | rc=0 >>
mysql:x:306:306::/home/mysql:/sbin/nologin
---
- hosts: dbserver
gather_facts: no
remote_user: root
tasks:
- name: rpm nginx
shell: rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
- name: create group nginx
group: name=nginx
- name: create name nginx
user: name=nginx
- name: install nginx
yum: name=nginx state=present
- name: start nginx
service: state=started enabled=yes name=nginx
# 查看启动端口
[root@master ansible]# ansible dbserver -m shell -a "netstat -lnatp | grep 80"
# 卸载 nginx
---
- hosts: dbserver
gather_facts: no
remote_user: root
tasks:
- name: stop nginx
service: state=stopped name=nginx
- name: remove group nginx
group: name=nginx state=absent
- name: create name nginx
user: name=nginx state=absent
- name: install nginx
yum: name=nginx state=absent
# 在一台指定主机上执行
[root@master ansible]# ansible-playbook removeNginx.yml --limit=192.168.169.161
下面的 yml
文件中仍有一些问题,但是总体可以使用
---
- hosts: dbserver
remote_user: root
gather_facts: no
tasks:
- name: uninsert mariadb # 问题1:如果没有找到 mariadb 这个安装信息,会报错
shell: rpm -e --nodeps $(rpm -qa | grep mariadb)
- name: install packages
yum: name=libaio
- name: create group mysql
group: name=mysql gid=306
- name: create user mysql
user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes
- name: copy tar to remote host and file mode
unarchive: src=/root/mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/ owner=root group=root
- name: create linkfile /usr/local/mysql
file: src=/usr/local/mysql-5.7.38-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
- name: mysql path
shell: echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profile;source /etc/profile
- name: mkdir file
file: path=/usr/local/mysql/mysql_file owner=mysql group=mysql mode=0755 state=directory
- name: init mysql
shell: /usr/local/mysql/bin/mysqld --initialize-insecure --user=mysql --datadir=/usr/local/mysql/data --basedir=/usr/local/mysql --log_error=/usr/local/mysql/mysql-file/mysql.log
- name: copy mysql.server to /etc/init.d
copy: src=/usr/local/mysql/support-files/mysql.server dest=/etc/init.d/mysql remote_src=yes
- name: copy my.cnf
copy: src=/root/my.cnf dest=/etc
- name: start mysql
service: name=mysql state=started
- name: change password # 问题2:这里会提示找不到 mysqladmin 这个命令,不知道是为什么
shell: mysqladmin -uroot password Abcd@1234
---
- hosts: dbserver
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum: name=httpd state=persent
- name: copy configure file
copy: src=/root/httpd.conf dest=/etc/httpd/conf # 将配置文件从本地拷贝到远程
notify: restart httpd
tags: conf
- name: ensure apache is running
tags: service
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state:restarted
notify
触发标识,含有notify的任务需要触发处理程序才能彻底完成。
handlers
处理程序的标识,被notify调用的处理程序的执行位置。往往放在所有任务之后执行。
使用过程中,notify和handlers是通过名称匹配,所以要求notify和handlers任务名称,必须相同,才可调用。
处理程序的使用
1、处理程序始终按照play的handlers部分指定的顺序运行,与notify中的顺序无关;
2、处理程序通常在相关play中所有其他任务运行完后运行 ;
3、处理程序名称存在于个play命名空间中(如果两个处理程序同名,只会运行一个);
4、如果多个任务通知(notify)处理程序,处理程序也只会运行一次 ;
5、如果包含notify的语句任务没有报告changed结果,则处理程序不会获得通知。
示例:
---
- hosts: dbserver
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum: name=httpd state=persent
- name: copy configure file
copy: src=/root/httpd.conf dest=/etc/httpd/conf # 文件发生变化,就会触发 notify,然后调用 handlers
notify: restart httpd # 注意名称要完全相同,且在一个 yml 文件中要唯一
- name: ensure apache is running
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted
也可以有多个指令
---
- name: template
hosts: webservera
tasks:
- name: copy file
template:
src: files/example.conf
dest: /etc/httpd/conf.d/example.conf
notify: # 多个通知名称
- restart apache
- restart mysql
handlers: # 处理程序任务
- name: restart apache # 名称必须匹配
service:
name: httpd
state: restarted
- name: restart mysql # 名称必须匹配
service:
name: mariadb
state: restarted
在 playbook
文件中,可以利用 tags
组件,为特定的 task
指定标签,当在执行 playbook
时,可以只执行特定的 tags
的 task
,而非整个 playbook
文件
示例:
---
- hosts: dbserver
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum: name=httpd state=persent
- name: copy configure file
copy: src=/root/httpd.conf dest=/etc/httpd/conf
notify: restart httpd
tags: conf
- name: ensure apache is running
tags: service
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state:restarted
# 检查端口是否运行
[root@master ansible]# ansible dbserver -m shell -a "ss -lnt"
# 可以使用 --list-tags 参数查看有哪些 tags
[root@master ansible]# ansible-playbook --list-tags installHttpd.yml
playbook: installHttpd.yml
play #1 (dbserver): dbserver TAGS: []
TASK TAGS: [conf, service]
# 使用 -t 参数指定运行 yml 文件中的 tags 标签定义的内容,这里是修改 httpd 端口后再次将文件拷贝过去,这次单独执行拷贝动作,然后还会调用 handlers
[root@master ansible]# ansible-playbook -t conf installHttpd.yml
PLAY [dbserver] ********************************************************************************************************************
TASK [copy configure file] *********************************************************************************************************
changed: [192.168.169.162]
RUNNING HANDLER [restart httpd] ****************************************************************************************************
changed: [192.168.169.162]
PLAY RECAP *************************************************************************************************************************
192.168.169.162 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 查看端口运行情况
[root@master ansible]# ansible dbserver -m shell -a "netstat -lnatp"
192.168.169.162 | CHANGED | rc=0 >>
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 900/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 999/master
tcp 0 0 192.168.169.162:22 192.168.169.1:4289 ESTABLISHED 1862/sshd: root@not
tcp 0 0 192.168.169.162:22 192.168.169.1:4288 ESTABLISHED 1857/sshd: root@pts
tcp 0 0 192.168.169.162:22 192.168.169.160:50172 ESTABLISHED 4566/sshd: root@pts
tcp6 0 0 :::22 :::* LISTEN 900/sshd
tcp6 0 0 ::1:25 :::* LISTEN 999/master
tcp6 0 0 :::6666 :::* LISTEN 4485/httpd
变量名:仅能由字母、数字、和下划线组成,且只能以字母开头
定义变量:
key=value
示例:
http_port=8888
变量调用方式:
通过 {{ variable_name }} 调用变量,变量名前后建议加空格使用,有时用 “{{ variable_name }}” 才生效,不过很少用到
变量来源:
[root@master ~]# ansible servers -m setup -a "filter=ansible_hostname"
192.168.169.162 | SUCCESS => {
"ansible_facts": {
"ansible_hostname": "node02",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
192.168.169.161 | SUCCESS => {
"ansible_facts": {
"ansible_hostname": "node01", # ansible_hostname 就相当于一个变量
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
ansible-playbook -e varname=value
示例:
使用 yml
文件创建可以使用 setup
模块中的参数
---
- hosts: servers
remote_user: root
tasks:
- name: touch file
file: path=/root/{{ ansible_hostname }}.log state=touch
注意:不支持如下格式的,直接在命令行中使用 sertup 参数
[root@master ~]# ansible servers -m file -a "path=/root/{{ ansible_hostname }}.log state=touch"
可以使用 ansible-playbook
的 -e
参数自定义变量名
示例:
创建一个名为 demo2.yml
的文件,内容如下
---
- hosts: servers
remote_user: root
tasks:
- name: install package
yum: name={{ packageName }} state=present
# 使用 -e 参数定义一个变量,这样他就回去下载安装 httpd 服务
[root@master ~]# ansible-playbook -e packageName=httpd /root/ansible/demo2.yml
在 yml
文件中定义变量
示例:
创建一个名为 demo3.yml
的文件,内容如下
---
- hosts: servers
remote_user: root
vars:
- uaername: user1
- groupname: group1
tasks:
- name: create group
group: name={{ groupname }} state=present
- name: create user
user: name={{ uaername }} state=present
[root@master ~]# ansible-playbook /root/ansible/demo3.yml
如果在 yml
文件中定义了变量的值,我们也可以在命令行中重新定义
示例:
# 使用 -e 参数重新定义文件中的变量内容
[root@master ~]# ansible-playbook -e "groupname=group2 uaername=user2" /root/ansible/demo3.yml
可以在一个独立的 playbook
文件中定义变量,在另一个 playbook
文件中引用变量文件中的变量,比 playbook
文件中定义的变量优先级要高
示例:
创建一个名为 variables.yml
文件,存放变量名
---
# variables file
package_name: vsftpd
service_name: vsftpd
在其他 yml
文件中引用,注意引用名称一定要相同
---
- hosts: servers
remote_user: root
vars_files:
- variables.yml
tasks:
- name: install packages
yum: name={{ package_name }}
tags: install
- name: start service
service: name={{ service_name }} state=started enabled=yes
执行测试
# 执行 yml 文件
[root@master ~]# ansible-playbook /root/ansible/demo4.yml
PLAY [servers] *********************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************
ok: [192.168.169.161]
ok: [192.168.169.162]
TASK [install packages] ************************************************************************************************************
changed: [192.168.169.162]
changed: [192.168.169.161]
TASK [start service] ***************************************************************************************************************
changed: [192.168.169.161]
changed: [192.168.169.162]
PLAY RECAP *************************************************************************************************************************
192.168.169.161 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.169.162 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 查看监听端口
[root@master ~]# ansible servers -m shell -a "netstat -lnatp"
192.168.169.162 | CHANGED | rc=0 >>
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 900/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 999/master
tcp 0 0 192.168.169.162:22 192.168.169.1:4289 ESTABLISHED 1862/sshd: root@not
tcp 0 0 192.168.169.162:22 192.168.169.1:4288 ESTABLISHED 1857/sshd: root@pts
tcp 0 0 192.168.169.162:22 192.168.169.160:50280 ESTABLISHED 16096/sshd: root@pt
tcp6 0 0 :::21 :::* LISTEN 16083/vsftpd
tcp6 0 0 :::22 :::* LISTEN 900/sshd
tcp6 0 0 ::1:25 :::* LISTEN 999/master
tcp6 0 0 :::6666 :::* LISTEN 4485/httpd
192.168.169.161 | CHANGED | rc=0 >>
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 900/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1025/master
tcp 0 0 192.168.169.161:22 192.168.169.1:2224 ESTABLISHED 1132/sshd: root@not
tcp 0 0 192.168.169.161:22 192.168.169.1:2223 ESTABLISHED 1129/sshd: root@pts
tcp 0 0 192.168.169.161:22 192.168.169.160:38554 ESTABLISHED 3152/sshd: root@pts
tcp6 0 0 :::21 :::* LISTEN 3143/vsftpd
tcp6 0 0 :::22 :::* LISTEN 900/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1025/master
在主机清单文件中为指定的主机定义变量,以便于在 playbook
中使用
示例:
[servers]
192.168.169.161 http_port=80
192.168.169.162 mysql_port=3307
在主机清单文件中赋予给定组内所有主机上的在 playbook
中可用的变量
示例:
[servers]
192.168.169.161 name=node01
192.168.169.162 name=node02
[servers:vars]
public=ansible
# 使用变量修改主机名
[root@master ~]# ansible servers -m hostname -a "name={{ public }}.{{ name }}"
192.168.169.161 | CHANGED => {
"ansible_facts": {
"ansible_domain": "node01",
"ansible_fqdn": "ansible.node01",
"ansible_hostname": "ansible",
"ansible_nodename": "ansible.node01",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"name": "ansible.node01"
}
192.168.169.162 | CHANGED => {
"ansible_facts": {
"ansible_domain": "node02",
"ansible_fqdn": "ansible.node02",
"ansible_hostname": "ansible",
"ansible_nodename": "ansible.node02",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"name": "ansible.node02"
}
# 查看修改情况
[root@master ~]# ansible servers -m shell -a "hostname"
192.168.169.161 | CHANGED | rc=0 >>
ansible.node01
192.168.169.162 | CHANGED | rc=0 >>
ansible.node02
注意:如果主机定义的参数和组定义的参数名相同,那么则以主机定义的为准(即优先级更高)
示例:
[servers]
192.168.169.161 name=node01 http_port=8080 # 以主机定义的参数为准(类似于就近原则)
192.168.169.162 name=node02 http_port=8888
[servers:vars]
public=ansible
http_port=6666
这个后面在介绍 role 的时候详细说
模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja语法
jinja2语言
网站:https://jinja.palletsprojects.com/en/2.11.x/
jinja2 语言使用字面量,有下面形式:
类型 | 示例 |
---|---|
数字 | 整数,浮点数 |
字符串 | 使用单引号或双引号 |
列表 | [item1, item2, …] |
元组 | (item1, item2, …) |
字典 | {key1:value1, key2:value2, …} |
布尔型 | true/false |
算术运算 | +, -, *, /, //, %, ** |
比较操作 | ==, !=, >, >=, <, <= |
逻辑运算 | and,or,not |
流表达式 | For,If,When |
表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如“Hello World”
双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),如42,42.23
数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在 Python 里, 42 和 42.0 是不一样的
Jinja 允许用计算值。支持下面的运算符
类型 | 说明 |
---|---|
+ | 把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2 |
- | 用第一个数减去第二个数。 {{ 3 – 2 }} 等于 1 |
/ | 对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 {{ 0.5 }} |
// | 对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2 |
% | 计算整数除法的余数。 {{ 11 % 7 }} 等于 4 |
* | 用右边的数乘左边的操作数。 {{ 2 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ ‘=’ *80 }} 会打印 80 个等号的横条* |
** | 取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8 |
[root@master ~]# vim test.j2
[root@master ~]# cat test4.j2
{{ 3 + 2 }}
{{ 3 - 4 }}
{{ 3 * 5 }}
{{ 2 ** 3 }}
{{ 7 / 5 }}
{{ 7 // 5 }}
{{ 17 % 5 }}
[root@master ~]# ansible servers -m template -a "src=test.j2 dest=/root/test"
[root@master ~]# cat test
5
-1
15
8
1.4
1
2
类型 | 说明 |
---|---|
== | 比较两个对象是否相等 {{ 1 == 1 }} |
!= | 比较两个对象是否不等 {{ 2 != 2 }} |
> | 如果左边大于右边,返回 true {{ 2 > 1 }} |
>= | 如果左边大于等于右边,返回 true {{ 2 >= 1 }} |
< | 如果左边小于右边,返回 true {{ 1 < 2 }} |
<= | 如果左边小于等于右边,返回 true {{ 1 <= 2 }} |
[root@master ~]# vim test.j2
[root@master ~]# cat test.j2
{{ 1 == 1 }}
{{ 2 != 2 }}
{{ 2 > 1 }}
{{ 2 >= 1 }}
{{ 2 < 1 }}
{{ 2 <= 1 }}
[root@master ~]# ansible servers -m template -a "src=test.j2 dest=/root/test"
[root@master ~]# cat test
True
False
True
True
False
False
类型 | 说明 |
---|---|
and | 如果左操作数和右操作数同为真,返回 true(即同为真则为真,一个为假则为假) |
or | 如果左操作数和右操作数有一个为真,返回 true(即同为假则为假,一个为真则为真) |
not | 对一个表达式取反 |
expr | 表达式组 |
true / false | true 永远是 true ,而 false 始终是 false |
[root@master ~]# cat test.j2
{{ (2 > 1) or (1 > 2) }}
{{ (2 > 1) and (1 > 2) }}
{{ not true }}
{{ not True }}
{{ not false }}
{{ not False }}
[root@master ~]# ansible servers -m template -a "src=test.j2 dest=/root/test"
[root@master ~]# cat test
True
False
False
False
True
True
类型 | 说明 |
---|---|
in | 指定的内容在一个列表里 |
not in | 指定的内容不在一个列表里 |
[root@master ~]# vim test.j2
[root@master ~]# cat test.j2
{{ 1 in [1,2,3,4] }}
{{ 1 not in [1,2,3,4] }}
[root@master ~]# ansible servers -m template -a "src=test.j2 dest=/root/test"
[root@master ~]# cat test
True
False
template 功能:可以根据和参考模块文件,动态生成相类似的配置文件
template 文件必须存放于 templates 目录下,且命名为 .j2 结尾
yaml/yml 文件需和 templates 目录平级,目录结构如下示例:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
示例:
利用template 同步nginx配置文件
#准备templates/nginx.conf.j2文件,vim temnginx.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf # 这里就是将 nginx.conf.j2 文件拷贝到远程主机的指点目录下,注意这里不需要写绝对路径,他只要 template 和当前 yml 文件在同一级目录下,就会自动去找(参考上面目录结构)
ansible-playbook temnginx.yml
示例:
installNginx.yml
文件---
- hosts: servers
remote_user: root
tasks:
- name: install nginx
yum: name=nginx
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: restart nginx
notify: restart nginx
- name: start service
service: name=nginx state=started enable=yes
handlers:
- name: restart nginx
service: name=nginx state=restarted
nginx.conf.j2
,文件路径为 yml
文件同级目录 template
目录下worker_processes {{ ansible_processor_vcpus**3 }}; # 修改文件中工作进程数做测试,设置为 CPU 核数的 3 次方,测试数据有限,所以这里感觉和直接 copy 没什么很大差异
[root@master ~]# ansible-playbook /root/ansible/installNginx.yml --limit 192.168.169.161
# 查看进程数
[root@master ~]# ansible 192.168.169.161 -m shell -a "ps -ef | grep nginx"
192.168.169.161 | CHANGED | rc=0 >>
root 2559 1 0 23:49 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx 2560 2559 0 23:49 ? 00:00:00 nginx: worker process
nginx 2561 2559 0 23:49 ? 00:00:00 nginx: worker process
nginx 2562 2559 0 23:49 ? 00:00:00 nginx: worker process
nginx 2563 2559 0 23:49 ? 00:00:00 nginx: worker process
nginx 2564 2559 0 23:49 ? 00:00:00 nginx: worker process
nginx 2565 2559 0 23:49 ? 00:00:00 nginx: worker process
nginx 2566 2559 0 23:49 ? 00:00:00 nginx: worker process
nginx 2567 2559 0 23:49 ? 00:00:00 nginx: worker process
root 2640 2639 0 23:53 pts/1 00:00:00 /bin/sh -c ps -ef | grep nginx
root 2642 2640 0 23:53 pts/1 00:00:00 grep nginx
template 中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能
示例 1:
如下只是一个 demo
样例
创建 yml
测试文件 templateNginx.yml
---
- hosts: servers
remote_user: root
vars:
nginx_host:
- 80
- 81
- 82
tasks:
- name: template config
template: src=nginx.conf2.j2 dest=/root/nginx2.conf
创建 j2
测试文件 nginx.conf2.j2
{% for vhost in nginx_host %}
server {
listen {{ vhost }}
}
{% endfor %}
测试结果:
[root@master ansible]# ansible-playbook templateNginx.yml --limit=192.168.169.161
[root@master ansible]# ansible 192.168.169.161 -m shell -a "ls /root"
192.168.169.161 | CHANGED | rc=0 >>
anaconda-ks.cfg
nginx2.conf
setStaticIP.sh
# 查看文件内容
[root@master ansible]# ansible 192.168.169.161 -m shell -a "cat /root/nginx2.conf"
192.168.169.161 | CHANGED | rc=0 >>
server {
listen 80
}
server {
listen 81
}
server {
listen 82
}
示例2:
创建 yml
测试文件 templateNginx3.yml
---
- hosts: servers
remote_user: root
vars:
nginx_host:
- listen: 8088
tasks:
- name: template config
template: src=nginx.conf3.j2 dest=/root/nginx3.conf
创建 j2
测试文件 nginx.conf3.j2
{% for vhost in nginx_host %}
server {
listen {{ vhost.listen }}
}
{% endfor %}
测试结果:
[root@master ansible]# ansible-playbook templateNginx3.yml --limit=192.168.169.161
[root@master ansible]# ansible 192.168.169.161 -m shell -a "ls /root"
192.168.169.161 | CHANGED | rc=0 >>
anaconda-ks.cfg
nginx2.conf
nginx3.conf
setStaticIP.sh
[root@master ansible]# ansible 192.168.169.161 -m shell -a "cat /root/nginx3.conf"
192.168.169.161 | CHANGED | rc=0 >>
server {
listen 8088
}
示例:3
创建 yml
测试文件 templateNginx4.yml
---
- hosts: servers
remote_user: root
vars:
nginx_host:
- listen: 8081
server_name: www.demo81.com
- listen: 8082
server_name: www.demo82.com
- {listen: 8083, server_name: www.demo83.com}
tasks:
- name: template config
template: src=nginx.conf4.j2 dest=/root/nginx4.conf
创建 j2
测试文件 nginx.conf4.j2
{% for vhost in nginx_host %}
server {
listen {{ vhost.listen }}
server_name {{ vhost.server_name }}
}
{% endfor %}
测试结果:
[root@master ansible]# ansible-playbook templateNginx4.yml --limit=192.168.169.161
[root@master ansible]# ansible 192.168.169.161 -m shell -a "ls /root"
192.168.169.161 | CHANGED | rc=0 >>
anaconda-ks.cfg
nginx2.conf
nginx3.conf
nginx4.conf
setStaticIP.sh
[root@master ansible]# ansible 192.168.169.161 -m shell -a "cat /root/nginx4.conf"
192.168.169.161 | CHANGED | rc=0 >>
server {
listen 8081
server_name www.demo81.com
}
server {
listen 8082
server_name www.demo82.com
}
server {
listen 8083
server_name www.demo83.com
}
示例:
创建 yml
测试文件 templateNginx5.yml
---
- hosts: servers
remote_user: root
vars:
nginx_host:
- web1:
listen: 8081
server_name: www.demo81.com
- web2:
listen: 8082
server_name: www.demo82.com
- web3:
listen: 8083
tasks:
- name: template config
template: src=nginx.conf5.j2 dest=/root/nginx5.conf
创建 j2
测试文件 nginx.conf5.j2
{% for vhost in nginx_host %}
server {
listen {{ vhost.listen }}
{% if vhost.server_name is defined %} # 如果 vhost.server_name 是有定义的,则执行下面的
server_name {{ vhost.server_name }}
{% endif %}
}
{% endfor %}
测试结果:
注:这里有个小细节可以注意一下,如果参照上面 nginx.conf5.j2
文件中的缩进格式,那么生成文件的格式则如下测试结果所示,所以可以根据自己的需求去调整缩进格式
[root@master ansible]# ansible-playbook templateNginx5.yml --limit=192.168.169.161
[root@master ansible]# ansible 192.168.169.161 -m shell -a "ls /root"
192.168.169.161 | CHANGED | rc=0 >>
anaconda-ks.cfg
nginx2.conf
nginx3.conf
nginx4.conf
nginx5.conf
setStaticIP.sh
[root@master ansible]# ansible 192.168.169.161 -m shell -a "cat /root/nginx5.conf"
192.168.169.161 | CHANGED | rc=0 >>
server {
listen 8081
server_name www.demo81.com
}
server {
listen 8082
server_name www.demo82.com
}
server {
listen 8083
}
when语句,可以实现条件测试。如果需要根据变量、facts 或此前任务的执行结果来做为某 task 执行与否的前提时要用到条件测试,通过在 task 后添加 when 子句即可使用条件测试,jinja2 的语法格式
示例:1
---
- name: when test
hosts: servers
remote_user: root
tasks:
- name: httpd installed
yum:
name: httpd
state: present
when:
- ansible_facts['architecture'] == 'x86_64'
- ansible_facts['bios_version'] == '0.5.1'
示例:2
---
- name: when test
hosts: servera
remote_user: root
tasks:
- name: httpd installed
yum:
name: httpd
state: present
when: >
( ansible_facts['architecture'] == "x86_64" and
ansible_facts['bios_version'] == "6.00" )
or
( ansible_facts['bios_version'] == "5.00" and
ansible_facts['architecture'] == "x86_32" )
迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为”item“
要在task中使用with_items给定要迭代的元素列表
列表元素格式:
示例:1
---
- hosts: servers
remote_user: root
tasks:
- name: create group
group: name=demo
- name: add user
user: name={{ item }} state=present group=demo
with_items:
- user1
- user2
等同于下面创建用户
---
- hosts: servers
remote_user: root
tasks:
- name: create group
group: name=demo
- name: add user1
user: name=user1 group=demo state=present
- name: add user2
user: name=user2 group=demo state=present
示例:2
---
- hosts: servers
remote_user: root
tasks:
- name: create group
group: name={{ item }} state=present
with_items:
- group1
- group2
- group3
- name: add user
user: name={{ item.name }} group={{ item.group }} state=present
with_items:
- { name: user1,group: group1 }
- { name: user2,group: group2 }
- { name: user3,group: group3 }
角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织 playbook。roles 能够根据层次型结构自动装载变量文件、tasks 以及 handlers 等。要使用roles 只需要在 playbook 中使用 include 指令即可。简单来讲,roles 就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include 它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
运维复杂的场景:建议使用roles,代码复用度高
roles:多个角色的集合, 可以将多个的 role,分别放至 roles 目录下的独立子目录中
未完待续…