remote-rdr / Dockerfile.build.multistage
shiveshnavin's picture
Add common-utils build stage to multi-stage Dockerfile
6970102
# Multi-stage build for better reliability
FROM node:22-bookworm-slim as base
# Install system dependencies in a single layer to reduce image size
RUN apt-get update && apt-get install -y \
libnss3 \
libdbus-1-3 \
libatk1.0-0 \
libgbm-dev \
libasound2 \
libxrandr2 \
libxkbcommon-dev \
libxfixes3 \
libxcomposite1 \
libxdamage1 \
libatk-bridge2.0-0 \
libpango-1.0-0 \
libcairo2 \
libcups2 \
bash \
git git-lfs \
wget curl procps \
htop vim nano \
xz-utils \
xvfb x11-utils \
nginx \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
# Install FFmpeg 8 from static build with error handling
RUN set -e && \
wget --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 -t 3 \
https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \
tar -xf ffmpeg-release-amd64-static.tar.xz && \
mv ffmpeg-*-amd64-static/ffmpeg /usr/local/bin/ffmpeg && \
mv ffmpeg-*-amd64-static/ffprobe /usr/local/bin/ffprobe && \
chmod +x /usr/local/bin/ffmpeg /usr/local/bin/ffprobe && \
rm -rf ffmpeg-* && \
ln -sf /usr/local/bin/ffmpeg /usr/bin/ffmpeg && \
ln -sf /usr/local/bin/ffprobe /usr/bin/ffprobe && \
ffmpeg -version
# Common-utils build stage - build the local common-utils dependency
FROM base as common-utils-builder
RUN mkdir /app && chown 1000 /app
USER 1000
WORKDIR /app
# Copy common-utils source and package files
COPY --chown=1000 common-utils/ ./common-utils/
# Install TypeScript globally for building common-utils
USER root
RUN npm install -g typescript
USER 1000
# Build common-utils - install dependencies and compile
WORKDIR /app/common-utils
RUN npm install && \
npm run build && \
echo "Common-utils build completed successfully"
# Dependencies stage - isolate dependency installation
FROM base as dependencies
RUN mkdir /app && chown 1000 /app
USER 1000
WORKDIR /app
# Copy package files and npm config first for better caching
COPY --chown=1000 package*.json ./
COPY --chown=1000 .npmrc ./
# Copy built common-utils from the builder stage
COPY --from=common-utils-builder --chown=1000 /app/common-utils ./common-utils
# Set comprehensive npm configurations for reliability and speed
RUN npm config set fetch-retry-mintimeout 20000 && \
npm config set fetch-retry-maxtimeout 120000 && \
npm config set fetch-retries 5 && \
npm config set fetch-timeout 600000 && \
npm config set registry https://registry.npmjs.org/ && \
npm config set audit false && \
npm config set fund false && \
npm config set update-notifier false
# Environment variables to skip problematic binary downloads
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV PUPPETEER_SKIP_DOWNLOAD=true
ENV SKIP_FFMPEG_DOWNLOAD=true
ENV SHARP_IGNORE_GLOBAL_LIBVIPS=1
ENV NODE_ENV=production
ENV CI=true
# Clear any existing npm cache to prevent corruption
RUN npm cache clean --force
# Install dependencies with multiple fallback strategies and comprehensive error handling
# Note: NOT using --no-optional to allow esbuild platform-specific binaries to install
# Skip preinstall script since we already built common-utils
RUN set -e && \
echo "Starting dependency installation..." && \
(timeout 900 npm ci --verbose --ignore-scripts --production=false 2>&1 | tee /tmp/npm-install.log) || \
(echo "First attempt failed, cleaning cache and retrying..." && \
npm cache clean --force && \
rm -rf node_modules package-lock.json && \
timeout 900 npm install --verbose --ignore-scripts --production=false 2>&1 | tee -a /tmp/npm-install.log) || \
(echo "Second attempt failed, trying with reduced concurrency..." && \
npm cache clean --force && \
rm -rf node_modules && \
timeout 1200 npm install --verbose --maxsockets 1 --production=false 2>&1 | tee -a /tmp/npm-install.log)
# Run postinstall scripts separately for better control and debugging
# Skip the common-utils build in postinstall since we already have it built
RUN echo "Running postinstall scripts..." && \
echo "Skipping common-utils build in postinstall as it's already built" && \
node ffmpeg-fix.js 2>&1 | tee -a /tmp/postinstall.log || echo "ffmpeg-fix completed" && \
npm rebuild --verbose 2>&1 | tee -a /tmp/npm-rebuild.log || \
echo "Some rebuilds failed, but continuing..."
# Verify critical packages are installed
RUN node -e "console.log('Node version:', process.version)" && \
node -e "require('react'); console.log('React OK')" && \
node -e "require('remotion'); console.log('Remotion OK')" && \
ls -la node_modules/.bin/ | head -20
# Final production stage
FROM base as final
# Create app directory and set permissions
RUN mkdir -p /app /app/public /app/out /app/frames /app/uploads && chown -R 1000:1000 /app
# Copy installed dependencies from the dependencies stage
COPY --from=dependencies --chown=1000 /app/node_modules ./app/node_modules
COPY --from=dependencies --chown=1000 /app/package*.json ./app/
COPY --from=dependencies --chown=1000 /app/common-utils ./app/common-utils
USER 1000
WORKDIR /app
# Copy application code (node_modules excluded via .dockerignore)
COPY --chown=1000 . ./
# Ensure proper permissions for writable directories
USER root
RUN chmod -R 777 /app/public /app/out /app/uploads /app/frames || true && \
chmod 777 /app/index.html || true && \
mkdir -p /tmp/client_body /tmp/proxy_temp /tmp/fastcgi_temp /tmp/uwsgi_temp /tmp/scgi_temp && \
chmod -R 777 /tmp && \
chmod -R 777 /var && \
chmod -R 777 /app/node_modules/.cache || true
# Copy nginx config and start script
COPY --chown=1000 nginx.conf /etc/nginx/nginx.conf
COPY --chown=1000 start.sh /app/start.sh
RUN chmod +x /app/start.sh
# Ensure nginx runs as root
RUN sed -i 's/^user .*;/user root;/' /etc/nginx/nginx.conf || true
USER 1000
# Ensure remotion browser is properly set up (do this after all dependencies are ready)
RUN echo "Setting up Remotion browser..." && \
npx remotion browser ensure 2>&1 | tee /tmp/remotion-browser.log || \
echo "Browser setup had issues, but continuing..."
# Verify the installation
RUN echo "Verifying installation..." && \
node -e "console.log('Final verification - Node:', process.version)" && \
npm list --depth=0 | head -10 || true
# Set up environment for runtime
ENV DISPLAY=:99
ENV NODE_ENV=production
# Expose required ports
EXPOSE 7860 3000 8083
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8083/ || exit 1
# Start the application
CMD ["sh", "/app/start.sh"]
# Build and run commands:
# docker build -f Dockerfile.build.multistage -t render-farm:latest .
# docker run -p 8083:8083 -it --rm render-farm:latest
# docker run -p 8083:8083 -it --rm --entrypoint /bin/sh render-farm:latest