🐳 Migrate media-processor image to DHI and wire up its build"

Migrate docker/images/Dockerfile.media-processor from ubuntu:26.04 to
dhi.io/node (Debian 13/trixie), which also drops the manual Node tarball
download since the base image ships it. The -dev tag stays as the final
image: fontforge, woff2 and the graphics libraries are needed at runtime.

scripts/build now assembles the release bundle under target/ (dist/ plus
the manifests and a generated setup script), the way the other modules do,
since esbuild leaves the runtime dependencies external. manage.sh gains
build-media-processor-bundle and build-media-processor-docker-image, both
wired into build-bundle and build-docker-images.

The CI workflows are intentionally left untouched: the module is still work
in progress and its images are not published yet, so this only enables
local builds."

Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>
This commit is contained in:
David Barragán Merino 2026-08-27 11:10:26 +02:00 committed by David Barragán Merino
parent a534e49abc
commit 091fe456ad
5 changed files with 92 additions and 32 deletions

1
.gitignore vendored
View File

@ -91,6 +91,7 @@ opencode.json
/playwright/.cache/
/render-wasm/target/
/media-processor/dist/
/media-processor/target/
/**/node_modules
/**/.yarn/*
/.pnpm-store

View File

@ -1,18 +1,16 @@
FROM ubuntu:26.04
# syntax=docker/dockerfile:1
FROM dhi.io/node:24.20.0-debian13-dev
LABEL maintainer="Penpot <docker@penpot.app>"
ENV LANG=en_US.UTF-8 \
LC_ALL=en_US.UTF-8 \
NODE_VERSION=v24.20.0 \
PNPM_VERSION=12.5.1 \
DEBIAN_FRONTEND=noninteractive \
PATH=/opt/node/bin:$PATH
DEBIAN_FRONTEND=noninteractive
# passwd provides useradd, not preinstalled on the DHI base image.
RUN set -ex; \
useradd -U -M -u 1001 -s /bin/false -d /opt/penpot penpot; \
mkdir -p /etc/resolvconf/resolv.conf.d; \
echo "nameserver 127.0.0.11" > /etc/resolvconf/resolv.conf.d/tail; \
apt-get -qq update; \
apt-get -qqy --no-install-recommends install passwd; \
useradd -U -M -u 1001 -s /bin/false -d /opt/penpot penpot; \
apt-get -qq -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade; \
apt-get -qqy --no-install-recommends install \
curl \
@ -35,7 +33,7 @@ RUN set -ex; \
\
libgomp1 \
libheif1 \
libjpeg-turbo8 \
libjpeg62-turbo \
liblcms2-2 \
libopenexr-3-1-30 \
libopenjp2-7 \
@ -45,23 +43,35 @@ RUN set -ex; \
libwebp7 \
libwebpdemux2 \
libwebpmux3 \
libxml2-16 \
libxml2 \
libzip5 \
libzstd1 \
; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*;
rm -rf /var/lib/apt/lists/*; \
mkdir -p /opt/penpot; \
chown -R penpot:penpot /opt/penpot;
ARG BUNDLE_PATH="./bundle-media-processor/"
COPY --chown=penpot:penpot $BUNDLE_PATH /opt/penpot/media-processor/
WORKDIR /opt/penpot/media-processor
# pnpm ships as a system binary (same tarball + SHA pin as
# docker/devenv/Dockerfile); ./setup expects it on PATH.
# Corepack is gone from Node 25+, so nothing here may use it.
ARG PNPM_VERSION=12.5.1
RUN set -eux; \
apt-get -qq update; \
apt-get -qqy --no-install-recommends install gzip; \
rm -rf /var/lib/apt/lists/*; \
ARCH="$(dpkg --print-architecture)"; \
case "${ARCH}" in \
aarch64|arm64) \
BINARY_URL="https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-arm64.tar.gz"; \
PNPM_ARCH='arm64'; \
PNPM_SHA256='84e1290e82c800acd406b6db27e9650e15db3c2344d12162cc305ea1f942c6ff'; \
;; \
amd64|x86_64) \
BINARY_URL="https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.gz"; \
PNPM_ARCH='x64'; \
PNPM_SHA256='5a397dfb6b3d4b07d3d7769586aeb471048faf04299a492e2808b95a9a1c701f'; \
;; \
@ -70,28 +80,18 @@ RUN set -eux; \
exit 1; \
;; \
esac; \
curl -LfsSo /tmp/nodejs.tar.gz ${BINARY_URL}; \
mkdir -p /opt/node; \
cd /opt/node; \
tar -xf /tmp/nodejs.tar.gz --strip-components=1; \
chown -R root /opt/node; \
rm -rf /tmp/nodejs.tar.gz; \
PNPM_URL="https://github.com/pnpm/pnpm/releases/download/v${PNPM_VERSION}/pnpm-linux-${PNPM_ARCH}.tar.gz"; \
curl -LfsSo /tmp/pnpm.tar.gz "${PNPM_URL}"; \
curl -LfsSo /tmp/pnpm.tar.gz "https://github.com/pnpm/pnpm/releases/download/v${PNPM_VERSION}/pnpm-linux-${PNPM_ARCH}.tar.gz"; \
echo "${PNPM_SHA256} */tmp/pnpm.tar.gz" | sha256sum -c -; \
tar -xzf /tmp/pnpm.tar.gz -C /opt/node/bin pnpm; \
chmod 755 /opt/node/bin/pnpm; \
mkdir -p /usr/local/bin; \
tar -xzf /tmp/pnpm.tar.gz -C /usr/local/bin pnpm; \
chmod 755 /usr/local/bin/pnpm; \
rm -f /tmp/pnpm.tar.gz; \
pnpm --version; \
mkdir -p /opt/penpot; \
chown -R penpot:penpot /opt/penpot;
pnpm --version;
ARG BUNDLE_PATH="./bundle-media-processor/"
COPY --chown=penpot:penpot $BUNDLE_PATH /opt/penpot/media-processor/
# Runs as root: this base image installs Node system-wide (symlinked into
# /usr/bin), so ./setup needs write access there.
RUN ./setup && chown -R penpot:penpot /opt/penpot/media-processor
WORKDIR /opt/penpot/media-processor
USER penpot:penpot
RUN ./setup
CMD ["node", "dist/index.js"]

View File

@ -1235,6 +1235,22 @@ function build-mcp-bundle {
}
function build-media-processor-bundle {
echo ">> bundle media-processor start";
mkdir -p ./bundles
local version=$(print-current-version);
local bundle_dir="./bundles/media-processor";
build "media-processor";
rm -rf $bundle_dir;
mv ./media-processor/target $bundle_dir;
echo $version > $bundle_dir/version.txt;
put-license-file $bundle_dir;
echo ">> bundle media-processor end";
}
function build-backend-bundle {
echo ">> bundle backend start";
@ -1350,6 +1366,10 @@ function build-mcp-docker-image {
_build-release-docker-image mcp bundle-mcp Dockerfile.mcp "$@"
}
function build-media-processor-docker-image {
_build-release-docker-image media-processor bundle-media-processor Dockerfile.media-processor "$@"
}
function build-storybook-docker-image {
_build-release-docker-image storybook bundle-storybook Dockerfile.storybook "$@"
}
@ -1428,6 +1448,7 @@ function usage {
echo "- build-backend-bundle Build backend bundle."
echo "- build-exporter-bundle Build exporter bundle."
echo "- build-mcp-bundle Build mcp bundle."
echo "- build-media-processor-bundle Build media-processor bundle."
echo "- build-storybook-bundle Build storybook bundle."
echo "- build-docs-bundle Build docs bundle."
echo ""
@ -1439,6 +1460,7 @@ function usage {
echo "- build-backend-docker-image [--tag TAG] Build backend docker image."
echo "- build-exporter-docker-image [--tag TAG] Build exporter docker image."
echo "- build-mcp-docker-image [--tag TAG] Build mcp docker image."
echo "- build-media-processor-docker-image [--tag TAG] Build media-processor docker image."
echo "- build-storybook-docker-image [--tag TAG] Build storybook docker image."
echo "- build-imagemagick-docker-image [--tag TAG] [--push]"
echo " Build the imagemagick docker image. Local-only by default (single-"
@ -1494,6 +1516,7 @@ case $1 in
build-bundle)
build-frontend-bundle;
build-mcp-bundle;
build-media-processor-bundle;
build-backend-bundle;
build-exporter-bundle;
build-storybook-bundle;
@ -1507,6 +1530,10 @@ case $1 in
build-mcp-bundle;
;;
build-media-processor-bundle)
build-media-processor-bundle;
;;
build-backend-bundle)
build-backend-bundle;
;;
@ -1528,6 +1555,7 @@ case $1 in
build-backend-docker-image "${@:2}"
build-exporter-docker-image "${@:2}"
build-mcp-docker-image "${@:2}"
build-media-processor-docker-image "${@:2}"
build-storybook-docker-image "${@:2}"
;;
@ -1547,6 +1575,10 @@ case $1 in
build-mcp-docker-image "${@:2}"
;;
build-media-processor-docker-image)
build-media-processor-docker-image "${@:2}"
;;
build-storybook-docker-image)
build-storybook-docker-image "${@:2}"
;;

View File

@ -32,7 +32,7 @@ cp pnpm-lock.yaml ./dist/;
touch ./dist/pnpm-workspace.yaml;
cat <<EOF | tee ./dist/setup
#/usr/bin/env bash
#!/usr/bin/env bash
set -e;
command -v pnpm >/dev/null || { echo "error: pnpm not found in PATH" >&2; exit 1; };
pnpm install -P

View File

@ -1,4 +1,31 @@
#!/bin/bash
set -e
cd "$(dirname "$0")/.."
# package.json pins pnpm via "packageManager", so the first build on a fresh
# devenv makes corepack fetch it. Without this it asks for confirmation on
# stdin, which hangs a CI build (and aborts an interactive one); `corepack
# install` then fetches the pinned version explicitly.
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
corepack install
pnpm run build
# Assemble the release bundle under target/, the way the other modules do.
# esbuild leaves the runtime dependencies external (sharp, pino, pino-pretty,
# pino-loki), so the image has to install them on build: ship the manifests
# next to dist/ plus a setup script for Dockerfile.media-processor to run.
rm -rf target
mkdir -p target
rsync -avr --delete dist/ target/dist/
cp package.json pnpm-lock.yaml pnpm-workspace.yaml target/
cat <<SETUP | tee target/setup > /dev/null
#!/usr/bin/env bash
set -e;
corepack enable;
corepack install;
pnpm install -P;
SETUP
chmod +x target/setup