Skip to content

Commit 4f3af4a

Browse files
authored
Add default Dockerfiles (rails#46762)
1 parent 41c2c26 commit 4f3af4a

File tree

9 files changed

+162
-0
lines changed

9 files changed

+162
-0
lines changed

railties/CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
* Add Docker files by default to new apps: Dockerfile, .dockerignore, bin/docker-entrypoint.
2+
These files can be skipped with `--skip-docker`. They're intended as a starting point for
3+
a production deploy of the application. Not intended for development (see Docked Rails for that).
4+
5+
Example:
6+
7+
```
8+
docker build -t app .
9+
docker volume create app-storage
10+
docker run --rm -it -v app-storage:/rails/storage -p 3000:3000 --env RAILS_MASTER_KEY=<see config/master.key> app
11+
```
12+
13+
You can also start a console or a runner from this image:
14+
15+
```
16+
docker run --rm -it -v app-storage:/rails/storage --env RAILS_MASTER_KEY=<see config/master.key> app console
17+
```
18+
19+
To create a multi-platform image on Apple Silicon to deploy on AMD or Intel and push to Docker Hub for user/app:
20+
21+
```
22+
docker login -u <user>
23+
docker buildx create --use
24+
docker buildx build --push --platform=linux/amd64,linux/arm64 -t <user/image> .
25+
```
26+
27+
*DHH*
28+
129
* Add ENV["SECRET_KEY_BASE_DUMMY"] for starting production environment with a generated secret base key,
230
which can be used to run tasks like `assets:precompile` without making the RAILS_MASTER_KEY available
331
to the build process.

railties/lib/rails/generators/app_base.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ def self.add_shared_options_for(name)
3737
class_option :skip_git, type: :boolean, aliases: "-G", default: nil,
3838
desc: "Skip git init, .gitignore and .gitattributes"
3939

40+
class_option :skip_docker, type: :boolean, default: nil,
41+
desc: "Skip Dockerfile, .dockerignore and bin/docker-entrypoint"
42+
4043
class_option :skip_keeps, type: :boolean, default: nil,
4144
desc: "Skip source control .keep files"
4245

railties/lib/rails/generators/rails/app/app_generator.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ def gitattributes
7070
template "gitattributes", ".gitattributes"
7171
end
7272

73+
def dockerfiles
74+
template "Dockerfile"
75+
template "dockerignore", ".dockerignore"
76+
77+
template "docker-entrypoint", "bin/docker-entrypoint"
78+
chmod "bin/docker-entrypoint", 0755 & ~File.umask, verbose: false
79+
end
80+
7381
def version_control
7482
if !options[:skip_git] && !options[:pretend]
7583
run git_init_command, capture: options[:quiet], abort_on_failure: false
@@ -342,6 +350,12 @@ def update_active_storage
342350
end
343351
remove_task :update_active_storage
344352

353+
def create_dockerfiles
354+
unless options[:skip_docker]
355+
build(:dockerfiles)
356+
end
357+
end
358+
345359
def create_config_files
346360
build(:config)
347361
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Make sure it matches the Ruby version in .ruby-version and Gemfile
2+
ARG RUBY_VERSION=<%= Gem.ruby_version %>
3+
FROM ruby:$RUBY_VERSION
4+
5+
<% if using_node? -%>
6+
# Install JavaScript dependencies and libvips for Active Storage
7+
ARG NODE_MAJOR_VERSION=19
8+
RUN curl -sL https://deb.nodesource.com/setup_$NODE_MAJOR_VERSION.x | bash -
9+
RUN apt-get update -qq && \
10+
apt-get install -y build-essential libvips nodejs && \
11+
apt-get clean && \
12+
rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man && \
13+
npm install -g yarn
14+
15+
<% elsif !skip_active_storage? -%>
16+
# Install libvips for Active Storage preview support
17+
RUN apt-get update -qq && \
18+
apt-get install -y build-essential libvips && \
19+
apt-get clean && \
20+
rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man
21+
22+
<% end -%>
23+
# Rails app lives here
24+
WORKDIR /rails
25+
26+
# Set production environment
27+
ENV RAILS_LOG_TO_STDOUT="1" \
28+
RAILS_SERVE_STATIC_FILES="true" \
29+
RAILS_ENV="production" \
30+
BUNDLE_WITHOUT="development:test"
31+
32+
# Install application gems
33+
COPY Gemfile Gemfile.lock ./
34+
RUN bundle install
35+
36+
# Copy application code
37+
COPY . .
38+
39+
<% if depend_on_bootsnap? -%>
40+
# Precompile bootsnap code for faster boot times
41+
RUN bundle exec bootsnap precompile --gemfile app/ lib/
42+
43+
<% end -%>
44+
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
45+
RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile
46+
47+
# Entrypoint prepares database and starts app on 0.0.0.0:3000 by default,
48+
# but can also take a rails command, like "console" or "runner" to start instead.
49+
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
50+
EXPOSE 3000
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/sh
2+
3+
if [ $# -eq 0 ]; then
4+
# Create new or migrate existing database
5+
./bin/rails db:prepare
6+
7+
# Start the server by default
8+
exec bin/rails server
9+
else
10+
# Allow other commands, like console or runner, to be called
11+
exec bin/rails "$@"
12+
fi
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.
2+
3+
# Ignore bundler config.
4+
/.bundle
5+
6+
# Ignore all default key files
7+
config/master.key
8+
config/credentials/*.key
9+
10+
# Ignore all logfiles and tempfiles.
11+
/log/*
12+
/tmp/*
13+
<% if keeps? -%>
14+
!/log/.keep
15+
!/tmp/.keep
16+
17+
# Ignore pidfiles, but keep the directory.
18+
/tmp/pids/*
19+
!/tmp/pids/
20+
!/tmp/pids/.keep
21+
<% end -%>
22+
23+
# Ignore storage (uploaded files in development and any SQLite databases).
24+
/storage/*
25+
<% if keeps? -%>
26+
!/storage/.keep
27+
/tmp/storage/*
28+
!/tmp/storage/
29+
!/tmp/storage/.keep
30+
<% end -%>
31+
<% unless options.api? -%>
32+
33+
/public/assets
34+
<% end -%>

railties/test/generators/api_app_generator_test.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ def test_app_update_does_not_generate_unnecessary_bin_files
110110
def default_files
111111
%w(.gitignore
112112
.ruby-version
113+
.dockerignore
113114
README.md
114115
Gemfile
115116
Rakefile
117+
Dockerfile
116118
config.ru
117119
app/channels
118120
app/controllers
@@ -121,6 +123,7 @@ def default_files
121123
app/views/layouts
122124
app/views/layouts/mailer.html.erb
123125
app/views/layouts/mailer.text.erb
126+
bin/docker-entrypoint
124127
bin/rails
125128
bin/rake
126129
bin/setup

railties/test/generators/app_generator_test.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
DEFAULT_APP_FILES = %w(
88
.gitattributes
99
.gitignore
10+
.dockerignore
1011
.ruby-version
1112
README.md
1213
Gemfile
1314
Rakefile
15+
Dockerfile
1416
config.ru
1517
app/assets/config/manifest.js
1618
app/assets/images
@@ -34,6 +36,7 @@
3436
app/views/layouts/application.html.erb
3537
app/views/layouts/mailer.html.erb
3638
app/views/layouts/mailer.text.erb
39+
bin/docker-entrypoint
3740
bin/rails
3841
bin/rake
3942
bin/setup
@@ -1006,6 +1009,14 @@ def test_gitignore
10061009
end
10071010
end
10081011

1012+
def test_dockerignore
1013+
run_generator
1014+
1015+
assert_file ".dockerignore" do |content|
1016+
assert_match(/config\/master\.key/, content)
1017+
end
1018+
end
1019+
10091020
def test_system_tests_directory_generated
10101021
run_generator
10111022

railties/test/generators/shared_generator_tests.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ def test_skip_keeps
132132
assert_no_file("app/models/concerns/.keep")
133133
end
134134

135+
def test_skip_docker
136+
run_generator [destination_root, "--skip-docker", "--full"]
137+
assert_no_file(".dockerignore")
138+
assert_no_file("Dockerfile")
139+
assert_no_file("bin/docker-entrypoint")
140+
end
141+
135142
def test_default_frameworks_are_required_when_others_are_removed
136143
run_generator [
137144
destination_root,

0 commit comments

Comments
 (0)