Skip to content

Commit d5a7e44

Browse files
authored
Docker: Move to distroless Debian (#661)
1 parent 6c80cad commit d5a7e44

File tree

10 files changed

+68
-113
lines changed

10 files changed

+68
-113
lines changed

.dockerignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ scripts
1111
.prettierrc.json
1212
dev.json
1313
Dockerfile
14-
debian.Dockerfile
1514
Makefile
1615
plugin_start*
1716
tslint.json

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## Unreleased (4.0.0)
1+
## 4.0.0 (2025-07-22)
22

33
- Build: Update all dependencies, [#663](https://github.com/grafana/grafana-image-renderer/pull/663), [Proximyst](https://github.com/Proximyst)
44
- Docker: Update Chromium (CVE-2025-6558, CVE-2025-7656, CVE-2025-7657), [#667](https://github.com/grafana/grafana-image-renderer/pull/667), [Proximyst](https://github.com/Proximyst)
@@ -11,6 +11,9 @@ Breaking changes:
1111
- Plugin: Update minimum Grafana version to 11.3.8, [#663](https://github.com/grafana/grafana-image-renderer/pull/663), [Proximyst](https://github.com/Proximyst)
1212
- If you use any Grafana version newer than 11.3.8 (incl. 11.4.x, 11.5.x, 11.6.x, 12.x), you will not have to do anything.
1313
- If you are not in that group, you must update Grafana before updating.
14+
- Docker: Move to distroless Debian, [#661](https://github.com/grafana/grafana-image-renderer/pull/661), [Proximyst](https://github.com/Proximyst)
15+
- In practice, this SHOULD come with no changes for most users.
16+
- If you are building a new Docker image on top of us, you will have to adapt to distroless Debian instead of Alpine.
1417

1518
## 3.12.9 (2025-07-01)
1619

Dockerfile

Lines changed: 37 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,59 @@
1-
# Base stage
2-
FROM node:22-alpine AS base
1+
FROM debian:12-slim AS debian-updated
32

4-
ENV CHROME_BIN="/usr/bin/chromium-browser"
5-
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD="true"
3+
SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
4+
5+
# If we ever need to bust the cache, just change the date here.
6+
# While we don't cache anything in Drone, that might not be true when we migrate to GitHub Actions where some action might automatically enable layer caching.
7+
# This is fine, but is terrible in situations where we want to _force_ an update of a package.
8+
RUN echo 'cachebuster 2025-07-16' && apt-get update
69

7-
# Folder used by puppeteer to write temporal files
8-
ENV XDG_CONFIG_HOME=/tmp/.chromium
9-
ENV XDG_CACHE_HOME=/tmp/.chromium
10+
FROM debian-updated AS debs
1011

11-
WORKDIR /usr/src/app
12+
RUN apt-cache depends chromium chromium-driver chromium-shell chromium-sandbox font-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-khmeros fonts-kacst fonts-freefont-ttf libxss1 unifont fonts-open-sans fonts-roboto fonts-inter bash busybox util-linux openssl \
13+
--recurse --no-recommends --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances --no-pre-depends | grep '^\w' | xargs apt-get download
14+
RUN mkdir /dpkg && \
15+
find . -type f -name '*.deb' -exec sh -c 'dpkg --extract "$1" /dpkg || exit 5' sh '{}' \;
1216

13-
# We use edge for Chromium to get the latest release.
14-
RUN apk --no-cache upgrade && \
15-
apk add --no-cache udev ttf-opensans unifont ca-certificates dumb-init && \
16-
apk add --no-cache 'chromium>=138.0.7204.157' 'chromium-swiftshader>=138.0.7204.157' --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community && \
17-
# Remove NPM-related files and directories
18-
rm -rf /usr/local/lib/node_modules/npm && \
19-
rm -rf /usr/local/bin/npm && \
20-
rm -rf /usr/local/bin/npx && \
21-
rm -rf /root/.npm && \
22-
rm -rf /root/.node-gyp && \
23-
# Clean up
24-
rm -rf /tmp/*
17+
FROM debian:testing-slim AS ca-certs
2518

26-
# Build stage
27-
FROM base AS build
19+
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates
20+
RUN update-ca-certificates --fresh
2821

22+
FROM node:22-alpine AS build
23+
24+
WORKDIR /src
2925
COPY . ./
3026

3127
RUN yarn install --pure-lockfile
3228
RUN yarn run build
29+
RUN rm -rf node_modules/ && yarn install --pure-lockfile --production
3330

34-
# Production dependencies stage
35-
FROM base AS prod-dependencies
36-
37-
COPY package.json yarn.lock ./
38-
RUN yarn install --pure-lockfile --production
39-
40-
# Final stage
41-
FROM base
31+
FROM gcr.io/distroless/nodejs22-debian12:nonroot
4232

4333
LABEL maintainer="Grafana team <[email protected]>"
4434
LABEL org.opencontainers.image.source="https://github.com/grafana/grafana-image-renderer/tree/master/Dockerfile"
4535

46-
ARG GF_UID="472"
47-
ARG GF_GID="472"
48-
ENV GF_PATHS_HOME="/usr/src/app"
49-
50-
WORKDIR $GF_PATHS_HOME
36+
COPY --from=debs /dpkg /
37+
COPY --from=ca-certs /etc/ssl/certs /etc/ssl/certs
5138

52-
RUN addgroup -S -g $GF_GID grafana && \
53-
adduser -S -u $GF_UID -G grafana grafana && \
54-
mkdir -p "$GF_PATHS_HOME" && \
55-
chown -R grafana:grafana "$GF_PATHS_HOME"
39+
USER root
40+
SHELL ["/bin/busybox", "sh", "-c"]
41+
RUN /bin/busybox --install
42+
# Verify that the browser was actually installed.
43+
RUN /usr/bin/chromium --version
44+
RUN fc-cache -fr
45+
USER nonroot
5646

47+
ENV CHROME_BIN="/usr/bin/chromium"
48+
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD="true"
5749
ENV NODE_ENV=production
5850

59-
COPY --from=prod-dependencies /usr/src/app/node_modules node_modules
60-
COPY --from=build /usr/src/app/build build
61-
COPY --from=build /usr/src/app/proto proto
62-
COPY --from=build /usr/src/app/default.json config.json
63-
COPY --from=build /usr/src/app/plugin.json plugin.json
51+
COPY --from=build /src/node_modules node_modules
52+
COPY --from=build /src/build build
53+
COPY --from=build /src/proto proto
54+
COPY --from=build /src/default.json config.json
55+
COPY --from=build /src/plugin.json plugin.json
6456

6557
EXPOSE 8081
6658

67-
USER grafana
68-
69-
ENTRYPOINT ["dumb-init", "--"]
70-
CMD ["node", "build/app.js", "server", "--config=config.json"]
59+
CMD ["build/app.js", "server", "--config=config.json"]

Makefile

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: all clean deps build clean_package package archive build_package docker-alpine docker-debian
1+
.PHONY: all clean deps build clean_package package archive build_package docker
22

33
ARCH = darwin-x64-unknown
44
SKIP_CHROMIUM =
@@ -30,12 +30,9 @@ archive:
3030

3131
build_package: clean clean_package build package archive
3232

33-
docker-alpine:
33+
docker:
3434
docker build -t grafana/grafana-image-renderer:${DOCKER_TAG} .
3535

36-
docker-debian:
37-
docker build -t grafana/grafana-image-renderer:${DOCKER_TAG}-debian -f debian.Dockerfile .
38-
3936
# This repository's configuration is protected (https://readme.drone.io/signature/).
4037
# Use this make target to regenerate the configuration YAML files when
4138
# you modify starlark files.

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ You can install the plugin using Grafana CLI (recommended way) or with Grafana D
3333
### Grafana CLI (recommended)
3434

3535
```bash
36-
grafana-cli plugins install grafana-image-renderer
36+
grafana cli plugins install grafana-image-renderer
3737
```
3838

39+
Please run this as the same user that Grafana runs as.
40+
3941
### Grafana Docker image
4042

4143
This plugin is not compatible with the current Grafana Docker image and requires additional system-level dependencies. We recommend setting up another Docker container for rendering and using remote rendering instead. For instruction, refer to [Run in Docker](#run-in-docker).
@@ -134,4 +136,4 @@ For available configuration settings, please refer to [Grafana Image Rendering d
134136
## Troubleshooting
135137

136138
For troubleshooting help, refer to
137-
[Grafana Image Rendering troubleshooting documentation](https://grafana.com/docs/grafana/latest/image-rendering/troubleshooting/).
139+
[Grafana Image Rendering troubleshooting documentation](https://grafana.com/docs/grafana/latest/image-rendering/troubleshooting/).

debian.Dockerfile

Lines changed: 0 additions & 54 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
services:
2+
grafana:
3+
image: grafana/grafana-enterprise:latest
4+
ports:
5+
- 3000:3000
6+
environment:
7+
GF_RENDERING_SERVER_URL: http://renderer:8081/render
8+
GF_RENDERING_CALLBACK_URL: http://grafana:3000/
9+
GF_LOG_FILTERS: rendering:debug
10+
11+
renderer:
12+
build:
13+
context: ../../../
14+
dockerfile: Dockerfile
15+
ports:
16+
- 8081
17+
environment:
18+
ENABLE_METRICS: 'true'

plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
}
2626
],
2727
"version": "4.0.0",
28-
"updated": "2025-07-01"
28+
"updated": "2025-07-22"
2929
},
3030
"dependencies": {
3131
"grafanaDependency": ">=11.3.8"

src/service/http-server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export class HttpServer {
131131

132132
try {
133133
const browserVersion = await this.browser.getBrowserVersion();
134+
this.log.info('Browser version', 'version', browserVersion);
134135
browserInfo.labels(browserVersion).set(1);
135136
} catch {
136137
this.log.error('Failed to get browser version');

src/service/metrics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import promBundle from 'express-prom-bundle';
22
import * as promClient from 'prom-client';
3-
import * as onFinished from 'on-finished';
3+
import onFinished from 'on-finished';
44
import { Express } from 'express';
55

66
import { MetricsConfig } from './config';

0 commit comments

Comments
 (0)