运维自动化之ANSIBLE

运维自动化之ANSIBLE

    • 运维自动化之ANSIBLE
      • 本章内容
      • 1 自动化运维应用场景
        • 1.1 云计算运维工程师核心职能
        • 1.2 运维职业发展路线
        • 1.3 企业实际应用场景分析
          • 1.3.1 Dev开发环境
          • 1.3.2 测试环境
          • 1.3.3 预发布环境
          • 1.3.4 发布环境
          • 1.3.5 生产环境
          • 1.3.6 灰度环境
        • 1.4 程序发布
        • 1.5 自动化运维应用场景
        • 1.6 常用自动化运维工具
    • 2 Ansible 介绍和架构
      • 2.1 Ansible发展史
      • 2.2 Ansible 特性
      • 2.3 Ansible 架构
        • 2.3.1 Ansible 组成
        • 2.3.2 Ansible 命令执行来源
        • 2.3.3 注意事项
    • 3 Ansible 安装和入门
      • 3.1 Ansible安装
        • 3.1.1 EPEL源的rpm包安装:
        • 3.1.2 编译安装
        • 3.1.3 Git方式
        • 3.1.4 pip 安装
        • 3.1.5 确认安装
      • 3.2 Ansible 相关文件
        • 3.2.1 配置文件
        • 3.2.2 ansible主配置文件
        • 3.2.3 inventory 主机清单
      • 3.3 Ansible相关工具
        • 3.3.1 ansible-doc
        • 3.3.2 ansible
        • 3.3.3 ansible-playbook
        • 3.3.4 ansible-vault
        • 3.3.5 ansible-console
        • 3.3.6 ansible-galaxy
      • 3.4 Ansible常用模块
        • 3.4.1 Command 模块
        • 3.4.2 Shell模块
        • 3.4.3 Script模块
        • 3.4.4 Copy模块
        • 3.4.5 Fetch模块
        • 3.4.6 File模块
        • 3.4.7 unarchive模块
        • 3.4.8 Archive模块
        • 3.4.9 Hostname模块
        • 3.4.10 Cron模块
        • 3.4.11 Yum模块
        • 3.4.12 Service 模块
        • 3.4.13 User模块
        • 3.4.14 Group模块
        • 3.4.15 Lineinfile模块
        • 3.4.16 Replace模块
        • 3.4.17 Setup模块
    • 4 Playbook
      • 4.1 playbook介绍
      • 4.2 YAML 语言
        • 4.2.1 YAMl 语言介绍
        • 4.2.2 YAML 语言特性
        • 4.2.3 YAML语法简介
          • 4.2.3.1 List列表
          • 4.2.3.2 Dictionary字典
        • 4.2.4 三种常见的数据格式
      • 4.3 Playbook 核心组件
        • 4.3.1 hosts 组件
        • 4.3.2 remote_user 组件
        • 4.3.3 task列表和action组件
        • 4.3.4 其它组件
        • 4.3.5 ShellScripts VS Playbook 案例
      • 4.4 playbook 命令
      • 4.5 Playbook 初步
        • 4.5.1 利用 playbook 创建 mysql 用户
        • 4.5.2 利用 playbook 安装 nginx
        • 4.5.3 利用 playbook 安装和卸载 httpd
        • 4.5.4 利用 playbook 安装 mysql
      • 4.6 Playbook中使用handlers和notify
      • 4.7 Playbook中使用tags组件
      • 4.8 Playbook中使用变量
        • 4.8.1 使用 setup 模块中变量
        • 4.8.2 在playbook 命令行中定义变量
        • 4.8.3 在playbook文件中定义变量
        • 4.8.4 使用变量文件
        • 4.8.5 主机清单文件中定义变量
          • 4.8.5.1 主机变量
          • 4.8.5.2 组(公共)变量
      • 4.9 template 模板
        • 4.9.1 jinja2语言
        • 4.9.2 template
        • 4.9.3 template中使用流程控制 for 和 if
      • 4.10 playbook使用 when
      • 4.11 playbook 使用迭代 with_items
      • 4.12 管理节点过多导致的超时问题解决方法
    • 5 roles角色
      • 5.1 Ansible Roles目录编排
      • 5.2 创建 role
      • 5.3 playbook调用角色
      • 5.4 roles 中 tags 使用
      • 5.5 实战案例
        • 5.5.1 案例1:实现 httpd 角色
        • 5.5.2 案例2:实现 nginx 角色
        • 5.5.3 案例3:实现 memcached 角色
        • 5.5.4 案例4:实现 mysql 5.6 的角色
        • 5.5.5 案例5 :实现多角色的选择
    • 6 ansible 推荐学习资料
    • 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
        • 5.5.4 案例4:实现 mysql 5.6 的角色
        • 5.5.5 案例5 :实现多角色的选择
    • 6 ansible 推荐学习资料

运维自动化之ANSIBLE

本章内容

  • 运维自动化发展历程及技术应用

  • Ansible命令使用

  • Ansible常用模块详解

  • YAML语法简介

  • Ansible playbook基础

  • Playbook变量、tags、handlers使用

  • Playbook模板 templates

  • Playbook条件判断 when

  • Playbook字典 with_items

  • Ansible Roles

1 自动化运维应用场景

1.1 云计算运维工程师核心职能

运维自动化之ANSIBLE_第1张图片

相关工具

  • 代码管理(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

1.2 运维职业发展路线

运维自动化之ANSIBLE_第2张图片
运维的未来是什么?

一切皆自动化

“运维的未来是,让研发人员能够借助工具、自动化和流程,并且让他们能够在运维干预极少的情况下 部署和运营服务,从而实现自助服务。每个角色都应该努力使工作实现自动化。”——《运维的未来》

1.3 企业实际应用场景分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WLl3inug-1592754503994)(G:Tptupian\1.3.PNG)]

1.3.1 Dev开发环境

使用者:程序员

功能:程序员个人的办公电脑或项目的开发测试环境,部署开发软件,测试个人或项目整体的BUG的 环境

管理者:程序员

1.3.2 测试环境

使用者:QA测试工程师

功能:测试经过Dev环境测试通过的软件的功能和性能,判断是否达到项目的预期目标,生成测试报 告

管理者:运维

说明:测试环境往往有多套,测试环境满足测试功能即可,不宜过多

1、测试人员希望测试环境有多套,公司的产品多产品线并发,即多个版本,意味着多个版本同步测试

2、通常测试环境有多少套和产品线数量保持一样

1.3.3 预发布环境

运维自动化之ANSIBLE_第3张图片
使用者:运维

功能:使用和生产环境一样的数据库,缓存服务等配置,测试是否正常

1.3.4 发布环境

包括代码发布机,有些公司为堡垒机(安全屏障)

使用者:运维

功能:发布代码至生产环境

管理者:运维(有经验)

发布机:往往需要有2台(主备)

1.3.5 生产环境

使用者:运维,少数情况开放权限给核心开发人员,极少数公司将权限完全开放给开发人员并其维护

功能:对用户提供公司产品的服务

管理者:只能是运维 生产环境服务器数量:一般比较多,且应用非常重要。往往需要自动工具协助部署配置应用

1.3.6 灰度环境

属于生产环境的一部分

使用者:运维

功能:在全量发布代码前将代码的功能面向少量精准用户发布的环境,可基于主机或用户执行灰度发布 案例:共100台生产服务器,先发布其中的10台服务器,这10台服务器就是灰度服务器

管理者:运维

灰度环境:往往该版本功能变更较大,为保险起见特意先让一部分用户优化体验该功能,待这部分用 户使用没有重大问题的时候,再全量发布至所有服务器

1.4 程序发布

程序发布要求: 不能导致系统故障或造成系统完全不可用 不能影响用户体验

预发布验证: 新版本的代码先发布到服务器(跟线上环境配置完全相同,只是未接入到调度器)

灰度发布:

基于主机,用户,业务

发布路径:

软链接技术:软件的升级和回滚其实就是软链接指向的路径改变

/webapp/tuangou

/webapp/tuangou-1.1

/webapp/tuangou-1.2

发布过程:

  1. 在调度器上下线一批主机(标记为maintenance 状态)
  2. 关闭服务
  3. 部署新版本的应用程序
  4. 启动服务
  5. 在调度器上启用这一批服务器

自动化灰度发布:

  • 脚本
  • 发布平台

1.5 自动化运维应用场景

  • 文件传输
  • 应用部署
  • 配置管理
  • 任务流编排

1.6 常用自动化运维工具

  • 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
    运维自动化之ANSIBLE_第4张图片
    运维自动化之ANSIBLE_第5张图片
    同类自动化工具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

2 Ansible 介绍和架构

公司计划在年底做一次大型市场促销活动,全面冲刺下交易额,为明年的上市做准备。公司要求各业务 组对年底大促做准备,运维部要求所有业务容量进行三倍的扩容,并搭建出多套环境可以共开发和测试 人员做测试,运维老大为了在年底有所表现,要求运维部门同学尽快实现,当你接到这个任务时,有没 有更快的解决方案?

2.1 Ansible发展史

作者: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/

2.2 Ansible 特性

  • 模块化:调用特定的模块完成特定任务,支持自定义模块,可使用任何编程语言写模块
  • Paramiko(python对ssh的实现),PyYAML,Jinja2(模板语言)三个关键模块 基于Python语言实现
  • 部署简单,基于python和SSH(默认已安装),agentless,无需代理不依赖PKI(无需ssl)
  • 安全,基于OpenSSH
  • 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
  • 支持playbook编排任务,YAML格式,编排任务,支持丰富的数据结构
  • 较强大的多层解决方案 role

2.3 Ansible 架构

2.3.1 Ansible 组成

组合INVENTORY、API、MODULES、PLUGINS的绿框,为ansible命令工具,其为核心执行工具

运维自动化之ANSIBLE_第6张图片

2.3.2 Ansible 命令执行来源

  • USER 普通用户,即SYSTEM ADMINISTRATOR
  • PLAYBOOKS:任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执 行,通常是JSON格式的YML文件
  • CMDB(配置管理数据库) API 调用 PUBLIC/PRIVATE CLOUD API调用
  • USER-> Ansible Playbook -> Ansibile

2.3.3 注意事项

  • 执行ansible的主机一般称为主控端,中控,master或堡垒机
  • 主控端Python版本需要2.6或以上
  • 被控端Python版本小于2.4,需要安装python-simplejson
  • 被控端如开启SELinux需要安装libselinux-python
  • windows 不能做为主控端

Ansible无代理,通过ssh协议就可以管理,不是一个独立服务,没有以service结尾的文件,abslble是管理端,需要的时候连接,不需要的时候就不连接。ansible不是一个时时刻刻都需要在运行的软件,是临时性运行的,不需要设置为开机启动。

运维自动化之ANSIBLE_第7张图片

3 Ansible 安装和入门

3.1 Ansible安装

ansible的安装方法有多种

3.1.1 EPEL源的rpm包安装:

[root@ansible ~]#yum install ansible

3.1.2 编译安装

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

3.1.3 Git方式

git clone git://github.com/ansible/ansible.git --recursive
cd ./ansible
source ./hacking/env-setup

3.1.4 pip 安装

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

3.1.5 确认安装

[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)]

3.2 Ansible 相关文件

3.2.1 配置文件

  • /etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性
  • /etc/ansible/hosts 主机清单
  • /etc/ansible/roles/ 存放角色的目录

3.2.2 ansible主配置文件

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

3.2.3 inventory 主机清单

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

3.3 Ansible相关工具

  • /usr/bin/ansible 主程序,临时命令执行工具
  • /usr/bin/ansible-doc 查看配置文档,模块功能查看工具,相当于man
  • /usr/bin/ansible-playbook 定制自动化任务,编排剧本工具,相当于脚本
  • /usr/bin/ansible-pull 远程执行命令的工具
  • /usr/bin/ansible-vault 文件加密工具
  • /usr/bin/ansible-console 基于Console界面与用户交互的执行工具
  • /usr/bin/ansible-galaxy 下载/上传优秀代码或Roles模块的官网平台

利用ansible实现管理的主要方式:

  • Ad-Hoc 即利用ansible命令,主要用于临时命令使用场景
  • Ansible-playbook 主要用于长期规划好的,大型项目的场景,需要有前期的规划过程

3.3.1 ansible-doc

此工具用来显示模块帮助

格式

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.

3.3.2 ansible

此工具通过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命令执行过程

  1. 加载自己的配置文件 默认/etc/ansible/ansible.cfg
  2. 加载自己对应的模块文件,如:command
  3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户 $HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
  4. 给文件+x执行
  5. 执行并返回结果
  6. 删除临时py文件,退出

范例:

[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

3.3.3 ansible-playbook

此工具用于执行编写好的 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   


3.3.4 ansible-vault

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


3.3.5 ansible-console

此工具可交互执行命令,支持tab,ansible 2.0+新增

提示符格式:

执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$

常用子命令:

  • 设置并发数: forks n 例如: forks 10
  • 切换组: cd 主机组 例如: cd web
  • 列出当前组主机列表: list
  • 列出所有的内置命令: ?或help

范例

[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

3.3.6 ansible-galaxy

此工具会连接 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

在这里插入图片描述
运维自动化之ANSIBLE_第8张图片

3.4 Ansible常用模块

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

3.4.1 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

3.4.2 Shell模块

功能:和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

3.4.3 Script模块

功能:在远程主机上运行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

3.4.4 Copy模块

功能:从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"

3.4.5 Fetch模块

功能:从远程主机提取文件至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

3.4.6 File模块

功能:设置文件属性

模块说明

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

3.4.7 unarchive模块

功能:解包解压缩

实现有两种用法:

1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes

2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no

常见参数:

  • copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为 copy=no,会在远程主机上寻找src源文件
  • remote_src:和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在 ansible主机上
  • src:源路径,可以是ansible主机上的路径,也可以是远程主机(被管理端或者第三方主机)上的路径,如果是远程主机上的路 径,则需要设置copy=no
  • dest:远程主机上的目标路径
  • mode:设置解压缩后的文件权限

只要包不在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

3.4.8 Archive模块

功能:打包压缩 保存在被管理节点,配合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

3.4.9 Hostname模块

功能:管理主机名 针对一台主机来设置,否则都设置为同样的主机名

范例:

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

3.4.10 Cron模块

功能:计划任务 支持时间: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

3.4.11 Yum模块

功能:管理软件包,只支持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)

3.4.12 Service 模块

功能:管理服务

范例:

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

3.4.13 User模块

功能:管理用户

范例:

#创建用户
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'

3.4.14 Group模块

功能:管理组

范例:

#创建组
ansible websrvs -m group  -a 'name=nginx gid=88 system=yes'
#删除组
ansible websrvs -m group  -a 'name=nginx state=absent'

3.4.15 Lineinfile模块

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="^#"'

3.4.16 Replace模块

该模块有点类似于sed命令,主要也是基于正则进行匹配和替换,建议使用

范例:

ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"  
ansible all -m replace -a "path=/etc/fstab regexp='^#(.*)' replace='\1'"

3.4.17 Setup模块

功能: 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
}

4 Playbook

4.1 playbook介绍

运维自动化之ANSIBLE_第9张图片

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

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

4.2 YAML 语言

4.2.1 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

4.2.2 YAML 语言特性

  • YAML的可读性好
  • YAML和脚本语言的交互性好
  • YAML使用实现语言的数据类型
  • YAML有一个一致的信息模型
  • YAML易于实现
  • YAML可以基于流来处理
  • YAML表达能力强,扩展性好

4.2.3 YAML语法简介

  • 在单一文件第一行,用连续三个连字号“-” 开始,还有选择性的连续三个点号( … )用来表示文件的 结尾
  • 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
  • 使用#号注释代码 缩进必须是统一的,不能空格和tab混用
  • 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
  • YAML文件内容是区别大小写的,key/value的值均需大小写敏感
  • 多个key/value可同行写也可换行写,同行使用,分隔
  • v可是个字符串,也可是另一个列表
  • YAML文件扩展名通常为yml或yaml

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

4.2.3.1 List列表

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

范例:

#不同行,行以-开头,后面有一个空格
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango

#同一行
[Apple,Orange,Strawberry,Mango]
4.2.3.2 Dictionary字典

字典由多个key与value构成,key和value之间用 :分隔(:后面有一个空格),所有k/v可以放在一行,或者每个 k/v 分别放在不同行

冒号后有空格

范例 :

#不同行
# An employee record
name: Example Developer
job: Developer
skill: Elite

#同一行,也可以将key:value放置于{}中进行表示,用,分隔多个key:value
# An employee record
{name: “Example Developer”, job: “Developer”, skill: “Elite”}

范例: 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 }

4.2.4 三种常见的数据格式

  • XML:Extensible Markup Language,可扩展标记语言,可用于数据交换和配置
  • JSON:JavaScript Object Notation, JavaScript 对象表记法,主要用来数据交换或配置,不支持注释

JSON格式为了节约空间,通常写在一行,文件比较小,在网络中传输减少网路带宽

  • YAML:YAML Ain’t Markup Language YAML 不是一种标记语言, 主要用来配置,大小写敏感, 不支持tab

运维自动化之ANSIBLE_第10张图片
可以用工具互相转换,参考网站:

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

4.3 Playbook 核心组件

一个playbook 中由列表组成,其中所用到的常见组件类型如下:

  • Hosts 执行的远程主机列表
  • Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典
  • Variables 内置变量或自定义变量在playbook中调用
  • Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
  • Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此 会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地 长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
  • 一个完整的代码块功能需最少元素需包括 name 和 task,一个name只能包括一个task

4.3.1 hosts 组件

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

4.3.2 remote_user 组件

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

4.3.3 task列表和action组件

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

4.3.4 其它组件

某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers

任务可以通过"tags"打标签,可在ansible-playbook命令上使用-t指定进行调用

4.3.5 ShellScripts VS Playbook 案例

#SHELL脚本实现
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp/tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl enable --now httpd
#Playbook实现
---
- hosts: 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

4.4 playbook 命令

格式

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

4.5 Playbook 初步

4.5.1 利用 playbook 创建 mysql 用户

范例: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

4.5.2 利用 playbook 安装 nginx

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

4.5.3 利用 playbook 安装和卸载 httpd

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

4.5.4 利用 playbook 安装 mysql

范例:安装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

4.6 Playbook中使用handlers和notify

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

4.7 Playbook中使用tags组件

在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)]

4.8 Playbook中使用变量

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

变量定义:

variable=value

范例:

http_port=80

变量调用方式:

通过{{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效

变量来源:

  1. ansible 的 setup facts 远程主机的所有变量都可直接调用
  2. 通过命令行指定变量,优先级最高
ansible-playbook -e varname=value test.yml
  1. 在playbook文件中定义
vars:
  - var1: value1
  - var2: value2
  1. 在独立的变量YAML文件中定义
- hosts: all
  vars_files:
    - vars.yml
  1. 在 /etc/ansible/hosts 中定义

    主机(普通)变量:主机组中主机单独定义,优先级高于公共变量

    组(公共)变量:针对主机组中所有主机定义统一变量

  2. 在role中定义

4.8.1 使用 setup 模块中变量

本模块自动在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

4.8.2 在playbook 命令行中定义变量

命令行 -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.

4.8.3 在playbook文件中定义变量

范例:

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

4.8.4 使用变量文件

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

4.8.5 主机清单文件中定义变量

4.8.5.1 主机变量

在inventory 主机清单文件中为指定的主机定义变量以便于在playbook中使用

范例:

[websrvs]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909
4.8.5.2 组(公共)变量

在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"
}

4.9 template 模板

模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja语法

4.9.1 jinja2语言

运维自动化之ANSIBLE_第11张图片
官方网站:

http://jinja.pocoo.org/

https://jinja.palletsprojects.com/en/2.11.x/

jinja2 语言使用字面量,有下面形式:

  • 字符串:使用单引号或双引号
  • 数字:整数,浮点数
  • 列表:[item1, item2, …]
  • 元组:(item1, item2, …)
  • 字典:{key1:value1, key2:value2, …}
  • 布尔型:true/false
  • 算术运算:+, -, *, /, //, %, **
  • 比较操作:==, !=, >, >=, <, <=
  • 逻辑运算:and,or,not
  • 流表达式:For,If,When

字面量

表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如"Hello World"

双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过 滤器或只是包含或继承一个模板的参数),如42,42.23

数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在 Python 里, 42 和 42.0 是不 一样的

算术运算:

Jinja 允许用计算值。支持下面的运算符

  • +:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接 它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2
  • -:用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1
  • /:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 0.5
  • //:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2
  • %:计算整数除法的余数。 {{ 11 % 7 }} 等于 4
  • *:用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ ‘=’ * 80 }} 会打印 80 个等号的横条
  • ** 取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8

比较操作符

== 比较两个对象是否相等

!= 比较两个对象是否不等 > 如果左边大于右边,返回 true

>= 如果左边大于等于右边,返回 true

<=如果左边小于右边,返回 true <= 如果左边小于等于右边,返回 true

逻辑运算符

对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式

and 如果左操作数和右操作数同为真,返回 true

or 如果左操作数和右操作数有一个为真,返回

true not 对一个表达式取反 (expr)表达式组

true / false true 永远是 true ,而 false 始终是 false

4.9.2 template

template功能:可以根据和参考模块文件,动态生成相类似的配置文件

template文件必须存放于templates目录下,且命名为 .j2 结尾

yaml/yml 文件需和templates目录平级,目录结构如下示例:

./

​ ├── temnginx.yml

​ └── templates

​ └── nginx.conf.j2

范例:利用template 同步nginx配置文件

#准备templates/nginx.conf.j2文件
vim temnginx.yml
---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
 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

4.9.3 template中使用流程控制 for 和 if

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

4.10 playbook使用 when

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

4.11 playbook 使用迭代 with_items

迭代:当有需要重复性执行的任务时,可以使用迭代机制

对迭代项的引用,固定变量名为"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' }

4.12 管理节点过多导致的超时问题解决方法

默认情况下,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%的主机

5 roles角色

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

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

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

roles/
   mysql/
   nginx/
   tomcat/
   redis/

5.1 Ansible Roles目录编排

roles目录结构如下所示

运维自动化之ANSIBLE_第12张图片
每个角色,以特定的层级目录结构进行组织

roles目录结构:

playbook.yml
roles/
  project/
    tasks/
    files/
    vars/      
    templates/
    handlers/
    default/    
    meta/    

Roles各目录作用

roles/project/ :项目名称,有以下子目录

  • files/ :存放由copy或script模块等调用的文件
  • templates/:template模块查找所需要模板文件的目录 tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在 此文件中通过include进行包含
  • handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
  • vars/:定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过 include进行包含
  • meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文 件需在此文件中通过include进行包含
  • default/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低

5.2 创建 role

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

5.3 playbook调用角色

调用角色方法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' }

5.4 roles 中 tags 使用

#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

5.5 实战案例

5.5.1 案例1:实现 httpd 角色

调用的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

5.5.2 案例2:实现 nginx 角色

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

5.5.3 案例3:实现 memcached 角色

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 

5.5.4 案例4:实现 mysql 5.6 的角色

[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

5.5.5 案例5 :实现多角色的选择

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 

6 ansible 推荐学习资料

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

#目录结构如下

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


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

5.5.4 案例4:实现 mysql 5.6 的角色

[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

5.5.5 案例5 :实现多角色的选择

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 

6 ansible 推荐学习资料

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

你可能感兴趣的:(Linux运维学习)