Skip to content

Commit f8ffd46

Browse files
authored
Merge pull request rails#51063 from anonychun/speedup-docker-build-time
Speedup Docker Build Time
2 parents 2e4a2b7 + bdb8a6d commit f8ffd46

File tree

7 files changed

+61
-73
lines changed

7 files changed

+61
-73
lines changed

railties/lib/rails/generators/app_base.rb

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -561,18 +561,29 @@ def dockerfile_binfile_fixups
561561
binfixups
562562
end
563563

564+
def dockerfile_base_packages
565+
# Add curl to work with the default healthcheck strategy in Kamal
566+
packages = ["curl"]
567+
568+
# ActiveRecord databases
569+
packages << base_package_for_database unless skip_active_record?
570+
571+
# ActiveStorage preview support
572+
packages << "libvips" unless skip_active_storage?
573+
574+
# jemalloc for memory optimization
575+
packages << "libjemalloc2"
576+
577+
packages.compact.sort
578+
end
579+
564580
def dockerfile_build_packages
565581
# start with the essentials
566582
packages = %w(build-essential git pkg-config)
567583

568584
# add database support
569585
packages << build_package_for_database unless skip_active_record?
570586

571-
# ActiveStorage preview support
572-
packages << "libvips" unless skip_active_storage?
573-
574-
packages << "curl" if using_js_runtime?
575-
576587
packages << "unzip" if using_bun?
577588

578589
# node support, including support for building native modules
@@ -585,22 +596,6 @@ def dockerfile_build_packages
585596
packages.compact.sort
586597
end
587598

588-
def dockerfile_deploy_packages
589-
# Add curl to work with the default healthcheck strategy in Kamal
590-
packages = ["curl"]
591-
592-
# ActiveRecord databases
593-
packages << deploy_package_for_database unless skip_active_record?
594-
595-
# ActiveStorage preview support
596-
packages << "libvips" unless skip_active_storage?
597-
598-
# jemalloc for memory optimization
599-
packages << "libjemalloc2"
600-
601-
packages.compact.sort
602-
end
603-
604599
def css_gemfile_entry
605600
return if options[:api]
606601
return unless options[:css]

railties/lib/rails/generators/database.rb

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,22 @@ def gem_for_database(database = options[:database])
2727
end
2828
end
2929

30-
def docker_for_database_build(database = options[:database])
30+
def docker_for_database_base(database = options[:database])
3131
case database
32-
when "mysql" then "build-essential default-libmysqlclient-dev git"
33-
when "trilogy" then "build-essential git"
34-
when "postgresql" then "build-essential git libpq-dev"
35-
when "sqlite3" then "build-essential git"
32+
when "mysql" then "curl default-mysql-client libvips"
33+
when "trilogy" then "curl libvips"
34+
when "postgresql" then "curl libvips postgresql-client"
35+
when "sqlite3" then "curl libsqlite3-0 libvips"
3636
else nil
3737
end
3838
end
3939

40-
def docker_for_database_deploy(database = options[:database])
40+
def docker_for_database_build(database = options[:database])
4141
case database
42-
when "mysql" then "curl default-mysql-client libvips"
43-
when "trilogy" then "curl libvips"
44-
when "postgresql" then "curl libvips postgresql-client"
45-
when "sqlite3" then "curl libsqlite3-0 libvips"
42+
when "mysql" then "build-essential default-libmysqlclient-dev git"
43+
when "trilogy" then "build-essential git"
44+
when "postgresql" then "build-essential git libpq-dev"
45+
when "sqlite3" then "build-essential git"
4646
else nil
4747
end
4848
end
@@ -59,19 +59,19 @@ def convert_database_option_for_jruby
5959
end
6060
end
6161

62-
def build_package_for_database(database = options[:database])
62+
def base_package_for_database(database = options[:database])
6363
case database
64-
when "mysql" then "default-libmysqlclient-dev"
65-
when "postgresql" then "libpq-dev"
64+
when "mysql" then "default-mysql-client"
65+
when "postgresql" then "postgresql-client"
66+
when "sqlite3" then "libsqlite3-0"
6667
else nil
6768
end
6869
end
6970

70-
def deploy_package_for_database(database = options[:database])
71+
def build_package_for_database(database = options[:database])
7172
case database
72-
when "mysql" then "default-mysql-client"
73-
when "postgresql" then "postgresql-client"
74-
when "sqlite3" then "libsqlite3-0"
73+
when "mysql" then "default-libmysqlclient-dev"
74+
when "postgresql" then "libpq-dev"
7575
else nil
7676
end
7777
end

railties/lib/rails/generators/rails/app/templates/Dockerfile.tt

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,21 @@ FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
77
# Rails app lives here
88
WORKDIR /rails
99

10+
# Install base packages
11+
RUN apt-get update -qq && \
12+
apt-get install --no-install-recommends -y <%= dockerfile_base_packages.join(" ") %>
13+
1014
# Set production environment
1115
ENV RAILS_ENV="production" \
1216
BUNDLE_DEPLOYMENT="1" \
1317
BUNDLE_PATH="/usr/local/bundle" \
1418
BUNDLE_WITHOUT="development"
1519

16-
1720
# Throw-away build stage to reduce size of final image
1821
FROM base as build
1922

2023
# Install packages needed to build gems<%= using_node? ? " and node modules" : "" %>
21-
RUN apt-get update -qq && \
22-
apt-get install --no-install-recommends -y <%= dockerfile_build_packages.join(" ") %>
24+
RUN apt-get install --no-install-recommends -y <%= dockerfile_build_packages.join(" ") %>
2325

2426
<% if using_node? -%>
2527
# Install JavaScript dependencies
@@ -79,13 +81,9 @@ RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
7981
# Final stage for app image
8082
FROM base
8183

82-
<% unless dockerfile_deploy_packages.empty? -%>
83-
# Install packages needed for deployment
84-
RUN apt-get update -qq && \
85-
apt-get install --no-install-recommends -y <%= dockerfile_deploy_packages.join(" ") %> && \
86-
rm -rf /var/lib/apt/lists /var/cache/apt/archives
84+
# Clean up installation packages to reduce image size
85+
RUN rm -rf /var/lib/apt/lists /var/cache/apt/archives
8786

88-
<% end -%>
8987
# Copy built artifacts: gems, application
9088
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
9189
COPY --from=build /rails /rails

railties/lib/rails/generators/rails/app/templates/github/ci.yml.tt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ jobs:
9999
<%- end -%>
100100
steps:
101101
- name: Install packages
102-
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y google-chrome-stable <%= (dockerfile_deploy_packages + [build_package_for_database]).join(" ") %>
102+
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y google-chrome-stable <%= (dockerfile_base_packages + [build_package_for_database]).join(" ") %>
103103

104104
- name: Checkout code
105105
uses: actions/checkout@v4

railties/lib/rails/generators/rails/db/system/change/change_generator.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,40 +44,40 @@ def edit_dockerfile
4444
dockerfile_path = File.expand_path("Dockerfile", destination_root)
4545
return unless File.exist?(dockerfile_path)
4646

47+
base_name = docker_for_database_base
4748
build_name = docker_for_database_build
48-
deploy_name = docker_for_database_deploy
49+
if base_name
50+
gsub_file("Dockerfile", all_docker_bases_regex, base_name)
51+
end
4952
if build_name
5053
gsub_file("Dockerfile", all_docker_builds_regex, build_name)
5154
end
52-
if deploy_name
53-
gsub_file("Dockerfile", all_docker_deploys_regex, deploy_name)
54-
end
5555
end
5656

5757
private
5858
def all_database_gems
5959
DATABASES.map { |database| gem_for_database(database) }
6060
end
6161

62-
def all_docker_builds
63-
DATABASES.map { |database| docker_for_database_build(database).nil? ? nil : docker_for_database_build(database) }.compact!
62+
def all_docker_bases
63+
DATABASES.map { |database| docker_for_database_base(database).nil? ? nil : docker_for_database_base(database) }.compact!
6464
end
6565

66-
def all_docker_deploys
67-
DATABASES.map { |database| docker_for_database_deploy(database).nil? ? nil : docker_for_database_deploy(database) }.compact!
66+
def all_docker_builds
67+
DATABASES.map { |database| docker_for_database_build(database).nil? ? nil : docker_for_database_build(database) }.compact!
6868
end
6969

7070
def all_database_gems_regex
7171
all_database_gem_names = all_database_gems.map(&:first)
7272
/(\b#{all_database_gem_names.join('\b|\b')}\b)/
7373
end
7474

75-
def all_docker_builds_regex
76-
/(\b#{all_docker_builds.join('\b|\b')}\b)/
75+
def all_docker_bases_regex
76+
/(\b#{all_docker_bases.join('\b|\b')}\b)/
7777
end
7878

79-
def all_docker_deploys_regex
80-
/(\b#{all_docker_deploys.join('\b|\b')}\b)/
79+
def all_docker_builds_regex
80+
/(\b#{all_docker_builds.join('\b|\b')}\b)/
8181
end
8282

8383
def gem_entry_regex_for(gem_name)

railties/test/fixtures/Dockerfile.test

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,28 @@ FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
77
# Rails app lives here
88
WORKDIR /rails
99

10+
# Install base packages
11+
RUN apt-get update -qq && \
12+
apt-get install --no-install-recommends -y curl libsqlite3-0 libvips
13+
1014
# Set production environment
1115
ENV RAILS_ENV="production" \
1216
BUNDLE_DEPLOYMENT="1" \
1317
BUNDLE_PATH="/usr/local/bundle" \
1418
BUNDLE_WITHOUT="development"
1519

16-
1720
# Throw-away build stage to reduce size of final image
1821
FROM base as build
1922

2023
# Install packages needed to build gems
21-
RUN apt-get update -qq && \
22-
apt-get install --no-install-recommends -y build-essential git libvips pkg-config
23-
24-
24+
RUN apt-get install --no-install-recommends -y build-essential git pkg-config
2525

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

32-
33-
3432
# Copy application code
3533
COPY . .
3634

@@ -40,14 +38,11 @@ RUN bundle exec bootsnap precompile app/ lib/
4038
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
4139
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
4240

43-
4441
# Final stage for app image
4542
FROM base
4643

47-
# Install packages needed for deployment
48-
RUN apt-get update -qq && \
49-
apt-get install --no-install-recommends -y curl libsqlite3-0 libvips && \
50-
rm -rf /var/lib/apt/lists /var/cache/apt/archives
44+
# Clean up installation packages to reduce image size
45+
RUN rm -rf /var/lib/apt/lists /var/cache/apt/archives
5146

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

railties/test/generators/db_system_change_generator_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class ChangeGeneratorTest < Rails::Generators::TestCase
8585
end
8686

8787
assert_file("Dockerfile") do |content|
88-
assert_match "build-essential git libvips", content
88+
assert_match "build-essential git", content
8989
assert_match "curl libsqlite3-0 libvips", content
9090
end
9191
end

0 commit comments

Comments
 (0)