GraalVM and ChromeDriver in a Docker image for Render.com
This should work on Heroku or in any Docker-based deployment as well.
Adding Chrome and ChromeDriver into a GraalVM Docker image isn't as straightforward as I thought. The main complication originates from the fact that GraalVM is lean. There are 2 problems from being lean: (1) microdnf
as the main package manager and (2) unwritable home directory, and Chrome needs a writable home directory.
I didn't even know what microdnf
(or dnf
) was before this. I was initially surprised that I couldn't find a package manager at all until I randomly landed on this GraalVM Community Edition page that mentioned microdnf
here.
The first problem is microdnf
doesn't support installing Chrome nor ChromeDriver. I was researching how to install those 2 programs manually. While installing ChromeDriver is simple, installing Chrome manually looks extremely complex.
Eventually, I've found a feasible path where I'd install yum
first with microdnf install yum
and then use yum
to install Chrome (through a Chrome rpm). That works out pretty well.
The second problem is that Chrome wouldn't start at all. After hours of debugging, I've figured it out that the home directory of the user daemon
(which is apparently the user that we use inside the docker image) is set to /sbin
and isn't writable. Chrome and Selenium seems to utilise the home directory for caching and myriad of other things.
After solving these 2 problems, the headless Chrome, ChromeDriver, and Play Framework all work together like a charm.
Here's the Dockerfile that sets everything up:
FROM container-registry.oracle.com/graalvm/jdk:21
RUN microdnf install yum
# Install Chrome
RUN yum install wget unzip
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm
RUN yum install google-chrome-stable_current_x86_64.rpm
# Install ChromeDriver
RUN wget https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.85/linux64/chromedriver-linux64.zip
RUN unzip chromedriver-linux64.zip
RUN chmod 755 chromedriver-linux64/chromedriver
RUN mv chromedriver-linux64/chromedriver /usr/local/bin/chromedriver
# Change the home directory to /home/daemon.
RUN mkdir -p /home/daemon
RUN usermod -d /home/daemon daemon
RUN chown daemon:daemon /home/daemon
Edit: This person on Reddit shares this cool Docker trick that we'll apply to our Dockerfile.