How to run cucumber/selenium tests in Docker? - ruby

I am struggling to run my cucumber tests from a Docker image.
Here is my setup:
I use OSX with XQuartz to run an X11 session
I use an Ubuntu 14 Vagrant image for development where I forward my X11 session
I am trying to run a docker image with Firefox that will use my XQuartz session for display
So far, I managed to start Firefox with the following setup:
# Dockerfile
FROM ubuntu:14.04
RUN apt-get update && apt-get install -y firefox
# Replace 1000 with something appropriate ;)
RUN export uid=1000 gid=1000 && \
mkdir -p /home/developer && \
echo "developer:x:${uid}:${gid}:Developer,,,:/home/dev:/bin/bash" >> /etc/passwd && \
echo "developer:x:${uid}:" >> /etc/group && \
echo "developer ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/developer && \
chmod 0440 /etc/sudoers.d/developer && \
chown ${uid}:${gid} -R /home/developer
USER developer
ENV HOME /home/developer
CMD /usr/bin/firefox
I can start Firefox with --net=host from my Vagrant machine:
docker build -t firefox .
docker run --net=host -ti --rm -e DISPLAY=$DISPLAY -v $HOME/.Xauthority:/home/developer/.Xauthority -v /tmp/.X11-unix:/tmp/.X11-unix:rw firefox:latest
But this is not ideal because I can't link other containers to my machine in the docker-compose.yml file. Ideally, I would like to run my docker machine without --net=host like this:
docker build -t firefox .
docker run -ti --rm -e DISPLAY=$DISPLAY -v $HOME/.Xauthority:/home/developer/.Xauthority -v /tmp/.X11-unix:/tmp/.X11-unix:rw firefox:latest
But I get the following error:
error: XDG_RUNTIME_DIR not set in the environment.
Error: cannot open display: localhost:10.0
Please help :)

You could simply use elgalu/docker-selenium to avoid dealing with what's already solved for you, and maintained:
docker run --rm -ti --net=host --pid=host --name=grid \
-e SELENIUM_HUB_PORT=4444 -e TZ="US/Pacific" \
-v /dev/shm:/dev/shm --privileged elgalu/selenium
If you need advanced features like a dashboard with video recording for example, or live preview, you can use Zalenium and start it with:
curl -sSL https://raw.githubusercontent.com/dosel/t/i/p | bash -s start -i

Related

Executing docker from terminal directly works fine but not when executed from inside a .sh script?

I am on ubuntu 20.04 I installed docker using sudo snap install docker now when I run directly from the terminal (terminal installed with ubuntu) docker command it works fine but when I execute a .sh script from the terminal using either bash ./script.sh or ./script.sh I am getting an error docker: command not found.
This is the script:
#!/bin/bash
source $(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/env.sh
docker run -e "NODE_ENV=dev" -it --rm --name my-npm-2 -v $PROJECT_HOME/code:/var/www/html/code -w /var/www/html/code node:14 npm install
docker run -e "NODE_ENV=dev" -it --rm --name my-npm -v $PROJECT_HOME/code/web:/var/www/html/code/web -w /var/www/html/code/web node:14 npm install
$SCRIPT_HOME/buildjs_dev.sh
docker exec project_php sudo php -d memory_limit=-1 /usr/local/bin/composer install --working-dir=/var/www/html/code
docker exec project_php chown -R www-data:www-data /var/www/html/code/var/cache
docker exec project_php chown -R www-data:www-data /var/www/html/code/var/log
I am new to linux in general and I don't know if the problem is with the script itself or why isn't it recognizing docker?
You are defining a source file at the start of your script which might be changing the PATH variable. Try by either commenting the source line or calling the docker command with full path.

Port forwarding through nested docker containers on Jenkins

My Jenkins pipeline uses the docker plugin that then runs a docker container from inside of that to set up a general test environment like this:
node('docker') {
sh """
cat > .Dockerfile.build <<EOF
FROM ruby:$rubyVersion
RUN apt-get update && apt-get install -y locales && localedef -i en_US -f UTF-8 en_US.UTF-8
ENV LANG=en_US.UTF-8 \\
LANGUAGE=en_US:en \\
LC_LANG=en_US.UTF-8 \\
LC_ALL=en_US.UTF-8
RUN \\
curl -sSL -o /tmp/docker.tgz https://download.docker.com/linux/static/stable/x86_64/docker-${dockerVersion}.tgz && \\
tar --strip-components 1 --directory /usr/local/bin/ --extract --file /tmp/docker.tgz
RUN \\
groupadd -g $gid docker && \\
useradd -d $env.HOME -u $uid build -r -m && \\
usermod -a -G docker build
EOF
""".stripIndent().trim()
}
Once the test environment container is up, I run another container that has my code and tests inside that previously made environment container. One of my tests includes making sure a firewall was set up through iptables that allow certain ports through. To test to see if my firewall is setup correctly, I simple run this from inside that container (now 3 docker containers deep):
def listener_response(port, host = 'localhost')
TCPSocket.open(host, port) do |socket|
socket.read(2)
end
rescue SystemCallError
nil
end
This is called by simply passing in the random port I used and the Jenkins docker node IP. When I run my test container, I do something like:
docker run -d -e DOCKER_HOST_IP=10.x.x.x -e RANDOM_OPEN_PORT=52459 -p 52459:52459 -v /var/run/docker.sock:/var/run/docker.sock
However, I still get a nil response from my test rather than an OK. Is there a way to port forward from the Jenkins host to my test environment to my test container?
Running the test environment with the option --network host seemed to solve the problem for me.

Run Maven in Docker container via current user

I want to run Maven to build a project in a Docker container. First, I came up with:
docker run -it --rm
-v $HOME/.m2:/root/.m2:rw
-v $PWD:$PWD:rw
-w $PWD
maven:alpine
mvn "$#"
This builds fine, but the problem here is that all files are now written and owned by the root user. I want them to be owned by the current user, myself.
So I tried this:
docker run -it --rm
--user $(id -u):$(id -g)
-v $HOME/.m2:/root/.m2:rw
-v $PWD:$PWD:rw
-w $PWD
maven:alpine
mvn "$#"
This did not work as expected. I believe I know why: now with --user $(id -u):$(id -g), we are indeed executing as myself, but now the mapping of -v $HOME/.m2:/root/.m2:rw becomes incorrect, there is no /root in place anymore.
So let's try this:
docker run -it --rm
--user $(id -u):$(id -g)
-v $HOME:$HOME:rw
-v $PWD:$PWD:rw
-w $PWD
maven:alpine
mvn "$#"
Now I am getting the following warning:
Can not write to /root/.m2/copy_reference_file.log. Wrong volume permissions? Carrying on ...
Also, Maven seems to be able to build (although I am having problems with accessing the Docker daemon during integration tests, but that might be better suited for another question), but I don't see any artifacts appearing in ~/.m2/repository on the host? They are also not in /root/.m2/repository (which does not exist, as expected) on the host. Where are they? What am I doing wrong?
Here is described how to run maven as non-root-user:
Maven needs the user home to download artifacts to, and if the user does not exist in the image an extra user.home Java property needs to be set.
Something in that direction should work:
docker run -it --rm \
--user $(id -u):$(id -g) \
-v ~/.m2:/var/maven/.m2:rw \
-e MAVEN_CONFIG=/var/maven/.m2 \
-v $PWD:$PWD:rw \
-w $PWD \
maven:alpine \
mvn -Duser.home=/var/maven "$#"

Run a Docker Container from a Desktop File Without Terminal GUI?

I have a couple of Docker images I've built for this and that;one for scanner program, another for a browser etc. Once I had them working, I created .desktop files that execute a bash run scripts I've created to run a container with them.
My question is: is there a way to run the .desktop file without the terminal GUI showing up? I've tried a couple of approaches with no success.
For instance, I've tried:
[Desktop Entry]
Name=gscan2pdf
Icon=gscan2pdf.png
Exec=gnome-terminal -e
"/home/hildy/Documents/repos/docker/gscan2pdf/run_gscan.sh"
Type=Application
Terminal=false
As well as:
[Desktop Entry]
Name=gscan2pdf
Icon=gscan2pdf.png
Exec="/home/hildy/Documents/repos/docker/gscan2pdf/run_gscan.sh"
Type=Application
Terminal=true
Both of these execute the scripts just fine of course, I'd just like it better if the application launched without a terminal GUI launching first.
Host System:
CentOS 7 - Gnome 3 Desktop
One example of a run script:
#!/bin/bash
HOST_UID=$(id -u)
HOST_GID=$(id -g)
XSOCK=/tmp/.X11-unix &&
XAUTH=/tmp/.docker.xauth &&
touch $XAUTH &&
xauth nlist :0 | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge - &&
#These are only run the first time a container is run from the image
#docker run -e NEW_USER="${USER}" -e NEW_UID="${HOST_UID}" -e
#NEW_GID="${HOST_GID}" hildy/gscan2pdf:v1
#LAST_CONTAINER=$(docker ps -lq) &&
#docker commit "${LAST_CONTAINER}" hildy/gscan2pdf:v1
docker run \
-ti \
--user $USER \
--privileged \
-v /dev/bus/usb:/dev/bus/usb \
-v $XAUTH:$XAUTH -v $XSOCK:$XSOCK -v /home/$USER:/home/$USER \
-e XAUTHORITY=$XAUTH -e DISPLAY \
--entrypoint "" hildy/gscan2pdf:v1 gscan2pdf &>/dev/null
I have found an answer to my question. The issue was that the command to run the container contained the -i option for an interactive terminal. #sneep was correct in the comments to the question when he said "It should work with Terminal=false." His technique to add a line to the script to create a log file is also a great technique, which I will certainly use in the future and it helped me to diagnose the issue.
I can also confirm that replacing -it with -d for detached mode, as suggested by #Oleg Skylar, works.
Amended Docker command for the run script:
docker run \
-t \
--user $USER \
--privileged \
-v /dev/bus/usb:/dev/bus/usb \
-v $XAUTH:$XAUTH -v $XSOCK:$XSOCK -v /home/$USER:/home/$USER \
-e XAUTHORITY=$XAUTH -e DISPLAY \
--entrypoint "" hildy/gscan2pdf:v1 gscan2pdf &>/dev/null
Amended .desktop file:
[Desktop Entry]
Name=gscan2pdf
Icon=gscan2pdf.png
Exec=/home/hildy/Documents/repos/docker/gscan2pdf/run_gscan.sh
Type=Application
Terminal=false
StartupNotify=true

Docker network does not work with bash entrypoint

First, we have a Docker network like so:
docker network create cdt-net
Then I have this bash script which will start a selenium server:
cd $(dirname "$0")
./node_modules/.bin/webdriver-manager update
./node_modules/.bin/webdriver-manager start
The above bash script is called by this Dockerfile:
FROM openjdk:latest
RUN apt-get update && \
apt-get -y install sudo
RUN mkdir -p /root/cdt-webdriver
WORKDIR /root/cdt-webdriver
COPY start-selenium-server.sh .
ENTRYPOINT ["/bin/bash", "/root/cdt-webdriver/start-selenium-server.sh"]
I would build it like so:
docker build -t cdt-selenium .
and then run it like so:
docker run --network=cdt-net --name cdt-selenium -d cdt-selenium
the problem that I am having, is that even though everything is clean with no errors, other processes in the same Docker network cannot talk to the selenium server.
On the other hand, if I create a selenium server using a pre-existing image, like so:
docker run -d --network=cdt-net --name cdt-selenium selenium/standalone-firefox:3.4.0-chromium
then things are working as expected, and I can connect to the selenium server from other processes in the Docker network.
Anyone know what might be wrong with my bash script or Dockerfile? Perhaps my manually created Selenium server is not listening on the right host?
Here is the complete Dockerfile for reference:
FROM openjdk:latest
RUN apt-get update && \
apt-get -y install sudo
RUN sudo apt-get install -y curl
RUN sudo apt-get install -y apt-utils
RUN sudo apt-get -y update
RUN sudo apt-get -y upgrade
RUN sudo apt-get purge nodejs npm
RUN curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
RUN sudo apt-get install -y nodejs
RUN echo "before nodejs => $(which nodejs)"
RUN echo "before npm => $(which npm)"
RUN sudo ln -s `which nodejs` /usr/bin/node || echo "ignore error"
RUN mkdir -p /root/cdt-webdriver
WORKDIR /root/cdt-webdriver
COPY start-selenium-server.sh .
RUN rm -rf node_modules > /dev/null 2>&1
RUN npm init -f || echo "ignore non-zero exit code" > /dev/null 2>&1
RUN npm install webdriver-manager > /dev/null 2>&1
ENTRYPOINT ["/bin/bash", "/root/cdt-webdriver/start-selenium-server.sh"]
You should use -d only when you docker images run fine. Before that use -it.
Change you webdriver-manager to a global install
RUN npm install -g webdriver-manager > /dev/null 2>&1
ENTRYPOINT ["/bin/bash", "/root/cdt-webdriver/start-selenium-server.sh"]
Also change your start-selenium-server.sh to
webdriver-manager update
webdriver-manager start
And use below to run and check if there are any issues
docker run --network=cdt-net --name cdt-selenium -it cdt-selenium

Resources