当我运行rails console时,在Docker中找不到任何宝石。

3

当我在我的Docker容器中启动Rails控制台时,我遇到了错误Could not find ..... in locally installed gems,并列出了所有的gems。

rails srails routes正常工作,构建时没有错误。

运行bundle install没有改变任何东西。

我找到的解决方法是使用docker-compose run web bundle install --binstubs

我在所有gems捆绑安装问题中没有发现同样的问题,我想知道我的Docker文件有什么问题。

Dockerfile:

# Use the official Ruby 2.5.0 image as the parent image
FROM ruby:2.5.0-slim

# Install dependencies
RUN apt-get update -qq \
    && apt-get install -y \
    # Needed for certain gems
    build-essential \
    shared-mime-info \
    # Needed for postgres gem
    libpq-dev \
    # Needed for mysql
    default-libmysqlclient-dev \
    # Needed for redis
    libssl-dev \
    # Needed for elastic search
    libcurl4-openssl-dev \
    # Needed for foreman
    procps

# Set the working directory to /app
WORKDIR /app

# Copy the Gemfile and Gemfile.lock into the image and install gems
ENV BUNDLER_VERSION=2.3.26
COPY Gemfile Gemfile.lock ./
RUN gem install bundler -v $BUNDLER_VERSION && bundle install --jobs 20 --retry 5

# Copy the rest of the application code into the image
COPY . .

# Expose port 3000 for the Rails app to listen on
EXPOSE 3000

# Start the Rails app with Puma
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]

Docker-compose:

version: '3.3'

services:
  db:
    image: mysql/mysql-server:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: app_api_dev
      MYSQL_USER: app_api
      MYSQL_PASSWORD: app_api
    volumes:
      - ./tmp/db:/var/lib/mysql
    ports:
      - "3306:3306"
  redis:
    image: redis
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app
    ports:
      - "3000:3000"
    depends_on:
      - db
      - redis
    environment:
      DATABASE_HOST: db
      DATABASE_USERNAME: app_api
      DATABASE_PASSWORD: app_api
      DATABASE_NAME: app_api_dev

容器中的/app/vendor目录是否安装了Gem包?由于您的volumes:隐藏了/app中的所有内容,该块也将隐藏该目录。您不需要那个volumes:块(应用程序代码已正确复制到映像中),删除它可能会有所帮助。 - David Maze
我尝试使用bash检查vendor目录,但是我没有看到gems,当我删除web的volumes块时它并没有发生改变。 - Wako
请包含从构建镜像的日志,同时包含 gem info 命令的输出结果。 - anothermh
1个回答

0

另一个答案没有太多意义:

  1. --binstubs 不会安装 gem,它会从已经作为 bundle 的一部分安装的 gem 中生成 stubs 在 bin/ 目录下,使得可以在不用加前缀 bundle exec 的情况下调用它们。
  2. 将命令拆分成两个独立的 RUN 语句,与之前完全相同地运行每个命令对于命令运行结果没有影响,只是会产生两个独立的 Docker 层,这将无缘无故增加 Docker 镜像的总体积。

我认为你可能遇到了几个实际问题。首先是:

  1. 在容器中将 WORKDIR 设置为 /app
  2. 使用 COPY . . 将应用程序的内容复制到 /app
  3. 配置 Docker Compose 将 . 挂载到 Docker 容器的 /app 目录下
结果是第二步可能根本没有发生;您复制到 /app 中的文件被忽略了,Docker Compose 直接从您本地计算机的文件系统中读取。如果您希望构建包含应用程序的 Docker 镜像,则这可能不是预期的行为。
如果您使用了 .dockerignore 文件,并且希望某些文件和文件夹不会被复制到镜像中,则这可能特别有问题;卷不遵循 .dockerignore,整个目录都可以在 /app 中使用。
如果您使用了 bundle config 选项,例如 BUNDLE_PATHBUNDLE_CACHE_PATH,并且您不希望将其加载到应用程序中,则这也可能会出现问题。您可能希望将 gem 安装到 Docker 镜像的系统路径中,并从其中读取,但如果 bundle config 中存在您不希望的选项,例如指向本地路径的 vendor/bundlevendor/cache,则挂载卷到本地路径将使用您本地系统上的这些预先存在的路径,而不是镜像中的路径。

第二个问题是您没有使用bundle exec运行命令。您没有清楚地说明您尝试如何运行rails consolerails serverrails routes,但这些命令需要以bundle exec为前缀,例如:bundle exec rails console。例如,如果您已经运行了docker compose up并且服务器正在运行:

docker exec -it web bash

然后当你在你的容器中时:

cd /app
bundle exec rails console

如果您想使用binstubs,那么在创建Docker镜像之前,您需要在本地计算机上运行bundle binstubs --all以在bin/中创建存根。然后,要使用binstubs调用这些命令,您需要包含它们的相对路径来运行它们,例如:
bin/rails console
bin/rails server
bin/rails routes

你需要在任何其他情况下运行 bundle exec rails ... 的地方都需要这样做。

最后,尝试仅使用rails consolerails server 运行它们很可能不起作用,因为它要求 Docker 镜像本身在全局安装这些 gem,而这些全局版本可能与你的捆绑版本不匹配。如果你只是运行 rails <something> 那么发生的情况是系统将查找 $PATH 中的一个名为rails 的二进制文件- 它不会自动找到你在 Gemfile.lock 中定义的 Rails 版本,并且不会自动找到由 bundle install 安装的二进制文件。它只是查找第一个响应的二进制文件,该文件可能或可能不知道你捆绑的应用程序及其依赖项。始终使用 bundle exec rails ...bin/rails ... 指定命令。

所有这些都说了,你的帖子中可能没有足够的信息来提供完整的答案。你没有提供minimal reproducible example,也没有在Docker镜像内提供gem infobundle config的输出,也没有提供构建日志,也没有提供生成错误所遵循的确切步骤。这个声明没有诊断意义:

当我在我的Docker容器中开始运行Rails控制台时,我得到了错误Could not find ..... in locally installed gems和所有gems的列表

你应该提供详细的逐步重现问题的步骤,例如:
  1. 首先我运行命令docker compose up
  2. 然后我运行docker ps以获取容器ID
  3. 然后我运行docker exec -it web rails console
  4. 然后我看到这个确切而完整的错误消息:
在没有这些信息的情况下,我们能做的最好的事情就是指引您朝正确的方向前进,但我们无法像您要求的那样从可靠的来源给出答案。在将问题设置为悬赏之前,我建议您仔细阅读如何提出一个好问题?,因为遵循这些说明将使您提供必要的信息以获得答案,而不需要悬赏或等待11天才能关闭悬赏。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接