DevToolsActivePort: Why Chrome Suddenly Refused to Start in Headless Mode in Docker

DevToolsActivePort: Why Chrome Suddenly Refused to Start in Headless Mode in Docker

Docker images that used to work perfectly can suddenly and mysteriously stop working as expected. Here’s a good lesson in why its important to pin your versions, and sometimes flat out specify packages by name.

Our automated test process uses a Docker image based on Alpine Linux. It contains Ruby, Watir, Chromium, and a copy of our test scripts.

The image used by our CI and the developer team is built automatically up in Dockerhub. I build my own local copy when I need to debug something.

The whole thing has been working really well so far. That is until Chrome decided to start barfing during start up.

The strange thing is when Dockerhub builds the image with the same dockerfile, Chrome launches correctly and the tests work. It just breaks within my locally built image.

Why?

The Magic of Headless Chrome

When run within Docker, the web browser can’t display an actual browser window. Chrome specifically has a feature called “headless mode” which means the browser can start and navigate to websites, except it doesn’t draw a window to the screen.

The Ruby tests would fire up an instance of Chrome in headless mode, run through the scripts, and report back the results all without opening a browser window.

But in my case, Chrome would crash during initialization:

Selenium::WebDriver::Error::UnknownError:        
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
           (unknown error: DevToolsActivePort file doesn't exist)
           (The process started from chrome location /usr/lib/chromium/chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
           (Driver info: chromedriver=2.38 (f91d32489882be7df38da3422a19713bfd113fa5),platform=Linux 4.9.93-linuxkit-aufs x86_64)

Sleuthing Around

Take a hard look at the message from Chromedriver:

The process started from chrome location /usr/lib/chromium/chrome is no longer running, 
so ChromeDriver is assuming that Chrome has crashed."

So how do you figure out why Chrome crashed?

My Docker container is setup to run any Rake tasks passed to it, and return an error in their absence.

To get around this, I fired up the Docker container, and forced the execution of a shell using the “–entrypoint” option.

This lets bum around and try stuff.

docker run -ti --entrypoint='/bin/sh' --env-file /tmp/docker_params --network compose_default mytestingimage:latest

Once inside, I decided to manually launch Chrome. The simplest way to do this is to ask it for its version.

$ /usr/lib/chromium/chrome --version

In the Dockerhub version of the image, I get this:

$ /usr/lib/chromium/chrome --version
Chromium 68.0.3440.75

Nice.

Now this is what I get when I use the image I built on my laptop with the identical Dockerfile.

$ /usr/lib/chromium/chrome --version Error relocating /usr/lib/chromium/chrome: hb_font_funcs_set_glyph_h_advances_func: symbol not found

At first I thought I was looking at a typo (advances vs advance), but no.

That method is from a library called Harfbuzz. The version that was automatically installed by Docker was 1.7.6.

$ apk list | grep harf
WARNING: Ignoring APKINDEX.adfa7ceb.tar.gz: No such file or directory
WARNING: Ignoring APKINDEX.efaa1f73.tar.gz: No such file or directory
WARNING: Ignoring APKINDEX.0a5ec95f.tar.gz: No such file or directory
WARNING: Ignoring APKINDEX.3f8e9ca0.tar.gz: No such file or directory
harfbuzz-1.7.6-r1 x86_64 {harfbuzz} (MIT) [installed]

Checking the Harfbuzz website for that particular method shows it was only added to the library in version 1.8.6.

H’Oh Boy! Progress!

So the solution here was to force an upgrade of Harfbuzz in my dockerfile.

# Installs latest stable Chromium package.
RUN apk update && apk upgrade \
     && echo @latest-stable http://nl.alpinelinux.org/alpine/latest-stable/community >> /etc/apk/repositories \
     && echo @latest-stable http://nl.alpinelinux.org/alpine/latest-stable/main >> /etc/apk/repositories \
     && apk add --no-cache \
     chromium@latest-stable \
     harfbuzz@latest-stable \     <--- New!
     nss@latest-stable \
     && rm -rf /var/lib/apt/lists/* \
     /var/cache/apk/* \
     /usr/share/man \
     /tmp/*

Once I rebuilt the image, my tests fired up Chrome in headless mode and everything was once again right with the world.

 

7 Responses

  1. Fredrik says:

    Just wanted to say thank you for taking the time to write this up and share.

  2. Gareth says:

    Hi Dennis,

    Many thanks for taking your time to share this helpful guide.

    I have encountered an error when running my tests

    "unknown error: Chrome failed to start: exited abnormally (unknown error: DevToolsActivePort file doesn't exist)
    (The process started from chrome location /usr/lib/chromium/chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)"

    Do you have any idea what could be causing this?

    Ive used your command above for Chrome and this for Chromedriver

    ## Install ChromeDriver
    RUN apk --no-cache add \
    chromium-chromedriver\
    zlib-dev \
    chromium \
    xvfb \
    wait4ports \
    xorg-server \
    dbus \
    ttf-freefont \
    mesa-dri-swrast \
    udev

    • Dennis McLaughlin says:

      Hi Gareth.

      This error is frustrating as I’m sure your tests work properly on your workstation, right?
      The error is exactly what it says, that Chrome (Chromium) has crashed – you need to figure out why that is.

      What’s the environment you’re running this in? Docker? What OS are you using? (Ubuntu? Alpine Linux?)

      Remember that Chrome is just the browser, but the chromedriver is what your tests are “talking” to. Chromedriver then tries to fire up Chrome, but Chrome is barfing.

      Try running Chromium manually.

      The package listed above normally installs Chromium at /usr/lib/chromium.
      You can’t start it in window’d mode, but you can still get it to return its version. If it’ll do this, then Chrome can start up.

      /usr/lib/chromium –version

      My result is this:
      /usr/lib/chromium $ ./chrome –version
      Chromium 72.0.3626.121

      In you’re case, I’m expecting it to crash. What error are you getting?

      If you’re running in Alpine Linux, have you tried also installing the Harfbuzz library?

      • Gareth says:

        Hi Dennis,

        Thanks for the reply.

        Yes, this issue has caused me no ends of headaches the last few days.

        I am indeed using the Alpine image to build the tests and this is what I get when i run this command
        ‘RUN echo $(/usr/lib/chromium –version)’

        Step 10/25 : RUN echo $(/usr/lib/chromium –version)
        /bin/sh: /usr/lib/chromium: Permission denied.

        I am running this in Drone.io which is where i am getting the failure, locally it has run fine. So frustrating

        Thanks Again
        Gareth

  3. Dennis McLaughlin says:

    Ok so here’s what I’d suggest.

    Drop Drone.io for now, just until you get all of this working in Docker on your local workstation.

    This post shows you a copy of my Dockerfile that is known to work.
    https://www.dennismclaughlin.tech/build-docker-image-ruby-watir-webdriver-shopify-and-chrome/

    It has different libraries in it that support my specific test framework (Shopify and AWS support) but it at least contains a working Chromium (and Firefox). You can adjust it later.

    In a situation like yours, I’d just fire up the Docker container. Then manually try stuff inside of it.

    For example, when I want to debug a Docker problem, I do this.

    $ docker run -ti [yourcontainername] /bin/sh

    ([yourcontrainername] is the name you gave your container when you ran the Docker build command; omit the brackets though)

    That drops you inside your running container.
    You can then manually run stuff like this:

    $ whoami
    webdriver

    This will be returned in MY case based on the Docker image I mentioned earlier. I’m in here logged in as user ‘webdriver’.

    Then you can do your chromium test:

    $ /usr/lib/chromium –version
    /bin/sh: /usr/lib/chromium: Permission denied

    It returns this error because ‘chromium’ is a directory.

    Switch into the /usr/lib/chromium directory, then hit it with the “–version” command.

    $ cd /usr/lib/chromium
    /usr/lib/chromium $ ./chrome --version
    Chromium 72.0.3626.121

    Boom!

    Or in your case, it’ll help reveal the actual reason Chrome isn’t starting up in your environment.

    Debugging AS the user your tests will run as will give you a better idea of what’s going on.

    Type ‘exit’ to return to your PC.

    $ exit

    Once you can get Chrome running in regular Docker on your workstation, then manually run your tests inside that container.
    Once you get THOSE going, only then should you try getting it all to work up in Drone.io.

Leave a Reply