概述
正如Ansible官网的标题“Ansible is Simple IT Automation”含义,Ansible简化了IT自动化的实现,是高效运维的一个重要工具。
Ansible的设计初衷就是在若干服务器上从零开始执行所有必需的配置与操作。例如,在启动Web 服务器之前先启动数据库,或者为了实现零停机升级,将Web 服务器逐一从负载均衡上摘除并升级。Ansible通过极简的模型来控制各种操作按照所需顺序执行。其它同类工具有:Chef、Puppet 及Saltstack。
Ansible的主要特点
- 基于Python语言实现,由Paramiko(Python的一个可并发连接ssh主机功能库),PyYAML和Jinja2(模板化)三个关键模块实现
- 模块化设计,ansible自身是一个核心组件,调用特定的模块来完成特定任务
- 基于SSH协议工作,免客户端,有两种认证方式:密码、公钥
- 使用yaml语言编排剧本,连续任务按先后设置顺序完成
- 是一个声明式的管理工具,在编写脚本时使用的是声明式语言
1 | 声明式语言表示“期望目标是什么状态”,如果已经是则返回"ok",否则改变目标状态并返回"changed"。 |
- 具有幂等性的特点,执行一次或多次,安装出来的环境是一样的
1 | HTTP/1.1中对“幂等性”的定义是:一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。 |
Ansible架构图
组件 | 功能 |
---|---|
ansible core | ansible自身核心模块 |
host inventory | 主机清单,定义可管控的主机列表 |
connection plugins | 连接插件,一般默认基于ssh协议连接 |
modules | core modules(自带的核心模块)、custom modules(自定义模块) |
playbooks | 剧本,按照所设定编排的顺序执行命令 |
适用场景
在自动化运维方面,关于Ansible适用场景,,可以从与同类工具Saltstack对比的角度来理解。
共同点:
Ansible和SaltStack都是的目前最流行的自动化运维工具,能满足企业IT系统的自动化运维管理。这两个工具都是用python开发的,可以部署到不同的系统环境中和具有良好的二次开发特性。
在执行的命令的时候,Ansible和SaltStack都支持Ad-hoc操作模式,也可以支持将命令写入yaml格式文件中再批量执行。
在处理返回结果方面,Ansible和SaltStack的返回结果格式都是JSON格式,比较易懂和方便解析。
差异:
响应速度:SaltStack更快,在文件传输方面快一个量级,但在批量脚本执行、多机器部署方面相近
SaltStack的master和minion主机是通过ZeroMQ传输数据,而Ansible是通过标准SSH进行数据传输,SaltStack的响应速度要比Ansible快很多。标准SSH连接的时候比较耗费时间,ZeroMQ传输的速度会快很多,所以单单从响应速度方面考虑SaltStack会是更好的选择。但是在一般的运维场景下Ansible的响应速度也可以满足需求。
有测试数据表明,在执行命令、分发文件、读取文件方面,SaltStack的响应速度是Ansible的10倍左右。但在批量脚本执行、多机器部署方面,二者速度相当。安全性:Ansible更安全
Ansible使用标准SSH连接传输数据,不需要在远程主机上启动守护进程,并且标准SSH数据传输本身就是加密传输,这样远程主机不容易被攻击。
自身运维:Ansible更友好
Ansible和远端主机之间的通过标准SSH通信,远程主机上只需要运行SSH进程就可以进行运维操作,而SSH是机房主机中一般都安装和启动的进程,所以Ansible对机房运维不会增加过多的运维成本。
综合以上,可以认为1000台以内的服务器自动化运维,使用Ansible做配置管理、应用部署、批量脚本执行等工作无需顾虑太多。
基本知识
常用模块
Ansible的常用模块主要有以下十来个:
模块名称 | 功能 |
---|---|
ping | 尝试连接主机,如果测试成功会返回”pong” |
command | 在远程节点执行命令 |
yum | 使用yum软件包管理工具管理软件包 |
shell | 和command模块类似,执行命令,支持变量等符号 |
cron | 管理定时任务 |
service | 管理程序服务 |
file | 设置文件属性 |
copy | 复制本地文件到远程主机 |
script | 传送本地的一个脚本并在远程主机上执行 |
setup | 获取远程主机的参数信息 |
user | 管理用户账户 |
group | 添加或者删除用户组 |
… | … |
配置文件
Ansible配置是以ini格式存储数据的,在Ansible中,几乎所有配置都可以通过Playbook或环境变量来重新赋值。加载配置文件的优先顺序如下:
ANSIBLE_CONFIG:优先查找环境变量ANSIBLE_CONFIG指向的配置文件
./ansible.cfg:当前目录下的ansible.cfg配置文件
~/.ansible.cfg:当前用户home目录下的.ansible.cfg配置文件
/etc/ansible/ansible.cfg:安装ansible生成的默认配置文件
Ansible按顺序查找并应用最先找到的ansible配置。ansible.cfg中的配置可被playbook中的自定义配置覆盖
常用的配置参数:
配置项 | 含义 |
---|---|
inventory | 资源清单文件,就是一些Ansible需要连接管理的主机列表 |
library | Ansible模块的安装目录 |
forks | 默认并发进程数5,可根据控制主机的性能和被管理节点的数量调整 |
sudo_user | 执行命令的用户,可在playbook中重新设置 |
remote_port | SSH连接端口一般是22,如有个别特殊的,可在inventory中单独指定 |
host_key_checking | 是否检查公钥,一般设置为false |
timeout | SSH连接的超时间隔,默认20s |
log_path | ansible日志路径 |
… | … |
执行过程
- 加载自己的配置文件,默认
/etc/ansible/ansible.cfg
- 查找对应的主机配置文件,找到要执行的主机或者组
- 加载自己对应的模块文件,如 command
- 通过ansible将模块或命令生成对应的临时py文件(python脚本), 并将该文件传输至远程服务器
- 对应执行用户的家目录的
.ansible/tmp/XXX/XXX.PY
文件 - 给文件 +x 执行权限
- 执行并返回结果
- 删除临时py文件,
sleep 0
退出
剧本(Playbook)
playbook的构成:
- Target section:定义将要执行 playbook 的远程主机组
- Variable section:定义 playbook 运行时需要使用的变量
- Task section:定义将要在远程主机上执行的任务列表
- Handler section:定义 task 执行完成以后需要调用的任务
一般所需的目录层:
- vars:变量层
- tasks:任务层
- handlers:触发条件
- files:文件
- template:模板
安装方法
以root用户安装ansible为例,方式如下:
1. 从Github获取源码安装
需预先安装好Python2.5以上版本。另外,对于Ansible,Windows系统不可以做控制主机。如果控制主机没有预装Python,从Python官网选择2.7.15版本的源码包,解压到控制主机执行安装即可。
安装过Python环境之后,更新以下模块:
1 | # 安装python的包管理工具pip |
下载、安装ansible
1 | git clone git://github.com/ansible/ansible.git --recursive |
2. Yum安装
Fedora 用户可直接安装Ansible,但RHEL或CentOS用户,需要 配置 EPEL。
更新EPEL源
1 | # rpm方式安装EPEL源 |
然后更新一下缓存
1 | [root@VM_0_6_centos ~]# yum clean all |
安装ansible
1 | [root@VM_0_6_centos ~]# yum install ansible -y |
3. 其它系统安装Ansible
其它操作系统,详见Ansible安装方法。
操作示例
我们主要使用ansible和ansible-playbook这两个命令。批量执行简单命令时,使用ansible;执行更复杂的批量安装部署时用ansible-playbook。以下是我在云主机上使用ansible的三个示例:
个人云主机主机环境如下:
1 | [root@VM_0_7_centos ~]# cat /etc/redhat-release |
使用ansible
1. 执行简单命令
安装好ansible之后,在当前目录编写一个hosts文件,定义一个主机群组vm,配置好待部署机器的主机别名、IP地址等信息,格式可以如下:
1 | cat myhosts |
然后,通过指定-i
参数指定自定义hosts文件执行一个简单的命令,如查询系统(redhat系列)版本:cat /etc/redhat-release
1) 仅查询vm01
1 | [root@VM_0_7_centos ~]# ansible -i myhosts vm01 -m shell -a "cat /etc/redhat-release" |
2) 查询主机群组vm中的所有主机
1 | [root@VM_0_7_centos ~]# ansible -i myhosts vm -m shell -a "cat /etc/redhat-release" |
3) 查询hosts文件中的所有主机
1 | [root@VM_0_7_centos ~]# ansible -i myhosts all -m shell -a "cat /etc/redhat-release" |
!注意:command
模块不支持管道
例如,企图通过"df -h |sed -n 2p"
获取第一个列出的文件系统的数据时,报错如下:
1 | [root@VM_0_7_centos ~]# ansible -i myhosts vm01 -m command -a "df -h |sed -n 2p" |
此时,可以使用shell
模块替代,如下:
1 | [root@VM_0_7_centos ~]# ansible -i myhosts vm01 -m shell -a "df -h | sed -n 2p" |
2. 执行控制主机上的脚本
如果需要执行多条shell命令,而又不想编写playbook,可以将包含这些命令的shell脚本放在控制主机上,通过script模块执行。
1 | cat <<EOF > /root/test.sh |
使用ansible-playbook
3. 使用ansible-playbook部署一个tomcat集群
此例演示如何将一个Web应用部署到由 一个NginX节点 + 两个tomcat节点
集群,然后模拟升级、回退过程:
1+2集群设定:
主机 | 应用 | 监听端口 | 版本 |
---|---|---|---|
vm_nginx | NginX | 80 | 1.12 |
vm_tomcat_1 | tomcat | 8080 | 8.5.38 |
vm_tomcat_2 | tomcat | 8080 | 8.5.38 |
为了模拟升级、回退操作,准备两个Web应用:
Web应用 | 版本 | 说明 |
---|---|---|
examples.war | 1.0 | 旧版本,回退用 |
examples.war | 2.0 | 新版本,升级用 |
接下来,编写playbook。
在不是特别清楚每个步骤该如何编写的情况下,先一条一条以文字形式罗列出来:
- 更新所有节点的yum源
- 在NginX节点通过yum安装NginX 1.12
- 在tomcat节点通过yum安装Java 8
- 解压tomcat安装包到tomcat节点的安装目录
- 配置tomcat(添加环境变量、开机自启、开放8080端口等)
- 将examples.war v1.0发布到tomcat并启动tomcat(因初始已有examples,改为替换首页)
- 配置NginX并启动
- 停止vm_tomcat_1上的tomcat,将examples.war v2.0发布到tomcat并启动
- 等待vm_tomcat_1的tomcat启动正常
- 停止vm_tomcat_2上的tomcat,将examples.war v2.0发布到tomcat并启动
- 等待vm_tomcat_2的tomcat启动正常
- 重复步骤8~11,但改用examples.war v1.0,模拟回退过程
据此,可作以下规划。
角色设定:
role | 说明 | 包含步骤 |
---|---|---|
tomcat | 安装Java 8,tomcat 8,并替换examples首页 | 1,3 ~ 6 |
nginx | 安装NginX 1.12 | 1,2,7 |
upgrade | 升级到examples.war v2.0 | 8 ~ 11 |
rollback | 回退到examples.war v1.0 | 12 |
主机组划分:
group | hosts | roles |
---|---|---|
lb | vm_nginx | nginx |
web | vm_tomcat_1 vm_tomcat_2 |
tomcat upgrade rollback |
入口playbook划分:
name | roles |
---|---|
start.yml | tomcat nginx |
upgrade.yml | upgrade |
rollback.yml | rollback |
完整的playbook目录结构如下:
1 | [root@VM_0_7_centos test]# tree ansible_tomcat_cluster/ |
- inventory(即hosts文件):
1 | [root@VM_0_7_centos test]# cat ansible_tomcat/hosts |
- role nginx的任务编排:
1 |
|
- role tomcat的任务编排:
1 | [root@VM_0_7_centos test]# cat ansible_tomcat/roles/install/tasks/main.yaml |
执行nginx和tomcat的安装部署:
1 | [root@VM_0_7_centos test]# ansible-playbook roles/start.yml |
结果如下图:
检验环境变量是否已写入/etc/profile
:
检验tomcat开机自启动是否已写入/etc/rc.local
:
检验index.html模板是否注入成功:
预置的index.html模板:
注入变量后,h3标签值变成了”this is vm01”(另一个节点是”this is vm02”):
检验NginX负载均衡是否生效:
执行逐个节点升级:
upgrade.yml:
1 | - hosts: web |
upgrade/tasks/main.yml:
1 | - name: 升级 |关闭tomcat |
handlers/main.yml:
1 | - name: clean tomcat cache |
模拟应用升级的过程过程如下:
1 | [root@VM_0_7_centos ansible_tomcat_cluster]# ansible-playbook roles/upgrade.yml |
先对vm_tomat_1:
再对vm_tomcat_2:
升级后,从浏览器访问变成了2.0版本(两个节点的页面一致,未作区分):
执行逐个节点回退:
rollback剧本内容与upgrade相似,从略。
1 | [root@VM_0_7_centos ansible_tomcat_cluster]# ansible-playbook roles/rollback.yml |
回退过程类似升级过程,结果如下:
回退后,从浏览器访问变成了1.0版本:
一切符合预期。
至此,NginX 1 + Tomcat 2方式部署war包,然后模拟升级、回退的过程演示完毕。完整的playbook见gitlab仓库
P.s. 以上操作不是使用密码,需事先作SSH免密认证。
1 | # 控制主机生成ssh密钥对,简单点,直接ssh-keygen不带任何参数 |
其它模块的用法,及高级特性,请结合实际需求,阅读官方文档《Ansible User Guide》。
Ansible参考
(End)