Skip to content

bootsnap precompile and rails assets:precompile commands cause error when building Docker image #54452

Closed as not planned
@rgxcp

Description

@rgxcp

Steps to reproduce

# Create a new Rails app
gem install rails -v 8.0.1
rails new my-app -d postgresql

# Build Docker image using generated Dockerfile file
docker build --platform linux/amd64 --rm --tag my-app:latest .

Expected behavior

The Docker image build process is success.

Actual behavior

The Docker image build process is failed with the following error:

67.57 bundler: failed to load command: bootsnap (/usr/local/bundle/ruby/3.4.0/bin/bootsnap)
67.57 /usr/local/lib/ruby/3.4.0/bundler/definition.rb:676:in 'Bundler::Definition#materialize': Could not find net-smtp-0.5.0 in locally installed gems (Bundler::GemNotFound)
67.57   from /usr/local/lib/ruby/3.4.0/bundler/definition.rb:232:in 'Bundler::Definition#specs'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/definition.rb:299:in 'Bundler::Definition#specs_for'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/runtime.rb:18:in 'Bundler::Runtime#setup'
67.57   from /usr/local/lib/ruby/3.4.0/bundler.rb:167:in 'Bundler.setup'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/setup.rb:32:in 'block in <top (required)>'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/ui/shell.rb:173:in 'Bundler::UI::Shell#with_level'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/ui/shell.rb:119:in 'Bundler::UI::Shell#silence'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/setup.rb:32:in '<top (required)>'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/cli/exec.rb:57:in 'Kernel#require_relative'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/cli/exec.rb:57:in 'Bundler::CLI::Exec#kernel_load'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/cli/exec.rb:23:in 'Bundler::CLI::Exec#run'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/cli.rb:452:in 'Bundler::CLI#exec'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/vendor/thor/lib/thor/command.rb:28:in 'Bundler::Thor::Command#run'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in 'Bundler::Thor::Invocation#invoke_command'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/vendor/thor/lib/thor.rb:538:in 'Bundler::Thor.dispatch'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/cli.rb:35:in 'Bundler::CLI.dispatch'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/vendor/thor/lib/thor/base.rb:584:in 'Bundler::Thor::Base::ClassMethods#start'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/cli.rb:29:in 'Bundler::CLI.start'
67.57   from /usr/local/lib/ruby/gems/3.4.0/gems/bundler-2.6.2/exe/bundle:28:in 'block in <top (required)>'
67.57   from /usr/local/lib/ruby/3.4.0/bundler/friendly_errors.rb:117:in 'Bundler.with_friendly_errors'
67.57   from /usr/local/lib/ruby/gems/3.4.0/gems/bundler-2.6.2/exe/bundle:20:in '<top (required)>'
67.57   from /usr/local/bin/bundle:25:in 'Kernel#load'
67.57   from /usr/local/bin/bundle:25:in '<main>'
------
Dockerfile:38
--------------------
  37 |     COPY Gemfile Gemfile.lock ./
  38 | >>> RUN bundle install && \
  39 | >>>     rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
  40 | >>>     bundle exec bootsnap precompile --gemfile
  41 |
--------------------
ERROR: failed to solve: process "/bin/sh -c bundle install &&     rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git &&     bundle exec bootsnap precompile --gemfile" did not complete successfully: exit code: 1

System configuration

Rails version: 8.0.1

Ruby version: 3.4.1

Notes

After hours of trial and error, I found these 3 lines that caused the error:

bundle exec bootsnap precompile --gemfile
bundle exec bootsnap precompile app/ lib/
SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile

If I remove those 3 lines the build process is success.

My full Dockerfile (basically it just a standard generated Dockerfile from Rails, nothing changed):

# syntax=docker/dockerfile:1
# check=error=true

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

# 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=3.4.1
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base

# Rails app lives here
WORKDIR /rails

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

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

# Throw-away build stage to reduce size of final image
FROM base AS build

# Install packages needed to build gems
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential git libpq-dev pkg-config && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
    rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
    bundle exec bootsnap precompile --gemfile

# Copy application code
COPY . .

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/

# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile




# Final stage for app image
FROM base

# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails

# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
    useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
    chown -R rails:rails db log storage tmp
USER 1000:1000

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

# Start server via Thruster by default, this can be overwritten at runtime
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions