一、简介
Ansible 是一个 IT 自动化工具,他能配置系统,部署软件,编排更复杂的 IT 任务,如连续部署或零停机时间滚动更新。
Ansible 用 Python 编写,Ansible 允许不需要在每个节点上安装自己的组件,可以在不止一个地方控制整个基础架构。
二、工作原理
Inventory
:被管理节点的列表,资源池。PlayBook
:类似于 Shell 脚本,通过一系列命令执行自动化操作。Module
。
在 Ansible 管理体系中,存在
管理节点
和被管理节点
两种角色。
被管理节点通常被成为资产。
在管理节点上,Ansible 将 AdHoc 或 PlayBook 转换为 python 脚本,并通过 SSH 传输到被管理节点上。
在被管理节点上依次执行 Python 脚本。
三、Ansible 安装
3.1、先决条件
3.2、安装 Ansible
yum 方式:
[root@localhost ~]# yum install epel-release
[root@localhost ~]# yum install ansible
pip 方式:
[root@localhost ~]# yum install epel-release
[root@localhost ~]# yum install python2-pip
[root@localhost ~]# pip install ansible
查看 Ansible 版本:
[root@localhost ~]# 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
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)]
四、Ansible 简单部署
4.1、管理节点与被管理节点建立 SSH 信任关系
管理节点 (ansible) 中创建密钥对:
[root@localhost ~]# ssh-keygen -t rsa
将本地的公钥传输到被管理节点:
[root@localhost .ssh]# ssh-copy-id root@192.168.200.135
[root@localhost .ssh]# ssh-copy-id root@192.168.200.136
4.2、场景
4.2.1、检测所有被管理主机在线状态
[root@manager ~]# ansible all -i 192.168.19.135,192.168.19.136 -m ping
192.168.19.135 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.19.136 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
-i
: 参数后面是一个列表 (List) , 因此当为一个被管理节点时,我们后面一定要加一个英文逗号 (,) , 告知是 List。
4.2.2、确保 /tmp/a.conf
发布到所有被管理节点上
[root@manager ~]# touch /tmp/a.conf
[root@manager ~]# ansible all -i 192.168.19.135,192.168.19.136 -m copy -a "src=/tmp/a.conf dest=/tmp/a.conf"
192.168.19.136 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/tmp/a.conf",
"gid": 0,
"group": "root",
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"mode": "0644",
"owner": "root",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 0,
"src": "/root/.ansible/tmp/ansible-tmp-1702535672.46-6415-225212235428808/source",
"state": "file",
"uid": 0
}
192.168.19.135 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/tmp/a.conf",
"gid": 0,
"group": "root",
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"mode": "0644",
"owner": "root",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 0,
"src": "/root/.ansible/tmp/ansible-tmp-1702535672.44-6413-170350629067151/source",
"state": "file",
"uid": 0
}
all
: 在 Ansible 中,叫做 pattern , 即匹配,用来在 -i 参数的资产中匹配一部分,all 代表匹配所有-i
: 指定 Ansible 的资产,即被管理主机 (也可以是文件名)-m
: 指定要运行的模板,比如这里的 ping 模块 和 copy 模块-a
: 指定模块的参数,这里 ping 模块没有指定参数,copy 模块指定了 src 和 dest 参数
五、Ansible 资产
实际场景中,被管理的服务器肯定不止 2 台,因此我们可以将被管理服务器写入一个文件或脚本中。
5.1、静态资产
顾名思义,静态资产本身是一个文本文件,一个类似 INI 的文件
默认情况下,Ansible 的资产文件 位于 /etc/ansible/hosts.pip
安装的可能没有这个文件,创建一个即可。
示例:
# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip addresses
# - A hostname/ip can be a member of multiple groups
`Ex 1: 不属于任何组的单独主机,必须放在所有主机组的前面,也就是必须位于文件最前方
green.example.com
blue.example.com
192.168.100.1
192.168.100.10
`Ex 2: 主机组 webservers 包含 4 个主机,调用时可以通过组名匹配主机
[webservers]
alpha.example.org
beta.example.org
192.168.1.100
192.168.1.110
` 有规律的主机可以使用这总方法显示,这代表 www001.example.com , www002.example.com , ...
www [001:006].example.com
`Ex 3: 主机组可以在 组和主机中间添加空格以便阅读
[dbservers]
db01.intranet.mydomain.net
db02.intranet.mydomain.net
10.25.1.56
10.25.1.57
# Here's another example of host ranges, this time there are no
# leading 0s:
## db-[99:101]-node.example.com
5.1.1、自定义资产
vim /etc/ansible/inventory.ini
# 没有组名的属于 all 组
1.1.1.1
2.2.2.2
3.3.3.[1:15]
test01.lml.com
test03.lml.com
test [05:09].lml.com
[web_servers]
192.168.1.2
192.168.1.3
192.168.1.5
[db_servers]
192.168.2.2
192.168.2.3
192.168.2.5
192.168.1.5
# 创建 all_server 组,并将 db_servers 和 web_servers 添加为自己的子组
# 选择 all_server 组时,则代表选中了 web_servers 和 db_servers 组下的所有主机
[all_servers]
[all_servers:children]
db_servers
web_servers
- 1、Ansible 的资产文件中,可以以 IP 地址的形式或者主机名的形式存在。
- 2、Ansible 的资产若连续,可以使用 [start:end] 的形式去表达。
- 3、可以将服务器按照业务场景定义成组,比如 db_servers 和 web_servers。
- 4、组合组之间可以存在继承关系,比如 db_servers 和 web_servers 同时继承 all_servers 组。
5.1.2、如何使用自定义资产
通过 -i
参数指定自定义资产的位置即可 (可以是全路径,也可以是相对路径)。
# ansible all -i inventory.ini .........// 伪命令,不可执行
5.1.3、验证自定义资产
列举出所有资产:
ansible all -i inventory.ini --list-hosts
hosts (19) :
1.1.1.1
2.2.2.2
3.3.3.1
......
列举出选定资产 (比如 db_servers):
ansible db_servers -i inventory.ini --list-hosts
5.2、资产选择器
5.2.1、基本语法格式
ansible PATTERN -i inventory -m moudle -a argument
PATTERN
:可以是 IP 列表,也可以是组名,值得注意的是,资产中写的什么就要写什么,不能通过域名解析-i
:资产列表,从哪里进行筛选-m
:使用哪一个模块-a
:模块所对应的参数
1、选择一台或几台服务器
[root@localhost ansible]# ansible 1.1.1.1 -i inventory.ini --list-host
hosts (1):
1.1.1.1
[root@localhost ansible]# ansible test01.lml.com -i inventory.ini --list-host
hosts (1):
test01.lml.com
[root@localhost ansible]# ansible 1.1.1.1,2.2.2.2 -i inventory.ini --list-host
hosts (2):
1.1.1.1
2.2.2.2
2、选择一组服务器
[root@localhost ~]# ansible all_servers -i inventory.ini --list-host
hosts (6):
192.168.2.2
192.168.2.3
192.168.2.5
192.168.1.2
192.168.1.3
192.168.1.5
# 两个子组的重复部分会被去重
3、使用 * 匹配
[root@localhost ansible]# ansible 3.3.3.1* -i inventory.ini --list-host
hosts (7):
3.3.3.10
3.3.3.11
3.3.3.12
3.3.3.13
3.3.3.14
3.3.3.15
3.3.3.1
4、使用逻辑进行匹配
1)并集 (两个组中所有主机,去重)
# 显示两个组中所有的主机
[root@localhost ansible]# ansible 'web_servers:db_servers' -i inventory.ini --list-host
hosts (6):
192.168.1.2
192.168.1.3
192.168.1.5
192.168.2.2
192.168.2.3
192.168.2.5
2)交集 (两个组中共有主机)
# 显示同时承担 web_server 和 db_server 的主机
[root@localhost ansible]# ansible 'web_servers:&db_servers' -i inventory.ini --list-host
hosts (1):
192.168.1.5
3)差集 (A 有 B 没有,或 B 有 A 没有)
# 在 web_servers 中,但是不在 db_servers 中
[root@localhost ansible]# ansible 'web_servers:!db_servers' -i inventory.ini --list-host
hosts (2):
192.168.1.2
192.168.1.3
# 在 db_servers 中,但是不再 web_servers 中
[root@localhost ansible]# ansible 'db_servers:!web_servers' -i inventory.ini --list-host
hosts (3):
192.168.2.2
192.168.2.3
192.168.2.5
六、Ansible Ad-Hoc Command
Ad-hoc 命令是一个概念性的名字,是相对于 Ansible playbook 来说的,类似于在命令行敲入 shell 和写 shell scripts 两者之间的关系,可以用于执行一些临时命令。
如果我们敲入一些命令去比较快的完成一些事情,而不需要将这些执行的命令特别保存下载,这样的命令就叫做 ad-hoc 命令。
Ansible 提供两种方式去完成任务,一是 ad-hoc , 一是写 Ansible playbook, 前者可以解决一些简单的任务,后者解决较复杂的任务,比如做配置管理或部署。
6.1、命令格式
命令格式语法如下 :
ansible pattern [-i inventory] -m moudule -a argument
pattern
: 资产选择器-i
: 指定资产清单文件的位置。-m
: 指定本次 Ansible ad-hoc 要执行的模块,可以类别成 shell 中的命令。-a
: 模块的参数,可以类比成 SHELL 中的命令参数。
6.3、联机帮助
Ansible 的核心模块和附加模块,数量有 1000+ , 很难一次性掌握,因此我们可以使用 Ansible 的帮助文档,它本身提供的命令就是由 Ansible-doc 实现
- 列出所有的核心模块和附加模块:
ansible-doc -l
- 查询某个模块的使用方法:
ansible-doc modulename
6.4、常用模块
为方便演示,我们使用如下配置文件:
管理机 : 192.168.200.132
被管理机 1 : 192.168.200.133
被管理机 2 : 192.168.200.134
编写如下配置文件到 /etc/ansible/hosts
:
[dbservers]
192.168.200.133
[webservers]
192.168.200.134
6.4.1、command & shell 模块
两个模块都是在远程服务器上执行命令
command 模块:是 ad-hoc 的默认模块,在执行 ad-hoc 时,若不指定模块的名字则默认使用此模块
[root@localhost ansible]# ansible all -i hosts -a "echo 'hello world'"
192.168.200.133 | CHANGED | rc=0 >>
hello world
192.168.200.134 | CHANGED | rc=0 >>
hello world
[root@localhost ansible]# ansible all -i hosts -m shell -a "echo 'hello world'"
192.168.200.133 | CHANGED | rc=0 >>
hello world
192.168.200.134 | CHANGED | rc=0 >>
hello world
command 模块 和 shell 模块的差异:
shell 模块
:可以执行 SHELL 的内置命令和特性 (比如管道符)。command 模块
:无法执行 SHELL 的内置命令和特性。
实例:
[root@localhost ansible]# ansible all -i hosts -m shell -a "echo 'hello' | grep -o 'e'"
192.168.200.133 | CHANGED | rc=0 >>
e
192.168.200.134 | CHANGED | rc=0 >>
e
[root@localhost ansible]# ansible all -i hosts -m command -a "echo 'hello' | grep -o 'e'"
192.168.200.133 | CHANGED | rc=0 >>
hello | grep -o e
192.168.200.134 | CHANGED | rc=0 >>
hello | grep -o e
6.4.2、script 模块
将管理节点上的脚本传到被管理节点 (远程服务器) 上进行执行,理论上此模块的执行完全不需要被管理服务器上有 Python。
示例:
[root@localhost ansible]# echo "touch /tmp/testfile" > /root/a.sh
[root@localhost ansible]# ansible webservers -i hosts -m script -a "/root/a.sh"
192.168.200.134 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.200.134 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.200.134 closed."
],
"stdout": "",
"stdout_lines": []
}
[root@localhost ansible]# ansible webservers -i hosts -m shell -a "ls -l /tmp"
192.168.200.134 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 0 Dec 18 21:23 testfile
6.4.5、yum 模块
等同于 Linux 上的 yum 命令,对远程服务器上 RPM 包进行管理,常用参数如下:
name
要安装的软件包名,多个软件包以 ( , ) 隔开。state
对当前指定的软件安装,移除操作 (present installed latest absent removed)。present
确认已经安装,但不升级。installed
确认已经安装。- latest 确保安装,且升级为最新。
- absent 和 removed 确认已删除。
6.4.5.1、安装一个软件包
[root@localhost ansible]# ansible webservers -i hosts -m yum -a "name=nginx state=present"
[root@localhost ansible]# ansible webservers -i hosts -m yum -a "name=nginx state=installed"
[root@localhost ansible]# ansible webservers -i hosts -m yum -a "name=nginx state=latest"
# 检查是否安装
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m shell -a "nginx -version"
192.168.200.134 | CHANGED | rc=0 >>
nginx version: nginx/1.20.1
6.4.5.2、移除一个软件包
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m yum -a "name=nginx state=absent"
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m yum -a "name=nginx state=removed"
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m shell -a "nginx -version"
192.168.200.134 | FAILED | rc=127 >>
/bin/sh: nginx: command not foundnon-zero return code
6.4.5.3、安装一个软件包组
[root@manager ~]# ansible all -i /etc/ansible/hosts -m yum -a "name='@Developmenttools' state=present"
6.4.6、systemd 模块
CentOS6 之前的版本使用 service 模块,使用 ansible-doc service
命令查看帮助信息。
管理远程节点上的 systemd 服务,就是由 systemd 所管理的服务,常用参数如下
daemon_reload
:重新载入 systemd , 扫描新的或有变动的单元,值为 yes。enabled
:是否开机自启动 yes | no。name
:必选项,服务名称,比如 httpd , vsftpd 等。state
:对当前服务执行启动,停止,重新加载等操作 (started , stopped , restarted , reloaded)。
6.4.6.1、Example : 重新加载 systemd
[root@localhost ~]# ansible webservers -i /etc/ansible/hosts -m systemd -a "daemon_reload=yes"
192.168.200.134 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"name": null,
"status": {}
}
6.4.6.2、Example : 启动 nginx
[root@localhost ~]# ansible webservers -i /etc/ansible/hosts -m systemd -a "name=nginx state=started"
6.4.6.3、Example : 关闭 nginx
[root@localhost ~]# ansible webservers -i /etc/ansible/hosts -m systemd -a "name=nginx state=stopped"
6.4.7、group 模块
对被管理节点的组进行管理,常用参数如下:
name
:组名称,必须的。system
:是否为系统组,yes | no。
6.4.7.1、Example : 创建普通组 db_admin
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m group -a "name=db_admin"
192.168.200.133 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 1001,
"name": "db_admin",
"state": "present",
"system": false
}
6.4.8、user 模块
用于对被管理节点上的用户进行管理,常用参数如下 :
name
:必须的参数,指定用户名。password
:设置用户的密码,这里接受的是一个加密的值,因为会直接存到 shadow , 默认不设置密码。update_password
:加入设置的密码不同于原密码,则会更新密码,在 1.3 版本中被加入。home
:指定用户的家目录。shell
:设置用户的 shell。comment
:用户的描述信息。create_home
:在创建用户时,是否创建其家目录,默认创建,加入不创建,设置为 no , 在 2.5 版本之前使用 createhome 参数。group
:设置用户的主组。groups
:将用户加入到多个其他组中,多个用逗号隔开,默认会把用户从其他已经加入的组中删除。append
:值为 yes | no , 和 groups 配合使用,值为 yes 时,不会把用户从其他已经加入的组中删除。system
:值为 yes 时,会创建一个系统账户。expires
:设置用户的过期时间,值为时间戳,会转为天数后,放在 shadow 的第 8 个字段里。generate_ssh_key
:设置为 yes 时,会为用户生成密钥,这不会覆盖原来的密钥。ssh_key_type
:指定用户的密钥类型,默认 rsa , 具体的类型取决于被管理节点。state
:删除或添加用户,yes 为添加,absent 为删除,默认值为 yes。remove
当与state=absent
一起使用时,删除一个用户及关联的目录,比如家目录,邮箱目录,可选的值为 yes/no。
先生成加密密码:
[root@localhost ~]# pass=$(echo “LML123456” | openssl passwd -l -stdin)
[root@localhost ~]# echo $pass
111MQBJpWBh$krH/eQgBQcMpyDMKxVpS.0
6.4.8.1、Example : 创建账号,设置密码
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m user -a "name=foo password=${pass}"
6.4.8.2、Example : 创建账号,设置密码,改密钥类型
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m user -a "name=Dragon password=${pass} ssh_key_type=ecdsa"
6.4.8.3 Example : 创建账号,设置密码,有效期,加组
创建 Cai 用户,并设置其有效期到 2024_4_15 日,加入到 db_admin 组中。
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m user -a "name=Cai password=${pass} group=db_admin append=yes"
6.4.9、file 模块
file 模块主要用于远程主机上的文件操作,常用参数:
group
:定义文件 / 目录的属组。mode
:定义文件 / 目录的而权限。owner
:定义文件 / 目录属组。path
:必选项,操作文件 / 目录 的路径。recurse
:递归的设置文件的属性,只对目录有效。src
:要被链接 (软/硬) 的源文件的路径,值用于 state=link 的情况。dest
:被链接到的路径,只应用于 state=link 的情况。state
:对文件执行什么操作。directory
:如果目录不存在则创建目录。file
:文件不存在则不不会被创建,存在则返回文件的信息,常用于检查文件是否存在。link
:创建软连接。hard
:创建硬链接。touch
:如果文件不存在,则会创建一个新的文件,如果文件或目录存在,则更新其最后修改时间。absent
:删除目录,文件或者取消链接。
6.4.9.1、Example : 文件操作
# 创建一个文件
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/foo.conf state=touch"
# 改变文件所有者及权限
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/foo.conf owner=nobody group=nobody mode=0644"
# 创建一个软连接
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "src=/tmp/foo.conf dest=/tmp/link.conf state=link"
# 创建一个目录
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/test_dir state=directory"
# 取消一个链接
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/link.conf state=absent"
# 删除一个文件
[root@localhost ~]# ansible all -i /etc/ansible/hosts -m file -a "path=/tmp/foo.conf state=absent"
6.4.10、cron 模块
管理远程节点的 CRON 服务,等同于 Linux 中的计划任务,常用参数如下。
注意:使用 Ansible 创建的计划任务,是不能使用本地 crontab -e 去编辑,否则 Ansible 无法再次操作此计划任务。
name
:指定一个 cron job 的名字,一定要指定,便于日后删除。minute
:指定分钟,可以设置成 (0-59 , * , /2 等) 格式,默认是 * , 也就是每分钟。hour
:指定小时,可以设置达成 (0-23 , * , */2 等) 格式,默认是 * , 也就是每小时。day
:指定天,可以设置成 (1-31 , * , */2 等) 格式,默认是 * , 也就是每天。month
:指定月份,可以设置成 (1-12 , * , */2 等) 格式,默认是 * , 也就是每周。weekday
:指定星期,可以设置成 (0-6 for Sunday-Saturday , * 等) 格式,默认是 * , 也就是每天。job
:要执行的内容,通常可以写个脚本,或者一段内容。state
:指定这个 job 的状态,可以是新增 (present) , 或者是删除 (absent) , 默认为 (present)。
6.4.10.1、Example 1 : 创建一个 cron job 任务
[root@manager ~]# ansible all -i /etc/ansible/hosts -m cron -a "name=newJob minute='0' job='ls -alh > /dev/null'"
验证
[root@host1 ~]# crontab -l
#Ansible: newJob
0 * * * * ls -alh > /dev/null
6.4.10.2、Example 2 : 删除一个 cron job 任务
[root@manager ~]# ansible all -i /etc/ansible/hosts -m cron -a "name=newJob state=absent"
6.4.11、debug 模块
6.4.11.1、Example 1 : 打印变量
debug 模块主要用于调试时使用,通常的作用是将一个变量的值打印出来,常用参数如下:
var
:直接打印一个指定的变量值。msg
:打印一段可以格式化的字符串。
# 直接打印一个变量 (-e 是传入变量)
[root@manager ~]# ansible all -i /etc/ansible/hosts -m debug -a "var=role" -e "role=web"
# 打印带字符串的 变量
[root@manager ~]# ansible all -i /etc/ansible/hosts -m debug -a "msg='role is {{role}}'" -e "role=web"
6.4.12、template 模块
template 模块使用了 jinjia2 格式作文文件模板,可以进行文档内变量的替换。
它的每次使用都会被 ansible 标记为 “changed” 状态,文件以 .j2 结尾,常用参数如下:
src
:指定 Ansible 控制端的文件路径。dest
:指定 Ansible 被控制端的文件路径。owner
:指定文件的属主。group
:指定文件的属组。mode
:指定文件的权限。backup
:创建一个包含时间错信息的备份文件,这样如果以某种方式损坏了原始文件,就可以将其复原,yes/no。
6.4.12.1、Example 1 : 传递文件 (带变量)
# 1. 创建一个 hello_world.j2 文件
[root@manager ~]# cat hello_world.j2
Hello {{var}} !
# 2. 执行命令,并且设置变量 var 的值为 world
[root@manager ~]# ansible all -i /etc/ansible/hosts -m template -a "src=hello_world.j2 dest=/tmp/hello_world.world" -e "var=world"
# 3. 在被控主机上验证
Hello world !
6.4.13、lineinfile 模块
在被管理节点上,使用正则匹配的方式对目标文件的一行内容修改删除等操作。
如果是一个文件中把所有匹配到的多行进行统一处理,参考 replace 模块。
如果相对一个文件进行一次性 添加 / 更新 / 删除等多行内容操作,参考 blockinfile 模块。
常用参数如下:
path
:目标文件路径,必须的。state
:可选值 present 替换 (默认 | absent 删除。regexp
:在文件的每一行中查找的正则表达式,对于 state=present , 进找到的最后一行将被替代。line
:要在文件中插入/替换的行,需要 state=present。create
:文件不存在时,是否要创建文件并添加内容,yes/no。
6.4.13.1、Example 1 : 删除被控节点文件里的某一条内容
[root@manager ~]# ansible all -i /etc/ansible/hosts -m lineinfile -a "path=/etc/sudoers regexp='^% wheel' state=absent"
6.4.13.2、Example 1 : 关闭远程主机的 selinux
[root@manager ~]# ansible all -i /etc/ansible/hosts -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=disabled' state=present"
七、Ansible-Playbook
Ad-Hoc 的问题:AD-HOC 每次只能在被管理节点上执行简单的命令。
而日常工作中,我们往往面临的是一系列复杂的操作,例如我们可能需要安装软件,更新配置,重启服务等等一系列操作的组合,此时 Ad-Hoc 有些力不从心,使用 PLAYBOOK 可以帮助我们解决这个问题。
7.1、什么是 PalyBook
Playbook 通常被大家翻译成剧本。
可以认为它是 Ansible 自定义的一门语言 (可以将 Playbook 比作 Linux 中的 shell) , 而 Ansible 中的 Module 可以比作为 Linux 中的各种命令。
7.2、YAML 学习
安装 pip 对 yaml 文件格式进行检查。
yum install python2-pip
7.2.1、YAML 特点
# YAML 文件以 # 为注释
# YAML 文件以 .yml 或 .yaml 结尾
# YAML 文件以 --- 开始,以... 结束,但是开始和结束标志都是可选的
7.2.2、基本语法
- 大小写敏感。
- 使用缩进表示层级关系,一般规范 2 个空格。
- 缩进时使用 tab 键,还是空格 一定要达到统一,建议使用空格。
- 相同层级的元素必须左侧对齐。
YAML 支持的数据结构有三种:
- 字符串
- 列表
- 字典
7.2.2.5、校验 YAML 语句
将 YAML 文件,通过 Python 的 YAML 模块进行验证:
# 安装 python2-pip
[root@manager ~]# yum install python2-pip
# 安装 pyyaml
[root@manager ~]# pip install pyyaml
# cat test.yaml
---
- red
- green
- blue
...
# 对 YAML 格式文件进行检验
[root@manager ~]# python -c 'import yaml,sys; print yaml.load (sys.stdin)' < test.yaml
['red', 'green', 'blue']
7.3、定义一个 Playbook
一个 Playbook 是由一个或多个 Play 构成,那么一个含有多个 Play 的 Playbook 结构上应该是如下的样子:
---
- key1: value1
key2: value2
key3: value3
...
一个含有多个 Play 的 Playbook 结构山应该是如下的样子:
---
# 一个含有 3 个 Play 的伪 PlayBook 构成
- key1: value1
key2: value2
key3: value3
- key4: value1
key5: value2
key6: value3
- key1: value1
key2: value2
key3: value3
...
7.3.1、Play 的属性
Play 中的每一个 key , 比如 key1 , key2 等,这些 key 在 PlayBook 中被定义为 Play 的属性。
这些属性具有特殊意义,我们不能随意的自定义 Play 的属性,常用属性如下:
name
:每个 play 的名字,用于任务执行后的回显 (一定要写)。hosts
:每个 play 涉及的被管理服务器,通 ad hoc 中的 pattern。tasks
:每个 play 中具体要完成的任务,以列表的形式表达。become
:如果需要提权,则加上 become 相关属性。become_user
:若提权的话,提权到哪个用户上。remote_user
:指定连接用户,若不指定,则默认使用当前执行 ansible Playbook 的用户。- 等等
7.3.2、一个完整的剧本
最常规写法:
---
- name: the first play example
hosts: all
remote_user: root
tasks:
- name: install nginx packet
yum: name=nginx state=present
- name: copy nginx.conf to remote server
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
- name: start nginx service
service: name=nginx enabled=true state=started
...
tasks 属性中任务的多种写法:
# 以启动 nginx 服务,并增加开机启动为例
# 一行的形式
service: name=nginx enabled=true state-started
# 多行的形式
service:
name=nginx
enabled=true
state=started
# 多行字典的形式
service:
name: nginx
enabled: true
state: started
7.3.3、具有多个 Play 的 Playbook
---
- name: manage web servers
hosts: webservers
remote_user: root
tasks:
- name: install nginx packet
yum: name=nginx state=present
- name: copy nginx.conf to remote server
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
- name: start nginx server
service: name=nginx enabled=true state=started
- name: manager db servers
hosts: dbservers
tasks:
- name: update database config
copy: src=my.cnf dest=/etc/my.cnf
...
7.4、校验一个 PlayBook
下面校验的方法,只能校验 PlayBook 是否正确,而不能校验 YAML 文件是否语法正确。
之前 YAML 校验的方法:
[root@manager ~]# python -c 'import yaml,sys; print yaml.load (sys.stdin)' < test.yaml
PlayBook 校验:
[root@manager ~]# ansible-playbook myplaybook.yml --syntax-check
playbook: myplaybook.yml
7.5、运行一个 PlayBook
[root@manager ~]# ansible-playbook myplaybook.yml
7.6、如何单步跟从调试 PlayBook
ansible-playbook myplaybook.yml --step
7.7、如何测试运行 PlayBook
// 会执行完整个 PlayBook , 但是所有 Task 中的行为都不会在远程服务器上执行,所有执行都是模拟行为
# ansible-playbook myplaybook.yml -C
//-C 为大写字母 C
八、Ansible 变量
8.1、Ansible 变量介绍
变量由 字母 数字 下划线 组成。
但 只能以字母开头,保留关键字不能作为变量名称。
8.2、变量类型
根据变量的作用范围,大体的将变量分为:
- 全局变量
- 剧本变量
- 资产变量
但这只是一个比较除粗糙的划分,不能囊括 Ansible 中的所有变量,下面将分别从这三种变量入手,去介绍变量的使用。
8.2.1、全局变量
全局变量 是 我们使用 ansible 或者使用 ansible-playbook 时,手动通过 -e 参数传递给 Ansible 的变量。
通过 ansible 或 ansible-playbook 的 help 帮助,可以获取具体格式使用方式。
普通的 key-value 模式:
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m debug -a "msg='name is {{key}}'" -e "key='LiuMenglong'"
192.168.200.133 | SUCCESS => {
"msg": "name is LiuMenglong"
}
传递一个 YAML/JSON
的形式 (他们的最终形式必须是字典):
# 指定时必须加 @
[root@manager ~]# cat a.json
{"name": "LiuML", "age": "16"}
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m debug -a "msg='name is {{name}} , age is {{age}}'" -e @a.json
[WARNING]: Found variable using reserved name: name
192.168.200.133 | SUCCESS => {
"msg": "name is LiuML , age is 16"
}
[root@manager ~]# cat b.yaml
---
name: lisi
age: 33
...
[root@manager ~]# ansible webservers -i /etc/ansible/hosts -m debug -a "msg='name is {{name}} , age is {{age}}'" -e @b.yaml
[WARNING]: Found variable using reserved name: name
192.168.200.133 | SUCCESS => {
"msg": "name is lisi , age is 33"
}
8.2.2、剧本变量
在 Playbook 中使用的变量叫做剧本变量,他的定义由多种方式,我们使用两种,文件内定义即引用文件。
8.2.2.1、通过 PLAY 属性 vars 定义
---
- name: test play vars
hosts: all
vars:
user: lisi
home: /home/lisi
...
8.2.2.2、通过 PLAY 属性 vars_file 定义
---
- name: test play vars
hosts: all
vars_files:
- vars/users.yaml
...
cat vars/users/yaml
---
user: lilei
home: /home/lilei
...
8.2.2.3、如何在 Playbook 中使用这些变量
在 PlayBook 中使用变量时,使用 {{ 变量名 }}
来使用变量,在使用变量是,大部分情况外侧要加双引号即 “{{ 变量 }}”
。
Example1:
---
- name: Test Vars using in playbook
hosts: all
vars:
user: lisi
home: /home/lisi
tasks:
- name: create the users {{user}}
user: name={{user}} home={{home}}
...
[root@manager ~]# ansible-playbook 123456.yaml -C
[root@manager ~]# ansible-playbook 123456.yaml
注意事项:在下面的例子 (字典) 中,{{ 变量 }} 外一定要加双引号,否则会 yaml 解析错误
Example2
---
- name: Test Vars using in playbook
hosts: all
vars:
user: lisi
home: /home/lisi
tasks:
- name: create the users {{user}}
user:
name: "{{user}}"
home: "{{home}}"
...
8.2.3、资产变量
资产变量是和资产紧密相关的一种变量,资产变量分为 主机变量 和 主机组变量,分别针对单个主机和一组主机。
8.2.3.1、主机变量
# cat hostsandhostvars
[webservers]
192.168.200.133 user=lisi age=18
192.168.200.134
验证:
[root@localhost ansible]# ansible webservers -i /etc/ansible/hostsandhostvars -m debug -a "var=user"
192.168.200.133 | SUCCESS => {
"user": "lisi"
}
192.168.200.134 | SUCCESS => {
"user": "VARIABLE IS NOT DEFINED!"
}
8.2.3.2、主机组变量
主机变量优先于主机组变量。
# cat hostsandhostvars
[webservers]
192.168.200.133 user=lisi age=18
192.168.200.134
[webservers:vars]
user=tom
验证:
[root@localhost ansible]# ansible webservers -i /etc/ansible/hostsandhostvars -m debug -a "var=user"
192.168.200.133 | SUCCESS => {
"user": "lisi"
}
192.168.200.134 | SUCCESS => {
"user": "tom"
}
8.2.3.3、变量的继承
变量是可以继承的:
# cat host_v3
[dbservers]
192.168.200.133
[webservers]
192.168.200.134
[allserver]
[allserver:children]
webservers
dbservers
[allserver:vars]
user=lml
验证:
[root@localhost ansible]# ansible webservers -i /etc/ansible/host_v3 -m debug -a "var=user"
192.168.200.134 | SUCCESS => {
"user": "lml"
}
评论