标签 Ansible 下的文章

无服务 serverless 托管服务 managed service 发展方向的又一步,并且与 Ansible 的无代理体系结构相得益彰。

Ansible 被设计为实际工作中的最简化的部署工具。这意味着它不是一个完整的编程语言。你需要编写定义任务的 YAML 模板,并列出任何需要自动完成的任务。

大多数人认为 Ansible 是一种更强大的“处于 for 循环中的 SSH”,在简单的使用场景下这是真的。但其实 Ansible 是任务,而非 SSH。在很多情况下,我们通过 SSH 进行连接,但它也支持 Windows 机器上的 Windows 远程管理(WinRM),以及作为云服务的通用语言的 HTTPS API 之类的东西。

在云中,Ansible 可以在两个独立的层面上操作: 控制面 control plane 实例资源 on-instance resource 。控制面由所有没有运行在操作系统上的东西组成。包括设置网络、新建实例、供给更高级别的服务,如亚马逊的 S3 或 DynamoDB,以及保持云基础设施安全和服务客户​​所需的一切。

实例上的工作是你已经知道 Ansible 可以做的:启动和停止服务、配置文件 模版化 templating 、安装软件包以及通过 SSH 执行的所有与操作系统相关的操作。

现在,什么是 无服务 serverless 呢?这要看你问谁,无服务要么是对公有云的无限延伸,或者是一个全新的范例,其中所有的东西都是 API 调用,以前从来没有这样做过。

Ansible 采取第一种观点。在 “无服务” 是专门术语之前,用户不得不管理和配置 EC2 实例、虚拟私有云 (VPC) 网络以及其他所有内容。无服务是托管服务方向迈出的另一步,并且与 Ansible 的无代理体系结构相得益彰。

在我们开始 Lambda 示例之前,让我们来看一个简单的配置 CloudFormation 栈任务:

- name: Build network
  cloudformation:
    stack_name: prod-vpc
    state: present
    template: base_vpc.yml

编写这样的任务只需要几分钟,但它是构建基础架构所涉及的最后的半手动步骤 - 点击 “Create Stack” - 这将 playbook 与其他放在一起。现在你的 VPC 只是在建立新区域时可以调用的另一项任务了。

由于云提供商是你帐户中发生些什么的真相来源,因此 Ansible 有许多方法来取回并使用 ID、名称和其他参数来过滤和查询运行的实例或网络。以 cloudformation_facts 模块为例,我们可以从我们刚刚创建的模板中得到子网 ID、网络范围和其他数据。

- name: Pull all new resources back in as a variable
  cloudformation_facts:
    stack_name: prod-vpc
  register: network_stack

对于无服务应用,除了 DynamoDB 表,S3 bucket 和其他任何其他功能之外,你肯定还需要一个 Lambda 函数的补充。幸运的是,通过使用 lambda 模块, Lambda 函数可以以上次任务的堆栈相同的方式创建:

- lambda:
    name: sendReportMail
    zip_file: "{{ deployment_package }}"
    runtime: python3.6
    handler: report.send
    memory_size: 1024
    role: "{{ iam_exec_role }}"
  register: new_function

如果你有其他想用来交付无服务应用的工具,这也是可以的。开源的无服务框架有自己的 Ansible 模块,它也可以工作:

- serverless:
    service_path: '{{ project_dir }}'
    stage: dev
  register: sls
- name: Serverless uses CloudFormation under the hood, so you can easily pull info back into Ansible
  cloudformation_facts:
    stack_name: "{{ sls.service_name }}"
  register: sls_facts

这不是你需要的全部,因为无服务项目也必须存在,你将在那里大量的定义你的函数和事件源。对于此例,我们将制作一个响应 HTTP 请求的函数。无服务框架使用 YAML 作为其配置语言(和 Ansible 一样),所以这应该看起来很熟悉。

# serverless.yml
service: fakeservice

provider:
  name: aws
  runtime: python3.6

functions:
  main:
    handler: test_function.handler
    events:
      - http:
          path: /
          method: get

AnsibleFest 中,我将介绍这个例子和其他深入的部署策略,以最大限度地利用你已经拥有的 playbook 和基础设施,还有新的无服务实践。无论你是否能到,我希望这些例子可以让你开始使用 Ansible,无论你是否有任何服务要管理。

AnsibleFest 是一个单日会议,汇集了数百名 Ansible 用户、开发人员和行业合作伙伴。加入我们吧,这里有产品更新、鼓舞人心的交谈、技术深度潜水,动手演示和整天的网络。

(题图: opensource.com)


via: https://opensource.com/article/17/8/ansible-serverless-applications

作者:Ryan Scott Brown 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Libral 为系统资源和服务提供了一个统一的管理 API ,其可以作为脚本管理任务和构建配置管理系统的坚实基础。

 title=

作为继承了 Unix 的传统的 Linux 操作系统,其并没有一个综合的系统管理 API 接口,相反,管理操作是通过多种特定用途的工具和 API 来实现的,其每一个都有自己约定和特有的风格。这就使得编写一个哪怕是简单的系统管理任务的脚本也很困难、很脆弱。

举个例子来说,改变 “app” 用户的登录 shell 要运行 usermod -s /sbin/nologin app。这个命令通常没有问题,只是当系统上没有 “app” 用户时就不行了。为了解决这个例外错误,具有创新精神的脚本编写者也许要这样写:

grep -q app /etc/passwd \
  && usermod -s /sbin/nologin app \
  || useradd ... -s /sbin/nologin app

这样,当 “app” 用户存在于系统中时,会执行更改登录 shell 的操作;而当此用户不存在时,就会创建此用户。不幸的是,这种编写系统管理任务脚本的方式是不适合的:对于每一种资源来说都会有一套不同的工具,而且每个都有其不同的使用惯例;不一致性和经常出现的不完备的错误报告将会使错误的处理变得困难;再者也会因为工具自身的特性引发的故障而导致执行失败。

实际上,以上所举的例子也是不正确的:grep 并不是用来查找 “app” 用户的,它只能在文件 /etc/passwd 的一些行中简单的查找是否有字符串 “app”,在大多数情况下它或许可以工作,但是也可能会在最关键的时刻出错。

很显然,那些执行简单任务的脚本管理工具,很难成为大型管理系统的基础。认识到这一点,现有的配置管理系统,比如 Puppet、Chef 及 Ansible,围绕基本的操作系统资源的管理竭尽全力的建立其内部 API 就是明智之举。这些资源抽象是内部 API,其与所需的相应工具密切相关。但这不仅导致大量的重复性工作,也为尝试一个新创新的管理工具设置了强大的障碍。

在创建虚拟机或者容器镜像这一领域,这种障碍就变得非常明显:比如在创建镜像的过程中,就要么需要回答关于它们的简单问题,要么需要对其进行简单的更改才行。但是工具全都需要特别处理,那些所遇到的问题和更改需要用脚本逐个处理。因此,镜像构建要么依靠特定的脚本,要么需要使用(和安装)一个相当强大的配置管理系统。

Libral 将为管理工具和任务提供一个可靠的保证,通过对系统资源提供一个公用的管理 API,并使其可以通过命令行工具 ralsh 使用,它允许用户按照相同的方法查询和修改系统资源,并有可预见的错误报告。对以上的举例来说,可以通过命令 ralsh -aq user app 检查 “app” 用户是否存在;通过 ralsh -aq package foo 检查 “foo” 软件包是否已经安装;一般情况下,可以通过命令 ralsh -aq TYPE NAME 检查 ”NAME“ 是否是 ”TYPE“ 类型的资源。类似的,要创建或更改已存在的用户,可以运行:

ralsh user app home=/srv/app shell=/sbin/nologin

以及,要在文件 /etc/hosts 创建和修改条目,可以运行命令:

ralsh hostmyhost.example.com ip=10.0.0.1 \
  host_aliases=myhost,apphost

以这种方式运行,“ralsh” 的使用者事实上完全隔离在那两个命令内部的不同运行工作机制之外:第一个命令需要适当的调用命令 useradd 或者 usermod,而第二个需要在 /etc/hosts 文件中进行编辑。而对于该用户来说,他们似乎都采取同样的模型:“确保资源处于我所需要的状态。”

怎样获取和使用 Libral 呢?

Libral 可以在这个 git 仓库找到并下载。其核心是由 C++ 编写的,构建它的说明可以在该仓库中找到,不过只是在你想要为 Libral 的 C++ 核心做贡献的时候才需要看它。Libral 的网站上包含了一个 预构建的 tarball,可以用在任何使用 “glibc 2.12” 或者更高版本的 Linux 机器上。可以使用该 “tarball” 的内容进一步探究 ralsh ,以及开发新的提供者(provider),它使得 Libral 具备了管理新类型资源的能力。

在下载解压 tarball 后,在目录 ral/bin 下能找到 ralsh 命令。运行不需要任何参数的 ralsh 命令就会列举出来 Libral 的所有资源类型。利用 --help 选项可以打印输出关于 ralsh 的更多说明。

与配置管理系统的关系

知名的配置管理系统,如 Puppet、Chef 及 Ansible,解决了一些 Libral 所解决的同样的问题。将 Libral 与它们的区分开的主要是它们所做工作和 Libral 不同。配置管理系统被构建来处理跨大量节点管理各种事物的多样性和复杂性。而另一方面 Libral 旨在提供一个定义明确的低级别的系统管理 API ,独立于任何特定的工具,可用于各种各样的编程语言。

通过消除大型配置管理系统中包含的应用程序逻辑,Libral 从前面介绍里提及的简单的脚本任务,到作为构建复杂的管理应用的构建块,它在如何使用方面是非常灵活的。专注与这些基础层面也使其保持很小,目前不到 2.5 MB,这对于资源严重受限的环境,如容器和小型设备来说是一个重要考虑因素。

Libral API

在过去的十年里,Libral API 是在实现配置管理系统的经验下指导设计的,虽然它并没有直接绑定到它们其中任何一个应用上,但它考虑到了这些问题,并规避了它们的缺点。

在 API 设计中四个重要的原则:

  • 期望的状态
  • 双向性
  • 轻量级抽象
  • 易于扩展

基于期望状态的管理 API,举个例子来说,用户表示当操作执行后希望系统看起来是什么状态,而不是怎样进入这个状态,这一点什么争议。双向性使得使用(读、写)相同的 API 成为可能,更重要的是,相同的资源可以抽象成读取现有状态和强制修改成这种状态。轻量级抽象行为确保能容易的学习 API 并能快速的使用;过去在管理 API 上的尝试过度加重了学习建模框架的使用者的负担,其中一个重要的因素是他们的接受力缺乏。

最后,它必须易于扩展 Libral 的管理功能,这样用户可以教给 Libral 如何管理新类型的资源。这很重要,因为人们也许要管理的资源可能很多(而且 Libral 需要在适当时间进行管理),再者,因为即使是完全成熟的 Libral 也总是存在达不到用户自定义的管理需求。

目前与 Libral API 进行交互的主要方式是通过 ralsh 命令行工具。它也提供了底层的 C++ API ,不过其仍处在不断的演变当中,主要的还是为简单的脚本任务做准备。该项目也提供了为 CRuby 提供语言绑定,其它语言也在陆续跟进。

未来 Libral 还将提供一个提供远程 API 的守护进程,它可以做为管理系统的基础服务,而不需要在管理节点上安装额外的代理。这一点,加上对 Libral 管理功能的定制能力,可以严格控制系统的哪些方面可以管理,哪些方面要避免干扰。

举个例子来说,一个仅限于管理用户和服务的 Libral 配置会避免干扰到在节点上安装的包。当前任何现有的配置管理系统都不可能控制以这种方式管理的内容;尤其是,需要对受控节点进行任意的 SSH 访问也会将该系统暴露不必要的意外和恶意干扰。

Libral API 的基础是由两个非常简单的操作构成的:“get” 用来检索当前资源的状态,“set” 用来设置当前资源的状态。理想化地实现是这样的,通过以下步骤:

provider.get(names) -> List[resource]
provider.set(List[update]) -> List[change]

“provider” 是要知道怎样管理的一种资源的对象,就像用户、服务、软件包等等,Libral API 提供了一种查找特定资源的 管理器 provider 的方法。

“get” 操作能够接收资源名称列表(如用户名),然后产生一个资源列表,其本质来说是利用散列的方式列出每种资源的属性。这个列表必须包含所提供名称的资源,但是可以包含更多内容,因此一个简单的 “get” 的实现可以忽略名称并列出所有它知道的资源。

“set” 操作被用来设置所要求的状态,并接受一个更新列表。每个更新可以包含 “update.is”,其表示当前状态的资源,“update.should” 表示被资源所期望的状态。调用 “set” 方法将会让更新列表中所提到的资源成为 “update.should” 中指示的状态,并列出对每个资源所做的更改。

ralsh 下,利用 ralsh user root 能够重新获得 “root” 用户的当前状态;默认情况下,这个命令会产生一个用户可读的输出,就像 Puppet 中一样,但是 ralsh 支持 --json 选项,可以生成脚本可以使用的 JSON 输出。用户可读的输出是:

# ralsh user root
user::useradd { 'root':
  ensure  => 'present',
  comment => 'root',
  gid     => '0',
  groups  => ['root'],
  home    => '/root',
  shell   => '/bin/bash',
  uid     => '0',
}

类似的,用户也可以用下面的形式修改:

# ralsh user root comment='The superuser'
user::useradd { 'root':
  ensure  => 'present',
  comment => 'The superuser',
  gid     => '0',
  groups  => ['root'],
  home    => '/root',
  shell   => '/bin/bash',
  uid     => '0',
}
comment(root->The superuser)

ralsh 的输出列出了 “root” 用户的新状态和被改变的 comment 属性,以及修改了什么内容(在这种情形下单指 comment 属性)。下一秒运行相同的命令将产生同样的输出,但是不会提示修改,因为没有需要修改的内容。

编写 管理器 provider

ralsh 编写新的管理器(provider) 是很容易的,也花费不了多少工夫,但是这一步骤是至关重要的。正因为如此,ralsh 提供了大量的调用约定,使得可以根据管理器所能提供的能力而调整其实现复杂性成为可能。管理器可以使用遵循特定调用约定的外部脚本,也可以以 C++ 实现并内置到 Libral 里面。到目前为止,有三种调用约定:

  • simple 调用约定是编写 shell 脚本用为管理器。
  • JSON 调用约定意味着可以利用 Ruby 或者 Python 脚本语言编写管理器。
  • 内部 C++ API[8 可以被用来实现原生的管理器。

强烈建议使用 “simple” 或者 “JSON” 调用约定开始开发管理器。GitHub 上的 simple.prov 文件包含了一个简单的 shell 管理器框架,应该很容易的替换为你自己的管理器。python.prov 文件包含了利用 Python编写的 JSON 管理器框架。

利用高级脚本语言编写的管理器存在一个问题是,对于这些语言,在当前运行 Libral 的系统上需要包含所有的支持库在内运行环境。在某些情况下,这不是一个障碍;举例子来说,基于 “yum” 的包管理的管理器需要 Python 被安装在当前的系统上,因为 “yum” 就是用 Python 开发的。

然而在很多时候,无法预期一种 Bourne shell(Bash)之外的设计语言能够安装到所有的管理系统上。通常,管理器的编写者需要一个更加强大的脚本编译环境是实际需要。然而事与愿违,绑定一个完整的 Ruby 或 Python 作为解释器来运行将会增加 Libral 的大小超出了实际使用环境对资源的限制。另一方面,通常选择 Lua 或者 JavaScript 作为可嵌入的脚本编辑语言是不适应这种环境的,因为大多数的管理器的编写者不熟悉他们,通常情况下需要做大量的工作才能满足系统管理的实际需求。

Libral 绑定了一个 mruby 版本,一个小的、嵌入在 Ruby 的版本,提供给管理器的编写者一个稳定的基础以及功能强大的可实现的程序设计语言。mruby 是 Ruby 语言的一个完整实现,尽管其减少了大量的标准库支持。与 Libral 绑定的 mruby 包含了 Ruby 用于脚本编辑管理任务的大多数的重要标准库,其将基于管理器编写者的需求随着时间的推移得到加强。Libral 的 mruby 绑定了 API 适配器使编写管理器更适合 JSON 约定,比如它包含了简单的工具(如编译修改结构体文件的 Augeas)来解决解析和输出 JSON 的约定。mruby.prov 文件包含了利用 mruby 编写的 JSON 管理器框架实例。

下一步工作

Libral 最关键的是下一步要使其增加广泛的可用性——从 预编译的 tarball 对于开发管理器的起步和深入是一个不错的方法,但是 Libral 也需要打包到主流的发行版上,并在上面可以找到。同样的,Libral 强大的功能取决于它附带的管理器的集合,及需要被扩展覆盖一组核心管理功能。Libral 的网站上包含了一个 todo 列表列出了管理器的最迫切需求。

现在有多种方法能够提高不同用途的 Libral 的可用性:从编写更多程序语言的绑定,举例来说,Python 或者 Go;到使 ralsh 更容易在 shell 脚本中使用,除了现有的可读输出和 JSON 输出之外,可以很轻松的在 shell 脚本中格式化输出。在大规模的管理中使用 Libral 也能够在增加上面讨论过的远程 API 而得到改良,Libral 利用像 SSH 这样的传输工具实现更好的支持批量安装要求为各种架构提供预编译的 tarball,并且脚本基于所发现的目标系统架构选择正确的包。

Libral 和它的 API、它的性能能够不断地进化发展;一个有趣的可能性是为 API 增加提醒能力,这样做可以向系统报告资源在超出它的范围发生的变化。Libral 面临的挑战是保持小型化、轻量级和良好定义的工具,来对抗不断增加的用例和管理性能——我希望每一个读者都能成为这个挑战之旅的一部分。

如果这让你很好奇,我很想听听你的想法,可以用拉取请求的方式,也可以是增强请求方式,亦或者报告你对 ralsh 体验经验。

(题图:Internet Archive Book Images,修改:Opensource.com. CC BY-SA 4.0)


作者简介:

David Lutterkort - 戴维是一个 Puppet 的软件工程师,他曾经参与的项目有 Direct Puppet 和最好的供给工具 Razor。他是 Puppet 最早的编著者之一,也是配置编辑工具 Augeas 的主要作者。


via: https://opensource.com/article/17/5/intro-libral-systems-management-library-linux

作者:David Lutterkort 译者:stevenzdg988 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

这是一篇关于 Ansible 的速成课程,你可以用作小项目的模板,或者帮你深入了解这个神奇的工具。阅读了本指南之后,你将对自动化服务器配置、部署等有足够的了解。

Ansible 是什么,为什么你该了解?

Ansible 简单的说是一个 配置管理系统 configuration management system 。你只需要可以使用 ssh 访问你的服务器或设备就行。它也不同于其他工具,因为它使用推送的方式,而不是像 puppet 或 chef 那样使用拉取的方式。你可以将代码部署到任意数量的服务器上,配置网络设备或在基础架构中自动执行任何操作。

前置要求

假设你使用 Mac 或 Linux 作为你的工作站,Ubuntu Trusty 作为你的服务器,并有一些安装软件包的经验。此外,你的计算机上将需要以下软件。所以,如果你还没有它们,请先安装:

情景

我们将模拟 2 个连接到 MySQL 数据库的 Web 应用程序服务器。Web 应用程序使用 Rails 5 和 Puma。

准备

Vagrantfile

为这个项目创建一个文件夹,并将下面的内容保存到名为 Vagrantfile 的文件。

VMs = [
    [ "web1", "10.1.1.11"],
    [ "web2", "10.1.1.12"],
    [ "dbserver", "10.1.1.21"],
  ]

Vagrant.configure(2) do |config|
  VMs.each { |vm|
    config.vm.define vm[0] do |box|
      box.vm.box = "ubuntu/trusty64"
      box.vm.network "private_network", ip: vm[1]
      box.vm.hostname = vm[0]
      box.vm.provider "virtualbox" do |vb|
         vb.memory = "512"
      end
    end
  }
end

配置你的虚拟网络

我们希望我们的虚拟机能互相交互,但不要让流量流出到真实的网络,所以我们将在 Virtualbox 中创建一个仅主机(HOST-Only)的网络适配器。

  1. 打开 Virtualbox
  2. 转到 Preferences
  3. 转到 Network
  4. 单击 Host-Only
  5. 单击添加网络
  6. 单击 Adapter
  7. 将 IPv4 设置为 10.1.1.1,IPv4 网络掩码:255.255.255.0
  8. 单击 “OK”

测试虚拟机及虚拟网络

在终端中,在存放 Vagrantfile 的项目目录中,输入下面的命令:

vagrant up

它会创建你的虚拟机,因此会花费一会时间。输入下面的命令并验证输出内容以检查是否已经工作:

$ vagrant status
Current machine states:

web1                      running (virtualbox)
web2                      running (virtualbox)
master                    running (virtualbox)

This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.

现在使用 vagrant 的用户名和密码 ,按 Vagrantfile 中的 IP 登录其中一台虚拟机,这将验证虚拟机并将它们的密钥添加到你的已知主机(known_hosts)文件中。

ssh [email protected] # password is `vagrant`
ssh [email protected]
ssh [email protected]

恭喜你!现在你已经有可以实验的服务器了。下面的剩下的部分!

安装 Ansible

对于 Mac 用户:

$ brew install ansible

对于 Ubuntu 用户:

$ sudo apt install ansible

确保你使用了ansible 最近的版本 2.1 或者更高的版本:

$ ansible --version
ansible 2.1.1.0

清单

Ansible 使用清单文件来了解要使用的服务器,以及如何将它们分组以并行执行任务。让我们为这个项目创建我们的清单文件 inventory,并将它放在与 Vagrantfile 相同的文件夹中:

[all:children]
webs
db

[all:vars]
ansible_user=vagrant
ansible_ssh_pass=vagrant

[webs]
web1 ansible_host=10.1.1.11
web2 ansible_host=10.1.1.12

[db]
dbserver ansible_host=10.1.1.21
  • [all:children] 定义一个组的组(all
  • [all:vars] 定义属于组 all 的变量
  • [webs] 定义一个组,就像 [db] 一样
  • 文件的其余部分只是主机的声明,带有它们的名称和 IP
  • 空行表示声明结束

现在我们有了一个清单,我们可以从命令行开始使用 ansible,指定一个主机或一个组来执行命令。以下是检查与服务器的连接的命令示例:

$ ansible -i inventory all -m ping
  • -i 指定清单文件
  • all 指定要操作的服务器或服务器组
  • -m' 指定一个 ansible 模块,在这种情况下为ping`

下面是命令输出:

dbserver | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
web1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
web2 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

服务器以不同的顺序响应,这只取决于谁先响应,但是这个没有关系,因为 ansible 独立保持每台服务器的状态。

你也可以使用另外一个选项来运行任何命令:

  • -a <command>
$ ansible -i inventory all -a uptime
web1 | SUCCESS | rc=0 >>
 21:43:27 up 25 min,  1 user,  load average: 0.00, 0.01, 0.05

dbserver | SUCCESS | rc=0 >>
 21:43:27 up 24 min,  1 user,  load average: 0.00, 0.01, 0.05

web2 | SUCCESS | rc=0 >>
 21:43:27 up 25 min,  1 user,  load average: 0.00, 0.01, 0.05

这是只有一台服务器的另外一个例子:

$ ansible -i inventory dbserver -a "df -h /"
dbserver | SUCCESS | rc=0 >>
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        40G  1.4G   37G   4% /

剧本

剧本(playbook)只是个 YAML 文件,它将清单文件中的服务器组与命令关联。在 ansible 中的对于关键字是 tasks,它可以是一个预期的状态、shell 命令或许多其它的选项。有关 ansible 可做的所有事情列表,可以查看所有模块的列表

下面是一个运行 shell 命令的剧本示例,将其保存为 playbook1.yml

---
- hosts: all
  tasks:
    - shell: uptime
  • --- 是 YAML 文件的开始
  • - hosts:指定要使用的组
  • tasks:标记任务列表的开始
  • - shell:指定第一个任务使用 shell 模块
  • 记住:YAML 需要缩进结构,确保你始终遵循剧本中的正确结构

用下面的命令运行它:

$ ansible-playbook -i inventory playbook1.yml

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [web1]
ok: [web2]
ok: [dbmaster]

TASK [command] *****************************************************************
changed: [web1]
changed: [web2]
changed: [dbmaster]

PLAY RECAP *********************************************************************
dbmaster                   : ok=2    changed=1    unreachable=0    failed=0
web1                       : ok=2    changed=1    unreachable=0    failed=0
web2                       : ok=2    changed=1    unreachable=0    failed=0

正如你所见,ansible 运行了 2 个任务,而不是只有剧本中的一个。TASK [setup] 是一个隐式任务,它会首先运行以捕获服务器的信息,如主机名、IP、发行版和更多详细信息,然后可以使用这些信息运行条件任务。

还有最后的 PLAY RECAP,其中 ansible 显示了运行了多少个任务以及每个对应的状态。在我们的例子中,因为我们运行了一个 shell 命令,ansible 不知道结果的状态,它被认为是 changed

安装软件

我们将使用 apt 在我们的服务器上安装软件,因为我们需要 root 权限,所以我们必须使用 become 语句,将这个内容保存在 playbook2.yml 中并运行它(ansible-playbook playbook2.yml):

---
- hosts: webs
  become_user: root
  become: true
  tasks:
    - apt: name=git state=present

有一些语句可以应用于 ansible 中所有模块;一个是 name 语句,可以让我们输出关于正在执行的任务的更具描述性的文本。要使用它,保持任务内容一样,但是添加 name :描述性文本 作为第一行,所以我们以前的文本将改成:

---
- hosts: webs
  become_user: root
  become: true
  tasks:
    - name: This task will make sure git is present on the system
      apt: name=git state=present

使用 with_items

当你要处理一个列表时,比如要安装的项目和软件包、要创建的文件,可以用 ansible 提供的 with_items。下面是我们如何在 playbook3.yml 中使用它,同时添加一些我们已经知道的其他语句:

---
- hosts: all
  become_user: root
  become: true
  tasks:
    - name: Installing dependencies
      apt: name={{item}} state=present
      with_items:
        - git
        - mysql-client
        - libmysqlclient-dev
        - build-essential
        - python-software-properties

使用 templatevars

vars 是一个定义变量语句,可以在 task 语句或 template 文件中使用。 Jinja2 是 Ansible 中使用的模板引擎,但是关于它你不需要学习很多。在你的剧本中定义变量,如下所示:

---
- hosts: all
  vars:
    - secret_key: VqnzCLdCV9a3jK
    - path_to_vault: /opt/very/deep/path
  tasks:
    - name: Setting a configuration file using template
      template: src=myconfig.j2 dest={{path_to_vault}}/app.conf

正如你看到的,我可以使用 {{path_to_vault}} 作为剧本的一部分,但也因为我使用了 template语句,我可以使用 myconfig.j2 中的任何变量,该文件必须存在一个名为 templates 的子文件夹中。你项目树应该如下所示:

├── Vagrantfile
├── inventory
├── playbook1.yml
├── playbook2.yml
└── templates
    └── myconfig.j2

当 ansible 找到一个 template 语句后它会在 templates 文件夹内查找,并将把被 {{}} 括起来的变量展开来。

示例模板:

this is just an example vault_dir: {{path_to_vault}} secret_password: {{secret_key}}

即使你不扩展变量你也可以使用 template。考虑到将来会添加所以我先做了。比如创建一个 hosts.j2 模板并加入主机名和 IP。

10.1.1.11 web1
10.1.1.12 web2
10.1.1.21 dbserver

这里要用像这样的语句:

  -  name: Installing the hosts file in all servers
     template: src=hosts.j2 dest=/etc/hosts mode=644

shell 命令

你应该尽量使用模块,因为 Ansible 可以跟踪任务的状态,并避免不必要的重复,但有时 shell 命令是不可避免的。 对于这些情况,Ansible 提供两个选项:

  • command:直接运行一个命令,没有环境变量或重定向(|<> 等)
  • shell:运行 /bin/sh 并展开变量和支持重定向

其他有用的模块

  • apt\_repository - 在 Debian 系的发行版中添加/删除包仓库
  • yum\_repository - 在 RedHat 系的发行版中添加/删除包仓库
  • service - 启动/停止/重新启动/启用/禁用服务
  • git - 从 git 服务器部署代码
  • unarchive - 从 Web 或本地源解开软件包

只在一台服务器中运行任务

Rails 使用 migrations 来逐步更改数据库,但由于你有多个应用程序服务器,因此这些迁移任务不能被分配为组任务,而我们只需要一个服务器来运行迁移。在这种情况下,当使用 run_once 时,run_once 将分派任务到一个服务器,并直到这个任务完成继续下一个任务。你只需要在你的任务中设置 run_once:true

    - name: 'Run db:migrate'
      shell: cd {{appdir}};rails db:migrate
      run_once: true

会失败的任务

通过指定 ignore_errors:true,你可以运行可能会失败的任务,但不会影响剧本中剩余的任务完成。这是非常有用的,例如,当删除最初并不存在的日志文件时。

    - name: 'Delete logs'
      shell: rm -f /var/log/nginx/errors.log
      ignore_errors: true

放到一起

现在用我们先前学到的,这里是每个文件的最终版:

Vagrantfile

VMs = [
    [ "web1", "10.1.1.11"],
    [ "web2", "10.1.1.12"],
    [ "dbserver", "10.1.1.21"],
  ]

Vagrant.configure(2) do |config|
  VMs.each { |vm|
    config.vm.define vm[0] do |box|
      box.vm.box = "ubuntu/trusty64"
      box.vm.network "private_network", ip: vm[1]
      box.vm.hostname = vm[0]
      box.vm.provider "virtualbox" do |vb|
         vb.memory = "512"
      end
    end
  }
end

inventory

[all:children]
webs
db

[all:vars]
ansible_user=vagrant
ansible_ssh_pass=vagrant

[webs]
web1 ansible_host=10.1.1.11
web2 ansible_host=10.1.1.12

[db]
dbserver ansible_host=10.1.1.21

templates/hosts.j2:

10.1.1.11 web1
10.1.1.12 web2
10.1.1.21 dbserver

templates/my.cnf.j2

[client]
port        = 3306
socket      = /var/run/mysqld/mysqld.sock

[mysqld_safe]
socket      = /var/run/mysqld/mysqld.sock
nice        = 0

[mysqld]
server-id   = 1
user        = mysql
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
port        = 3306
basedir     = /usr
datadir     = /var/lib/mysql
tmpdir      = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
bind-address        = 0.0.0.0
key_buffer      = 16M
max_allowed_packet  = 16M
thread_stack        = 192K
thread_cache_size       = 8
myisam-recover         = BACKUP
query_cache_limit   = 1M
query_cache_size        = 16M
log_error = /var/log/mysql/error.log
expire_logs_days    = 10
max_binlog_size         = 100M

[mysqldump]
quick
quote-names
max_allowed_packet  = 16M

[mysql]

[isamchk]
key_buffer      = 16M

!includedir /etc/mysql/conf.d/

final-playbook.yml

- hosts: all
  become_user: root
  become: true
  tasks:
    - name: 'Install common software on all servers'
      apt: name={{item}} state=present
      with_items:
        - git
        - mysql-client
        - libmysqlclient-dev
        - build-essential
        - python-software-properties
    - name: 'Install hosts file'
      template: src=hosts.j2 dest=/etc/hosts mode=644

- hosts: db
  become_user: root
  become: true
  tasks:
    - name: 'Software for DB server'
      apt: name={{item}} state=present
      with_items:
        - mysql-server
        - percona-xtrabackup
        - mytop
        - mysql-utilities
    - name: 'MySQL config file'
      template: src=my.cnf.j2 dest=/etc/mysql/my.cnf
    - name: 'Restart MySQL'
      service: name=mysql state=restarted
    - name: 'Grant access to web app servers'
      shell: echo 'GRANT ALL PRIVILEGES ON *.* TO "root"@"%" WITH GRANT OPTION;FLUSH PRIVILEGES;'|mysql -u root mysql

- hosts: webs
  vars:
    - appdir: /opt/dummyapp
  become_user: root
  become: true
  tasks:
    - name: 'Add ruby-ng repo'
      apt_repository: repo='ppa:brightbox/ruby-ng'
    - name: 'Install rails software'
      apt: name={{item}} state=present
      with_items:
        - ruby-dev
        - ruby-all-dev
        - ruby2.2
        - ruby2.2-dev
        - ruby-switch
        - libcurl4-openssl-dev
        - libssl-dev
        - zlib1g-dev
        - nodejs
    - name: 'Set ruby to 2.2'
      shell: ruby-switch --set ruby2.2
    - name: 'Install gems'
      shell: gem install bundler rails
    - name: 'Kill puma if running'
      shell: file /run/puma.pid >/dev/null && kill `cat /run/puma.pid` 2>/dev/null
      ignore_errors: True
    - name: 'Clone app repo'
      git:
           repo=https://github.com/c0d5x/rails_dummyapp.git
           dest={{appdir}}
           version=staging
           force=yes
    - name: 'Run bundler'
      shell: cd {{appdir}};bundler
    - name: 'Run db:setup'
      shell: cd {{appdir}};rails db:setup
      run_once: true
    - name: 'Run db:migrate'
      shell: cd {{appdir}};rails db:migrate
      run_once: true
    - name: 'Run rails server'
      shell: cd {{appdir}};rails server -b 0.0.0.0 -p 80 --pid /run/puma.pid -d

放在你的环境中

将这些文件放在相同的目录,运行下面的命令打开你的开发环境:

vagrant up
ansible-playbook -i inventory final-playbook.yml

部署新的代码

确保修改了代码并推送到了仓库中。接下来,确保你 git 语句中使用了正确的分支:

    - name: 'Clone app repo'
      git:
           repo=https://github.com/c0d5x/rails_dummyapp.git
           dest={{appdir}}
           version=staging
           force=yes

作为一个例子,你可以修改 version 字段为 master,再次运行剧本:

ansible-playbook -i inventory final-playbook.yml

检查所有的 web 服务器上的页面是否已更改:http://10.1.1.11http://10.1.1.12。将其更改为 version = staging 并重新运行剧本并再次检查页面。

你还可以创建只包含与部署相关的任务的替代剧本,以便其运行更快。

接下来是什么 ?!

这只是可以做的很小一部分。我们没有接触 角色 role 过滤器 filter 、调试等许多其他很棒的功能,但我希望它给了你一个良好的开始!所以,请继续学习并使用它。如果你有任何问题,你可以在 twitter 或评论栏联系我,让我知道你还想知道哪些关于 ansible 的东西!


via: https://gorillalogic.com/blog/getting-started-with-ansible/?utm_source=webopsweekly&utm_medium=email

作者:JOSE HIDALGO 译者:geekpi 校对:wxy

本文由 LCTT 组织编译,Linux中国 荣誉推出

Ansible 是一款系统管理员进行自动化运维的强大工具。Ansible 让配置、交付、管理各种容器、软件部署变得非常简单。基于轻量级模块的架构非常适合系统管理,一个优点就是如果某个节点没有被 Ansible 管理的话,它的资源就不会被使用。

这篇文章介绍用 Ansible 来配置 Vagrant 实例,它是一个配置好的基础虚拟机映像,包含了开发环境中需要用到的工具。你可以用它来部署开发环境,然后和其他成员协同工作。用 Ansible,你可以用你的开发包自动化交付 Vagrant 实例。

我们用 Fedora 24 做主机,用 CentOS 7 来作 Vagrant 实例。

设置工作环境

在用 Ansible 配置 Vagrant 实例时,你需要做几件准备的事情。首先在宿主机上安装 Ansible 和 Vagrant,在你的主机上运行下面的命令来安装:

sudo dnf install ansible vagrant vagrant-libvirt

上面的命令将 Ansible 和 Vagrant 在你的宿主机上,以及包括 Vagrant 的 libvirt 接口。Vagrant 并没有提供托管你的虚拟机的功能,它需要第三方工具比如:libirt、VirtualBox、VMWare 等等。这些工具可以直接与你的 Fedora 系统上的 libvirt 和 KVM 协同工作。

接着确认你的账户在正确的 wheel 用户组当中,确保你可以运行系统管理员命令。如果你的账号在安装过程中就创建为管理员,那么你就肯定在这个用户组里。运行下面的命令查看:

id | grep wheel

如果你能看到输出,那么你的账户就在这个组里,可以进行下一步。如果没有的话,你需要运行下面的命令,这一步需要你提供 root 账户的密码,将 换成你的用户名:

su -c 'usermod -a -G wheel <username>'

然后,你需要注销然后重新登录,确保在用户组里。

现在要建立你的第一个 Vagrant 实例了,你需要用 Ansible 来配置它。

设置 Vagrant 实例

配置一个镜像实例之前,你需要先创建它。创建一个目录,存放 Vagrant 实例相关的文件,并且将它作为当前工作目录,用下面这条命令:

mkdir -p ~/lampbox && cd ~/lampbox

在创建镜像实例之前,你需要搞清楚目的,这个镜像实例是一个运行 CentOS 7 基础系统,模板包括 Apache 的 Web 服务,MariaDB(MySQL 原开发者创建的一个流行的开源数据库)数据库和 PHP 服务。

初始化 Vagrant 实例,用 vagrant init 命令:

vagrant init centos/7

这个命令初始化 Vagrant 实例,并创建一个名为 Vagrantfile 的文件,包含一些预先配置的变量。打开并编辑它,下面的命令显示了用于这次配置的基本镜像实例。

config.vm.box = "centos/7"

现在设置端口转发,以便你配置完毕 Vagrant 实例并让它运行起来之后可以测试它。将下述配置加入到 Vagrantfile 的最终的 end 语句之前:

config.vm.network "forwarded_port", guest: 80, host: 8080

这个命令将 Vagrant 实例 的 80 端口映射为主机的 8080 端口。

下一步是设置 Ansible 作为配置 Vagrant 实例的工具,将下述配置加入到 Vagrantfile 最终的 end 语句之前,将 Ansible 作为 配置工具 provisioning provider

config.vm.provision :ansible do |ansible|
  ansible.playbook = "lamp.yml"
end

(必须将这三行在最后的 end 语句之前加入)注意 ansible.playbook = "lamp.yml" 这一句定义了配置镜像实例的 Ansible playbook 的名字。

创建 Ansible playbook

在 Ansible 之中,playbook 是指在你的远端节点执行的策略,换句话说,它管理远端节点的配置和部署。详细的说,playbook 是一个 Yaml 文件,在里面写入你要在远端节点上将要执行的任务。所以,你需要创建一个名为 lamp.yml 的 playbook 来配置镜像实例。

在 Vagrantfile 相同的目录里创建一个 lamp.yml 文件,将下面的内容粘贴到文件当中:

---
- hosts: all
  become: yes
  become_user: root
  tasks:
  - name: Install Apache
    yum: name=httpd state=latest
  - name: Install MariaDB
    yum: name=mariadb-server state=latest
  - name: Install PHP5
    yum: name=php state=latest
  - name: Start the Apache server
    service: name=httpd state=started
  - name: Install firewalld
    yum: name=firewalld state=latest
  - name: Start firewalld
    service: name=firewalld state=started
  - name: Open firewall
    command: firewall-cmd --add-service=http --permanent

每一行代表的意思:

  • hosts: all 指定该 playbook 需要在 Ansible 配置文件中定义的所有主机上都执行,因为还没定义主机, playbook 将只在本地运行。
  • sudo: true 表明该任务需要用 root 权限运行。(LCTT 译注:此语句上述配置中缺失。)
  • tasks: 指定当 playbook 运行是需要执行的任务,在这一节之下:

    • name: ... 描述任务的名字
    • yum: ... 描述该任务应该由 yum 模块执行,可选的 key=value 键值对将由 yum 模块所使用。

当 playbook 运行时,它会安装最新的 Apache Web 服务(http),MariaDB 和 PHP。当安装完毕并启动防火墙 firewalld,给 Apache 打开一个端口。你可以通过编写 playbook 来完成这些。现在可以配置它了。

配置镜像 实例

用 Ansible 配置 Vagrant 实例只需要以下几步了:

vagrant up --provider libvirt

上面的命令运行 Vagrant 实例,将实例的基础镜像下载到宿主机当中(如果还没下载的话),然后运行 lamp.yml 来进行配置。

如果一切正常,输出应该和下面的例子类似:

这个输出显示镜像实例已经被配置好了,现在检查服务是否可用,在宿主机上打开浏览器,输入 http://localhost:8080,记住本地主机的 8080 端口是 Vagrant 实例映射过来的 80 端口。你应该可以看到如下的 Apache 的欢迎界面。

要修改你的 Vagrant 实例,你可以修改 lamp.yml,你能从 Ansible 的官网上找到很多文章。然后运行下面的命令来重新配置:

vagrant provision

总结

现在我们知道怎么用 Ansible 来配置 Vagrant 实例了。这只是一个基本的例子,但是你可以用这些工具来实现不同的例子。比如你可以用所需工具的最新版本来部署一个完整的应用。现在你可以用 Ansible 来配置你自己的远端服务器和容器了。


via: https://fedoramagazine.org/using-ansible-provision-vagrant-boxes/

作者:Saurabh Badhwar 译者:jiajia9linuxer 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在生产环境中,我会更喜欢做与自动化相关的所有事情。如果计算机能完成你的任务,何必需要你亲自动手呢?但是,在不断变化并存在多种技术的环境中,创建和实施自动化是一项艰巨的任务。这就是为什么我喜欢 Ansible 的原因。Ansible 是一个用于 IT 配置管理,部署和业务流程的开源工具,使用起来非常方便。

我最喜欢 Ansible 的一个特点是,它是完全无客户端的。要管理一个系统,通过 SSH 建立连接,它使用Paramiko(一个 Python 库)或本地的 OpenSSH。Ansible 另一个吸引人的地方是它有许多可扩展的模块。这些模块可被系统管理员用于执行一些的常见任务。特别是,它们使用 Ansible 这个强有力的工具可以跨多个服务器、环境或操作系统安装和配置任何程序,只需要一个控制节点。

在本教程中,我将带你使用 Ansible 完成安装和部署开源 NGINX 和我们的商业产品 NGINX Plus。我将在 CentOS 服务器上演示,但我也在下面的“在 Ubuntu 上创建 Ansible Playbook 来安装 NGINX 和 NGINX Plus”小节中包含了在 Ubuntu 服务器上部署的细节。

在本教程中我将使用 Ansible 1.9.2 版本,并在 CentOS 7.1 服务器上部署运行。

$ ansible --version
ansible 1.9.2

$ cat /etc/redhat-release
CentOS Linux release 7.1.1503 (Core)

如果你还没有 Ansible,可以在 Ansible 网站 查看说明并安装它。

如果你使用的是 CentOS,安装 Ansible 十分简单,只要输入以下命令。如果你想使用源码编译安装或使用其他发行版,请参阅上面 Ansible 链接中的说明。

$ sudo yum install -y epel-release && sudo yum install -y ansible

根据环境的不同,在本教程中的命令有的可能需要 sudo 权限。文件路径,用户名和目标服务器取决于你的环境的情况。

创建一个 Ansible Playbook 来安装 NGINX (CentOS)

首先,我们要为 NGINX 的部署创建一个工作目录,包括子目录和部署配置文件。我通常建议在你的主目录中创建该目录,在文章的所有例子中都会有说明。

$ cd $HOME
$ mkdir -p ansible-nginx/tasks/
$ touch ansible-nginx/deploy.yml
$ touch ansible-nginx/tasks/install_nginx.yml

目录结构看起来是这样的。你可以使用 tree 命令来查看。

$ tree $HOME/ansible-nginx/
/home/kjones/ansible-nginx/
├── deploy.yml
└── tasks
    └── install_nginx.yml

1 directory, 2 files

如果你没有安装 tree 命令,使用以下命令去安装。

$ sudo yum install -y tree

创建主部署文件

接下来,我们在文本编辑器中打开 deploy.yml。我喜欢在命令行上使用 vim 来编辑配置文件,在整个教程中也都将使用它。

$ vim $HOME/ansible-nginx/deploy.yml

deploy.yml 文件是 Ansible 部署的主要文件,在“使用 Ansible 部署 NGINX”小节中,我们运行 ansible‑playbook 命令时会使用此文件。在这个文件中,我们指定 Ansible 运行时使用的库以及其它配置文件。

在这个例子中,我使用 include 模块来指定配置文件一步一步来安装NGINX。虽然可以创建一个非常大的 playbook 文件,我建议你将其分割为小文件,让它们更有条理。include 的示例中可以复制静态内容,复制配置文件,为更高级的部署使用逻辑配置设定变量。

在文件中输入以下行。我在顶部的注释包含了文件名用于参考。

# ./ansible-nginx/deploy.yml

- hosts: nginx
  tasks:
    - include: 'tasks/install_nginx.yml'

hosts 语句说明 Ansible 部署 nginx 组的所有服务器,服务器在 /etc/ansible/hosts 中指定。我们会在下面的“创建 NGINX 服务器列表”小节编辑此文件。

include 语句说明 Ansible 在部署过程中从 tasks 目录下读取并执行 install\_nginx.yml 文件中的内容。该文件包括以下几步:下载,安装,并启动 NGINX。我们将在下一节创建此文件。

为 NGINX 创建部署文件

现在,先保存 deploy.yml 文件,并在编辑器中打开 install\_nginx.yml

$ vim $HOME/ansible-nginx/tasks/install_nginx.yml

该文件包含有指令(使用 YAML 格式写的), Ansible 会按照指令安装和配置我们的 NGINX 部署过程。每个节(过程中的步骤)起始于一个描述此步骤的 name 语句(前面有连字符)。 name 后的字符串是 Ansible 部署过程中输出到标准输出的,可以根据你的意愿来修改。YAML 文件中的节的下一行是在部署过程中将使用的模块。在下面的配置中,使用了 yumservice 模块。yum 模块用于在 CentOS 上安装软件包。service 模块用于管理 UNIX 的服务。在这个节的最后一行或几行指定了几个模块的参数(在本例中,这些行以 namestate 开始)。

在文件中输入以下行。就像 deploy.yml,在我们文件的第一行是用于参考的文件名的注释。第一个节告诉 Ansible 在CentOS 7 上从 NGINX 仓库安装该 .rpm 文件。这让软件包管理器直接从 NGINX 仓库安装最新最稳定的版本。根据你的 CentOS 版本修改路径。所有可用的包的列表可以在 开源 NGINX 网站 上找到。接下来的两节告诉 Ansible 使用 yum 模块安装最新的 NGINX 版本,然后使用 service 模块启动 NGINX。

注意: 在第一个节中,CentOS 包中的路径名可能由于宽度显示为连着的两行。请在一行上输入其完整路径。

# ./ansible-nginx/tasks/install_nginx.yml

- name: NGINX | Installing NGINX repo rpm
  yum:
    name: http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

- name: NGINX | Installing NGINX
  yum:
    name: nginx
    state: latest

- name: NGINX | Starting NGINX
  service:
    name: nginx
    state: started

创建 NGINX 服务器列表

现在,我们设置好了 Ansible 部署的所有配置文件,我们需要告诉 Ansible 部署哪个服务器。我们需要在 Ansible 中指定 hosts 文件。先备份现有的文件,并新建一个新文件来部署。

$ sudo mv /etc/ansible/hosts /etc/ansible/hosts.backup
$ sudo vim /etc/ansible/hosts

在文件中输入(或编辑)以下行来创建一个名为 nginx 的组并列出安装 NGINX 的服务器。你可以通过主机名、IP 地址、或者在一个范围,例如 server[1-3].domain.com 来指定服务器。在这里,我通过 IP 地址指定一台服务器。

# /etc/ansible/hosts

[nginx]
172.16.239.140

设置安全性

接近完成了,但在部署之前,我们需要确保 Ansible 已被授权通过 SSH 访问我们的目标服务器。

首选并且最安全的方法是添加 Ansible 所要部署服务器的 RSA SSH 密钥到目标服务器的 authorized\_keys 文件中,这给予 Ansible 在目标服务器上的不受限制 SSH 权限。要了解更多关于此配置,请参阅 wiki.centos.org 上 安全加固 OpenSSH。这样,你就可以自动部署而无需用户交互。

另外,你也可以在部署过程中要求输入密码。我强烈建议你只在测试过程中使用这种方法,因为它是不安全的,没有办法跟踪目标主机的身份(fingerprint)变化。如果你想这样做,将每个目标主机 /etc/ssh/ssh\_config 文件中 StrictHostKeyChecking 的默认值 yes 改为 no。然后在 ansible-playbook 命令中添加 --ask-pass 参数来让 Ansible 提示输入 SSH 密码。

在这里,我将举例说明如何编辑 ssh\_config 文件来禁用在目标服务器上严格的主机密钥检查。我们手动连接 SSH 到我们将部署 NGINX 的服务器,并将 StrictHostKeyChecking 的值更改为 no。

$ ssh [email protected]
[email protected]'s password:***********

[kjones@nginx ]$ sudo vim /etc/ssh/ssh_config

当你更改后,保存 ssh\_config,并通过 SSH 连接到你的 Ansible 服务器。保存后的设置应该如下所示。

# /etc/ssh/ssh_config

StrictHostKeyChecking no

运行 Ansible 部署 NGINX

如果你一直照本教程的步骤来做,你可以运行下面的命令来使用 Ansible 部署 NGINX。(再次提示,如果你设置了 RSA SSH 密钥认证,那么 --ask-pass 参数是不需要的。)在 Ansible 服务器运行命令,并使用我们上面创建的配置文件。

$ sudo ansible-playbook --ask-pass $HOME/ansible-nginx/deploy.yml

Ansible 提示输入 SSH 密码,输出如下。recap 中显示 failed=0 这条信息,意味着部署成功了。

$ sudo ansible-playbook --ask-pass $HOME/ansible-nginx/deploy.yml
SSH password:

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [172.16.239.140]

TASK: [NGINX | Installing NGINX repo rpm] *************************************
changed: [172.16.239.140]

TASK: [NGINX | Installing NGINX] **********************************************
changed: [172.16.239.140]

TASK: [NGINX | Starting NGINX] ************************************************
changed: [172.16.239.140]

PLAY RECAP ********************************************************************
172.16.239.140             : ok=4    changed=3    unreachable=0    failed=0

如果你没有得到一个成功的 play recap,你可以尝试用 -vvvv 参数(带连接调试的详细信息)再次运行 ansible-playbook 命令来解决部署过程的问题。

当部署成功(假如我们是第一次部署)后,你可以在远程服务器上运行基本的 cURL 命令验证 NGINX 。在这里,它会返回 200 OK。Yes!我们使用 Ansible 成功安装了 NGINX。

$ curl -Is 172.16.239.140 | grep HTTP
HTTP/1.1 200 OK

创建 Ansible Playbook 来安装 NGINX Plus (CentOS)

现在,我已经展示了如何安装 NGINX 的开源版本,我将带你完成安装 NGINX Plus。这需要更改一些额外的部署配置,并展示了一些 Ansible 的其他功能。

复制 NGINX Plus 上的证书和密钥到 Ansible 服务器

使用 Ansible 安装和配置 NGINX Plus 时,首先我们需要将 NGINX Plus Customer Portal NGINX Plus 订阅的密钥和证书复制到 Ansible 部署服务器上的标准位置。

购买了 NGINX Plus 或正在试用的客户也可以访问 NGINX Plus Customer Portal。如果你有兴趣测试 NGINX Plus,你可以申请免费试用30天,点击这里。在你注册后不久你将收到一个试用证书和密钥的链接。

在 Mac 或 Linux 主机上,我在这里使用 scp 工具演示。在 Microsoft Windows 主机,可以使用 WinSCP。在本教程中,先下载文件到我的 Mac 笔记本电脑上,然后使用 scp 将其复制到 Ansible 服务器。密钥和证书的位置都在我的家目录下。

$ cd /path/to/nginx-repo-files/
$ scp nginx-repo.* user@destination-server:.

接下来,我们通过 SSH 连接到 Ansible 服务器,确保 NGINX Plus 的 SSL 目录存在,移动文件到这儿。

$ ssh user@destination-server
$ sudo mkdir -p /etc/ssl/nginx/
$ sudo mv nginx-repo.* /etc/ssl/nginx/

验证你的 /etc/ssl/nginx 目录包含了证书(.crt)和密钥(.key)文件。你可以使用 tree 命令检查。

$ tree /etc/ssl/nginx
/etc/ssl/nginx
├── nginx-repo.crt
└── nginx-repo.key

0 directories, 2 files

如果你没有安装 tree,可以使用下面的命令去安装。

$ sudo yum install -y tree

创建 Ansible 目录结构

以下执行的步骤和我们的“创建 Ansible Playbook 来安装 NGINX(CentOS)”小节中部署开源 NGINX 的非常相似。首先,我们建一个工作目录用于部署 NGINX Plus 使用。我喜欢将它创建为我主目录的子目录。

$ cd $HOME
$ mkdir -p ansible-nginx-plus/tasks/
$ touch ansible-nginx-plus/deploy.yml
$ touch ansible-nginx-plus/tasks/install_nginx_plus.yml

目录结构看起来像这样。

$ tree $HOME/ansible-nginx-plus/
/home/kjones/ansible-nginx-plus/
├── deploy.yml
└── tasks
└── install_nginx_plus.yml

1 directory, 2 files

创建主部署文件

接下来,像开源的 NGINX 一样,我们使用 vim 创建 deploy.yml 文件。

$ vim ansible-nginx-plus/deploy.yml

和开源 NGINX 的部署唯一的区别是,我们将包含文件的名称修改为 install\_nginx\_plus.yml。该文件告诉 Ansible 在 nginx 组中的所有服务器(/etc/ansible/hosts 中定义的)上部署 NGINX Plus ,然后在部署过程中从 tasks 目录读取并执行 install\_nginx\_plus.yml 的内容。

# ./ansible-nginx-plus/deploy.yml

- hosts: nginx
  tasks:
    - include: 'tasks/install_nginx_plus.yml'

如果你之前没有安装过的话,你需要创建 hosts 文件,详细说明在上面的“创建 NGINX 服务器的列表”小节。

为 NGINX Plus 创建部署文件

在文本编辑器中打开 install\_nginx\_plus.yml。该文件包含了使用 Ansible 来安装和配置 NGINX Plus 部署过程中的指令。这些命令和模块仅针对 CentOS,有些是 NGINX Plus 独有的。

$ vim ansible-nginx-plus/tasks/install_nginx_plus.yml

第一节使用 file 模块,告诉 Ansible 使用指定的pathstate参数为 NGINX Plus 创建特定的 SSL 目录,设置属主为 root,将权限 mode 更改为0700。

# ./ansible-nginx-plus/tasks/install_nginx_plus.yml

- name: NGINX Plus | 创建 NGINX Plus ssl 证书目录
  file: path=/etc/ssl/nginx state=directory group=root mode=0700

接下来的两节使用 copy 模块从 Ansible 部署服务器上将 NGINX Plus 的证书和密钥复制到 NGINX Plus 服务器上,再修改属主为 root,权限 mode 为0700。

- name: NGINX Plus | 复制 NGINX Plus repo 证书 
  copy: src=/etc/ssl/nginx/nginx-repo.crt dest=/etc/ssl/nginx/nginx-repo.crt owner=root group=root mode=0700

- name: NGINX Plus | 复制 NGINX Plus 密钥
  copy: src=/etc/ssl/nginx/nginx-repo.key dest=/etc/ssl/nginx/nginx-repo.key owner=root group=root mode=0700

接下来,我们告诉 Ansible 使用 get_url 模块在 url 参数指定的远程位置从 NGINX Plus 仓库下载 CA 证书,通过 dest 参数把它放在指定的目录 dest ,并设置权限 mode 为 0700。

- name: NGINX Plus | 下载 NGINX Plus CA 证书
  get_url: url=https://cs.nginx.com/static/files/CA.crt dest=/etc/ssl/nginx/CA.crt mode=0700

同样,我们告诉 Ansible 使用 get_url 模块下载 NGINX Plus repo 文件,并将其复制到 NGINX Plus 服务器上的 /etc/yum.repos.d 目录下。

- name: NGINX Plus | 下载 yum NGINX Plus 仓库
  get_url: url=https://cs.nginx.com/static/files/nginx-plus-7.repo dest=/etc/yum.repos.d/nginx-plus-7.repo mode=0700

最后两节的 name 告诉 Ansible 使用 yumservice 模块下载并启动 NGINX Plus。

- name: NGINX Plus | 安装 NGINX Plus
  yum:
    name: nginx-plus
    state: latest

- name: NGINX Plus | 启动 NGINX Plus
  service:
    name: nginx
    state: started

运行 Ansible 来部署 NGINX Plus

在保存 install\_nginx\_plus.yml 文件后,运行 ansible-playbook 命令来部署 NGINX Plus。同样在这里,我们使用 --ask-pass 参数使用 Ansible 提示输入 SSH 密码并把它传递给每个 NGINX Plus 服务器,并指定主配置文件路径 deploy.yml 文件。

$ sudo ansible-playbook --ask-pass $HOME/ansible-nginx-plus/deploy.yml

PLAY [nginx] ******************************************************************

GATHERING FACTS ***************************************************************
ok: [172.16.239.140]

TASK: [NGINX Plus | Creating NGINX Plus ssl cert repo directory] **************
changed: [172.16.239.140]

TASK: [NGINX Plus | Copying NGINX Plus repository certificate] ****************
changed: [172.16.239.140]

TASK: [NGINX Plus | Copying NGINX Plus repository key] ************************
changed: [172.16.239.140]

TASK: [NGINX Plus | Downloading NGINX Plus CA certificate] ********************
changed: [172.16.239.140]

TASK: [NGINX Plus | Downloading yum NGINX Plus repository] ********************
changed: [172.16.239.140]

TASK: [NGINX Plus | Installing NGINX Plus] ************************************
changed: [172.16.239.140]

TASK: [NGINX Plus | Starting NGINX Plus] **************************************
changed: [172.16.239.140]

PLAY RECAP ********************************************************************
172.16.239.140             : ok=8    changed=7    unreachable=0    failed=0

playbook 的 recap 成功完成。现在,使用 curl 命令来验证 NGINX Plus 是否在运行。太好了,我们得到的是 200 OK!成功了!我们使用 Ansible 成功地安装了 NGINX Plus。

$ curl -Is http://172.16.239.140 | grep HTTP
HTTP/1.1 200 OK

在 Ubuntu 上创建 Ansible Playbook 来安装 NGINX 和 NGINX Plus

Ubuntu 服务器 上部署 NGINX 和 NGINX Plus 的过程与 CentOS 很相似,我将一步一步的指导来完成整个部署文件,并指出和 CentOS 的细微差异。

首先和 CentOS 一样,创建 Ansible 目录结构和 Ansible 主部署文件。也按“创建 NGINX 服务器的列表”小节的描述创建 /etc/ansible/hosts 文件。对于 NGINX Plus,你也需要安装“复制 NGINX Plus 证书和密钥到 Ansible 服务器”小节的描述复制证书和密钥。

下面是开源 NGINX 的 install\_nginx.yml 部署文件。在第一节,我们使用 apt_key 模块导入 NGINX 的签名密钥。接下来的两节使用 lineinfile 模块来添加 Ubuntu 14.04 的软件包 URL 到 sources.list 文件中。最后,我们使用 apt 模块来更新缓存并安装 NGINX(apt 取代了我们在 CentOS 中部署时的 yum 模块)。

# ./ansible-nginx/tasks/install_nginx.yml

- name: NGINX | 添加 NGINX 签名密钥
  apt_key: url=http://nginx.org/keys/nginx_signing.key state=present

- name: NGINX | 为 NGINX 添加 sources.list deb url  
  lineinfile: dest=/etc/apt/sources.list line="deb http://nginx.org/packages/mainline/ubuntu/ trusty nginx"

- name: NGINX Plus | 为 NGINX 添加 sources.list deb-src url  
  lineinfile: dest=/etc/apt/sources.list line="deb-src http://nginx.org/packages/mainline/ubuntu/ trusty nginx"

- name: NGINX | 更新 apt 缓存
  apt:
    update_cache: yes

- name: NGINX | 安装 NGINX
  apt:
    pkg: nginx
    state: latest

- name: NGINX | 启动 NGINX
  service:
    name: nginx
    state: started

下面是 NGINX Plus 的部署文件 install\_nginx.yml。前四节设置了 NGINX Plus 密钥和证书。然后,我们像开源的 NGINX 一样用 apt_key 模块导入签名密钥,get_url 模块为 NGINX Plus 下载 apt 配置文件。shell 模块使用 printf 命令写下输出到 sources.list.d 目录中的 nginx-plus.list 文件。最终的 name 模块和开源 NGINX 一样。

# ./ansible-nginx-plus/tasks/install_nginx_plus.yml

- name: NGINX Plus | 创建 NGINX Plus ssl 证书 repo 目录
  file: path=/etc/ssl/nginx state=directory group=root mode=0700

- name: NGINX Plus | 复制 NGINX Plus 仓库证书
  copy: src=/etc/ssl/nginx/nginx-repo.crt dest=/etc/ssl/nginx/nginx-repo.crt owner=root group=root mode=0700

- name: NGINX Plus | 复制 NGINX Plus 仓库密钥
  copy: src=/etc/ssl/nginx/nginx-repo.key dest=/etc/ssl/nginx/nginx-repo.key owner=root group=root mode=0700

- name: NGINX Plus | 安装 NGINX Plus CA 证书
  get_url: url=https://cs.nginx.com/static/files/CA.crt dest=/etc/ssl/nginx/CA.crt mode=0700

- name: NGINX Plus | 添加 NGINX Plus 签名密钥
  apt_key: url=http://nginx.org/keys/nginx_signing.key state=present

- name: NGINX Plus | 安装 Apt-Get NGINX Plus 仓库
  get_url: url=https://cs.nginx.com/static/files/90nginx dest=/etc/apt/apt.conf.d/90nginx mode=0700

- name: NGINX Plus | 为 NGINX Plus 添加 sources.list url  
  shell: printf "deb https://plus-pkgs.nginx.com/ubuntu `lsb_release -cs` nginx-plus\n" >/etc/apt/sources.list.d/nginx-plus.list

- name: NGINX Plus | 运行 apt-get update
  apt:
    update_cache: yes

- name: NGINX Plus | 安装 NGINX Plus 通过 apt-get
  apt:
    pkg: nginx-plus
    state: latest

- name: NGINX Plus | 启动 NGINX Plus
  service:
    name: nginx
    state: started

现在我们已经准备好运行 ansible-playbook 命令:

$ sudo ansible-playbook --ask-pass $HOME/ansible-nginx-plus/deploy.yml

你应该得到一个成功的 play recap。如果你没有成功,你可以使用冗余参数,以帮助你解决出现的问题。

小结

我在这个教程中演示是什么是 Ansible,可以做些什么来帮助你自动部署 NGINX 或 NGINX Plus,这仅仅是个开始。还有许多有用的模块,包括从用户账号管理到自定义配置模板等。如果你有兴趣了解关于这些的更多信息,请访问 Ansible 官方文档


via: https://www.nginx.com/blog/installing-nginx-nginx-plus-ansible/

作者:Kevin Jones 译者:strugglingyouth 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具。它用Python写成,类似于Chef和Puppet,但是有一个不同和优点是我们不需要在节点中安装任何客户端。它使用SSH来和节点进行通信。

本篇中我们将在CentOS 7上安装并配置Ansible,并且尝试管理两个节点。

  • Ansible 服务端 – ansible.linuxtechi.com ( 192.168.1.15 )
  • 节点 – 192.168.1.9 , 192.168.1.10

第一步: 设置EPEL仓库

Ansible仓库默认不在yum仓库中,因此我们需要使用下面的命令启用epel仓库。

[root@ansible ~]# rpm -iUvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm

第二步: 使用yum安装Ansible

[root@ansible ~]# yum install ansible

安装完成后,检查ansible版本:

[root@ansible ~]# ansible --version

ansible-version

第三步: 设置用于节点鉴权的SSH密钥

在Ansible服务端生成密钥,并且复制公钥到节点中。

root@ansible ~]# ssh-keygen

ssh-keygen

使用ssh-copy-id命令来复制Ansible公钥到节点中。

ssh-copy-id-command

第四步:为Ansible定义节点的清单

文件 /etc/ansible/hosts 维护着Ansible中服务器的清单。

[root@ansible ~]# vi /etc/ansible/hosts
[test-servers]
192.168.1.9
192.168.1.10

保存并退出文件。

主机文件示例如下:

ansible-host

第五步:尝试在Ansible服务端运行命令

使用ping检查‘test-servers’或者ansible节点的连通性。

[root@ansible ~]# ansible -m ping 'test-servers'

ansible-ping

执行shell命令

例子1:检查Ansible节点的运行时间(uptime)

[root@ansible ~]# ansible -m command -a "uptime" 'test-servers'

ansible-uptime

例子2:检查节点的内核版本

[root@ansible ~]# ansible -m command -a "uname -r" 'test-servers'

kernel-version-ansible

例子3:给节点增加用户

[root@ansible ~]# ansible -m command -a "useradd mark" 'test-servers'
[root@ansible ~]# ansible -m command -a "grep mark /etc/passwd" 'test-servers'

useradd-ansible

例子4:重定向输出到文件中

[root@ansible ~]# ansible -m command -a "df -Th" 'test-servers' > /tmp/command-output.txt

redirecting-output-ansible


via: http://www.linuxtechi.com/install-and-use-ansible-in-centos-7/

作者:Pradeep Kumar 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出