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
块。 我们可以使用我们在 listen
和 server_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; } }
完成后保存并关闭文件。
我们现在可以转到 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 服务器前引导流量。 我们将使用本指南中使用的一些相同技术来使我们的负载均衡器变得灵活。