运维自动化发展历程及技术应用
Ansible命令使用
Ansible常用模块详解
YAML语法简介
Ansible playbook基础
Playbook变量、tags、handlers使用
Playbook模板 templates
Playbook条件判断 when
Playbook字典 with_items
Ansible Roles
相关工具
代码管理(SCM):GitHub、GitLab、BitBucket、SubVersion
构建工具:maven、Ant、Gradle
自动部署:Capistrano、CodeDeploy
持续集成(CI):Jenkins、Travis
配置管理:Ansible、SaltStack、Chef、Puppet
容器:Docker、Podman、LXC、第三方厂商如AWS
编排:Kubernetes、Core、Apache Mesos
服务注册与发现:Zookeeper、etcd、Consul
脚本语言:python、ruby、shell
日志管理:ELK、Logentries
系统监控:Prometheus、Zabbix、Datadog、Graphite、Ganglia、Nagios
性能监控:AppDynamics、New Relic、Splunk
压力测试:JMeter、Blaze Meter、loader.io
应用服务器:Tomcat、JBoss、IIS
Web服务器:Apache、Nginx
数据库:MySQL、Oracle、PostgreSQL等关系型数据库;mongoDB、redis等NoSQL数据库
项目管理(PM):Jira、Asana、Taiga、Trello、Basecamp、Pivotal Tracker
一切皆自动化
“运维的未来是,让研发人员能够借助工具、自动化和流程,并且让他们能够在运维干预极少的情况下 部署和运营服务,从而实现自助服务。每个角色都应该努力使工作实现自动化。”——《运维的未来》
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WLl3inug-1592754503994)(G:Tptupian\1.3.PNG)]
使用者:程序员
功能:程序员个人的办公电脑或项目的开发测试环境,部署开发软件,测试个人或项目整体的BUG的 环境
管理者:程序员
使用者:QA测试工程师
功能:测试经过Dev环境测试通过的软件的功能和性能,判断是否达到项目的预期目标,生成测试报 告
管理者:运维
说明:测试环境往往有多套,测试环境满足测试功能即可,不宜过多
1、测试人员希望测试环境有多套,公司的产品多产品线并发,即多个版本,意味着多个版本同步测试
2、通常测试环境有多少套和产品线数量保持一样
功能:使用和生产环境一样的数据库,缓存服务等配置,测试是否正常
包括代码发布机,有些公司为堡垒机(安全屏障)
使用者:运维
功能:发布代码至生产环境
管理者:运维(有经验)
发布机:往往需要有2台(主备)
使用者:运维,少数情况开放权限给核心开发人员,极少数公司将权限完全开放给开发人员并其维护
功能:对用户提供公司产品的服务
管理者:只能是运维 生产环境服务器数量:一般比较多,且应用非常重要。往往需要自动工具协助部署配置应用
属于生产环境的一部分
使用者:运维
功能:在全量发布代码前将代码的功能面向少量精准用户发布的环境,可基于主机或用户执行灰度发布 案例:共100台生产服务器,先发布其中的10台服务器,这10台服务器就是灰度服务器
管理者:运维
灰度环境:往往该版本功能变更较大,为保险起见特意先让一部分用户优化体验该功能,待这部分用 户使用没有重大问题的时候,再全量发布至所有服务器
程序发布要求: 不能导致系统故障或造成系统完全不可用 不能影响用户体验
预发布验证: 新版本的代码先发布到服务器(跟线上环境配置完全相同,只是未接入到调度器)
灰度发布:
基于主机,用户,业务
发布路径:
软链接技术:软件的升级和回滚其实就是软链接指向的路径改变
/webapp/tuangou
/webapp/tuangou-1.1
/webapp/tuangou-1.2
发布过程:
自动化灰度发布:
Ansible:python,Agentless(无代理),中小型应用环境
Saltstack:python,一般需部署agent,执行效率更高
Puppet:ruby, 功能强大,配置复杂,重型,适合大型环境
Fabric:python,agentless Chef:ruby,国内应用少 Cfengine
func
https://github.com/ansible/ansible https://github.com/Saltstack/salt
同类自动化工具GitHub关注程度(2016-07-10)
自动化运维工 具 | Watch(关 注) | Star(点 赞) | Fork(复 制) | Contributors(贡献 者) |
---|---|---|---|---|
Ansible | 1387 | 17716 | 5356 | 1428 |
Saltstack | 530 | 6678 | 3002 | 1520 |
Puppet | 463 | 4044 | 1678 | 425 |
Chef | 383 | 4333 | 1806 | 464 |
Fabric | 379 | 7334 | 1235 | 116 |
公司计划在年底做一次大型市场促销活动,全面冲刺下交易额,为明年的上市做准备。公司要求各业务 组对年底大促做准备,运维部要求所有业务容量进行三倍的扩容,并搭建出多套环境可以共开发和测试 人员做测试,运维老大为了在年底有所表现,要求运维部门同学尽快实现,当你接到这个任务时,有没 有更快的解决方案?
作者:Michael DeHaan( Cobbler 与 Func 作者)
ansible 的名称来自科幻小说《安德的游戏》中跨越时空的即时通信工具,使用它可以在相距数光年的 距离,远程实时控制前线的舰队战斗。
2012-03-09,发布0.0.1版,2015-10-17,Red Hat宣布1.5亿美元收购
官网:https://www.ansible.com/
官方文档:https://docs.ansible.com/
组合INVENTORY、API、MODULES、PLUGINS的绿框,为ansible命令工具,其为核心执行工具
Ansible无代理,通过ssh协议就可以管理,不是一个独立服务,没有以service结尾的文件,abslble是管理端,需要的时候连接,不需要的时候就不连接。ansible不是一个时时刻刻都需要在运行的软件,是临时性运行的,不需要设置为开机启动。
ansible的安装方法有多种
[root@ansible ~]#yum install ansible
yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto
tar xf ansible-1.5.4.tar.gz
cd ansible-1.5.4
python setup.py build
python setup.py install
mkdir /etc/ansible
cp -r examples/* /etc/ansible
git clone git://github.com/ansible/ansible.git --recursive
cd ./ansible
source ./hacking/env-setup
pip 是安装Python包的管理器,类似 yum
yum install python-pip python-devel
yum install gcc glibc-devel zibl-devel rpm-bulid openssl-devel
pip install --upgrade pip
pip install ansible --upgrade
[root@ansible ~]#ansible --version
ansible 2.9.5
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules',
'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.8 (default, Nov 21 2019, 19:31:34) [GCC 8.3.1 20190507
(Red Hat 8.3.1-4)]
Ansible 的配置文件 /etc/ansible/ansible.cfg ,其中大部分的配置内容无需进行修改 ,以下建议修改
建议开启日志文件,会记录ansible对被管理者执行了哪些操作就,会记录在/var/log/ansible.log文件中,
不开启则没有这个文件。
host_key_checking = False开启,基于key验证,即通过ssh连接被管理端不用敲yes。
或者将ssh配置文件/etc/ssh/ssh_config中 # StrictHostKeyChecking ask 选项改为StrictHostKeyChecking no
[defaults]
#inventory = /etc/ansible/hosts # 主机列表配置文件
#library = /usr/share/my_modules/ # 库文件存放目录
#remote_tmp = $HOME/.ansible/tmp # 临时py命令文件存放在远程主机目录
#local_tmp = $HOME/.ansible/tmp # 本机的临时命令执行目录
#forks = 5 # 默认并发数
#sudo_user = root # 默认sudo 用户
#ask_sudo_pass = True # 每次执行ansible命令是否询问ssh密码
#ask_pass = True
#remote_port = 22
#host_key_checking = False # 检查对应服务器的host_key,建议取消注释
#log_path=/var/log/ansible.log # 日志文件,建议启用
#module_name = command # 默认模块,可以修改为shell模块
ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file中将其分组命名
默认的inventory file为 /etc/ansible/hosts inventory
file可以有多个,且也可以通过Dynamic Inventory来动态生成
主机清单文件格式
inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中
此外,当如若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明
如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机
范例:
ntp.magedu.com
[webservers]
www1.magedu.com:2222
www2.magedu.com
[dbservers]
db1.magedu.com
db2.magedu.com
db3.magedu.com
[websrvs]
www[1:100].example.com
[dbsrvs]
db-[a:f].example.com
[appsrvs]
10.0.0.[1:100]
实验:连接被管理端
[root@ansible ~]#vim /etc/ansible/ansible.cfg
log_path = /var/log/ansible.log
host_key_checking = False
[root@ansible ~]#vim /etc/ansible/hosts
[websrvs]
10.0.0.8
10.0.0.7
[appsrvs]
10.0.0.6
[dbsrvs]
10.0.0.8
10.0.0.18
[root@ansible ~]#ansible all --list
hosts (5):
10.0.0.8
10.0.0.7
10.0.0.6
10.0.0.18
[root@ansible ~]#ansible websrvs --list
hosts (2):
10.0.0.8
10.0.0.7
[root@ansible ~]#ansible appsrvs --list
hosts (2):
10.0.0.6
[root@ansible ~]#ansible dbsrvs --list
hosts (2):
10.0.0.8
10.0.0.18
#没有配置基于key验证,则不可达
[root@ansible ~]#ansible all -m ping
10.0.0.18 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Warning: Permanently added '10.0.0.18' (ECDSA) to the list of known hosts.\r\[email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
10.0.0.8 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Warning: Permanently added '10.0.0.8' (ECDSA) to the list of known hosts.\r\[email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
10.0.0.6 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Warning: Permanently added '10.0.0.6' (RSA) to the list of known hosts.\r\[email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
10.0.0.7 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Warning: Permanently added '10.0.0.7' (ECDSA) to the list of known hosts.\r\[email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
#因为修改了配置文件host_key_checking = False选项,则把管理的主机的公钥下载到本地
[root@ansible ~]#ls .ssh
known_hosts
[root@ansible ~]#cd .ssh
[root@ansible .ssh]#cat known_hosts
10.0.0.8 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIgQHXFnlcUSqBKPQH4BCgFwFoF1XUfH/jRLgj+LjAfUCxO5KH0NGN4M/C4XVWCcOBEVbDmHBTQsxGsoB0Cc=
10.0.0.18 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIgQHXFnlcUSqBKPQH4BCgFwFoF1XUfH/jRLgj+LjAfUCxO5KH0NGN4M/C4XVWCcOBEVbDmHBTQsxGsoB0Cc=
10.0.0.6 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA13SMVX1GDoav1P7eXAQUbojEkWEasxvocWRsuZfjy0hEwzFMsw/x901QuMe4LtfJxWXYN4U/1jyfO158kIKH5JonwD52F8IeT9EQdaYucTO+p2veAwmztXpz2QWwLBcYvLvqX5jgKxYZ2gnnjhiW46kENlKL1+YReYqdhENfJkH9j6Ep1iZnAUAsjm9Q7K9qTX524JDOWfOei5MkjfM1l2T0nDI6rLCSOW/z9doi3Bob8t+100N4jcdu6Fe6+8dXd1T1WMaMh0ziztONujHOREUs6KQ2TtOUYgaYXlh/WE1Ur+Pb88l0Q1xD5puoNaiCFY9j4x/f2HwPRbr7JkCDuw==
10.0.0.7 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDjiC5jrh6lR+fdBKZlGt84/3vUonsPLZ3Dsx9wndpSXcKHNL6I4QNevqlS1tf2Rpdns4MlpoBIkJcX/5I9pGUE=
#配置基于key验证
[root@ansible ~]#vim ssh_push_key.sh
#!/bin/bash
IPLIST="
10.0.0.8
10.0.0.18
10.0.0.7
10.0.0.6"
rpm -q sshpass &> /dev/null || yum -y install sshpass
[ -f /root/.ssh/id_rsa ] || ssh-keygen -f /root/.ssh/id_rsa -P ''
export SSHPASS=96110933
for IP in $IPLIST;do
sshpass -e ssh-copy-id -o StrictHostKeyChecking=no $IP
done
root@ansible ~]#bash ssh_push_key.sh
[root@ansible ~]#ansible all -m ping
10.0.0.7 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.18 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
10.0.0.6 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.8 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
#逻辑
[root@ansible ~]#ansible "websrvs:appsrvs" --list
hosts (3):
10.0.0.8
10.0.0.7
10.0.0.6
[root@ansible ~]#ansible "websrvs" --list
hosts (2):
10.0.0.8
10.0.0.7
[root@ansible ~]#ansible "appsrvs" --list
hosts (1):
10.0.0.6
[root@ansible ~]#ansible "websrvs:&appsrvs" --list
[WARNING]: No hosts matched, nothing to do
hosts (0):
[root@ansible ~]#ansible "websrvs:&dbsrvs" --list
hosts (1):
10.0.0.8
[root@ansible ~]#ansible "dbsrvs" --list
hosts (2):
10.0.0.8
10.0.0.18
#取反需要用单引号,用双引号会出错,会把!当成命令执行,表示前一个命令执行的历史
[root@ansible ~]#ansible "websrvs:!dbsrvs" --list
-bash: !dbsrvs: event not found
[root@ansible ~]#ansible 'websrvs:&dbsrvs' --list
hosts (1):
10.0.0.8
#把所有ansible管理的主机全部关闭,但有些没有关闭,
#原因:此处ansible管理了自己,先把自己关闭了,有些主机没来得及关闭
[root@ansible ~]#ansible all -a reboot
#取反应用
#上述解决办法,先关闭别人再关闭自己
[root@ansible ~]#ansible 'all:!10.0.0.18' -a reboot; reboot
扩展知识点:Ubuntu修改密码
[root@ubuntu1804 ~]#echo root:ubuntu|chpasswd
[root@ubuntu1804 ~]#su - rain
[rain@ubuntu1804 ~]$su -
Password:
[root@ubuntu1804 ~]#echo -e '96110933\n96110933' |passwd
Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully
利用ansible实现管理的主要方式:
此工具用来显示模块帮助
格式
ansible-doc [options] [module...]
-l, --list #列出可用模块
-s, --snippet #显示指定模块的playbook片段
范例:
#列出所有模块
ansible-doc -l
#查看指定模块帮助用法
ansible-doc ping
#查看指定模块帮助用法
ansible-doc -s ping
范例:
[root@ansible ~]#date
Wed Jun 17 16:08:09 CST 2020
[root@ansible ~]#ansible --version
ansible 2.9.9
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules',
'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.8 (default, Apr 16 2020, 01:36:27) [GCC 8.3.1 20191121
(Red Hat 8.3.1-5)]
[root@ansible ~]#ansible-doc -l|wc -l
3387
范例:ping模块
#ping模块用来连接目标主机,校验对方是否支持本方ssh连接,是否能够通过ansible远程进行管理
[root@ansible ~]#ansible-doc -l| grep '^ping'
ping Try to connect to host, verify a usable python and ...
pingdom Pause/unpause Pingdom alerts
#ping模块用法,其本身就是一个python程序,属于核心模块,不属于第三方扩展模块
[root@ansible ~]#ansible-doc ping
> PING (/usr/lib/python3.6/site-packages/ansible/modules/system/ping.py)
A trivial test module, this module always returns `pong' on successful contact. It
does not make sense in playbooks, but it is useful from `/usr/bin/ansible' to verify
the ability to login and that a usable Python is configured. This is NOT ICMP ping,
this is just a trivial test module that requires Python on the remote-node. For
Windows targets, use the [win_ping] module instead. For Network targets, use the
[net_ping] module instead.
* This module is maintained by The Ansible Core Team
OPTIONS (= is mandatory):
- data
Data to return for the `ping' return value.
If this parameter is set to `crash', the module will cause an exception.
[Default: pong]
type: str
SEE ALSO:
* Module net_ping
The official documentation on the net_ping module.
https://docs.ansible.com/ansible/2.9/modules/net_ping_module.html
* Module win_ping
The official documentation on the win_ping module.
https://docs.ansible.com/ansible/2.9/modules/win_ping_module.html
AUTHOR: Ansible Core Team, Michael DeHaan
METADATA:
status:
- stableinterface
supported_by: core
EXAMPLES:
# Test we can logon to 'webservers' and execute python with json lib.
# ansible webservers -m ping
# Example from an Ansible Playbook
- ping:
# Induce an exception to see what happens
- ping:
data: crash
RETURN VALUES:
ping:
description: value provided with the data parameter
returned: success
type: str
sample: pong
(END)
#查看ping最重要的用法
[root@ansible ~]#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.
此工具通过ssh协议,实现对远程主机的配置管理、应用部署、任务执行等功能
建议:使用此工具前,先配置ansible主控端能基于密钥认证的方式联系各个被管理节点
范例:利用sshpass批量实现基于key验证脚本1
[root@centos8 ~]#vim /etc/ssh/ssh_config
#修改下面一行
StrictHostKeyChecking no
[root@centos8 ~]#cat hosts.list
10.0.0.18
10.0.0.28
[root@centos8 ~]#vim push_ssh_key.sh
#!/bin/bash
rpm -q sshpass &> /dev/null || yum -y install sshpass
[ -f /root/.ssh/id_rsa ] || ssh-keygen -f /root/.ssh/id_rsa -P ''
export SSHPASS=magedu
while read IP;do
sshpass -e ssh-copy-id -o StrictHostKeyChecking=no $IP
done < hosts.list
范例: 实现基于key验证的脚本2
[root@centos8 ~]#vim push_ssh_key.sh
#!/bin/bash
IPLIST="
10.0.0.8
10.0.0.18
10.0.0.7
10.0.0.6
10.0.0.200"
rpm -q sshpass &> /dev/null || yum -y install sshpass
[ -f /root/.ssh/id_rsa ] || ssh-keygen -f /root/.ssh/id_rsa -P ''
export SSHPASS=centos
for IP in $IPLIST;do
sshpass -e ssh-copy-id -o StrictHostKeyChecking=no $IP
done
格式:
ansible <host-pattern> [-m module_name] [-a args]
选项说明:
--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@ansible ~]#ansible all -v -m shell -a 'ls'
Using /etc/ansible/ansible.cfg as config file
10.0.0.7 | CHANGED | rc=0 >>
anaconda-ks.cfg
10.0.0.6 | CHANGED | rc=0 >>
anaconda-ks.cfg
install.log
install.log.syslog
10.0.0.8 | CHANGED | rc=0 >>
anaconda-ks.cfg
hellodb_innodb.sql
ifcfg-eth0
mha4mysql-node-0.56-0.el6.noarch.rpm
testlog.sql
10.0.0.18 | CHANGED | rc=0 >>
anaconda-ks.cfg
hello.yml
ifcfg-eth0
ssh_push_key.sh
#可以重定向到一个文件中详细观察
[root@ansible ~]#ansible all -vv -m shell -a 'ls' > ansible.log
[root@ansible ~]#vim ansible.log
ansible 2.9.9
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.8 (default, Nov 21 2019, 19:31:34) [GCC 8.3.1 20190507 (Red Hat 8.3.1-4)]
Using /etc/ansible/ansible.cfg as config file
META: ran handlers
10.0.0.7 | CHANGED | rc=0 >>
anaconda-ks.cfg
10.0.0.6 | CHANGED | rc=0 >>
anaconda-ks.cfg
install.log
install.log.syslog
10.0.0.8 | CHANGED | rc=0 >>
anaconda-ks.cfg
hellodb_innodb.sql
ifcfg-eth0
mha4mysql-node-0.56-0.el6.noarch.rpm
testlog.sql
10.0.0.18 | CHANGED | rc=0 >>
anaconda-ks.cfg
ansible.log
hello.yml
ifcfg-eth0
ssh_push_key.sh
META: ran handlers
META: ran handlers
ansible的Host-pattern
用于匹配被控制的主机的列表
All :表示所有Inventory中的所有主机
范例
ansible all –m ping
*:通配符
ansible "*” -m ping
ansible 192.168.1.* -m ping
ansible "srvs” -m ping
或关系
ansible "websrvs:appsrvs" -m ping
ansible "192.168.1.10:192.168.1.20" -m ping
逻辑与
#在websrvs组并且在dbsrvs组中的主机
ansible "websrvs:&dbsrvs" –m ping
逻辑非
#在websrvs组,但不在dbsrvs组中的主机
#注意:此处为单引号
ansible 'websrvs:!dbsrvs' –m ping
综合逻辑
ansible 'websrvs:dbsrvs:&appsrvs:!ftpsrvs' –m ping
正则表达式
ansible "websrvs:dbsrvs" –m ping
ansible "~(web|db).*\.magedu\.com" –m ping
范例:
[root@kube-master1 ~]#ansible 'kube*:etcd:!10.0.0.101' -a reboot
ansible命令执行过程
范例:
[root@ansible ~]#ansible all -m shell -a 'sleep 10'
10.0.0.7 | CHANGED | rc=0 >>
10.0.0.6 | CHANGED | rc=0 >>
10.0.0.8 | CHANGED | rc=0 >>
10.0.0.18 | CHANGED | rc=0 >>
#10秒结束,临时文件删除,py程序能不能执行和被管理端的版本有关
[root@centos7 ~]#tree .ansible/tmp/
.ansible/tmp/
└── ansible-tmp-1592491558.6252227-3665-11109623338293
└── AnsiballZ_command.py
1 directory, 1 file
[root@centos7 ~]#tree .ansible/tmp/
.ansible/tmp/
0 directories, 0 files
ansible 的执行状态:
[root@centos8 ~]#grep -A 14 '\[colors\]' /etc/ansible/ansible.cfg
[colors]
#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
ansible使用范例
#以wang用户执行ping存活检测
ansible all -m ping -u wang -k
#以wang sudo至root执行ping存活检测
ansible all -m ping -u wang -k -b
#以wang sudo至mage用户执行ping存活检测
ansible all -m ping -u wang -k -b --become-user=mage
#以wang sudo至root用户执行ls
ansible all -m command -u wang -a 'ls /root' -b --become-user=root -k -K
此工具用于执行编写好的 playbook 任务
范例:
[root@ansible ~]vim hello.yml
---
#hello world yml file
- hosts: websrvs
remote_user: root
tasks:
- name: hello world
command: /usr/bin/wall hello world
[root@ansible ~]#ansible-playbook hello.yml
PLAY [websrvs] *******************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [hello world] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
此工具可以用于加密解密yml文件
格式:
ansible-vault [create|decrypt|edit|encrypt|rekey|view]
范例
ansible-vault encrypt hello.yml #加密
ansible-vault decrypt hello.yml #解密
ansible-vault view hello.yml #查看
ansible-vault edit hello.yml #编辑加密文件
ansible-vault rekey hello.yml #修改口令
ansible-vault create new.yml #创建新文件
范例:
#对hello.yml加密
[root@ansible ~]#ansible-vault encrypt hello.yml
New Vault password:
Confirm New Vault password:
Encryption successful
[root@ansible ~]#ll hello.yml
-rw------- 1 root root 873 Jun 18 21:59 hello.yml
[root@ansible ~]#cat hello.yml
$ANSIBLE_VAULT;1.1;AES256
31306334636536363230666339636166353732343531386537613166613434323963316133383234
3136656662363162663863643965363832386635376331320a376332346361356338623165333833
63616361356633666538303563353063356466343761636236313034326365366530633530653236
6466346561653737310a643636313864313361366561333430323865366661303435333666376561
65363233323862613631383830333130396235323438363236623631346330346165323032663134
30636234393361313665626631316263393763643166333136636162343266653961643330316234
65343136396664646238666162653032643130303866323739303562376238616366643839643563
38346532396663346632633434633832363537656531323730613864613564623033366434646235
35623966386536373433663163616238313931313536306634366364366536626231643266373363
61383564306164316263313565313533663163316130346666613436643563303835346531643564
323436396338383966633864336364303032
#加密过后不能执行
[root@ansible ~]#ansible-playbook hello.yml
ERROR! Attempting to decrypt but no vault secrets found
#解密
[root@ansible ~]#ansible-vault decrypt hello.yml
Vault password:
Decryption successful
[root@ansible ~]#cat hello.yml
#hello world yml file
- hosts: websrvs
remote_user: root
tasks:
- name: hello world
command: /usr/bin/wall hello world
[root@ansible ~]#ansible-playbook hello.yml
PLAY [websrvs] *******************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [hello world] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
此工具可交互执行命令,支持tab,ansible 2.0+新增
提示符格式:
执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$
常用子命令:
范例
[root@ansible ~]#ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
root@all (3)[f:5]$ list
10.0.0.8
10.0.0.7
10.0.0.6
root@all (3)[f:5]$ cd websrvs
root@websrvs (2)[f:5]$ list
10.0.0.7
10.0.0.8
root@websrvs (2)[f:5]$ forks 10
root@websrvs (2)[f:10]$ cd appsrvs
root@appsrvs (2)[f:5]$ yum name=httpd state=present
root@appsrvs (2)[f:5]$ service name=httpd state=started
此工具会连接 https://galaxy.ansible.com 下载相应的roles
范例
#列出所有已安装的galaxy
ansible-galaxy list
#安装galaxy
ansible-galaxy install geerlingguy.mysql
ansible-galaxy install geerlingguy.redis
#删除galaxy
ansible-galaxy remove geerlingguy.redis
2015年底270多个模块,2016年达到540个,2018年01月12日有1378个模块,2018年07月15日1852 个模块,2019年05月25日(ansible 2.7.10)时2080个模块,2020年03月02日有3387个模块 虽然模块众多,但最常用的模块也就2,30个而已,针对特定业务只用10几个模块
常用模块帮助文档参考:
https://docs.ansible.com/ansible/latest/modules/modules_by_category.html
默认模块配置
#默认command模块,可进行修改
[root@ansible ~]#vim /etc/ansible/ansible.cfg
# default module name for /usr/bin/ansible
#module_name = command
功能:在远程主机执行命令,此为默认模块,可忽略-m选项
注意:此命令不支持 $VARNAME < > | ; & 等,用shell模块实现
模块说明:可直接调用Linux命令 ,默认模块,可省略不写
[root@ansible ~]#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.
范例:
#查看command模块说明,,可直接调用Linux命令 ,默认模块,可省略不写
[root@ansible ~]#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.
[root@ansible ~]#ansible websrvs -m command -a 'chdir=/etc cat centos-release'
10.0.0.7 | CHANGED | rc=0 >>
CentOS Linux release 7.7.1908 (Core)
10.0.0.8 | CHANGED | rc=0 >>
CentOS Linux release 8.1.1911 (Core)
[root@ansible ~]#ansible websrvs -m command -a 'chdir=/etc creates=/data/f1.txt
cat centos-release'
10.0.0.7 | CHANGED | rc=0 >>
CentOS Linux release 7.7.1908 (Core)
10.0.0.8 | SUCCESS | rc=0 >>
skipped, since /data/f1.txt exists
[root@ansible ~]#ansible websrvs -m command -a 'chdir=/etc removes=/data/f1.txt
cat centos-release'
10.0.0.7 | SUCCESS | rc=0 >>
skipped, since /data/f1.txt does not exist
10.0.0.8 | CHANGED | rc=0 >>
CentOS Linux release 8.1.1911 (Core)
ansible websrvs -m command -a ‘service vsftpd start’
ansible websrvs -m command -a ‘echo magedu |passwd --stdin wang’
ansible websrvs -m command -a 'rm -rf /data/'
ansible websrvs -m command -a 'echo hello > /data/hello.log'
ansible websrvs -m command -a "echo $HOSTNAME"
[root@ansible ~]#ansible all -m command -a 'hostname'
10.0.0.6 | CHANGED | rc=0 >>
centos6min.rain.org
10.0.0.7 | CHANGED | rc=0 >>
centos7.8.rain.org
10.0.0.8 | CHANGED | rc=0 >>
centos8.1-min.rain.org
10.0.0.18 | CHANGED | rc=0 >>
ansible
[root@ansible ~]#ansible all -a 'hostname'
10.0.0.7 | CHANGED | rc=0 >>
centos7.8.rain.org
10.0.0.6 | CHANGED | rc=0 >>
centos6min.rain.org
10.0.0.8 | CHANGED | rc=0 >>
centos8.1-min.rain.org
10.0.0.18 | CHANGED | rc=0 >>
ansible
#进入/data创建文件,warning是提示你用file模块,如果不利用chdir参数进入目录,默认创建在/root下
#chdir适合编译安装,进入指定目录
[root@ansible ~]#ansible all -a 'chdir=/data touch a.txt'
[WARNING]: Consider using the file module with state=touch rather than running 'touch'. 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.
10.0.0.7 | CHANGED | rc=0 >>
10.0.0.8 | CHANGED | rc=0 >>
10.0.0.6 | CHANGED | rc=0 >>
10.0.0.18 | CHANGED | rc=0 >>
[root@ansible ~]#ansible all -a 'ls a.txt'
10.0.0.6 | FAILED | rc=2 >>
ls: cannot access a.txt: No such file or directorynon-zero return code
10.0.0.7 | FAILED | rc=2 >>
ls: cannot access a.txt: No such file or directorynon-zero return code
10.0.0.8 | FAILED | rc=2 >>
ls: cannot access 'a.txt': No such file or directorynon-zero return code
10.0.0.18 | FAILED | rc=2 >>
ls: cannot access 'a.txt': No such file or directorynon-zero return code
功能:和command相似,用shell执行命令
模块说明
[root@ansible ~]#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.
范例:
[root@ansible ~]#ansible websrvs -m shell -a "echo $HOSTNAME"
10.0.0.7 | CHANGED | rc=0 >>
ansible
10.0.0.8 | CHANGED | rc=0 >>
ansible
[root@ansible ~]#ansible websrvs -m shell -a 'echo $HOSTNAME'
10.0.0.7 | CHANGED | rc=0 >>
centos7.wangxiaochun.com
10.0.0.8 | CHANGED | rc=0 >>
centos8.localdomain
[root@ansible ~]#ansible websrvs -m shell -a 'echo centos | passwd --stdin wang'
10.0.0.7 | CHANGED | rc=0 >>
Changing password for user wang.
passwd: all authentication tokens updated successfully.
10.0.0.8 | CHANGED | rc=0 >>
Changing password for user wang.
passwd: all authentication tokens updated successfully.
[root@ansible ~]#ansible websrvs -m shell -a 'ls -l /etc/shadow'
10.0.0.7 | CHANGED | rc=0 >>
---------- 1 root root 889 Mar 2 14:34 /etc/shadow
10.0.0.8 | CHANGED | rc=0 >>
---------- 1 root root 944 Mar 2 14:34 /etc/shadow
[root@ansible ~]#ansible websrvs -m shell -a 'echo hello > /data/hello.log'
10.0.0.7 | CHANGED | rc=0 >>
10.0.0.8 | CHANGED | rc=0 >>
[root@ansible ~]#ansible websrvs -m shell -a 'cat /data/hello.log'
10.0.0.7 | CHANGED | rc=0 >>
hello
10.0.0.8 | CHANGED | rc=0 >>
hello
注意:调用bash执行命令 类似 cat /tmp/test.md | awk -F‘|’ ‘{print $1,$2}’ &> /tmp/example.txt 这些 复杂命令,即使使用shell也可能会失败,解决办法:写到脚本时,copy到远程,执行,再把需要的结果拉回执行命令的机器
范例:将shell模块代替command,设为模块
[root@ansible ~]#vim /etc/ansible/ansible.cfg
#修改下面一行
module_name = shell
功能:在远程主机上运行ansible服务器上的脚本(无需执行权限)
模块说明
#script模块说明
[root@ansible ~]#ansible-doc -s script
- name: Runs a local script on a remote node after transferring it
script:
chdir: # Change into this directory on the remote node before running the script.
cmd: # Path to the local script to run followed by optional arguments.
creates: # A filename on the remote node, when it already exists, this step will *not* be run.
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: # A filename on the remote node, when it does not exist, this step will *not* be run.
范例 :
[root@ansible ~]#ansible websrvs -m script -a /data/test.sh
功能:从ansible服务器主控端复制文件到远程主机
#如目标存在,默认覆盖,此处指定先备份
ansible websrvs -m copy -a "src=/root/test1.sh dest=/tmp/test2.sh owner=wang
mode=600 backup=yes"
#指定内容,直接生成目标文件
ansible websrvs -m copy -a "content='test line1\ntest line2' dest=/tmp/test.txt"
#复制/etc目录自身,注意/etc/后面没有/
ansible websrvs -m copy -a "src=/etc dest=/backup"
#复制/etc/下的文件,不包括/etc/目录自身,注意/etc/后面有/
ansible websrvs -m copy -a "src=/etc/ dest=/backup"
功能:从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录
模块说明
#fetch模块说明
[root@ansible ~]#ansible-doc -s fetch
- name: Fetch files from remote nodes
fetch:
dest: # (required) A directory to save the file into. For example, if the `dest' directory is
`/backup' a `src' file named `/etc/profile' on host
`host.example.com', would be saved into
`/backup/host.example.com/etc/profile'. The host name
is based on the inventory name.
fail_on_missing: # When set to `yes', the task will fail if the remote file cannot be read for any
reason. Prior to Ansible 2.5, setting this would only
fail if the source file was missing. The default was
changed to `yes' in Ansible 2.5.
flat: # Allows you to override the default behavior of appending hostname/path/to/file to the
destination. If `dest' ends with '/', it will use the
basename of the source file, similar to the copy
module. This can be useful if working with a single
host, or if retrieving files that are uniquely named
per host. If using multiple hosts with the same
filename, the file will be overwritten for each host.
src: # (required) The file on the remote system to fetch. This `must' be a file, not a
directory. Recursive fetching may be supported in a
later release.
validate_checksum: # Verify that the source and destination checksums match after the files are fetched.
范例:
[root@ansible ~]#ansible websrvs -m fetch -a 'src=/root/test.sh dest=/data/scripts'
范例:
[root@ansible ~]#ansible all -m fetch -a 'src=/etc/redhat-release
dest=/data/os'
[root@ansible ~]#tree /data/os/
/data/os/
├── 10.0.0.6
│ └── etc
│ └── redhat-release
├── 10.0.0.7
│ └── etc
│ └── redhat-release
└── 10.0.0.8
└── etc
└── redhat-release
6 directories, 3 files
功能:设置文件属性
模块说明
[root@ansible ~]#ansible-doc -s file
- name: Manage files and file properties
file:
access_time: # This parameter indicates the time the file's access time should be set to. Should be
`preserve' when no modification is required,
`YYYYMMDDHHMM.SS' when using default time format, or
`now'. Default is `None' meaning that `preserve' is the
default for `state=[file,directory,link,hard]' and
`now' is default for `state=touch'.
access_time_format: # When used with `access_time', indicates the time format that must be used. Based on
default Python format (see time.strftime doc).
attributes: # The attributes the resulting file or directory should have. To get supported flags
look at the man page for `chattr' on the target system.
This string should contain the attributes in the same
order as the one displayed by `lsattr'. The `='
operator is assumed as default, otherwise `+' or `-'
operators need to be included in the string.
follow: # This flag indicates that filesystem links, if they exist, should be followed. Previous
to Ansible 2.5, this was `no' by default.
force: # Force the creation of the symlinks in two cases: the source file does not exist (but
will appear later); the destination exists and is a
file (so, we need to unlink the `path' file and create
symlink to the `src' file in place of it).
group: # Name of the group that should own the file/directory, as would be fed to `chown'.
mode: # The permissions the resulting file or directory should have. For those used to
`/usr/bin/chmod' remember that modes are actually octal
numbers. You must either add a leading zero so that
Ansible's YAML parser knows it is an octal number (like
`0644' or `01777') or quote it (like `'644'' or
`'1777'') so Ansible receives a string and can do its
own conversion from string into number. Giving Ansible
a number without following one of these rules will end
up with a decimal number which will have unexpected
results. As of Ansible 1.8, the mode may be specified
as a symbolic mode (for example, `u+rwx' or
`u=rw,g=r,o=r'). As of Ansible 2.6, the mode may also
be the special string `preserve'. When set to
`preserve' the file will be given the same permissions
as the source file.
modification_time: # This parameter indicates the time the file's modification time should be set to.
Should be `preserve' when no modification is required,
`YYYYMMDDHHMM.SS' when using default time format, or
`now'. Default is None meaning that `preserve' is the
default for `state=[file,directory,link,hard]' and
`now' is default for `state=touch'.
modification_time_format: # When used with `modification_time', indicates the time format that must be used. >
on default Python format (see time.strftime doc).
owner: # Name of the user that should own the file/directory, as would be fed to `chown'.
path: # (required) Path to the file being managed.
recurse: # Recursively set the specified file attributes on directory contents. This applies only
when `state' is set to `directory'.
selevel: # The level part of the SELinux file context. This is the MLS/MCS attribute, sometimes
known as the `range'. When set to `_default', it will
use the `level' portion of the policy if available.
serole: # The role part of the SELinux file context. When set to `_default', it will use the
`role' portion of the policy if available.
setype: # The type part of the SELinux file context. When set to `_default', it will use the
`type' portion of the policy if available.
seuser: # The user part of the SELinux file context. By default it uses the `system' policy,
where applicable. When set to `_default', it will use
the `user' portion of the policy if available.
src: # Path of the file to link to. This applies only to `state=link' and `state=hard'. For
`state=link', this will also accept a non-existing
- name: Manage files and file properties
file:
access_time: # This parameter indicates the time the file's access time should be set to. Should be
`preserve' when no modification is required,
`YYYYMMDDHHMM.SS' when using default time format, or
`now'. Default is `None' meaning that `preserve' is the
default for `state=[file,directory,link,hard]' and
`now' is default for `state=touch'.
access_time_format: # When used with `access_time', indicates the time format that must be used. Based on
default Python format (see time.strftime doc).
attributes: # The attributes the resulting file or directory should have. To get supported flags
look at the man page for `chattr' on the target system.
This string should contain the attributes in the same
order as the one displayed by `lsattr'. The `='
operator is assumed as default, otherwise `+' or `-'
operators need to be included in the string.
follow: # This flag indicates that filesystem links, if they exist, should be followed. Previous
to Ansible 2.5, this was `no' by default.
force: # Force the creation of the symlinks in two cases: the source file does not exist (but
will appear later); the destination exists and is a
file (so, we need to unlink the `path' file and create
symlink to the `src' file in place of it).
group: # Name of the group that should own the file/directory, as would be fed to `chown'.
mode: # The permissions the resulting file or directory should have. For those used to
`/usr/bin/chmod' remember that modes are actually octal
numbers. You must either add a leading zero so that
Ansible's YAML parser knows it is an octal number (like
`0644' or `01777') or quote it (like `'644'' or
`'1777'') so Ansible receives a string and can do its
own conversion from string into number. Giving Ansible
a number without following one of these rules will end
up with a decimal number which will have unexpected
results. As of Ansible 1.8, the mode may be specified
as a symbolic mode (for example, `u+rwx' or
`u=rw,g=r,o=r'). As of Ansible 2.6, the mode may also
be the special string `preserve'. When set to
`preserve' the file will be given the same permissions
as the source file.
modification_time: # This parameter indicates the time the file's modification time should be set to.
Should be `preserve' when no modification is required,
`YYYYMMDDHHMM.SS' when using default time format, or
`now'. Default is None meaning that `preserve' is the
default for `state=[file,directory,link,hard]' and
`now' is default for `state=touch'.
modification_time_format: # When used with `modification_time', indicates the time format that must be used. >
on default Python format (see time.strftime doc).
owner: # Name of the user that should own the file/directory, as would be fed to `chown'.
path: # (required) Path to the file being managed.
recurse: # Recursively set the specified file attributes on directory contents. This applies only
when `state' is set to `directory'.
selevel: # The level part of the SELinux file context. This is the MLS/MCS attribute, sometimes
known as the `range'. When set to `_default', it will
use the `level' portion of the policy if available.
serole: # The role part of the SELinux file context. When set to `_default', it will use the
`role' portion of the policy if available.
setype: # The type part of the SELinux file context. When set to `_default', it will use the
`type' portion of the policy if available.
seuser: # The user part of the SELinux file context. By default it uses the `system' policy,
where applicable. When set to `_default', it will use
the `user' portion of the policy if available.
src: # Path of the file to link to. This applies only to `state=link' and `state=hard'. For
`state=link', this will also accept a non-existing
path. Relative paths are relative to the file being
created (`path') which is how the Unix command `ln -s
SRC DEST' treats relative paths.
state: # If `absent', directories will be recursively deleted, and files or symlinks will be
unlinked. In the case of a directory, if `diff' is
declared, you will see the files and folders deleted
listed under `path_contents'. Note that `absent' will
not cause `file' to fail if the `path' does not exist
as the state did not change. If `directory', all
intermediate subdirectories will be created if they do
not exist. Since Ansible 1.7 they will be created with
the supplied permissions. If `file', without any other
options this works mostly as a 'stat' and will return
the current state of `path'. Even with other options
(i.e `mode'), the file will be modified but will NOT be
created if it does not exist; see the `touch' value or
the [copy] or [template] module if you want that
behavior. If `hard', the hard link will be created or
changed. If `link', the symbolic link will be created
or changed. If `touch' (new in 1.4), an empty file will
be created if the `path' does not exist, while an
existing file or directory will receive updated file
access and modification times (similar to the way
`touch' works from the command line).
unsafe_writes: # Influence when to use atomic operation to prevent data corruption or inconsistent
reads from the target file. By default this module uses
atomic operations to prevent data corruption or
inconsistent reads from the target files, but sometimes
systems are configured or just broken in ways that
prevent this. One example is docker mounted files,
which cannot be updated atomically from inside the
container and can only be written in an unsafe manner.
This option allows Ansible to fall back to unsafe
methods of updating files when atomic operations fail
(however, it doesn't force Ansible to perform unsafe
writes). IMPORTANT! Unsafe writes are subject to race
conditions and can lead to data corruption.
(END)
范例:
#创建空文件
ansible all -m file -a 'path=/data/test.txt state=touch'
ansible all -m file -a 'path=/data/test.txt state=absent'
ansible all -m file -a "path=/root/test.sh owner=wang mode=755“
#创建目录
ansible all -m file -a "path=/data/mysql state=directory owner=mysql
group=mysql"
#创建软链接
ansible all -m file -a ‘src=/data/testfile dest=/data/testfile-link state=link’
功能:解包解压缩
实现有两种用法:
1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes
2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
常见参数:
只要包不在ansible的机器上就要写copy=no
范例:
ansible all -m unarchive -a 'src=/data/foo.tgz dest=/var/lib/foo owner=wang
group=bin'
ansible all -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777'
ansible all -m unarchive -a 'src=https://example.com/example.zip dest=/data copy=no'
实验:copy=yes
#xz压缩比比较高,但效率低,不建议使用
[root@ansible ~]#tar Jcvf etc.tar.xz /etc/
tar: Removing leading `/' from member names
/etc/
/etc/mtab
/etc/fstab
...省略...
[root@ansible ~]#ll -h
-rw-r--r-- 1 root root 3.0M Jun 20 09:15 etc.tar.xz
[root@ansible ~]#ansible websrvs --list
hosts (2):
10.0.0.8
10.0.0.7
#解压缩到websrvs主机上,并设置所有者所属组,默认copy=yes
[root@ansible ~]#ansible websrvs -m unarchive -a 'src=etc.tar.xz dest=/data owner=rain group=bin'
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"dest": "/data",
"extract_results": {
"cmd": [
"/usr/bin/gtar",
"--extract",
"-C",
"/data",
"--owner=rain",
"--group=bin",
"-f",
"/root/.ansible/tmp/ansible-tmp-1592616098.1796424-1724-258155876293741/source"
],
"err": "",
"out": "",
"rc": 0
},
"gid": 0,
"group": "root",
"handler": "TarArchive",
"mode": "0755",
"owner": "root",
"size": 17,
"src": "/root/.ansible/tmp/ansible-tmp-1592616098.1796424-1724-258155876293741/source",
"state": "directory",
"uid": 0
}
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/data",
"extract_results": {
"cmd": [
"/usr/bin/gtar",
"--extract",
"-C",
"/data",
"--owner=rain",
"--group=bin",
"-f",
"/root/.ansible/tmp/ansible-tmp-1592616098.1529355-1725-138307783669796/source"
],
"err": "",
"out": "",
"rc": 0
},
"gid": 0,
"group": "root",
"handler": "TarArchive",
"mode": "0755",
"owner": "root",
"size": 17,
"src": "/root/.ansible/tmp/ansible-tmp-1592616098.1529355-1725-138307783669796/source",
"state": "directory",
"uid": 0
}
#复制成功,/etc/下文件所有者所属组也为rain bin
[root@centos8 ~]#ll /data
total 12
drwxr-xr-x 79 rain bin 8192 Jun 20 08:20 etc
[root@centos7 ~]#ll /data
total 12
drwxr-xr-x 79 rain bin 8192 Jun 20 08:20 etc
实验:copy=no
#先利用copy模块将压缩包拷贝到目标主机,再在目标主机上直接解压缩,copy=no
[root@ansible ~]#ansible websrvs -m copy -a 'src=etc.tar.xz dest=/root/'
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "5a2c23793afdf8d94e2ca8caafd36d8d507ac3fe",
"dest": "/root/etc.tar.xz",
"gid": 0,
"group": "root",
"md5sum": "0df601dbc7c30ce4f58f5a07d2bf0b70",
"mode": "0644",
"owner": "root",
"size": 3059304,
"src": "/root/.ansible/tmp/ansible-tmp-1592616446.7397408-1849-184580434632948/source",
"state": "file",
"uid": 0
}
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"checksum": "5a2c23793afdf8d94e2ca8caafd36d8d507ac3fe",
"dest": "/root/etc.tar.xz",
"gid": 0,
"group": "root",
"md5sum": "0df601dbc7c30ce4f58f5a07d2bf0b70",
"mode": "0644",
"owner": "root",
"size": 3059304,
"src": "/root/.ansible/tmp/ansible-tmp-1592616446.7338972-1847-201697234434438/source",
"state": "file",
"uid": 0
}
[root@ansible ~]#ansible websrvs -m unarchive -a 'src=/root/etc.tar.xz dest=/data copy=no'
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/data",
"extract_results": {
"cmd": [
"/usr/bin/gtar",
"--extract",
"-C",
"/data",
"-f",
"/root/etc.tar.xz"
],
"err": "",
"out": "",
"rc": 0
},
"gid": 0,
"group": "root",
"handler": "TarArchive",
"mode": "0755",
"owner": "root",
"size": 17,
"src": "/root/etc.tar.xz",
"state": "directory",
"uid": 0
}
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"dest": "/data",
"extract_results": {
"cmd": [
"/usr/bin/gtar",
"--extract",
"-C",
"/data",
"-f",
"/root/etc.tar.xz"
],
"err": "",
"out": "",
"rc": 0
},
"gid": 0,
"group": "root",
"handler": "TarArchive",
"mode": "0755",
"owner": "root",
"size": 17,
"src": "/root/etc.tar.xz",
"state": "directory",
"uid": 0
}
[root@centos8 ~]#ll
-rw-r--r-- 1 root root 3059304 Jun 20 09:27 etc.tar.xz
[root@centos8 ~]#ll /data
total 12
drwxr-xr-x 79 root root 8192 Jun 20 08:20 etc
[root@centos7 ~]#ll
total 2992
-rw-------. 1 root root 1577 May 28 18:56 anaconda-ks.cfg
-rw-r--r-- 1 root root 3059304 Jun 20 09:27 etc.tar.xz
[root@centos7 ~]#ll /data
total 12
drwxr-xr-x 79 root root 8192 Jun 20 08:20 etc
功能:打包压缩 保存在被管理节点,配合Fetch模块(只能抓取文件,不能抓取目录)配合archive模块,抓取被管理节点的目录(archive打包成压缩包,fetch抓取)
范例:
ansible websrvs -m archive -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2
owner=wang mode=0600'
实验:
[root@ansible ~]#ansible websrvs -m archive -a 'path=/var/log dest=/data/log.tar.bz2 format=bz2 owner=rain mode=0600'
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"archived": [
"/var/log/tallylog",
"/var/log/grubby_prune_debug",
"/var/log/lastlog",
"/var/log/wtmp",
"/var/log/messages",
"/var/log/secure",
"/var/log/maillog",
"/var/log/boot.log",
"/var/log/vmware-vgauthsvc.log.0",
"/var/log/vmware-vmsvc.log",
"/var/log/cron",
"/var/log/dmesg.old",
"/var/log/yum.log",
"/var/log/dmesg",
"/var/log/vmware-network.5.log",
"/var/log/vmware-network.4.log",
"/var/log/vmware-network.3.log",
"/var/log/vmware-network.2.log",
"/var/log/vmware-network.1.log",
"/var/log/vmware-network.log",
"/var/log/tuned/tuned.log",
"/var/log/audit/audit.log",
"/var/log/anaconda/anaconda.log",
"/var/log/anaconda/syslog",
"/var/log/anaconda/X.log",
"/var/log/anaconda/program.log",
"/var/log/anaconda/packaging.log",
"/var/log/anaconda/storage.log",
"/var/log/anaconda/ifcfg.log",
"/var/log/anaconda/ks-script-LJCIYz.log",
"/var/log/anaconda/ks-script-PfUENy.log",
"/var/log/anaconda/journal.log"
],
"arcroot": "/var/",
"changed": true,
"dest": "/data/log.tar.bz2",
"expanded_exclude_paths": [],
"expanded_paths": [
"/var/log"
],
"gid": 0,
"group": "root",
"missing": [],
"mode": "0600",
"owner": "rain",
"size": 280776,
"state": "file",
"uid": 1000
}
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"archived": [
"/var/log/lastlog",
"/var/log/README",
"/var/log/wtmp",
"/var/log/messages",
"/var/log/secure",
"/var/log/maillog",
"/var/log/spooler",
"/var/log/boot.log",
"/var/log/vmware-vgauthsvc.log.0",
"/var/log/vmware-vmsvc.log",
"/var/log/firewalld",
"/var/log/cron",
"/var/log/dnf.log",
"/var/log/dnf.librepo.log",
"/var/log/dnf.rpm.log",
"/var/log/hawkey.log",
"/var/log/boot.log-20200619",
"/var/log/vmware-network.9.log",
"/var/log/vmware-network.8.log",
"/var/log/vmware-network.7.log",
"/var/log/vmware-network.6.log",
"/var/log/vmware-network.5.log",
"/var/log/vmware-network.4.log",
"/var/log/vmware-network.3.log",
"/var/log/vmware-network.2.log",
"/var/log/vmware-network.1.log",
"/var/log/vmware-network.log",
"/var/log/boot.log-20200620",
"/var/log/sssd/sssd.log",
"/var/log/sssd/sssd_implicit_files.log",
"/var/log/sssd/sssd_nss.log",
"/var/log/sssd/sssd_kcm.log",
"/var/log/tuned/tuned.log",
"/var/log/audit/audit.log",
"/var/log/anaconda/anaconda.log",
"/var/log/anaconda/syslog",
"/var/log/anaconda/X.log",
"/var/log/anaconda/program.log",
"/var/log/anaconda/packaging.log",
"/var/log/anaconda/storage.log",
"/var/log/anaconda/ifcfg.log",
"/var/log/anaconda/dnf.librepo.log",
"/var/log/anaconda/hawkey.log",
"/var/log/anaconda/dbus.log",
"/var/log/anaconda/ks-script-3k1g07ss.log",
"/var/log/anaconda/ks-script-j5qqrfdb.log",
"/var/log/anaconda/journal.log",
"/var/log/mariadb/mariadb.log",
"/var/log/mariadb/mariadb.log-20200619.gz"
],
"arcroot": "/var/",
"changed": true,
"dest": "/data/log.tar.bz2",
"expanded_exclude_paths": [],
"expanded_paths": [
"/var/log"
],
"gid": 0,
"group": "root",
"missing": [],
"mode": "0600",
"owner": "rain",
"size": 427496,
"state": "file",
"uid": 1000
}
[root@centos8 ~]#ll /data
-rw------- 1 rain root 427496 Jun 20 09:36 log.tar.bz2
[root@centos7 ~]#ll /data
-rw------- 1 rain root 280776 Jun 20 09:36 log.tar.bz2
功能:管理主机名 针对一台主机来设置,否则都设置为同样的主机名
范例:
ansible node1 -m hostname -a “name=websrv”
ansible 192.168.100.18 -m hostname -a 'name=node18.magedu.com'
实验:
[root@ansible ~]#ansible 10.0.0.6 -m hostname -a 'name=centos66.rain.org'
10.0.0.6 | CHANGED => {
"ansible_facts": {
"ansible_domain": "rain.org",
"ansible_fqdn": "centos66.rain.org",
"ansible_hostname": "centos66",
"ansible_nodename": "centos66.rain.org",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"name": "centos66.rain.org"
}
#写到配置文件中了,是永久保存
[root@centos6min ~]#hostname
centos66.rain.org
[root@centos6min ~]#cat /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=centos66.rain.org
回顾知识:centos6,7,8和ubuntu主机名文件
#centos7,8和ubuntu一样,centos6不一样
[root@centos6min ~]#cat /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=centos6.rain.org
[root@centos7 ~]#cat /etc/hostname
centos7.8.rain.org
[root@ubuntu1804 ~]#cat /etc/hostname
ubuntu1804
[root@centos8 ~]#cat /etc/hostname
centos8.1-min.rain.org
功能:计划任务 支持时间:minute,hour,day,month,weekday
范例:
#备份数据库脚本
[root@centos8 ~]#cat /root/mysql_backup.sh
#!/bin/bash
mysqldump -A -F --single-transaction --master-data=2 -q -uroot |gzip >
/data/mysql_`date +%F_%T`.sql.gz
#创建任务
ansible 10.0.0.8 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql"
job=/root/mysql_backup.sh'
#ntpdate这个命令centos8没有,立即同步时间
ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate ntp.aliyun.com
&>/dev/null' name=Synctime"
#禁用计划任务
#启用计划任务
ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1
&>/dev/null' name=Synctime disabled=no"
#删除任务
ansible websrvs -m cron -a "name='backup mysql' state=absent"
ansible websrvs -m cron -a 'state=absent name=Synctime'
实验:
[root@ansible ~]#vim mysql_backup.sh
#!/bin/bash
mysqldump -A -F --single-transaction --master-data=2 -q -uroot |gzip > /data/mysql_`date +%F_%T`.sql.gz
[root@ansible ~]#chmod +x mysql_backup.sh
#利用copy模块拷贝被管理端节点
[root@ansible ~]#ansible websrvs -m copy -a 'src=/root/mysql_backup.sh dest=/opt/'
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "27724a1bba92de5f32e749e0630bef5ba71e3837",
"dest": "/opt/mysql_backup.sh",
"gid": 0,
"group": "root",
"md5sum": "caa9c5519f6adc18b2febb9cf5264484",
"mode": "0644",
"owner": "root",
"size": 117,
"src": "/root/.ansible/tmp/ansible-tmp-1592619277.6777751-2066-173556779346371/source",
"state": "file",
"uid": 0
}
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"checksum": "27724a1bba92de5f32e749e0630bef5ba71e3837",
"dest": "/opt/mysql_backup.sh",
"gid": 0,
"group": "root",
"md5sum": "caa9c5519f6adc18b2febb9cf5264484",
"mode": "0644",
"owner": "root",
"size": 117,
"src": "/root/.ansible/tmp/ansible-tmp-1592619277.70654-2065-42838351357128/source",
"state": "file",
"uid": 0
}
#查看是否拷贝成功
[root@ansible ~]#ansible websrvs -m shell -a 'ls -l /opt'
10.0.0.7 | CHANGED | rc=0 >>
total 4
-rw-r--r-- 1 root root 117 Jun 20 10:14 mysql_backup.sh
10.0.0.8 | CHANGED | rc=0 >>
total 4
-rw-r--r-- 1 root root 117 Jun 20 10:14 mysql_backup.sh
#创建计划任务
[root@ansible ~]#ansible websrvs -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/opt/mysql_backup.sh'
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"envs": [],
"jobs": [
"backup mysql"
]
}
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"envs": [],
"jobs": [
"backup mysql"
]
}
#查看计划任务是否创建成功
[root@ansible ~]#ansible websrvs -m shell -a 'crontab -l'
10.0.0.7 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
10.0.0.8 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
[root@centos8 ~]#cat /var/spool/cron/root
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
[root@centos7 ~]#cat /var/spool/cron/root
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
#禁用计划任务
[root@ansible ~]#ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate ntp.aliyun.com &>/dev/null' name=Synctime disabled=yes"
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"envs": [],
"jobs": [
"backup mysql",
"Synctime"
]
}
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"envs": [],
"jobs": [
"backup mysql",
"Synctime"
]
}
#实则加#注释掉
[root@ansible ~]#ansible websrvs -m shell -a 'crontab -l'
10.0.0.7 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
#Ansible: Synctime
#*/5 * * * * /usr/sbin/ntpdate ntp.aliyun.com &>/dev/null
10.0.0.8 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
#Ansible: Synctime
#*/5 * * * * /usr/sbin/ntpdate ntp.aliyun.com &>/dev/null
#启用计划任务
[root@ansible ~]#ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate ntp.aliyun.com &>/dev/null' name=Synctime disabled=no"
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"envs": [],
"jobs": [
"backup mysql",
"Synctime"
]
}
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"envs": [],
"jobs": [
"backup mysql",
"Synctime"
]
}
#去掉#注释
[root@ansible ~]#ansible websrvs -m shell -a 'crontab -l'
10.0.0.7 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
#Ansible: Synctime
*/5 * * * * /usr/sbin/ntpdate ntp.aliyun.com &>/dev/null
10.0.0.8 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
#Ansible: Synctime
*/5 * * * * /usr/sbin/ntpdate ntp.aliyun.com &>/dev/null
#删除计划任务
[root@ansible ~]#ansible websrvs -m cron -a 'state=absent name=Synctime'
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"envs": [],
"jobs": [
"backup mysql"
]
}
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"envs": [],
"jobs": [
"backup mysql"
]
}
#已删除,留下的只是数据库备份
[root@ansible ~]#ansible websrvs -m shell -a 'crontab -l'
10.0.0.7 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
10.0.0.8 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /opt/mysql_backup.sh
功能:管理软件包,只支持RHEL,CentOS,fedora,不支持Ubuntu其它版本
范例:
[root@ansible ~]#ansible websrvs -m yum -a 'name=httpd state=present' #安装
[root@ansible ~]#ansible websrvs -m yum -a 'name=httpd state=absent' #删除
[root@ansible ~]#ansible websrvs -m yum -a 'name=iotop,cowsay'
#装多个包
[root@ansible ~]#ansible websrvs -m shell -a 'rpm -q iotop cowsay'
[WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'. If you need to use command
because yum, dnf or zypper 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.
10.0.0.7 | CHANGED | rc=0 >>
iotop-0.6-4.el7.noarch
cowsay-3.04-4.el7.noarch
10.0.0.8 | CHANGED | rc=0 >>
iotop-0.6-16.el8.noarch
cowsay-3.04-14.el8.noarch
ubuntu使用apt模块
模块说明
[root@ansible ~]#ansible-doc -s apt
- name: Manages apt-packages
apt:
allow_unauthenticated: # Ignore if packages cannot be authenticated. This is useful for bootstrapping
environments that manage their own apt-key setup.
`allow_unauthenticated' is only supported with state:
`install'/`present'
autoclean: # If `yes', cleans the local repository of retrieved package files that can no longer be
downloaded.
autoremove: # If `yes', remove unused dependency packages for all module states except `build-dep'.
It can also be used as the only option. Previous to
version 2.4, autoclean was also an alias for
autoremove, now it is its own separate command. See
documentation for further information.
cache_valid_time: # Update the apt cache if its older than the `cache_valid_time'. This option is set in
seconds. As of Ansible 2.4, if explicitly set, this
sets `update_cache=yes'.
deb: # Path to a .deb package on the remote machine. If :// in the path, ansible will attempt
to download deb before installing. (Version added 2.1)
Requires the `xz-utils' package to extract the control
file of the deb package to install.
default_release: # Corresponds to the `-t' option for `apt' and sets pin priorities
dpkg_options: # Add dpkg options to apt command. Defaults to '-o "Dpkg::Options::=--force-confdef" -o
"Dpkg::Options::=--force-confold"' Options should be
supplied as comma separated list
force: # Corresponds to the `--force-yes' to `apt-get' and implies `allow_unauthenticated: yes'
This option will disable checking both the packages'
signatures and the certificates of the web servers they
are downloaded from. This option *is not* the
equivalent of passing the `-f' flag to `apt-get' on the
command line **This is a destructive operation with the
potential to destroy your system, and it should almost
never be used.** Please also see `man apt-get' for more
information.
force_apt_get: # Force usage of apt-get instead of aptitude
install_recommends: # Corresponds to the `--no-install-recommends' option for `apt'. `yes' installs
recommended packages. `no' does not install
recommended packages. By default, Ansible will use the
same defaults as the operating system. Suggested
packages are never installed.
name: # A list of package names, like `foo', or package specifier with version, like
`foo=1.0'. Name wildcards (fnmatch) like `apt*' and
version wildcards like `foo=1.0*' are also supported.
only_upgrade: # Only upgrade a package if it is already installed.
policy_rc_d: # Force the exit code of /usr/sbin/policy-rc.d. For example, if `policy_rc_d=101' the
installed package will not trigger a service start. If
/usr/sbin/policy-rc.d already exist, it is backed up
and restored after the package installation. If `null',
the /usr/sbin/policy-rc.d isn't created/changed.
purge: # Will force purging of configuration files if the module state is set to `absent'.
state: # Indicates the desired package state. `latest' ensures that the latest version is
installed. `build-dep' ensures the package build
dependencies are installed. `fixed' attempt to correct
a system with broken dependencies in place.
update_cache: # Run the equivalent of `apt-get update' before the operation. Can be run as part of the
package installation or as a separate step.
upgrade: # If yes or safe, performs an aptitude safe-upgrade. If full, performs an aptitude full-
upgrade. If dist, performs an apt-get dist-upgrade.
Note: This does not upgrade a specific package, use
state=latest for that. Note: Since 2.4, apt-get is used
as a fall-back if aptitude is not present.
(END)
功能:管理服务
范例:
ansible all -m service -a 'name=httpd state=started enabled=yes'
ansible all -m service -a 'name=httpd state=stopped'
ansible all -m service -a 'name=httpd state=reloaded’
ansible all -m shell -a "sed -i 's/^Listen 80/Listen 8080/'
/etc/httpd/conf/httpd.conf"
ansible all -m service -a 'name=httpd state=restarted'
实验:httpd服务
#安装httpd
[root@ansible ~]#ansible websrvs -m yum -a 'name=httpd'
#查看httpd状态
[root@ansible ~]#ansible websrvs -a 'systemctl status httpd'
10.0.0.7 | FAILED | rc=3 >>
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Active: inactive (dead)
Docs: man:httpd(8)
man:apachectl(8)non-zero return code
10.0.0.8 | FAILED | rc=3 >>
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Active: inactive (dead)
Docs: man:httpd.service(8)non-zero return code
#更改配置文件
[root@ansible ~]#ansible websrvs -m shell -a "sed -i 's/^Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf"
[WARNING]: Consider using the replace, lineinfile or template module rather than running 'sed'. If you need to use
command because replace, lineinfile or template 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.
10.0.0.7 | CHANGED | rc=0 >>
10.0.0.8 | CHANGED | rc=0 >>
#利用grep 查看配置文件是否更改
[root@ansible ~]#ansible websrvs -m shell -a "grep Listen /etc/httpd/conf/httpd.conf"
10.0.0.7 | CHANGED | rc=0 >>
# Listen: Allows you to bind Apache to specific IP addresses and/or
# Change this to Listen on specific IP addresses as shown below to
#Listen 12.34.56.78:80
Listen 8080
10.0.0.8 | CHANGED | rc=0 >>
# Listen: Allows you to bind Apache to specific IP addresses and/or
# Change this to Listen on specific IP addresses as shown below to
#Listen 12.34.56.78:80
Listen 8080
#启动
[root@ansible ~]#ansible websrvs -m service -a 'name=httpd state=restarted'
#查看httpd服务端口
[root@ansible ~]#ansible websrvs -m shell -a 'ss -ntl'
10.0.0.7 | 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 *:8080 *:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
10.0.0.8 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 *:8080 *:*
LISTEN 0 128 [::]:22 [::]:*
实验:vsftp服务
#安装vsftpd服务
[root@ansible ~]#ansible websrvs -m yum -a 'name=vsftpd'
10.0.0.8 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Installed: vsftpd-3.0.3-31.el8.x86_64"
]
}
10.0.0.7 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"vsftpd"
]
},
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.huaweicloud.com\n * epel: mirrors.yun-idc.com\n * extras: mirrors.tuna.tsinghua.edu.cn\n * updates: mirrors.tuna.tsinghua.edu.cn\nResolving Dependencies\n--> Running transaction check\n---> Package vsftpd.x86_64 0:3.0.2-27.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n vsftpd x86_64 3.0.2-27.el7 base 172 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 172 k\nInstalled size: 353 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : vsftpd-3.0.2-27.el7.x86_64 1/1 \n Verifying : vsftpd-3.0.2-27.el7.x86_64 1/1 \n\nInstalled:\n vsftpd.x86_64 0:3.0.2-27.el7 \n\nComplete!\n"
]
}
#服务没有启动
[root@ansible ~]#ansible websrvs -m shell -a 'systemctl status vsftpd'
10.0.0.7 | FAILED | rc=3 >>
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
Active: inactive (dead)non-zero return code
10.0.0.8 | FAILED | rc=3 >>
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
Active: inactive (dead)non-zero return code
#service模块 启动服务,并没有设置为开机启动
[root@ansible ~]#ansible websrvs -m service -a 'name=vsftpd state=started'
...省略...
#查看服务状态,已经启动
[root@ansible ~]#ansible websrvs -m shell -a 'systemctl status vsftpd'
10.0.0.7 | CHANGED | rc=0 >>
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
Active: active (running) since Sat 2020-06-20 11:53:01 CST; 40s ago
Process: 3416 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)
Main PID: 3417 (vsftpd)
CGroup: /system.slice/vsftpd.service
└─3417 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
Jun 20 11:53:01 centos7.8.rain.org systemd[1]: Starting Vsftpd ftp daemon...
Jun 20 11:53:01 centos7.8.rain.org systemd[1]: Started Vsftpd ftp daemon.
10.0.0.8 | CHANGED | rc=0 >>
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled(此处表示没有设置为开机启动); vendor preset: disabled)
Active: active (running) since Sat 2020-06-20 11:53:02 CST; 40s ago
Process: 5331 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)
Main PID: 5332 (vsftpd)
Tasks: 1 (limit: 12371)
Memory: 540.0K
CGroup: /system.slice/vsftpd.service
└─5332 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
Jun 20 11:53:02 centos8.1-min.rain.org systemd[1]: Starting Vsftpd ftp daemon...
Jun 20 11:53:02 centos8.1-min.rain.org systemd[1]: Started Vsftpd ftp daemon.
#设置开机启动
[root@ansible ~]#ansible websrvs -m service -a 'name=vsftpd state=started enabled=yes'
#查看开机启动设置是否成功
[root@ansible ~]#ansible websrvs -m shell -a 'systemctl is-enabled vsftpd'
10.0.0.7 | CHANGED | rc=0 >>
enabled
10.0.0.8 | CHANGED | rc=0 >>
enabled
#查看服务状态
[root@ansible ~]#ansible websrvs -m shell -a 'systemctl status vsftpd'
10.0.0.7 | CHANGED | rc=0 >>
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)
Active: active (running) since Sat 2020-06-20 11:53:01 CST; 3min 45s ago
Main PID: 3417 (vsftpd)
CGroup: /system.slice/vsftpd.service
└─3417 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
Jun 20 11:53:01 centos7.8.rain.org systemd[1]: Starting Vsftpd ftp daemon...
Jun 20 11:53:01 centos7.8.rain.org systemd[1]: Started Vsftpd ftp daemon.
10.0.0.8 | CHANGED | rc=0 >>
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)
Active: active (running) since Sat 2020-06-20 11:53:02 CST; 3min 45s ago
Main PID: 5332 (vsftpd)
Tasks: 1 (limit: 12371)
Memory: 540.0K
CGroup: /system.slice/vsftpd.service
└─5332 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
Jun 20 11:53:02 centos8.1-min.rain.org systemd[1]: Starting Vsftpd ftp daemon...
Jun 20 11:53:02 centos8.1-min.rain.org systemd[1]: Started Vsftpd ftp daemon.
#停止服务
[root@ansible ~]#ansible websrvs -m service -a 'name=vsftpd state=stopped'
[root@ansible ~]#ansible websrvs -m shell -a 'systemctl status vsftpd'
10.0.0.7 | FAILED | rc=3 >>
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Sat 2020-06-20 12:04:07 CST; 38s ago
Main PID: 3417 (code=killed, signal=TERM)
Jun 20 11:53:01 centos7.8.rain.org systemd[1]: Starting Vsftpd ftp daemon...
Jun 20 11:53:01 centos7.8.rain.org systemd[1]: Started Vsftpd ftp daemon.
Jun 20 12:04:07 centos7.8.rain.org systemd[1]: Stopping Vsftpd ftp daemon...
Jun 20 12:04:07 centos7.8.rain.org systemd[1]: Stopped Vsftpd ftp daemon.non-zero return code
10.0.0.8 | FAILED | rc=3 >>
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Sat 2020-06-20 12:04:08 CST; 38s ago
Main PID: 5332 (code=killed, signal=TERM)
Jun 20 11:53:02 centos8.1-min.rain.org systemd[1]: Starting Vsftpd ftp daemon...
Jun 20 11:53:02 centos8.1-min.rain.org systemd[1]: Started Vsftpd ftp daemon.
Jun 20 12:04:08 centos8.1-min.rain.org systemd[1]: Stopping Vsftpd ftp daemon...
Jun 20 12:04:08 centos8.1-min.rain.org systemd[1]: Stopped Vsftpd ftp daemon.non-zero return code
功能:管理用户
范例:
#创建用户
ansible all -m user -a 'name=user1 comment=“test user” uid=2048 home=/app/user1
group=root'
ansible all -m user -a 'name=nginx comment=nginx uid=88 group=nginx
groups="root,daemon" shell=/sbin/nologin system=ynoes create_home=no
home=/data/nginx non_unique=yes'
#remove=yes表示删除用户及家目录等数据,默认remove=no
ansible all -m user -a 'name=nginx state=absent remove=yes'
功能:管理组
范例:
#创建组
ansible websrvs -m group -a 'name=nginx gid=88 system=yes'
#删除组
ansible websrvs -m group -a 'name=nginx state=absent'
ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时, 存在问题,无法正常进行替换 。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可 以方便的进行替换
行较少用Linefile模块,行较多建议写个文件用copy模块直接拷贝
功能:相当于sed,可以修改文件内容
范例:
ansible websrvs -m lineinfile -a "path=/etc/httpd/conf/httpd.conf
regexp='^Listen' line='Listen 80'"
ansible all -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX='
line='SELINUX=disabled'"
ansible all -m lineinfile -a 'dest=/etc/fstab state=absent regexp="^#"'
该模块有点类似于sed命令,主要也是基于正则进行匹配和替换,建议使用
范例:
ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"
ansible all -m replace -a "path=/etc/fstab regexp='^#(.*)' replace='\1'"
功能: setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机 较多,会影响执行速度,可以使用 gather_facts: no 来禁止 Ansible 收集 facts 信息
范例:
ansible all -m setup
ansible all -m setup -a "filter=ansible_nodename" #节点主机名
ansible all -m setup -a "filter=ansible_hostname" #主机名
ansible all -m setup -a "filter=ansible_domain" #域名
ansible all -m setup -a "filter=ansible_memtotal_mb" #物理内存
ansible all -m setup -a "filter=ansible_memory_mb" #总内存
ansible all -m setup -a "filter=ansible_memfree_mb" #剩余内存
ansible all -m setup -a "filter=ansible_os_family" #操作系统的版本
ansible all -m setup -a "filter=ansible_distribution_major_version" #主版本号
ansible all -m setup -a "filter=ansible_distribution_version" #发行版本
ansible all -m setup -a "filter=ansible_processor_vcpus" #cpu信息
ansible all -m setup -a "filter=ansible_all_ipv4_addresses" #ip地址
ansible all -m setup -a "filter=ansible_architecture" #架构
ansible all -m setup -a "filter=ansible_processor*" #进程
范例:查看python版本
[root@ansible ~]#ansible all -m setup -a 'filter=ansible_python_version'
10.0.0.7 | SUCCESS => {
"ansible_facts": {
"ansible_python_version": "2.7.5",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
10.0.0.6 | SUCCESS => {
"ansible_facts": {
"ansible_python_version": "2.6.6",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
10.0.0.8 | SUCCESS => {
"ansible_facts": {
"ansible_python_version": "3.6.8",
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false
}
[root@ansible ~]#
范例:取IP地址
#取所有IP
ansible 10.0.0.101 -m setup -a 'filter=ansible_all_ipv4_addresses'
10.0.0.101 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.0.1",
"192.168.0.2",
"192.168.64.238",
"192.168.13.36",
"10.0.0.101",
"172.16.1.0",
"172.17.0.1"
]
},
"changed": false
}
#取默认IP 相当于第一个ip
ansible all -m setup -a 'filter="ansible_default_ipv4"'
10.0.0.101 | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "10.0.0.101",
"alias": "eth0",
"broadcast": "10.0.0.255",
"gateway": "10.0.0.2",
"interface": "eth0",
"macaddress": "00:0c:29:e8:c7:9b",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "10.0.0.0",
"type": "ether"
}
},
"changed": false
}
playbook 剧本是由一个或多个“play”组成的列表 play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是 调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排 的机制执行预定义的动作
Playbook 文件是采用YAML语言编写的
YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,包括:XML、C语言、 Python、Perl以及电子邮件格式RFC2822等。Clark Evans在2001年在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者,目前很多软件中采有此格式的文件,如:ubuntu, anisble,docker,k8s等 YAML:YAML Ain’t Markup Language,即YAML不是XML。不过,在开发的这种语言时,YAML的意思 其实是:“Yet Another Markup Language”(仍是一种标记语言)
YAML 官方网站:http://www.yaml.org
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构 (Structure)通过空格来展示,序列(Sequence)里的项用"-“来代表,Map里的键值对用”:"分隔,下 面介绍常见的数据结构。
列表由多个元素组成,每个元素放在不同行,且元素前均使用“-”打头,或者将所有元素用 [ ] 括起来放 在同一行
范例:
#不同行,行以-开头,后面有一个空格
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango
#同一行
[Apple,Orange,Strawberry,Mango]
字典由多个key与value构成,key和value之间用 :分隔(:后面有一个空格),所有k/v可以放在一行,或者每个 k/v 分别放在不同行
冒号后有空格
范例 :
#不同行
# An employee record
name: Example Developer
job: Developer
skill: Elite
#同一行,也可以将key:value放置于{}中进行表示,用,分隔多个key:value
# An employee record
{name: “Example Developer”, job: “Developer”, skill: “Elite”}
范例: YAML 表示一个家庭
name: John Smith
age: 41
gender: Male
spouse:
name: Jane Smith
age: 37
gender: Female
children:
- {name: Jenny Smith, age: 13, gender: Female}
- {name: hao Smith, age: 20, gender: Male }
JSON格式为了节约空间,通常写在一行,文件比较小,在网络中传输减少网路带宽
https://www.json2yaml.com/
http://www.bejson.com/json/json2yaml/
范例:
[root@ansible ~]#tree
.
├── anaconda-ks.cfg
├── ansible.log
├── etc.tar.xz
├── hello.yml
├── ifcfg-eth0
├── mysql_backup.sh
└── ssh_push_key.sh
0 directories, 7 files
#JSON格式显示
[root@ansible ~]#tree -J
[{"type":"directory","name": ".","contents":[
{"type":"file","name":"anaconda-ks.cfg"},
{"type":"file","name":"ansible.log"},
{"type":"file","name":"etc.tar.xz"},
{"type":"file","name":"hello.yml"},
{"type":"file","name":"ifcfg-eth0"},
{"type":"file","name":"mysql_backup.sh"},
{"type":"file","name":"ssh_push_key.sh"}
]},
{"type":"report","directories":0,"files":7}
]
一个playbook 中由列表组成,其中所用到的常见组件类型如下:
Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts 用于指定要执行指定任务的主机,须事先定义在主机清单中
one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
Websrvs:dbsrvs #或者,两个组的并集
Websrvs:&dbsrvs #与,两个组的交集
webservers:!phoenix #在websrvs组,但不在dbsrvs组
案例:
- hosts: websrvs:appsrvs
remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可 用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: websrvs
remote_user: root
tasks:
- name: test connection
ping:
remote_user: magedu
sudo: yes #默认sudo为root
sudo_user:wang #sudo为wang
play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主 机上执行,即在所有主机上完成第一个task后,再开始第二个task task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着 多次执行是安全的,因为其结果均一致
每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。 如果未提供name,则action的结果将用于输出
task两种格式:
action: module arguments
module: arguments 建议使用
注意:shell和command模块后面跟命令,而非key=value
范例:
---
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started enabled=yes
某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers
任务可以通过"tags"打标签,可在ansible-playbook命令上使用-t指定进行调用
#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: websrvs
remote_user: root
tasks:
- name: "安装Apache"
yum: name=httpd
- name: "复制配置文件"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
- name: "复制配置文件"
copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
- name: "启动Apache,并设置开机启动"
service: name=httpd state=started enabled=yes
格式
ansible-playbook <filename.yml> ... [options]
常见选项
-C --check #只检测可能会发生的改变,但不真正执行操作
--list-hosts #列出运行任务的主机
--list-tags #列出tag
--list-tasks #列出task
--limit 主机列表 #只针对主机列表中的特定主机执行
-v -vv -vvv #显示过程
范例:
[root@ansible ansible]#cat hello.yml
---
- hosts: websrvs
tasks:
- name: hello
command: echo "hello ansible"
[root@ansible ansible]#ansible-playbook hello.yml
[root@ansible ansible]#ansible-playbook -v hello.yml
范例
ansible-playbook file.yml --check #只检测
ansible-playbook file.yml
ansible-playbook file.yml --limit websrvs
范例:
[root@ansible ansible]#vim hello.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: 是否正常
ping:
- name: 清理/data/
shell: rm -rf /data/*
[root@ansible ansible]#ansible-playbook --list-hosts hello.yml
playbook: hello.yml
play #1 (websrvs): websrvs TAGS: []
pattern: ['websrvs']
hosts (2):
10.0.0.7
10.0.0.8
[root@ansible ansible]#ansible-playbook --list-tasks hello.yml
playbook: hello.yml
play #1 (websrvs): websrvs TAGS: []
tasks:
是否正常 TAGS: []
清理/data/ TAGS: []
[root@ansible ansible]#ansible-playbook --limit 10.0.0.7 hello.yml
PLAY [websrvs] *******************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
TASK [是否正常] **********************************************************************************************************
ok: [10.0.0.7]
TASK [清理/data/] ******************************************************************************************************
[WARNING]: Consider using the file module with state=absent rather than running 'rm'. 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.
changed: [10.0.0.7]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
实验:利用playbook安装httpd服务
[root@ansible ansible]#vim httpd.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started enabled=yes
#检查是否有语法错误
[root@ansible ansible]#ansible-playbook -C httpd.yml
PLAY [websrvs] *******************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [install httpd] *************************************************************************************************
changed: [10.0.0.8]
changed: [10.0.0.7]
TASK [start httpd] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible ansible]#ansible-playbook httpd.yml
PLAY [websrvs] *******************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [install httpd] *************************************************************************************************
changed: [10.0.0.8]
changed: [10.0.0.7]
TASK [start httpd] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#检查安装启动情况
[root@centos8 ~]#rpm -q httpd
httpd-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
[root@centos8 ~]#systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since Sat 2020-06-20 16:38:15 CST; 2min 11s ago
Docs: man:httpd.service(8)
Main PID: 10710 (httpd)
Status: "Running, listening on: port 80"
Tasks: 213 (limit: 12371)
Memory: 32.5M
CGroup: /system.slice/httpd.service
├─10710 /usr/sbin/httpd -DFOREGROUND
├─10723 /usr/sbin/httpd -DFOREGROUND
├─10724 /usr/sbin/httpd -DFOREGROUND
├─10725 /usr/sbin/httpd -DFOREGROUND
└─10726 /usr/sbin/httpd -DFOREGROUND
Jun 20 16:38:14 centos8.1-min.rain.org systemd[1]: Starting The Apache HTTP Server...
Jun 20 16:38:15 centos8.1-min.rain.org systemd[1]: Started The Apache HTTP Server.
Jun 20 16:38:15 centos8.1-min.rain.org httpd[10710]: Server configured, listening on: port 80
范例:mysql_user.yml
---
- hosts: dbsrvs
remote_user: root
tasks:
- {name: create group, group: name=mysql system=yes gid=306}
- name: create user
user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306
home=/data/mysql create_home=no
实验:详细版
[root@ansible ansible]#vim mysql.yml
---
- hosts: dbsrvs
remote_user: root
tasks:
- name: create group
group: name=mysql system=yes gid=306
- name: create user
user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 home=/data/mysql create_home=no
#语法检查
[root@ansible ansible]#ansible-playbook -C mysql.yml
PLAY [dbsrvs] ********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [create group] **************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [create user] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#执行
[root@ansible ansible]#ansible-playbook mysql.yml
PLAY [dbsrvs] ********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [create group] **************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [create user] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#检查是否创建成功
[root@centos8 ~]#getent passwd
mysql:x:306:306:MySQL Server:/data/mysql:/sbin/nologin
[root@centos8 ~]#getent group
mysql:x:306:
#删除上述创建的mysql账户,上述没有创建家目录,则state=absent 不用加remove=yes
[root@ansible ansible]#vim remove_mysql_user.yml
---
- hosts: dbsrvs
remote_user: root
tasks:
- name: delete user
user: name=mysql state=absent
[root@ansible ansible]#ansible-playbook -C remove_mysql_user.yml
PLAY [dbsrvs] ********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [delete user] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible ansible]#ansible-playbook remove_mysql_user.yml
PLAY [dbsrvs] ********************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [delete user] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#删除成功
[root@centos8 ~]#getent passwd mysql
[root@centos8 ~]#getent group mysql
nginx网页文件/usr/share/nginx/html/index.html
httpd网页文件/var/www/html/index.html
范例:install_nginx.yml
---
# install nginx
- hosts: websrvs
remote_user: root
tasks:
- name: add group nginx
user: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install Nginx
yum: name=nginx state=present
- name: web page
copy: src=files/index.html dest=/usr/share/nginx/html/index.html
- name: Start Nginx
service: name=nginx state=started enabled=yes
实验:详细版
[root@ansible ansible]#mkdir files
[root@ansible ansible]#vim files/index.html
>welcome to 6.18 magedu
>
[root@ansible ansible]#vim install_nginx.yml
---
# install nginx
- hosts: websrvs
remote_user: root
tasks:
- name: 创建nginx组
user: name=nginx
- name: 创建nginx用户
user: name=nginx group=nginx
- name: 安装 Nginx
yum : name=nginx state=present
- name: 网页
copy: src=files/index.html dest=/usr/share/nginx/html/index.html
- name: Start Nginx
service: name=nginx state=started enabled=yes
#安装
[root@ansible ansible]#ansible-playbook install_nginx.yml
PLAY [websrvs] *******************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [创建nginx组] ******************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [创建nginx用户] *****************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [安装 Nginx] ******************************************************************************************************
changed: [10.0.0.8]
changed: [10.0.0.7]
TASK [网页] ************************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [Start Nginx] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=6 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=6 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8bJd6Ll2-1592754504004)(G:\Tptupian\1592651771408.png)]
Nginx和Httpd服务冲突,装在同一台机器上需要错开端口号
范例:install_httpd.yml
---
#install httpd
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/ #先在本机安装httpd,然后将配置文件拷贝到目标主机对应目录
- name: modify config
lineinfile: path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 8080'
- name: mkdir website dir
file: path=/data/html state=directory
- name: web html
copy: src=files/index.html dest=/data/html/
- name: start service
service: name=httpd state=started enabled=yes
ansible-playbook install_httpd.yml --limit 10.0.0.8
实验:详细版
[root@ansible ansible]#cp /etc/httpd/conf/httpd.conf files/
[root@ansible ansible]#tree files/
files/
├── httpd.conf
└── index.html
0 directories, 2 files
[root@ansible ansible]#vim files/index.html
>welcome to 6.18 magedu for httpd >
[root@ansible ansible]#vim install_httpd.yml
---
# install httpd
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: Install Httpd 安装httpd
yum: name=httpd state=present
- name: Install configure file 安装配置文件
copy: src=files/httpd.conf dest=/etc/httpd/conf/
- name: modify config 修改配置文件
lineinfile: path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 8080'
- name: mkdir website dir 创建网页文件
file: path=/data/html state=directory
- name: web html 网页
copy: src=files/index.html dest=/data/html/
- name: start service 开启服务
service: name=httpd state=started enabled=yes
#修改httpd配置文件,因为网页文件放在/data/下
[root@ansible ansible]#vim files/httpd.conf
#DocumentRoot "/var/www/html"
DocumentRoot "/data/html"
#
# Relax access to content within /var/www.
#
>
AllowOverride None
# Allow open access:
Require all granted
>
# Further relax access to the default document root:
>
#语法检查,
[root@ansible ansible]#ansible-playbook -C install_httpd.yml
PLAY [websrvs] *******************************************************************************************************
TASK [Install Httpd 安装httpd] *****************************************************************************************
changed: [10.0.0.8]
changed: [10.0.0.7]
TASK [Install configure file 安装配置文件] *********************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [modify config 修改配置文件] *****************************************************************************************
#此处报错是因为语法检查没有真正执行,没有生成文件,故改文件发生错误,执行即可
fatal: [10.0.0.7]: FAILED! => {"changed": false, "msg": "Destination /etc/httpd/conf/httpd.conf does not exist !", "rc": 257}
fatal: [10.0.0.8]: FAILED! => {"changed": false, "msg": "Destination /etc/httpd/conf/httpd.conf does not exist !", "rc": 257}
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=2 changed=2 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=2 changed=2 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
#执行
[root@ansible ansible]#ansible-playbook install_httpd.yml
PLAY [websrvs] *******************************************************************************************************
TASK [Install Httpd 安装httpd] *****************************************************************************************
changed: [10.0.0.8]
changed: [10.0.0.7]
TASK [Install configure file 安装配置文件] *********************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [modify config 修改配置文件] ******************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [mkdir website dir 创建网页文件] **************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [web html 网页] ***************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [start service 开启服务] ********************************************************************************************
changed: [10.0.0.8]
changed: [10.0.0.7]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=6 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=6 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#查看端口
[root@ansible ansible]#ansible websrvs -m shell -a 'ss -ntl'
10.0.0.7 | 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 *:8080 *:*
LISTEN 0 128 *:80 *:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
LISTEN 0 128 [::]:80 [::]:*
10.0.0.8 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 *:8080 *:*
LISTEN 0 128 [::]:80 [::]:*
LISTEN 0 128 [::]:22 [::]:*
注意:写8080端口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jrvSVeyQ-1592754504005)(G:\Tptupian\1592653793383.png)]
范例:remove_httpd.yml
注意:安装的时候会创建用户,删除的时候不会删除用户,故第二步删除apache user
#remove_httpd.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: remove httpd package
yum: name=httpd state=absent
- name: remove apache user
user: name=apache state=absent
- name: remove config file
file: name=/etc/httpd state=absent
- name: remove web html
file: name=/data/html/ state=absent
实验:详细版
[root@ansible ansible]#vim remove_httpd.yml
# remove_httpd.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: remove httpd package 删除httpd安装包
yum: name=httpd state=absent
- name: remove apache user 删除用户
user: name=apache state=absent
- name: remove config file 删除配置文件
file: name=/etc/httpd state=absent
- name: remove web html 删除网页文件
file: name=/data/html state=absent
[root@ansible ansible]#ansible-playbook remove_httpd.yml
PLAY [websrvs] *******************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [remove httpd package 删除httpd安装包] *******************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [remove apache user 删除用户] ***************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [remove config file 删除配置文件] *************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [remove web html 删除网页文件] ****************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP ***********************************************************************************************************
10.0.0.7 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#检查是否删除成功
[root@centos8 ~]#ls /etc/httpd
ls: cannot access '/etc/httpd': No such file or directory
[root@centos8 ~]#ls /data/html
ls: cannot access '/data/html': No such file or directory
[root@centos8 ~]#getent passwd apache
范例:安装mysql-5.6.46-linux-glibc2.12
[root@ansible ~]#ls -l /data/ansible/files/mysql-5.6.46-linux-glibc2.12-
x86_64.tar.gz
-rw-r--r-- 1 root root 403177622 Dec 4 13:05 /data/ansible/files/mysql-5.6.46-
linux-glibc2.12-x86_64.tar.gz
[root@ansible ~]#cat /data/ansible/files/my.cnf
[mysqld]
socket=/tmp/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
log-bin
pid-file=/data/mysql/mysqld.pid
[client]
port=3306
socket=/tmp/mysql.sock
[mysqld_safe]
log-error=/var/log/mysqld.log
[root@ansible ~]#cat /data/ansible/files/secure_mysql.sh
#!/bin/bash
/usr/local/mysql/bin/mysql_secure_installation <<EOF
y
magedu
magedu
y
y
y
y
EOF
[root@ansible ~]#tree /data/ansible/files/
/data/ansible/files/
├── my.cnf
├── mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
└── secure_mysql.sh
0 directories, 3 files
[root@ansible ~]#cat /data/ansible/install_mysql.yml
---
# install mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
- hosts: dbsrvs
remote_user: root
gather_facts: no
tasks:
- name: install packages
yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long
- name: create mysql group
group: name=mysql gid=306
- name: create mysql user
user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql #不自动创建,家目录,手工创建
- name: copy tar to remote host and file mode
unarchive: src=/data/ansible/files/mysql-5.6.46-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.6.46-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
- name: data dir
shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db
--datadir=/data/mysql --user=mysql
tags: data
- name: config my.cnf
copy: src=/data/ansible/files/my.cnf dest=/etc/my.cnf
- name: service script
shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
- name: enable service
shell: /etc/init.d/mysqld start;chkconfig --add mysqld;chkconfig mysqld on
tags: service
- name: PATH variable
copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
- name: secure script
script: /data/ansible/files/secure_mysql.sh
tags: script
扩展知识点:手工创建家目录
若自动创建家目录,会把/etc/skel/ 目录下的文件拷贝到mysql家目录下/var/lib/mysql
/etc/skel/ 下有隐藏文件,可能有隐藏子目录,拷贝到/var/lib/mysql下,会在数据库中形成垃圾数据库
show databases可见到垃圾数据库
家目录下有几个子目录,show databases;则有几个数据库,还有一个内存数据库
范例:install_mariadb.yml
---
#Installing MariaDB Binary Tarballs
- hosts: dbsrvs
remote_user: root
gather_facts: no
tasks:
- name: create group
group: name=mysql gid=27 system=yes
- name: create user
user: name=mysql uid=27 system=yes group=mysql shell=/sbin/nologin
home=/data/mysql create_home=no
- name: mkdir datadir
file: path=/data/mysql owner=mysql group=mysql state=directory
- name: unarchive package
unarchive: src=/data/ansible/files/mariadb-10.2.27-linux-x86_64.tar.gz
dest=/usr/local/ owner=root group=root
- name: link
file: src=/usr/local/mariadb-10.2.27-linux-x86_64 path=/usr/local/mysql state=link
- name: install database
shell: chdir=/usr/local/mysql ./scripts/mysql_install_db --datadir=/data/mysql
--user=mysql
- name: config file
copy: src=/data/ansible/files/my.cnf dest=/etc/ backup=yes
- name: service script
shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
- name: start service
service: name=mysqld state=started enabled=yes
- name: PATH variable
copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
Handlers本质是task list ,类似于MySQL中的触发器触发的行为,其中的task与前述的task并没有本质 上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而Notify对应的action可用于在 每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完 成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的 操作
因为幂等性,修改了配置文件,改端口之类的,他不会自动重启服务,则用触发器
案例:
---
- hosts: websrvs
remote_user: root
gather_facts: no
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
- name: ensure apache is running
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted
案例:
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: add group nginx
user: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install Nginx
yum: name=nginx state=present
- name: config
copy: src=/root/config.txt dest=/etc/nginx/nginx.conf
notify:
- Restart Nginx
- Check Nginx Process
handlers:
- name: Restart Nginx
service: name=nginx state=restarted enabled=yes
- name: Check Nginx process
shell: killall -0 nginx &> /tmp/nginx.log
实验:更改httpd端口,触发重新启动
[root@ansible ansible]#vim install_httpd.yml
---
# install httpd
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: Install Httpd 安装httpd
yum: name=httpd state=present
- name: Install configure file 安装配置文件
copy: src=files/httpd.conf dest=/etc/httpd/conf/
notify: restart service
- name: modify config 修改配置文件
lineinfile: path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 8888'
notify: restart service
- name: mkdir website dir 创建网页文件
file: path=/data/html state=directory
- name: web html 网页
copy: src=files/index.html dest=/data/html/
- name: start service 开启服务
service: name=httpd state=started enabled=yes
handlers:
- name: restart service
service: name=httpd state=restarted
[root@ansible ansible]#ansible-playbook install_httpd.yml
PLAY [websrvs] *****************************************************************************************************************************************
TASK [Install Httpd 安装httpd] ***************************************************************************************************************************
ok: [10.0.0.8]
ok: [10.0.0.7]
TASK [Install configure file 安装配置文件] *******************************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [modify config 修改配置文件] ****************************************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [mkdir website dir 创建网页文件] ************************************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [web html 网页] *************************************************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [start service 开启服务] ******************************************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
RUNNING HANDLER [restart service] **********************************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP *********************************************************************************************************************************************
10.0.0.7 : ok=7 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=7 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible ansible]#ansible websrvs -m shell -a 'ss -ntl'
10.0.0.7 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:80 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 80 [::]:3306 [::]:*
LISTEN 0 128 [::]:80 [::]:*
LISTEN 0 32 [::]:21 [::]:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 128 [::]:8888 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
10.0.0.8 | CHANGED | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:80 [::]:*
LISTEN 0 32 *:21 *:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 128 *:8888 *:*
LISTEN 0 80 *:3306 *:*
实验:更改httpd配置文件,启动用户改为daemon
[root@ansible ansible]#vim files/httpd.conf
User daemon
Group daemon
[root@ansible ansible]#ansible-playbook install_httpd.yml
PLAY [websrvs] *****************************************************************************************************************************************
TASK [Install Httpd 安装httpd] ***************************************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [Install configure file 安装配置文件] *******************************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [modify config 修改配置文件] ****************************************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [mkdir website dir 创建网页文件] ************************************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [web html 网页] *************************************************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [start service 开启服务] ******************************************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
RUNNING HANDLER [restart service] **********************************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP *********************************************************************************************************************************************
10.0.0.7 : ok=7 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=7 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@centos8 ~]#ps aux
daemon 8712 0.0 0.4 292468 8472 ? S 11:16 0:00 /usr/sbin/httpd -DFOREGROUND
daemon 8713 0.0 0.5 1350244 11744 ? Sl 11:16 0:00 /usr/sbin/httpd -DFOREGROUND
daemon 8714 0.0 0.5 1350244 11744 ? Sl 11:16 0:00 /usr/sbin/httpd -DFOREGROUND
daemon 8715 0.0 0.6 1481372 13792 ? Sl 11:16 0:00 /usr/sbin/httpd -DFOREGROUND
在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特 定tags的task,而非整个playbook文件
案例:
vim httpd.yml
---
# tags example
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
tags: conf
- name: start httpd service
tags: service
service: name=httpd state=started enabled=yes
ansible-playbook –t conf,service httpd.yml
实验:添加标签
[root@ansible ansible]#vim install_httpd.yml
---
# install httpd
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: Install Httpd 安装httpd
yum: name=httpd state=present
- name: Install configure file 安装配置文件
copy: src=files/httpd.conf dest=/etc/httpd/conf/
tags: conf
notify: restart service
- name: modify config 修改配置文件
lineinfile: path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 8888'
notify: restart service
tags: conf
- name: mkdir website dir 创建网页文件
file: path=/data/html state=directory
- name: web html 网页
tags: html
copy: src=files/index.html dest=/data/html/
- name: start service 开启服务
service: name=httpd state=started enabled=yes
handlers:
- name: restart service
service: name=httpd state=restarted
#查看标签
[root@ansible ansible]#ansible-playbook --list-tags install_httpd.yml
playbook: install_httpd.yml
play #1 (websrvs): websrvs TAGS: []
TASK TAGS: [conf, html]
[root@ansible ansible]#vim files/index.html
<h1>welcome to 6.18 magedu for httpd v2 <h1>
#只执行html标签
[root@ansible ansible]#ansible-playbook -t html install_httpd.yml
PLAY [websrvs] *****************************************************************************************************************************************
TASK [web html 网页] *************************************************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP *********************************************************************************************************************************************
10.0.0.7 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YbWCusDp-1592754504006)(G:\Tptupian\1592709975040.png)]
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:
variable=value
范例:
http_port=80
变量调用方式:
通过{{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效
变量来源:
ansible-playbook -e varname=value test.yml
vars:
- var1: value1
- var2: value2
- hosts: all
vars_files:
- vars.yml
在 /etc/ansible/hosts 中定义
主机(普通)变量:主机组中主机单独定义,优先级高于公共变量
组(公共)变量:针对主机组中所有主机定义统一变量
在role中定义
本模块自动在playbook调用,不要用ansible命令调用
案例:使用setup变量
ansible 10.0.0.101 -m setup -a 'filter="ansible_default_ipv4"'
10.0.0.101 | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "10.0.0.101",
"alias": "eth0",
"broadcast": "10.0.0.255",
"gateway": "10.0.0.2",
"interface": "eth0",
"macaddress": "00:0c:29:e8:c7:9b",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "10.0.0.0",
"type": "ether"
}
},
"changed": false
}
范例:
---
#var1.yml
- hosts: all
remote_user: root
gather_facts: yes #必须搜集,不然setup模块不会使用,可不写,默认yes
tasks:
- name: create log file
file: name=/data/{{ ansible_nodename }}.log state=touch owner=wang
mode=600
ansible-playbook var.yml
实验:详细版
[root@ansible ansible]#vim var1.yml
---
# var1.yml
- hosts: websrvs
remote_user: root
gather_facts: yes
tasks:
- name: create log file
file: name=/data/{{ ansible_nodename }}.log state=touch owner=rain mode=600
[root@ansible ansible]#ansible-playbook var1.yml
PLAY [websrvs] *****************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [create log file] *********************************************************************************************************************************
changed: [10.0.0.7]
changed: [10.0.0.8]
PLAY RECAP *********************************************************************************************************************************************
10.0.0.7 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible ansible]#ansible websrvs -a 'ls -l /data'
10.0.0.8 | CHANGED | rc=0 >>
total 432
-rw------- 1 rain root 0 Jun 21 11:36 centos8.1-min.rain.org.log
drwxr-xr-x 79 root root 8192 Jun 20 08:20 etc
drwxr-xr-x 2 root root 24 Jun 21 11:21 html
-rw------- 1 rain root 427496 Jun 20 09:36 log.tar.bz2
drwx------ 5 mysql mysql 295 Jun 21 09:32 mysql
10.0.0.7 | CHANGED | rc=0 >>
total 0
-rw------- 1 rain root 0 Jun 21 11:36 centos7.8.rain.org.log
drwxr-xr-x 2 root root 24 Jun 21 11:21 html
drwx------ 5 mysql mysql 218 Jun 21 09:32 mysql
[root@ansible ansible]#vim var1.yml
---
# var1.yml
- hosts: websrvs
remote_user: root
gather_facts: yes
tasks:
- name: create log file
file: name=/data/{{ ansible_nodename }}-{{ansible_distribution_major_version}}.log state=touch owner=rain mode=600 #此处发生更改,{{}}中间变量首尾没有空格,习惯加空格,较为清晰
[root@ansible ansible]#ansible websrvs -a 'ls -l /data'
10.0.0.7 | CHANGED | rc=0 >>
total 0
-rw------- 1 rain root 0 Jun 21 11:39 centos7.8.rain.org-7.log
-rw------- 1 rain root 0 Jun 21 11:36 centos7.8.rain.org.log
drwxr-xr-x 2 root root 24 Jun 21 11:21 html
drwx------ 5 mysql mysql 218 Jun 21 09:32 mysql
10.0.0.8 | CHANGED | rc=0 >>
total 432
-rw------- 1 rain root 0 Jun 21 11:40 centos8.1-min.rain.org-8.log
-rw------- 1 rain root 0 Jun 21 11:36 centos8.1-min.rain.org.log
drwxr-xr-x 79 root root 8192 Jun 20 08:20 etc
drwxr-xr-x 2 root root 24 Jun 21 11:21 html
-rw------- 1 rain root 427496 Jun 20 09:36 log.tar.bz2
drwx------ 5 mysql mysql 295 Jun 21 09:32 mysql
命令行 -e的优先级比playbook优先级高
范例:
vim var2.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: install package
yum: name={{ pkname }} state=present
ansible-playbook –e pkname=httpd var2.yml
实验:详细版
[root@ansible ansible]#vim var2.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: install package 安装包
yum: name={{ pkname }} state=present #卸载将此处改为absent即可
[root@ansible ansible]#ansible-playbook -e pkname=memcached var2.yml
PLAY [websrvs] *****************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [install package 安装包] *****************************************************************************************************************************
changed: [10.0.0.8]
changed: [10.0.0.7]
PLAY RECAP *********************************************************************************************************************************************
10.0.0.7 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#查看安装情况
[root@ansible ansible]#ansible websrvs -m shell -a 'rpm -qi memcached'
[WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'. If you need to use command because yum, dnf or zypper 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.
10.0.0.7 | CHANGED | rc=0 >>
Name : memcached
Epoch : 0
Version : 1.4.15
Release : 10.el7_3.1
Architecture: x86_64
Install Date: Sun 21 Jun 2020 11:46:57 AM CST #安装时间
Group : System Environment/Daemons
Size : 180237
License : BSD
Signature : RSA/SHA256, Sat 26 Nov 2016 12:03:28 AM CST, Key ID 24c6a8a7f4a80eb5
Source RPM : memcached-1.4.15-10.el7_3.1.src.rpm
Build Date : Fri 25 Nov 2016 11:36:56 PM CST
Build Host : c1bm.rdu2.centos.org
Relocations : (not relocatable)
Packager : CentOS BuildSystem <http://bugs.centos.org>
Vendor : CentOS
URL : http://www.memcached.org/
Summary : High Performance, Distributed Memory Object Cache
Description :
memcached is a high-performance, distributed memory object caching
system, generic in nature, but intended for use in speeding up dynamic
web applications by alleviating database load.
10.0.0.8 | CHANGED | rc=0 >>
Name : memcached
Epoch : 0
Version : 1.5.9
Release : 3.el8
Architecture: x86_64
Install Date: Sun 21 Jun 2020 11:46:46 AM CST
Group : System Environment/Daemons
Size : 280586
License : BSD
Signature : RSA/SHA256, Tue 07 Apr 2020 09:18:39 AM CST, Key ID 05b555b38483c65d
Source RPM : memcached-1.5.9-3.el8.src.rpm
Build Date : Tue 07 Apr 2020 04:41:42 AM CST
Build Host : x86-01.mbox.centos.org
Relocations : (not relocatable)
Packager : CentOS Buildsys <[email protected]>
Vendor : CentOS
URL : https://www.memcached.org/
Summary : High Performance, Distributed Memory Object Cache
Description :
memcached is a high-performance, distributed memory object caching
system, generic in nature, but intended for use in speeding up dynamic
web applications by alleviating database load.
范例:
vim var3.yml
---
- hosts: websrvs
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
#命令行 -e的优先级比playbook优先级高
ansible-playbook -e "username=user2 groupname=group2" var3.yml
范例:
cat var4.yaml
---
- hosts: websrvs
remote_user: root
vars:
collect_info: "/data/test/{{ansible_default_ipv4['address']}}/"
tasks:
- name: create IP directory
file: name="{{collect_info}}" state=directory
#执行结果
tree /data/test/
/data/test/
└── 10.0.0.102
1 directory, 0 files
可以在一个独立的playbook文件中定义变量,在另一个playbook文件中引用变量文件中的变量,比 playbook中定义的变量优化级高
vim vars.yml
---
# variables file
package_name: mariadb-server
service_name: mariadb
vim var5.yml
---
#install package and start service
- hosts: dbsrvs
remote_user: root
vars_files:
- vars.yml
tasks:
- name: install package
yum: name={{ package_name }}
tags: install
- name: start service
service: name={{ service_name }} state=started enabled=yes
范例:
cat vars2.yml
---
var1: httpd
var2: nginx
cat var6.yml
---
- hosts: web
remote_user: root
vars_files:
- vars2.yml
tasks:
- name: create httpd log
file: name=/app/{{ var1 }}.log state=touch
- name: create nginx log
file: name=/app/{{ var2 }}.log state=touch
在inventory 主机清单文件中为指定的主机定义变量以便于在playbook中使用
范例:
[websrvs]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909
在inventory 主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变是 同名,优先级低于主机变量
范例:
vim /etc/ansible/hosts
[websrvs]
10.0.0.8 hname=www1 domain=magedu.io
10.0.0.7 hname=www2
[websvrs:vars]
mark="-"
domain=magedu.org
ansible websvrs –m hostname –a 'name={{ hname }}{{ mark }}{{ domain }}'
bash
#命令行指定变量:
ansible websvrs –e domain=magedu.cn –m hostname –a 'name={{ hname }}{{ mark}}{{ domain }}'
[root@ansible ansible]#ansible websrvs -m hostname -a 'name={{ hname }}{{ mark }}{{ domain }}'
10.0.0.7 | CHANGED => {
"ansible_facts": {
"ansible_domain": "org",
"ansible_fqdn": "www2-magedu.org",
"ansible_hostname": "www2-magedu",
"ansible_nodename": "www2-magedu.org",
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"name": "www2-magedu.org"
}
10.0.0.8 | CHANGED => {
"ansible_facts": {
"ansible_domain": "io",
"ansible_fqdn": "www1-magedu.io",
"ansible_hostname": "www1-magedu",
"ansible_nodename": "www1-magedu.io",
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"name": "www1-magedu.io"
}
模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja语法
http://jinja.pocoo.org/
https://jinja.palletsprojects.com/en/2.11.x/
jinja2 语言使用字面量,有下面形式:
字面量:
表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如"Hello World"
双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过 滤器或只是包含或继承一个模板的参数),如42,42.23
数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在 Python 里, 42 和 42.0 是不 一样的
算术运算:
Jinja 允许用计算值。支持下面的运算符
比较操作符
== 比较两个对象是否相等
!= 比较两个对象是否不等 > 如果左边大于右边,返回 true
>= 如果左边大于等于右边,返回 true
<=如果左边小于右边,返回 true <= 如果左边小于等于右边,返回 true
逻辑运算符
对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式
and 如果左操作数和右操作数同为真,返回 true
or 如果左操作数和右操作数有一个为真,返回
true not 对一个表达式取反 (expr)表达式组
true / false true 永远是 true ,而 false 始终是 false
template功能:可以根据和参考模块文件,动态生成相类似的配置文件
template文件必须存放于templates目录下,且命名为 .j2 结尾
yaml/yml 文件需和templates目录平级,目录结构如下示例:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
范例:利用template 同步nginx配置文件
#准备templates/nginx.conf.j2文件
vim temnginx.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
ansible-playbook temnginx.yml
template变更替换
范例:
#修改文件nginx.conf.j2
mkdir templates
vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus }};
vim temnginx2.yml
---
- hosts: websrvs
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: start service
service: name=nginx state=started enabled=yes
ansible-playbook temnginx2.yml
template算术运算
范例:
vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**2 }};
worker_processes {{ ansible_processor_vcpus+2 }};
范例:
[root@ansible ansible]#vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**3 }};
[root@ansible ansible]#cat templnginx.yml
---
- hosts: websrvs
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
notify: restart nginx
- name: start service
service: name=nginx state=started enabled=yes
handlers:
- name: restart nginx
service: name=nginx state=restarted
ansible-playbook templnginx.yml --limit 10.0.0.8
template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能
范例
#temlnginx2.yml
---
- hosts: websrvs
remote_user: root
vars:
nginx_vhosts:
- 81
- 82
- 83
tasks:
- name: template config
template: src=nginx.conf.j2 dest=/data/nginx.conf
#templates/nginx.conf2.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost }}
}
{% endfor %}
ansible-playbook -C templnginx2.yml --limit 10.0.0.8
#生成的结果:
server {
listen 81
}
server {
listen 82
}
server {
listen 83
}
范例:
#temlnginx3.yml
---
- hosts: websrvs
remote_user: root
vars:
nginx_vhosts:
- listen: 8080
tasks:
- name: config file
template: src=nginx.conf3.j2 dest=/data/nginx3.conf
#templates/nginx.conf3.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}
ansible-playbook templnginx3.yml --limit 10.0.0.8
#生成的结果
server {
listen 8080
}
范例:
#templnginx4.yml
- hosts: websrvs
remote_user: root
vars:
nginx_vhosts:
- listen: 8080
server_name: "web1.magedu.com"
root: "/var/www/nginx/web1/"
- listen: 8081
server_name: "web2.magedu.com"
root: "/var/www/nginx/web2/"
- {listen: 8082, server_name: "web3.magedu.com", root:
"/var/www/nginx/web3/"}
tasks:
- name: template config
template: src=nginx.conf4.j2 dest=/data/nginx4.conf
# templates/nginx.conf4.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
server_name {{ vhost.server_name }}
root {{ vhost.root }}
}
{% endfor %}
ansible-playbook templnginx4.yml --limit 10.0.0.8
#生成结果:
server {
listen 8080
server_name web1.magedu.com
root /var/www/nginx/web1/
}
server {
listen 8081
server_name web2.magedu.com
root /var/www/nginx/web2/
}
server {
listen 8082
server_name web3.magedu.com
root /var/www/nginx/web3/
}
在模版文件中还可以使用 if条件判断,决定是否生成相关的配置信息
范例:
#templnginx5.yml
- hosts: websrvs
remote_user: root
vars:
nginx_vhosts:
- web1:
listen: 8080
root: "/var/www/nginx/web1/"
- web2:
listen: 8080
server_name: "web2.magedu.com"
root: "/var/www/nginx/web2/"
- web3:
listen: 8080
server_name: "web3.magedu.com"
root: "/var/www/nginx/web3/"
tasks:
- name: template config to
template: src=nginx.conf5.j2 dest=/data/nginx5.conf
#templates/nginx.conf5.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }}
{% endif %}
root {{ vhost.root }}
}
{% endfor %}
#生成的结果
server {
listen 8080
root /var/www/nginx/web1/
}
server {
listen 8080
server_name web2.magedu.com
root /var/www/nginx/web2/
}
server {
listen 8080
server_name web3.magedu.com
root /var/www/nginx/web3/
}
when语句,可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与 否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式
范例:
---
- hosts: websrvs
remote_user: root
tasks:
- name: "shutdown RedHat flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "RedHat"
范例:
---
- hosts: websrvs
remote_user: root
tasks:
- name: add group nginx
tags: user
user: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install Nginx
yum: name=nginx state=present
- name: restart Nginx
service: name=nginx state=restarted
when: ansible_distribution_major_version == "6"
范例:
---
- hosts: websrvs
remote_user: root
tasks:
- name: install conf file to centos7
template: src=nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
template: src=nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "6"
实验:只重启Debian系统
[root@ansible ansible]#vim reboot.yml
---
- hosts: all
remote_user: root
tasks:
- name: "shutdown Debian systems"
command: reboot
when: ansible_os_family == "Debian"
[root@ansible ansible]#ansible-playbook reboot.yml
PLAY [all] *********************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [10.0.0.100]
ok: [10.0.0.8]
ok: [10.0.0.7]
ok: [10.0.0.6]
TASK [shutdown Debian systems] *************************************************************************************************************************
skipping: [10.0.0.8]
skipping: [10.0.0.7]
skipping: [10.0.0.6]
fatal: [10.0.0.100]: FAILED! => {"msg": "Failed to connect to the host via ssh: mux_client_request_session: read from master failed: Broken pipe\r\nFailed to connect to new control master"} #此处报错显示已经重启,连接不上
PLAY RECAP *********************************************************************************************************************************************
10.0.0.100 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
10.0.0.6 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
10.0.0.7 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
10.0.0.8 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
#uptime显示,开机0min
[root@ubuntu1804 ~]#uptime
08:43:16 up 0 min, 1 user, load average: 1.00, 0.23, 0.07
迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为"item"
要在task中使用with_items给定要迭代的元素列表
列表元素格式:
范例:
---
- hosts: websrvs
remote_user: root
tasks:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
- testuser3
#上面语句的功能等同于下面的语句
- name: add several users
user: name=testuser1 state=present groups=wheel
- name: add several users
user: name=testuser2 state=present groups=wheel
- name: add several users
user: name=testuser3 state=present groups=wheel
范例:卸载 mariadb
---
#remove mariadb server
- hosts: appsrvs:!10.0.0.8
remote_user: root
tasks:
- name: stop service
shell: /etc/init.d/mysqld stop
- name: delete files and dir
file: path={{item}} state=absent
with_items:
- /usr/local/mysql
- /usr/local/mariadb-10.2.27-linux-x86_64
- /etc/init.d/mysqld
- /etc/profile.d/mysql.sh
- /etc/my.cnf
- /data/mysql
- name: delete user
user: name=mysql state=absent remove=yes
范例:
---
- hosts:websrvs
remote_user: root
tasks
- name: install some packages
yum: name={{ item }} state=present
with_items:
- nginx
- memcached
- php-fpm
范例:
---
- hosts: websrvs
remote_user: root
tasks:
- name: copy file
copy: src={{ item }} dest=/tmp/{{ item }}
with_items:
- file1
- file2
- file3
- name: yum install httpd
yum: name={{ item }} state=present
with_items:
- apr
- apr-util
- httpd
**迭代嵌套子变量:**在迭代中,还可以嵌套子变量,关联多个变量在一起使用
示例
---
- hosts: websrvs
remote_user: root
tasks:
- name: add some groups
group: name={{ item }} state=present
with_items:
- nginx
- mysql
- apache
- name: add some users
user: name={{ item.name }} group={{ item.group }} state=present
with_items:
- { name: 'nginx', group: 'nginx' }
- { name: 'mysql', group: 'mysql' }
- { name: 'apache', group: 'apache' }
范例:
cat with_item2.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: add some groups
group: name={{ item }} state=present
with_items:
- g1
- g2
- g3
- name: add some users
user: name={{ item.name }} group={{ item.group }} home={{ item.home }}
create_home=yes state=present
with_items:
- { name: 'user1', group: 'g1', home: '/data/user1' }
- { name: 'user2', group: 'g2', home: '/data/user2' }
- { name: 'user3', group: 'g3', home: '/data/user3' }
#删除上述创建的组和用户,不能同时absent,否则报错
[root@ansible ansible]#vim with_item.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: add some groups
group: name={{ item }} state=present
with_items:
- g1
- g2
- g3
- name: add some users
user: name={{ item.name }} group={{ item.group }} home={{ item.home }} create_home=yes state=absent #改为absent
with_items:
- { name: 'user1', group: 'g1', home: '/data/user1' }
- { name: 'user2', group: 'g2', home: '/data/user2' }
- { name: 'user3', group: 'g3', home: '/data/user3' }
#删除组,幂等性后面删除用户不会在执行
[root@ansible ansible]#vim with_item.yml
---
- hosts: websrvs
remote_user: root
tasks:
- name: add some groups
group: name={{ item }} state=absent #改为absent
with_items:
- g1
- g2
- g3
- name: add some users
user: name={{ item.name }} group={{ item.group }} home={{ item.home }} create_home=yes state=absent
with_items:
- { name: 'user1', group: 'g1', home: '/data/user1' }
- { name: 'user2', group: 'g2', home: '/data/user2' }
- { name: 'user3', group: 'g3', home: '/data/user3' }
默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键 字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数 占总数的比例
范例:
#vim test_serial.yml
---
- hosts: all
serial: 2 #每次只同时处理2个主机
gather_facts: False
tasks:
- name: task one
comand: hostname
- name: task two
command: hostname
范例:
- name: test serail
hosts: all
serial: "20%" #每次只同时处理20%的主机
角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结 构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即 可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便 捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进 程等场景中
运维复杂的场景:建议使用 roles,代码复用度高
roles:多个角色的集合, 可以将多个的role,分别放至roles目录下的独立子目录中
roles/
mysql/
nginx/
tomcat/
redis/
roles目录结构如下所示
roles目录结构:
playbook.yml
roles/
project/
tasks/
files/
vars/
templates/
handlers/
default/
meta/
Roles各目录作用
roles/project/ :项目名称,有以下子目录
创建role的步骤
1 创建以roles命名的目录
2 在roles目录中分别创建以各角色名称命名的目录,如webservers等
3 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建
4 在playbook文件中,调用各角色
针对大型项目使用Roles进行编排
范例:roles的目录结构
nginx-role.yml
roles/
└── nginx
├── files
│ └── main.yml
├── tasks
│ ├── groupadd.yml
│ ├── install.yml
│ ├── main.yml
│ ├── restart.yml
│ └── useradd.yml
└── vars
└── main.yml
调用角色方法1:
---
- hosts: websrvs
remote_user: root
roles:
- mysql
- memcached
- nginx
调用角色方法2:
键role用于指定角色名称,后续的k/v用于传递变量给角色
---
- hosts: all
remote_user: root
roles:
- mysql
- { role: nginx, username: nginx }
调用角色方法3:
还可基于条件测试实现角色调用
---
- hosts: all
remote_user: root
roles:
- { role: nginx, username: nginx, when: ansible_distribution_major_version == '7' }
#nginx-role.yml
---
- hosts: websrvs
remote_user: root
roles:
- { role: nginx ,tags: [ 'nginx', 'web' ] ,when:
ansible_distribution_major_version == "6" }
- { role: httpd ,tags: [ 'httpd', 'web' ] }
- { role: mysql ,tags: [ 'mysql', 'db' ] }
- { role: mariadb ,tags: [ 'mariadb', 'db' ] }
ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml
调用的yml文件和roles平级
**/data/ansible/roles **
调用文件:/data/ansible/role_httpd.yml
#创建角色相关的目录
mkdir -pv /data/ansible/roles/httpd/{tasks,handlers,files}
#创建角色相关的文件
cd /data/ansible/roles/httpd/
#main.yml 是task的入口文件
vim tasks/main.yml
- include: group.yml
- include: user.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
vim tasks/group.yml
- name: create apache group
group: name=apache system=yes gid=80
vim tasks/user.yml
- name: create apache user
user: name=apache system=yes shell=/sbin/nologin home=/var/www/ uid=80 group=apache
vim tasks/install.yml
- name: install httpd package
yum: name=httpd
vim tasks/config.yml
- name: config file
copy: src=httpd.conf dest=/etc/httpd/conf/ backup=yes
notify: restart
vim tasks/index.yml
- name: index.html
copy: src=index.html dest=/var/www/html/
vim tasks/service.yml
- name: start service
service: name=httpd state=started enabled=yes
vim handlers/main.yml
- name: restart
service: name=httpd state=restarted
#在files目录下准备两个文件
ls files/
httpd.conf index.html
tree /data/ansible/roles/httpd/
/data/ansible/roles/httpd/
├── files
│ ├── httpd.conf
│ └── index.html
├── handlers
│ └── main.yml
└── tasks
├── config.yml
├── group.yml
├── index.yml
├── install.yml
├── main.yml
├── service.yml
└── user.yml
3 directories, 10 files
#在playbook中调用角色,
vim /data/ansible/role_httpd.yml
---
# httpd role
- hosts: websrvs
remote_user: root
roles:
- httpd
#运行playbook
ansible-playbook /data/ansible/role_httpd.yml
mkdir -pv /data/ansible/roles/nginx/{tasks,handlers,templates,vars}
#创建task文件
cd /data/ansible/roles/nginx/
vim tasks/main.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
vim tasks/install.yml
- name: install
yum: name=nginx
vim tasks/config.yml
- name: config file for centos7
template: src=nginx7.conf.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version=="7"
notify: restart
- name: config file for centos8
template: src=nginx8.conf.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version=="8"
notify: restart
vim tasks/index.yml
- name: index.html
copy: src=roles/httpd/files/index.html dest=/usr/share/nginx/html/
vim tasks/service.yml
- name: start service
service: name=nginx state=started enabled=yes
#创建handler文件
cat handlers/main.yml
- name: restart
service: name=nginx state=restarted
#创建两个template文件
cat templates/nginx7.conf.j2
...省略...
user {{user}};
worker_processes {{ansible_processor_vcpus+3}}; #修改此行
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
...省略...
cat templates/nginx8.conf.j2
...省略...
user nginx;
worker_processes {{ansible_processor_vcpus**3}}; #修改此行
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
...省略...
#创建变量文件
vim vars/main.yml
user: daemon
#目录结构如下
tree /data/ansible/roles/nginx/
/data/ansible/roles/nginx/
├── handlers
│ └── main.yml
├── tasks
│ ├── config.yml
│ ├── file.yml
│ ├── install.yml
│ ├── main.yml
│ └── service.yml
├── templates
│ ├── nginx7.conf.j2
│ └── nginx8.conf.j2
└── vars
└── main.yml
4 directories, 9 files
#在playbook中调用角色
vim /data/ansible/role_nginx.yml
---
#nginx role
- hosts: websrvs
roles:
- role: nginx
#运行playbook
ansible-playbook /data/ansible/role_nginx.yml
mkdir -pv /data/ansible/roles/memcached/{tasks,templates}
cd /data/ansible/roles/memcached
vim tasks/main.yml
- include: install.yml
- include: config.yml
- include: service.yml
vim tasks/install.yml
- name: install
yum: name=memcached
vim tasks/config.yml
- name: config file
template: src=memcached.j2 dest=/etc/sysconfig/memcached
vim tasks/service.yml
- name: service
service: name=memcached state=started enabled=yes
vim templates/memcached.j2
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ansible_memtotal_mb//4}}" #//4 整除4
OPTIONS=""
tree /data/ansible/roles/memcached/
/data/ansible/roles/memcached/
├── tasks
│ ├── config.yml
│ ├── install.yml
│ ├── main.yml
│ └── service.yml
└── templates
└── memcached.j2
2 directories, 5 files
vim /data/ansible/role_memcached.yml
---
- hosts: appsrvs
roles:
- role: memcached
ansible-play /data/ansible/role_memcached.yml
[root@ansible ~]#cat /data/ansible/roles/mysql/files/my.cnf
[mysqld]
socket=/tmp/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
log-bin
pid-file=/data/mysql/mysqld.pid
[client]
port=3306
socket=/tmp/mysql.sock
[mysqld_safe]
log-error=/var/log/mysqld.log
[root@ansible ~]#cat /data/ansible/roles/mysql/files/secure_mysql.sh
#!/bin/bash
/usr/local/mysql/bin/mysql_secure_installation <[root@ansible ~]#chmod +x /data/ansible/roles/mysql/files/secure_mysql.sh
[root@ansible ~]#ls /data/ansible/roles/mysql/files/
my.cnf mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz secure_mysql.sh
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/main.yml
- include: install.yml
- include: group.yml
- include: user.yml
- include: unarchive.yml
- include: link.yml
- include: data.yml
- include: config.yml
- include: service.yml
- include: path.yml
- include: secure.yml
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/install.yml
- name: install packages
yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/group.yml
- name: create mysql group
group: name=mysql gid=306
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/user.yml
- name: create mysql user
user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes
create_home=no home=/data/mysql
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/unarchive.yml
- name: copy tar to remote host and file mode
unarchive: src=mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/
owner=root group=root
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/link.yml
- name: mkdir /usr/local/mysql
file: src=/usr/local/mysql-5.6.46-linux-glibc2.12-x86_64 dest=/usr/local/mysql
state=link
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/data.yml
- name: data dir
shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --
datadir=/data/mysql --user=mysql
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/config.yml
- name: config my.cnf
copy: src=my.cnf dest=/etc/my.cnf
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/service.yml
- name: service script
shell: /bin/cp /usr/local/mysql/support-files/mysql.server
/etc/init.d/mysqld;chkconfig --add mysqld;chkconfig mysqld on;/etc/init.d/mysqld
start
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/path.yml
- name: PATH variable
copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/secure.yml
- name: secure script
script: secure_mysql.sh
[root@ansible ~]#tree /data/ansible/roles/mysql/
/data/ansible/roles/mysql/
├── files
│ ├── my.cnf
│ ├── mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
│ └── secure_mysql.sh
└── tasks
├── config.yml
├── data.yml
├── group.yml
├── install.yml
├── link.yml
├── main.yml
├── path.yml
├── secure.yml
├── service.yml
├── unarchive.yml
└── user.yml
2 directories, 14 files
[root@ansible ~]#cat /data/ansible/mysql_roles.yml
- hosts: dbsrvs
remote_user: root
roles:
- {role: mysql,tags: ["mysql","db"]}
- {role: nginx,tage: ["nginx","web"]}
[root@ansible ~]#ansible-playbook -t mysql /data/ansible/mysql_roles.yml
vim /data/ansible/role_httpd_nginx.yml
---
- hosts: websrvs
roles:
- {role: httpd,tags: [httpd,web], when:
ansible_distribution_major_version=="7" }
- {role: nginx,tags: [nginx,web], when:
ansible_distribution_major_version=="8" }
nsible-playbook -t nginx /data/ansible/role_httpd_nginx.yml
http://galaxy.ansible.com
https://galaxy.ansible.com/explore#/
http://github.com/
http://ansible.com.cn/
https://github.com/ansible/ansible
or.log;
pid /run/nginx.pid;
…省略…
#创建变量文件
vim vars/main.yml
user: daemon
#目录结构如下
#nginx role
hosts: websrvs
roles:
#运行playbook
ansible-playbook /data/ansible/role_nginx.yml
#### 5.5.3 案例3:实现 memcached 角色
```yaml
mkdir -pv /data/ansible/roles/memcached/{tasks,templates}
cd /data/ansible/roles/memcached
vim tasks/main.yml
- include: install.yml
- include: config.yml
- include: service.yml
vim tasks/install.yml
- name: install
yum: name=memcached
vim tasks/config.yml
- name: config file
template: src=memcached.j2 dest=/etc/sysconfig/memcached
vim tasks/service.yml
- name: service
service: name=memcached state=started enabled=yes
vim templates/memcached.j2
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ansible_memtotal_mb//4}}" #//4 整除4
OPTIONS=""
tree /data/ansible/roles/memcached/
/data/ansible/roles/memcached/
├── tasks
│ ├── config.yml
│ ├── install.yml
│ ├── main.yml
│ └── service.yml
└── templates
└── memcached.j2
2 directories, 5 files
vim /data/ansible/role_memcached.yml
---
- hosts: appsrvs
roles:
- role: memcached
ansible-play /data/ansible/role_memcached.yml
[root@ansible ~]#cat /data/ansible/roles/mysql/files/my.cnf
[mysqld]
socket=/tmp/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
log-bin
pid-file=/data/mysql/mysqld.pid
[client]
port=3306
socket=/tmp/mysql.sock
[mysqld_safe]
log-error=/var/log/mysqld.log
[root@ansible ~]#cat /data/ansible/roles/mysql/files/secure_mysql.sh
#!/bin/bash
/usr/local/mysql/bin/mysql_secure_installation <[root@ansible ~]#chmod +x /data/ansible/roles/mysql/files/secure_mysql.sh
[root@ansible ~]#ls /data/ansible/roles/mysql/files/
my.cnf mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz secure_mysql.sh
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/main.yml
- include: install.yml
- include: group.yml
- include: user.yml
- include: unarchive.yml
- include: link.yml
- include: data.yml
- include: config.yml
- include: service.yml
- include: path.yml
- include: secure.yml
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/install.yml
- name: install packages
yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/group.yml
- name: create mysql group
group: name=mysql gid=306
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/user.yml
- name: create mysql user
user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes
create_home=no home=/data/mysql
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/unarchive.yml
- name: copy tar to remote host and file mode
unarchive: src=mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/
owner=root group=root
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/link.yml
- name: mkdir /usr/local/mysql
file: src=/usr/local/mysql-5.6.46-linux-glibc2.12-x86_64 dest=/usr/local/mysql
state=link
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/data.yml
- name: data dir
shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --
datadir=/data/mysql --user=mysql
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/config.yml
- name: config my.cnf
copy: src=my.cnf dest=/etc/my.cnf
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/service.yml
- name: service script
shell: /bin/cp /usr/local/mysql/support-files/mysql.server
/etc/init.d/mysqld;chkconfig --add mysqld;chkconfig mysqld on;/etc/init.d/mysqld
start
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/path.yml
- name: PATH variable
copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/secure.yml
- name: secure script
script: secure_mysql.sh
[root@ansible ~]#tree /data/ansible/roles/mysql/
/data/ansible/roles/mysql/
├── files
│ ├── my.cnf
│ ├── mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
│ └── secure_mysql.sh
└── tasks
├── config.yml
├── data.yml
├── group.yml
├── install.yml
├── link.yml
├── main.yml
├── path.yml
├── secure.yml
├── service.yml
├── unarchive.yml
└── user.yml
2 directories, 14 files
[root@ansible ~]#cat /data/ansible/mysql_roles.yml
- hosts: dbsrvs
remote_user: root
roles:
- {role: mysql,tags: ["mysql","db"]}
- {role: nginx,tage: ["nginx","web"]}
[root@ansible ~]#ansible-playbook -t mysql /data/ansible/mysql_roles.yml
vim /data/ansible/role_httpd_nginx.yml
---
- hosts: websrvs
roles:
- {role: httpd,tags: [httpd,web], when:
ansible_distribution_major_version=="7" }
- {role: nginx,tags: [nginx,web], when:
ansible_distribution_major_version=="8" }
nsible-playbook -t nginx /data/ansible/role_httpd_nginx.yml
http://galaxy.ansible.com
https://galaxy.ansible.com/explore#/
http://github.com/
http://ansible.com.cn/
https://github.com/ansible/ansible
https://github.com/ansible/ansible-examples