[toc]
这样理解Ansible更容易
这篇文章是 Jenkins 2.x实践指南
作者翟志军博客中的一篇内容,看完之后觉得写的非常好,所以收藏一下
滚滚长江东逝水,浪花淘尽英雄。是非成败转头空。青山依旧在,几度夕阳红。—— 《临江仙》
电脑店
从前,有一家电脑店。原来你即是老板,又是店员时,拿到清单,你就必须亲自动手采购,然后一个个零件组装。每天都做着即重复又辛苦的活。
虽说你的组装技术已经很娴熟了,但是偶尔还发生装错的情况(大概是那天和老板娘吵架了),把一个客人要求的 CPU i5 装成了 CPU i7。结果是你亏本或者赚得少了。
后来,你采购了一个自动组装电脑的机器人。你只要告诉它电脑的配置,并把零件放到指定的箱子中。接着启动这台机器,它就自动帮你组装好电脑了。它每天都干重复的活也不会叫辛苦。
最重要的是准确,它不会因为心情不好,而装错。因为它根本不会闹情绪。
这样,老板就可以从重复的工作解放出来。然后将多出来的时间花在与人的沟通上,为有不同需求的人设计更合适的电脑配置清单。毕竟游戏发烧友和办公小白领的需求是不一样的。
在运维领域,不少运维人都干着即是老板又是店员的工作。如果在运维领域也能有这样的“机器人”该多好。事实上,Ansible、Puppet、Check 就是这样的机器人。
为什么要从零设计一个运维机器人
本文并不想生硬地罗列 Ansible 的各个知识点。因为那样,大家不如直接看 Ansible 官方文档就好。
笔者采用从零设计一个运维机器人的方式来告诉你,为什么 Ansible 会是现在这个样子。当然,现实中的 Ansible 不会像本文所写的那样一步步设计。
为什么要这样呢?因为笔者觉得只有知道一个工具背后的设计原理,真正用这个工具才会得心应手。
运维机器人的最终模样
首先,需要确定一下实现这个运维机器人的目的是什么。我们并不是希望所有的运维工作都交给运维机器人,而是希望运维工作中重复的那部分尽可能的交给机器人,把创造性的工作全部交给人。如下图所示。
以终为始是一种非常有效的实现目标的思考模型。根据此思考模型,我们首先必须探讨运维机器人的最终模样。 然后,再讨论可能的解决方案。
那么,什么样的运维机器人能帮助我们实现上述的自动化运维目标呢?想像一下。是不是只要我们对着运维机器人说一句:“我要部署一个 Nginx 到 192.168.12.11”。它就可以帮我们完成了?
但是它怎么知道如何连接到 192.168.12.11 呢?是使用用户名密码的方式,还是使用私钥?它又怎么知道 Nginx 需要什么样的配置呢?一问下来,其实,语音运维只适用于启动一些预定义的动作。就像汽车的一键启动。你不可能使用语音来对 Nginx 进行大量的配置。
而纯文本才是进行大量配置的最好媒介。
所以,运维机器人的最终模样是:我们将部署的主机 IP、登录方式、Nginx 的配置放在一个文本文件中,然后运维机器人读取这个文本文件,然后根据配置进行部署。如果部署的是业务系统,我们还需要准备该业务系统的二进制包。如下图所示。
那么,我们在文本文件中使用何种语言描述我们的配置需求呢?可以分成两种。一种是利于人类学习的自然语言(如英语)。另一种是利于机器读取的结构化数据(如YAML、JSON)。
按当前的技术实现的可能性,不论是运维机器人,还是交给其它程序,都需要将自然语言转到结构化的数据。就像程序员,需要将业务知识翻译成编程语言;像编译器将编程语言翻译成机器真正能识别的二进制代码。
运维机器人的真正核心不是将自然语言转成结构化的数据 。所以,文本文件中,我们直接写结构化数据。同时,我们决定使用 YAML 格式作为结构化数据的载体。因为它是非常流行的配置文件格式。降低人们写结构化数据的难度。
当然,好的设计不应该与具体配置文件格式耦合。
实现运维机器人要解决哪些问题
以上只是确定了运维机器人的最终模样及使用方式,解决的是用户的问题。但是因为我们是运维机器人的设计者,我们必须考虑如何实现它。
回想一下,平时我们的运维人员是如何实现自动化的?是不是写好了 bash 脚本后,然后将脚本上传到目标机器,最后在目标机器上执行该脚本。
这个 bash 脚本其实也可以算是一种结构化的数据格式,而且是一种不需要再做编译,目标机器能直接运行的格式。
在平时的自动化方式基础上进行抽象。我们觉得要实现运维机器人要解决的关键问题有:
- 需要将 YAML 转成目标机器可执行的程序(或脚本)。
- 需要将可执行的程序上传到目标机器,并执行。
为什么一定要将 YAML 转成目标机器可执行的程序呢?直接写 bash 不就可以了?
因为运维机器人要解决的不止是 Linux 系统的自动化运维,还有 Windows,甚至路由器的。所以,我们需要使用一种独立于目标机器的语言来描述我们的运维需求。
问题 2 我们先放一放,因为上传代码到目标不是运维机器人的关键问题。
实现 YAML 转成 ?
虽然咱们希望运维机器人能运维所有类型的机器,但是本文重点不是要在一篇文章内实现所有类型机器的自动化运维。接下我们只针对 Linux 机器进行讲解。
现在我们遇到的问题是要将 YAML 转成什么程序以实现在目标机器上执行?
如果我们将 YAML 转成 Java 程序,那么目标机器就必须装有 JDK,这是不现实的。你不可能让所有的 Linux 机器都安装 JDK。所以,YAML 最好是能转成所有 Linux 都支持程序。目前笔者能想到的就是:bash 和 Python。
P.S. 现实中,很多运维工具要求所有的目标机器必须安装特定的客户端的。而 Ansible 却不需要。如果在使用自动化运维工具前,你要为所有的机器安装特定的客户端,那么,你怎么自动化为所有的机器自动安装客户端呢?留着读者思考。
从 bash 和 Python 之间做选择,没有什么好讨论的,选择 Python。
那么,怎么将 YAML 转成 Python 代码呢?这要看我们怎么设计 YAML 内的描述语言了。其实就是设计自动化运维机器人的领域特定语言(DSL)。为方便讨论,我们称之为:OPL 语言。
OPL 语言1.0:基本要素
现在咱们在为一台机器部署一个 Nginx 作为切入点,来设计我们的 OPL 语言。以下就是1.0版本:
---
- host: "192.168.35.10"
ansible_ssh_user: vagrant
ansible_ssh_pass: vagrant
tasks:
- name: install nginx
yum:
name: nginx
action: install
- host:代表部署的目标机器。
- ansible_ssh_*:开头的 key 是指定 ssh 连接的用户名和密码。
- tasks:是一个数组,包含一系列任务。
- name:任务名称,方便人阅读。
- yum:要执行的任务的类型,也就是要执行 yum 操作。yum 任务下的 name 属性代表要安装的软件名称,action 属性代表执行的是安装操作。
1.0版的 OPL 语言包含了运维领域最基本要素:
- 目标主机的描述
- 连接目标主机的必要信息
- 任务描述
为方便沟通,我们暂将些 YAML 文件命名为 playbook.yml
。