如何在 Rails docker 镜像中安装新的 gems 而无需重建它

Pra*_*ora 4 ruby bundle ruby-on-rails docker docker-compose

我正在尝试在 Docker 环境中创建我的 Rails 应用程序。我已使用卷将主机中的源目录挂载到容器内的目标路径。该应用程序正处于开发阶段,我需要不断向其添加新的 gem。我从正在运行的容器的 bash 安装 gem,它会安装 gem 和所需的依赖项。但是当我删除正在运行的容器(docker-compose down)然后再次实例化它们(docker-compose up)时,我的 Rails Web 图像显示缺少 gem 的错误。我知道重建图像会添加宝石,但是有没有办法在不重建图像的情况下添加宝石?

我按照 docker-compose 文档设置 Rails 应用程序 https://docs.docker.com/compose/rails/#define-the-project

Dockerfile

FROM ruby:2.7.1-slim-buster
LABEL MAINTAINER "Prayas Arora" "<prayasa@mindfiresolutions.com>"

# Install apt based dependencies required to run Rails as
# well as RubyGems. As the Ruby image itself is based on a
# Debian image, we use apt-get to install those.
RUN apt-get update \
    && apt-get install -qq -y --no-install-recommends \
       build-essential \
       libpq-dev \
       netcat \
       postgresql-client \
       nodejs \
    && rm -rf /var/lib/apt/lists/*


ENV APP_HOME /var/www/repository/repository_api

# Configure the main working directory. This is the base
# directory used in any further RUN, COPY, and ENTRYPOINT
# commands.
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

# Copy the Gemfile as well as the Gemfile.lock and install
# the RubyGems. This is a separate step so the dependencies
# will be cached unless changes to one of those two files
# are made.
COPY ./repository_api/Gemfile $APP_HOME/Gemfile
COPY ./repository_api/Gemfile.lock $APP_HOME/Gemfile.lock
RUN bundle install

# Copy the main application.
COPY ./repository_api $APP_HOME 

# Add a script to be executed every time the container starts.
COPY ./repository_docker/development/repository_api/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

# Expose port 3000 to the Docker host, so we can access it
# from the outside.
EXPOSE 3000

# The main command to run when the container starts. Also
# tell the Rails dev server to bind to all interfaces by
# default.
CMD ["rails","server","-b","0.0.0.0"]

Run Code Online (Sandbox Code Playgroud)

docker-compose.yml

    container_name: repository_api
    build:
      context: ../..
      dockerfile: repository_docker/development/repository_api/Dockerfile
    user: $UID
    env_file: .env
    stdin_open: true
    environment:
      DB_NAME: ${POSTGRES_DB}
      DB_PASSWORD: ${POSTGRES_PASSWORD}
      DB_USER: ${POSTGRES_USER}
      DB_HOST: ${POSTGRES_DB}
    volumes:
      - ../../repository_api:/var/www/repository/repository_api
    networks:
      - proxy
      - internal
    depends_on:
      - repository_db
Run Code Online (Sandbox Code Playgroud)

小智 6

一个简单的解决方案是将 gems 缓存在 docker 卷中。您可以在 docker 中创建一个卷并将其附加到捆绑 gems 的路径。这将保持共享状态,并且您不需要在您旋转的每个容器中安装 gem。

  container_name: repository_api
  build:
    context: ../..
    dockerfile: repository_docker/development/repository_api/Dockerfile
  user: $UID
  env_file: .env
  stdin_open: true
  environment:
    DB_NAME: ${POSTGRES_DB}
    DB_PASSWORD: ${POSTGRES_PASSWORD}
    DB_USER: ${POSTGRES_USER}
    DB_HOST: ${POSTGRES_DB}
  volumes:
    - ../../repository_api:/var/www/repository/repository_api
    - bundle_cache:/usr/local/bundle
  networks:
    - proxy
    - internal
    .
    .
volumes: 
  bundle_cache:
Run Code Online (Sandbox Code Playgroud)

另外,请参阅bundler.io,Ruby 的官方 Docker 镜像假设您将仅使用一个应用程序和一个 Gemfile,并且不会在您的容器中安装或运行其他 gem 或 Ruby 应用程序。因此,一旦添加了应用程序开发中所需的所有 gem,您就可以删除此bundle_cache卷并使用最终的 Gemfile 重建映像。