Docker Selenium is highly used by test teams to run their tests in parallel on Selenium Grid. In this article, I will explain to you how to use docker selenium and selenium grid infrastructure to run your tests in parallel. You can also find the system architecture and meaning of selenium grid, docker selenium, and docker network. Let’s get started!
What is Selenium Grid
Selenium Grid is a project created for executing tests on different browsers and operating systems. It has a simple architecture: A hub and one or more nodes. You run your test across the hub and the hub distributes the test across different browsers.
Advantages of Selenium Grid:
- Reduces execution time with distributed testing.
- Allows cross-browser and platform testing.
Problems of Selenium Grid:
- Hard to configure (Installing Java, downloading selenium standalone server, installing related browsers and drivers, etc.)
- Hard to manage (testing different versions of different browsers)
- Resource usage.
What is Docker Selenium?
It uses the same architecture but each component, hub, and nodes, is a separate container.
What are the advantages of Docker Selenium?
- We got rid of all the dependencies are mentioned above.
- Does not use system resources like VM’s so it’s lightweight.
- We can easily manage all the version complexity with the docker registry.
Docker Selenium Configuration
To be able to use docker selenium, the first thing you need to do is docker installation. If Docker is not already installed on your system, please follow the documentation for installation steps. There are different ways to configure selenium. In this tutorial, I will show the docker network and docker-compose methods.
Docker Network
Create a Docker Network
Use docker network create <NETWORK_NAME> command to create a network so that the containers can communicate with each other.
List networks with docker network ls
Other networks come with docker installation.
If you notice, I did not provide any parameters while creating the network, so the “bridge” network was used by default. There are other network types like Host, Overlay, and Macvlan for different use cases. For example, if you have containers on different Docker hosts, you will need an Overlay network.
You may ask “Why we defined a new bridge network instead of using the default bridge driver?” The reason is user-defined bridges have some advantages over the default bridges like providing automatic DNS resolution between containers. If I use the default network, I should link the containers explicitly by using “–link” parameter which is legacy.
For now, there is no container in our network.
Create a Docker Hub
Use docker run to create a hub.
$ docker run -d -p 4444:4444 --net grid --name selenium-hub selenium/hub:3.11.0-dysprosium
d: detached mode. The container starts in the background with this command. You don’t see any output from the container console.
p: publish port (we bind the port 4444 of the container to 4444 of the docker host)
net: specify which network we add the container
name: specify a name of the container and the last parameter is the image name used when creating the container.
What happened under the hood?
Step-1: The Docker client contacted the Docker daemon.
Step-2: The Docker daemon pulled the “hub” image from the Docker Hub.
Step-3: The Docker daemon created a new container from that image.
If you want to see the logs of the container, you can use the below command.
docker logs <CONTAINER_ID>
Images build for docker-selenium are listed below and available in Docker Hub:
- base
- hub
- node-base
- node-chrome
- node-firefox
- node-chrome-debug
- node-firefox-debug
- standalone-chrome
- standalone-firefox
- standalone-chrome-debug
- standalone-firefox-debug
node-{Browser Name} and node-{Browser Name}-debug cannot be used alone; they must be connected to a hub. Debug versions include a VNC server to visually debug the browser during the test.
List available images with docker images
Tagging convention for images is like this;
<Major>.<Minor>.<Patch>-<Chemical Element in Alphabetical order>
When I wrote this tutorial the latest tag was “dysprosium”. If you don’t specify a tag for an image, it will download the latest one.
Now, list running containers by typing docker ps
Check http://localhost:4444/grid/console
As you see above, our hub is up and running.
Create a Docker Node
Create a chrome node:
$ docker run -d --net grid -e HUB_HOST=selenium-hub -v /dev/shm:/dev/shm selenium/node-chrome:3.11.0-dysprosium
e: stands for environment variables. NODE_MAX_SESSION, NODE_MAX_INSTANCE etc. are defined in this part. You can see other environment variables by using docker inspect <IMAGE_ID> command.
v: This option suggested in official documentation to use host’s shared memory.
Similarly, docker daemon could not find chrome image, downloaded, start the container and print the id.
Let’s add one Firefox node:
$ docker run -d --net grid -e HUB_HOST=selenium-hub -v /dev/shm:/dev/shm selenium/node-firefox:3.11.0-dysprosium
Same thing. The only difference is the image name. We simply replaced Chrome with Firefox. :)
We have one hub, one chrome node, and one Firefox node. Let’s check them by docker images command.
Run docker ps to check their status.
If we look at our network again, we should see our newly added containers.
Our setup is ready. Let’s execute some tests on this configuration.
Execution of Tests
You can use the project mentioned here:
https:/selenium-parallel-tests-grid-testng/
Change only two things in the code. Enable RemoteWebdriver section in TLDriverFactory and edit testng.xml like below;
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Suite" parallel="tests" > <listeners> <listener class-name="com.InvokedMethodListener"></listener> </listeners> <test name="com.FirstTest"> <parameter name="browser" value="chrome"/> <classes> <class name="com.FirstTest"> <methods> <include name="GOOGLE0" /> <include name="GOOGLE2" /> <include name="GOOGLE3" /> <include name="GOOGLE4" /> </methods> </class> </classes> </test> <test name="com.SecondTest"> <parameter name="browser" value="firefox"/> <classes> <class name="com.SecondTest"> <methods> <include name="GOOGLE1" /> <include name="YANDEX" /> </methods> </class> </classes> </test> </suite>
Thus, we execute FirstTest and SecondTest in parallel. The FirstTest will use chrome while the SecondTest will use firefox.
How to See the Running Tests Visually in Docker Containers
Stop nodes by using docker stop <CONTAINER_ID>
Run the containers, but use node-{Browser Name}-debug versions for this time.
docker run -d -P -p 5900:5900 --net grid -e HUB_HOST=selenium-hub -v /dev/shm:/dev/shm selenium/node-chrome-debug:3.11.0-dysprosium docker run -d -P -p 5901:5900 --net grid -e HUB_HOST=selenium-hub -v /dev/shm:/dev/shm selenium/node-firefox-debug:3.11.0-dysprosium
Also, publish the ports. Open a VNC client and try to connect with selected ports. It will ask for a password, type secret
Now, I will make the same configuration with docker-compose.
Docker Compose for Selenium Grid
What is docker compose?
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.
Please follow docker compose installation.
docker-compose file
Create a file called docker-compose.yml as follows with your favorite text editor;
version: "3" services: selenium-hub: image: selenium/hub container_name: selenium-hub ports: - "4444:4444" chrome: image: selenium/node-chrome volumes: - /dev/shm:/dev/shm depends_on: - selenium-hub environment: - HUB_HOST=selenium-hub - HUB_PORT=4444 firefox: image: selenium/node-firefox volumes: - /dev/shm:/dev/shm depends_on: - selenium-hub environment: - HUB_HOST=selenium-hub - HUB_PORT=4444
version: There are several versions of compose file. It can be 1, 2, 2.x 3.x check compatibility matrix
image: determine which container will be used to start container.
container_name: specifies container name
ports: publish port with <HOST:CONTAINER> format
volumes: mount host path to service with <HOST:CONTAINER> format
depends_on: containers start according to dependency order. In our example, chrome and firefox will start after the hub starts.
environment: specifies environment variables. You can see other environment variables of selenium images by using docker image inspect <IMAGE_ID>
Run Docker Compose
docker-compose up -d
Scale Docker Compose
docker-compose up –d ––scale chrome=5
You can observe CPU, the memory usage of containers with docker stats
How to Stop Docker Containers
docker-compose down
That was a little bit long but I hope you enjoyed reading it.
In the next tutorials, I will try to explain other containerization solutions for selenium like Selenoid and Zalenium. Then I will make a comparison between them.
Keep calm and automate all things. :)
Kaan Sariveli

Kaan Sariveli is a Senior Technical Engineer at Emirates Airline and he loves automating the stuff.
Nice document , thanks for sharing it
Hi Kaan,
when i run “docker run -d -p 5900:5900 –link selenium-hub:hub -v /dev/shm:/dev/shm selenium/node-chrome-debug:3.11.0-dysprosium” this command i got
“docker: Error response from daemon: Cannot link to /selenium-hub, as it does not belong to the default network.” this error, prior to this i am able to perform all tasks.
Hi Mayur,
Command in the tutorial was wrong, sorry about that.
Correct one should be,
docker run -d –net grid -e HUB_HOST=selenium-hub -v /dev/shm:/dev/shm selenium/node-chrome-debug:3.11.0-dysprosium
The reason you got the error is that we don’t specify the network and docker tried to find the hub in default network which is not exist.
Could you please try with the new command?
Thanks,
Kaan
Hello Kaan,
Whenever we run the debug command for Chrome container. Which port should we use to connect via VNC?
We have just fixed that part. ;)
docker run -d -P -p 5900:5900 –net grid -e HUB_HOST=selenium-hub -v /dev/shm:/dev/shm selenium/node-chrome-debug:3.11.0-dysprosium
docker run -d -P -p 5901:5900 –net grid -e HUB_HOST=selenium-hub -v /dev/shm:/dev/shm selenium/node-firefox-debug:3.11.0-dysprosium
docker-compose.yml mentioned above has validation issue. A colon is reqiired at the end of third line. it has to be “selenium-hub:”. Or else we get an error – “ERROR: yaml.scanner.ScannerError: mapping values are not allowed here”
Thank you for pointing out this. It is fixed. ;)
hello is it beneficial to use docker :
because using other grid methods i was able to execute 6 execution at a time but using docker machine struggle to complete the execution, is that because of the recourse management of the docker that by default docker provide.