文章目录
介绍
Ansible是一个IT自动化工具。它能配置系统、部署软件、编排更复杂的IT任务,如连续部署或零停机时间滚动更新。
Ansible用Python编写,尽管市面上已经有很多可供选择的配置管理解决方案(例如Salt,Puppet,Chef等),但它们各有优劣,而Ansible的特点在于它的简洁。让Ansible在主流的配置管理系统中与众不同的一点便是,它并不需要你在想要配置的每个节点上安装自己的组件。同时提供的另一个优点,如果需要的话,你可以在不止一个地方控制你的整个基础架。
一、安装
yum install -y epel-release
yum install -y ansible
二、管理节点(192.168.1.130)与被管理节点(192.168.1.129)建立ssh信任关系
管理节点创建密钥对,敲回车
ssh-keygen -t rsa
三、将本地的公钥传输到被管理节点
每个管理节点都需要被传递
过程需要被管理节点(192.168.1.129)的用户名(root)及密码
[root@ansible ~]# ssh-copy-id root@192.168.1.129
[root@ansible ~]# ssh 'root@192.168.1.129'
Last login: Sun Jul 25 22:31:34 2021 from 192.168.1.10
[root@localhost-2 ~]# #已经登录到被管理节点了,exit退出
小插曲:使用ssh传递秘钥之后,使用ssh复制文件
# 从本地复制文件到远程主机,-r表示递归
scp -r /httpd.conf root@远程主机ip:/root
# 从远程主机拉取文件到本地
scp -r root@远程主机ip:/root /httpd.conf
快速入门
测试场景一
管理节点 192.168.1.130 被管理节点 192.168.1.128 192.168.1.129
管理节点和被管理节点之间的节点已经打通ssh信任关系
在管理节点上,测试与所有被管理节点的网络连通信
[root@ansible ~]# ansible all -i 192.168.1.128,192.168.1.129 -m ping
192.168.1.129 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.1.128 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
注意,-i 参数后面接的是一个列表(list),因此当为一个被管理节点时,我们后面一点要加个英文逗号,告知是list
测试场景二
在管理节点上确保文件/tmp/a.conf 发布到所有被管理节点
touch /tmp/a.conf
ansible all -i 192.168.1.128,192.168.1.129 -m copy -a "src=/tmp/a.conf dest=/tmp/a.conf"
选项参数解析
all 在 ansible中,将其叫做 pattern,即匹配。我通常称它为资产选择器。就是匹配资产(参数指定)中的一部分。这里的是匹配所有指定的所有资产。将在下面资产部分详细阐述。
-i 指定 Ansible的资产,也就是资产清单文件的位置
-m 指定要运行的模块比如这里的ping模块和copy模块
-a 指定模块的参数,这里模块ping没有指定参数。模块copy指定了src和dest参数。
总结:ansible就是用什么模块,让谁去干什么事情
ansible资产
ansible静态资产
自定义资产,默认文件在/etc/ansible/hosts下
## green.example.com 其他组
## 192.168.100.10
## [webservers] webserver组
## alpha.example.org
## 192.168.1.110
## [dbservers] dbserver组
## db01.intranet.mydomain.net
## 10.25.1.57
## [all_servers] 所有组
## [all_servers:children]
[root@ansible ~]# vim /etc/ansible/hosts
[db_servers]
192.168.1.130
192.179.1.131
[web_servers]
192.168.1.128
192.168.1.129
列出所有资产
[root@ansible ~]# ansible all --list-hosts
hosts (4):
192.168.1.128
192.168.1.129
192.168.1.130
192.179.1.131
列出选定资产(如web_servers)
[root@ansible ~]# ansible web_servers --list-hosts
hosts (2):
192.168.1.128
192.168.1.129
资产选择器
有时操作者希望只对资产中的一部分服务器进行操作,而不是资产中所有服务器,此时可以使用ansible资产选择器PATTERN
语法格式 ansible PATTERN -i inventory.ini -m module -a argument
选择一台或几台服务器
ansible 1.1.1.1 --list-hosts
ansible 1.1.1.1* --list-hosts
1.1.1.1*可以匹配1.1.1.13等
ansible 后面可以接ip,域名以及多个ip(逗号隔开),必须根据资产里的服务器写,即使/etc/hosts里有域名解析也不能用ip对应的域名
选择一组
ansible web_servers --list-hosts
ansible all_servers --list-hosts
在all_servers里有两个组有同一ip,可以去重
使用逻辑匹配
web_servers和db_servers的并集(两个组内所有的主机)
ansible 'web_servers:db_servers' --list-hosts
web_servers和db_servers的交集(两个组内共有的主机)
ansible 'web_servers:&db_servers' --list-hosts
在web_servers中,但是不在db_server中
ansible 'web_servers:!db_servers' --list-hosts
Ansible Ad-Hoc命令
Ad-hoc命令是什么呢?这其实是一个概念性的名字,是相对于写Ansibleplaybook来说的.类似于在命令行敲入shell命令和写shell scripts两者之间的关系。可以用于执行一些临时命令。
如果我们敲入一些命令去比较快的完成一些事情,而不需要将这些执行的命令特别保存下来,这样的命令就叫做ad-hoc命令。
Ansible提供两种方式去完成任务,一 是ad-hoc命令,一是写Ansibleplaybook。 前者可以解决一些简单的任务,后者解决较复杂的任务,比如做配置管理或部署。
1、命令格式
在快速入门中执行的Ansible命令,类似于批量执行命令。在Ansible中统称Ansible Ad-Hoc
语法格式
ansible pattern [-i inventory] -m module -a argument
pattern 资产选择器,如[web_servers]
-i 指定资产清单文件的位置,如果资产清单不放在默认文件,就要使用-i参数指定文件路径
-m 指定本次Ansible ad-hoc要执行的模块。可以类别与shell中的命令
-a 模块的参数,可以类比成shell中的命令参数
2、模块类型
Ansible模块分三种类型:核心模块(core module)、附加模块(extra module)及用户自定义模块(consume module)。
核心模块是由Ansible的官方团队提供的。
附加模块是由各个社区提供的。例如: OPENSTACK社区、DOCKER社区等等。
当核心模块和附加模块都无法满足你的需求时,用户可以自定义模块。
默认情况下,在安装Ansible的时候, 核心模块和附加模块都已经安装而无需用户干预。
3、联机帮助
Ansible的模块不需要去熟记,掌握。我们可以使用Ansible的帮助文档。
常用帮助参数
列举出所有的核心模块和附加模块
ansible-doc -l
查询某个模块的使用方法
ansible-doc modulename
查询某个模块的使用方法,比较简洁的信息
ansible-doc -s modulemane
常用模块
环境:被管理主机ip:192.168.1.128 192.168.1.129,资产文件在/root/hosts
资产保存在hosts目录中
[root@ansible ~]# vim /etc/ansible/hosts
[db_servers]
192.168.1.128
[web_servers]
192.168.1.129
command & shell 模块
两个模块都是在远程服务器上去执行命令的
但command模块是ad-hoc的默认 模块,在执行ad-hoc时,若不指定模块的名字则默认使用此模块
[root@ansible ~]# ansible all -a "echo 'hello'"
## 相对路径
192.168.1.129 | CHANGED | rc=0 >>
hello
192.168.1.128 | CHANGED | rc=0 >>
hello
[root@ansible ~]# ansible all -m shell -a "echo 'hello'"
192.168.1.128 | CHANGED | rc=0 >>
hello
192.168.1.129 | CHANGED | rc=0 >>
hello
两个模块的差异
默认模块:command模块无法执行SHELL的内置命令和特性
shell 模块可以执行SHELL的内置命令和特性(比如管道符)
script模块
将管理节点上的脚本传递到被管理节点(远程服务器)上进行执行。
管理节点上的一个脚本
创建一个脚本
echo "touch /tmp/testfile" > /root/a.sh
将管理节点上的脚本传递到被管理节点上进行执行
ansible web_servers -m script -a "/root/a.sh"
查看
ansible web_servers -m shell -a "ls -l /tmp/"
192.168.1.129 | CHANGED | rc=0 >>
总用量 0
-rw-r--r-- 1 root root 0 7月 26 14:13 testfile
copy模块
copy模块主要用于管理节点和被管理节点之间的文件拷贝,经常使用到以下参数:
src 指定拷贝文件的源地址
dest 指定拷贝文件的目标地址
backup 拷贝文件前,若源文件发现变化,则对目标文件进行备份
owner 指定新拷贝文件的所有者
group 指定新拷贝文件的所有组
mod 指定新拷贝文件的权限
ansible web_servers -m copy -a "src=/tmp/testfile dest=/tmp/testfile"
下次再copy时,若被管理节点上的testfile文件被修改,那么testfile修改文件被覆盖
加上参数backup=yes,则被修改文件将备份。
ansible webservers -i hosts -m copy -a "src=/tmp/testfile dest=/tmp/testfile backup=yes"
## copy文件的同时对文件进行用户及用户组的设置
ansible web_servers -m copy -a "src=/tmp/testfile dest=/tmp/testfile ower=nobody group=nobody"
copy文件的同时对文件权限进行设置,用户及用户组不会被覆盖。
ansible webservers -m copy -a "src=/tmp/testfile dest=/tmp/testfile mode=0755"
yum_repository模块
添加yum仓库(给被管理节点添加yum仓库),常用参数:
name 仓库名称,就是仓库文件中第一行的中括号的名称,必须的参数。
description 仓库描述信息,添加时必须的参数
baseurl yum存储库"repodata"目录所在目录的URL,添加时必须的参数。
它也可以是多个URL的列表。
file 仓库文件保存到被管理节点的文件名,不包含.repo。默认是name的值。
state present确认添加仓库文件, absent确认删除仓库文件。
gpgcheck 是否检查GPG yes|no,没有默认值,使用/etc/yum.conf中的配置。
添加epel源
ansible web_servers -m yum_repository -a "name=epel baseurl='http://http://mirrors.aliyun.com/centos/$releasever/centosplus/$basearch/' description='EPEL YUM repo'"
删除epel源
ansible web_servers -m yum_repository -a "name=epel state=absent"*
yum模块
等同于linux上的YUM命令,对远程服务器的rpm包进行管理。常用参数:
name 要安装的软件包名,多个软件包以英文逗号(,)隔开
state 对当前指定的软件安装、移除操作(present installed latest absent removed)
支持的参数:
-present 确认已经安装,但不升级
-installed 确认已经安装
-latest 确保安装,且升级为最新
-absent和removed 确认已移除
安装一个软件包
ansible webservers -m yum -a "name=nginx state=latest"
安装一个软件包组
ansible webservers -m yum -a "name='@Development tools' state=present"
systemd模块
Centos6之前的版本使用service模块
请使用ansible-doc service命令自行查看帮助信息
管理远程节点上的systemd服务,就是由systemd所管理的服务,常用参数:
daemon_reload 重新载入systemd, 扫描新的或有变动的单元
enabled 是否开机自启动yes|no
name 必选项,服务名称,比如httpd vsftpd
state 对当前服务执行启动、停止、重启、重新加载等操作(started/stopped/restart/reloaded)
重新加载webservers里的firewalld服务
ansible webservers -m systemd -a "name=firewalld state=reloaded"
group模块
在被管理节点上,对组进行管理,常用参数:
name 组名称,必须的
system 是否为系统组 yes/no,默认是no
state 创建或删除 present/absent 默认是present
创建普通组db_admin
ansible db_servers -m group -a "name=db_admin"
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 删除或添加用户,present为添加, absent为删除;默认值present
remove 当与 state=absent一起使用,删除一个用户及关联的目录,比如家目 录,邮箱目录。可选的值为:yes/no
创建用户设置密码
先生成密码,openssl是生成密码工具(MD5加密) -1为数字一
[root@ansible ~]# pass=$(echo "123456" | openssl passwd -1 -stdin)
[root@ansible ~]# echo $pass
$1$n6qfuRB4$alPJC8R2UgpmJi7KEKzVg0
执行ansible创建用户foo并设置密码
ansible webservers -m user -a "name=foo password=${pass}"
被管理节点的密文位置
tail -1 /etc/shadow
创建用户goo,并且为其创建密钥对,密钥类型为:ecdsa
ansible dbservers -m user -a "name=goo generate_ssh_key=yes ssh_ key__type=ecdsa
创建用户tom,并且设置有效期到2021年7月28日加入到组db_admin,不改变用户原有加入的组
[root@localhost-1 ~]# tail -2 /etc/group #被管理节点上创建db_admin和db2组
db_admin:x:1003:
db2:x:1005:
ansible dbservers -m user -a "name=tom expires=$(date +%s -d 20210728) groups=db_admin append=yes"
18834是指你哪一天创建的,18835是指到期时间
[root@localhost-1 ~]# tail -1 /etc/shadow
tom:!!:18834:0:99999:7::18835:
[root@localhost-1 ~]# id tom
uid=1003(tom) gid=1004(tom) 组=1004(tom),1003(db_admin)
不使用append参数,加入的db_admin组被覆盖
ansible dbservers -m user -a "name=tom groups=db2"
[root@localhost-1 ~]# id tom
uid=1003(tom) gid=1004(tom) 组=1004(tom),1005(db2)
使用append参数,指不改变原有的组,追加db_admin组
ansible dbservers -m user -a "name=tom groups=db_admin append=yes"
[root@localhost-1 ~]# id tom
uid=1003(tom) gid=1004(tom) 组=1004(tom),1003(db_admin),1005(db2)
删除用户,state和remove结合使用,删除用户及家目录
[root@ansible ~]# ansible webservers -m user -a "name=tom state=absent remove=yes "
file模块
file模块主要用于远程主机上的文件操作,常用参数:
owner 定义文件/目录的属主
group 定义文件/目录的属组
mode 定义文件/目录的权限
path 必选项,定义文件/目录的路径
recurse 递归的设置文件的属性,只对目录有效
src 链接(软/硬)文件的源文件的路径,只应用于 state=link的情况
dest 链接文件的路径,只应用于 state=link的情况
state
-directory 如果目录不存在,创建目录
-file 文件不存在,则不会被创建,存在则返回文件的信息,常用于检查文件是否 存在。
-link 创建软链接
-hard 创建硬链接
-touch 如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新 其最后修改时间
-absent 删除目录、文件或者取消链接文件
创建一个文件
ansible webservers -m file -a "path=/tmp/test.java state=touch"
修改文件所有者及权限
ansible webservers -m file -a "path=/tmp/test.java owner=nobody group=nobody mode=0644"
创建一个软链接
ansible webservers -m file -a "src=/tmp/test.txt dest=/tmp/link.txt state=link"
## 取消软链接
ansible webservers -m file -a "path=/tmp/link.txt state=absent"
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)
date
// 计算 3 ⼩时之后是⼏点⼏分
date +%T -d '3 hours'
// 任意⽇期的前 N 天,后 N 天的具体⽇期
date +%F -d "20190910 1 day"
date +%F -d "20190910 -1 day"
// 计算两个⽇期相差天数, ⽐如计算⽣⽇距离现在还有多少天
d1=$(date +%s -d 20180728)
d2=$(date +%s -d 20180726)
echo $(((d1-d2)/86400))
新建⼀个 CRON JOB 任务
ansible all -m cron -a "name='create new job' minute='0' job='ls -alh > /dev/null'"
删除⼀个 CRON JOB 任务,删除时,⼀定要正确指定job 的name参数,以免误删除。
ansible all -m cron -a "name='create new job' state=absent"
debug模块
debug 模块主要⽤于调试时使⽤,通常的作⽤是将⼀个变量的值给打印出来。常⽤参数**😗*
var 直接打印⼀个指定的变量值
msg 打印⼀段可以格式化的字符串
这⾥引⼊了变量,我们只需了解 debug 模板的使⽤即可。在学习变量、剧本时,我们会对它有更深刻的理解
[root@ansible ~]# ansible webservers -m debug -a "var=role" -e "role=web"
192.168.1.129 | SUCCESS => {
"role": "web"
}
[root@ansible ~]# ansible webservers -m debug -a "msg='role is {{role}} '" -e "role=web"
192.168.1.129 | SUCCESS => {
"msg": "role is web "
}
template模块
template 模块使⽤了Jinjia2格式作为⽂件模版,可以进⾏⽂档内变量的替换。⽂件以 .j2 结尾。
常⽤参数**😗*
src 指定 Ansible 控制端的⽂件路径
dest 指定 Ansible 被控端的⽂件路径
owner 指定⽂件的属主
group 指定⽂件的属组
mode 指定⽂件的权限
backup 创建⼀个包含时间戳信息的备份⽂件,这样如果您以某种⽅式错误地破坏了原始⽂ 件,就可以将其恢复原状。yes/no
⽤法其实和 copy 模块基本⼀样, template 模块的强⼤之处就是使⽤变量替换,就是可以把传递给 Ansible 的变量的值替换到模板⽂件中。
[root@ansible tmp]# cat hello.j2
hello {{var}}!
[root@ansible tmp]# ansible webservers -m template -a "src=/tmp/hello.j2 dest=/tmp/hello.txt" -e "var=world"
[root@localhost-2 tmp]# cat hello.txt
hello world!
lineinfile模块
在被管理节点上,⽤正则匹配的⽅式对⽬标⽂件的⼀⾏内容修改删除等操作。如果是在⼀个⽂件中把所有匹配到的多⾏都进⾏统⼀处理,请参考replace 模块。如果想对⼀个⽂件进⾏⼀次性添加/更新/删除多⾏内容等操作,参考blockinfifile模块
path 被管理节点的⽬标⽂件路径, 必须。
state 可选值absent 删除 |present 替换(默认值)。
regexp 在⽂件的每⼀⾏中查找的正则表达式。对于 state=present ,仅找到的最后⼀⾏将 被替换。
line 要在⽂件中插⼊/替换的⾏。需要state=present。
create ⽂件不存在时,是否要创建⽂件并添加内容。yes/no
删除被控节点⽂件⾥的某⼀条内容,删除wheel开头的一行内容
ansible dbservers -m lineinfile -a "path=/etc/sudoers regexp='^%wheel' state=absent"
替换某一行,替换开头为SELINUX的一行内容
ansible dbservers -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=disabled' state=present"
blockinfile模块
对目标文件进行多行的添加/更新/删除操作,常用参数:
path ⽬标⽂件路径
block ⽂件中被操作的块内容
state 块内容如何处理,absent 删除, present 添加/更新(默认值)
## 向⽂件/etc/ssh/sshd_config的最后添加⼏⾏内容添加的内容是
Match User ansible-agent
PasswordAuthentication no
ansible dbservers -m blockinfile -a "path=/etc/ssh/sshd_config block='Match User ansible-agent\nPasswordAuthentication no'"
注意:\n 是换⾏符的意思。
更新之前的内容
ansible dbservers -m blockinfile -a
"path=/etc/ssh/sshd_config block='Match User ansible-agent\nPasswordAuthentication yes'"
删除⽂件中的连续出现⼏⾏内容
ansible dbservers -m blockinfile -a
"path=/etc/ssh/sshd_config block='Match User
ansible-agent\nPasswordAuthentication yes' state=absent"
PlayBook
概念
它是ansible自定义的一门语言(可以将playbook比作linux中的shell,而ansible中的module可以比作linux的各种命令。)
YAML学习
playbook遵循yaml的语法格式
1、特点
YAML文件以 # 为注释符;以.yaml或.yml结尾;以—开始,以…结束,但开始和结束的标志都是可选的。
2、基本语法
大小写敏感;
使用缩进表示层次关系;
缩进时是使用Tab键还是使用空格一 定要达到统一,建议使用空格;
相同层级的元素必须左侧对齐即可。
支持的数据结构有三种:字符串,列表,字典
YAML中的字符串,可以不使用双引号或单引号
this is a string
若一行写不完你要表述的内容,可以进行折行
列表
可以理解为python中的list,或C语言的数组
定义:
- red
- blue
转换为python是['red','blue']
字典
可以理解为python中的dict
定义:key+冒号(:)+空格+值(value),即:key: value
name: useing ansible
code: 1234
转为python的dict是{'name': 'useing ansible','code': '1234'}
混合结构
---
class:
- name: stu1
num: 001
- name: stu2
num: 002
- name: stu3
num: 003
...
{'class':[{'name': 'stu1','num': '001'},{'name': 'stu2','num': '002'},{'name': 'stu3','num': '003'},...]}
3、验证yaml语法
将YAML文件,通过Python的YAML模块验证,若不正确则报错.若正确则会输出YAML里的内容。
注意使用时,一定确保安装了yaml软件包。
下载源码包:http : //pyyaml.org/download/libyaml/yaml-0.2.5.tar.gz。
要构建和安装 LibYAML,请运行
$ ./configure
$ make && make install
编写一个.yml文件
cat myyaml.yml
---
- red
- green
- blue
...
校验
python -c 'import yaml,sys; print yaml.safe_load(sys.stdin)' < myyaml.yml
['red', 'green', 'blue']
play定义
playbook是由一个或多个play组成的。
如何定义一个play:
1、每一个play都是有短横杆开始的
2、每一个play都是一个YAML字典格式
---
//一个含有3个playbook的伪playbook构成
- key1: value1
key2: value2
- key1: value1
key2: value2
- key1: value1
key2: value2
play属性
以上一小节中的Pay为基础,Pay中的每一个key,比如key1,key2等;这些key在 Play Book中被定义为Play的属性。
这些属性都具有特殊的意义我们不能随意的自定义Pay的属性。
接下来就来看看 Ansible本身都支持哪些Play属性。
常用属性:
name属性 每个play的名字
hosts属性 每个play涉及的被管理服务器,同 ad-hoc中的资产选择器
tasks属性 每个play中具体要完成的任务,以列表的形式表达
become属性 如果需要提权,则加上 become相关属性
become_user属性 若提权的话,提权到哪个用户上
remote user属性 指定连接到远程节点的用户,就是在远程服务上执行具体操作的用户。若不指定,则默认使用当前执行 ansible Playbook的用户
1、一个完整的剧本
2、tasks属性中任务的多种写法
以启动nginx服务,并增加开机启动为例
一行的形式:
service: name=nginx enable=true state=started
多行的形式
service:
name=nginx
enable=true
state=started
写成字典的形式
service:
name: nginx
enable: true
state: started
3、具有多个play的playbook
4、如何对playbook进行语法校验
vim myplaybook.yml
---
- name: manage web servers
hosts: webservers
remote_user: root
tasks:
- name: install nginx packge
yum: name=nginx state=present
- name: copy nginx.conf to remote server
copy: src=/root/nginx.conf dest=/etc/nginx/nginx.conf
- name: start nginx server
service:
name: nginx
enabled: true
state: started
...
校验playbook是否语法正确,注意:hosts和myplaybook都是用了相对路径
ansible-playbook myplaybook.yml --syntax-check
playbook: myplaybook.yml
运行playbook
ansible-playbook myplaybook.yml
如何单步跟从调试,每运行一个task就会询问一次
ansible-playbook myplaybook.yml --step
测试运行playbook(模拟是否出错)
ansible-playbook myplaybook.yml -C
Ansible变量
涉及到变量定义、控制结构的使用等特性
变量命名规则
变量的名字由字母、下划线和数字组成,必须以字母开头;
保留关键字不能作为变量名称。
变量类型
根据变量的作用范围大体的将变量分为:
- 全局变量;
- 剧本变量;
- 资产变量;
1、全局变量
是我们使用ansible或使用ansible-playbook时,手动通过-e参数传递给Ansible的变量,
通过ansible或ansible-playbook的help帮助,可以获取具体格式使用方法
传递一个YAML/JSON的形式(注意不管是YAML还是JSON,它们的最终格式一定要是一个字典)
cat a.json
{"net": "www.baidu.com","person": "zhangsan"}
或者
---
net: www.baidu.com
person: zhangsan
...
[root@ansible ~]# ansible webservers -m debug -a "msg='address is {{net}} the man is {{person}}'" -e @a.json
192.168.1.129 | SUCCESS => {
"msg": "address is www.baidu.com the man is zhangsan"
}
2、剧本变量
此种变量和playbook有关,定义在playbook中的。它的定义方式有很多,最常用的定义方式如下
通过play属性var定义
---
- name: test play vars
hosts: all
vars:
user: lilei
home: /home/lilei
通过play属性var_files定义
当通过var属性定义的变量很多时,这个play就会感觉很臃肿,此时我们可以将变量单独从play中抽离出来,形成单独的yaml文件
---
- name: test play vars
hosts: all
vars_files:
- vars/users.yml
# cat var/users.yml
name: lilei
home: /home/lilei
测试play属性var_files定义
[root@ansible ~]# cat test_vars.yml
user: lilei
home: /home/lilei
[root@ansible ~]# vim vars_files.yml
---
- name: test play vars
hosts: all
vars_files:
- /root/test_vars.yml
tasks:
- name: create the user {{ user }}
user:
name: "{{ user }}"
home: "{{ home }}"
...
[root@ansible ~]# ansible-playbook vars_files.yml -C
# PLAY RECAP ************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3、资产变量
在之前的课程中学习了资产。资产共分为静态资产和动态资产这一节中学习的资产变量,就是和资产紧密相关的一种变量。
资产变量分为主机变量和主机组变量,分别针对资产中的单个主机和主机组
在/root/下建一个资产清单
主机变量
[root@ansible ~]# cat hostsandhostvars
[webservers]
192.168.1.129 user=lilei port=3309
172.168.1.128
[root@ansible ~]# ansible 192.168.1.129 -i hostsandhostvars -m debug -a "msg='{{user}} {{port}}'"
192.168.1.129 | SUCCESS => {
"msg": "lilei 3309"
}
主机组变量
以下资产中,定义了一个组变量home,此变量将针对webservers这个主机组中的所有服务器有效
[root@ansible ~]# cat hostsandgroupvars
[webservers]
192.168.1.129 user=lilei
172.168.1.128
[webservers:vars] # 主机组里的变量会同时资产里生效。
home="/home/lilie" #1.129和1.128都会创建这个变量
当主机变量和组变量在同一个资产中发生重名的情况
[webservers]
192.168.1.129 user=lilei
172.168.1.128
[webservers:vars] # 主机组与主机的变量不同时
user=tom
[root@ansible ~]# ansible webservers -i hostsandgroupvars -m debug -a "var=user"
192.168.1.129 | SUCCESS => {
"user": "lilei"
}
192.168.1.128 | SUCCESS => {
"user": "tom"
}
得知:主机变量的优先级更高
在/root/下建一个资产清单
变量是否存在变量关系
[root@ansible ~]# vim host_v3
[webservers]
192.168.1.129
[dbservers]
192.168.1.128
[allservers]
[allservers:children]
webservers
dbservers
[allservers:vars]
user=lilei
[root@ansible ~]# ansible allservers -i host_v3 -m debug -a "var=user"
192.168.1.129 | SUCCESS => {
"user": "lilei"
}
192.168.1.128 | SUCCESS => {
"user": "lilei"
}
# 得知:变量存在继承关系
内置变量的说明
内置变量几乎都是以ansible_为前缀
ansible_ssh_host
将要连接的远程主机名与你想要设定的主机的别名不同的话,可通过此变量设置
ansible_ssh_port
ssh端口号.如果不是默认的端囗号,通过此变量设置
ansible_ssh_user
默认的ssh用户名
ansible_ssh_pass
ssh 密码(这种方式并不安全,官方强烈建议使用 --ask-pass或SSH密钥)
ansible_sudo_pass
sudo密码(这种方式并不安全,官方强烈建议使用--ask-sudo-pass)
ansible_sudo_exe (new in version 1.8)
sudo 命令路径(适用于1.8及以上版本)
ansible_ssh_private_key_ file
ssh 使用的私钥文件.适用于有多个密钥,而你不想使用SSH代理的情况.
ansible_python_interpreter
目标主机的python路径.适用于的情况:系统中有多个Python,或者命令路径不是"/usr/bin/python",比如,/usr/local/bin/python3
修改192.168.1.129的ssh的监听端口为2233后,发现不能到达
[root@ansible ~]# ansible allservers -i host_v3 -m shell -a "ls"
192.168.1.129 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: connect to host 192.168.1.129 port 22: Connection refused",
"unreachable": true
}
# 在host_v3中添加一个参数后可以访问远程节点
[webservers]
192.168.1.129 ansible_ssh_port=2233
playbook中使用变量
使用setup模块中的变量
# 环境:在/root/ansible/inventory.ini
[root@ansible ansible]# vim inventory.ini
[web_servers]
192.168.1.132
[db_servers]
192.168.1.133
[all_servers]
[all_servers:children]
web_servers
db_servers
列举出有关被管理服务器的操作系统版本、服务器iP地址、主机名,磁盘的使用情况、CPU个数、内存大小等等有关被管理服务器的私有信息。
[root@ansible ansible]# ansible db_servers -i inventory.ini -m setup
ansible_nodename是setup模块中的变量
[root@ansible ansible]# ansible db_servers -i inventory.ini -m setup -a 'filter="ansible_nodename"'
192.168.1.133 | SUCCESS => {
"ansible_facts": {
"ansible_nodename": "client-1",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
Facts
Facts变量不包含在前文中介绍的全局变量、剧本变量及资产变量之内。
Facts变量不需要我们人为去声明变量名及赋值。
它的声明和赋值完全有 Ansible 中的 setup模块帮我们完成
它收集了有关被管理服务器的操作系统版本、服务器iP地址、主机名,磁盘的使用情况、CPU个数、内存大小等等有关被管理服务器的私有信息。
在每次 PlayBook运行的时候都会发现在 PlayBook执行前都会有一个Gathering Facts的过程。这个过程就是收集被管理服务器的 Facts信息过程
手动收集Facts变量
ansible all -i localhost, -c local -m setup
过滤获取指定信息(内存信息)
ansible all -i localhost, -c local -m setup -a "filter=*memory*"
要求在playbook中使用,不要用ansible命令调用
使用playbook创建一个以ansible_nodename变量作为名字的空文件夹
[root@ansible ansible]# vim var.yml
---
- hosts: db_servers
remote_user: root
task:
- name: create log file
file: name=/data/{{ ansible_nodename }}.log state=touch owner=admin mode=600
[root@ansible ansible]# ansible db_servers -i inventory.ini -a "ls -l /data"
192.168.1.133 | CHANGED | rc=0 >>
总用量 0
-rw------- 1 admin root 0 8月 15 17:15 client-1.log
使用Facts变量
默认情况下,在执行playbook的时候,它会自动地获取每台被管理服务器的Facts信息
可以像使用其他变量一样去使用Facts变量
[root@ansible ~]# vim facts.yml
---
- name: print facts variable
hosts: all
tasks:
- name: print facts variable
debug:
msg:"The default IPV4 address is {{ ansible_default_ipv4.address }}"
...
[root@ansible ~]# ansible-playbook -i inventory.ini facts.yml
关闭 facts 变量的收集功能(在剧本中添加)
gather_facts: no 关闭后不能使用系统变量
remote_user: root 指定playbook的用户
命令行定义变量
[root@ansible ansible]# vim var2.yml
---
- hosts: db_servers
remote_user: root
tasks:
- name: install package
yum: name={{ pkname }} state=present
# 使用-e来传递变量
[root@ansible ansible]# ansible-playbook -i inventory.ini -e pkname=memcached var2.yml
[root@ansible ansible]# vim var3.yml
---
- hosts: db_servers
remote_user: root
vars:
- username: user1
- groupname: group1
tasks:
- name: create group
group: name={{ groupname }} state=present
- name: create user
user: name={{ username }} group={{ groupname }} state=present
[root@ansible ansible]# ansible-playbook -i inventory.ini var3.yml
注册变量
往往用于保存一个task任务的执行结果,以便于 debug时使用。
或者将此次task任务的结果作为条件,去判断是否去执行其他task任务。
注册变量在 PlayBook中通过 register关键字去实现。
[root@ansible ~]# vim myplaybook3.yml
---
- name: install a package and print the result
hosts: web_servers
remote_user: root
tasks:
- name: install nginx package
yum: name=nginx state=present
register: install_result #注册变量
- name: print result
debug: var=install_result #打印变量的值
...
[root@ansible ~]# ansible-playbook -i hosts myplaybook3.yml
PLAY [install a package and print the result] *****************************************
TASK [Gathering Facts] ****************************************************************
ok: [192.168.1.132]
TASK [install nginx package] **********************************************************
changed: [192.168.1.132]
TASK [print result] *******************************************************************
ok: [192.168.1.132] => {
"install_result": {
"changed": true,
"changes": {
"installed": [
"nginx"
]
},
"failed": false,
"results": []
}
}
PLAY RECAP ****************************************************************************
192.168.1.132 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
变量优先级
思考:我们同时在全局变量、剧本变量及资产变量声明了同一个变量名,那么哪一个优先级最高?
环境准备:
[root@ansible ~]# cat host_v3
[webservers]
192.168.1.129
[dbservers]
192.168.1.128
[allservers]
[allservers:children]
webservers
dbservers
[allservers:vars]
user=tomcat
[root@ansible ~]# cat playbook3.yml
---
- name: test variable priority
hosts: all
remote_user: root
vars:
user: mysql
tasks:
- name: print the user value
debug: msg='the user value is {{ user }}'
...
## www为全局
[root@ansible ~]# ansible-playbook -i host_v3 playbook3.yml -e "user=www"
PLAY [test variable priority] *********************************************************
TASK [Gathering Facts] ****************************************************************
ok: [192.168.1.132]
TASK [print the user value] ***********************************************************
ok: [192.168.1.132] => {
"msg": "the user value is www"
}
PLAY RECAP ****************************************************************************
192.168.1.132 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
输出结果为www
得出结论:优先级最高的是全局变量,其次剧本变量,最后是资产变量
Ansible任务控制
循环控制
[root@ansible ~]# vim loop.yml
---
- name: loop test
hosts: webservers
remote_user: root
tasks:
- name: nginx firewalld started
service:
name: "{{ item }}"
state: started
with_items:
- nginx
- firewalld
...
[root@ansible ~]# cat inventory.ini
[dbservers]
192.168.1.128
[webservers]
192.168.1.129
[root@ansible ~]# ansible-playbook -i inventory.ini loop.yml
循环散列
[root@ansible ~]# cat loop2.yml
---
- name: create user loop
hosts: web_servers
remote_user: root
tasks:
- name: create user
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
state: present
with_items:
- name: stu1
groups: root
- name: stu2
groups: foo
register: create_result
- name: show result
debug:
var=create_result
执行以上任务会得到结果,将结果赋值给注册变量,若没有任何变量则结果不显示。
[root@ansible ~]# ansible-playbook -i inventory.ini loop1.yml
PLAY [create user loop] ***************************************************************
TASK [Gathering Facts] ****************************************************************
ok: [192.168.1.132]
TASK [create user] ********************************************************************
changed: [192.168.1.132] => (item={u'name': u'stu1', u'groups': u'root'})
changed: [192.168.1.132] => (item={u'name': u'stu2', u'groups': u'foo'})
TASK [show result] ********************************************************************
ok: [192.168.1.132] => {
"create_result": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": true,
"failed": false,
"invocation": {
"module_args": {
"append": false,
"authorization": null,
"comment": null,
"create_home": true,
"expires": null,
"force": false,
"generate_ssh_key": null,
"group": null,
"groups": [
"root"
],
"hidden": null,
"home": null,
"local": null,
"login_class": null,
"move_home": false,
"name": "stu1",
"non_unique": false,
"password": null,
"password_lock": null,
"profile": null,
"remove": false,
"role": null,
"seuser": null,
"shell": null,
"skeleton": null,
"ssh_key_bits": 0,
"ssh_key_comment": "ansible-generated on client",
"ssh_key_file": null,
"ssh_key_passphrase": null,
"ssh_key_type": "rsa",
"state": "present",
"system": false,
"uid": null,
"update_password": "always"
}
},
"item": {
"groups": "root",
"name": "stu1"
}
},
{
"ansible_loop_var": "item",
"changed": true,
"failed": false,
"invocation": {
"module_args": {
"append": false,
"authorization": null,
"comment": null,
"create_home": true,
"expires": null,
"force": false,
"generate_ssh_key": null,
"group": null,
"groups": [
"foo"
],
"hidden": null,
"home": null,
"local": null,
"login_class": null,
"move_home": false,
"name": "stu2",
"non_unique": false,
"password": null,
"password_lock": null,
"profile": null,
"remove": false,
"role": null,
"seuser": null,
"shell": null,
"skeleton": null,
"ssh_key_bits": 0,
"ssh_key_comment": "ansible-generated on client",
"ssh_key_file": null,
"ssh_key_passphrase": null,
"ssh_key_type": "rsa",
"state": "present",
"system": false,
"uid": null,
"update_password": "always"
}
},
"item": {
"groups": "foo",
"name": "stu2"
}
}
]
}
}
PLAY RECAP ****************************************************************************
192.168.1.132 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
列表循环
[root@ansible ~]# vim loop.yml
---
- name: loop test
hosts: webservers
remote_user: root
vars:
myservice: # 使用列表
- nginx
- firewalld
tasks:
- name: nginx firewalld stopped
service:
name: "{{ item }}" # 使用item,指向with_items
state: stopped
with_items: "{{ myservice }}" # 指向列表变量
...
[root@ansible ~]# ansible-playbook -i inventory.ini loop.yml
when条件判断
nginx启动逻辑欠缺考虑
若 Nginx的配置文件语法错误则会导致启动 Nginx失败,以至于 Play Book执行失败。
如果我们能够在启动之前去对Nginx的配置文件语法做正确性的校验,只有当校验通过的时候我们才去启动或者重启 Nginx;否则则跳过启动 Nginx的过程。这样就会避免 Nginx配置文件语法问题而导致的无法启动Nginx的风险。
nginx语法校验
- name: check nginx syntax
shell: /usr/sbin/nginx -t
那如何将Nginx语法检查的TASK同Nginx启动的TASK关联起来呢?
如果我们能够获得语法检查的TASK的结果,根据这个结果去判断“启动NGINX的TASK”是否执⾏,这将是⼀个很好的⽅案。 如何和获取到语法检查TASK的结果呢? 此时就可以使⽤之前学到的 Ansible中的注册变量。
获取Task任务结果
- name: check nginx syntax
shell: /usr/sbin/nginx -t
register: nginxsyntax
此时有可能还有疑问,我获取到任务结果,但是结果⾥⾯的内容是个什么样⼦, 我如何根据内容在后续的PlayBook中使⽤呢?
通过debug模块去确认返回结果的数据结构
- name: print nginx syntax result
debug: var=nginxsyntax
通过debug 模块,打印出来的返回结果。 当nginxsyntax.rc 为 0时语法校验正确。
[root@ansible ~]# cat inventory.ini #资产管理文件
[dbservers]
192.168.1.128
[webservers]
192.168.1.129
[root@ansible ~]# vim nginxsyntax.yml
---
- name: check nginx syntax
hosts: webservers
gather_facts: no #不需要收集facts信息
remote_user: root
tasks:
- name: check nginx syntax
shell: /usr/sbin/nginx -t
register: nginxsyntax
- name: print nginx syntax result
debug: var=nginxsyntax
when: nginxsyntax.rc == 0
[root@ansible ~]# ansible-playbook -i inventory.ini nginxsyntax.yml
Handlers属性
观察当前的 Playbook,不能发现,当我的配置⽂件没有发⽣变化时,每次依然都会去触发TASK “reload nginx server”。
如何能做到只有配置⽂件发⽣变化的时候才去触发TASK “reload nginx server”,这样的处理才是最完美的实现。此时可以使⽤handlers 属性。
在tasks下添加一个通知notif,如
tasks:
- name: update nginx main config
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
notify: reload nginx service
tags: updateconfig
handlers:
- name: reload nginx service
service: name=nginx state=reloaded
when:
- nginxsyntax.rc == 0
- nginxrunning.stat.exists == true
[root@ansible ~]# ansible-playbook -i inventory.ini tags.yml -t updateconfig
环境准备:一个修改后的http.conf文件,拷贝到/root/ansible/files/
[root@ansible ~]# tree ansible/
ansible/
├── files
│ └── httpd.conf
├── http.yml
└── inventory.ini
[root@ansible ansible]# cat http.yml
---
- hosts: db_servers
gather_facts: no
remote_user: root
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
# notify作用:当上一条文件发生变化时,就重启httpd,类似标签,可写多个值
notify:
- restart httpd
- name: ensure apache running
service: name=httpd state=started enabled=yes
# notify就会查找handlers对应它的名字,执行相应的模块,可写多个值
handlers:
- name: restart httpd
service: name=httpd state=restarted
[root@ansible ansible]# ansible-playbook -i inventory.ini -C http.yml
测试,查看被管理节点的监听端口
[root@ansible ansible]# ansible 192.168.1.133 -i inventory.ini -a "ss -ntl"
192.168.1.133 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 100 [::1]:25 [::]:*
LISTEN 0 128 [::]:8080 (默认端口已变为8080) [::]:*
LISTEN 0 128 [::]:22 [::]:*
当修改files/httpd.conf的端口时,重复以上操作,发现端口已更改。
tags属性
我们可以通过Play中的tags 属性,去解决⽬前PlayBook变更⽽导致的扩⼤变更范围和变更⻛险的问题。
在改进的PlayBook中,针对⽂件发布TASK 任务"update nginx main config" 和 “add virtualhost config"新增了属性 tags ,属性值为updateconfig。另外我们新增"reload nginx server” TASK任务。当配置⽂件更新后,去reload Nginx 服务。
那重新加载需要依赖于 Nginx 服务是已经启动状态。所以,还需要进⼀步通过判断 Nginx 的 pid ⽂件存在,才证明 Nginx 服务本身是启动中,启动中才可以 reload Nginx 服务。判断⼀个⽂件是否存在使⽤ stat 模块。
在任务下加一个标签
tags: updateconfig
当执行ansible-playbook -i inventory.ini http.yml -t updateconfig 的时候
它会自动执行有标签tags的任务,而不是全部去执行任务,减少了变更范围和变更风险。
[root@ansible ansible]# cat http.yml
---
- hosts: db_servers
gather_facts: no
remote_user: root
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
notify: restart httpd
tags: updateconfig
- name: ensure apache running
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted
[root@ansible ansible]# ansible-playbook -i inventory.ini http.yml -t updateconfig
JinJa2模板
背景介绍
⽬前Nginx的配置⽂件在所有的服务器上都是相同的,但我希望能根据每⼀台服务器的性能去定制服务的启动进程。 同时定制每⼀台Nginx服务的响应头,以便于当某台服务出现问题时能快速定位到具体的服务器。 要做这样的定制势必会导致⼀个问题,Nginx 在每台物理服务器上的配置⽂件都不⼀样,这样的配置⽂件如何管理呢? 再使⽤copy 模块去做管理显然已经不合适。此时使⽤Ansible 提供的另⼀个==模板(template)==功能,它可以帮助我们完美的解决问题。
jinja2语言使用字面量,有下面形式
字符串:使用单引号或双引号
数字:整数、浮点型
列表:[item1,item2,…]
元组:(item1,item2,…)
字典:{key1:value1,key2:value2,…}
布尔型:true/false
算术运算:+ - * / // % **
比较操作:== != > < >= <=
逻辑运算:and or not
流表达式:For If When
jinja2 中存在 三种定界符
注释: {# 注释内容 #}
变量引⽤: {{ var }}
逻辑表达: {% %}
使用template模块
# 在/root/ansible/inventory.ini下
[root@ansible ansible]# vim inventory.ini
[web_servers]
192.168.1.132
[db_servers]
192.168.1.133
[all_servers]
[all_servers:children]
web_servers
db_servers
[root@ansible ansible]# ls
inventory.ini temnginx.yml templates
--------------------------------------------
[root@ansible ansible]# vim templates/nginx.conf.j2
#user nobody;
worker_processes {{ ansible_processor_vcpus }};
...
-------------------------------------------
[root@ansible ansible]# vim temnginx.yml
---
- hosts: web_servers
remote_user: root
# 必须打开数据收集,才能使用变量值,或者不写这个默认开启
gather_facts: yes
tasks:
- name: install epel
yum: name=epel-release
- name: install nginx
yum: name=nginx
# 源文件路径会根据template模块查找执行目录的templates目录下查找,templates文件夹名不可改为其他名
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: start service
service: name=nginx state=started enabled=yes
-------------------------------------------------------
[root@ansible ansible]# ansible-playbook -i inventory.ini temnginx.yml
验证
[root@ansible ansible]# ssh root@192.168.1.133
Last login: Sun Aug 15 23:11:26 2021 from 192.168.1.130
[root@client-1 ~]# head -3 /etc/nginx/nginx.conf
#user nobody;
worker_processes 2;
# 根据内核数得到进程数
小插曲:nginx的配置文件在/etc/nginx/nginx.conf还是在/usr/local/nginx/conf/nginx.conf?
/usr/local下的才是你正在使用的配置文件,/etc/nginx那个只是默认的配置, nginx -t 如果没有加-c指定配置文件,则测试的是默认配置文件
是安装方式不同导致的,使用
wget
安装的配置文件在/usr/local/nginx/conf
,使用yum
安装的配置文件在/etc/nginx
下。
使用流程控制for和if
template中也可以使用流程控制for循环和if条件判断,实现动态生成文件功能
案例一
[root@ansible ansible]# vim nginx.conf1.j2
{% for vhost in nginx_vhosts %}
server {
{{ vhost }}
}
{% endfor %}
[root@ansible ansible]# vim temnginx1.yml
---
- hosts: db_servers
remote_user: root
vars:
nginx_vhosts:
- 81
- 82
- 83
tasks:
- name: template config
template: src=nginx.conf1.j2 dest=/data/nginx.conf
[root@ansible ansible]# ansible-playbook -i inventory.ini temnginx1 .yml
验证
[root@client-1 data]# cat nginx.conf
server {
81
}
server {
82
}
server {
83
}
案例二
[root@ansible ansible]# vim templates/nginx.conf2.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}
{% for num in worker_processor%}
worker_processor {{ num.worker }}
{% endfor %}
--------------------------------------------------------
[root@ansible ansible]# vim temnginx2.yml
---
- hosts: db_servers
remote_user: root
vars:
nginx_vhosts:
- listen: 8080
#server_name: "web1.123.com"(可添加字典)
#root: "/var/www/nginx/web1"
- listen: 8081
#server_name: "web2.123.com"
#root: "/var/www/nginx/web2"
worker_processor:
- worker: 2
- worker: 3
tasks:
- name: config file
template: src=nginx.conf2.j2 dest=/data/nginx.conf2
-------------------------------------------------------------
[root@ansible ansible]# ansible-playbook -i inventory.ini temnginx2.yml
验证
[root@client-1 data]# cat nginx.conf2
server {
listen 8080
#server_name web1.123.com
#root /var/www/nginx/web1
}
server {
listen 8081
#server_name web1.123.com
#root /var/www/nginx/web1
}
worker_processor 2
worker_processor 3
案例三
[root@ansible ansible]# vim templates/nginx.conf4.j2
{% for vhost in nginx_vhost %}
server {
listen {{ vhost.listen }}
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }}
{% endif %}
root {{ vhost.root }}
}
{% endfor %}
-------------------------------------------------------------
[root@ansible ansible]# vim temnginx4.yml
---
- hosts: db_servers
remote_user: root
vars:
nginx_vhost:
- web1:
listen: 8080
root: "/var/www/nginx/web1"
- web2:
listen: 8080
server_name: "web2.123.com"
root: "/var/www/nginx/web2"
- web3:
listen: 8080
server_name: "web3.123.com"
root: "/var/www/nginx/web3"
tasks:
- name: template config to
template: src=nginx.conf4.j2 dest=/data/nginx4.conf
----------------------------------------------------------
[root@ansible ansible]# ansible-playbook -i inventory.ini temnginx4.yml
验证
[root@client-1 data]# cat nginx4.conf
server {
listen 8080
root /var/www/nginx/web1
}
server {
listen 8080
server_name web2.123.com
root /var/www/nginx/web2
}
server {
listen 8080
server_name web3.123.com
root /var/www/nginx/web3
}
使用迭代 with_items
迭代:当有需要重复执行的任务时,可以使用迭代机制,对迭代项的引用,固定变量名为“item”
要在task中使用with_item给定要迭代的元素列表
[root@ansible ansible]# vim with_item.yml
---
- hosts: db_servers
remote_user: root
tasks:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
[root@ansible ansible]# ansible-playbook -i inventory.ini with_item.yml
验证
[root@ansible ansible]# ansible db_servers -i inventory.ini -a 'getent passwd'
testuser1:x:1002:1002::/home/testuser1:/bin/bash
testuser2:x:1003:1003::/home/testuser2:/bin/bash
迭代嵌套子变量
在迭代中还可以嵌套子变量,关联多个变量一起使用
---
- hosts: db_servers
remote_user: root
tasks:
- name: add some group
group: name={{ item }} state=present
with_items:
- nginx
- mysql
-apache
- name: add some users
user: name={{ item.name }} group={{ item.group }} home={{ item.home }} create_home=yes state=present
with_items:
-{ name: 'nginx', group: 'nginx', home='/data/nginx' }
-{ name: 'mysql', group: 'mysql' home='/data/mysql' }
-{ name: 'apache', group: 'apache' home='/data/apache' }
Ansible Roles
介绍
- 一个数据中心有可能存在好多类型的服务器。比如WEB类型、DB类型、开发人员使用的开发类型、QA使用的测试类型等等。
- 实际生产中,基本每个类型的服务器的初始化行为都不一致。
- 那要在一个PlayBook中将这些动作完成,这个PlayBook将变s臃肿、庞大,且难以后续维护和更新。
- 如果能够针对每个类型的服务器单独编写PlayBook,最后通过某种方式整合这PlayBook, 在管理方式上就又会变得简单。
- Ansible中提供了类似的概念,也就是Role,它允许管理员将他们复杂的PlayBook分解成一个个小的逻辑单元,以便于维护和管理。
- roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。
- 运维复杂的场景建议使用roles,代码复用度高
roles: 多个角色的集合,可以将多个的role,分别放在roles目录下的独立子目录中
roles/
mysql/
httpd/
nginx/
redis/
结构
使用roles安装httpd服务
实验要求: 安装httpd服务,更换配置文件和index.html首页
1、启动入口,编排任务执行顺序,属于tasks任务文件
vim roles/httpd/tasks/main.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
2、安装httpd,属于tasks任务文件
vim roles/httpd/tasks/install.yml
- name: install httpd package
yum: name=httpd
3、拷贝文件,属于tasks任务文件,将修改的httpd.conf替换默认的配置文件
使用notify,当配置文件发生改变,执行playbook时重启服务,需添加handlers属性文件
vim roles/httpd/tasks/config.yml
- name: config file
copy: src=httpd.conf dest=/etc/httpd/conf/ backup=yes
notify: restart
4、拷贝文件,属于tasks任务文件
vim roles/httpd/tasks/index.yml
- name: index.html
copy: src=index.html dest=/var/www/html
5、启动服务,属于tasks任务文件
vim roles/httpd/tasks/service.yml
- name: start service
service: name=httpd state=started enabled=yes
6、因为添加了notify,需要添加handlers文件
vim roles/httpd/handlers/main.yml
- name: restart
service: name=httpd state=restarted
7、ansible-playbook执行文件,执行httpd的roles角色,后续可以添加其他的角色,如mysql,nginx
vim roles_httpd.yml
- hosts: web_servers
remote_user: root
roles:
- httpd
[root@ansible ansible]# tree roles/
roles/
└── httpd
├── files
│ ├── httpd.conf#修改过的配置文件
│ └── index.html#更换首页html
├── handlers
│ └── main.yml
└── tasks
├── config.yml
├── index.yml
├── install.yml
├── main.yml
└── service.yml
4 directories, 8 files
[root@ansible ansible]# ansible-playbook -i inventory.ini roles_httpd.yml
验证
[root@ansible ansible]# ansible web_servers -i inventory.ini -a 'ss -ntl'
192.168.1.132 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 [::]:6666 [::]:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
# 6666端口是修改后httpd的监听端口,是默认配置文件被替换的
使用memcached
准备工作
创建文件夹,写好template模板
mkdir roles/memcached/{tasks,templates} -pv
cp /root/memcached roles/memcached/templates/memcached.j2
vim roles/memcached/templates/memcached.j2
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ ansible_memtotal_mb//4 }}"#指memcached缓存为服务器内存整除4
OPTIONS=""
vim roles/memcached/tasks/main.yml
- include: install.yml
- include: config.yml
- include: service.yml
vim roles/memcached/tasks/install.yml
- name: install
yum: name=memcached
vim roles/memcached/tasks/config.yml
- name: config file
template: src=memcached.j2 dest=/etc/sysconfig/memcached
vim roles/memcached/tasks/service.yml
- name: service
service: name=memcached state=started enabled=yes
vim roles_memcached.yml
---
- hosts: web_servers
roles:
- memcached
[root@ansible ansible]# tree roles/memcached/
roles/memcached/
├── tasks
│ ├── config.yml
│ ├── install.yml
│ ├── main.yml
│ └── service.yml
└── templates
└── memcached.j2
[root@ansible ansible]# ansible-playbook -i inventory.ini roles_memcached.yml
验证:
默认值为64
[root@ansible ansible]# ansible web_servers -i inventory.ini -a 'cat /etc/sysconfig/memcached'
192.168.1.132 | CHANGED | rc=0 >>
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="243"
OPTIONS=""
作者:月光染衣袂
转发请加上该地址 : https://editor.csdn.net/md/?articleId=119152387
如果笔记对您有用,请帮忙点个赞!