【问题标题】:Fix DNS on a docker-compose selenium grid so the selenium node connects to a docker-compose hostname修复 docker-compose selenium 网格上的 DNS,以便 selenium 节点连接到 docker-compose 主机名
【发布时间】:2019-12-17 15:19:51
【问题描述】:

我有一个硒网格在 Jenkins 机器上的 docker-compose 下运行。我的 docker-compose 包括一个提供单页应用程序的简单 Web 服务器,以及一个编排测试的测试运行器容器。

version: "3"
services:
  hub:
    image: selenium/hub
    networks:
      - selenium
    privileged: true
    restart: unless-stopped
    container_name: hub
    ports:
      - "4444:4444"
    environment:
      - SE_OPTS=-browserTimeout 10 -timeout 20
  chrome:
    image: selenium/node-chrome-debug
    networks:
      - selenium
    privileged: true
    restart: unless-stopped
    volumes:
      - /dev/shm:/dev/shm
    depends_on:
      - hub
    environment:
      - HUB_HOST=hub
      - HUB_PORT=4444
      - SE_OPTS=-browserTimeout 10 -timeout 20
    ports:
      - "5900:5900"
  firefox:
    image: selenium/node-firefox-debug
    networks:
      - selenium
    privileged: true
    restart: unless-stopped
    volumes:
      - /dev/shm:/dev/shm
    depends_on:
      - hub
    environment:
      - HUB_HOST=hub
      - HUB_PORT=4444
      - SE_OPTS=-browserTimeout 10 -timeout 20
    ports:
      - "5901:5900"
  runner:
    build:
      context: ./
      dockerfile: ./python.dockerfile
    security_opt:
      - seccomp=unconfined    
    cap_add:
      -  SYS_PTRACE
    command: sleep infinity
    networks:
      - selenium
    volumes:
      - ./:/app
    depends_on:
      - hub
      - app
      - chrome
      - firefox
    environment:
      HUB_CONNECTION_STRING: http://hub:4444/wd/hub
      TEST_DOMAIN: "app"
  app:
    image: nginx:alpine
    networks:
      - selenium
    volumes:
      - ../dist:/usr/share/nginx/html
    ports:
      - "8081:80"
networks:
  selenium:

当我的测试运行时(在上面的 runner 容器中),只要我使用 IP 地址,我就可以加载主页 -

  def test_home_page_loads(self):
    host = socket.gethostbyname(self.test_domain) // this is the TEST_DOMAIN env var above
    self.driver.get(f"http://{host}")
    header = WebDriverWait(self.driver, 40).until(
      EC.presence_of_element_located((By.ID, 'welcome-message')))
    assert(self.driver.title == "My Page Title")
    assert(header.text == "My Header")

但我不能使用主机名app。以下超时 -

  def test_home_page_with_hostname(self):
    self.driver.get("http://app/")
    email = WebDriverWait(self.driver, 10).until(
      EC.presence_of_element_located((By.ID, 'email')))

我面临的问题是我无法使用 IP 地址完成所有这些操作,因为 Web 应用程序正在连接到外部 IP,我需要为 CORS 请求配置 API。

【问题讨论】:

  • 您是否将您的服务器地址暴露给0.0.0.0
  • 谢谢@Rash - 我已经通过在 Nginx 配置中更改 server_name 解决了这个问题。 (我认为问题是 chrome 容器无法访问应用程序容器 - 问题是应用程序容器上的 Web 服务器没有为主机名“app”提供页面)

标签: dns docker-compose cors selenium-grid


【解决方案1】:

我认为问题是 chrome 容器无法访问应用程序容器 - 问题是应用程序容器上的 Web 服务器没有为我正在使用的主机名提供页面。更新 Nginx conf 以包含正确的服务器已解决此问题。

我现在可以将主机名添加到网页正在使用的 api 的 access-control-allow-origin 设置中。

我在这里为其他想要做类似事情的人附加了一个基本的工作配置。

docker-compose.yml

version: "3"
services:
  hub:
    image: selenium/hub
    networks:
      - selenium
    privileged: true
    restart: unless-stopped
    container_name: hub
    ports:
      - "4444:4444"
    environment:
      - SE_OPTS=-browserTimeout 10 -timeout 20
  chrome:
    image: selenium/node-chrome-debug
    networks:
      - selenium
    privileged: true
    restart: unless-stopped
    volumes:
      - /dev/shm:/dev/shm
    depends_on:
      - hub
    environment:
      - HUB_HOST=hub
      - HUB_PORT=4444
      - SE_OPTS=-browserTimeout 10 -timeout 20
    ports:
      - "5900:5900"
  firefox:
    image: selenium/node-firefox-debug
    networks:
      - selenium
    privileged: true
    restart: unless-stopped
    volumes:
      - /dev/shm:/dev/shm
    depends_on:
      - hub
    environment:
      - HUB_HOST=hub
      - HUB_PORT=4444
      - SE_OPTS=-browserTimeout 10 -timeout 20
    ports:
      - "5901:5900"
  runner:
    build:
      context: ./
      dockerfile: ./python.dockerfile
    security_opt:
      - seccomp=unconfined    
    cap_add:
      -  SYS_PTRACE
    command: sleep infinity
    networks:
      - selenium
    volumes:
      - ./:/app
    depends_on:
      - hub
      - webserver
      - chrome
      - firefox
    environment:
      HUB_CONNECTION_STRING: http://hub:4444/wd/hub
      TEST_DOMAIN: "webserver"
  webserver:
    image: nginx:alpine
    networks:
      - selenium
    volumes:
      - ../dist:/usr/share/nginx/html
      - ./nginx_conf:/etc/nginx/conf.d
    ports:
      - "8081:80"
networks:
  selenium:

default.conf

server {
    listen       80;
    server_name  webserver;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

“runner”容器基于来自 python:3 的 docker 镜像,并包含 pytest。一个简单的工作测试看起来像 -

test.py

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import os
import pytest
import socket

#Fixture for Chrome
@pytest.fixture(scope="class")
def chrome_driver_init(request):
  hub_connection_string = os.getenv('HUB_CONNECTION_STRING')
  test_domain = os.getenv('TEST_DOMAIN')
  chrome_driver = webdriver.Remote(
      command_executor=hub_connection_string,
      desired_capabilities={
        'browserName': 'chrome',
        'version': '',
        "chrome.switches": ["disable-web-security"],
        'platform': 'ANY'})
  request.cls.driver = chrome_driver
  request.cls.test_domain = test_domain
  yield
  chrome_driver.close()

@pytest.mark.usefixtures("chrome_driver_init")
class Basic_Chrome_Test:
  driver = None
  test_domain = None
  pass

class Test_Atlas(Basic_Chrome_Test):
  def test_home_page_loads(self):
    self.driver.get(f"http://{self.test_domain}")
    header = WebDriverWait(self.driver, 40).until(
      EC.presence_of_element_located((By.ID, 'welcome-message')))
    assert(self.driver.title == "My Page Title")
    assert(header.text == "My Header")

这可以使用docker exec -it $(docker-compose ps -q runner) pytest test.py 之类的东西运行(执行到运行器容器中并使用 pytest 运行测试)。

然后可以将此框架添加到 Jenkins 步骤中 -

詹金斯文件

stage('Run Functional Tests') {
  steps {
    echo 'Running Selenium Grid'
    dir("${env.WORKSPACE}/functional_testing") {
      sh "/usr/local/bin/docker-compose -f ${env.WORKSPACE}/functional_testing/docker-compose.yml -p ${currentBuild.displayName} run runner ./wait-for-webserver.sh pytest tests/atlas_test.py"
    }
  }
}

wait-for-webserver.sh

#!/bin/bash
# wait-for-webserver.sh

set -e

cmd="$@"

while ! curl -sSL "http://hub:4444/wd/hub/status" 2>&1 \
        | jq -r '.value.ready' 2>&1 | grep "true" >/dev/null; do
    echo 'Waiting for the Grid'
    sleep 1
done


while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' http://webserver)" != "200" ]]; do 
    echo 'Waiting for Webserver'
    sleep 1; 
done

>&2 echo "Grid & Webserver are ready - executing tests"
exec $cmd

希望这对某人有用。

【讨论】:

    猜你喜欢
    • 2019-11-09
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 2020-05-16
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    • 2018-04-28
    相关资源
    最近更新 更多