云原生之 Ansible 篇(一)
一篇文章写三遍,去除杂质,提炼干货。这是一系列有温度的博客。
@[toc]
Ansible 是什么?怎么和云原生扯在一起了?
不了解 Ansible 的朋友可能会问出第一个问题,了解 Ansible 的朋友可能会问出第二个问题。跟着我这个系列的朋友可能还有另外的问题,比如:我看人家 Docker 之后都是 k8s 了呀,你这,你是不是不行啊?
哈哈,这些个问题不先解答一下这篇还真的很难继续编下去了。
我们先回过头来看一张 DevOps 的图:
上一篇没有什么文字,你们是不是以为这是三个人捆在一起开发呀?
想的有点多哦。
这是一个人要集三种能力于一身哦!!!我个人认为这是一种趋势,现在不是还出现了一种 “轻代码” 的开发模式吗,这些都快不是暗示了,简直是要明示了。
Ansible 是什么?是一门运维语言,是目前对我们这些开发党来说,性价比高的一门运维语言。
DevOps 是云原生的一个重要理念。所以,Ansible 自然也就和 云原生 扯在一起了。
Ansible 我会分两篇来写,第一篇先来一些基础概念,第二篇讲我自己使用的经验。
安装 ansible
Ansible 可以运行在任何机器上,但是对管理机有一定要求。管理机应安装 Python 2(2.7)或 Python 3(3.5 或更高版本),另外,管理机不支持 Windows 控制节点。我们可以使用 Linux 发行版包管理器、源码安装或者 Python 包管理器(PIP)来安装 Ansible。
我使用的是 CentOS7。
1、配置 EPEL YUM
2、yum install ansible -y #yum 安装最新版
3、ansible --version #安装后查看版本以及模块路径等信息
配置证书登录
为了使 Ansible 与客户端通信,需要使用用户帐户配置管理机和客户机。为了方便快捷安全,一般会配置证书方式连接客户机。
在所有客户机和管理上创建新的 ansible 用户之后,我们在管理机(ansible 用户)生成 SSH 密钥,然后将 SSH 公钥复制到所有客户机。
ssh-keygen
三个回车,要是想后面执行一条命令就要输入一次 ssh 密码的话也可以给它个密码。
现在,将 SSH 公钥复制到所有客户机,这使管理机 ansible 用户无需输入密码即可登录客户机:
ssh-copy-id -i ~/.ssh/id_rsa.pub 远程主机名@远程主机ip
Ansible 配置文件
1、/etc/ansible/hosts:主机列表清单,也叫 Inventory。在大规模的配置管理工作中,特别是云服务提供商或者 IDC 厂家,需要管理不同业务的不同机器,这些机器的信息都存放在 Ansible 的 inventory 组件里面。在我们使用 Ansible 进行远程主机管理时,必须先将主机信息存放在 inventory 里面,这样才能使用 Ansible 对它进行操作。如果不想使用默认清单的话可以用-i 选项指定自定义的清单文件,防止多人混合使用一个主机清单。如果没有定义在主机列表文件中,执行命令会提示“No hosts matched”
2、/etc/ansible/ansible.cfg:Ansible 服务主配置文件,比如并发数控制等在此文件定义
Inventory 定义方法
将主机 IP、端口、用户名、密码写在配置文件的不同组中,多种写法格式如下
Andible 常用模块和基本操作
这些常用的模块,就好比基本功,基本招式一样,我们需要掌握这些基本功,掌握这些基本招式。
ping 模块
ping
是测试远程节点的 SSH 连接是否就绪的常用模块,但是它并不像 Linux 命令那样简单地 ping 一下远程节点,而是先检查能否通过 SSH 登陆远程节点,再检查其 Python 版本能否满足要求,如果都满足则会返回 pong,表示成功。使用方式如下:
ping
无须任何参数。上述命令输出结果如下所示:
debug 模块
打印输出信息,类似 Linux 上的 echo 命令。在后续的学习过程中,我们会经常用这个命令来调试我们写的 playbook。
对于debug
模块有两种用法。下面就对这两种用法都进行详细的总结。
通过参数 msg 定义打印的字符串 msg 中可以嵌入变量,比如我先定义了以下的一个 playbook。
通过参数 var 定义需要打印的变量变量可以是系统变量,也可以是动态的执行结果,通过关键字
register
注入变量中。对于变量,我们可以这样玩:
对于注入变量,可以这样玩:
copy 模块
从当前的机器上复制静态文件到远程节点上,并且设置合理的文件权限。copy
模块在复制文件的时候,会先比较一下文件的 checksum,如果相同则不会复制,返回状态为 OK;如果不同才会复制,返回状态为 changed。
一般情况的使用,就是这样的:
在实际的工作中,一般会在进行文件分发时,需要备份原文件,这个时候就需要我们加上backup
选项:
加上backup: yes
后,在目标主机上,就会对原来的文件进行备份。
template 模块
如果只是复制静态文件,使用copy
模块就可以了;但是如果在复制的同时需要根据实际情况修改部分内容,那么就需要用到template
模块了。
比如我们在分发配置文件时,每个配置文件需要根据远程主机的一些属性不同而配置不同的值,对于需要替换的部分,我们就可以使用template
模块来进行替换。template
模块使用的是 Python 中的 Jinja2 模板引擎,这里我们不需要过多的去关注这个模板引擎,只需要知道变量的表示法是{{}}
就可以了。比如这里就有一个 http.conf.j2 的模板文件(我见过的更多的模板文件后缀都是 yaml 的),文件内容如下:
其中{{ansible_default_ipv4.address}}
就是需要根据不同的主机,动态变化的。接下来,我们就可以这样使用template
模块来完成变量的替换。
在目的主机上,文件内容如下:
和copy
模块一样,template
模块也可以进行权限设置和文件备份等功能。
file 模块
file
模块可以用来设置远程主机上的文件、软链接和文件夹的权限,也可以用来创建和删除它们。
我们可以使用mode
参数进行权限修改,可以直接赋值数字权限(必须以 0 开头)。
我们还可以根据state
参数的不同,实现不同的行为,比如创建软链接:
也可以设置state: touch
创建一个新文件,比如这样:
还可以设置state: directory
新建一个文件夹,比如这样:
user 模块
user
模块可以对用户进行管理,实现增、删、改 Linux 远程节点的用户账户。比如增加用户:
删除用户:
但是在使用这个user
模块时,需要注意权限问题。
shell 模块
在远程节点上通过/bin/sh
执行命令。如果一个命令可以通过模块yum
、copy
模块实现时,那么建议不要使用shell
或者command
这样通用的命令模块。因为通用的命令模块不会根据具体操作的特点进行状态判断,所以当没有必要再重新执行的时候,它还是会重新执行一遍。
支持
<
、>
、|
、;
和&
调用脚本
在执行命令之前,我们可以改变工作目录,并且仅在文件 somelog.txt 不存在时执行命令,除此之外,还可以指定用 bash 运行命令:
service/systemd
管理服务。
archive&unarchive
1. archive 模块
功能:在远端主机打包与压缩;
主要参数如下:
示例一:将
/var/log
目录压缩为tar.gz
格式,并存储至/opt
目录下;
2. unarchive 模块
功能:在远端主机解包与解压缩;
主要参数如下:
示例一:把压缩包推送到被控端,在被控端主机解压缩:
示例二:压缩包在
ansible
主机上,直接解压到被控主机:
Ansible playbook
playbook 本质是包含了一个或多个 play 的 YAML 配置文件,通常以.yaml 或者.yml 结尾。在单一的一个 playbook 文件中,使用连续的三个中横线(---)作为每个 play 的区分。
执行 playbook 命令
我们都是按照 yaml 语法规则来编写 playbook。
Ansible 提供了一个单独的命令:ansible-playbook
命令,我们可以通过这个命令来执行 yaml 脚本。常见的ansible-playbook
的使用方法如下:
最简单的使用方法:
我们还可以使用以下命令查看输出的细节:
我们也可以使用以下命令查看该 yaml 脚本将影响的主机列表:
还可以使用以下命令检查 yaml 脚本语法是否正确:
上面的几种使用方法基本就涵盖了我们日常工作中 80%的场景了,剩余的 20%场景,比如并行、异步等,很少用到,等真正用到的时候再去查阅相关资料也来的及。而工作中,更多的时候,我们不是在编写 playbook,就是在编写 playbook 的路上。所以,接下来我重点说说如何写这个 playbook,也就是 playbook 的基本语法。
playbook 基本语法
最基本的 playbook 脚本分为三个部分:
在哪些机器上以什么身份执行
执行的任务有哪些
善后任务有哪些
我们在编写 playbook 脚本的时候,总是离不开上面的三个部分的。下面先来一个稍微有点复杂的 playbook 脚本,让大家先有一个整体的认识。
任务列表
任务列表是整个 playbook 的核心,对于任务列表,我们首先需要知道以下三点内容:
任务是从上到下顺序执行的,如果中间发生错误,那么整个 playbook 会中止,除非 ignore error;
每一个任务都是对模块的一次调用,只是使用不同的参数和变量而已;
每一个任务最好有一个 name 属性,这样在执行 yaml 脚本时,可以看到执行进度信息(也方便失败的时候快速定位)。
对于任务的参数有两种不同的写法,我们在编写 yaml 脚本时,可以按照自己的喜好进行选择。
写法一:
写法二:
这两种写法都是 OK 的,我一般喜欢第二种写法。
最后,对于任务我们还需要特别一个点,那就是任务的执行状态。我们在执行 Ansible Ad-Hoc 或者 ansible-playbook 的时候,在输出中都会有一个changed
字段,比如:
或者
这里的这个changed
就是任务的执行状态,但是它为什么一会是 0,一会有是 1 呢?这就要说到 Ansible 中一个叫做“幂等性”的概念。
幂等性
幂等性是数学和计算机科学上一个常见的概念,多次执行产生的结果不会发生改变,这样的特性就被成为幂等性。
大多数的 Ansible 模块在设计时保证了幂等性,幂等性保证了 Ansible 脚本多次执行情况下的相同结果,尽可能的避免使用那些不能满足幂等性的模块。比如我们经常使用的
shell
模块就是非幂等性的。
我们要明白 Ansible 是以“结果为导向的”,我们指定了一个“目标状态”,Ansible 会自动判断“当前状态”是否与“目标状态”一致,如果一致,则不进行任何操作;如果不一致,那么就将“当前状态”变成“目标状态”,这就是“幂等性”,“幂等性”可以保证我们重复的执行同一项操作时,得到的结果是一样的。
那这个幂等性与上面的changed
又有什么关系呢?且听我下面慢慢道来!
当
changed
为 false 或者 0 时,表示 Ansible 没有进行任何操作,没有“改变什么”;当
changed
为 true 或者大于 0 时,表示 Ansible 执行了操作,“当前状态”已经被 Ansible 改变成了“目标状态”。
拿copy
这个模块来举例子说明,当我们准备将一个文件通过 Ansible 拷贝到远程主机时,copy
模块首先检查远程是否已经存在了该文件,如果不存在,则把文件拷贝过去,返回changed
为大于 0;如果存在时,则开始比对两个文件的 md5 值,如果 md5 值一致,则说明两个文件是一样的,则不需要拷贝,此时copy
模块则什么都不干,返回changed
为 0。
playbook 的 handlers 与 notify
一、Ansible handlers 的作用
handlers 是一种触发器,它可以对 task 进行监控,如果 task 所指定的任务状态发生变化,则进行 notify 通知,然后触发额外的一系列操作,看一个示例来帮助理解:
上面的 YAML 文件存在三个 task 任务,分别是安装 httpd、复制配置文件到远端主机、启动 httpd 服务。但是当第二个 task 中的配置文件发生了改变后再次执行 playbook 的话,会发现新的配置文件虽然会正确的复制到远端主机去,但是却没有重启 httpd 服务。因为 Ansible 在执行 playbook 时发现第三个任务与现在状态是一致的,就不会再次执行任务。为了解决这种问题,就需要使用 ansible 的 handlers 功能。handlers 是用于监控一个任务的执行状态,如果一个 tasks 任务最后是 changed 状态则会触发 handlers 指定的操作。
二、如何配置 handlers
Ansible 中通过 notify 这个模块来实现 handlers,将示例 1 修改后:
当 httpd.conf 的源文件发生修改后,只需重新执行 playbook 就会自动重启 httpd 服务,因为配置文件状态是 changed 而非 ok。
playbook 的变量定义与调用
1.作用:将 playbook 中的某些值使用变量代替,从而简化 playbook 的编写 2.变量简介:要创建的用户、要安装的软件包、要重启的服务、要删除的文件、要从互联网检索的文档 3.方法:变量名应该由字母、数字、下划线组成,变量名需要以字母开头,ansible 内置的关键字不能作为变量名。4.范围
vars 定义变量
1、playbook 中的变量(vars 和 vars_files)
在定义变量时,还能够以类似”属性”的方式定义变量,示例如下
引用变量
当我们需要引用这两个变量时,有两种语法可用
在外部文件定义 playbook 变量(vars_files)在 playbook 中引入包含变量的文件时,需要使用 vars_files 关键字,被引入的文件需要以- 开头,以 YAML 中块序列的语法引入,示例如下
在外部文件中写入
上例中使用 vars_files 关键字引入了对应的变量文件,然后使用了文件中定义的变量。
上例中 vars_files 关键字只引入了一个变量文件,也可以引入多个变量文件,每个被引入的文件都需要以- 开头,示例如下
“vars”关键字和”vars_files”关键字可以同时使用,如下
流程控制
条件:
循环:
常用循环语句:
使用 template 实现灵活配置
一、Ansible template 作用
是什么前面说了,这里就直接看怎么用。
遗漏部分在文末补全。
Ansible 之 roles 使用
函数。
所有的 role 单独放在一个 名为 roles 的目录下,在 playbook 中调用 role 的方式为:
或者
每个 role 下面有个 tasks 目录,里面至少得有 main.yaml 文件,会被调用到。
每个 role 下面有个目录叫 meta,在里面可以新建文件 main.yml,在文件中可以设置该 role 和其它 role 之前的关联关系。
版权声明: 本文为 InfoQ 作者【看,未来】的原创文章。
原文链接:【http://xie.infoq.cn/article/1bb6adc99b6964f9cdfc62764】。文章转载请联系作者。
评论