Ctrl K
ComunidadGuías…

Dockerfile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# syntax=docker/dockerfile:1.19
# check=error=true;skip=SecretsUsedInArgOrEnv

# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
# docker build -t harbor .
# docker run -d -p 80:80 -e RAILS_MASTER_KEY=<value from config/master.key> --name harbor harbor

# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
ARG RUBY_VERSION=4.0.6

FROM docker.io/oven/bun:1.4-slim AS bun

FROM docker.io/library/ruby:$RUBY_VERSION-slim AS ruby-base

# Rails app lives here
WORKDIR /rails

# Keeping Bun on the common parent makes the same pinned binary available to
# dependency installation, asset compilation, and the production SSR runtime.
COPY --from=bun /usr/local/bin/bun /usr/local/bin/bun

# Set production environment
ENV RAILS_ENV="production" \
    BUNDLE_DEPLOYMENT="1" \
    BUNDLE_PATH="/usr/local/bundle" \
    BUNDLE_WITHOUT="development:test"

# Build the runtime base independently from application dependencies so these
# packages are installed in parallel with the builder toolchain and Bundler.
FROM ruby-base AS runtime-base

# Install base packages
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y \
    curl \
    fontconfig \
    libjemalloc2 \
    tar \
    tzdata && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Install only the compiler toolchain needed by native gems.
FROM ruby-base AS build-base

RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y g++ gcc libffi-dev make && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Install Git and the font conversion tool independently so native gem
# compilation does not wait for unrelated build packages.
FROM ruby-base AS frontend-base

RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y git woff2 && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Install JavaScript dependencies independently so BuildKit can run this stage
# in parallel with the Ruby dependency stage.
FROM frontend-base AS javascript-dependencies

COPY package.json bun.lock bunfig.toml ./
COPY patches patches
RUN --mount=type=cache,target=/root/.bun/install/cache \
    bun i --frozen-lockfile --linker=isolated && \
    mkdir -p node_modules/.vite-client node_modules/.vite-ssr node_modules/.vite-temp

RUN cp node_modules/@fontsource-variable/spline-sans/files/spline-sans-latin-wght-normal.woff2 /tmp/spline-sans-latin-wght-normal.woff2 && \
    woff2_decompress /tmp/spline-sans-latin-wght-normal.woff2 && \
    install -Dm644 /tmp/spline-sans-latin-wght-normal.ttf vendor/fonts/spline-sans-latin-wght-normal.ttf

# Sharp ships one libvips binary with its codecs. Ruby Vips loads the same ABI.
FROM javascript-dependencies AS libvips

RUN mkdir /libvips && \
    cp node_modules/@img/sharp-libvips-linux-*/lib/libvips-cpp.so.* /libvips/libvips-cpp.so

# Prepare the runtime concurrently with dependency and asset compilation.
FROM runtime-base AS prepared-runtime

ENV LD_LIBRARY_PATH="/usr/local/lib"

COPY --from=frontend-base /usr/bin/git /usr/bin/git
COPY --from=frontend-base /usr/lib/git-core /usr/lib/git-core
COPY --from=libvips /libvips/libvips-cpp.so /usr/local/lib/libvips-cpp.so
COPY --from=javascript-dependencies /rails/vendor/fonts/spline-sans-latin-wght-normal.ttf \
    /usr/local/share/fonts/spline-sans/spline-sans-latin-wght-normal.ttf

RUN ln -s libvips-cpp.so /usr/local/lib/libvips.so.42 && \
    fc-cache -f /usr/local/share/fonts/spline-sans && \
    groupadd --system --gid 1000 rails && \
    useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
    git config --system http.timeout 30 && \
    git config --system http.lowSpeedLimit 1000 && \
    git config --system http.lowSpeedTime 10

# Install gems independently from JavaScript dependencies.
FROM build-base AS ruby-dependencies

COPY Gemfile Gemfile.lock ./
RUN --mount=type=cache,target=/root/.bundle/cache \
    --mount=type=cache,target=/usr/local/bundle/ruby/4.0.0/cache \
    BUNDLER_VERSION="$(awk 'END { print $1 }' Gemfile.lock)" && \
    (gem list --installed bundler --version "$BUNDLER_VERSION" || \
      gem install bundler --version "$BUNDLER_VERSION" --no-document) && \
    bundle "_${BUNDLER_VERSION}_" install && \
    rm -rf "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git

# Copy application source without persisting build-only dependencies in its
# layers. Rails and Blume consume those dependencies through read-only mounts.
FROM ruby-base AS application-source

# image_processing 2.0 loads Ruby Vips during Rails boot, so the stages that
# boot Rails below (route helpers, asset precompilation) need libvips too.
ENV LD_LIBRARY_PATH="/usr/local/lib"

COPY --from=libvips /libvips/libvips-cpp.so /usr/local/lib/libvips-cpp.so
RUN ln -s libvips-cpp.so /usr/local/lib/libvips.so.42

COPY --from=javascript-dependencies /rails/vendor/fonts /rails/vendor/fonts
COPY --exclude=blume.config.ts --exclude=docs . .

# Build Blume from only its inputs so Rails application changes neither
# invalidate nor delay documentation generation.
FROM ruby-base AS docs-assets

COPY package.json blume.config.ts theme.css ./
COPY config/themes.yml config/themes.yml
COPY public public
COPY docs docs
RUN --mount=type=bind,from=javascript-dependencies,source=/rails/node_modules,target=/rails/node_modules,rw \
    bun run build:docs

# Generate route helpers before the two asset branches start.
FROM application-source AS route-helpers

RUN --network=none \
    --mount=type=bind,from=ruby-dependencies,source=/usr/local/bundle,target=/usr/local/bundle \
    export SECRET_KEY_BASE_DUMMY=1 JS_FROM_ROUTES_FORCE=true && \
    AWS_EC2_METADATA_DISABLED=true \
      S3_BUCKET=dummy S3_ACCESS_KEY_ID=dummy S3_SECRET_ACCESS_KEY=dummy S3_ENDPOINT=http://127.0.0.1 \
      ./bin/rake js_from_routes:generate

# Build Rails assets in one Rails process. Save its Bootsnap cache in the image
# so production does not compile the same Ruby files again at boot.
FROM route-helpers AS rails-assets

RUN --network=none \
    --mount=type=bind,from=ruby-dependencies,source=/usr/local/bundle,target=/usr/local/bundle \
    --mount=type=cache,target=/root/.cache/bootsnap \
    export SECRET_KEY_BASE_DUMMY=1 BOOTSNAP_CACHE_DIR=/root/.cache/bootsnap \
      VITE_RUBY_SKIP_ASSETS_PRECOMPILE_EXTENSION=true && \
    AWS_EC2_METADATA_DISABLED=true \
      S3_BUCKET=dummy S3_ACCESS_KEY_ID=dummy S3_SECRET_ACCESS_KEY=dummy S3_ENDPOINT=http://127.0.0.1 \
      ./bin/rails runner 'Rails.application.eager_load!; Rails.application.load_tasks; Rake::Task["assets:precompile"].invoke' && \
    rm -rf tmp/cache/bootsnap && \
    cp -a "$BOOTSNAP_CACHE_DIR/bootsnap" tmp/cache/bootsnap

# Build Vite from only the files that can affect its output. Tailwind scans
# Rails controllers, helpers, and views in addition to the JavaScript source.
FROM ruby-base AS frontend-assets

COPY app/javascript app/javascript
COPY app/assets/tailwind app/assets/tailwind
COPY app/controllers app/controllers
COPY app/helpers app/helpers
COPY app/views app/views
COPY config/vite.json config/vite.json
COPY package.json ./
COPY svelte.config.js ./
COPY tsconfig.json tsconfig.node.json ./
COPY vite.config.ts ./
COPY --from=route-helpers /rails/app/javascript/api app/javascript/api

RUN --mount=type=bind,from=javascript-dependencies,source=/rails/node_modules,target=/rails/node_modules \
    --mount=type=cache,target=/rails/node_modules/.vite-client \
    --mount=type=cache,target=/rails/node_modules/.vite-ssr \
    --mount=type=tmpfs,target=/rails/node_modules/.vite-temp \
    --mount=type=cache,target=/root/.bun/install/cache \
    (VITE_CACHE_DIR=node_modules/.vite-client bun x --bun vite build & \
      client_pid=$!; \
      VITE_CACHE_DIR=node_modules/.vite-ssr bun x --bun vite build --ssr & \
      ssr_pid=$!; \
      wait "$client_pid" && \
      wait "$ssr_pid")

# Combine generated Rails, Vite, and documentation assets.
FROM rails-assets AS build

COPY --from=frontend-assets /rails/public /rails/public
COPY --from=docs-assets /rails/public /rails/public

# Final stage for app image
FROM prepared-runtime

# Copy built artifacts: gems, application
COPY --from=ruby-dependencies "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build --exclude=db --exclude=log --exclude=spec --exclude=storage --exclude=test --exclude=tmp /rails /rails
COPY --from=build --chown=1000:1000 /rails/db /rails/db
COPY --from=build --chown=1000:1000 /rails/log /rails/log
COPY --from=build --chown=1000:1000 /rails/storage /rails/storage
COPY --from=build --chown=1000:1000 /rails/tmp /rails/tmp

ARG SOURCE_COMMIT=unknown
RUN printf '%s\n' "$SOURCE_COMMIT" > REVISION

USER 1000:1000

# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start either web server or job worker based on WORKER env var
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]