Docker、Django和Selenium - Selenium无法连接

3
我已经配置了Docker,使用docker-compose.yml运行Postgres和Django,它可以正常工作。但是我遇到的问题是Selenium无法连接到Django liveserver。现在对我来说很明显,Django必须访问Selenium以控制浏览器,而Selenium必须访问Django以访问服务器。我尝试使用docker的“ambassador”模式,使用以下docker-compose.yml配置,来自这里:https://github.com/docker/compose/issues/666
postgis:
  dockerfile: ./docker/postgis/Dockerfile
  build: .
  container_name: postgis

django-ambassador:
  container_name: django-ambassador
  image: cpuguy83/docker-grand-ambassador
  volumes:
    - "/var/run/docker.sock:/var/run/docker.sock"
  command: "-name django -name selenium"

django:
  dockerfile: ./docker/Dockerfile-dev
  build: .
  command: python /app/project/manage.py test my-app
  container_name: django
  volumes:
    - .:/app
  ports:
    - "8000:8000"
    - "8081:8081"
  links:
    - postgis
    - "django-ambassador:selenium"
  environment:
    - SELENIUM_HOST=http://selenium:4444/wd/hub

selenium:
  container_name: selenium
  image: selenium/standalone-firefox-debug
  ports:
    - "4444:4444"
    - "5900:5900"
  links:
    - "django-ambassador:django"

当我检查http://DOCKER-MACHINE-IP:4444/wd/hub/static/resource/hub.html时,我可以看到Firefox启动了,但是所有的测试都失败了,因为Firefox无法连接到Django。
'Firefox can't establish a connection to the server at localhost:8081'

我也尝试了这个解决方案https://github.com/docker/compose/issues/1991,但是它不起作用,因为我无法让Django同时连接到PostGIS和Selenium。
'django.db.utils.OperationalError: could not translate host name "postgis" to address: Name or service not known'

我尝试使用以下列出的网络功能。
postgis:
  dockerfile: ./docker/postgis/Dockerfile
  build: .
  container_name: postgis
  net: appnet

django:
  dockerfile: ./docker/Dockerfile-dev
  build: .
  command: python /app/project/manage.py test foo
  container_name: django
  volumes:
    - .:/app
  ports:
    - "8000:8000"
    - "8081:8081"
  net: appnet
  environment:
    - SELENIUM_HOST=http://selenium:4444/wd/hub

selenium:
  container_name: selenium
  image: selenium/standalone-firefox-debug
  ports:
    - "4444:4444"
    - "5900:5900"
  net: appnet

但结果是相同的。
'Firefox can't establish a connection to the server at localhost:8081'

那么如何让selenium连接到django呢?
我已经在尝试了几天,真的很需要帮助。
更多信息:
另一个奇怪的事情是,当测试服务器使用docker(使用旧的虚拟环境配置等)运行时,如果我运行./manage.py test foo,我可以通过http://localhost:8081在任何浏览器中访问服务器并获取网页,但是如果我在docker下运行相同的命令,则无法访问测试服务器。这很奇怪,因为我正在映射端口8081:8081 —— 这是否相关?
注意:我正在使用OSX和Docker v1.9.1
3个回答

5

我最终想到了一个更好的解决方案,不需要硬编码IP地址。以下是我在使用docker运行django测试时使用的配置。

Docker-compose文件

# docker-compose base file for everything
version: '2'

services:
  postgis:
    build:
      context: .
      dockerfile: ./docker/postgis/Dockerfile
    container_name: postgis
    volumes:
      # If you are using boot2docker, postgres data has to live in the VM for now until #581 fixed
      # for more info see here: https://github.com/boot2docker/boot2docker/issues/581
      - /data/dev/docker_cookiecutter/postgres:/var/lib/postgresql/data

  django:
    build:
      context: .
      dockerfile: ./docker/django/Dockerfile
    container_name: django
    volumes:
      - .:/app
    depends_on:
      - selenium
      - postgis
    environment:
      - SITE_DOMAIN=django
      - DJANGO_SETTINGS_MODULE=settings.my_dev_settings
    links:
      - postgis
      - mailcatcher

  selenium:
    container_name: selenium
    image: selenium/standalone-firefox-debug:2.52.0
    ports:
      - "4444:4444"
      - "5900:5900"

Dockerfile (for Django)

ENTRYPOINT ["/docker/django/entrypoint.sh"]

在入口文件中

#!/bin/bash
set -e

# Now we need to get the ip address of this container so we can supply it as an environmental
# variable for django so that selenium knows what url the test server is on
# Use below or alternatively you could have used
# something like "$@ --liveserver=$THIS_DOCKER_CONTAINER_TEST_SERVER"

if [[ "'$*'" == *"manage.py test"* ]]  # only add if 'manage.py test' in the args
then
  # get the container id
  THIS_CONTAINER_ID_LONG=`cat /proc/self/cgroup | grep 'docker' | sed 's/^.*\///' | tail -n1`
  # take the first 12 characters - that is the format used in /etc/hosts
  THIS_CONTAINER_ID_SHORT=${THIS_CONTAINER_ID_LONG:0:12}
  # search /etc/hosts for the line with the ip address which will look like this:
  #     172.18.0.4    8886629d38e6
  THIS_DOCKER_CONTAINER_IP_LINE=`cat /etc/hosts | grep $THIS_CONTAINER_ID_SHORT`
  # take the ip address from this
  THIS_DOCKER_CONTAINER_IP=`(echo $THIS_DOCKER_CONTAINER_IP_LINE | grep -o '[0-9]\+[.][0-9]\+[.][0-9]\+[.][0-9]\+')`
  # add the port you want on the end
  # Issues here include: django changing port if in use (I think)
  # and parallel tests needing multiple ports etc.
  THIS_DOCKER_CONTAINER_TEST_SERVER="$THIS_DOCKER_CONTAINER_IP:8081"
  echo "this docker container test server = $THIS_DOCKER_CONTAINER_TEST_SERVER"
  export DJANGO_LIVE_TEST_SERVER_ADDRESS=$THIS_DOCKER_CONTAINER_TEST_SERVER
fi


eval "$@"

在您的Django设置文件中

SITE_DOMAIN = 'django'

然后运行您的测试

docker-compose run django ./manage.py test

比我的答案更准确。好的反馈。+1 - VonC
为什么不在docker-compose文件中设置DJANGO_LIVE_TEST_SERVER_ADDRESS?那里是您必须指定容器名称的地方,也是这些设置的位置。 - holms

2
每当你看见"localhost"时,先尝试在VM级别端口转发该端口。
参见 "从外部连接运行在Docker容器内的服务"。
VBoxManage controlvm "default" natpf1 "tcp-port8081,tcp,,8081,,8081"
VBoxManage controlvm "default" natpf1 "udp-port8081,udp,,8081,,8081"

default 替换为您的 docker-machine 名称:参见 docker-machine ls 这与 docker 主机级别的端口映射有所不同(即,您的基于 boot2docker 的 Linux 主机)。 OP luke-aus评论中 确认:

输入网络的 IP 地址解决了问题!


@luke_aus 你需要检查一下 http://localhost:8081 是从哪个设置中来的。如果是从一个容器访问另一个容器,'localhost' 不是指实际主机,而应该改为 'django'(因为它是暴露 8081 端口的容器),http://django:8081 就可以工作了。 - VonC
所以发生的情况是Django启动了一个LiveTestServer,默认情况下它在localhost:8081上。您可以使用./manage.py test myapp --liveserver=django:8081更改此设置,但Django会抱怨gaierror:[Errno -2]名称或服务未知 - lukeaus
在正在运行的 Django 容器上运行 curl -I http://localhost:8081 将返回状态为 'HTTP/1.0 200 OK'。在正在运行的 Selenium 容器上运行 curl -I http://localhost:8081 将返回 curl: (7) Failed to connect to localhost port 8081: Connection refused - lukeaus
输入网络的IP地址解决了问题! - lukeaus
@luke_aus 很好!我已经将您的评论包含在答案中以增加可见性。 - VonC
显示剩余3条评论

1

我也曾经为此苦苦挣扎,最终找到了适合我的解决方案。你可以尝试像这样做:

postgis:
  dockerfile: ./docker/postgis/Dockerfile
  build: .

django:
  dockerfile: ./docker/Dockerfile-dev
  build: .
  command: python /app/project/manage.py test my-app
  volumes:
    - .:/app
  ports:
    - "8000:8000"
  links:
    - postgis
    - selenium  # django can access selenium:4444, selenium can access django:8081-8100
  environment:
    - SELENIUM_HOST=http://selenium:4444/wd/hub
    - DJANGO_LIVE_TEST_SERVER_ADDRESS=django:8081-8100  # this gives selenium the correct address

selenium:
  image: selenium/standalone-firefox-debug
  ports:
    - "5900:5900"

我认为在selenium配置中不需要包括端口4444。该端口默认已经暴露,因此没有必要将其映射到主机上,因为django容器可以通过与selenium容器的链接直接访问它。

[编辑] 我发现您也不需要显式地公开django容器的8081端口。此外,我为测试服务器使用了一系列端口,因为如果并行运行测试,您可能会遇到“地址已在使用中”的错误,如here所讨论的那样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接