ansible 学习

文章目录

  • ansible 学习
    • 1. ansible 介绍
    • 2. Ansible 架构解析
    • 3. 环境准备
    • 4. 安装 ansible
      • 4.1 查看安装信息
      • 4.2 配置文件目录说明
      • 4.3 ansible 配置文件详情
      • 4.4 ansible 命令参考
      • 4.5 主机清单 host 详解
        • :one: 第一种写法
        • :two: 第二种写法
        • :three: 第三中写法
        • :four: 第四种写法
        • :five: 第五种写法
        • :six: 第六种写法
    • 5. ansible 管理方式
      • 5.1 传统的输入 ssh 密码验证
      • 5.2 秘钥管理
      • 5.3 总结
    • 6. ansible 模式与命令工具
      • 6.1 ad-hoc 模式
        • 6.1.1 ansible
        • 6.1.2 ansible-doc
        • 6.1.3 ansible-galaxy
      • 6.2 playbook 模式
        • 6.2.1 ansible-playbook
        • 6.2.2 ansible-vault
    • 7. ansible 模块学习
        • command 模块
        • shell 模块
        • script 模块
        • ping 模块
        • setup 模块
        • copy 模块
        • fetch 模块
        • file 模块
        • unarchive 模块
        • archive 模块
        • HostName 模块
        • Cron 模块
        • Yum 模块
        • service 模块
        • User 模块
        • Group 模块
        • Lineinfile模块
        • Replace 模块
    • 8. Playbook
      • 8.1 playbook 简介
      • 8.2 YAML 简介
          • YAMl 语言介绍
          • YAML 语言特性
          • YAML语法简介
            • List列表
            • Dictionary字典
          • 三种常见的数据格式
      • 8.3 Playbook 核心元素
        • 8.3.1 Hosts 组件
        • 8.3.2 remote_user 组件
        • 8.3.3 task列表和action组件
        • 8.3.4 其它组件
        • 8.3.5 ShellScripts VS Playbook 案例
      • 8.4 playbook 命令
      • 8.5 playbook 案例
        • 8.5.1 利用 playbook 创建 mysql 用户
        • 8.5.2 使用 playbook 安装 nginx
        • 8.5.3 使用 playbook 二进制安装 mysql
        • 8.5.4 使用 playbook 安装 httpd 服务
      • 8.6 playbook 中使用 handlers 和 notify
      • 8.7 playbook 中使用 tags 组件
      • 8.8 playbook 中使用变量
        • 8.8.1 使用 setup 模块中的变量
        • 8.8.2 在 ansible 命令行中自定义变量
        • 8.8.3 在 playbook 文件中自定义变量
        • 8.8.4 使用变量文件
        • 8.8.5 主机清单文件(hosts)定义变量
        • 主机变量
        • 组(公共)变量
        • 8.8.6 在 role 中定义变量
      • 8.9 template 模板
        • template
          • template算术运算
          • template 中使用 for 循环
          • template 中使用 if 判断
      • 8.10 playbook 使用 when
      • 8.11 playbook 使用迭代 with_items
    • 9. role 角色

ansible 学习

1. ansible 介绍

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 模块

  • 安装部署简单
  • 管理主机便捷,支持多台主机并行管理
  • 无需安装被管理节点的客户端(no agent),且无需占用客户端的其他接口,仅仅使用 ssh 服务即可
  • 不仅仅支持 python,还支持其他语言的二次开发
  • 不用 root 用户也可以执行,降低系统权限问题
  • 幂等性:一个任务执行一遍和执行多次效果一样,不会因为重复执行带来意外情况

注意事项

  • 执行 ansible 的主机一般称为主控端,中控,master或者堡垒机
  • 主控端 python 版本需要 2.6 或以上
  • 被控端 python 版本低于 2.4 则需要安装 python-simplejson
  • 被控端如果开启了 selinux 则需要安装 libselinux-python
  • windows 不能作为主控端

写在最后:ansible 其实就是一个使用工具,他更多的则是去调用一些模块去完成任务内容,所以与其说我们在学习 ansible ,不如说是在学习 ansible 的模块。

2. Ansible 架构解析

ansible 学习_第1张图片

  • Host Inventory:主机群,主机清单,定义ansible管理的主机,还可以存放一下针对不同主机的变量,也可以写入主机的用户名和密码

  • Playbooks:ansible的任务配置文件,将多个任务定义在剧中本,由ansible自动执行

  • Core Modules:核心模块,Ansible自带的模块。

  • Custom Modules:自定义模块,如果核心模块不足以完成某种功能,可以自行添加自定义模块(支持现在主流的大部分编程语言,甚至于shell)

  • Plugins:插件,支持使用插件的方式对ansible本身的功能进行扩展,模块是用来实现任务的,增强ansible平台自己的功能就需要使用插件(loggin插件记录日志,email插件发送邮件),其中最常用的是:连接插件(Connectionr Plugins)ansible基于连接插件连接到各个主机上,虽然默认情况下ansible使用ssh连接到各个主机上,但它还支持其它的连接方法。

访问执行顺序

ansible 学习_第2张图片

3. 环境准备

这里准备三台测试机器

IP 主机名 角色
192.168.169.150 master 安装 ansible
192.168.169.151 node01 被管理机器
192.168.169.152 node02 被管理机器

4. 安装 ansible

# 安装 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

4.1 查看安装信息

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 版本信息

4.2 配置文件目录说明

/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的方式从服务器上拉取文件

4.3 ansible 配置文件详情

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

4.4 ansible 命令参考

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)

4.5 主机清单 host 详解

配置介绍

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解释器

1️⃣ 第一种写法

[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:指定连接密码

2️⃣ 第二种写法

[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文件不安全,可以通过私钥来进行连接

3️⃣ 第三中写法

[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]分组内的机器使用该变量

4️⃣ 第四种写法

[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文件内所有的分组应用此变量

5️⃣ 第五种写法

[dbservers]
db01.intranet.mydomain.net
db02.intranet.mydomain.net

#主机名
如果目标地址的主机名本机可以解析,那么也可以添加主机名

6️⃣ 第六种写法

db-[99:101]-node.example.com
#域名或主机名的正则表达式匹配

5. ansible 管理方式

ansible 批量管理主机的方式主要有两种

5.1 传统的输入 ssh 密码验证

# 配置好 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.

ansible 学习_第3张图片

正常如果在 ~/.ssh 下没有文件,说明这台机器还没有使用 ssh 方式连接过其他主机

  1. 这样我们可以手动去连接一次(这样肯定不方便)
ssh [email protected]
# 152 也是同样的操作
ssh [email protected]

ansible 学习_第4张图片

  1. 修改 /etc/ansible/ansible.cfg 配置文件
# 找到如下内容,将注释取消
# 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'

5.2 秘钥管理

使用 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

5.3 总结

  1. 在生产环境中,ansible 的连接方式二选一即可,最好是选择配置 ssh 公私钥免密登陆。

  2. 如果生产环境要求更高,可以使用普通用户去执行,在使用 sudo 进行提权操作。

  3. 可以禁止外网 ssh 登陆,使用 VPN 连接内网操作。

6. ansible 模式与命令工具

ansible 实现批量化主机管理的模式主要有两种:

  • 利用 ansible 的纯命令行实现批量化管理,即 ad-hoc 模式
  • 利用 ansible 的 playbook 剧本来实现批量化管理,即 playbook 剧本模式

6.1 ad-hoc 模式

ansible 的 ad-hoc 模式就是 ansible 的命令行形式,也就是处理一些临时的,简单的任务,可以利用 ansible 的命令行来操作。

应用场景:

  • 临时批量查看被管理机器的内存情况,CPU负载,网络情况等
  • 比如临时的分发配置文件等

6.1.1 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
  • ansible 命令执行过程
  1. 加载自己的配置文件,默认为 /etc/ansible/ansible.cfg
  2. 加载指定的模块文件,如 -m ping
  3. 通过 ansible 将模块或者命令生成对应的临时 py 文件,并将该文件传输至远程服务器的对应执行用户 $HOME/.ansible/tmp/ansible-tmp-数字/xxx.PY 文件
  4. 给文件 +x 执行权限
  5. 执行并返回结果
  6. 删除临时 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



6.1.2 ansible-doc

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.

6.1.3 ansible-galaxy

“Ansible Galaxy” 指的是一个网站共享和下载 Ansible 角色,也可以是帮助 roles(playbook 类似于脚本,roles 就相当于这些脚本的集合) 更好的工作的命令行工具。

此工具会连接 https://galaxy.ansible.com/ 下载相应的 roles,下载完成之后我们可以直接使用或者修改成更加合适自己的脚本

  1. 打开官网,找到我们想要下载的信息

ansible 学习_第5张图片

  1. 选择我们想要的类型

ansible 学习_第6张图片

  1. 点击我们想要下载的内容

ansible 学习_第7张图片

  1. 复制命令即可在服务器上下载

ansible 学习_第8张图片

  1. 下载完成
[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 学习_第9张图片

6.2 playbook 模式

ansible 的 playbook 模式主要针对比较具体,且比较大的任务,那就需要提前写好 playbook 剧本

应用场景:

  • 一键部署 rsync 备份服务器
  • 一键部署 lnmp 环境

6.2.1 ansible-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

ansible 学习_第10张图片

6.2.2 ansible-vault

此工具用于加密解密 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: 


7. ansible 模块学习

ansible 学习的两个核心内容就是 ansible模块 学习以及 playbook 剧本模式编写

我们可以使用 ansible-doc -l 列出 ansible 所支持的所有模块

command 模块

作用:在远程节点上执行一个命令

我们可以使用 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 是否提供告警信息

注意:

  • 使用 command 模块时,不得出现 shell 变量 $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

在这里插入图片描述

  • 让客户端机器,先切换到 /tmp 目录下,然后打印出当前的目录信息
[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 ~]# 

ansible 学习_第11张图片

  • creates 参数练习

该参数的作用是在创建一个文件之前,先判断文件是否存在,如果存在则跳过前面的东西,如果不存在则执行前面的动作

# 判断 /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 >>
  • removes 参数练习

判断一个文件是否存在,如果存在则执行前面的动作,如果不存在则跳过前面的内容(和上面的 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 参数练习

是否提供告警信息

# 没有使用 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 >>

shell 模块

官网参考地址:https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html

切换到某个 shell 执行指定的指令,与 command 不同的是,此模块可以支持命令管道,同时还有另一个模块也具备此功能:raw

了解模块用法的渠道:

  • 使用 ansible-doc -s shell 查看帮助文档
  • 查看官网地址学习
  • 官网不好看,多去学习别人的文档
[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 是否提供告警信息
  • 示例1:

查看被管理机器上的进程信息

[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

  • 示例2:

批量远程执行脚本,需要执行的脚本要求必须在客户端存在,否则会报错文件不存在。这个是 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

script 模块

指定本地的脚本文件,到远程主机运行一次

注意:和 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"
    ]
}

ping 模块

[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 模块

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"
        }, 
		........
  • 搜集系统信息并保存在指定目录,默认自动创建文件名,即为主机 ip 地址
[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
}

copy 模块

主要用于将管理主机上的数据信息拷贝给多台主机
官方文档: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

示例:

  • 将本地 test.txt 文件拷贝到远程机器上,并修改文件用户(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 学习_第12张图片

  • content 指定内容,并生成目标文件
ansible dong -m copy -a "content='test line1\ntest lin2' dest=/root/123.txt"
参数解析:
	content			添加文件内容,将内容写入远程机器文件
	dest			定义远程服务器文件路径

ansible 学习_第13张图片

fetch 模块

从远程主机提取文件到 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"

ansible 学习_第14张图片

file 模块

功能:实现创建、删除信息。对数据权限进行修改

官方文档: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"
  • 在创建链接文件时,如果源文件不存在,或者链接文件与其他文件同名时,强制覆盖同名文件或者创建链接文件,参考上述 force 参数的解释。
[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"
}

ansible 学习_第15张图片

  • 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"
  • 当操作远程主机中的目录时,同时递归的将目录中的文件的属主属组都设置为 dong
[root@master ~]# ansible dong -m file -a "path=/data/test/demo state=directory owner=dong group=dong recurse=yes"

unarchive 模块

功能:解包解压缩

有两种实现方法:

主要差异为压缩包所在位置不同,一个是在 ansible 主控端上,一个是在远程主机上

  1. ansible 主机上的压缩包传到远程主机后解压缩至特定目录,使用 copy=yes 参数
  2. 将远程主机上的某个压缩包解压到指定路径下,使用 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 解压后的目录或文件的属组

示例:

  • 将 ansible 主机的压缩文件拷贝到到远程主机并解压,修改文件所属组和用户
[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"

archive 模块

功能:打包压缩

常用参数:

参数 说明
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"

HostName 模块

功能:管理主机名

示例:

  • 修改远程主机名
[root@master ~]# ansible 192.168.169.161 -m hostname -a "name=demo"

Cron 模块

功能:用来管理 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

示例:

  • 创建名称为 ntpdate 的计划任务,每天凌晨1点5分同步时间
[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"
  • 把刚才添加的ntpdate任务删除并备份

建议:删除和关闭计划任务的时候,把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 模块

功能:使用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 卸载软件包

示例:

  • 安装一个 http 服务
[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"

service 模块

功能:系统服务管理

官方文档: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 停止

示例:

  • 启动 httpd 服务
[root@master ~]# ansible dong -m service -a "name=httpd state=started"
  • 关闭 httpd 服务
[root@master ~]# ansible dong -m shell -a "systemctl status httpd"

User 模块

功能:系统用户管理

官方文档: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"

Group 模块

功能:系统用户组管理

官方文档: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 删除指定的用户组

示例:

  • 创建一个指定用户组 123 gid=1022
[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"

Lineinfile模块

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'"

Replace 模块

该模块有点类似于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'"

8. Playbook

8.1 playbook 简介

playbook 实际上就是一个文本文件,它是由 yuml 语言实现的。它里面定义了各种模块的调用,并且规定了执行的先后顺序,按照一定的次序来调用,

playbook 剧本是由一个或多个“play”组成的列表

play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作

Playbook 文件是采用YAML语言编写的

ansible 学习_第16张图片

8.2 YAML 简介

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可以基于流来处理
  • YAML表达能力强,扩展性好
YAML语法简介
  • 在单一文件第一行,用连续三个连字号“-” 开始,还有选择性的连续三个点号( … )用来表示文件的结尾
  • 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
  • 使用#号注释代码
  • 缩进必须是统一的,不能空格和tab混用
  • 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的,YAML文件内容是区别大小写的,key/value的值均需大小写敏感
  • 多个key/value可同行写也可换行写,同行使用 ,(逗号)分隔
  • v 可是个字符串,也可是另一个列表
  • 一个完整的代码块功能需最少元素需包括 name 和 task
  • 一个name只能包括一个task,一个 task 对应一个模块
  • YAML文件扩展名通常为yml或yaml

YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-“来代表,Map里的键值对用”:"分隔,下面介绍两种常见的数据结构。

List列表

列表由多个元素组成,每个元素放在不同行,且元素前均使用“-”打头,或者将所有元素用 [ ] 括起来放在同一行
范例:

# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango
或者放在一个 [ ] 里
[Apple,Orange,Strawberry,Mango]
Dictionary字典

字典由多个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
三种常见的数据格式
  • XML:Extensible Markup Language,可扩展标记语言,可用于数据交换和配置
  • JSON:JavaScript Object Notation, JavaScript 对象表记法,主要用来数据交换或配置,不支持注释
  • YAML:YAML Ain’t Markup Language YAML 不是一种标记语言, 主要用来配置,大小写敏感,不支持tab

ansible 学习_第17张图片

可以用工具互相转换,参考网站:

https://www.json2yaml.com/

http://www.bejson.com/json/json2yaml/

8.3 Playbook 核心元素

参数 说明
Hosts 执行的远程主机列表(应用在哪些主机上)
Tasks 任务集,具体要调用的模块
Variables 内置变量或自定义变量在playbook中调用
Handlers / notify Handlers和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
tags 指定某条任务执行,用于选择运行playbook中的部分代码。
ansible具有幂等性,因此会自动跳过没有变化的部分,
即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。
此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
ansible-playbook -t tagsname useradd.yml
Templates 模板可替换模板文件中的变量并实现一些简单逻辑的文件

8.3.1 Hosts 组件

Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中。

Websrvs:dbsrvs      	#或者,两个组的并集
Websrvs:&dbsrvs     	#与,两个组的交集
webservers:!phoenix  	#在websrvs组,但不在dbsrvs组

案例:

# 属于 webservers 或者 appservs
- hosts: websrvs:appsrvs

8.3.2 remote_user 组件

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,不过不常用

8.3.3 task列表和action组件

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 并设置为开机自启

8.3.4 其它组件

  • 某任务的状态在运行后为 changed 时,可通过 “notify” 通知给相应的 handlers
  • 任务可以通过 "tags“ 打标签,可在 ansible-playbook 命令上使用-t指定进行调用

8.3.5 ShellScripts VS Playbook 案例

# 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

8.4 playbook 命令

格式:

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 这个分组里的主机

8.5 playbook 案例

8.5.1 利用 playbook 创建 mysql 用户

---
# 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

8.5.2 使用 playbook 安装 nginx

---
- 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

8.5.3 使用 playbook 二进制安装 mysql

下面的 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

8.5.4 使用 playbook 安装 httpd 服务

---
- 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

8.6 playbook 中使用 handlers 和 notify

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

8.7 playbook 中使用 tags 组件

playbook 文件中,可以利用 tags 组件,为特定的 task 指定标签,当在执行 playbook 时,可以只执行特定的 tagstask ,而非整个 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 

8.8 playbook 中使用变量

变量名:仅能由字母、数字、和下划线组成,且只能以字母开头

定义变量:

key=value

示例:

http_port=8888

变量调用方式:

通过 {{ variable_name }} 调用变量,变量名前后建议加空格使用,有时用 “{{ variable_name }}” 才生效,不过很少用到

8.8.1 使用 setup 模块中的变量

变量来源:

  1. ansible 中的 setup filter(使用方法参考 setup 模块内容) 远程主机的所有变量都可以直接调用
[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
}

  1. 通过命令行指定变量,优先级最高
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"

8.8.2 在 ansible 命令行中自定义变量

可以使用 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

8.8.3 在 playbook 文件中自定义变量

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

8.8.4 使用变量文件

可以在一个独立的 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

8.8.5 主机清单文件(hosts)定义变量

主机变量

在主机清单文件中为指定的主机定义变量,以便于在 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

8.8.6 在 role 中定义变量

这个后面在介绍 role 的时候详细说

8.9 template 模板

模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套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 功能:可以根据和参考模块文件,动态生成相类似的配置文件
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
template算术运算

示例:

  1. 准备 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
  1. 准备 nginx.conf.j2 ,文件路径为 yml 文件同级目录 template 目录下
worker_processes  {{ ansible_processor_vcpus**3 }}; # 修改文件中工作进程数做测试,设置为 CPU 核数的 3 次方,测试数据有限,所以这里感觉和直接 copy 没什么很大差异
  1. 测试
[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 循环

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
}

template 中使用 if 判断

示例:

创建 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
    }

8.10 playbook 使用 when

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" )

8.11 playbook 使用迭代 with_items

迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为”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 }
        

9. role 角色

角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织 playbook。roles 能够根据层次型结构自动装载变量文件、tasks 以及 handlers 等。要使用roles 只需要在 playbook 中使用 include 指令即可。简单来讲,roles 就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include 它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中

运维复杂的场景:建议使用roles,代码复用度高

roles:多个角色的集合, 可以将多个的 role,分别放至 roles 目录下的独立子目录中

 
 
 

未完待续…

你可能感兴趣的:(ansible,ansible,ansible,学习)