SaltStack基础设施:为NginxWeb服务器创建Salt状态

来自菜鸟教程
跳转至:导航、​搜索

介绍

SaltStack 或 Salt 是一个功能强大的远程执行和配置管理系统,可用于以结构化、可重复的方式轻松管理基础架构。 在本系列中,我们将演示一种从 Salt 部署管理开发、登台和生产环境的方法。 我们将使用 Salt 状态系统来编写和应用可重复的操作。 这将使我们能够安全地破坏我们的任何环境,因为我们知道我们可以在以后轻松地将它们以相同的状态重新上线。

在我们的 previous guide 中,我们通过为 salt-cloud 设置 DigitalOcean 提供程序来扩展 Salt 主服务器的功能。 我们创建了允许我们为每个环境启动新服务器所需的文件。 在本文中,我们将通过为 Nginx 创建 Salt 状态文件来开始深入研究配置管理。 Nginx 将在所有三种环境中的 Web 服务器节点上使用,以处理 Web 请求。

创建主 Nginx 状态文件

Salt 通过其状态系统处理配置管理。 在最简单的情况下,它们由位于 Salt 文件服务器根目录中的文件控制(我们将其配置为 /srv/salt)。 要开始我们的 Nginx 配置,我们将在此位置创建一个目录,该目录特定于我们正在配置的软件:

sudo mkdir /srv/salt/nginx

状态文件有一个 .sls 后缀。 目录中的 init.sls 文件用作该特定 Salt 状态或公式的主要配置文件。 我们引用父目录名称来执行关联的 init.sls 文件中包含的功能。

考虑到这一点,在此目录中创建并打开一个 init.sls 文件以开始:

sudo nano /srv/salt/nginx/init.sls

Nginx 包和服务状态

我们将首先使用 nginx 标识符创建一个状态。 这将作为 Salt 状态系统中此特定状态的唯一名称。 由于我们不会为我们的状态模块包含“名称”属性,因此它也将用作要安装的目标(对于 pkg.installed 功能)和要运行的服务(对于 service.running 功能)。

我们希望 Nginx 在某些情况下自动重新加载:更新包时、更改主配置文件时或修改默认服务器块文件时。 当这些情况发生时,我们可以使用 watch 告诉 Salt 重启 Nginx 服务:

/srv/salt/nginx/init.sls

nginx:
  pkg:
    - installed
  service.running:
    - watch:
      - pkg: nginx
      - file: /etc/nginx/nginx.conf
      - file: /etc/nginx/sites-available/default

watch: 键下方的 pkg:file: 键表示与要监视的资源关联的状态模块。 pkg 资源在同一定义的第一部分中得到处理。 接下来我们必须创建状态以匹配 file 资源。

Nginx 配置文件状态

我们可以从 /etc/nginx/nginx.conf 文件开始。 我们想让它成为一个托管文件。 在 Salt 术语中,这只是意味着我们将在主服务器上定义文件的内容并将其上传给每个需要它的 minion。 我们将对文件设置相当典型的权限和所有权。 源引用了 Salt 文件服务器中的一个位置(我们当前的文件也在这个结构中)。 我们将立即创建此路径和文件:

/srv/salt/nginx/init.sls

nginx:
  pkg:
    - installed
  service.running:
    - watch:
      - pkg: nginx
      - file: /etc/nginx/nginx.conf
      - file: /etc/nginx/sites-available/default

/etc/nginx/nginx.conf:
  file.managed:
    - source: salt://nginx/files/etc/nginx/nginx.conf
    - user: root
    - group: root
    - mode: 640

我们还想控制 /etc/nginx/sites-available/default 文件的内容。 这定义了控制如何提供我们的内容的服务器块。 状态块与最后一个非常相似。 主要区别在于该文件将是一个 Jinja 模板。

Jinja 模板允许 Salt 自定义文件的某些内容,其中包含特定于每个将要放置的 Minion 的详细信息。 这意味着我们可以从每个主机中提取信息,并为我们的每个 Web 服务器构建一个适当的、定制的文件版本。 我们指出该文件将使用带有 template 选项的 Jinja。 我们还将在源文件上使用 .jinja 后缀,以便我们一眼就能看出该文件是一个模板:

/srv/salt/nginx/init.sls

. . .

/etc/nginx/nginx.conf:
  file.managed:
    - source: salt://nginx/files/etc/nginx/nginx.conf
    - user: root
    - group: root
    - mode: 640

/etc/nginx/sites-available/default:
  file.managed:
    - source: salt://nginx/files/etc/nginx/sites-available/default.jinja
    - template: jinja
    - user: root
    - group: root
    - mode: 640

我们将默认服务器块文件放置在 minion 主机上的 sites-available 目录中。 但是,我们仍然需要将文件链接到 sites-enabled 目录才能激活它。 我们可以使用 file.symlink 函数来做到这一点。 我们只需要提供原始文件位置为 target。 我们还需要“要求”该文件,以便仅在前一个状态成功完成后才执行此状态:

/srv/salt/nginx/init.sls

. . .

/etc/nginx/sites-available/default:
  file.managed:
    - source: salt://nginx/files/etc/nginx/sites-available/default.jinja
    - template: jinja
    - user: root
    - group: root
    - mode: 640

/etc/nginx/sites-enabled/default:
  file.symlink:
    - target: /etc/nginx/sites-available/default
    - require:
      - file: /etc/nginx/sites-available/default

我们默认网站内容的状态

我们编写了 Nginx 安装和配置状态。 现在,我们只需要为我们的 index.html 文件创建一个状态,这将是我们网站的实际内容。

此状态使用与我们之前的模板状态完全相同的格式。 唯一的区别是此文件的标识符、来源和权限模式:

/srv/salt/nginx/init.sls

. . .

/etc/nginx/sites-enabled/default:
  file.symlink:
    - target: /etc/nginx/sites-available/default
    - require:
      - file: /etc/nginx/sites-available/default

/usr/share/nginx/html/index.html:
  file.managed:
    - source: salt://nginx/files/usr/share/nginx/html/index.html.jinja
    - template: jinja
    - user: root
    - group: root
    - mode: 644

完成后,保存并关闭此文件。 目前我们已经完成了实际的 Nginx 状态信息。

安装 Nginx 并将原始文件传输到 Salt Master

我们创建了主要的 Nginx Salt 状态文件。 但是,我们在 Salt Master 的文件服务器上创建的一些状态引用了尚不存在的文件。

由于我们的文件与 Ubuntu 的 Nginx 包安装的默认文件基本相同,因此我们最简单的方法是使用该包中的文件。 我们其中一个环境中的 Web 服务器提供了一个安装 Nginx 的理想场所,这样我们就可以获取必要的文件。

如果您尚未启动其中一个环境,请选择您的环境映射文件之一进行部署。 我们将在本系列中使用“stage”环境,因为它是拥有我们需要的所有服务器类型的最小环境。

sudo salt-cloud -P -m /etc/salt/cloud.maps.d/stage-environment.map

一旦您的服务器启动并运行,请选择您的 Web 服务器之一来安装 Nginx。 此时我们将使用 pkg 执行模块,因为我们的状态还没有完全发挥作用:

sudo salt stage-www1 pkg.install nginx

当我们设置我们的 Salt Master 配置时,我们启用了 file_recv 选项。 这允许我们请求 minions 将某些文件推送回 master。 我们可以使用它来获取我们将要管理的文件的默认版本:

sudo salt stage-www1 cp.push /etc/nginx/nginx.conf
sudo salt stage-www1 cp.push /etc/nginx/sites-available/default
sudo salt stage-www1 cp.push /usr/share/nginx/html/index.html

这些文件现在应该在主服务器上可用。 这些文件的路径在 /var/cache/salt/master/minions/minion_id/files 目录中重新创建。 在我们的例子中,minion ID 是 stage-www1。 我们可以通过键入以下内容将该位置下的目录(代表 minion 上的文件路径)复制到我们的 Salt state 目录:

sudo cp -r /var/cache/salt/master/minions/stage-www1/files /srv/salt/nginx

如果您查看状态目录的内容,您将看到一个名为“files”的新目录。 在这个目录下,可以看到minion文件系统中的相关目录和我们复制的三个文件:

find /srv/salt/nginx -printf "%P\n"
Outputfiles
files/usr
files/usr/share
files/usr/share/nginx
files/usr/share/nginx/html
files/usr/share/nginx/html/index.html
files/etc
files/etc/nginx
files/etc/nginx/sites-available
files/etc/nginx/sites-available/default
files/etc/nginx/nginx.conf
init.sls

这是维护我们所有托管文件的地方。 这与我们在 Nginx 状态文件中设置的“源”位置一致。

由于我们现在已经从安装 Nginx 的 minion 中提取了所有需要的文件,因此我们可以销毁 minion 并重建它。 这将确保以后可以在干净的服务器上测试我们的状态文件。 销毁 Nginx 仆从:

sudo salt-cloud -d stage-www1

等待事件处理完毕后,我们就可以重建minion了。

我们通常会为此使用映射文件,但由于我们只重建单个服务器,因此实际上最好直接使用 stage-web 配置文件。 然后我们可以使用 cloud.profile Salt 执行函数代替 salt-cloud,这允许我们添加 --async 标志。 基本上,这让我们可以在继续工作时在后台重建我们的 stage-www1 服务器。 我们将不得不在这个命令中定位我们的 Salt Master,因为这是具有我们需要的云配置文件的服务器:

sudo salt --async sm cloud.profile stage-web stage-www1

当我们的 stage-www1 节点在后台重建时,我们可以继续。

配置 /etc/nginx/nginx.conf 文件

我们先看一下主要的 Nginx 配置文件,它将放在我们的 minions 上的 /etc/nginx/nginx.conf 处。 我们可以在没有 Nginx 状态目录的 files 目录下找到这个路径:

cd /srv/salt/nginx/files/etc/nginx

我们现在实际上不打算修改这个文件,但我们可以帮自己一个忙,现在备份原始文件:

sudo cp nginx.conf nginx.conf.orig

这将为我们将来可能进行的自定义提供一个很好的参考点。 我们可以通过键入以下内容快速查看我们所做的任何更改:

diff nginx.conf nginx.conf.orig

将来,如果我们发现需要在各种环境中自定义 Nginx 的配置(例如,我们可能希望稍后将 worker_processes 与生产服务器上的 CPU 数量相匹配),我们可能希望过渡到使用模板文件。 我们目前不需要这个,所以作为一个非模板文件,我们的更改将被硬编码。

正如我们之前所说,我们目前不需要任何修改。 让我们继续前进。

配置 /etc/nginx/sites-available/default 模板

接下来,让我们看看我们的默认服务器块模板。 我们可以在这个目录下找到原文:

cd /srv/salt/nginx/files/etc/nginx/sites-available

同样,我们应该将原件复制到备份位置以备日后需要:

sudo cp default default.orig

然后我们可以重命名文件,使其具有 .jinja 扩展名。 这会在视觉上提醒我们这个文件是一个模板,而不是一个可用的文件:

sudo mv default default.jinja

现在,我们可以打开模板文件进行一些更改:

sudo nano default.jinja

在文件的最顶部,我们需要开始使用 Jinja 的模板功能。 我们的默认服务器块需要根据 Web 服务器是否位于负载均衡器后面来呈现不同的文件。

当通过负载均衡器接收连接时,我们希望我们的 Web 服务器将其流量限制到私有接口。 然而,当我们在开发环境中时,我们没有负载均衡器,因此我们希望通过公共接口提供服务。 我们可以用 Jinja 创造这种区别。

我们将创建一个名为 interface 的变量,它应该包含我们想要地址的接口。 我们将测试 minion 的环境是否设置为“dev”,在这种情况下,我们将使用 eth0 接口。 否则,我们将其设置为服务器的私有接口 eth1。 然后,我们将使用 grains.get 执行模块函数来获取与所选接口关联的地址,并将其用作 addr 变量的值。 我们将把它添加到文件的最顶部:

/srv/salt/nginx/files/etc/nginx/sites-available/default.jinja

{%- set interface = 'eth0' if salt['grains.get']('env') == 'dev' else 'eth1' -%}
{%- set addr = salt['network.interface_ip'](interface) -%}
# You may add here your
# server {
#       ...
# }

. . .

接下来,我们可以在文件中进一步编辑 server 块。 我们可以使用我们在 listenserver_name 指令顶部设置的 addr 变量。 我们删除了 IPv6 和默认服务器部分以限制此块的服务:

/srv/salt/nginx/files/etc/nginx/sites-available/default.jinja

{%- set interface = 'eth0' if salt['grains.get']('env') == 'dev' else 'eth1' -%}
{%- set addr = salt['network.interface_ip'](interface) -%}

. . .

server {
    listen {{ addr }}:80;

    root /usr/share/nginx/html;
    index index.html index.htm;

    server_name {{ addr }};

    location / {
        try_files $uri $uri/ =404;
    }
}

完成后保存并关闭文件。

配置 /usr/share/nginx/html/index.html 模板

我们现在可以转到 index.html 文件。 移至 Salt Master 上包含该文件的目录:

cd /srv/salt/nginx/files/usr/share/nginx/html

在里面,我们需要从上次使用的相同程序开始。 我们应该存储原始文件的副本以用于审计和备份目的。 然后我们应该重命名文件以表明这将是一个模板:

sudo cp index.html index.html.orig
sudo mv index.html index.html.jinja

打开模板文件,以便我们进行所需的修改:

sudo nano index.html.jinja

在顶部,我们将使用 Jinja 设置另一个变量。 我们将使用 grains.get 执行模块函数来获取 minion 的主机名。 我们将其存储在 host 变量中:

{% set host = salt['grains.get']('host') -%}
<!DOCTYPE html>
<html>

. . .

然后,我们将在整个文件中使用此值,以便我们可以轻松判断哪个 Web 服务器正在为我们的请求提供服务。 先改变<title>值:

{% set host = salt['grains.get']('host') -%}
<!DOCTYPE html>
<html>
<head>
<title>Welcome from {{ host }}</title>
. . .

让我们将正文文本更改为:

. . .

<body>
<h1>Welcome to nginx!</h1>
<p>Hello!  This is being served from:</p>

<h2>{{ host }}</h2>

</body>
</html>

完成后保存并关闭文件。

测试 Nginx 状态文件

我们现在已经完成了 Nginx 配置。 我们可以测试状态的某些方面,以确保它正常工作。

首先,我们可以使用 state.show_sls 执行模块函数来查看 Salt 将如何解释我们的 Nginx 状态文件。 我们可以使用我们的 stage-www1 服务器作为目标。 但此时服务器上不会执行任何操作:

sudo salt stage-www1 state.show_sls nginx

您应该得到如下所示的输出:

Outputstage-www1:
    ----------
    /etc/nginx/nginx.conf:
        ----------
        __env__:
            base
        __sls__:
            nginx
        file:
            |_
              ----------
              source:
                  salt://nginx/files/etc/nginx/nginx.conf
            |_
              ----------
              user:
                  root
            |_
              ----------
              group:
                  root
            |_
              ----------
              mode:
                  640
            - managed
            |_
              ----------
              order:
                  10002

. . .

它主要渲染来自我们的 /srv/salt/nginx/init.sls 文件的信息,并添加了一些有趣的内容。 检查是否存在 Salt 不知道如何阅读命令的解释错误。 每件的“订单”是另一个需要检查的好项目。 这决定了文件中的每个单独状态何时运行。 第一个状态的订单号为“10000”。 每个额外的州都会从那里开始计数。 请注意,__env__ 与我们使用颗粒设置的 env 不同。 在本指南中,我们没有使用 Salt 的环境概念。

接下来,我们可以试运行应用我们的状态文件。 我们可以使用带有 test=True 选项的 state.apply 函数来做到这一点。 该命令如下所示:

sudo salt stage-www1 state.apply nginx test=True

这将显示如果删除 test=True 选项将进行的更改。 查看以确保更改有意义并且 Salt 能够正确解释您的所有文件。 “评论”字段特别重要,因为即使在 Salt 没有将状态标记为失败的情况下,它也可以揭示问题。

如果试运行没有发现任何问题,您可以尝试通过键入以下命令将状态应用于所有可用的 Web 服务器:

sudo salt -G 'role:webserver' state.apply nginx

如果您将 Nginx 状态应用于暂存或生产 Web 服务器,您将需要获取它们的内部 IP 地址。 这些页面将无法通过公共界面访问:

sudo salt-call mine.get 'role:webserver' internal_ip expr_form=grain
Outputlocal:
    ----------
    stage-www1:
        ip_address
    stage-www2:
        ip_address

另一方面,如果您启动了开发 Web 服务器并应用了 Nginx 状态,您将需要获取外部地址,因为:

sudo salt-call mine.get 'role:webserver' external_ip expr_form=grain

您可以使用 curl 测试您的服务器:

curl ip_address

您应该看到我们修改的 index.html 页面:

Output<!DOCTYPE html>
<html>
<head>
<title>Welcome from stage-www1</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>Hello!  This is being served from:</p>

<h2>stage-www1</h2>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

如您所见,在渲染 Jinja 时,minion 的主机名已放置在文件中。 我们的 Nginx 状态现在已经完成。

结论

您现在应该拥有一个功能齐全的 Nginx 状态。 这将允许您快速轻松地将任何 Salt 控制的机器变成具有您的规范的 Web 服务器。 我们将使用它作为我们更大的基础设施管理策略的一部分,以便在我们的环境中轻松构建 Web 服务器。

下一个指南 中,我们将继续并为负载均衡器构建状态,这些负载均衡器将在我们的 Web 服务器前引导流量。 我们将使用本指南中使用的一些相同技术来使我们的负载均衡器变得灵活。