CDC

Place to Be & Show Yourself

Ansible入门和案例分析

《Ansible入门和案例分析》

问题的提出

如果有多台服务器需要远程进行配置?如果几个集群环境搭建好之后,需要扩容新增一台机器?如何才能更加方便快捷的完成服务器配置呢?答案就是Ansible。
Ansible是一个配置管理和配置工具,它使用SSH连接到服务器并运行配置好的任务,服务器上不用安装任何多余的软件,只需要开启ssh,所有工作都交给client端的ansible负责。
关于Ansible的一个好处是,将bash脚本转换为可执行任务是非常容易的。我们可以编写自己的配置程序,但是Ansible更加干净,因为它可以自动在执行任务之前获取上下文。ansible任务是幂等的,没有大量额外的编码,ansible可以一次又一次地安全运,而bash命令这种幂等性。
ansible使用“facts”来确保任务的幂等安全运行, 它是在运行任务之前收集的系统和环境信息。ansible使用这些facts来检查状态,看看是否需要改变某些东西以获得所需的结果。这使得ansible可以让服务器一次又一次地运行可复制的任务。

安装

Ansible基于Python进行开发,最简单的安装方式就是使用Pip命令
sudo pip install ansible
安装完成之后,可以运行命令
ansible --version
来查看最新的版本号,目前最新版本号是2.6

配置

ansible的默认配置文件路径为 /etc/ansible,当然可以根据需要在本地目录中创建配置文件。

管理服务器:Inventory文件

Inventory文件实际上就是主机文件,缺省位置为/etc/ansible/hosts,当然也可以是任意路径和名字,hosts文件中定义了被管理主机。一个主机可以属于一个或者多个组,当然也可以不属于任何组。下面的hosts文件定义了两个组,每个组内有一台主机

NOTE: 当然Inventory文件中不仅仅可以定义一个group下面包含的主机,还可以定义这个group可以使用的变量,例如

Ansible如何连接服务器

Ansible是通过SSH连接服务器的。
1. 连接内网服务器
1.1 直接在hosts文件中直接配置用户名和密码,
例如

1.2 配置无密码登陆,参考“无密码登陆的简易配置和浅显解释”。
1.3 如果所有服务器的用户名和密码都相同,且用户名和当前用户名一致,也可以通过命令行参数–ask-pass来提示输入登陆密码
ansible all -m ping --ask-pass
2. 连接AWS服务器
hostname ansible_ssh_private_key_file=~/.ssh/keyfile.pem ansible_user=ubuntu

基础:运行命令

在命令行运行ansible命令,并观察输出结果

命令说明:

模块(Modules)

Ansible使用“模块”来完成大部分的任务。模块可以做安装软件,复制文件,使用模板等等。因为它们可以使用可用的上下文(“Facts”)来决定完成一个task需要做什么操作。如果没有模块,我们就得运行shell命令或者bash脚本了。下面运行shell脚本,实际上也是在用shell模块

命令说明:

但是这并不是特别强大。尽管能够一次在所有服务器上运行这些命令,但是我们仍然只能完成任何bash脚本可能执行的操作。如果我们使用了更合适的模块,我们可以运行命令来保证结果。可靠的模块确保我们可以一次又一次地运行相同的任务,而不会影响最终结果。
要在Debian / Ubuntu服务器上安装软件,“apt”模块将运行相同的命令,但确保幂等。

这里使用apt模块来安装Nginx(如果没有安装)。
运行任务的结果是”changed”: false。这表明没有变化; 我已经使用该shell模块安装了Nginx 。我可以一遍又一遍地运行这个命令,而不用担心它会改变预期的结果 – Nginx已经安装,Ansible知道,并且不尝试重新安装它

其他所有模块,请参考下面的链接“模块列表

剧本(Playbooks)

Playbook可以运行多个任务,并提供一些更高级的功能。让我们将上述任务移到一本剧本中。在ansible中剧本(playbooks)和角色(roles)都使用Yaml文件定义。
创建文件nginx.yml:

执行这个剧本,可以看到执行结果

这里可以看到一个Playbook执行的过程,先收集FACTS,再执行然后显示结果。

处理程序(Handlers)

处理程序与任务完全相同(它可以做task可以做的任何事),但只有当另一个任务调用它时才会运行。您可以将其视为事件系统的一部分; 处理程序将通过其侦听的事件调用进行操作。 这对于运行任务后可能需要的“辅助”操作非常有用,例如在配置更改后安装或重新加载服务后启动新服务。

以上notify指令和handlers配合使用,当执行完Install Nginx之后执行Start Nginx, 当然如果Nginx已经安装的情况下,Task不执行,对应的Handler也不会执行

更多的任务(More Tasks)

可以再一个Playbook中包括多个相关的任务

这个Playbook中包含了3个任务
– Add Nginx Repository- 使用apt_repository模块添加Nginx稳定PPA以获取最新的稳定版本的Nginx 。
– Install Nginx – 使用Apt模块安装Nginx,并启动
– Create Web Root – 最后创建一个Web根目录,并Reload Nginx

新的register和when指令,可以实现在某些事情发生后让ansible执行任务的功能。例如,注册通过shell模块运行命令的结果可以让您访问该命令的stdout。
这里面还有一个新的语法结构就是变量,docroot变量在定义vars部分。然后将其用作创建定义目录的文件模块的目标参数,这是Jinja2的模板语法,需要用引号引起来。

角色(roles)

角色很适合组织多个相关任务并封装完成这些任务所需的数据,真实的配置通常需要额外的数据,如变量,文件,动态模板等等。这些工具可以与Playbook一起使用,但是我们可以通过将相关任务和数据组织成一个角色(role, 相关的结构)很快就能做得更好。角色有一个这样的目录结构:

创建角色(Creating a Role)

可以使用ansible-galaxy命令来创建一个新角色。此工具可用于将角色保存到Ansible的公共注册表,但是我通常只是使用它来在本地创建role的基础目录结构。

文件(files)

在files目录中,我们可以添加我们要复制到我们的服务器中的文件

处理程序(handlers)

我们可以把在剧本中的定义的所有处理程序放入到handlers目录中。约定必须包含main.yml文件。handlers/main.yml 内容:

一旦handlers/main.yml中的处理程序定义好了,我们可以自由地从其他的yaml配置中引用它们。

元(meta)

meta目录中的main.yml文件包含Role元数据,包含的依赖关系。如果这个角色依赖于另一个角色,我们可以在这里定义。例如,nginx角色取决于安装SSL证书的ssl角色。约定必须包含main.yml文件。 meta/main.yml 内容:

如果我调用了“nginx”角色,它将尝试首先运行“ssl”角色。 否则我们可以省略此文件,或将角色定义为没有依赖关系:

模板(templates)

基于Python的Jinja2模板引擎(和django的模板引擎很类似),模板文件可以包含模板变量。这里的文件应该以.j2为类型后缀,提倡但是不强制,也可以取其他的名字。类似于files,在templates目录中没有main.yml文件,只包含.j2后缀的模板文件。
这是一个Nginx服务器(“虚拟主机”)配置的例子。请注意,它使用了稍后在vars/main.yml文件中定义的一些变量。
我们的示例中的Nginx配置文件位于templates/serversforhackers.com.conf.j2:

domain
ssl_crt
ssl_key
这三个变量将在变量部分(vars)中定义。

变量(vars)

在使用任务集成所有事情之前,让我们来看看变量。该vars目录包含一个main.yml文件(如handlers和meta目录一样),在main.yml中我们可以列出将要使用的所有变量。
以下是该vars/main.yml文件的内容:

我们可以在这个角色的其他地方使用这三个变量。我们在上面的模板中看到它们的使用,但是我们也可以在我们定义的任务中看到它们。
注意这里和inventory文件中定义变量方式的不同。

任务(tasks)

终于到了将一切都是放在一系列的任务中的时候了。
使用角色时运行的主文件是tasks/main.yml文件。看看我们的用例将会是什么样的:

这一系列任务使得Nginx能被完整的安装。任务按照出现的顺序完成以下工作:

  1. 添加nginx / stable库
  2. 安装并启动Nginx
  3. 添加H5BP配置文件
  4. 从sites-enabled目录中删除文件的符号链接来禁用默认的Nginx配置
  5. 将serversforhackers.com.conf.j2虚拟主机模板复制到Nginx配置中,渲染模板
  6. 通过将其符号链接到sites-enabled目录来启用Nginx服务器配置
  7. 创建Web根目录
  8. 更改项目根目录的权限(递归),该目录位于之前创建的Web根目录之上

有一些新的模块(和一些我们已经涵盖的新用途),包括复制,模板和文件模块。通过设置每个模块的参数,我们可以做一些有趣的事情,例如确保文件“不存在”(如果存在则删除它们)的state: absent,或者通过创建一个文件作为符号链接的state: link。您应该检查每个模块的文档,以查看可以用它们完成哪些有趣和有用的事情。

运行角色

要对服务器运行一个或多个角色,我们将重新使用另一个playbook。该playbook与roles目录位于同一个目录中,同一层级。当我们用ansible-playbook命令运行的时候需要先cd进入到该目录中。让我们创建一个“主”的yaml文件(被ansible-playbook命令执行的文件),该文件定义要使用的角色以及运行它们的主机:
文件~/ansible-example/server.yml位于与roles目录相同的目录中:

然后就可以和普通的playbook一样来运行了。

实际上写到这里,大家可以做一个不恰当,但是非常简单的类比。角色就好比面向对象编程中的对象,把相关的数据和动作都封装在一起了。但是最终要能运行完成特定功能,还是需要有一个main函数/方法来调用。

事实(Facts)

可以运行命令查看所有可用的Facts
ansible -i ./hosts remote -m setup

案例分析

案例1

我们的开发环境需要统一配置,安装JDK,修改对应的环境设置,安装Cassendra和其他必要软件。这个是Ansible最适合的应用场景了。用一个

案例2

在另一个自然语言处理的项目,新版本部署涉及到多台beta环境和生产环境的机器,每次部署的大概流程就是本地构建好docker image,然后使用paramiko登陆到远程环境,下载最新的docker image,并运行docker容器
这个场景中,Ansible登陆远程机器pull docker image,并运行Docker容器,也是一个不错的选择。在没有遇到Ansible之前,我们就硬生生的自己写了一套

总结

本篇文章带着做了如下工作:

  • 安装了ansible
  • 配置了ansible inventory文件(仅在不使用connection: local 时才需要)
  • 同时在多个服务器上执行幂等的 ad-hoc命令
  • 创建一个基本的Playbook来运行多个任务(tasks),并使用了处理程序(handlers)
  • 将多个任务抽象为一个角色,以保持所有Nginx相关的操作在一个角色内
  • 展示了如何设置依赖关系
  • 展示了如何注册任务的“依赖”执行关系,当一个任务执行成功后再执行另一个任务
  • 展示了如何在我们的任务中使用更多的模板,文件和变量
  • 展示了如何整合使用ansible事实(facts)
点赞

发表评论

电子邮件地址不会被公开。