升级后运行多个容器时出现防火墙问题

我在升级过程中遇到了一些问题:第一个论坛在首次尝试升级(通过仪表板)时失败,随后通过重建再次失败,但在第二次重建尝试中似乎成功了,尽管之后我又不得不额外重建一次。这让我想起,在进行 PG12 更新升级时,我需要停止所有 Discourse 实例(该服务器上有三个独立的 Discourse 论坛容器)。因此,以下操作对另外两个论坛有效:

然而,出于某种原因,第一个论坛现已无法访问,Safari 提示服务器意外断开了连接。执行重建似乎顺利,但论坛仍无法访问。我可以进入应用和 Rails 控制台,数据库看起来也完好无损。

重建过程中看到的唯一可能与问题相关的警告如下:

168:M 31 Jan 2021 21:39:22.459 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
168:M 31 Jan 2021 21:39:22.459 # Server initialized
168:M 31 Jan 2021 21:39:22.459 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
168:M 31 Jan 2021 21:39:22.459 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled (set to 'madvise' or 'never').
168:M 31 Jan 2021 21:39:22.459 * Loading RDB produced by version 6.0.9
168:M 31 Jan 2021 21:39:22.459 * RDB age 21 seconds
168:M 31 Jan 2021 21:39:22.459 * RDB memory usage when created 4.03 Mb
168:M 31 Jan 2021 21:39:22.466 * DB loaded from disk: 0.006 seconds
168:M 31 Jan 2021 21:39:22.466 * Ready to accept connections

production.log 内容如下:


Job exception: Error connecting to Redis on localhost:6379 (Errno::ENETUNREACH)

Error connecting to Redis on localhost:6379 (Errno::ENETUNREACH) subscribe failed, reconnecting in 1 second. Call stack /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/redis-4.2.5/lib/redis/client.rb:367:in `rescue in establish_connection'

类似的错误信息也出现在 unicorn.stderr.logunicorn.stdout.log 中。

进入容器并执行 redis-cli ping,我收到了 PONG 响应。Redis 正在服务器上运行(但不在各个容器中运行——据我所知,这一直是这种情况)。

大家有什么想法,这可能是什么问题吗?

(我还重启了服务器,并为该域名重新创建了新的 letsencrypt 证书以确保安全,但问题依旧。)

1 个赞

看起来一切应该都能正常工作……您是否尝试过更换浏览器或清除缓存?如果这没有帮助,能否请您发布以下命令的输出结果:

curl -vv -o /dev/null <forum url>
2 个赞

我在多个浏览器上尝试过,但得到的结果都一样(Michael)。这是该命令的输出:

~$ curl -vv -o /dev/null https://metaruby.com
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 78.46.110.60...
* TCP_NODELAY set
* Connected to metaruby.com (78.46.110.60) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
} [226 bytes data]
* TLSv1.2 (IN), TLS handshake, Server hello (2):
{ [93 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [2473 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [333 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [70 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
{ [1 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=metaruby.com
*  start date: Jan 31 03:33:05 2021 GMT
*  expire date: May  1 03:33:05 2021 GMT
*  subjectAltName: host "metaruby.com" matched cert's "metaruby.com"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
> GET / HTTP/1.1
> Host: metaruby.com
> User-Agent: curl/7.64.1
> Accept: */*
> 
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0* TLSv1.2 (IN), TLS alert, close notify (256):
{ [2 bytes data]
* Empty reply from server
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
* Connection #0 to host metaruby.com left intact
curl: (52) Empty reply from server
* Closing connection 0
1 个赞

可能导致空响应错误的一些原因:

  1. 服务器位于 VPN 中,无法访问该端口。
  2. 如果同一台服务器上有多个 Discourse 实例,我假设前面有反向代理。请确保它指向 Discourse 容器(您可能需要重启它)。
  3. 服务器空间不足(您可以运行 df -hT / 检查)。

我建议首先查看可用磁盘空间(第 3 点)。

2 个赞

磁盘使用率显示为 31%,但我还是执行了 ./launcher cleanup

docker container ls 
(确保三个论坛容器都在运行)

./launcher cleanup

警告!这将删除所有已停止的容器。
您确定要继续吗?[y/N] y
总共释放空间:0B
警告!这将删除所有未关联任何容器的镜像。
您确定要继续吗?[y/N] y
已删除的镜像:
...
总共释放空间:32.56GB

我们使用 HAProxy,我已检查并重启了它,目前它正在运行(我们也在通过它进行从 HTTP 到 HTTPS 的重定向,该功能对域名同样正常工作,因此我认为问题不在这里——而且在此次更新之前一切正常)。

我仍然可以进入容器并访问 Rails 控制台,数据库也依然存在且与容器连接正常——这实在非常奇怪——有人有其他想法或排查步骤吗?

1 个赞

如果您无法通过调试查明问题,一种可行的方案是从命令行备份数据,并将其恢复到运行 PG13 的全新站点上。或者,如果您需要尽快让站点恢复运行,可以将版本回退至 PG12,将现有的 shared/postgres_data_old 目录移回 shared/postgres_data,然后重新构建。不过,我建议优先尝试备份/恢复方案,因为问题似乎与数据库升级本身无关。

3 个赞

您这里的情况已经超出了标准支持的安装范围了。:slight_smile:

每个 Discourse 实例都有独立的 PostgreSQL,还是三个实例共用一个 PostgreSQL?

如果您确实只有一个 PostgreSQL/数据容器,那么在尝试升级 PostgreSQL 之前,请先停止所有 Discourse 实例。

HaProxy 与 PostgreSQL 无关,所以我认为这并不重要。

3 个赞

如果你还有其他排查思路,我很乐意尝试,Michael。幸运的是,这个论坛离线并不是什么大事,因为它原本就处于只读模式(已被另一个论坛取代)。

如果你已经想不出其他办法,那我就去尝试恢复备份。但如果可能的话,我还是希望能排查一下这个问题,因为我很想知道为什么会发生这种情况(我想你可能也一样)。所以,如果你也愿意深入调查,我绝对支持。

说实话,这让我对将其他一些论坛迁移到 Discourse 感到有些担忧。了解问题出在哪里对我们大家都有帮助。

这是一个标准的多容器安装方案,每个论坛都有独立的 app.yml 文件,并基于 host: discourse/shared-site-name/standalonehost: discourse/shared-site-name/standalone/log/var-log 的容器配置(正如我之前在论坛提问和发帖所讨论的那样)。

进入每个容器并执行 psql 命令(sudo -u postgres psql discourse)以及 \\l+,结果显示每个容器中只有一个 discourse 数据库(且每个数据库的大小都不同),因此我推测这些是独立的 Discourse 实例。

你是否有运行多个独立 Discourse 论坛的“标准”方法的链接?我可以检查一下是否与我的配置一致,不过我相当确定我的配置是基于 Discourse 团队的帖子和指导构建的。

2 个赞

您是在容器内运行 nginx 吗?接下来我建议追踪请求最终被路由到了哪里。据我理解,您使用 HAProxy 进行 SSL 终止,然后将请求代理到相应的容器中,对吗?

3 个赞

啊,好的。所以对于每个应用,你应该运行两次 ./launcher rebuild YOUR-APP-NAME。我认为无法通过网页界面完成此操作。

另外,yml 容器中的 ssl 和 letsencrypt 模板是否都被注释掉了(或删除了)?

2 个赞

据我所知,容器本身都是“标准”配置(所以我推测每个容器都在运行 nginx),是的,HAProxy 处理所有 SSL 并将请求分发到各个容器。

我的设置完全按照这里的指南:https://meta.discourse.org/t/how-to-set-up-discourse-on-a-server-with-existing-apache-sites/30013(其中 SSL 版本的 HAProxy 配置见此处)。

HAProxy 配置曾出现过一个问题:

backend main_apache_sites
  server server1 127.0.0.1:8080 cookie A check
  cookie JSESSIONID prefix nocache

backend discourse_docker
  server server2 127.0.0.1:8888 cookie A check
  cookie JSESSIONID prefix nocache

backend discourse_docker_2
  server server2 127.0.0.1:8889 cookie A check
  cookie JSESSIONID prefix nocache

backend discourse_docker_3
  server server2 127.0.0.1:8890 cookie A check
  cookie JSESSIONID prefix nocache

backend letsencrypt-backend
  server letsencrypt 127.0.0.1:54321

不知为何,所有 Discourse 后端在第二行都配置为 server2。我昨天将它们分别改为了 server2server3 等,但这并没有带来任何改变(而且之前这样配置时一切正常)。

有没有特定的日志文件可以查看,以提供更多线索?也许是 Docker 日志文件?

是的,这些都已注释掉:

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## 如果希望添加 Lets Encrypt (https),请取消以下两行的注释
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"
1 个赞

应用容器内的 nginx 日志应能确认请求是否已到达应用程序,您能检查一下吗?容器中的 nginx 会将请求代理到 127.0.0.1:3000,即 unicorn 进程。

1 个赞

查看 /var/log/nginx/shared/log/rails 目录,并没有发现任何异常。事实上,除了 /shared/log/rails/production.log 外,今天(4 日)没有任何日志更新,而该日志中仅包含几条类似这样的任务记录:

Rails 日志:

Nginix 日志:

我还修改了 HAProxy 中的端口,结果按预期出现了“服务器未找到”的错误。随后我将容器更新为相同的端口,行为又恢复到了原来的状态(因此我认为可以排除 HAProxy 的问题)。

是否有 Docker 日志可供查看?或者我能否保存/导出此容器并发送给您,以便您检查?我想您和我一样好奇到底出了什么问题 :blush:

1 个赞

实际上我刚又看了一眼(上面的是昨晚的),现在在:

unicorn.stderr.log

(抱歉,它不允许我复制文本)

今天没有任何 nginx 日志被修改过,不过 1 月 30 日的最后一条日志显示:7: limiting requests by zone “flood” client: my.ip.address, POST /mini-profiler-resources 类型错误。

编辑:不确定这是否有帮助,但运行 docker logs APP 的结果如下:

论坛无法访问时:

# docker logs metaruby
run-parts: executing /etc/runit/1.d/00-ensure-links
run-parts: executing /etc/runit/1.d/00-fix-var-logs
run-parts: executing /etc/runit/1.d/01-cleanup-web-pids
run-parts: executing /etc/runit/1.d/anacron
run-parts: executing /etc/runit/1.d/cleanup-pids
Cleaning stale PID files
run-parts: executing /etc/runit/1.d/copy-env
Started runsvdir, PID is 43
ok: run: redis: (pid 55) 0s
ok: run: postgres: (pid 56) 0s
chgrp: invalid group: ‘syslog’
supervisor pid: 50 unicorn pid: 89

论坛 2(运行正常):

# docker logs f2

run-parts: executing /etc/runit/1.d/00-ensure-links

run-parts: executing /etc/runit/1.d/00-fix-var-logs

run-parts: executing /etc/runit/1.d/01-cleanup-web-pids

run-parts: executing /etc/runit/1.d/anacron

run-parts: executing /etc/runit/1.d/cleanup-pids

Cleaning stale PID files

run-parts: executing /etc/runit/1.d/copy-env

Started runsvdir, PID is 42

ok: run: redis: (pid 55) 0s

ok: run: postgres: (pid 54) 0s

chgrp: invalid group: ‘syslog’

supervisor pid: 51 unicorn pid: 82

(51) Reopening logs

(51) Reopening logs

(51) Reopening logs

(51) Stopping Sidekiq

(51) Reloading unicorn (82)

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid... 22039

(51) Old pid is: 82 New pid is: 22039

(51) Stopping Sidekiq

(51) Reloading unicorn (22039)

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid...

(51) Waiting for new unicorn master pid... 23358

(51) Old pid is: 22039 New pid is: 23358

(51) Reopening logs

(51) Reopening logs

论坛三(也运行正常):

# docker logs f3

run-parts: executing /etc/runit/1.d/00-ensure-links

run-parts: executing /etc/runit/1.d/00-fix-var-logs

run-parts: executing /etc/runit/1.d/01-cleanup-web-pids

run-parts: executing /etc/runit/1.d/anacron

run-parts: executing /etc/runit/1.d/cleanup-pids

Cleaning stale PID files

run-parts: executing /etc/runit/1.d/copy-env

Started runsvdir, PID is 42

ok: run: redis: (pid 54) 0s

chgrp: invalid group: ‘syslog’

ok: run: postgres: (pid 55) 0s

supervisor pid: 56 unicorn pid: 88

(56) Reopening logs

(56) Reopening logs

(56) Reopening logs

(56) Reopening logs

(56) Reopening logs
1 个赞

查看日志并回顾你之前的回复——应用程序试图在容器内的 localhost:6379 访问 Redis,而且 Redis 似乎启动正常,但不知为何无法连接(令人困惑)。不过,这些错误信息也可能是 message_bus 在 Redis 启动前尝试连接,或在重启事件中 Redis 停止后尝试连接时产生的。

你提到 Redis 在服务器上运行但不在各个容器中运行——能否详细说明一下?

使用此配置,Redis 将在容器内运行(你可以在 Docker 日志输出中看到这一点)。

另外,当你访问无法正常工作的网站 URL 时,nginx 日志中显示了什么?error.log 应该是空的,而 access.log 应包含各种 HTTP 请求。我们只是想确定问题具体出在哪个环节。

1 个赞

抱歉,我之前搞混了。实际上 Redis 在每个容器中都在运行,这一点通过在服务器本身以及三个 Discourse 容器分别执行以下命令并得到相同输出得到了验证:

$ redis-cli ping
PONG
$ redis-server
# Creating Server TCP listening socket *:6379: bind: Address already in use (means it's already started)
$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> get mykey
(nil)
127.0.0.1:6379> set mykey somevalue
OK
127.0.0.1:6379> get mykey
"somevalue"

所有三个容器的情况都是如此(值得注意的是,第一次 get mykey 总是返回 nil),因此可以确定 Redis 在所有容器中都已启动并独立运行。

该目录中今天没有任何写入内容,日志文件为空:

drwxr-xr-x 2 www-data www-data  4096 Feb  4 21:26 .
drwxrwxr-x 9 root     root      4096 Feb  2 08:03 ..
-rw-r--r-- 1 www-data www-data     0 Feb  3 07:38 access.log
-rw-r--r-- 1 www-data www-data     0 Feb  2 08:03 access.log.1
-rw-r--r-- 1 www-data www-data   294 Feb  1 09:43 access.log.2.gz
-rw-r--r-- 1 www-data www-data 37598 Jan 30 23:56 access.log.3.gz
-rw-r--r-- 1 www-data www-data 58059 Jan 30 07:36 access.log.4.gz
-rw-r--r-- 1 www-data www-data 55988 Jan 29 07:34 access.log.5.gz
-rw-r--r-- 1 www-data www-data 73964 Jan 28 07:49 access.log.6.gz
-rw-r--r-- 1 www-data www-data 78069 Jan 27 07:53 access.log.7.gz
-rw-r--r-- 1 www-data www-data     0 Feb  3 07:38 error.log
-rw-r--r-- 1 www-data www-data     0 Feb  2 08:03 error.log.1
-rw-r--r-- 1 www-data www-data    20 Feb  1 00:31 error.log.2.gz
-rw-r--r-- 1 www-data www-data   632 Jan 30 23:46 error.log.3.gz
-rw-r--r-- 1 www-data www-data   265 Jan 29 09:07 error.log.4.gz
-rw-r--r-- 1 www-data www-data    20 Jan 28 07:50 error.log.5.gz
-rw-r--r-- 1 www-data www-data  3107 Jan 28 07:41 error.log.6.gz
-rw-r--r-- 1 www-data www-data    20 Jan 26 07:53 error.log.7.gz

我检查了另一个容器的访问日志,一切正常,所以问题仅出现在这个容器上。

看起来 HAProxy 已经将请求转发过去了,但该容器似乎无法处理或接收它。不知道是否有什么可以重置的地方?(我本来以为重建容器应该会自动完成这些操作吧?)

1 个赞

听起来确实如此。能否确认在主机上运行 docker ps 时,每个容器存在哪些端口绑定?

1 个赞

好的:

IMAGE                   COMMAND             CREATED             STATUS              PORTS
local_discourse/1      "/sbin/boot"        20 小时前           运行中 20 小时       0.0.0.0:2225->22/tcp, 0.0.0.0:8892->80/tcp
local_discourse/2      "/sbin/boot"        4 天前              运行中 4 天         0.0.0.0:2223->22/tcp, 0.0.0.0:8889->80/tcp
local_discourse/3      "/sbin/boot"        4 天前              运行中 4 天         0.0.0.0:2224->22/tcp, 0.0.0.0:8890->80/tcp

我直觉认为这与通过仪表板进行的失败操作有关。通常,在进行 PostgreSQL 或重大更新时,仪表板会提示您需要执行重建,并且会禁用通过仪表板进行更新的功能。但不知为何这次没有提示(也许是因为我很久没有更新该论坛了,所以我认为应该先通过仪表板操作),或者可能是因为在执行重建之前,服务未能正确关闭或启动 :confused:

2 个赞

在 HAProxy 配置中,我看到后端被配置为转发到端口 888888898890

然而,应用容器监听的是 889288898890 —— backend discourse_docker 似乎存在不一致。自从该帖子发布以来,您是否在配置中对此进行了更新?

1 个赞

是的,HAProxy 端口确实对应正确的容器端口 :smiley: 我相当确定这与这个问题无关,因为之前一切正常——问题只是在那次升级/重建之后才出现的。

进入容器并打开 Top 统计,然后访问网站似乎也没有任何区别。如果这对你有帮助,这里有一张截图:

如果对你来说更方便的话,我很乐意“保存”这个容器并发送给你(Docker 容器真的可以这样做吗?哈哈!):slight_smile:

1 个赞