如何使用负载均衡器和托管数据库集群扩展Discourse部署
作者选择了 COVID-19 Relief Fund 作为 Write for DOnations 计划的一部分来接受捐赠。
介绍
Discourse 由 StackOverflow 的一位创始人创建,是一个开源讨论平台。 Discourse 可以为在线论坛、邮件列表、聊天室等提供支持。
使用 DigitalOcean 的一键安装,Discourse 在单个 Droplet 上运行良好,但随着社区的发展,它可能会超过单个 Droplet。 如果您的一个 Droplet 离线,使用多个 Droplet 可为您的社区提供弹性。 每个 Droplet 还会增加您的带宽限额。 使用多个 Droplet 时,负载均衡器可以帮助扩展您的部署并为您的 Web 应用程序带来高可用性。 最后,托管数据库实例确保跨多个 Droplet 的用户体验一致。
完成本教程后,您将拥有一个在 DigitalOcean 上运行的高度可用、易于扩展的 Discourse 部署。 您将从一个全新的 Ubuntu 20.04 Droplet 开始,您将完成一个水平可扩展的 Discourse 安装,其中包括负载均衡器、托管 PostgreSQL 集群、Redis 实例(可选)和其他 Droplet。
先决条件
要遵循本教程,您将需要:
- 一个至少有 2GB RAM 的 Ubuntu 20.04 服务器,配置了具有
sudo
权限和防火墙的非 root 用户,您可以按照指南 Initial Server Setup with Ubuntu 20.04 进行操作. - 在您的服务器上安装和配置 Discourse,您可以按照教程 如何在 Ubuntu 20.04 上安装 Discourse 来完成。
- 一个域名,其 DNS 记录由 DigitalOcean 管理,您可以按照教程 如何从公共域注册商 指向 DigitalOcean 名称服务器。 在您的服务器上设置 Discourse 时,请务必使用主域名而不是子域名(例如,使用
yoursite.com
而不是discourse.yoursite.com
)。 - 熟悉 Docker,可以从教程 The Docker Ecosystem: An Introduction to Common Components 中获得。
- 熟悉负载均衡器,您可以在我们的 产品文档 中找到。
第 1 步 — 将 DigitalOcean 负载均衡器添加到 Discourse 服务器
在此步骤中,您将向您在先决条件中创建的 Discourse 服务器添加一个 DigitalOcean 负载均衡器。 访问您的 DigitalOcean 控制面板,单击 Networking,然后单击 Load Balancers,然后单击 Create Load Balancer。
您需要为负载均衡器选择一个数据中心区域。 请务必选择您为 Discourse Droplet 选择的相同区域。 负载均衡器使用其专用网络与您的 Droplet 进行通信,因此您的 Droplet 和负载均衡器需要位于同一区域。
接下来,通过在文本字段中输入您的 Droplet 的名称,将您的 Droplet 添加到您的负载均衡器。
Discourse 通常通过在安装过程中颁发免费的 Let's Encrypt 证书来为您处理 HTTPS。 但是,当您的 Droplet 位于负载均衡器后面时,Let's Encrypt 将无法续订您的证书,因为您的域的 IP 地址与您的 Droplet 的 IP 不匹配。
幸运的是,DigitalOcean 负载均衡器可以为您管理证书。 您只需将 HTTPS 的 转发规则 添加到负载均衡器。 转发规则告诉负载均衡器将特定类型的流量转发到您的 Droplet。
注意:转发规则详见负载均衡产品文档。
您需要两条转发规则,一条用于 HTTP,一条用于 HTTPS。 通过为 HTTPS 添加转发规则,DigitalOcean 可以自动为您生成和更新证书。 HTTPS 支持对于安全性和您网站的 SEO 也很重要。
由于您将域添加到 DigitalOcean 作为先决条件的一部分,因此只需单击几下即可添加 HTTPS 支持。 在 Forwarding rules 部分,添加一个名为 HTTPS
的新规则,您可以从下拉列表中选择该规则。 现在单击证书,然后单击+新证书。
在文本字段中输入您的域名,该字段会自动为您填写。 然后为您的证书命名并单击 Generate Certificate 让 DigitalOcean 请求并为您管理证书。
您几乎完成了负载均衡器的设置。 单击 编辑高级设置 按钮并勾选标记为 启用代理协议 的框。 启用 PROXY 协议后,负载均衡器会将用户 IP 地址等客户端信息转发到负载均衡器后面的 Droplet。 如果没有 PROXY 协议,Discourse 会认为它的所有流量都来自单个用户(负载均衡器),并且所有日志都会显示负载均衡器的 IP 地址,而不是用户的真实 IP 地址。
最后,为您的负载均衡器选择一个名称,然后单击创建负载均衡器。
现在您已经设置了负载均衡器,您需要修改您的 Discourse 配置文件。
第 2 步 — 修改 Discourse 配置文件
在此步骤中,您将修改 Discourse 包含的默认配置文件。 SSH 进入您的 Droplet 并使用以下命令移动到 /var/discourse
目录:
cd /var/discourse
使用 nano 或您喜欢的文本编辑器,在 templates
目录中创建并打开一个名为 loadbalancer.template.yml
的新文件:
sudo nano templates/loadbalancer.template.yml
模板文件夹包含您的 Discourse 配置文件。 在这里,您将添加一个新的自定义模板,以启用对您的 Discourse 安装的 PROXY 协议支持。
在 loadbalancer.template.yml
中,插入以下行:
模板/负载均衡器.template.yml
run: - exec: "sed -i 's:listen 80: listen 80 proxy_protocol:g' /etc/nginx/conf.d/discourse.conf" - exec: "sed -i 's:$remote_addr:$proxy_protocol_addr:g' /etc/nginx/conf.d/discourse.conf" - exec: "sed -i 's:X-Forwarded-For $proxy_add_x_forwarded_for:X-Forwarded-For $proxy_protocol_addr:g' /etc/nginx/conf.d/discourse.conf"
第一行修改 Discourse Nginx 配置以启用对 PROXY 协议的支持。 如果在负载均衡器上启用了代理协议但在 Nginx 中未启用,Discourse 将返回服务器错误。
第二行执行查找和替换,将所有出现的 $remote_addr
替换为 $proxy_protocol_addr
。 $proxy_protocol_addr
包含客户端的 IP 地址,从负载均衡器转发。 $remote_addr
通常显示用户的 IP 地址,但由于 Discourse 在负载均衡器后面,它会显示负载均衡器的 IP 地址。
最后一行将所有出现的 X-Forwarded-For $proxy_add_x_forwarded_for
替换为 X-Forwarded-For $proxy_protocol_addr
,确保 X-Forwarded-For
标头正确记录客户端 IP 地址,而不是负载均衡器的 IP 地址。
按 CTRL+X
然后按 y
保存并关闭文件。
您需要做的最后一件事是将模板加载到 Discourse 并重建 Discourse。
使用 nano 或您喜欢的文本编辑器,编辑 containers
目录中名为 app.yml
的文件:
sudo nano containers/app.yml
首先,您将添加刚刚创建的模板。 在 templates
下,添加突出显示的行,如下所示:
容器/app.yml
templates: - "templates/postgres.template.yml" - "templates/redis.template.yml" - "templates/web.template.yml" - "templates/web.ratelimited.template.yml" - "templates/loadbalancer.template.yml"
请务必在 templates/web.template.yml
下面的一行中添加新模板。
接下来,确保通过添加井号 [#
] 将两行 web.ssl.template.yml
和 templates/web.letsencrypt.ssl.template.yml
都注释掉,如下所示:
容器/app.yml
templates: - "templates/postgres.template.yml" - "templates/redis.template.yml" - "templates/web.template.yml" - "templates/web.ratelimited.template.yml" - "templates/loadbalancer.template.yml" ## Uncomment these two lines if you wish to add Lets Encrypt (https) # - "templates/web.ssl.template.yml" # - "templates/web.letsencrypt.ssl.template.yml"
最后,向下走几行,直到看到 expose
。 通过添加井号 [#
] 注释掉行 - "443:443" # https
,如下所示:
容器/app.yml
... expose: - "80:80" # http # - "443:443" # https
当你重建 Discourse 时,HTTPS 现在将在 Discourse 上被禁用。 HTTPS 连接在负载均衡器处终止,负载均衡器通过 DigitalOcean 的安全专用网络与您的 Droplet 通信,因此您不需要直接在 Discourse 服务器上设置 HTTPS。
按 CTRL+X
然后按 y
保存并关闭文件。
要应用配置并重建 Discourse,请运行以下命令:
sudo ./launcher rebuild app
此命令需要超级用户权限,这就是为什么它前面带有 sudo
。
至此,您已经完成了 Discourse 和负载均衡器的配置。 接下来,您将域名指向负载均衡器的 IP 地址。
第 3 步 — 更新您的 DNS
在此步骤中,您将域指向负载均衡器的 IP 地址,而不是 Droplet 的 IP 地址。
如果您使用 DigitalOcean 的 DNS 托管,请转到控制面板并单击 Networking。 单击您的域名,然后查找指向您的 Droplet 的 A 记录。 选择记录的更多菜单修改记录。 将此记录的值从您的 Droplet 的 IP 地址更改为您的负载均衡器的 IP 地址。
您的 Discourse 服务器将在 DigitalOcean 负载均衡器后面运行,您不必管理自己的 SSL 证书,因为 DigitalOcean 会为您完成。
通过访问您的域名来测试您的 Discourse 安装是否正常。 您应该会看到一个类似于此的页面:
现在您的域指向负载均衡器,您将添加一个托管数据库实例来为您的用户创建一致的体验。
第 4 步 — 添加托管 DigitalOcean 数据库
在此步骤中,您将创建一个 DigitalOcean Managed PostgreSQL 实例并将其添加到您的 Discourse 部署中。
负载均衡器的主要优点是在多个 Droplet 之间分配您的流量。 到目前为止,您的数据库、Redis 服务器和 Web 服务器都运行在一个 Droplet 上。 如果添加第二个 Discourse 实例,它将拥有自己的数据库、Redis 服务器和 Web 服务器,并且会像一个完全不同的网站一样工作。 您的访问者可能会觉得他们正在访问具有不同帖子和用户的其他网站,因为他们将连接到不同的数据库。 您可以通过使用 DigitalOcean 的托管 PostgreSQL 实例之一来解决此问题,而不是在每个 Discourse Droplet 上运行单独的数据库。
通过转到 DigitalOcean 控制面板来设置 DigitalOcean Managed PostgreSQL 实例。 单击 Databases,然后单击 Create Database Cluster,最后选择 PostgresSQL,设置区域以匹配您的 Droplet 的位置,然后单击 Create a Database Cluster ]。
在配置数据库时,将您的 Droplet 作为可信来源添加到您的数据库中。 这将允许您的 Droplet 使用 DigitalOcean 的安全专用网络与您的数据库进行通信。
在下一个屏幕上选择 VPC Network 并记下数据库主机、用户名、密码和端口的值,因为您需要将这些添加到您的 containers/app.yml
文件中。
创建数据库集群后,您需要更新 Discourse 的配置。 打开containers/app.yml
:
sudo nano containers/app.yml
在 templates
部分中,注释掉 - templates/postgres.template.yml
行,如下所示:
容器/app.yml
templates: # - "templates/postgres.template.yml" - "templates/redis.template.yml" - "templates/web.template.yml" - "templates/web.ratelimited.template.yml" - "templates/loadbalancer.template.yml"
这可以防止 Discourse 在重建时提供自己的 Postgres 服务器。
接下来,查找 containers/app.yml
的 env
部分并添加以下行,将这些值替换为您自己的数据库用户名、密码、主机、名称和端口值。
容器/app.yml
env: DISCOURSE_DB_USERNAME: your_db_username DISCOURSE_DB_PASSWORD: your_db_password DISCOURSE_DB_HOST: your_db_host DISCOURSE_DB_NAME: your_db_name DISCOURSE_DB_PORT: your_db_port
这些额外的变量允许您的 Droplet 连接到您的外部数据库。
按 CTRL+X
然后按 y
保存文件。
如果您有预先存在的 Discourse 安装,您应该将其导出为备份。 您可以通过转到您网站的管理区域,单击 Backups,然后单击 Backup 来完成此操作。
注意:有关备份和恢复站点的更多信息,请参阅Discourse产品文档,将您的Discourse实例移动到不同的服务器。
要应用配置并重建 Discourse,请运行以下命令:
sudo ./launcher rebuild app
即使您导出了站点,您也必须重新安装 Discourse 网络以创建新的管理员帐户。 既然您已连接到新数据库,您就可以使用此帐户恢复 Discourse。
最后,您将更改一项设置以确保用户在访问该站点时停留在同一个 Droplet 上。
返回到 DigitalOcean 控制面板中的负载均衡器设置。 转到 Networking,然后是 Load Balancers,然后是 Settings,然后查找 Sticky Sessions。 单击编辑。
将 Sticky Sessions 从 none 更改为 Cookie 并单击 Save。
粘性会话确保通过负载均衡器访问您网站的每个用户在访问期间保持连接到同一个 Droplet。 这很重要,因为每个 Droplet 仍然有自己的 Redis 实例,而 Redis 是 Discourse 在用户登录时跟踪用户的方式。 如果没有粘性会话,用户可以登录一个 Droplet,然后访问一个新页面并(他们不知道)交换到他们未登录的另一个 Droplet。 Sticky Sessions 通过将用户保持在同一个 Droplet 上来防止这种情况。
正如我们对数据库所做的那样,您可以将 Redis 移至其自己的专用实例,然后您就不需要 Sticky Sessions。 您可以在下一步中尝试此操作。
第 5 步 - (可选)添加 DigitalOcean 托管 Redis 实例
此步骤是可选的,需要一个 DigitalOcean Managed Redis 实例。 直到此时,Redis 实例被烘焙到负载均衡器后面的 Droplet 中,这需要粘性会话来确保用户保持登录状态。 如果 Droplet 出现故障,负载均衡器将在剩余的 Droplet 之间共享用户。 但是,在之前的设置中,用户一旦切换 Droplet 就会被注销,因为他们的会话信息存储在 Droplet 上。
在 Droplets 外部添加一个 Redis 服务器可以解决这个问题。 这将有效地将 Discourse 的状态从您的 Droplets 中移开。 如果 Droplet 离线,您的用户不会被注销——事实上,他们甚至不会注意到。
您可以像创建托管 PostgreSQL 数据库一样设置 DigitalOcean 托管 Redis 服务器。 转到 DigitalOcean 控制面板。 单击 Databases,然后单击 Create,然后单击 Database,然后为您的数据库引擎选择 Redis。 选择与您的其他资源相同的区域,以确保它们位于同一个 VPC 网络 上。 为您的服务器命名,然后单击 创建数据库集群 。
就像在创建 Postgres 数据库时一样,您会看到一个带有一些 Getting Started 步骤的欢迎屏幕。 点击 Secure this database cluster,输入你的 Droplet 的名称,然后点击 Allow these inbound sources only 。 这确保只有你的 Droplet 可以连接到 Redis。
现在您需要为您的 Redis 服务器选择驱逐策略。 选择 allkeys-lru。 此策略意味着,如果您的 Redis 服务器已满,它将开始删除其最旧的条目。 这将注销一段时间未使用您的网站的用户,但总比让 Redis 返回错误并停止工作要好。
保存您的驱逐政策。 与您的 PostgreSQL 数据库一样,在 Connection details 屏幕上,选择 VPC network。
创建 Redis 实例后,您需要更新 Discourse 配置。 使用 nano
打开 containers/app.yml
:
sudo nano containers/app.yml
将 Redis 连接详细信息添加到 env
部分,如下所示。 请务必用您自己的信息替换突出显示的文本。 (您不需要包含用户名字段。)
容器/app.yml
env: DISCOURSE_REDIS_HOST: your_redis_host DISCOURSE_REDIS_PASSWORD: your_redis_password DISCOURSE_REDIS_PORT: your_redis_port DISCOURSE_REDIS_USE_SSL: true
接下来,在 templates
部分中,注释掉 - templates/redis.template.yml
行,如下所示:
容器/app.yml
templates: # - "templates/postgres.template.yml" # - "templates/redis.template.yml" - "templates/web.template.yml" - "templates/web.ratelimited.template.yml" - "templates/loadbalancer.template.yml"
这可以防止 Discourse 创建自己的 Redis 实例。
按 CTRL+X
然后按 y
保存并关闭文件。
要应用配置并重建 Discourse,请运行以下命令:
sudo ./launcher rebuild app
使用托管 Redis 实例,您不再需要粘性会话。 如果您愿意,您可以关闭该选项,但您的用户不会注意到任何一种方式的差异。
现在您已将托管数据库添加到您的配置中,您将创建 Discourse 服务器的快照以添加更多 Droplet。
第 6 步 — 添加额外的液滴
在这一步中,您将创建 Discourse Droplet 的 快照,这使得创建新服务器更容易。 snapshot 提供现有 Droplet 的完整副本,您可以使用它们创建具有相同内容的新 Droplet。
通过转到 DigitalOcean 控制面板创建新快照。 单击 Droplet,找到您的 Droplet,然后单击 Snapshots。 为您的快照命名,然后单击 Take live snapshot。
您可以使用此快照在负载均衡器后面添加额外的 Droplet 并增加网站的容量。
每次创建新的 Droplet 时,都需要更新 Postgres 和 Redis 服务器上的可信源,这可以通过控制面板进行。 与上一步一样,选择要修改的数据库实例,转到 Overview,然后 Secure this database cluster。 将新的 Droplet IP 地址添加到可信来源列表中。
在此步骤中,您使用快照创建额外的 Droplet,并将它们作为可信源添加到您的 PostgreSQL 和 Redis 实例中。
结论
在本教程中,您在 DigitalOcean 负载均衡器后面设置了一个 Discourse 服务器。 为了帮助扩展您的部署,您还添加了托管 PostgreSQL 数据库和托管 Redis 实例。 最后,使用快照和控制面板,您添加了更多 Droplet。 使用控制面板,您可以随着社区的发展添加更多资源。
现在您已经设置了负载均衡器,您可以探索 DigitalOcean 负载均衡器 的其他 用例,例如 Canary 部署。 您还可以按照教程 如何使用 Stunnel 和 redis-cli 通过 TLS 连接到托管 Redis 实例,尝试使用命令行连接到您的 Redis 实例。 最后,您还可以通过 Managed Databases Documentation 和教程 Managed Databases Connection Pools and PostgreSQL Benchmarking Using pgbench 了解有关 DigitalOcean 的数据库及其性能的更多信息。