From 36bccfa74885d8b4ff8d76e06280f8ce5329a98d Mon Sep 17 00:00:00 2001 From: Alexandre Galtier Date: Mon, 16 Sep 2024 22:01:44 +0200 Subject: [PATCH] Docker improvement and fix screenshots . Dockerfile optimization (reorder) . Docker: Add xvfb package . Docker: Add entrypoint.sh . Launch dbus at container start (entrypoint.sh) . Lauch Xvfb at container start (entrypoint.sh) . Above fix screenshot error on docker . Add environment variables: . . SCREEN_RESOLUTION: for Xvfb resolution . . BROWSER_WIDTH: for screenshot . . BROWSER_HEIGHT: for screenshot . . BROWSER_TIMEOUT: for screenshot --- Dockerfile | 37 ++++++++++++++++++++++++------------- api/screenshot.js | 8 ++++++-- entrypoint.sh | 12 ++++++++++++ 3 files changed, 42 insertions(+), 15 deletions(-) create mode 100755 entrypoint.sh diff --git a/Dockerfile b/Dockerfile index a01ddd8e..14298834 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,6 @@ +########################### +#### APP Build ##### +########################### # Specify the Node.js version to use ARG NODE_VERSION=21 @@ -11,13 +14,12 @@ FROM node:${NODE_VERSION}-${DEBIAN_VERSION} AS build SHELL ["/bin/bash", "-euo", "pipefail", "-c"] # Install Chromium browser and Download and verify Google Chrome’s signing key -RUN apt-get update -qq --fix-missing && \ - apt-get -qqy install --allow-unauthenticated gnupg wget && \ +RUN apt-get update --quiet --yes --fix-missing && \ + DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes install --allow-unauthenticated gnupg wget && \ wget --quiet --output-document=- https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor > /etc/apt/trusted.gpg.d/google-archive.gpg && \ echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \ - apt-get update -qq && \ - apt-get -qqy --no-install-recommends install chromium traceroute python make g++ && \ - rm -rf /var/lib/apt/lists/* + apt-get update --quiet --yes && \ + DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes --no-install-recommends install chromium traceroute python make g++ # Run the Chromium browser's version command and redirect its output to the /etc/chromium-version file RUN /usr/bin/chromium --no-sandbox --version > /etc/chromium-version @@ -29,8 +31,10 @@ WORKDIR /app COPY package.json yarn.lock ./ # Run yarn install to install dependencies and clear yarn cache -RUN apt-get update && \ - yarn install --frozen-lockfile --network-timeout 100000 && \ +RUN yarn install --frozen-lockfile --network-timeout 100000 + +# Cleanup +RUN rm -rf /var/lib/apt/lists/* && \ rm -rf /app/node_modules/.cache # Copy all files to working directory @@ -39,24 +43,31 @@ COPY . . # Run yarn build to build the application RUN yarn build --production -# Final stage + +########################### +#### Final STAGE ##### +########################### FROM node:${NODE_VERSION}-${DEBIAN_VERSION} AS final +RUN apt-get update --yes && \ + DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends chromium traceroute xvfb && \ + chmod 755 /usr/bin/chromium && \ + rm -rf /var/lib/apt/lists/* /app/node_modules/.cache + WORKDIR /app COPY package.json yarn.lock ./ COPY --from=build /app . -RUN apt-get update && \ - apt-get install -y --no-install-recommends chromium traceroute && \ - chmod 755 /usr/bin/chromium && \ - rm -rf /var/lib/apt/lists/* /app/node_modules/.cache - # Exposed container port, the default is 3000, which can be modified through the environment variable PORT EXPOSE ${PORT:-3000} # Set the environment variable CHROME_PATH to specify the path to the Chromium binaries ENV CHROME_PATH='/usr/bin/chromium' +# Entrypoint to lauchn +COPY --chmod=755 entrypoint.sh /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] + # Define the command executed when the container starts and start the server.js of the Node.js application CMD ["yarn", "start"] diff --git a/api/screenshot.js b/api/screenshot.js index f6d33bf5..468e0e67 100644 --- a/api/screenshot.js +++ b/api/screenshot.js @@ -20,9 +20,12 @@ const screenshotHandler = async (targetUrl) => { let browser = null; try { + const width = process.env.BROWSER_WIDTH ? parseInt(process.env.BROWSER_WIDTH, 10) : 800; + const height = process.env.BROWSER_HEIGHT ? parseInt(process.env.BROWSER_HEIGHT, 10) : 600; + browser = await puppeteer.launch({ args: [...chromium.args, '--no-sandbox'], // Add --no-sandbox flag - defaultViewport: { width: 800, height: 600 }, + defaultViewport: { width, height }, executablePath: process.env.CHROME_PATH || await chromium.executablePath, headless: chromium.headless, ignoreHTTPSErrors: true, @@ -32,7 +35,8 @@ const screenshotHandler = async (targetUrl) => { let page = await browser.newPage(); await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]); - page.setDefaultNavigationTimeout(8000); + const browserTimeout = process.env.BROWSER_TIMEOUT ? parseInt(process.env.BROWSER_TIMEOUT, 10) : 8000; + page.setDefaultNavigationTimeout(browserTimeout); await page.goto(targetUrl, { waitUntil: 'domcontentloaded' }); await page.evaluate(() => { diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 00000000..004eb7c9 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +SCREEN_RESOLUTION="${SCREEN_RESOLUTION:-1280x1024x24}" +if [[ ! "${SCREEN_RESOLUTION}" =~ ^[0-9]+x[0-9]+x(8|16|24)$ ]]; then + echo "SCREEN_RESOLUTION must match screen resolution like '1280x1024x24'" + echo "last number (color) must be 8,16 or 24" + exit 1 +fi + +service dbus start +[[ -z "${DISPLAY}" ]] && export DISPLAY=":99" +Xvfb "${DISPLAY}" -screen 0 "${SCREEN_RESOLUTION}" & +exec "${@}"