想问问是否有人在自己的独立容器中使用 unixsocket /var/discourse/shared/... 来连接 Redis?看起来 redis-rb 也支持通过域套接字连接,用法如下:
redis = Redis.new(path: "/var/discourse/shared/standalone/redis.sock")
根据 这篇 Medium 文章 的说法,通过 Unix 域套接字连接比使用 TCP 套接字快约 20%……
此外,使用 Unix 域套接字会让在同一主机上运行多个独立容器变得更加容易,而无需将 Web 容器与数据容器分离。否则,你可能会遇到 Redis 监听 127.0.0.1 导致的冲突……
我目前正尝试在一台主机上部署两个完全独立的容器,由于它们都用于非常小的站点,我更希望保持它们在独立容器中运行的灵活性……但不幸的是,如果 Redis(可能还有 Postgres)监听 127.0.0.1,将会产生冲突。
1 个赞
neounix
(Dark Matter)
2020 年6 月 5 日 14:36
2
你好 @ryanerwin
看来你对容器和 Docker 的理解还不够深入,让我来帮你解答一下。
Redis 默认在独立容器中运行,监听端口为 6379:
cd /var/discourse
./launcher enter app
apt install net-tools
netstat -an | grep :6379 |wc -l
74
现在退出容器并检查 Redis 的 netstat 状态:
exit
root@localhost:/var/discourse# netstat -an | grep :6379 |wc -l
0
你可以看到,Redis 在容器内部监听的是 localhost;而容器内的 localhost 并未(也从未)被暴露到容器外部。
因此,如果你运行多个独立的 Discourse 容器,容器之间不会出现 Redis 冲突,因为 Redis 并未被暴露到每个容器之外。
这就是为什么它被称为“容器”……
容器内的每个套接字都必须显式暴露,才能在容器外部可用。
希望这对大家有一点帮助。
注意,Unix 域套接字非常酷……我只是针对你关于独立容器之间感知到的 Redis 冲突的评论进行了回应,并未涉及 Unix 域套接字这个话题。
5 个赞
我原本以为在 Docker 中运行 Discourse 也会是这样,但实际运行时,在引导过程中我看到了:
INFO -- : > cd /var/www/discourse && git reset --hard
# oO0OoO0OoO0Oo Redis 正在启动 oO0OoO0OoO0Oo
# Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=195, just started
# Configuration loaded
# Could not create server TCP listening socket *:6379: bind: Address already in use
Checking out files: 100% (27893/27893), done.
我还找到了这个关于“安装失败是因为其他 Redis 容器 ”的帖子,但真正的问题其实是磁盘空间不足 ……重新整理了一些内容后,多个独立容器确实可以正常运行。
2 个赞
neounix
(Dark Matter)
2020 年6 月 6 日 02:16
4
亲爱的 @ryanerwin ,
很高兴得知您已找到根本问题,并理解 Redis 是“在容器内”运行的,从套接字 I/O 的角度来看,它并未暴露在容器外部(按开箱即用的默认配置)。
关于使用 Unix 域套接字与 Redis 配合,我认为这是个很好的想法。我尚未进行过此类设置,也未查阅过任何关于如何在 Discourse 中配置此功能的文档,因此我鼓励您继续探索这一方案。
如果时间允许,我将进一步研究,并尝试在测试服务器上配置 Discourse 使用 Unix 域套接字连接 Redis。在此期间,如果您能成功实现并分享结果,我们将不胜感激。我相信许多其他人也对这个有趣的 Redis 话题感兴趣。
谢谢。
3 个赞
neounix
(Dark Matter)
2020 年6 月 6 日 09:22
5
你好 @ryanerwin ,
很高兴告诉你,我已经在独立容器中成功运行了 Discourse,并使用了 Unix 套接字连接 Redis,正如你所询问的那样。
请查看下方来自 Sidekiq 的截图底部:
此外,这里还有一些构建应用时的其他截图:
我接下来的计划是:
将 Unix 套接字移动到共享卷,以便容器外部也能访问。
使用最少的环境变量重新测试,以获取“最简”配置,使系统正常运行。
基本上,我已经创建了这个新模板:
-rw-r–r-- 1 root root 2028 Jun 6 08:13 redis.socketed.template.yml
并对老朋友 app.yml 做了少量修改。
由于我今天才开始这项工作,计划在发布详细信息之前再进行一些测试。
希望这能有所帮助。
更新
当 Unix 套接字位于共享卷上时,在容器外部也能按预期工作:
4 个赞
neounix
(Dark Matter)
2020 年6 月 6 日 12:03
6
相关 PR:
main ← unixneo:patch-1
closed 06:39AM - 06 May 24 UTC
This file adds the required directives to set up Redis in Discourse with a unix … domain socket.
See Also:
https://meta.discourse.org/t/discourse-container-with-unixsocket-for-redis/153945/5
Note:
To implement:
- Change the redis template in the container yml file
- Add one additional line to the same container yml file
```
## Set the REDIS_URL and use the ```redis.socketed.template.yml``` to use
## a unix domain socket for Redis
REDIS_URL: unix:///shared/tmp/redis.sock
```
Notes:
1. If concerned about security of the Redis DB on the host, there is no need to expose this unix socket in the shared volume.
2. If you wish to set the permissions of the unix socket to 770 (instead of 777) , change the group of the unix socket to www-data.
注意:
实施步骤:
修改容器 yml 文件中的 redis 模板
在同一容器 yml 文件中添加一行
## 设置 REDIS_URL 并使用 redis.socketed.template.yml 以使用
## Redis 的 Unix 域套接字
REDIS_URL: unix:///shared/tmp/redis.sock
实施说明:
如果担心主机上 Redis 数据库的安全性,无需在共享卷中暴露此 Unix 套接字。
如果希望将 Unix 套接字的权限设置为 770(而非 777),请将 Unix 套接字的组更改为 www-data。
4 个赞
有没有其他人注意到 REDIS_URL 不再起作用了?在(重新)构建和容器启动时,尽管 REDIS_URL 设置为通过 UNIX 套接字连接,但它仍然尝试通过 redis://localhost:6379 进行连接。
一方面,这是有道理的,因为 Discourse 有主机和端口的配置并仅应用它们:discourse/app/models/global_setting.rb at main · discourse/discourse · GitHub
会有一个 path 参数来定义 UNIX 套接字路径,它将覆盖主机和端口。并且会有一个 url 参数来定义一个完整的 URL,例如 unix:///shared/redis_data/redis.sock。
Redis gem 文档指出 REDIS_URL 环境变量将覆盖任何其他设置,并且直到某个 Discourse/Redis gem 版本之前,这都是有效的:redis-rb/lib/redis.rb at master · redis/redis-rb · GitHub
当 Discourse 迁移到 Redis gem 版本 5 时,UNIX 套接字使用中断了:DEV: Upgrade the Redis gem to v5.4 · discourse/discourse@2ed31fe · GitHub
所以我猜 REDIS_URL 是在 Redis gem 中中断的(不再覆盖其他选项),而不是 Discourse(相关的代码没有改变)?
很可能是这个提交中断了它:Use redis-client as transport · redis/redis-rb@08a2100 · GitHub
我会在 Redis gem 仓库报告这个问题,或者有人知道这是 Discourse 实现方式的问题吗?
顺便说一句,环境变量已正确传递。我将其保留,并且只配置 Redis 不监听 UNIX 套接字,虽然 unicorn 启动正常,但 sidekiq 失败,反而找不到 UNIX 套接字 :
Error in demon processes heartbeat check: No such file or directory - connect(2) for /shared/redis_data/redis.sock
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/ruby_connection.rb:116:in `initialize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/ruby_connection.rb:116:in `new'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/ruby_connection.rb:116:in `connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/ruby_connection.rb:51:in `initialize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:759:in `new'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:759:in `block in connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/middlewares.rb:12:in `connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:758:in `connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:745:in `raw_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:705:in `ensure_connected'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:285:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/redis_client_adapter.rb:36:in `block (2 levels) in <module:CompatMethods>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/api.rb:912:in `block in cleanup'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/config.rb:175:in `block in redis'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:110:in `block (2 levels) in with'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:109:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:109:in `block in with'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:106:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:106:in `with'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/config.rb:172:in `redis'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq.rb:74:in `redis'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/api.rb:912:in `cleanup'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/api.rb:903:in `initialize'
/var/www/discourse/lib/demon/sidekiq.rb:25:in `new'
/var/www/discourse/lib/demon/sidekiq.rb:25:in `heartbeat_check'
config/unicorn.conf.rb:131:in `block (2 levels) in reload'
这与 REDIS_URL 仍然有效但仅在未另外定义连接设置时才起作用的情况相符。从错误跟踪来看,global_setting.rb 没有像 unicorn 那样为主机和端口应用 sidekiq。