Merge pull request #51063 from anonychun/speedup-docker-build-time

Speedup Docker Build Time
This commit is contained in:
Rafael Mendonça França 2024-02-13 18:17:05 -05:00 committed by GitHub
commit f8ffd46ccc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 63 additions and 75 deletions

@ -561,6 +561,22 @@ def dockerfile_binfile_fixups
binfixups
end
def dockerfile_base_packages
# Add curl to work with the default healthcheck strategy in Kamal
packages = ["curl"]
# ActiveRecord databases
packages << base_package_for_database unless skip_active_record?
# ActiveStorage preview support
packages << "libvips" unless skip_active_storage?
# jemalloc for memory optimization
packages << "libjemalloc2"
packages.compact.sort
end
def dockerfile_build_packages
# start with the essentials
packages = %w(build-essential git pkg-config)
@ -568,11 +584,6 @@ def dockerfile_build_packages
# add database support
packages << build_package_for_database unless skip_active_record?
# ActiveStorage preview support
packages << "libvips" unless skip_active_storage?
packages << "curl" if using_js_runtime?
packages << "unzip" if using_bun?
# node support, including support for building native modules
@ -585,22 +596,6 @@ def dockerfile_build_packages
packages.compact.sort
end
def dockerfile_deploy_packages
# Add curl to work with the default healthcheck strategy in Kamal
packages = ["curl"]
# ActiveRecord databases
packages << deploy_package_for_database unless skip_active_record?
# ActiveStorage preview support
packages << "libvips" unless skip_active_storage?
# jemalloc for memory optimization
packages << "libjemalloc2"
packages.compact.sort
end
def css_gemfile_entry
return if options[:api]
return unless options[:css]

@ -27,6 +27,16 @@ def gem_for_database(database = options[:database])
end
end
def docker_for_database_base(database = options[:database])
case database
when "mysql" then "curl default-mysql-client libvips"
when "trilogy" then "curl libvips"
when "postgresql" then "curl libvips postgresql-client"
when "sqlite3" then "curl libsqlite3-0 libvips"
else nil
end
end
def docker_for_database_build(database = options[:database])
case database
when "mysql" then "build-essential default-libmysqlclient-dev git"
@ -37,16 +47,6 @@ def docker_for_database_build(database = options[:database])
end
end
def docker_for_database_deploy(database = options[:database])
case database
when "mysql" then "curl default-mysql-client libvips"
when "trilogy" then "curl libvips"
when "postgresql" then "curl libvips postgresql-client"
when "sqlite3" then "curl libsqlite3-0 libvips"
else nil
end
end
def convert_database_option_for_jruby
if defined?(JRUBY_VERSION)
opt = options.dup
@ -59,15 +59,7 @@ def convert_database_option_for_jruby
end
end
def build_package_for_database(database = options[:database])
case database
when "mysql" then "default-libmysqlclient-dev"
when "postgresql" then "libpq-dev"
else nil
end
end
def deploy_package_for_database(database = options[:database])
def base_package_for_database(database = options[:database])
case database
when "mysql" then "default-mysql-client"
when "postgresql" then "postgresql-client"
@ -76,6 +68,14 @@ def deploy_package_for_database(database = options[:database])
end
end
def build_package_for_database(database = options[:database])
case database
when "mysql" then "default-libmysqlclient-dev"
when "postgresql" then "libpq-dev"
else nil
end
end
private
def mysql_socket
@mysql_socket ||= [

@ -7,19 +7,21 @@ FROM registry.docker.com/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 <%= dockerfile_base_packages.join(" ") %>
# 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<%= using_node? ? " and node modules" : "" %>
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y <%= dockerfile_build_packages.join(" ") %>
RUN apt-get install --no-install-recommends -y <%= dockerfile_build_packages.join(" ") %>
<% if using_node? -%>
# Install JavaScript dependencies
@ -79,13 +81,9 @@ RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
# Final stage for app image
FROM base
<% unless dockerfile_deploy_packages.empty? -%>
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y <%= dockerfile_deploy_packages.join(" ") %> && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Clean up installation packages to reduce image size
RUN rm -rf /var/lib/apt/lists /var/cache/apt/archives
<% end -%>
# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails

@ -99,7 +99,7 @@ jobs:
<%- end -%>
steps:
- name: Install packages
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y google-chrome-stable <%= (dockerfile_deploy_packages + [build_package_for_database]).join(" ") %>
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y google-chrome-stable <%= (dockerfile_base_packages + [build_package_for_database]).join(" ") %>
- name: Checkout code
uses: actions/checkout@v4

@ -44,14 +44,14 @@ def edit_dockerfile
dockerfile_path = File.expand_path("Dockerfile", destination_root)
return unless File.exist?(dockerfile_path)
base_name = docker_for_database_base
build_name = docker_for_database_build
deploy_name = docker_for_database_deploy
if base_name
gsub_file("Dockerfile", all_docker_bases_regex, base_name)
end
if build_name
gsub_file("Dockerfile", all_docker_builds_regex, build_name)
end
if deploy_name
gsub_file("Dockerfile", all_docker_deploys_regex, deploy_name)
end
end
private
@ -59,12 +59,12 @@ def all_database_gems
DATABASES.map { |database| gem_for_database(database) }
end
def all_docker_builds
DATABASES.map { |database| docker_for_database_build(database).nil? ? nil : docker_for_database_build(database) }.compact!
def all_docker_bases
DATABASES.map { |database| docker_for_database_base(database).nil? ? nil : docker_for_database_base(database) }.compact!
end
def all_docker_deploys
DATABASES.map { |database| docker_for_database_deploy(database).nil? ? nil : docker_for_database_deploy(database) }.compact!
def all_docker_builds
DATABASES.map { |database| docker_for_database_build(database).nil? ? nil : docker_for_database_build(database) }.compact!
end
def all_database_gems_regex
@ -72,12 +72,12 @@ def all_database_gems_regex
/(\b#{all_database_gem_names.join('\b|\b')}\b)/
end
def all_docker_builds_regex
/(\b#{all_docker_builds.join('\b|\b')}\b)/
def all_docker_bases_regex
/(\b#{all_docker_bases.join('\b|\b')}\b)/
end
def all_docker_deploys_regex
/(\b#{all_docker_deploys.join('\b|\b')}\b)/
def all_docker_builds_regex
/(\b#{all_docker_builds.join('\b|\b')}\b)/
end
def gem_entry_regex_for(gem_name)

@ -7,21 +7,21 @@ FROM registry.docker.com/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 libsqlite3-0 libvips
# 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 libvips pkg-config
RUN apt-get install --no-install-recommends -y build-essential git pkg-config
# Install application gems
COPY Gemfile Gemfile.lock ./
@ -29,8 +29,6 @@ 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 . .
@ -40,14 +38,11 @@ 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
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libsqlite3-0 libvips && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Clean up installation packages to reduce image size
RUN rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"

@ -85,7 +85,7 @@ class ChangeGeneratorTest < Rails::Generators::TestCase
end
assert_file("Dockerfile") do |content|
assert_match "build-essential git libvips", content
assert_match "build-essential git", content
assert_match "curl libsqlite3-0 libvips", content
end
end