Docker Selenium Grid 全量集成测试环境搭建和负载均衡

Posted 上海一亩地

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker Selenium Grid 全量集成测试环境搭建和负载均衡相关的知识,希望对你有一定的参考价值。

Selenium Grid优点

传统的web测试环境是先装一个浏览器,然后下载对应浏览器对应版本的启动,然后自动化程序中写如下一行

driver = webdriver.Chrome(executable_path="C:\\\\python37\\\\chromedriver.exe",chrome_options=browser_options)

传统测试框架有两个弊端:

  1. 不易部署、升级和卸载。假设测试环境有10台机器,如果需要升级浏览器,则需要每台登上去折腾一番,然后把驱动换了。即使使用配置管理工具,维护起来也麻烦。如果你想从火狐换成谷歌浏览器,是不是一台一台卸载?
  2. 负载不均衡,伤硬件。大公司如果测试工作量大,如何做到10台机器每台都能执行差不多量的任务,负载均衡,而不是总薅一只羊的羊毛?如果有的部门都把测试放到一台上执行,机器内存泄漏怎么办?
  3. 测试环境隔离性差。如果有人登录了测试环境并操作,可能影响测试甚至导致测试中断。
    搭建Grid能解决这些问题。

Selenium Grid环境搭建

找一台性能较好,有固定ip的机器,开始搭建。

第一步:安装Docker

docker支持windows、Mac、linux。各个平台安装方法参考官方文档:
https://docs.docker.com/get-docker/
我以CentOS为例,以下安装方法支持CentOS全系列(7,8)。

# 先尝试卸载本机所有docker组件
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine

# 添加docker yum源
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 激活测试库
sudo yum-config-manager --enable docker-ce-nightly
sudo yum-config-manager --enable docker-ce-test

# 安装docker全特性
sudo yum install docker-ce docker-ce-cli containerd.io

# 启动docker并设置开机自启动
sudo systemctl start docker
sudo systemctl enable docker

#查看是否安装成功
docker version

在Centos8中安装docker有时会报错,提示包已存在。其实是系统包太旧了和docker yum源中的新版本冲突,手动直接把这个报错的旧包卸载掉,然后重新执行安装命令。

sudo yum -y remove xxxx

第二步:安装docker-compose命令

以下安装方法支持所有Linux系统。

# 下载命令文件
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 添加软链接
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

第三部:保存yaml文件

以下代码请保存成docker-compose-v3-full-grid.yml
这篇代码来源于github上的docker-selenium项目,进行了适当改造
原文:https://github.com/SeleniumHQ/docker-selenium/blob/trunk/docker-compose-v3-full-grid.yml
请根据自己的需要改造里面的Node配置,也可以不改,直接用即可。

# To execute this docker-compose yml file use `docker-compose -f docker-compose-v3-full-grid.yml up`
# Add the `-d` flag at the end for detached execution
# To stop the execution, hit Ctrl+C, and then `docker-compose -f docker-compose-v3-full-grid.yml down`
version: "3"
services:
  selenium-event-bus: # 这个不要改
    image: selenium/event-bus:4.0.0-rc-1-prerelease-20210618
    container_name: selenium-event-bus
    ports:
      - "4442:4442"
      - "4443:4443"
      - "5557:5557"

  selenium-sessions: # 这个不要改
    image: selenium/sessions:4.0.0-rc-1-prerelease-20210618
    container_name: selenium-sessions
    ports:
      - "5556:5556"
    depends_on:
      - selenium-event-bus
    environment:
      - SE_EVENT_BUS_HOST=selenium-event-bus
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443

  selenium-session-queue: # 这个不要改
    image: selenium/session-queue:4.0.0-rc-1-prerelease-20210618
    container_name: selenium-session-queue
    ports:
      - "5559:5559"
    depends_on:
      - selenium-event-bus
    environment:
      - SE_EVENT_BUS_HOST=selenium-event-bus
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443

  selenium-distributor: # 这个不要改
    image: selenium/distributor:4.0.0-rc-1-prerelease-20210618
    container_name: selenium-distributor
    ports:
      - "5553:5553"
    depends_on:
      - selenium-event-bus
      - selenium-sessions
      - selenium-session-queue
    environment:
      - SE_EVENT_BUS_HOST=selenium-event-bus
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_SESSIONS_MAP_HOST=selenium-sessions
      - SE_SESSIONS_MAP_PORT=5556
      - SE_SESSION_QUEUE_HOST=selenium-session-queue
      - SE_SESSION_QUEUE_PORT=5559

  selenium-router:
    image: selenium/router:4.0.0-rc-1-prerelease-20210618
    container_name: selenium-router
    ports:
    # 这个可以修改左边的4444,右边的4444不能改。左边的是4444宿主机Grid访问接口!
    # 使用 ip:4444可以访问router网页,查看当前连接的node和session
    # selenium自动化远程执行就是连接router,左边的端口就是入口,映射到右边的容器内端口
      - "4444:4444"
    depends_on:
      - selenium-distributor
      - selenium-sessions
      - selenium-session-queue
    environment:
      - SE_DISTRIBUTOR_HOST=selenium-distributor
      - SE_DISTRIBUTOR_PORT=5553
      - SE_SESSIONS_MAP_HOST=selenium-sessions
      - SE_SESSIONS_MAP_PORT=5556
      - SE_SESSION_QUEUE_HOST=selenium-session-queue
      - SE_SESSION_QUEUE_PORT=5559

  chrome1: # 这是 Node,每个Node是一个容器,每个容器默认只能启动一个浏览器窗口!!!
    image: selenium/node-chrome:4.0.0-rc-1-prerelease-20210618
    volumes: # 根据需要可以适当添加几个数据卷
      - /dev/shm:/dev/shm
    depends_on:
      - selenium-event-bus
    environment:
      - SE_EVENT_BUS_HOST=selenium-event-bus #不能改
      - SE_EVENT_BUS_PUBLISH_PORT=4442 #不能改
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 #不能改
      - SE_NODE_MAX_SESSIONS=5  # 添加这个参数能让一个容器运行多个浏览器窗口(跑多个job)
      - SE_NODE_OVERRIDE_MAX_SESSIONS=true # 如果添加了SE_NODE_MAX_SESSIONS,则这个参数必须添加
      - SCREEN_HEIGHT=900
      - SCREEN_WIDTH=1600  # 容器分辨率 1600X900
    ports:
      - "5901:5900" # 下载VNC Viewer软件,新建会话 ip:5901 ,能看到容器中运行的浏览器窗口,密码secret
      - "7901:7900" #  浏览器中直接访问 ip:7901 , 能看到容器中运行的浏览器窗口,密码secret。如果noVNC连不上说明网络有防火墙。

  chrome2:
    image: selenium/node-chrome:4.0.0-rc-1-prerelease-20210618
    volumes:
      - /dev/shm:/dev/shm
    depends_on:
      - selenium-event-bus
    environment:
      - SE_EVENT_BUS_HOST=selenium-event-bus
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_MAX_SESSIONS=5
      - SE_NODE_OVERRIDE_MAX_SESSIONS=true
      - SCREEN_HEIGHT=900
      - SCREEN_WIDTH=1600
    ports:
      - "5902:5900"
      - "7902:7900"
  
  edge1:
    image: selenium/node-edge:4.0.0-rc-1-prerelease-20210618
    volumes:
      - /dev/shm:/dev/shm
    depends_on:
      - selenium-event-bus
    environment:
      - SE_EVENT_BUS_HOST=selenium-event-bus
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
    ports:
      - "5903:5900"
      - "7903:7900"

  firefox1:
    image: selenium/node-firefox:4.0.0-rc-1-prerelease-20210618
    volumes:
      - /dev/shm:/dev/shm
    depends_on:
      - selenium-event-bus
    environment:
      - SE_EVENT_BUS_HOST=selenium-event-bus
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_MAX_SESSIONS=5
      - SE_NODE_OVERRIDE_MAX_SESSIONS=true
      - SCREEN_HEIGHT=900
      - SCREEN_WIDTH=1600
    ports:
      - "5904:5900"
      - "7904:7900"

第四部:生成测试环境

# 一键生成测试环境
docker-compose -f docker-compose-v3-full-grid.yml up -d

# 停止selenium grid
docker-compose -f docker-compose-v3-full-grid.yml down

# 彻底删除selenium Grid (这是删除所有容器的命令,慎用!!!)
docker rm -f $(docker ps -qa)

运行测试

如下是一个selenium测试脚本,只需要你的机器装了Python3 并且安装了selenium
将代码中ip 和port替换成你安装Grid的主机ip 和Router 容器端口

# coding=utf-8
import time
start_time = time.time()
from selenium import webdriver

ip = "xxx.xxx.xxx.xxx"
port = "4444"

# 设置浏览器能力
node_chrome_capabilities=webdriver.DesiredCapabilities.CHROME.copy()
node_chrome_capabilities["browserName"] = "chrome"
node_chrome_capabilities["version"] = ""
node_chrome_capabilities["platform"] = "ANY"
node_chrome_capabilities["javascriptEnabled"] = True
node_chrome_capabilities["acceptInsecureCerts"] = True # 这一行是让浏览器忽略不安全SSL证书


browser = webdriver.Remote("http://%s:%s/wd/hub"%(ip,port), desired_capabilities=node_chrome_capabilities)
browser.get("https://www.163.com")
time.sleep(20)
print(browser.current_url)
browser.get_screenshot_as_file(r"D:/sample/chrome.png")
browser.quit()
end_time = time.time()
cost = end_time-start_time
print("time cost:%d"%int(cost))

浏览器访问 Grid主机ip:7901 和 Grid主机ip:7902
输入secret密码就能找到浏览器窗口,两个容器中必有一个。
如果找不到,说明跑完了。

负载均衡和排队

负载均衡就是新来的测试任务会运行在集群中压力最小的那台机器上。
我们的Node容器都是用cpu中的一个core处理的,假如服务器cpu有64核,理论上能开60个Node容器。
官方文档建议一个Node容器只运行一个浏览器测试任务,启动一个窗口。

登录 Grid主机ip:4444 能看到所有Node容器和测试任务的session情况。
如果你同时运行两遍这个脚本,它一定会运行在两个容器上,而不是同时运行在一个容器上。你可以修改yaml开多个Node容器并运行多个脚本,看看负载均衡的效果。
如下是3个job运行在3个Chrome的案例。

排队

上图中我有4个Chrome容器,每个容器做多同时并行5个job,即我能同时测20个任务。如果来了21个呢?最后来的那个会一直等待知道有一个任务结束了。

使用本地文件

如果测试过程中需要读本地文件怎么办?
原来本地化测试直接给个路径就能读到文件,现在缺搬到了容器里了。
在yaml文件中的Node配置中有一行: - /dev/shm:/dev/shm
这个就是宿主机和容器的共享文件夹,只要将待测文件放到宿主机的/dev/shm中,不管job运行在哪个容器里,都能读到和改写文件,这种共享文件夹叫数据卷,属于docker的功能。

今天就分享到这里,Bye!

以上是关于Docker Selenium Grid 全量集成测试环境搭建和负载均衡的主要内容,如果未能解决你的问题,请参考以下文章

Selenium Grid Docker-通过 Jenkins 实现自动化

基于Docker+Selenium Grid的测试技术应用

docker+selenium Grid搭建自动化分布式测试环境

基于Docker Selenium Grid 搭建分布式测试环境

在本地 Python 3 下将扩展安装到 Selenium Grid(远程驱动程序)到在 docker 下运行的远程服务器

selenium hub/node配置以及webdriver.io集成selenium