获取python docker容器与redis docker容器进行交互

时间:2019-01-11 16:07:01

标签: python docker redis containers

我对docker,redis和任何类型的网络都是陌生的(至少我了解python!)。首先,我想出了如何获取redis docker映像并将其在docker容器中运行:

docker run --name some-redis -d redis

据我了解,此Redis实例具有可用于连接其他容器的端口6379。

docker network inspect bridge

   "Containers": {
        "2ecceba2756abf20d5396078fd9b2ecf0d60ab04ca6b8df5e1b631b6fb5e9a85": {
            "Name": "some-redis",
            "EndpointID": "09f0069dae3632a2456cb4d82ad5e7c9782a2b58cb7a4ee655f57b5c410c3e87",
            "MacAddress": "02:42:ac:11:00:02",
            "IPv4Address": "172.17.0.2/16",
            "IPv6Address": ""
        }

如果我运行以下命令,则可以与redis实例进行交互并生成key:value对:

docker run -it --link some-redis:redis --rm redis redis-cli -h redis -p 6379
set 'a' 'abc'
>OK
get 'a'
>"abc"
quit

我已经弄清楚如何制作并运行安装了redis库的docker容器,该容器将运行python脚本,如下所示:

这是我的Dockerfile:

FROM python:3
ADD redis_test_script.py /
RUN pip install redis 
CMD [ "python", "./redis_test_script.py" ]

这是redis_test_script.py:

import redis
print("hello redis-py")

构建docker映像:

docker build -t python-redis-py .

如果我运行以下命令,脚本将在其容器中运行:

docker run -it --rm --name pyRed python-redis-py

并返回预期值:

>hello redis-py

似乎两个容器都可以正常工作,问题是将两个容器都连接在一起,我想最终使用python对redis容器执行操作。如果我按以下方式修改脚本并为python容器重建图像,则它将失败:

import redis
print("hello redis-py")
r = redis.Redis(host="localhost", port=6379, db=0)
r.set('z', 'xyz')
r.get('z')

我遇到几个错误:

...
OSError: [Errno 99] Cannot assign requested address
...
redis.exceptions.ConnectionError: Error 99 connecting to localhost:6379. Cannot assign requested address.
.....

似乎他们没有连接,我在python脚本中使用网桥IP再次尝试:

r = redis.Redis(host="172.17.0.0/16", port=6379, db=0)

并收到此错误:

redis.exceptions.ConnectionError: Error -2 connecting to 172.17.0.0/16:6379. Name or service not known.

我尝试了redis子IP:

r = redis.Redis(host="172.17.0.2/16", port=6379, db=0)

我得到这个错误:

redis.exceptions.ConnectionError: Error -2 connecting to 172.17.0.2/16:6379. Name or service not known.

感觉像是我从根本上误解了如何使容器彼此对话。我已经阅读了很多文档和教程,但是正如我所说,他们没有网络经验,并且以前没有使用过docker,因此任何有用的解释和/或解决方案都非常好。

非常感谢

2 个答案:

答案 0 :(得分:2)

关于Docker网络的全部内容。快速解决方案-对两个容器都使用host网络模式。缺点是隔离度低,但是您可以使其快速运行:

docker run -d --network=host redis ...
docker run --network=host python-redis-py ...

然后从python连接到redis只需使用localhost作为主机名。

更好的解决方案是使用docker用户定义的网桥

# create network
docker network create foo
docker run -d --network=foo --name my-db redis ...
docker run    --network=foo python-redis-py ...

请注意,在这种情况下,您不能使用localhost,而是使用my-db作为主机名。这就是为什么我在启动第一个容器时使用--name my-db参数的原因。在用户定义的桥网络中,容器通过它们的名称相互访问。

答案 1 :(得分:2)

执行

  • 为您的应用程序明确创建一个Docker网络,并运行连接到该网络的容器。 (如果您使用Docker Compose,这将自动为您发生,您无需执行任何操作。)

    docker network create foo
    docker run -d --net foo --name some-redis redis
    docker run -it --rm --net foo --name pyRed python-redis-py
    
  • 使用容器的--name作为DNS主机名:您连接到some-redis:6379以访问容器。 (在Docker Compose中,服务块的名称也适用。)

  • 使外部服务的位置可配置,最有可能使用环境变量。在您的Python代码中,您可以连接到

    redis.Redis(host=os.environ.get("REDIS_HOST", "localhost"),
                port=int(os.environ.get("REDIS_PORT", "6379"))
    
    docker run --rm -it \
      --name py-red \
      --net foo \
      -e REDIS_HOST=some-redis \
      python-redis-py
    

不要:

  • docker inspect用于查找容器专用IP地址的任何内容。在容器之间,您始终可以如上所述使用主机名。容器专用IP地址无法从其他主机访问,甚至在某些平台上也不能从相同主机访问。

  • 在Docker中使用localhost进行任何操作,期望从主机(不是在容器中)直接在主机上运行浏览器或其他进程 到端口的连接的特定情况您已与docker run -p在同一主机上发布。 (通常指“此容器”。)

  • 您的代码中的硬编码主机名是这样的;这使得在不同的环境中运行服务变得困难。 (特别是对于数据库,通常在Docker之外甚至在托管的云服务中运行它们。)

  • 使用--link,它已经过时且不必要。