如何从 Django-Channels 库中获取通道层,以便使用 Docker Toolbox 与 Oracle VM 中的 Redis 进行通信?

如何从 Django-Channels 库中获取通道层,以便使用 Docker Toolbox 与 Oracle VM 中的 Redis 进行通信?

我正在使用 Django Channels,并试图确保通道层可以与 Redis 通信。但是,我使用的是 Windows 10 Home 版,这意味着我必须使用 Docker Toolbox 创建 Oracle VM Virtualbox,这样我才能在 Linux 环境中运行 Redis。我的 Django 项目在桌面上有自己的虚拟环境,而 Redis 在 Docker Toolbox 上运行。我完全遵循 django-channels 教程:https://channels.readthedocs.io/en/latest/tutorial/part_2.html

最初,我运行了$ docker run -p 6379:6379 -d redis:2.8,它什么也没做,只是为我创建了 docker 镜像。但是,我运行了

$ docker run -p 6379:6379 redis:2.8

这启动了端口,这很好。不确定这是否与此有关,在 redis 服务器能够接受端口 6379 上的连接之前,我收到了以下响应:

[1] 08 Aug 21:12:19.210 # Server started, Redis version 2.8.23
[1] 08 Aug 21:12:19.211 # 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.
[1] 08 Aug 21:12:19.211 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
[1] 08 Aug 21:12:19.212 * The server is now ready to accept connections on port 6379

下一部分我按照教程运行了以下内容:

$ python3 manage.py shell
>>> import channels.layers
>>> channel_layer = channels.layers.get_channel_layer()
>>> from asgiref.sync import async_to_sync
>>> async_to_sync(channel_layer.send)('test_channel', {'type': 'hello'})

我收到了这个错误信息:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\asgiref\sync.py", line 110, in __call__
    return call_result.result()
  File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\concurrent\futures\_base.py", line 425, in result
    return self.__get_result()
  File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\concurrent\futures\_base.py", line 384, in __get_result
    raise self._exception
  File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\asgiref\sync.py", line 142, in main_wrap
    result = await self.awaitable(*args, **kwargs)
  File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\channels_redis\core.py", line 293, in send
    async with self.connection(index) as connection:
  File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\channels_redis\core.py", line 820, in __aenter__
    self.conn = await self.pool.pop()
  File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\channels_redis\core.py", line 70, in pop
    conns.append(await aioredis.create_redis(**self.host, loop=loop))
  File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\aioredis\commands\__init__.py", line 178, in create_redis
    loop=loop)
  File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\aioredis\connection.py", line 108, in create_connection
    timeout, loop=loop)
  File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\tasks.py", line 339, in wait_for
    return (yield from fut)
  File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\aioredis\stream.py", line 19, in open_connection
    lambda: protocol, host, port, **kwds)
  File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\base_events.py", line 778, in create_connection
    raise exceptions[0]
  File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\base_events.py", line 765, in create_connection
    yield from self.sock_connect(sock, address)
  File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\selector_events.py", line 450, in sock_connect
    return (yield from fut)
  File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\selector_events.py", line 480, in _sock_connect_cb
    raise OSError(err, 'Connect call failed %s' % (address,))
ConnectionRefusedError: [Errno 10061] Connect call failed ('127.0.0.1', 6379)

只是想确认我在 settings.py 上确实设置了以下内容:

# mysite/settings.py
# Channels
ASGI_APPLICATION = 'mysite.routing.application'
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

这是因为我的项目不在 Redis 所在的同一 VM 容器中吗?我认为这没关系,因为它是它自己的服务器,我正尝试与本地主机进行通信。

任何帮助将不胜感激...

答案1

这很可能是由于 Docker Toolbox 的工作方式造成的(有同样的问题)。

Docker Toolbox 使用 VirtualBox 作为虚拟化解决方案,它使用自己的 IP 创建自己的虚拟网络设备。

解决方案

  1. 对属于docker容器的IP进行硬编码,如Docker Quickstart Terminal启动后所示。


                        ##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
           \______ o           __/
             \    \         __/
              \____\_______/

docker is configured to use the default machine with IP xxx.xxx.xxx.xxx
For help getting started, check out the docs at https://docs.docker.com


Start interactive shell
$
  1. 从环境变量中提取IP DOCKER_HOST,例如:
import os
import re

def get_docker_ip():
    docker_host = os.environ.get("DOCKER_HOST", "127.0.0.1")
    docker_ip = re.search(r"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", docker_host)
    return docker_ip.group(1)
  1. 使用Docker Desktop for Windows使用 Hyper-v(Microsoft 虚拟化解决方案),因为它绑定到本地主机。

    请注意,使用 Hyper-v 会破坏 VirtualBox,因为它们不能很好地协同运行。

    如果你仍想同时使用两者,则需要根据要使用的内容停用/激活 Hyper-v 并重新启动,如本指南

答案2

我按照下面的建议对 IP 进行了硬编码,并且成功了。在设置 CHANNEL_LAYERS 配置中添加 IP。

CHANNEL_LAYERS = {
'default': {
    'BACKEND': 'channels_redis.core.RedisChannelLayer',
    'CONFIG': {
        'hosts': [('xxx.xxx.xxx.xxx', 6379)],
    },
},

}

非常感谢。Adrian

相关内容