You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker构建缓存bundle install,解决docker-compose下gems从头安装问题

Docker Compose Bundle Install Caching: Your Setup & Improvements

Great question! Your current Dockerfile is absolutely heading in the right direction for caching bundle install—but let’s break down how well it works, and share some tweaks to make it even more reliable and efficient.

Is Your Current Setup Effective?

Yes, it will work for caching, and here’s why:

  • Copying Gemfile/Gemfile.lock first: Docker’s layer caching relies on unchanged files to skip re-running steps. By copying these two files before your full application code, you ensure that bundle install only re-runs if your gem dependencies change (not every time you edit app code).
  • Setting BUNDLE_PATH/GEM_* variables: Redirecting gem installation to /gems (outside your app’s $APP_HOME) prevents the subsequent COPY . $APP_HOME step from overwriting or invalidating the gem cache.
  • bundle check || bundle install: This command smartly skips reinstalling gems if all required versions are already present in /gems, which adds another layer of efficiency.

Optimizations for Better Caching & Production Readiness

Here are some adjustments to tighten up your setup:

1. Slim Down the Alpine Image

Replace apk update && apk add with apk add --no-cache—this eliminates the need for a separate apk update and avoids leaving package manager cache in your final image, reducing its size significantly.

2. Add Production-Focused Bundle Flags

For production builds, you should enforce strict gem versioning and skip unnecessary groups (like development/test):

ENV BUNDLE_WITHOUT="development test" \
    BUNDLE_FROZEN="true" \
    BUNDLE_DEPLOYMENT="true"
  • BUNDLE_FROZEN ensures you can’t install gems without updating Gemfile.lock, keeping dependencies consistent.
  • BUNDLE_DEPLOYMENT installs gems in a way optimized for production (no documentation, strict version locks).

3. Ensure Proper Directory Permissions (Optional)

If you plan to run the container as a non-root user (a security best practice), pre-create the /gems directory with correct permissions:

RUN mkdir -p /gems && chown -R ruby:ruby /gems

(The official Ruby Alpine image uses the ruby user by default.)

4. Final Optimized Dockerfile

Here’s how your updated file might look:

FROM ruby:2.5.0-alpine

# Install dependencies without leftover cache
RUN apk add --no-cache build-base postgresql-dev nodejs git tzdata

ENV APP_HOME /panabus-api
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

# Copy gem files first to leverage cache
COPY Gemfile Gemfile.lock ./

# Configure bundle for production and cache
ENV BUNDLE_PATH=/gems \
    GEM_PATH=/gems \
    GEM_HOME=/gems \
    BUNDLE_WITHOUT="development test" \
    BUNDLE_FROZEN="true" \
    BUNDLE_DEPLOYMENT="true"

# Install gems only if dependencies changed
RUN bundle check || bundle install

# Copy remaining app code
COPY . $APP_HOME

ENV RAILS_ENV=production

# Add production tasks (e.g., asset precompilation)
RUN bundle exec rails assets:precompile

Key Takeaway

Your core approach is solid—prioritizing gem file copying to leverage Docker’s layer caching is the standard way to avoid re-installing gems on every build. The optimizations above just make the setup more production-ready, efficient, and reliable.

内容的提问来源于stack exchange,提问作者hcarreras

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:01:52