摘 要
Ansible是新出现的自动化运维工具,基于Python开发,主要使用Paramiko、PyYaml和JinJa2三个关键模块,部署简单。Ansible集合了众多运维工具的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
本文将按照个人学习Ansible的过程,由浅入深逐渐向读者介绍ansible的概念,playbook常用模块以及编写脚本时的文档结构,从而为后续各部门SaaS化软件需提供的自动安装部署脚本打下工作基础。
关键词:ansible playbook 自动运维
1 引言
在互联网迅猛发展的同时,运维这个工种也从默默无闻的后台走向公众视野,被更多的人所知晓。一个公司拥有几十台上百台机器早已不是稀奇事,巨型公司数以万计的机器都不在话下,在沿用老一套办法一台台的人工修改配置已然不现实,这该怎么办呢?相信此时你已然明白运维自动化具体是什么了。简单来讲,运维自动化就是将日常重复性的工作通过规则设定使其遵循预先既定规则,在指定的范围时间内自动化运行,但整个过程无需人工参与。而Ansible正是帮助运维人员实现自动化的工具之一。
1)Ansible主要架构如下图所示:
- INVENTORY: Ansible管理主机的清单,默认位置/etc/anaible/hosts。
- PLAYBOOKS:任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执行,通常是YML格式文件。
- ANSIBLE:组合INVENTORY、 API、 MODULES、PLUGINS的绿框,可以理解为ansible命令工具,这一部分是核心执行工具。
- MODULES: Ansible执行命令的功能模块,多数为内置的核心模块,也可自定义,ansible-doc –l 可查看模块。
- PLUGINS:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用。
- HOST:运维操作的目标主机。
2)Ansible执行流程如下图所示
3)注意事项
- 主控端Python版本需要2.6或以上。
- 被控端Python版本小于2.4需要安装python-simplejson。
- 被控端如开启SELinux需要安装libselinux-python。
- windows不能做为主控端。
4)Ansible特性
- 模块化:调用特定的模块,完成特定任务,可使用任何编程语言写模块。
- 部署简单安全,基于python和OpenSSH,无需在受控主机上安装客户端。
- 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况。
2 Ansible入门
下文所有操作运行环境如下,其他环境可能会略有出入。
主机 | CentOS Linux release 7.4.1708 (Core) |
Python | 2.7.5 |
Ansible | 2.5.3 |
2.1 yum安装
//安装eple源
1)yum install epel-release
//安装Ansible
2)yum install ansible
2.2 Ansible中常用基本概念
在使用Ansible的过程首先需要了解四个基本,其中前两个属于基础文件的定义,后两个是基本命令的定义:
1)ansible.cfg
Ansible的配置文件,与其他软件一样,通过该文件对Ansible运行过程中涉及的一些参数进行设置,常用设置主要包括ssh的配置以及plugin的定义。使用时Ansible通常会在当前目录下查找是否存在ansible.cfg文件,如果不存在则会到用户根目录下查找默认的. ansible.cfg文件。可以运行ansible --version命令查看当前使用的配置文件路径。
2)hosts
Ansible的主机清单(INVENTORY)文件,主要以分组的形式罗列受控主机连接信息。内容如下图所示:
以[ ]形式描述分组名称,下面是隶属于该组的主机列表,可以是具体的IP地址,也可以是相应访问域名。同时也可以把一个组作为另一个组的子成员以children作为标识。运行时可以通过-i参数来指定hosts文件所在位置,如果没有指定将使用默认文件/etc/anaible/hosts。
3)ad-hoc 命令
Ansible提供两种方式去完成任务,一种是 ad-hoc 命令,敲入一些命令去比较快的完成一些事情,而不需要将这些执行的命令特别保存下来,例如停电维护时需要预先关闭所有受控主机。ad-hoc使用ansible命令执行。
4)playbook命令
Ansible提供的另一种完成任务的方式就是playbook命令。playbooks 是一种简单的配置管理系统与多机器部署系统的基础。与现有的其他系统有不同之处,且非常适合于复杂应用的部署。Playbook使用ansible-playbook命令执行。
3 Ad-hoc介绍
我们首先通过简单的ad-hoc示例来熟悉下ansible的基本操作。在这过程中也会涉及到ansible使用ssh进行通信的一些特性。
3.1 Ad-hoc中的Hello World
运维管理中最常用的就是ping命令,用来测试与目标主机的通道是否正常,在ad-hoc中可以使用如下命令实现这一操作。命令中通过-i参数指定主机清单位置,可根据实际情况更换自己的路径信息,被控主机组名一定要存在于主机清单内。-k参数在执行过程中要求用户填写密码,效果如下图所示。
3.2 ad-hoc命令语法
从上面的“Hello World”示例中,我们对ad-hoc的执行有了一个初步的认识,命令的详细语法如下所示:
ansible <host-pattern> [-m module_name] [options]
--version 显示版本
-a 模块参数(如果有)
-m module 指定模块,默认为command
-v 详细过程 –vv -vvv更详细
--list-hosts 显示主机列表,可简写--list
-k --ask-pass 提示连接密码,默认Key验证
-K --ask-become-pass 提示使用sudo密码
-C --check 检查,并不执行
-T --timeout=TIMEOUT 执行命令的超时时间,默认10s
-u --user=REMOTE_USER 执行远程执行的用户
-U SUDO_USER, --sudo-user 指定sudu用户
-b --become 代替旧版的sudo 切换
-i 指定主机清单文件位置
3.3 Ansible常用模块
ad-hoc命令中的-m用来指定运行的模块,其中最重要的模块就是command/shell模块,用来在被控主机端执行命令脚本,而command和shell模块主要区别就是command模块中的命令不能带有特殊字符,shell模块可以。
ad-hoc还将一些shell命令整合为具体模块,用户可以通过调用模块的方式更加快捷的实现操作目标。这些模块主要有:
- command/shell模块,
- ping模块,测试主机是否是通的。
- file模块,主要用于远程主机上的文件操作。
- copy模块,复制文件到远程主机。
- service模块,用于管理服务 。
- yum模块,使用yum包管理器来管理软件包。
- user模块与group模块,用来管理用户和用户组。
- setup模块,获取主机信息。
- cron模块,用于管理计划任务。
例如下面的命令实现在tomcat分组的被控主机内建立/data/test文件夹,并设置用户组是vh,所有者是vh,操作权限是755。
ansible tomcat -m file -a "dest=/data/test mode=755 owner=vh group=vh state=directory" –i source/tomcat/9.0/hosts
4 Playbook介绍
在 playbook中可以编排有序的执行过程,甚至于做到在多组机器间,来回有序的执行特别指定的步骤,并且可以同步或异步的发起任务。简单来说,可以把playbook看做是软件当中的宏,按照预定的内容完成一系列操作。
4.1 Playbook目录结构
playbook的典型目录结构如下图所示,其中各自文件主要作用是:
- ansible.cfg:ansible配置文件,如果用户的操作有些个性配置可以在文件中声明,这样会取代系统默认的ansible配置。需要注意的是必须将工作路径切换到ansible.cfg文件所在目录才会生效。ansible.cfg文件命名不可变。
- hosts:主机清单,罗列本次操作所涉及的被控主机,通过-i参数引入。hosts文件命名不可变。
- roles:角色目录,playbook的工作任务以角色进行划分,每个角色会按照任务列表执行相关操作。roles文件命名不可变。
- tomcat.yml:playbook的入口文件,根据扩展名可以看出该文件以yml格式编写,在文件内规定了操作的指引信息。文件名称可自定义。
4.2 Playbook命令语法
playbook命令的详细语法如下:
ansible-playbook [options] playbook.yml [playbook2 ...]
-u REMOTE_USER, --user=REMOTE_USER # ssh 连接的用户名
-k, --ask-pass #ssh登录认证密码
-s, --sudo #sudo 到root用户,相当于Linux系统下的sudo命令
-U SUDO_USER, --sudo-user=SUDO_USER #sudo 到对应的用户
-K, --ask-sudo-pass #用户的密码(—sudo时使用)
-T TIMEOUT, --timeout=TIMEOUT # ssh 连接超时,默认 10 秒
-C, --check # 指定该参数后,执行 playbook 文件不会真正去执行,而是模拟执行一遍,然后输出本次执行会对远程主机造成的修改
-e EXTRA_VARS, --extra-vars=EXTRA_VARS # 设置额外的变量如:key=value 形式 或者 YAML or JSON,以空格分隔变量,或用多个-e -f FORKS, --forks=FORKS # 进程并发处理,默认 5
-i INVENTORY, --inventory-file=INVENTORY # 指定 hosts 文件路径,默认 default=/etc/ansible/hosts
-l SUBSET, --limit=SUBSET # 指定一个 pattern,对- hosts:匹配到的主机再过滤一次 --list-hosts # 只打印有哪些主机会执行这个 playbook 文件,不是实际执行该 playbook --list-tasks # 列出该 playbook 中会被执行的 task --private-key=PRIVATE_KEY_FILE # 私钥路径 --step # 同一时间只执行一个 task,每个 task 执行前都会提示确认一遍 --syntax-check # 只检测 playbook 文件语法是否有问题,不会执行该 playbook
-t TAGS, --tags=TAGS #当 play 和 task 的 tag 为该参数指定的值时才执行,多个 tag 以逗号分隔 --skip-tags=SKIP_TAGS # 当 play 和 task 的 tag 不匹配该参数指定的值时,才执行
-v, --verbose #输出更详细的执行过程信息,-vvv可得到所有执行过程信息。
4.3 Playbook常用模块
为了方便用户使用,playbook内置了许多功能模块,比较常用的模块主要有:
1)file模块
参数名 | 是否必须 | 默认值 | 选项值 | 说明 |
follow | no | no | yes/no | 如果原来的文件是link,拷贝后依旧是link |
force | no | no | yes/no | 强制执行,没说的 |
group | no | 设定一个群组拥有拷贝到远程节点的文件权限 | ||
mode | no | 等同于chmod,参数可以为“u+rwx or u=rw,g=r,o=r” | ||
owner | no | 设定一个用户拥有拷贝到远程节点的文件权限 | ||
path | yes | 目标路径,也可以用dest,name代替 | ||
src | yes | 待拷贝文件/文件夹的原始位置。 | ||
state | no | file | file/link/directory/hard/touch/absent | file代表拷贝后是文件;link代表最终是个软链接;directory代表文件夹;hard代表硬链接;touch代表生成一个空文件;absent代表删除 |
2)copy模块
参数名 | 是否必须 | 默认值 | 选项值 | 说明 |
src | no | 用于定位ansible执行的机器上的文件,需要绝对路径。如果拷贝的是文件夹,那么文件夹会整体拷贝,如果结尾是”/”,那么只有文件夹内的东西被考过去。一切的感觉很像rsync | ||
content | no | 用来替代src,用于将指定文件的内容,拷贝到远程文件内 | ||
dest | yes | 用于定位远程节点上的文件,需要绝对路径。如果src指向的是文件夹,这个参数也必须是指向文件夹 | ||
backup | no | no | yes/no | 备份远程节点上的原始文件,在拷贝之前。如果发生什么意外,原始文件还能使用。 |
directory_mode | no | 这个参数只能用于拷贝文件夹时候,这个设定后,文件夹内新建的文件会被拷贝。而老旧的不会被拷贝 | ||
follow | no | no | yes/no | 当拷贝的文件夹内有link存在的时候,那么拷贝过去的也会有link |
force | no | yes | yes/no | 默认为yes,会覆盖远程的内容不一样的文件(可能文件名一样)。如果是no,就不会拷贝文件,如果远程有这个文件 |
group | no | 设定一个群组拥有拷贝到远程节点的文件权限 | ||
mode | no | 等同于chmod,参数可以为“u+rwx or u=rw,g=r,o=r” | ||
owner | no | 设定一个用户拥有拷贝到远程节点的文件权限 |
3)template模块
参数名 | 是否必须 | 默认值 | 选项值 | 说明 |
backup | no | no | yes/no | 建立个包括timestamp在内的文件备份,以备不时之需. |
dest | yes | 远程节点上的绝对路径,用于放置template文件。 | ||
group | no | 设置远程节点上的的template文件的所属用户组 | ||
mode | no | 设置远程节点上的template文件权限。类似Linux中chmod的用法 | ||
owner | no | 设置远程节点上的template文件所属用户 | ||
src | yes | 本地Jinjia2模版的template文件位置。 |
4)shell 模块
参数名 | 是否必须 | 默认值 | 选项值 | 参数说明 | ||
chdir | no | 运行command命令前先cd到这个目录 | ||||
creates | no | 如果这个参数对应的文件存在,就不运行command | ||||
executable | no | 将shell切换为command执行,这里的所有命令需要使用绝对路径 | ||||
removes | no | 如果这个参数对应的文件不存在,就不运行command | ||||
5)Yum模块
参数名 | 是否必须 | 默认值 | 选项值 | 参数说明 |
conf_file | no | 设定远程yum执行时所依赖的yum配置文件 | ||
disable_gpg_check | no | no | yes/no | 在安装包前检查包,只会影响state参数为present或者latest的时候 |
list | no | 只能由ansible调用,不支持playbook,这个干啥的大家都懂 | ||
name | yes | 你需要安装的包的名字,也能如此使用name=python=2.7安装python2.7 | ||
state | no | present | present/latest/absent | 用于描述安装包最终状态,present/latest用于安装包,absent用于remove安装包 |
update_cache | no | no | yes/no | 用于安装包前执行更新list,只会影响state参数为present/latest的时候 |
6)service模块
参数名 | 是否必须 | 默认值 | 选项值 | 说明 |
enabled | no | yes/no | 启动os后启动对应service的选项。使用service模块的时候,enabled和state至少要有一个被定义 | |
name | yes | 需要进行操作的service名字 | ||
state | no | stared/stoped/restarted/reloaded | service最终操作后的状态。 |
7)unarchive模块
参数名 | 是否必须 | 默认值 | 选项值 | 说明 |
copy | no | yes | yes/no | 在解压文件之前,是否先将文件复制到远程主机,默认为yes。若为no,则要求目标主机上压缩包必须存在。 |
creates | yes | 指定一个文件名,当该文件存在时,则解压指令不执行 | ||
dest | yes | 远程主机上的一个路径,即文件解压的路径 | ||
grop | no | 解压后的目录或文件的属组 | ||
list_files | no | no | yes/no | 如果为yes,则会列出压缩包里的文件,默认为no,2.0版本新增的选项 |
mode | no | 解压后文件的权限 | ||
src | no | 如果copy为yes,则需要指定压缩文件的源路径 | ||
owner | no | 解压后文件或目录的属主 |
4.4 编写Playbook
在编写playbooke实现运维管理的时候,最主要的就是定义好入口文件,并依照操作顺序利用功能模块编写任务列表。整个过程可以这样理解:运维管理就是一场表演,入口文件就是导演,它规定了演员是谁、出演什么角色、到哪表演;任务列表就是角色的剧本,每一条任务就是一句台词。当所有人按照剧本表演完成整场演出也就顺理完成。
1)导演的职责
编写入口文件的内容相对固定,以tomcat.yml举例来看:
- 第2行表明是注释,用户可自行描述,需要注意的是注释中不能有中文。
- 第3行声明的被控主机的组名,在引入的hosts文件里需有对应的定义,导演就是通过这里规定了演员的表演场所。
- 第4行声明的是以root用户身份去被控主机执行操作,导演就是通过这里规定了谁是演员。
- 第5行声明的是主控机是否需要收集被控主机的系统变量,最常用的就是获知当前正在操作的受控主机IP地址。
- 第6、7行声明的是参与本次操作的角色信息。每个角色对应roles目录里面的一个子目录。导演就是通过这里规定了演员担任的角色。
2)剧本的作用
playbook的具体操作逻辑都是由角色来实现的,在规范中对于角色目录下的内容都有明确定义,最常见的就是files、tasks、templates、vars四个文件夹,其中tasks就是存放剧本的位置,其他文件夹都是表演中使用的道具。
- files:文件夹内存放第三方文件,这里的文件不经过任何变化直接复制到被控主机。通常files目录用来存放程序的安装包文件,由copy模块操作。
- tasks:文件夹内存放以yml格式定义任务列表,playbook执行后会按入口文件定义的顺序依次执行角色文件夹内main.yml文件。
- templates:文件夹内存放模板文件,模板文件以JinJa2格式编写的,执行时会将相应变量替换成真正内容后,再复制到被控主机。通常templates目录用来存放软件的配置文件、辅助文件,对需要动态调整的内容以参数替换形成模板,由template模块操作。
- vars:文件夹内存放以yml格式定义参数文件,playbook查找参数时会默认搜索vars目录下main.yml文件。
任务列表由一条条任务组成,每条任务都可以看做是一条ad-hoc(shell命令),不过任务中可以搭配循环、条件、异常处理等逻辑控制,实现更加复杂的操作。任务列表格式如下图所示:name定义任务的描述信息,下一行指出执行任务使用的模块。模块的参数值可指定为参数文件里面定义的变量,用两层{}包裹起来,需要注意的是为了跟YAML语法中字典的定义进行区分,引入变量的{{}}需要用英文状态的双引号包起来,为了简便也可整行参数直接用双引号包起来。
5 总结
本文主要通过介绍ansible框架、基本概念、ad-hoc及playbook的使用,让读者对ansible工具有了初步认识,明确编写playbook脚本时需要关注的内容,以及各部分所起到的作用,对于运维中的操作可以快速找到相对应的模块实现具体操作。读者也可以从参考文献1处的网址下载ansible示例,通过学习以及动手改造可以使你更快的掌握ansible工具。由于篇幅限制本文对于如何免密登录ssh、如何避免自动化执行过程中的交互动作以及playbook的循环、逻辑控制等没有展开详谈,这些内容会在下一篇内容中进行阐述,帮助读者更加全面了解ansible的作用。
参考文献
[1] ansible示例 https://github.com/ansible/ansible-examples
[2] ansible中文权威指南 http://ansible.com.cn/docs/intro.html
[3] YAML 语言教程 http://www.ruanyifeng.com/blog/2016/07/yaml.html
[4] Ansible安装与配置 https://blog.csdn.net/xyang81/article/details/51568227