Giter VIP home page Giter VIP logo

dockerfile-rails's Issues

`git` package does not properly resolve

Proposal

Always include git in the official Rails Dockerfile.

Rationale

Even if a Gemfile starts off without a git reference, it's something that is likely to happen during the course of a Rails project. It would be great to not have this break the Dockerfile build.

Bug

Everything below is a bug I ran into when deploying a Rails application with a github reference. I can dive deeper into the problem, but the simpler fix with what I think is a better dev experience is what I propose above.


When I deploy an application with the following Gemfile:

source 'https://rubygems.org'

git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
  "https://github.com/#{repo_name}.git"
end

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 7.0.0'
# Use Puma as the app server
gem 'puma', '~> 6.0'
# Use SCSS Gor stylesheets
gem 'sassc-rails'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.10'
# Use Redis adapter to run Action Cable in production
gem 'redis', '~> 3.0'
# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.13'
# HAML templates yo
gem 'haml-rails'
# Authorization libraries
gem 'omniauth'
gem 'omniauth-google-oauth2'
# Authorization logic
gem 'pundit'
# Form helper
gem 'simple_form', '~> 5.0'
# Communicate with Twilio
gem 'twilio-ruby'
# Handle phone numbers as a propper data type (and normalize)
gem 'phony_rails'
# For claims to create resources in a phone ack
gem 'jwt'
# Validate password and token strengths based on entropy.
gem 'strong_password'
# Display times locally
gem 'local_time'
# Run Postgres in production
gem 'pg', '~> 1.4'
# Application error alerts
gem 'rollbar'
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false
# Generate's PDFs, mostly for labels
gem "prawn", "~> 2.0"
# Print QR codes in a PDF
gem "prawn-qrcode", "~> 0.5.0"
# Hierarchial record organization in ActiveRecord
gem "closure_tree", "~> 7.0"
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
# Parse natrual language date and time strings
gem "chronic", "~> 0.10.2"
# Search Postgres records
gem "pg_search", "~> 2.3"
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 5.3'
# Blanks from forms are converted into nil instead of stored as "" in the database
gem "nilify_blanks", "~> 1.4"
# Does union queries in ActiveRecord.
gem "active_record_union"
# Converts GUIDs in the URLs into shorter ids
gem "anybase", "~> 0.0.15"
# Pull this out when Rails 6.1 is a thing
gem "view_component", "~> 2.0"
# View template for CSV files
gem "csv_builder", "~> 2.1"
# Content management
if sitepress_gem_path = ENV["SITEPRESS_GEM_PATH"]
  gem "sitepress",        path: sitepress_gem_path
  gem "sitepress-cli",    path: sitepress_gem_path
  gem "sitepress-rails",  path: sitepress_gem_path
  gem "sitepress-core",   path: sitepress_gem_path
  gem "sitepress-server", path: sitepress_gem_path
else
  gem "sitepress-rails", github: "sitepress/sitepress", branch: "main"
end

# Markdown gem
gem "redcarpet", "~> 3.5.0"
# Parses SVG vector files and inverts them for darkmode.
gem "color", "~> 1.8"
# Used for reporting from the shell so I can see who signed up within a day/week
gem "groupdate", "~> 5.2"
# Render PDF file as an image to get around really annoying problems
# embedding PDFs in webpages or trying to embed them via PDF.js
gem "mini_magick", "~> 4.0.0"

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'rspec-rails'
  gem 'faker'
  gem 'factory_bot_rails'
end

group :development do
  # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  gem 'spring-commands-rspec'
end

group :test do
  gem 'pundit-matchers', '~> 1.7.0'
  gem 'shoulda-matchers', '~> 4.5.0'
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of web drivers to run system tests with browsers
  gem 'webdrivers'
  gem 'rexml'
end

if featureomatic_path = ENV["FEATUREOMATIC_GEM_PATH"]
  gem "featureomatic", path: featureomatic_path
else
  gem "featureomatic", "~> 0.1.1", github: "rocketshipio/featureomatic"
end

gem "imageomatic", "~> 0.1.1", github: "imageomatic/ruby"

gem "mailto", "~> 0.1.1"

gem "stripe", "~> 5.38"

# Resource-oriented rails controllers
if oxidizer_peth = ENV["OXIDIZER_GEM_PATH"]
  gem "oxidizer", path: oxidizer_peth
else
  gem "oxidizer", github: "rocketshipio/oxidizer", branch: "main"
end

# No-password login flow
gem "nopassword", github: "rocketshipio/nopassword", branch: "main"
gem "matrix", "~> 0.4.2"

gem "ahoy_matey", "~> 4.1"

gem "slim-rails", "~> 3.5"

gem "blazer", "~> 2.6"

gem "turbo-rails", "~> 1.3"

gem "dockerfile-rails", ">= 1.0.0", :group => :development

The git package is not included.

I've tracked down where that's set at https://github.com//rubys/dockerfile-rails/blob/f8564073360444cfd967eeb6c3d7f08c6ac29615/lib/dockerfile-rails/scanner.rb#L30-L42

What I'm not sure about is if the rescue block is catching "too much" since it rescues all errors. Here's what I get when I run that block in irb or bundle exec irb

irb(main):007:0> gemfile_definition.spec_git_paths.empty?
/Users/bradgessler/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.3.16/lib/bundler/source/git/git_proxy.rb:224:in `allowed_with_path': The git source https://github.com/rocketshipio/nopassword.git is not yet checked out. Please run `bundle install` before trying to start your application (Bundler::GitError)
	from /Users/bradgessler/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.3.16/lib/bundler/source/git/git_proxy.rb:190:in `find_local_revision'
	from /Users/bradgessler/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.3.16/lib/bundler/source/git/git_proxy.rb:62:in `revision'
	from /Users/bradgessler/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.3.16/lib/bundler/source/git.rb:234:in `revision'
	from /Users/bradgessler/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.3.16/lib/bundler/source/git.rb:103:in `install_path'
	from /Users/bradgessler/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.3.16/lib/bundler/definition.rb:274:in `block in spec_git_paths'
	from /Users/bradgessler/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.3.16/lib/bundler/definition.rb:274:in `map'
	from /Users/bradgessler/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.3.16/lib/bundler/definition.rb:274:in `spec_git_paths'
	from (irb):7:in `<main>'
	from /Users/bradgessler/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/irb-1.6.2/exe/irb:11:in `<top (required)>'
	from /Users/bradgessler/.rbenv/versions/3.2.0/bin/irb:25:in `load'
	from /Users/bradgessler/.rbenv/versions/3.2.0/bin/irb:25:in `<main>'
irb(main):008:1*       if File.exist? 'Gemfile'
irb(main):009:2*         begin
irb(main):010:2*           gemfile_definition = Bundler::Definition.build('Gemfile', nil, [])
irb(main):011:2*           @gemfile += gemfile_definition.dependencies.map(&:name)
irb(main):012:2*
irb(main):013:3*           unless ENV['RAILS_ENV'] == 'test'
irb(main):014:3*             @git = !gemfile_definition.spec_git_paths.empty?
irb(main):015:2*           end
irb(main):016:2*         rescue => error
irb(main):017:2*           STDERR.puts error.message
irb(main):018:1*         end
irb(main):019:0>       end
irb(main):020:0*
undefined method `+' for nil:NilClass
=> nil

Copy local gems specified with path in Gemfile

We have a couple of generated gems that are in the same repo as our application.

Bundle install fails if they haven't been copied to docker image.

Would it be possible to look through the Gemfile/ Gemfile.lock for all gems specified with with a path and copy them before running bundle install

Order of `COPY` commands doesn't allow for Gemfile's `file` directive

I'm trying to use ruby file: ".ruby-version" on my Gemfile so I just have one file to update Ruby's version but I noticed I can't deploy on Fly with this change, I get the error that .ruby-version does not exist.

I noticed that COPY --link Gemfile Gemfile.lock ./ happens before COPY . . so at the bundle install phase, .ruby-version file is not there yet. There are a couple of ways to fix this, either put COPY . . before running bundle (not great) or simply copy .ruby-version before (or with) copying gemfile/gemfile.lock, but there's a catch: not everyone will have this file (or maybe the file is in the gitignore/dockerignore list)

thinking if this could be fixed somehow. any ideas?

Add more clarity on deb packages being build or runtime dependencies

Consider adding a new option or more information in README about installing deb packages needed for gem compilation and those needed for runtime.

It's about a situation when the app needs a gem for Postgresql, MySQL and MSSQL server to work (as well as GEOS for geospatial extensions). In this case, simply using the -add option does not help, and you have to assign different packages in the section:

FROM base as build

# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential default-libmysqlclient-dev git libpq-dev node-gyp pkg-config python-is-python3 \
    freetds-dev libgeos-dev

than the packages needed here:

FROM base

# Install packages needed for deployment
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y \
    default-libmysqlclient-dev default-mysql-client freetds-bin libgeos-* libvips nodejs postgresql-client && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

Apparently --add only adds packages required to build gems.

I am also curious if this tool is to be used to create Docker images for development or is it intended to be only for building production images? I'm asking because here is hardcoded RAILS_ENV production

Missing RUN statement when using execjs and Yarn

When generating a Dockerfile for a project that uses execjs and Yarn, the "Install yarn" section of the generated Dockerfile is missing a RUN instruction.

Steps to reproduce

The steps below were used to recreate the issue and the result is available here: https://github.com/jeff-french/dockerfile-rails-issue-reproduction

# Check environment
ruby --version
# ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]
rails --version
# Rails 7.1.3
node --version
# v20.11.0
yarn --version
# 4.0.2

# New rails project
rails new blog
cd blog

# Setup Yarn
corepack enable
yarn init -2
yarn set version stable
yarn install

# Add execjs
bundle add execjs

# dockerfile-rails
bundle add dockerfile-rails --optimistic --group development
rails g dockerfile --force

Actual output

This will produce an invalid section starting around line 40 of the generated Dockerfile

# Install yarn
ARG YARN_VERSION=4.0.2
    corepack enable && \
    corepack prepare yarn@$YARN_VERSION --activate

Expected output

# Install yarn
ARG YARN_VERSION=4.0.2
RUN corepack enable && \
    corepack prepare yarn@$YARN_VERSION --activate

Investigation

The issue appears to be caused when the install_node template is called the second time to setup Yarn:

<% elsif using_node? and (!using_execjs? || File.exist?('yarn.lock')) -%>
<%= render partial: 'install_node', locals: {node_version: using_execjs? ? nil : node_version, yarn_version: File.exist?('yarn.lock') ? yarn_version : nil} %>
<% end -%>

In this call node_version gets set to nil due to the usage of execjs and yarn_version get set to 4.0.2.

When the install_node template gets rendered from this call, the following section gets skipped entirely since node_version=nil:

<% if node_version && node_version != 'lts' -%>
<% if options.alpine? -%>
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://unofficial-builds.nodejs.org/download/release/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64-musl.tar.gz | tar xz -C /tmp/ && \
mkdir /usr/local/node && \
cp -rp /tmp/node-v${NODE_VERSION}-linux-x64-musl/* /usr/local/node/ && \
<% else -%>
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
/tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
<% end -%>
<% end -%>

and then this section attempts to append to the RUN command from the previously skipped section:

<% if yarn_version -%>
<% if yarn_version < '2' -%>
<% if node_version -%> <% else %>RUN<% end %> npm install -g yarn@$YARN_VERSION<% if node_version -%> && \<% end %>
<% else -%>
<% if node_version && (node_version.split('.').map(&:to_i) <=> [16,10,0]) < 0 -%>
npm i -g corepack && \
<% else -%>
corepack enable && \
<% end -%>
corepack prepare yarn@$YARN_VERSION --activate<% if node_version -%> && \<% end %>
<% end -%>
<% end -%>

Solution

I was able to get the expected output by changing the following section:

<% else -%>
corepack enable && \
<% end -%>

to

<% else -%>
<% if node_version -%>   <% else %>RUN<% end %> corepack enable && \
<% end -%>

Caveats

This fix worked in this particular situation but I'm not sure if it is a drop in solution when execjs is not being used and the node_install ends up rendering the full template.

vendor directory is empty in CI

Hello, I am trying to use this dockerfile in a rails 6.1 project to run tests in Gitlab CI.

The build step runs fine with kaniko, but the test step fails with bundler: command not found: rails. When I check what the vendor directory contains, it looks OK in the build step, but empty in the test step.

This is my dockerfile.yml

# generated by dockerfile-rails

---
options:
  cache: true
  ci: true
  jemalloc: true
  mysql: true
  redis: true
  root: true
  packages:
    build:
    - git
    - ruby-dev
    - gcc
    - make
    - g++
    - libffi-dev
    - libmariadb-dev-compat

This is the Dockerfile

# syntax = docker/dockerfile:1

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.1.4
FROM ruby:$RUBY_VERSION-slim as base

# Rails app lives here
WORKDIR /rails

# Set production environment
ENV RAILS_ENV="production" \
    BUNDLE_WITHOUT="development" \
    BUNDLE_DEPLOYMENT="1"

# Update gems and bundler
RUN gem update --system --no-document && \
    gem install -N bundler


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

# Install packages needed to build gems and node modules
RUN --mount=type=cache,id=dev-apt-cache,sharing=locked,target=/var/cache/apt \
    --mount=type=cache,id=dev-apt-lib,sharing=locked,target=/var/lib/apt \
    apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential curl default-libmysqlclient-dev g++ gcc git libffi-dev libmariadb-dev-compat make node-gyp pkg-config python-is-python3 ruby-dev

# Install Node.js
ARG NODE_VERSION=17.6.0
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
    /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
    rm -rf /tmp/node-build-master

# Install application gems
COPY --link Gemfile Gemfile.lock ./
RUN --mount=type=cache,id=bld-gem-cache,sharing=locked,target=/srv/vendor \
    bundle config set app_config .bundle && \
    bundle config set path /srv/vendor && \
    bundle install && \
    bundle exec bootsnap precompile --gemfile && \
    bundle clean && \
    mkdir -p vendor && \
    bundle config set path vendor && \
    cp -ar /srv/vendor .

# Install node modules
COPY --link package.json package-lock.json ./
RUN --mount=type=cache,id=bld-npm-cache,target=/root/.npm \
    npm install

# Copy application code
COPY --link . .

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


# Final stage for app image
FROM base

# Install packages needed for deployment
RUN --mount=type=cache,id=dev-apt-cache,sharing=locked,target=/var/cache/apt \
    --mount=type=cache,id=dev-apt-lib,sharing=locked,target=/var/lib/apt \
    apt-get update -qq && \
    apt-get install --no-install-recommends -y curl default-mysql-client imagemagick libjemalloc2

# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails

# Deployment options
ENV LD_PRELOAD="libjemalloc.so.2" \
    MALLOC_CONF="dirty_decay_ms:1000,narenas:2,background_thread:true" \
    RAILS_LOG_TO_STDOUT="1" \
    RAILS_SERVE_STATIC_FILES="true"

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

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]

This is the kaniko command in the build step:

  script:
    - mkdir -p /kaniko/.docker
    - export container=docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor --force --cache=false --context $CI_PROJECT_DIR --dockerfile Dockerfile --build-arg BUILDKIT_INLINE_CACHE=1 --build-arg RAILS_MASTER_KEY=$MASTER_KEY --destination $CI_REGISTRY_IMAGE:$DESTINATION_TAG

Don't default to sqlite3, or provide option to disable?

I'm using SQL Server in my app. When I build a Dockerfile without specifying a database, it assumes I wish to use Sqlite3.

My Dockerfile is generated with the following additional lines:

RUN mkdir /data
# ...
ENV DATABASE_URL="sqlite3:///data/production.sqlite3" 
# ...
VOLUME /data

A few notes:

  • The scanner.rb correctly does not set @sqlite3 = true
  • However dockerfile_generator.rb sets a default to sqlite3
  • The Readme seems to imply that if this tool cannot infer the database correctly, you will need to specify it, such as specifying --sqlite3 from the Add a Database section.

I can appreciate that adding sqlite3 as a default is probably convenient or likely, however, if it is being used, it will be in the gemfile, or the database config, and as such, will be detected and should not be assumed unless specified. Because it is, I am manually editing the Dockerfile, even though it's otherwise entirely autogenerated from my config/dockerfile.yml config file.

Would you consider removing the default value for #deploy_database, and require checking as you do for pg and mysql?

Will there be multiple db migrations running if multiple rails servers started?

So the dockerfile has this line

ENTRYPOINT ["/rails/bin/docker-entrypoint"]

It will run migration when rails server being started. My question is, if auto-scaling triggers multiple web instances, will that run multiple db migrations at the same time? I think it would be nice if the migration could only run just once, after deployment, not everytime when a web server starts.

dockerfile_generator.rb:505:in `>=': comparison of Gem::Version with String failed (ArgumentError)

https://github.com/fly-apps/dockerfile-rails/blob/31c1d3de61e53cbd5f1ad4bc773b40cfcaf0d8a8/lib/generators/dockerfile_generator.rb#L504C1-L504C75

Support to compare versions using String is a recent addition, causing this line to raise exception RubyGems < 3.4.19

โ–ถ ruby --version
ruby 3.0.4p208 (2022-04-12 revision 3fa771dded) [x86_64-darwin20]

โ–ถ gem --version
3.2.33

โ–ถ bin/rails generate dockerfile --parallel --cache --ci
/Users/ttilberg/.asdf/installs/ruby/3.0.4/lib/ruby/gems/3.0.0/gems/dockerfile-rails-1.5.7/lib/generators/dockerfile_generator.rb:504:in `>=': comparison of Gem::Version with String failed (ArgumentError)
	from /Users/ttilberg/.asdf/installs/ruby/3.0.4/lib/ruby/gems/3.0.0/gems/dockerfile-rails-1.5.7/lib/generators/dockerfile_generator.rb:504:in `base_gems'

Error installing psych (5.1.2) when creating DockerFile with Rails 7.1.2

๐Ÿ‘‹ Thanks for your contribution.

Issue:
I have a new Rails 7.1.2 which after the creation of the app I deleted the default DockerFile that comes with Rails 7.1.x
and run the command.

bin/rails generate dockerfile --fullstaq --jemalloc

Then when I tried to check that the image builds with

docker build .

I got this error.

23.69 An error occurred while installing psych (5.1.2), and Bundler cannot continue.
23.69 
23.69 In Gemfile:
23.69   importmap-rails was resolved to 1.2.3, which depends on
23.69     railties was resolved to 7.1.2, which depends on
23.69       irb was resolved to 1.10.1, which depends on
23.69         rdoc was resolved to 6.6.2, which depends on
23.69           psych

....
....
....

Dockerfile:32
--------------------
 31 |     COPY --link Gemfile Gemfile.lock ./
 32 | >>> RUN bundle install && \
 33 | >>>     bundle exec bootsnap precompile --gemfile && \
 34 | >>>     rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git
 35 |     
--------------------
ERROR: failed to solve: process "/bin/bash -o pipefail -c bundle install &&     bundle exec bootsnap precompile --gemfile &&     rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git" did not complete successfully: exit code: 5

Doing some extra research it turns out that Phych 5.x.x requires libyaml on MacOS and libyaml-dev on ubuntu.
ruby/psych#602

Resolution:

Adding libyaml-dev in the DockerFile builds the image successfully.

Thanks

The esbuild-demo is failing: assets are not present in the asset pipeline.

I think the Dockerfile is missing the rails assets:precompile and because of that the assets are not included in the asset pipeline.

โฏ docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) esbuild-welcome
W, [2023-01-22T00:16:02.288717 #7]  WARN -- : You are running SQLite in production, this is generally not recommended. You can disable this warning by setting "config.active_record.sqlite3_production_warning=false".
=> Booting Puma
=> Rails 7.0.4.1 application starting in production 
=> Run `bin/rails server --help` for more startup options
W, [2023-01-22T00:16:02.729948 #1]  WARN -- : You are running SQLite in production, this is generally not recommended. You can disable this warning by setting "config.active_record.sqlite3_production_warning=false".
Puma starting in single mode...
* Puma version: 5.6.5 (ruby 3.1.3-p185) ("Birdie's Version")
*  Min threads: 5
*  Max threads: 5
*  Environment: production
*          PID: 1
* Listening on http://0.0.0.0:3000
Use Ctrl-C to stop
I, [2023-01-22T00:16:09.640125 #1]  INFO -- : [51ad9596-d807-424d-a198-1f70350edc90] Started GET "/" for 172.17.0.1 at 2023-01-22 00:16:09 +0000
I, [2023-01-22T00:16:09.641340 #1]  INFO -- : [51ad9596-d807-424d-a198-1f70350edc90] Processing by TimeController#index as HTML
I, [2023-01-22T00:16:09.643353 #1]  INFO -- : [51ad9596-d807-424d-a198-1f70350edc90]   Rendered time/index.html.erb within layouts/application (Duration: 0.3ms | Allocations: 288)
I, [2023-01-22T00:16:09.645141 #1]  INFO -- : [51ad9596-d807-424d-a198-1f70350edc90]   Rendered layout layouts/application.html.erb (Duration: 2.1ms | Allocations: 1272)
I, [2023-01-22T00:16:09.645281 #1]  INFO -- : [51ad9596-d807-424d-a198-1f70350edc90] Completed 500 Internal Server Error in 4ms (Allocations: 2487)
F, [2023-01-22T00:16:09.645694 #1] FATAL -- : [51ad9596-d807-424d-a198-1f70350edc90]   
[51ad9596-d807-424d-a198-1f70350edc90] ActionView::Template::Error (The asset "application.css" is not present in the asset pipeline.
):
[51ad9596-d807-424d-a198-1f70350edc90]      6:     <%= csrf_meta_tags %>
[51ad9596-d807-424d-a198-1f70350edc90]      7:     <%= csp_meta_tag %>
[51ad9596-d807-424d-a198-1f70350edc90]      8: 
[51ad9596-d807-424d-a198-1f70350edc90]      9:     <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
[51ad9596-d807-424d-a198-1f70350edc90]     10:     <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
[51ad9596-d807-424d-a198-1f70350edc90]     11:   </head>
[51ad9596-d807-424d-a198-1f70350edc90]     12: 
[51ad9596-d807-424d-a198-1f70350edc90]   
[51ad9596-d807-424d-a198-1f70350edc90] app/views/layouts/application.html.erb:9

Gems installed with git break the scanner

Hey Sam!

Thanks for all the work you've put into this gem. I'm currently running in an error from the scanner.rb when trying to determine if git is needed. My gemfile has multiple gems requiring git. This is the stacktrace when running bin/rails generate dockerfile

/Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bundler-2.3.25/lib/bundler/source/git/git_proxy.rb:224:in `allowed_with_path': The git source https://github.com/shrinerb/shrine.git is not yet checked out. Please run `bundle install` before trying to start your application (Bundler::GitError)
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bundler-2.3.25/lib/bundler/source/git/git_proxy.rb:190:in `find_local_revision'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bundler-2.3.25/lib/bundler/source/git/git_proxy.rb:62:in `revision'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bundler-2.3.25/lib/bundler/source/git.rb:234:in `revision'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bundler-2.3.25/lib/bundler/source/git.rb:103:in `install_path'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bundler-2.3.25/lib/bundler/definition.rb:284:in `block in spec_git_paths'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bundler-2.3.25/lib/bundler/definition.rb:284:in `map'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bundler-2.3.25/lib/bundler/definition.rb:284:in `spec_git_paths'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/dockerfile-rails-0.4.3/lib/dockerfile-rails/scanner.rb:31:in `scan_rails_app'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/dockerfile-rails-0.4.3/lib/generators/dockerfile_generator.rb:48:in `generate_app'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/invocation.rb:134:in `block in invoke_all'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/invocation.rb:134:in `each'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/invocation.rb:134:in `map'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/invocation.rb:134:in `invoke_all'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/group.rb:232:in `dispatch'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/base.rb:485:in `start'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/railties/lib/rails/generators.rb:275:in `invoke'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/railties/lib/rails/commands/generate/generate_command.rb:26:in `perform'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/railties/lib/rails/command/base.rb:69:in `perform'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/railties/lib/rails/command.rb:48:in `invoke'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/railties/lib/rails/commands.rb:18:in `<main>'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bootsnap-1.13.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/bootsnap-1.13.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/kernel.rb:38:in `require'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/gems/skylight-5.3.4/lib/skylight/probes.rb:166:in `require'
	from /Users/louim/work/didacte/bin/rails:5:in `<main>'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/activesupport/lib/active_support/fork_tracker.rb:10:in `block in fork'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/activesupport/lib/active_support/fork_tracker.rb:10:in `block in fork'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/activesupport/lib/active_support/fork_tracker.rb:8:in `fork'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/activesupport/lib/active_support/fork_tracker.rb:8:in `fork'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/activesupport/lib/active_support/fork_tracker.rb:27:in `fork'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/activesupport/lib/active_support/fork_tracker.rb:8:in `fork'
	from /Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/gems/3.1.0/bundler/gems/rails-ca3e163b7cf8/activesupport/lib/active_support/fork_tracker.rb:27:in `fork'
	from <internal:/Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
	from <internal:/Users/louim/.asdf/installs/ruby/3.1.3/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
	from -e:1:in `<main>'

But the source is checked out and I'm able to start the application without any problem. I'm using the latest version (ATM) of the gem: 0.43. The problem is not specific to that gem, if commented from the file, it fails on the next one using git.

Happy to help debugging if you need more details!

Install Bun when it is being used instead of Node

The latest jsbundling-rails release includes the ability to use bun as well. It would be nice if when the Dockerfile is being generated, it could also detect bun as the js runtime (probably via the presence of bun.lockb or bun.config.js files and use that instead of Node

`docker-compose.yml` for `postgresql` specifies a local volume that ends up being owned by `root` on the host

Disclaimer: I'm not a docker superuser, especially when it comes to managing permissions and users between the host and containers, so it's very possible I'm doing something wrong.

Doing a standard generation with --compose --postgresql seems to generate a docker-compose.yml that specifies a volume mapping of ./tmp/db:/var/lib/postgresql/data; the resulting tmp/db directory is owned by root on the host system which is problematic - this caught me out specifically because when I attempted to do docker build . it would fail since it wasn't allowed to read that file.

I suspect this is probably not a direct bug in the gem itself, but it's the sort of thing I feel this gem should be trying to help with.

(I assume this probably happened with all variations that configure volumes, but have only used postgresql myself)

[Suggestion] Prominently warn or error if on arm with no platform specified

We just encountered a deploy issue because we were generating the docker file on an M1 Mac and deploying to x86 without explicitly setting the platform.

Given the intention of this effort is to operate on the principle of least surprise, that most deploy environments are still x86, and M(1|2) Macs are going to be more common, it would be helpful to provide a notice that you may be generating unintentional results without specifying the --platform option.

Erroring and asking to declare the --platform option might be the cleanest option, but a bit heavy handed. A very obvious warning might be better. The warning/error could be isolated to if Gem::Platform.local.cpu is used as a fallback.

`yarn: not found` when using `jsbundling-rails` with `--parallel` option

 > [build 7/7] RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile:
#21 3.323 sh: 1: yarn: not found
#21 3.323 rails aborted!
#21 3.324 jsbundling-rails: Command build failed, ensure yarn is installed and `yarn build` runs without errors
#21 3.324 /rails/vendor/ruby/3.2.0/gems/jsbundling-rails-1.1.1/lib/tasks/jsbundling/build.rake:5:in `block (2 levels) in <main>'
Dockerfile

# syntax = docker/dockerfile:1

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.1
FROM quay.io/evl.ms/fullstaq-ruby:${RUBY_VERSION}-jemalloc-slim as base

LABEL fly_launch_runtime="rails"

# Rails app lives here
WORKDIR /rails

# Set production environment
ENV RAILS_ENV="production" \
    BUNDLE_WITHOUT="development:test" \
    BUNDLE_DEPLOYMENT="1"

# Update gems and bundler
RUN gem update --system --no-document && \
    gem install -N bundler


# Throw-away build stages to reduce size of final image
FROM base as prebuild

# Install packages needed to build gems and node modules
RUN --mount=type=cache,id=dev-apt-cache,sharing=locked,target=/var/cache/apt \
    --mount=type=cache,id=dev-apt-lib,sharing=locked,target=/var/lib/apt \
    apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential curl git node-gyp pkg-config python-is-python3


FROM prebuild as node

# Install JavaScript dependencies
ARG NODE_VERSION=16.15.1
ARG YARN_VERSION=1.22.18
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
    /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
    npm install -g yarn@$YARN_VERSION && \
    rm -rf /tmp/node-build-master

# Install node modules
COPY --link package.json yarn.lock ./
RUN --mount=type=cache,id=bld-yarn-cache,target=/root/.yarn \
    YARN_CACHE_FOLDER=/root/.yarn yarn install --frozen-lockfile


FROM prebuild as build

# Install application gems
COPY --link Gemfile Gemfile.lock ./
RUN --mount=type=cache,id=bld-gem-cache,sharing=locked,target=/srv/vendor \
    bundle config set app_config .bundle && \
    bundle config set path /srv/vendor && \
    bundle install && \
    bundle exec bootsnap precompile --gemfile && \
    bundle clean && \
    mkdir -p vendor && \
    bundle config set path vendor && \
    cp -ar /srv/vendor .

# Copy node modules
COPY --from=node /rails/node_modules /rails/node_modules

# Copy application code
COPY --link . .

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

# Adjust binfiles to set current working directory
RUN grep -l '#!/usr/bin/env ruby' /rails/bin/* | xargs sed -i '/^#!/aDir.chdir File.expand_path("..", __dir__)'

# 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

# Install packages needed for deployment
RUN --mount=type=cache,id=dev-apt-cache,sharing=locked,target=/var/cache/apt \
    --mount=type=cache,id=dev-apt-lib,sharing=locked,target=/var/lib/apt \
    apt-get update -qq && \
    apt-get install --no-install-recommends -y iputils-ping libsqlite3-0 net-tools procps traceroute

# Run and own the application files as a non-root user for security
RUN useradd rails --home /rails --shell /bin/bash

# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build --chown=rails:rails /rails /rails

# Deployment options
ENV RUBY_YJIT_ENABLE="1"

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

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]

Spent some time to debug it, but maybe put some warning/confirmation when jsbundling-rails is present and user is using --parallel option or add node/yarn into prebuild stage?

`packages` directive on `dockerfile.yaml` doesn't install all packages

I have a config file like this:

# generated by dockerfile-rails

---
options:
  bin-cd: true
  cache: true
  fullstaq: true
  jemalloc: true
  parallel: true
  postgresql: true
  redis: true
  root: true
  yjit: true
  packages:
    base:
    - git
    - libyaml-dev
  envs:
    base:
      BUNDLE_WITHOUT: development:test:linting:profiler
      GIT_REV: "${GIT_REV}"
      BUILD_DATE: "${BUILD_DATE}"
      RAILS_LOG_TO_STDOUT: 'true'
  args:
    base:
      GIT_REV: "${GIT_REV}"
      BUILD_DATE: "${BUILD_DATE}"

when I try to generate the Dockerfile, libyaml-dev is simply ignored, no matter what I try and if I manually add it to the Dockerfile, it gets wiped if I try to regenerate the Dockerfile.

I'm not sure if it is related or not but I'm using Rails from the main branch and when I run the generator, I see this before anything else:

The git source https://github.com/rails/rails.git is not yet checked out. Please run `bundle install` before trying to start your application
   identical  Dockerfile
   identical  .dockerignore
   identical  .node-version
   identical  bin/docker-entrypoint
   identical  config/dockerfile.yml

even though the git source is definitely checked out

Getting an error from "lib/generators/templates/_install_node.erb"

(erb):23:in `get_binding': undefined method `split' for nil:NilClass (NoMethodError)
	from /Users/shin/.rbenv/versions/3.1.3/lib/ruby/3.1.0/erb.rb:905:in `eval'
	from /Users/shin/.rbenv/versions/3.1.3/lib/ruby/3.1.0/erb.rb:905:in `result'
	from /Users/shin/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/dockerfile-rails-1.0.7/lib/generators/dockerfile_generator.rb:142:in `render'
	from /Users/shin/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/dockerfile-rails-1.0.7/lib/generators/templates/Dockerfile.erb:57:in `template'

I was trying to deploy my app to Fly.io and saw this error. How should I solve this error?

`--max-idle` option generates corrupted Dockerfile

How to reproduce:

  1. Run bin/rails generate dockerfile --cache --parallel --yjit --max-idle=3600
  2. Under the configure nginx and passenger section of the generated Dockerfile, note how EOF appears twice in a row instead of above, rending the Dockerfile corrupted.
COPY <<-'EOF' /etc/nginx/sites-enabled/default
server {
    listen 3000;
    root /rails/public;
    passenger_enabled on;
    passenger_ctl hook_detached_process /etc/nginx/hook_detached_process;
    passenger_min_instances 0;
    passenger_pool_idle_time ;
}
                                                              # <<<<<<<<<<<<< SHOULD BE HERE
COPY <<-'EOF' /etc/nginx/sites-enabled/hook_detached_process
#!/usr/bin/env ruby
status = `passenger-status`
processes = status[/^Processes\s*:\s*(\d*)/, 1].to_i
system 'nginx -s stop' if processes == 0
EOF                                                           # <<<<<<<<<<<<< THIS
EOF

Support secrets for a private gemserver

I host some gems in a private gemserver.

As it seems, dockerfile-rails does not support to set secrets.

This is how I do it in my current Dockerfile:

RUN --mount=type=secret,id=gemserver_credentials,dst=/kaniko/gemserver_credentials \
  --mount=type=cache,id=gems,sharing=locked,target=/app/vendor/cache \
  BUNDLE_GEMS__MYSERVER__COM="$(cat /kaniko/gemserver_credentials)" \
  && mkdir -p /usr/local/bundle \
  && export BUNDLE_GEMS__MYSERVER__COM \
  && bundle config set cache_all true \
  && bundle install \
  && find /usr/local/bundle/ -name ".git" -exec rm -rv {} + \
  && find /usr/local/bundle/ -name "*.c" -delete \
  && find /usr/local/bundle/ -name "*.o" -delete \
  && bundle cache \
  && bundle config unset cache_all \
  && rm -rf /usr/local/bundle/ruby/*/cache

Notable is

  • I use env variables, as to pass the credentials to bundler
  • --mount=type=secret,id=gemserver_credentials,dst=/kaniko/gemserver_credentials I mount the secret at /kaniko to be able to support kaniko next to docker build
  • BUNDLE_GEMS__MYSERVER__COM="$(cat /kaniko/gemserver_credentials)" reads the secret
  • export BUNDLE_GEMS__MYSERVER__COM exposes the secret to bundler

I also have a special Docker Compose file, which I load in addition to the normal docker-compose.yml file

version: '3.8'

services:
  web:
    build:
      secrets:
        - gemserver_credentials
    secrets:
      - gemserver_credentials

secrets:
  gemserver_credentials:
    file: ./BUNDLE_GEMS__MYSERVER__COM.txt

Add curl

I understand this isn't meant for mrsk, but it'll be used by many people for that. And mrsk now requires curl to be installed.

basecamp/kamal#276

Maybe add it by default (it's a small package) or via an option?

Change default ports when Thruster is present

Over the weekend, I realized that the exposed port dockerfile-rails generated when Thruster is present is insufficient to make Thurster work transparently. I summed up my findings here but long story short:

  • Thruster's default port is 80
  • Thruster's default Puma port is 3000
  • dockerfile-rails exposes 3000
  • Services like Traefik, which checks for EXPOSE directives to route traffic to the correct port, will bypass Thruster completely in these cases

I think the easiest solution is to keep exposing 3000 for the sake of backward compatibility (and everyone expects Rails to expose 3000 anyway) but bind Thruster to 3000 and Puma to e.g. 3001, something like this:

if thurster?
 ARG TARGET_PORT=3001
 ARG HTTP_PORT=3000
 
 EXPOSE ${HTTP_PORT}
end

I can take a stab at a PR for it unless you have a better idea

Getting error `/usr/bin/env: 'ruby\r': no such file or directory` in Windows

I'm building a project using a template available in this repo

Now, someone tried running the project in Windows using docker desktop and they keep getting this error:

#17 110.5 Installing sprockets-rails 3.4.2 #17 110.6 Installing actionmailer 7.0.4.3 #17 110.7 Installing activestorage 7.0.4.3 #17 110.7 Installing railties 7.0.4.3 #17 111.1 Fetching actionmailbox 7.0.4.3 #17 111.1 Fetching actiontext 7.0.4.3 #17 111.3 Installing actionmailbox 7.0.4.3 #17 111.3 Installing actiontext 7.0.4.3 #17 112.1 Fetching cssbundling-rails 1.1.2 #17 112.1 Fetching jsbundling-rails 1.1.1 #17 112.1 Fetching turbo-rails 1.4.0
#17 112.1 Fetching stimulus-rails 1.2.1 #17 112.3 Installing cssbundling-rails 1.1.2 #17 112.3 Installing jsbundling-rails 1.1.1 #17 112.4 Installing stimulus-rails 1.2.1
#17 112.5 Installing turbo-rails 1.4.0
#17 114.7 Fetching actioncable 7.0.4.3
#17 114.7 Fetching puma 5.6.5
#17 114.9 Installing actioncable 7.0.4.3
#17 115.0 Installing puma 5.6.5 with native extensions
#17 115.1 Fetching rails 7.0.4.3
#17 115.3 Installing rails 7.0.4.3
#17 116.3 Fetching bootsnap 1.16.0
#17 116.4 Installing bootsnap 1.16.0 with native extensions
#17 127.0 Bundle complete! 18 Gemfile dependencies, 57 gems now installed.
#17 127.0 Gems in the groups 'development' and 'test' were not installed.
#17 127.0 Bundled gems are installed into `./vendor/bundle`
#17 DONE 130.2s
#18 [build 5/9] COPY --link package.json yarn.lock ./
# 18 DONE 0.1s
#19 [build 6/9] RUN yarn install --frozen-lockfile
#19 1.546 yarn install v1.22.19
#19 1.657 [1/4] Resolving packages...
#19 1.809 [2/4] Fetching packages...
#19 27.33 [3/4] Linking dependencies...
# 19 29.95 [4/4] Building fresh packages...
# 19 30.50 Done in 28.96s.
#19 DONE 30.7s
#20 [build 7/9] COPY --link . .
#20 DONE 0.2s
#21 [build 8/9] RUN bundle exec bootsnap precompile app/lib/
# 21 DONE 1.7s
#22 [build 9/9] RUN SECRET_KEY_BASE=DUMMY ./bin/rails assets: precompile
#22 0.692 /usr/bin/env: 'ruby\r': No such file or directory
#22 ERROR: executor failed running [/bin/sh -c SECRET_KEY_BASE=DUMMY ./bin/rails assets: precompile]: exit code: 127
> [build 9/9] RUN SECRET_KEY_BASE=DUMMY ./bin/rails assets: precompile:
#22 0.692 /usr/bin/env: 'ruby\r': No such file or directory
failed to solve: executor failed running [/bin/sh -c SECRET_KEY_BASE=DUMMY ./bin/rails assets: precompile]: exit code: 127 $

(sorry that I can't offer a more complete backtrace, it's what the person receiving the error sent me)

Here's the Dockerfile:

# syntax = docker/dockerfile:1

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.0
FROM ruby:$RUBY_VERSION-slim as base

# Rails app lives here
WORKDIR /rails

# Set production environment
ENV RAILS_ENV="production" \
    BUNDLE_WITHOUT="development:test" \
    BUNDLE_DEPLOYMENT="1"

# Update gems and bundler
RUN gem update --system --no-document && \
    gem install -N bundler


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

# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential curl libpq-dev node-gyp pkg-config python-is-python3

# Install JavaScript dependencies
ARG NODE_VERSION=14.20.1
ARG YARN_VERSION=1.22.19
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
    /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
    npm install -g yarn@$YARN_VERSION && \
    rm -rf /tmp/node-build-master

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

# Install node modules
COPY --link package.json yarn.lock ./
RUN yarn install --frozen-lockfile

# Copy application code
COPY --link . .

# 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 ./bin/rails assets:precompile


# Final stage for app image
FROM base

# Install packages needed for deployment
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y postgresql-client && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Run and own the application files as a non-root user for security
ARG UID=1000 \
    GID=1000
RUN groupadd -f -g $GID rails && \
    useradd -u $UID -g $GID rails --home /rails --shell /bin/bash
USER rails:rails

# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build --chown=rails:rails /rails /rails

# Deployment options
ENV RAILS_LOG_TO_STDOUT="1" \
    RAILS_SERVE_STATIC_FILES="true"

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

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]

the docker-compose.yml

version: "3.8"
services:
  web:
    build:
      context: .
      args:
        UID: ${UID:-1000}
        GID: ${GID:-${UID:-1000}}
    ports:
      - "3000:3000"
    environment:
      - RAILS_MASTER_KEY=$RAILS_MASTER_KEY
      - DATABASE_URL=postgres://root:password@postgres-db/
    depends_on:
      postgres-db:
        condition: service_healthy

  postgres-db:
    image: postgres
    environment:
      POSTGRES_USER: root
      POSTGRES_PASSWORD: password
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: pg_isready
      interval: 2s
      timeout: 5s
      retries: 30

(we're using docker compose to build and run the images)

The problem is that I don't really have any windows environment to test it. It runs perfectly in different Linux environments, and I've read that the problem is directly related to windows line endings. The other problem, not a minor one, is that the user trying to run the project is not really technical, so I vastly prefer to understand how to make it work out-of-the-box instead of offering some solution that the affected person has to run on they end.

Node being installed even if Bun is being used

hey ๐Ÿ‘‹๐Ÿป

I see this issue where node is installed in the image and .node-version is generated even if Bun is being used. This can cause problems, as I found before.

I think that using_node? method just checks for package.json existence which is not 100% correct since Bun also uses this. I believe that using_node? should also check I'm not using_bun?

Expose BUNDLE_WITHOUT as ARG to enable building test and production images

I think the old fly.io images also allowed this.

This allows me to build the image with BUNDLE_WITHOUT=development
This would be the image to use in the CI pipeline for testing.
After all tests were successful, one would build the production image with BUNDLE_WITHOUT=development:test.

ARG BUNDLE_WITHOUT=development:test
ENV BUNDLE_WITHOUT ${BUNDLE_WITHOUT}

Fly: `--swap` without `--root` lead to permission problems with fly volumes

I followed Sqlite3 on fly volumes tutorial and proactively enabled swap for demo rails app.

It turned out that, since the container is launched as root user when swap is on, fly mounts volumes for root too:
Mounting /dev/vdb at /mnt/volume w/ uid: 0, gid: 0 and chmod 0755

then entry-point script substitutes user for rails server command with rails user:

https://github.com/rubys/dockerfile-rails/blob/69f7631407735aa558bf99be46e0c0c988435479/lib/generators/templates/docker-entrypoint.erb#L18

rendering mounted volumes un-accessible for rails user.

Unable to load Jemalloc in compose

Hey! I bumped the gem to the latest version and I started seeing:

ERROR: ld.so: object '/usr/lib/x86_64-linux-gnu/libjemalloc.so.2' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.

in my docker compose logs. A wild guess is that it's related to the newly added security lockdown features, but I thought i'd ask before digging in.

I love this project... is it considered ready for primetime?

If so, are you able to add a a Changelog file or Release Notes for the tags, in order to show the purpose behind the updates. I've tried to follow the commits but it's hard to get a high level view of the purpose for the updates.

Much appreciated for the time spent on this. Impressive project. Thanks!

Change location of IRB history file

If you connect to a docker container and run rails console, IRB will attempt to record a history file in /rails/.irb_history, but this location is not writeable.

Perhaps configuring IRB to record this to /rails/log/irb_history.log would be preferable. Users can already do this manually by including a .irbrc file in the root of their project, so it may be helpful to create a default one if that file does not exist.

Use `bun` official images

Hey ๐Ÿ‘‹๐Ÿป
I've been using Bun for quite some time now, and it seems stable for use with Rails.
I was checking the Docker ecosystem for Bun and turns out that they have official images now. I toyed around a little bit and manage to use the official image instead of manually install Bun like this:

FROM oven/bun:1 as bun

# Install node modules
COPY --link package.json bun.lockb ./
RUN --mount=type=cache,id=bld-bun-cache,target=/root/.bun \
    bun install --frozen-lockfile


FROM prebuild as build

# Install application gems
COPY --link Gemfile Gemfile.lock .ruby-version ./
RUN --mount=type=cache,id=bld-gem-cache,sharing=locked,target=/srv/vendor \
    bundle config set app_config .bundle && \
    bundle config set path /srv/vendor && \
    bundle install && \
    bundle clean && \
    mkdir -p vendor && \
    bundle config set path vendor && \
    cp -ar /srv/vendor .

# Copy bun modules
COPY --from=bun /home/bun/app/node_modules /rails/node_modules
COPY --from=bun /usr/local/bin/bun /usr/local/bun
ENV PATH=/usr/local/bun/bin:$PATH

Changes needed were

- FROM prebuild as bun
+ FROM oven/bun:1 as bun # it could point to version and OS like `1-alpine` and so on

# on the prebuild stage

- COPY --from=bun /rails/node_modules /rails/node_modules
+ COPY --from=bun /home/bun/app/node_modules /rails/node_modules

- COPY --from=bun /usr/local/bun /usr/local/bun
+ COPY --from=bun /usr/local/bin/bun /usr/local/bun/bin/.

what are your thoughts on this one?

Node path not found error when building image with Alpine

Hi, I'm trying to generate Dockerfile with Alpine:

$ bin/rails generate dockerfile --alpine --jemalloc --yjit --cache --parallel

Node part of the generated Dockfile:

# Install JavaScript dependencies
ARG NODE_VERSION=20.10.0
ARG YARN_VERSION=1.22.21
RUN curl -sL https://unofficial-builds.nodejs.org/download/release/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64-musl.tar.gz | tar xz -C /tmp/ && \
    cp -rp /tmp/node-v${NODE_VERSION}-linux-x64-musl/* /usr/local && \
    npm install -g yarn@$YARN_VERSION && \
    rm -rf /tmp/node-v${NODE_VERSION}-linux-x64-musl

# Copy node modules
COPY --from=node /rails/node_modules /rails/node_modules
COPY --from=node /usr/local/node /usr/local/node
ENV PATH=/usr/local/node/bin:$PATH

When building the image, it raises an error:
Error: failed to fetch an image or build from source: error building: failed to solve: failed to compute cache key: "/usr/local/node" not found: not found

Found the reason is the Node paths are inconsistent:

  • cp -rp /tmp/node-v${NODE_VERSION}-linux-x64-musl/* /usr/local && \ use /usr/local
  • COPY --from=node /usr/local/node /usr/local/node use /usr/local/node

I tried to fix it by modifying the Dockerfile:

# Install JavaScript dependencies
ARG NODE_VERSION=20.10.0
ARG YARN_VERSION=1.22.21
+ ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://unofficial-builds.nodejs.org/download/release/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64-musl.tar.gz | tar xz -C /tmp/ && \
+    mkdir /usr/local/node && \
-    cp -rp /tmp/node-v${NODE_VERSION}-linux-x64-musl/* /usr/local && \
+    cp -rp /tmp/node-v${NODE_VERSION}-linux-x64-musl/* /usr/local/node && \
    npm install -g yarn@$YARN_VERSION && \
    rm -rf /tmp/node-v${NODE_VERSION}-linux-x64-musl

It works, but I'm not sure it's the best way.

So please fix it in the generator, thanks.

1.5.2 Dockerfile breaks on ECS

I upgraded a project from 1.5.1 to 1.5.2 and generated a new Dockerfile. Subsequently, nginx refuses to start:

July 29, 2023 at 09:01 (UTC+2:00) 07:01:17 rails.1 | terminated by SIGTERM  staging-web
July 29, 2023 at 09:01 (UTC+2:00) 07:01:17 nginx.1 | exited with code 1 staging-web
July 29, 2023 at 09:01 (UTC+2:00) 07:01:17 system | sending SIGTERM to all processes  staging-web
July 29, 2023 at 09:01 (UTC+2:00) 07:01:16 nginx.1 | 2023/07/29 07:01:16 [emerg] 20#20: open() "/usr/share/nginx/stdout" failed (13: Permission denied) staging-web
July 29, 2023 at 09:01 (UTC+2:00) 07:01:16 nginx.1 | 2023/07/29 07:01:16 [warn] 20#20: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:1  staging-web
July 29, 2023 at 09:01 (UTC+2:00) 07:01:16 nginx.1 | started with pid 14  staging-web
July 29, 2023 at 09:01 (UTC+2:00) 07:01:16 rails.1 | started with pid 15

This is on AWS ECS. For good measure, the Dockerfile diff:

diff --git a/Dockerfile b/Dockerfile
index c7220c5..06a329e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -51,14 +51,14 @@ RUN apt-get update -qq && \
 # configure nginx
 RUN gem install foreman && \
     sed -i 's|pid /run|pid /rails/tmp/pids|' /etc/nginx/nginx.conf && \
-    sed -i 's/access_log\s.*;/access_log \/dev\/stdout;/' /etc/nginx/nginx.conf && \
-    sed -i 's/error_log\s.*;/error_log \/dev\/stderr info;/' /etc/nginx/nginx.conf
+    sed -i 's/access_log\s.*;/access_log stdout;/' /etc/nginx/nginx.conf && \
+    sed -i 's/error_log\s.*;/error_log stderr info;/' /etc/nginx/nginx.conf

 COPY <<-"EOF" /etc/nginx/sites-available/default
 server {
   listen 3000 default_server;
   listen [::]:3000 default_server;
-  access_log /dev/stdout;
+  access_log stdout;

   root /rails/public;

@@ -92,7 +92,7 @@ RUN useradd rails --create-home --shell /bin/bash && \
 USER rails:rails

 # Deployment options
-ENV LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libjemalloc.so.2" \
+ENV LD_PRELOAD="libjemalloc.so.2" \
     MALLOC_CONF="dirty_decay_ms:1000,narenas:2,background_thread:true" \
     PORT="3001" \
     RAILS_LOG_TO_STDOUT="1"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.