From 091fe456ad29895f6df05d9ff0cb8ac1d1e79198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Thu, 27 Aug 2026 11:10:26 +0200 Subject: [PATCH] :whale: Migrate media-processor image to DHI and wire up its build" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .gitignore | 1 + docker/images/Dockerfile.media-processor | 62 ++++++++++++------------ manage.sh | 32 ++++++++++++ mcp/scripts/build | 2 +- media-processor/scripts/build | 27 +++++++++++ 5 files changed, 92 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index f076619f74..7d4f91e50b 100644 --- a/.gitignore +++ b/.gitignore @@ -91,6 +91,7 @@ opencode.json /playwright/.cache/ /render-wasm/target/ /media-processor/dist/ +/media-processor/target/ /**/node_modules /**/.yarn/* /.pnpm-store diff --git a/docker/images/Dockerfile.media-processor b/docker/images/Dockerfile.media-processor index a147b9d8b3..0671d7d820 100644 --- a/docker/images/Dockerfile.media-processor +++ b/docker/images/Dockerfile.media-processor @@ -1,18 +1,16 @@ -FROM ubuntu:26.04 +# syntax=docker/dockerfile:1 +FROM dhi.io/node:24.20.0-debian13-dev LABEL maintainer="Penpot " 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"] diff --git a/manage.sh b/manage.sh index e0c39e9d27..0cbc4e7cd7 100755 --- a/manage.sh +++ b/manage.sh @@ -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}" ;; diff --git a/mcp/scripts/build b/mcp/scripts/build index c7e2b1f922..3e5337fda2 100755 --- a/mcp/scripts/build +++ b/mcp/scripts/build @@ -32,7 +32,7 @@ cp pnpm-lock.yaml ./dist/; touch ./dist/pnpm-workspace.yaml; cat </dev/null || { echo "error: pnpm not found in PATH" >&2; exit 1; }; pnpm install -P diff --git a/media-processor/scripts/build b/media-processor/scripts/build index 94ec8e856c..e04a402c09 100755 --- a/media-processor/scripts/build +++ b/media-processor/scripts/build @@ -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 < /dev/null +#!/usr/bin/env bash +set -e; +corepack enable; +corepack install; +pnpm install -P; +SETUP + +chmod +x target/setup