grafana/grafana-image-renderer

Fails to find chromium binary

sjlongland opened this issue · 1 comments

What happened:

My workplace want the image renderer to be installed alongside Grafana in an AlpineLinux-based Docker container. This is very similar to what Grafana do in their own containers, so should be a supported and working configuration.

When doing this, the renderer plug-in starts, but then fails to find Chromium. No images are being rendered.

What you expected to happen:

I expected it to render images (like it says on the tin).

How to reproduce it (as minimally and precisely as possible):

We use supervisord in an AlpineLinux container to launch the plug-in…

Rough Dockerfile set-up:

FROM alpine:3.19
ENV GF_RENDERING_SERVER_URL=http://localhost:8081/render
ENV GF_RENDERING_CALLBACK_URL=http://localhost:3000/
ENV GF_PLUGIN_RENDERING_CHROME_BIN=/usr/bin/chromium-browser

ARG GRAFANA_IMG_RENDER_REPO=https://github.com/grafana/grafana-image-renderer.git
ARG GRAFANA_IMG_RENDER_VER=3.10.3

RUN apk add --no-cache \
        openssl \
        ca-certificates \
        chromium \
        supervisor \
        bash \
        git \
        nodejs \
        yarn \
        udev \
        ttf-opensans \
    && git clone --depth=1 --branch=v${GRAFANA_IMG_RENDER_VER} \
        ${GRAFANA_IMG_RENDER_REPO} /opt/grafana-image-renderer \
    && cd /opt/grafana-image-renderer \
    && yarn install --pure-lockfile \
    && yarn run build \
    && apk del yarn git

There are other steps like creating a grafana user (with a fixed UID/GID), importing a pre-built Grafana binary and its front-end, but that's the gist of how the image renderer plug-in is installed. supervisord then launches it with this command:

[supervisord]
logfile=/dev/null
pidfile=/var/run/supervisord.pid
nodaemon=true

[program:renderer]
directory=/opt/grafana-image-renderer
command=env HOME=/home/grafana /usr/bin/node build/app.js server --port=8081
user=grafana
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
auto_start=true
autorestart=true

Anything else we need to know?:

Grafana itself is working just fine (all functions except exporting a rendered image of a dashboard work). Exporting a rendering image fails.

The log message I get is:

{"level":"error","message":"Request failed","stack":"Error: Could not find Chrome (ver. 116.0.5845.96). This can occur if either\n 1. you did not perform an installation before running the script (e.g. `npm install`) or\n 2. your cache path is incorrectly configured (which is: /home/grafana/.cache/puppeteer).\nFor (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.\n    at ChromeLauncher.resolveExecutablePath (/opt/grafana-image-renderer/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:300:27)\n    at ChromeLauncher.executablePath (/opt/grafana-image-renderer/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:180:25)\n    at ChromeLauncher.computeLaunchArguments (/opt/grafana-image-renderer/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:97:37)\n    at async ChromeLauncher.launch (/opt/grafana-image-renderer/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:79:28)\n    at async Browser.render (/opt/grafana-image-renderer/build/browser/browser.js:227:23)\n    at async HttpServer.render (/opt/grafana-image-renderer/build/service/http-server.js:53:28)","url":"/render?deviceScaleFactor=1.000000&domain=localhost&encoding=&height=500&renderKey=Nh8z0RtEtlUZrsa28cw3OCakuYPPdNaY&timeout=60&timezone=Australia%2FBrisbane&url=http%3A%2F%2Flocalhost%3A3000%2Fd-solo%2FrErn5j0Sk%2Fm-bus-data%3ForgId%3D1%26from%3D1712141474590%26to%3D1713265796668%26panelId%3D2%26width%3D1000%26height%3D500%26tz%3DAustralia%252FBrisbane%26render%3D1&width=1000"}

De-JSON-ifying the stack:

Error: Could not find Chrome (ver. 116.0.5845.96). This can occur if either
 1. you did not perform an installation before running the script (e.g. `npm install`) or
 2. your cache path is incorrectly configured (which is: /home/grafana/.cache/puppeteer).
For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.
    at ChromeLauncher.resolveExecutablePath (/opt/grafana-image-renderer/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:300:27)
    at ChromeLauncher.executablePath (/opt/grafana-image-renderer/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:180:25)
    at ChromeLauncher.computeLaunchArguments (/opt/grafana-image-renderer/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:97:37)
    at async ChromeLauncher.launch (/opt/grafana-image-renderer/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:79:28)
    at async Browser.render (/opt/grafana-image-renderer/build/browser/browser.js:227:23)
    at async HttpServer.render (/opt/grafana-image-renderer/build/service/http-server.js:53:28)

Now… chromium is installed:

~ # apk list chromium
WARNING: opening from cache https://dl-cdn.alpinelinux.org/alpine/v3.19/main: No such file or directory
WARNING: opening from cache https://dl-cdn.alpinelinux.org/alpine/v3.19/community: No such file or directory
chromium-124.0.6367.78-r0 x86_64 {chromium} (BSD-3-Clause) [installed]
~ # which chromium
/usr/bin/chromium
~ # which chromium-browser
/usr/bin/chromium-browser

These are shell-script wrappers, around /usr/lib/chromium/chromium, which has all its dependencies present and accounted for:

~ # ldd /usr/lib/chromium/chromium
        /lib/ld-musl-x86_64.so.1 (0x7f98a42c8000)
        libgobject-2.0.so.0 => /usr/lib/libgobject-2.0.so.0 (0x7f9897a0f000)
        libglib-2.0.so.0 => /usr/lib/libglib-2.0.so.0 (0x7f98978c3000)
        libicui18n.so.74 => /usr/lib/libicui18n.so.74 (0x7f9897628000)
        libicuuc.so.74 => /usr/lib/libicuuc.so.74 (0x7f9897484000)
        libsmime3.so => /usr/lib/libsmime3.so (0x7f989745c000)
        libnss3.so => /usr/lib/libnss3.so (0x7f9897324000)
        libnssutil3.so => /usr/lib/libnssutil3.so (0x7f98972f8000)
        libnspr4.so => /usr/lib/libnspr4.so (0x7f98972b9000)
        libdbus-1.so.3 => /usr/lib/libdbus-1.so.3 (0x7f9897274000)
        libatk-1.0.so.0 => /usr/lib/libatk-1.0.so.0 (0x7f9897252000)
        libatk-bridge-2.0.so.0 => /usr/lib/libatk-bridge-2.0.so.0 (0x7f989721c000)
        libcups.so.2 => /usr/lib/libcups.so.2 (0x7f9897192000)
        libgio-2.0.so.0 => /usr/lib/libgio-2.0.so.0 (0x7f9896fc5000)
        libdrm.so.2 => /usr/lib/libdrm.so.2 (0x7f9896faf000)
        libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0x7f9896f71000)
        libz.so.1 => /lib/libz.so.1 (0x7f9896f57000)
        libdouble-conversion.so.3 => /usr/lib/libdouble-conversion.so.3 (0x7f9896f41000)
        libevent-2.1.so.7 => /usr/lib/libevent-2.1.so.7 (0x7f9896ef7000)
        libatspi.so.0 => /usr/lib/libatspi.so.0 (0x7f9896ec5000)
        libbrotlidec.so.1 => /usr/lib/libbrotlidec.so.1 (0x7f9896eb6000)
        libzstd.so.1 => /usr/lib/libzstd.so.1 (0x7f9896e07000)
        libexpat.so.1 => /usr/lib/libexpat.so.1 (0x7f9896de6000)
        libwebp.so.7 => /usr/lib/libwebp.so.7 (0x7f9896d72000)
        libwebpdemux.so.2 => /usr/lib/libwebpdemux.so.2 (0x7f9896d6c000)
        libwebpmux.so.3 => /usr/lib/libwebpmux.so.3 (0x7f9896d5f000)
        libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x7f9896cbb000)
        libjpeg.so.8 => /usr/lib/libjpeg.so.8 (0x7f9896c10000)
        libharfbuzz-subset.so.0 => /usr/lib/libharfbuzz-subset.so.0 (0x7f9896b1d000)
        libharfbuzz.so.0 => /usr/lib/libharfbuzz.so.0 (0x7f9896a11000)
        libopus.so.0 => /usr/lib/libopus.so.0 (0x7f98969b0000)
        libavcodec.so.60 => /usr/lib/libavcodec.so.60 (0x7f98954f3000)
        libavformat.so.60 => /usr/lib/libavformat.so.60 (0x7f9895264000)
        libavutil.so.58 => /usr/lib/libavutil.so.58 (0x7f989414f000)
        libopenh264.so.7 => /usr/lib/libopenh264.so.7 (0x7f9893fc3000)
        libdav1d.so.7 => /usr/lib/libdav1d.so.7 (0x7f9893dee000)
        libX11.so.6 => /usr/lib/libX11.so.6 (0x7f9893cd2000)
        libXcomposite.so.1 => /usr/lib/libXcomposite.so.1 (0x7f9893ccd000)
        libXdamage.so.1 => /usr/lib/libXdamage.so.1 (0x7f9893cc8000)
        libXext.so.6 => /usr/lib/libXext.so.6 (0x7f9893cb7000)
        libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0x7f9893caf000)
        libXrandr.so.2 => /usr/lib/libXrandr.so.2 (0x7f9893ca3000)
        libpipewire-0.3.so.0 => /usr/lib/libpipewire-0.3.so.0 (0x7f9893be9000)
        libgbm.so.1 => /usr/lib/libgbm.so.1 (0x7f9893bda000)
        libcrc32c.so.1 => /usr/lib/libcrc32c.so.1 (0x7f9893bd3000)
        libxcb.so.1 => /usr/lib/libxcb.so.1 (0x7f9893bac000)
        libxkbcommon.so.0 => /usr/lib/libxkbcommon.so.0 (0x7f9893b6d000)
        libffi.so.8 => /usr/lib/libffi.so.8 (0x7f9893b63000)
        libpango-1.0.so.0 => /usr/lib/libpango-1.0.so.0 (0x7f9893b0f000)
        libcairo.so.2 => /usr/lib/libcairo.so.2 (0x7f9893a23000)
        libasound.so.2 => /usr/lib/libasound.so.2 (0x7f9893941000)
        libpulse.so.0 => /usr/lib/libpulse.so.0 (0x7f98938f6000)
        libFLAC.so.12 => /usr/lib/libFLAC.so.12 (0x7f9893894000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0x7f9893785000)
        libminizip.so.1 => /usr/lib/libminizip.so.1 (0x7f989377a000)
        libxslt.so.1 => /usr/lib/libxslt.so.1 (0x7f9893741000)
        liblcms2.so.2 => /usr/lib/liblcms2.so.2 (0x7f98936ef000)
        libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x7f98936cb000)
        libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7f98a42c8000)
        libintl.so.8 => /usr/lib/libintl.so.8 (0x7f98936b9000)
        libpcre2-8.so.0 => /usr/lib/libpcre2-8.so.0 (0x7f9893612000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x7f9893379000)
        libicudata.so.74 => /usr/lib/libicudata.so.74 (0x7f9893376000)
        libplds4.so => /usr/lib/libplds4.so (0x7f9893371000)
        libplc4.so => /usr/lib/libplc4.so (0x7f989336a000)
        libavahi-common.so.3 => /usr/lib/libavahi-common.so.3 (0x7f989335d000)
        libavahi-client.so.3 => /usr/lib/libavahi-client.so.3 (0x7f989334d000)
        libgnutls.so.30 => /usr/lib/libgnutls.so.30 (0x7f9893178000)
        libgmodule-2.0.so.0 => /usr/lib/libgmodule-2.0.so.0 (0x7f9893171000)
        libmount.so.1 => /lib/libmount.so.1 (0x7f989312f000)
        libXi.so.6 => /usr/lib/libXi.so.6 (0x7f989311e000)
        libbrotlicommon.so.1 => /usr/lib/libbrotlicommon.so.1 (0x7f98930fb000)
        libsharpyuv.so.0 => /usr/lib/libsharpyuv.so.0 (0x7f98930f3000)
        libbz2.so.1 => /usr/lib/libbz2.so.1 (0x7f98930df000)
        libpng16.so.16 => /usr/lib/libpng16.so.16 (0x7f98930b0000)
        libgraphite2.so.3 => /usr/lib/libgraphite2.so.3 (0x7f9893091000)
        libswresample.so.5 => /usr/lib/libswresample.so.5 (0x7f9893072000)
        libvpx.so.8 => /usr/lib/libvpx.so.8 (0x7f9892d94000)
        libaom.so.3 => /usr/lib/libaom.so.3 (0x7f9892612000)
        libjxl.so.0.8 => /usr/lib/libjxl.so.0.8 (0x7f9892177000)
        libjxl_threads.so.0.8 => /usr/lib/libjxl_threads.so.0.8 (0x7f9892171000)
        libmp3lame.so.0 => /usr/lib/libmp3lame.so.0 (0x7f9892107000)
        librav1e.so.0.6 => /usr/lib/librav1e.so.0.6 (0x7f9891eca000)
        libSvtAv1Enc.so.1 => /usr/lib/libSvtAv1Enc.so.1 (0x7f989170d000)
        libtheoraenc.so.1 => /usr/lib/libtheoraenc.so.1 (0x7f98916d2000)
        libtheoradec.so.1 => /usr/lib/libtheoradec.so.1 (0x7f98916b8000)
        libvorbis.so.0 => /usr/lib/libvorbis.so.0 (0x7f9891690000)
        libvorbisenc.so.2 => /usr/lib/libvorbisenc.so.2 (0x7f98915f9000)
        libx264.so.164 => /usr/lib/libx264.so.164 (0x7f98912cd000)
        libx265.so.199 => /usr/lib/libx265.so.199 (0x7f989005c000)
        libxvidcore.so.4 => /usr/lib/libxvidcore.so.4 (0x7f988ff90000)
        libva.so.2 => /usr/lib/libva.so.2 (0x7f988ff66000)
        libvpl.so.2 => /usr/lib/libvpl.so.2 (0x7f988ff2a000)
        libopenmpt.so.0 => /usr/lib/libopenmpt.so.0 (0x7f988fda7000)
        libbluray.so.2 => /usr/lib/libbluray.so.2 (0x7f988fd56000)
        libssl.so.3 => /lib/libssl.so.3 (0x7f988fcd0000)
        libcrypto.so.3 => /lib/libcrypto.so.3 (0x7f988f8b3000)
        librist.so.4 => /usr/lib/librist.so.4 (0x7f988f88f000)
        libsrt.so.1.5 => /usr/lib/libsrt.so.1.5 (0x7f988f7b2000)
        libssh.so.4 => /usr/lib/libssh.so.4 (0x7f988f759000)
        libzmq.so.5 => /usr/lib/libzmq.so.5 (0x7f988f6a2000)
        libva-drm.so.2 => /usr/lib/libva-drm.so.2 (0x7f988f69d000)
        libva-x11.so.2 => /usr/lib/libva-x11.so.2 (0x7f988f696000)
        libvdpau.so.1 => /usr/lib/libvdpau.so.1 (0x7f988f691000)
        libXrender.so.1 => /usr/lib/libXrender.so.1 (0x7f988f684000)
        libwayland-server.so.0 => /usr/lib/libwayland-server.so.0 (0x7f988f673000)
        libxcb-randr.so.0 => /usr/lib/libxcb-randr.so.0 (0x7f988f663000)
        libXau.so.6 => /usr/lib/libXau.so.6 (0x7f988f65e000)
        libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0x7f988f656000)
        libfribidi.so.0 => /usr/lib/libfribidi.so.0 (0x7f988f639000)
        libxcb-render.so.0 => /usr/lib/libxcb-render.so.0 (0x7f988f62b000)
        libxcb-shm.so.0 => /usr/lib/libxcb-shm.so.0 (0x7f988f626000)
        libpixman-1.so.0 => /usr/lib/libpixman-1.so.0 (0x7f988f597000)
        libpulsecommon-16.1.so => /usr/lib/pulseaudio/libpulsecommon-16.1.so (0x7f988f51f000)
        libogg.so.0 => /usr/lib/libogg.so.0 (0x7f988f515000)
        liblzma.so.5 => /usr/lib/liblzma.so.5 (0x7f988f4de000)
        libp11-kit.so.0 => /usr/lib/libp11-kit.so.0 (0x7f988f3ad000)
        libidn2.so.0 => /usr/lib/libidn2.so.0 (0x7f988f37c000)
        libunistring.so.5 => /usr/lib/libunistring.so.5 (0x7f988f1de000)
        libtasn1.so.6 => /usr/lib/libtasn1.so.6 (0x7f988f1cc000)
        libnettle.so.8 => /usr/lib/libnettle.so.8 (0x7f988f180000)
        libhogweed.so.6 => /usr/lib/libhogweed.so.6 (0x7f988f13a000)
        libgmp.so.10 => /usr/lib/libgmp.so.10 (0x7f988f0d0000)
        libblkid.so.1 => /lib/libblkid.so.1 (0x7f988f0a0000)
        libsoxr.so.0 => /usr/lib/libsoxr.so.0 (0x7f988f044000)
        libhwy.so.1 => /usr/lib/libhwy.so.1 (0x7f988f039000)
        libbrotlienc.so.1 => /usr/lib/libbrotlienc.so.1 (0x7f988ef83000)
        libnuma.so.1 => /usr/lib/libnuma.so.1 (0x7f988ef77000)
        libmpg123.so.0 => /usr/lib/libmpg123.so.0 (0x7f988ef3b000)
        libvorbisfile.so.3 => /usr/lib/libvorbisfile.so.3 (0x7f988ef32000)
        libmbedcrypto.so.7 => /usr/lib/libmbedcrypto.so.7 (0x7f988eeca000)
        libcjson.so.1 => /usr/lib/libcjson.so.1 (0x7f988eec2000)
        libsodium.so.26 => /usr/lib/libsodium.so.26 (0x7f988ee6e000)
        libX11-xcb.so.1 => /usr/lib/libX11-xcb.so.1 (0x7f988ee69000)
        libxcb-dri3.so.0 => /usr/lib/libxcb-dri3.so.0 (0x7f988ee63000)
        libbsd.so.0 => /usr/lib/libbsd.so.0 (0x7f988ee50000)
        libsndfile.so.1 => /usr/lib/libsndfile.so.1 (0x7f988ede6000)
        libasyncns.so.0 => /usr/lib/libasyncns.so.0 (0x7f988eddf000)
        libgomp.so.1 => /usr/lib/libgomp.so.1 (0x7f988ed91000)
        libmd.so.0 => /usr/lib/libmd.so.0 (0x7f988ed83000)
~ # chromium --version
Chromium 124.0.6367.78 Alpine Linux

What I've tried:

  • Tried using grafana-cli install grafana-image-renderer: fails and crashes Grafana because it tries to launch a binary linked against glibc not the musl C library that AlpineLinux uses.
  • Tried using the grafana-image-renderer package shipped by AlpineLinux: saw the above message
  • Tried installing grafana-image-renderer via git: saw the above message
  • Tried symlinking /usr/bin/chromium-browser to /usr/bin/chrome (like is done in Grafana's own image renderer container): saw the above message
  • Tried setting GF_PLUGIN_RENDERING_CHROME_BIN as per the troubleshooting docs: saw the above message

Environment:

  • Grafana Image Renderer version: 3.10.3
  • Grafana version: 9.4.0
  • Installed plugin or remote renderer service: remote renderer service (inside the same container)
  • OS Grafana Image Renderer is installed on: Alpine Linux 3.19
  • User OS & Browser: Gentoo Linux/AMD64 & Firefox 115.9.1esr
  • Others:

More tinkering, it seems I have to set both GF_PLUGIN_RENDERING_CHROME_BIN AND CHROME_BIN.

Not sure if maybe process.env.CHROME_BIN can be set to process.env.GF_PLUGIN_RENDERING_CHROME_BIN before importing the underlying library to gracefully handle this… but the error message is misleading to say the least.

I'll leave this open for a bit while I test, but I think I may have found the answer to the question.