- 示例工程
【免费下载链接】examples
Kubernetes application example tutorials
本文基于 kubernetes examples 仓库中_archived/selenium目录的完整示例,讲解如何把 Selenium Grid 以主从(master/worker)模型部署到 Kubernetes,用于解决 CI 流水线中 Selenium 资源争用的问题。读者将掌握:Selenium Hub 与浏览器节点的部署配置、三种验证 Hub 的方式、Python 端执行远程测试任务、按需横向扩缩节点,以及通过 VNC 调试挂起测试的完整流程。
为什么要把 Selenium 部署到 Kubernetes
Selenium 是业界主流的浏览器自动化工具,主要用于 Web 应用的自动化测试。当 Selenium 被引入 CI 流水线后,多个构建任务同时跑测试时,常常会围绕有限的 Selenium 资源(浏览器实例、测试执行环境)产生争用:要么排队等待,要么互相挤占资源导致测试不稳定。
本示例给出的解法是:把 Selenium Grid 搬进 Kubernetes,利用其调度与弹性能力,把浏览器执行环境做成可按需扩容、用完即弃的资源池。Selenium Grid 采用典型的主从模型:
- Selenium Hub(主节点):网格的唯一入口,负责接收测试请求并把任务分发给空闲的 worker。整个网格只需要一个 Hub,但示例用 Deployment 保证它始终在运行。
- Selenium Nodes(工作节点):真正跑浏览器的 worker(注意这里的 node 是 Selenium 概念,与 Kubernetes 节点无关)。示例提供 Chrome 与 Firefox 两类节点,数量可按需伸缩。
前置条件与资源规划
在动手之前,需要满足以下条件:
- 一个可用的 Kubernetes 集群,以及配置好的
kubectl客户端(具体搭建方式可参考 Kubernetes 官方 Getting Started Guides)。 - 如果希望快速获得一个托管集群,Google Container Engine(GKE)是较便捷的选择。
- 集群资源要求:要完整跑通本示例直到扩缩容部分,集群至少需要4 CPU 和 6 GB RAM。从仓库中的部署文件可以看到,Hub 与每个浏览器节点都声明了
memory: 1000Mi、cpu: 0.5的资源上限(见 selenium-hub-deployment.yaml 与 selenium-node-chrome-deployment.yaml),加上节点默认 2 副本,资源消耗是可预估的,请据此规划节点规格。
部署文件全景解析:Hub 与服务
仓库_archived/selenium目录下共包含 6 个文件,其中 4 个 YAML 是部署的核心,本文先看 Hub 相关的两个。
Selenium Hub 的 Deployment 配置
selenium-hub-deployment.yaml 使用apps/v1的 Deployment 来托管 Hub,关键配置如下:
apiVersion: apps/v1 kind: Deployment metadata: name: selenium-hub labels: app: selenium-hub spec: replicas: 1 selector: matchLabels: app: selenium-hub template: metadata: labels: app: selenium-hub spec: containers: - name: selenium-hub image: selenium/hub:4.0 ports: - containerPort: 4444 - containerPort: 4443 - containerPort: 4442 resources: limits: memory: "1000Mi" cpu: ".5" livenessProbe: httpGet: path: /wd/hub/status port: 4444 initialDelaySeconds: 30 timeoutSeconds: 5 readinessProbe: httpGet: path: /wd/hub/status port: 4444 initialDelaySeconds: 30 timeoutSeconds: 5逐项说明:
- 镜像:
selenium/hub:4.0,即 Selenium Grid 4 官方镜像。 - 端口语义:容器暴露三个端口——
4444是 WebDriver 命令入口(/wd/hub);4442是事件总线发布(publish)端口;4443是事件总线订阅(subscribe)端口。Selenium 4 中 Hub 内部的事件总线是节点注册与任务分发的通道。 - 健康探针:分别配置了
livenessProbe(存活探针,判定容器是否需要重启)与readinessProbe(就绪探针,判定流量是否可以进入),均通过 HTTP GET/wd/hub/status检查 4444 端口,initialDelaySeconds: 30表示容器启动 30 秒后才开始探测,timeoutSeconds: 5表示探测超时时间为 5 秒。这两个探针是网格可用性的关键保障。
Selenium Hub 的 Service 配置
浏览器节点需要知道如何找到 Hub 才能注册,为此示例创建了 selenium-hub-svc.yaml:
apiVersion: v1 kind: Service metadata: name: selenium-hub labels: app: selenium-hub spec: ports: - port: 4444 targetPort: 4444 name: port0 - port: 4443 targetPort: 4443 name: port1 - port: 4442 targetPort: 4442 name: port2 selector: app: selenium-hub type: NodePort sessionAffinity: None要点:
selector: app: selenium-hub与 Deployment 的labels匹配,服务把流量路由到 Hub Pod。- 三个端口(4444/4443/4442)与容器的三个端口一一对应,
port与targetPort均为相同值。 - 类型为
NodePort:既能让集群内节点通过内部 DNS 名称selenium-hub访问,也能让集群外(如浏览器节点所在的其他网络)通过节点端口访问。 sessionAffinity: None表示不做会话粘滞,请求可分发到任意后端。
创建 Hub 与服务的命令
在仓库根目录执行以下命令即可完成部署(示例文件归档在_archived/selenium目录下):
kubectl create --filename=_archived/selenium/selenium-hub-deployment.yaml kubectl create --filename=_archived/selenium/selenium-hub-svc.yaml第一条命令创建 Hub 的 Deployment,第二条创建节点注册用的 Service。如果更习惯声明式管理,也可以将create换成apply。
验证 Hub 部署的三种方式
部署完成后,可以通过连接 Hub 的 Web 控制台来验证它是否正常工作。根据你的网络环境,有三种验证路径。
方式一:Kubernetes 节点可达——直连 NodePort
如果 Kubernetes 节点可以从你的网络直接访问,通过kubectl describe svc selenium-hub可以查到节点端口号。下面的代码段利用 kubectl 的模板功能自动提取 NodePort 与第一个节点名称,然后直接 curl:
export NODEPORT=`kubectl get svc --selector='app=selenium-hub' --output=template --template="{{ with index .items 0}}{{with index .spec.ports 0 }}{{.nodePort}}{{end}}{{end}}"` export NODE=`kubectl get nodes --output=template --template="{{with index .items 0 }}{{.metadata.name}}{{end}}"` curl http://$NODE:$NODEPORT如果返回 Hub 的页面内容,说明服务已正确路由到 Hub Pod。
方式二:Kubernetes 节点不可达——kubectl port-forward
如果节点无法从你的网络访问,可以通过 kubectl 代理访问。先拿到 Hub Pod 的名称:
export PODNAME=`kubectl get pods --selector="app=selenium-hub" --output=template --template="{{with index .items 0}}{{.metadata.name}}{{end}}"` kubectl port-forward $PODNAME 4444:4444在另一个终端中验证:
curl http://localhost:4444port-forward会把本机 4444 端口转发到 Pod 的 4444 端口,无需暴露任何 Service。
方式三:使用 Google Container Engine——暴露公网地址
如果集群运行在 Google Container Engine 上,还可以把 Hub 通过公网暴露出去。文档同时提醒:这对多数场景都是个坏主意(安全性差),但确实可以这样做:
kubectl expose deployment selenium-hub --name=selenium-hub-external --labels="app=selenium-hub,external=true" --type=LoadBalancer等待几分钟,selenium-hub-external服务会从 gcloud 获得一个负载均衡 IP。当kubectl get svc selenium-hub-external显示两个 IP 后,运行以下代码段取出公网 IP 并验证:
export INTERNET_IP=`kubectl get svc --selector="app=selenium-hub,external=true" --output=template --template="{{with index .items 0}}{{with index .status.loadBalancer.ingress 0}}{{.ip}}{{end}}{{end}}"` curl http://$INTERNET_IP:4444/此后你(以及互联网上的所有人)都可以在浏览器中访问$INTERNET_IP打开 Hub 控制台——这也是文档强调"坏主意"的原因。
部署 Firefox 与 Chrome 节点
Hub 就绪后,就可以部署 worker 了。示例默认部署 2 个 Chrome 节点与 2 个 Firefox 节点。
kubectl create --filename=_archived/selenium/selenium-node-chrome-deployment.yaml kubectl create --filename=_archived/selenium/selenium-node-firefox-deployment.yamlPod 启动后,它们会出现在 Selenium Hub 的界面中,完成注册。
Chrome 节点部署解析
selenium-node-chrome-deployment.yaml 的完整结构如下:
apiVersion: apps/v1 kind: Deployment metadata: name: selenium-node-chrome labels: app: selenium-node-chrome spec: replicas: 2 selector: matchLabels: app: selenium-node-chrome template: metadata: labels: app: selenium-node-chrome spec: volumes: - name: dshm emptyDir: medium: Memory containers: - name: selenium-node-chrome image: selenium/node-chrome:4.0 ports: - containerPort: 5555 volumeMounts: - mountPath: /dev/shm name: dshm env: - name: SE_EVENT_BUS_HOST value: "selenium-hub" - name: SE_EVENT_BUS_SUBSCRIBE_PORT value: "4443" - name: SE_EVENT_BUS_PUBLISH_PORT value: "4442" resources: limits: memory: "1000Mi" cpu: ".5"几个值得注意的设计:
/dev/shm内存卷(dshm):定义了一个emptyDir卷,medium: Memory表示挂载为内存文件系统,并挂载到容器的/dev/shm。Chrome 在容器中运行时常因共享内存不足而崩溃,这一配置为浏览器提供了充足的内存化共享存储,是浏览器节点稳定运行的常见做法。- 事件总线连接环境变量:通过
SE_EVENT_BUS_HOST=selenium-hub、SE_EVENT_BUS_SUBSCRIBE_PORT=4443、SE_EVENT_BUS_PUBLISH_PORT=4442三个环境变量,告诉节点到哪里注册自己。从部署配置可以看出,节点正是通过 Service DNS 名selenium-hub加上事件总线的发布/订阅端口与 Hub 建立通信的,这与前文 Hub Service 暴露的 4442/4443 端口严格对应。 - 端口与资源:节点自身暴露 5555 端口(Selenium 节点默认通信端口),并声明
memory: 1000Mi、cpu: .5的资源上限。
Firefox 节点部署解析
selenium-node-firefox-deployment.yaml 与 Chrome 版本结构完全一致,差异仅在镜像(selenium/node-firefox:4.0)、Deployment 名称与标签。它同样带有 dshm 内存卷、5555 端口、SE_EVENT_BUS_*三件套环境变量与相同的资源上限,这里不再重复贴出,读者可直接对照查看。
运行一次真实的 Selenium 任务
节点注册完成后,运行一个真实的 Selenium 任务来验证整个网格。
准备 Python 运行环境
先启动一个可交互的 Python 容器并进入其中(这一步相当于申请一台临时执行机):
kubectl run selenium-python --tty -i --image=python:slim bash进入容器后安装 Selenium 客户端库:
pip install selenium执行测试脚本
启动 Python 解释器:
python然后粘贴仓库中 selenium-test.py 的内容(完整源码如下):
from selenium import webdriver def check_browser(browser): if browser == "CHROME": options = webdriver.ChromeOptions() elif browser == "FIREFOX": options = webdriver.FirefoxOptions() driver = webdriver.Remote( command_executor='http://selenium-hub:4444/wd/hub', options=options ) driver.get("http://www.google.com") assert "google" in driver.page_source driver.quit() print("Browser %s checks out!" % browser) check_browser("FIREFOX") check_browser("CHROME")脚本逻辑解读:
- 根据浏览器类型构造对应的
ChromeOptions/FirefoxOptions。 - 关键点在于
webdriver.Remote:command_executor指向http://selenium-hub:4444/wd/hub——这是集群内通过 Service DNS 名访问 Hub 的标准方式,也是 Hub Service 存在的意义。 - 任务内容为访问
http://www.google.com并断言页面源码中包含google,通过则打印校验通过信息。 - 脚本依次对 Firefox 与 Chrome 各执行一次,从而验证两类节点都能正常接单。
如果一切正常,你会看到如下输出:
>>> check_browser("FIREFOX") Browser FIREFOX checks out! >>> check_browser("CHROME") Browser CHROME checks out!恭喜,你的 Selenium Hub 已经带着 Firefox 和 Chrome 节点稳定运行了。
按需扩缩浏览器节点
Selenium Grid 的可扩展性正是本示例的核心价值。当测试负载上来后,硬件资源就是唯一的瓶颈。一条命令即可把节点数扩到任意规模:
kubectl scale deployment selenium-node-firefox --replicas=10 kubectl scale deployment selenium-node-chrome --replicas=10执行后你就有 10 个 Firefox 节点和 10 个 Chrome 节点了。Deployment 的声明式副本管理让扩容、缩容都只需改replicas一个数字,新节点会自动通过事件总线注册到 Hub。当然,扩容前请确认集群剩余资源满足各节点的资源上限(每个节点约 0.5 CPU / 1000Mi 内存)。
通过 VNC 调试挂起的测试
测试偶尔会挂起,此时往往需要亲眼看看浏览器到底停在哪个页面。示例中每个节点 Pod 都运行了 VNC 服务。由于不想为每个 Pod 都暴露一个 Service,且容器内的 VNC 密码较弱,官方推荐用port-forward代理连接。把POD_NAME替换为想连接的 Pod 名称:
kubectl port-forward $POD_NAME 5900:5900然后用 VNC 客户端连接localhost:5900,密码为secret,即可实时看到该节点上浏览器正在执行的操作画面,这是定位挂起测试最直观的手段。
本示例改编自 SeleniumHQ 的 docker-selenium 项目,网格的浏览器镜像即来自该项目。
资源清理
测试完毕,删除本示例创建的所有资源:
kubectl delete deployment selenium-hub kubectl delete deployment selenium-node-chrome kubectl delete deployment selenium-node-firefox kubectl delete deployment selenium-python kubectl delete svc selenium-hub如果按"方式三"创建过外部服务,还需要额外清理selenium-hub-external。至此,一套完整的、可弹性扩缩的 Selenium Grid 就完成了从部署、验证、执行、扩容到清理的闭环。
小结
本示例展示了一条清晰的 Kubernetes 化 Selenium 路径:用 Deployment 保障 Hub 与浏览器节点的高可用与可伸缩,用 Service 提供节点注册与访问入口,用探针保证网格健康,用kubectl scale实现按需扩容,用 VNC 提供测试排障手段。对于 CI 流水线中频繁出现的 Selenium 资源争用问题,这套主从架构 + 弹性扩容的方案给出了开箱即用的参考答案。相关部署文件与测试脚本均可在仓库_archived/selenium目录下直接查看与复用。
- 示例工程
【免费下载链接】examples
Kubernetes application example tutorials
相关推荐
KEDA Selenium Grid Scaler 实战指南:基于会话队列实现浏览器节点弹性伸缩
KEDA Selenium Grid Scaler 实战指南:基于会话队列实现浏览器节点弹性伸缩 本指南围绕 KEDA 官方 selenium grid 触发器
测试后端云原生容器编排可观测性从单节点到弹性集群:Ludwig与Kubernetes的AI模型扩展实战
从单节点到弹性集群:Ludwig与Kubernetes的AI模型扩展实战 你是否还在为AI模型训练时的资源瓶颈发愁?当数据集从GB级增长到TB级,当模型参数量突
人工智能深度学习机器学习大模型预训练微调LoRA多模态NLP计算机视觉模型推理服务Web-Dev-For-Beginners 浏览器扩展第一课:从浏览器架构到碳排放追踪扩展的落地实战
Web Dev For Beginners 浏览器扩展第一课:从浏览器架构到碳排放追踪扩展的落地实战 本文基于 Web Dev For Beginners 仓库
文档教程前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考