导航员指南:具有配置管理的部署解决方案
注意:这是《导航指南》内容的早期版本,由 DigitalOcean 解决方案工程师提供。 本书的目标是帮助企业客户规划他们的基础设施需求,提供沿途的工作示例,并包括技术细微差别和使某些决策比其他决策更好的“原因”。
这本书和随附的代码将在 GitHub 存储库中公开提供。 因为这是一个早期版本,所以这本书还没有完成,存储库还没有公开,但请继续关注!
上一章演示了如何通过在基础架构的 Web 前端层添加冗余来减少停机时间。 如果您的服务处理文件和数据,您还需要一个集中式后端——它应该同样是冗余的,以避免成为单点故障。
前端和后端都可以使用负载平衡解决方案将流量分配到多个服务器。 这种结构在后端提供了一些独特的好处,例如能够在不导致停机的情况下更新应用程序代码,支持 A/B 测试、金丝雀部署和蓝/绿部署等。 但是,这也会给您的基础架构增加一些复杂性。 您需要考虑如何维护负载平衡器的配置、如何管理应用程序及其运行的服务器,以及如何处理用户会话、文件存储和数据库等事物的一致性。
无论您使用 DigitalOcean 负载均衡器还是一组自我管理的负载均衡器,您都需要保持其配置的一致性。 在自我管理的负载均衡器设置中使用配置管理工具管理配置文件需要更多的动手操作,并且需要预先进行一些额外的工作,而 DigitalOcean 负载均衡器是一种托管服务,可自动处理负载均衡器冗余。
对于 DigitalOcean 负载均衡器,配置选项经过精心策划,但您仍需要确保设置正确且一致。 使用 Droplet 标签来确定负载均衡器的后端是最直接的成功途径,因为它允许您自动添加和删除 Droplet(而不是通过单个 IP),并且意味着您的配置可以仅由 Terraform 处理而无需 Ansible。
如果您的负载平衡要求更复杂,您可能会选择使用自己的负载平衡器(使用 HAProxy,如前一章,或其他负载平衡软件)。 在这种情况下,您需要部署一组多个负载均衡器 Droplet 以及一个 DigitalOcean 浮动 IP 地址,以确保负载均衡层的冗余。
我们的设置
数据一致性是您将在负载均衡器配置中解决的主要问题。 当您的后端可以从多个服务器中的任何一个提供服务时,您需要确保每个服务器都可以访问相同的一致数据集,或者特定会话将继续连接到特定服务器。
我们将以此为契机展示更强大的配置管理软件的使用。 在我们托管运行 WordPress 的网站的示例中,我们必须决定如何确保集群中的每个节点都有正确的数据。 无论哪个节点正在处理请求,最终用户都需要有凝聚力的体验。 如果一个节点知道我们的 WordPress 站点中的帖子或图像,但其他节点不知道,最终用户可能会看到零星的结果。
在我们进行配置以确保一致性时,我们将审查三个相关组件:用户会话、文件存储和数据库。
了解配置
实际上,一旦配置完成就设置集群是一个相对较短的过程,但了解配置和其中的决策是能够将这些模式应用于您自己的基础架构的关键。 让我们一块一块地分解。
负载均衡器配置
DigitalOcean 负载均衡器
与前几章一样,我们将使用 Terraform 来管理负载均衡器配置。 以下条目创建负载均衡器并提供后端 Droplet 标签、转发规则、要使用的 TLS 证书以及负载均衡器将使用的运行状况检查。 SSL 和其他安全设置超出了本章的范围,但在第 13 章中将对其进行深入介绍。
这是位于 example-code/02-scale/ch05/init_deploy/main.tf
文件中的资源块:
... resource "digitalocean_loadbalancer" "public" { name = "${var.project}-lb" region = "${var.region}" droplet_tag = "${digitalocean_tag.backend_tag.id}" redirect_http_to_https = true depends_on = ["digitalocean_tag.backend_tag"] forwarding_rule { entry_port = 80 entry_protocol = "http" target_port = 80 target_protocol = "http" } healthcheck { port = 80 protocol = "http" path = "/" check_interval_seconds = 5 response_timeout_seconds = 3 unhealthy_threshold = 2 healthy_threshold = 2 } }
因为负载均衡器是一项服务而不是不可变资源(如 Droplet),所以对配置参数的更改不会重新创建整个负载均衡器; 它将更新到位。 有关支持的参数和输出属性的更多详细信息,请查看 Terraform 文档。
我们正在使用 DigitalOcean 负载均衡器来处理到我们的 Web 服务器的公共 Web 流量的负载均衡。
HAProxy 集群
如果您需要更复杂的配置,例如访问较低级别的负载平衡设置或支持多个后端服务,您可以设置自己的负载平衡器集群。 我们将继续上一章中的 HAProxy 示例。
Ansible 使用 Jinja2 模板系统,它简化了创建和更新配置文件的过程。 Jinja2 支持使用在编程语言中可以找到的变量和控制结构,例如 if 语句、循环、数学运算和内置过滤器的大型库。 此摘要对 Ansible 中的模板系统不公平。 我们建议查看 Ansible 的文档 了解更多详细信息。
当您的配置更改时,有几种方法可以触发更新。 如果您网站上的需求波动不大,或者您提前知道何时会发生更改,您可能不需要或不想设置全自动扩展。 相反,您可以手动运行 Ansible playbook,或者将其设置为在将 Terraform 部署脚本的更改推送到 git 存储库时运行。
另一种选择是使用 Consul 进行服务发现,并在负载均衡器上配置 consul-template
以自动刷新配置文件。 这为您的整体基础架构添加了额外的 Droplet,但您也可以将 Consul 用于其他服务。
我们正在使用 HAProxy 集群来处理数据库集群的负载平衡。
用户会话
会议回顾
当用户访问通过负载均衡器托管的站点时,无法保证他们的下一个请求将由同一后端服务器处理。 对于简单的静态页面,这不是问题,但如果服务需要了解用户会话(例如他们是否已登录),则需要处理该问题。 有几个选项可以解决这个问题,可以在堆栈中的不同点实现。
您选择处理用户会话的方法将取决于您的用例。 以下是一些选项:
IP 源关联 将来自同一 IP 地址的所有请求定向到同一后端。 在您的用户可能使用 NAT 从路由器后面连接的情况下,这不是最佳选择,因为他们都将拥有相同的 IP 地址。
负载均衡器会话和应用程序会话选项相似。 它们都将负载均衡器配置为查看 IP 标头信息以确定将请求发送到哪个后端。 与 IP 源关联方法不同,NAT 后面的用户将被识别为个人用户。 您可以通过在 HAProxy 负载平衡器上实现一个棒状表来进一步调整它,该表可用于根据多个不同的数据点配置用户标识。
文件系统复制复制文件系统中存储会话的路径,使所有后端都可以访问所有会话。 要考虑的一个关键方面是复制发生的速度。 根据方法的不同,即使后端节点之间存在适度的延迟以及要复制的大量会话,也可能会给最终用户带来问题。
使用 数据库 或 内存数据存储 是类似的。 两者都要求您以将用户会话存储在数据库或 Redis 等内存缓存中的方式创建应用程序。 使用数据库可能很方便,因为您的应用程序已经设置为连接到它以处理其他数据请求。 对于高度活跃的站点,这可能会给数据库本身带来更多开销,但在大多数用例中,额外的负载可以忽略不计。 使用 Redis 或 Memcached 等内存缓存意味着您需要创建更多 Droplet,但它们是非常快速且通用的解决方案,您还可以使用它们来缓存数据库查询响应以提高性能。
因为 WordPress 已经配置为使用数据库进行会话,所以这就是我们将使用的解决方案。
文件存储
文件存储评论:
您的应用程序使用的文件需要保持一致; 所有服务器都需要访问同一组资源。 解决此问题的一种好方法是将存储功能与后端应用服务器分离,而是使用单独的服务进行文件存储。 对于静态资产,您可以使用对象存储解决方案。 DigitalOcean Spaces 是一种具有内置冗余的高可用性对象存储服务。 我们将在第 7 章详细讨论存储选项,尤其是 Spaces。
与会话一样,您可以使用应用程序节点之间的本地文件系统复制来处理文件存储。 但是,这确实为您的基础架构添加了另一项服务,以及额外的配置更改。
一个更简单的解决方案是使用对象存储,例如 DigitalOcean Spaces,尤其是因为 WordPress 已经有一个 DigitalOcean Spaces Sync 插件。 因为设置简化为安装和配置单个插件,这就是我们将在本章中使用的解决方案。
数据库
数据库审查
就像文件存储一样,您的数据库需要可供所有后端 Droplet 访问。 如何跨集群复制数据库插入和更新对于功能性集群数据库解决方案至关重要。
此外,您的数据库应该是高度可用的——也就是说,它具有冗余和自动故障转移。 这可能比仅仅将其放在负载均衡器后面更复杂,因为系统需要处理数据一致性,例如如果对不同节点进行冲突更新会发生什么。
在我们的示例中,我们使用 MariaDB Galera 集群来处理这些问题。 Galera 处理对每个数据库节点的同步复制,每个数据库节点都充当完整的主数据库服务器。 这意味着您可以读取和写入集群中的每个节点,并且一切都保持同步。 还有其他方法可以对涉及主要和次要复制形式的数据库进行集群,其中特定节点被选为主要写入服务器。
每个集群解决方案都有其优点。 对于我们的练习,Galera 给我们带来了最大的好处,因为数据一致性是自动处理的,并且集群中的每个节点都可以充当主服务器。 没有必要的故障转移或故障回复步骤。
WordPress 几乎所有事情都依赖其数据库,而单个外部数据库服务器是单点故障。 数据库集群有几个选项,不同的部分可以根据你的情况进行混合和匹配。
在本章中,我们将构建一个运行在 MariaDB 上的 Galera 集群,MariaDB 是 MySQL 的一个分支。 这将在带有附加 DigitalOcean 浮动 IP 的几个 HAProxy 节点后面运行。
您可以在此处访问源代码库:https://github.com/DO-Solutions/galera-tf-mod。 它设置到集群的 TCP 路由,默认情况下该集群具有三个节点。 如果我们使用的节点少于三个,则需要一个 Galera Arbitrator 节点来避免脑裂情况并保持集群正常运行。 您还可以通过将以下行添加到我们的主 terraform 文件 example-code/02-scale/ch05/init_deploy/main.tf 中的模块代码块来增加节点的数量。 请注意,您需要有奇数个节点,以便在执行仲裁投票时集群可以拥有多数。 一个例子是,如果两个节点认为一条记录应该存在,而另外两个节点认为该记录不应该存在,则需要一个额外的节点来投决定性的一票。
module "sippin_db" { ... db_node_count = "5" }
设置 WordPress 集群
在我们的项目中,设置 WordPress 集群只需要几个命令。 我们将在控件 Droplet 上使用 /root/navigators-guide/example-code/02-scale/ch05/init_deploy
,其中包含本章的示例代码。
在该目录中,运行我们提供的初始化脚本。 它将引导您完成需要设置的所有设置和变量。
./bin/init_config
您可以在 GitHub 上查看初始化脚本的代码。 您将看到该脚本正在执行相当多的功能。 它真正做的是自动创建必要的 Terraform 和 Ansible 变量文件,并确保不存在已知问题。 脚本要做的第一件事是提示输入有效的 DigitalOcean API 令牌。 之后,该脚本将创建集群创建所需的一些唯一键。 您将看到的下一个提示将是命名项目并选择一个区域。 如果已经配置了 SSH 密钥(就像我们在第 4 章中所做的那样),脚本将告诉 Terraform 使用它。 如果尚未配置 SSH 密钥,则会自动创建一个并将其添加到您的 DigitalOcean 帐户。 最后,脚本将提示输入任何需要的密码。
一旦脚本完成 Terraform 计划和 Ansible playbook 就可以执行了。 这与第 4 章中的示例非常相似,但要创建和配置更多资源。
如果您要手动配置所有内容,则需要在 terraform.tvfars 文件中为 Terraform 输入的变量。 Ansible 在 group_vars 文件夹内的多个文件夹中有必需的变量。
初始化脚本将在退出之前打印有关如何继续使用 Terraform 的说明,但我们也将在此处进行介绍。
首先,运行 terraform plan
将在您的 DigitalOcean 帐户中创建以下项目:
- 一个负载均衡器,它将提供对您的 WordPress 站点的访问。
- 三个 Droplet 用作 WordPress Web 节点。
- 三个 Droplet 用作数据库节点。
- 数据库集群的两个 HAProxy 负载均衡器节点。
- 数据库负载平衡器的一个浮动 IP 地址。
terraform plan
接下来,使用 init
解析计划文件和模块以准备 Terraform 部署。
terraform init
最后,使用 apply
通过 DigitalOcean API 执行创建请求。
terraform apply
一旦 Terraform 完成创建所有基础设施组件,使用 Ansible 配置它们。 需要执行三个 Ansible 角色:一个用于配置数据库服务器,一个用于配置数据库负载均衡器,一个用于在所有 Web 节点上设置 WordPress。
您可以使用一个命令运行所有三个角色:
ansible-playbook -i /usr/local/bin/terraform-inventory site.yml
剧本完成后,您需要完成 WordPress 设置。
在浏览器中访问负载均衡器的 IP 地址,然后按照屏幕上的说明完成 WordPress 配置。 请注意,第 13 章介绍了如何使用 HTTPS 保护您的 WordPress 安装。
配置空间
我们将使用 DigitalOcean Spaces Sync 插件将媒体文件从 WordPress 应用服务器同步到对象存储。 空间充当存储您选择上传的任何媒体的中心位置。
DigitalOcean Spaces Sync 插件作为 Ansible playbook 的一部分预先安装。 为了使用这个插件,你首先需要使用控制面板创建一个空间。
创建空间后,在控制面板的“API”页面上创建一个空间访问密钥。 生成密钥后,您将看到主密钥和密钥。 记下这些,因为您将需要它们来设置 WordPress 插件。
现在,回到 WordPress,访问插件页面,由于我们的 Ansible playbook,您应该会看到 DigitalOcean Spaces Sync 已经安装。 单击激活链接以启用此插件。 启用后,您的设置中将出现一个名为“DigitalOcean Spaces Sync”的新链接。
在此设置页面上,输入您的 Spaces 密钥、Spaces 密码、Space 名称(在此设置页面上标记为“DO Spaces Container”)和端点。 请记住,端点将取决于您为空间选择的数据中心:例如,NYC3 将是“https://nyc3
.digitaloceanspaces.com”。
检查连接后,在“文件的完整 URL 路径:”下添加空间的完整 URL。 对于 NYC3 中的空间,这将是“https://space-name
.nyc3.digitaloceanspaces.com”(其中 space-name
是您的空间的名称)。 输入后,就可以保存您的设置,并通过上传文件来测试插件。
当您在“媒体”选项卡中上传文件时,您应该会看到它自动同步到您的空间。 您可以通过在 DigitalOcean 控制面板中查看 Space 的文件列表来检查这一点。
现在,默认情况下,此设置不使用 CDN。 在生产环境中,我们绝对推荐使用 CDN,因为这将使您能够快速可靠地为所有访问者提供这些媒体文件。
如果您稍后添加 CDN,请记住您需要将“文件的完整 URL 路径”指向这个新 CDN 的地址。 我们还在开发与 Spaces 集成的 CDN。 目前处于测试阶段,但如果您有兴趣,请随时向您的客户经理索取访问权限。
验证设置
通过在浏览器中访问负载均衡器 IP 地址,您可以看到默认的 WordPress 站点,类似于以下内容:
最终结果是一个功能齐全的 WordPress 网站。 您可以通过配置博客或创建帖子进行测试。 您可以关闭两个 Web 服务器、一个 HAProxy 服务器和一个数据库节点,并且网站应该仍然可以正常运行。
完成测试后,您可以使用一个命令从您的 DigitalOcean 帐户中删除所有这些基础架构组件。 这将删除整个集群以清理本章的工作。
terraform destroy
您可以重新运行 apply
,然后重新运行 Ansible playbook 以重新生成集群。
下一步是什么?
我们采用了高可用性示例,并将该概念应用于整个应用程序堆栈。 本章中的示例用于创建一个完全冗余且可扩展的 WordPress 网站。 这是通过利用配置管理工具实现的。 我们将在下一章探索一种进一步自动化和改进部署的方法。 本书的其余部分将涵盖与存储、监控和安全相关的概念,但更重要的是它们如何应用于您的业务以及规划基础架构时应考虑的事项。