构建Dockerfile时,Linux的source命令无法工作

9
我有一个定义了 Ruby on Rails 栈的 Dockerfile。
以下是 Dockerfile 的内容:
FROM ubuntu:14.04
MAINTAINER example <examplen@example.com>

# Update
RUN apt-get update

# Install Ruby and Rails dependencies
RUN apt-get install -y \
ruby \
ruby-dev \
build-essential \
libxml2-dev \
libxslt1-dev \
zlib1g-dev \
libsqlite3-dev \
nodejs \
curl

RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3

RUN curl -sSL https://get.rvm.io | bash -s stable --rails

RUN /bin/bash -c "source /usr/local/rvm/scripts/rvm"

# Install Rails
RUN gem install rails

# Create a new Rails app under /src/my-app
RUN mkdir -p /src/new-app

RUN rails new /src/new-app

WORKDIR /src/my-app

# Default command is to run a rails server on port 3000
CMD ["rails", "server", "--binding", "0.0.0.0", "--port" ,"3000"]

EXPOSE 3000

当我执行命令docker build -t anotherapp/my-rails-app .时,我遇到了以下错误:

删除中间容器3f8060cdc6f5
步骤8:运行gem install rails
---> 运行中的8c1793414e63
错误:安装rails时出现错误:
activesupport需要Ruby版本>= 2.2.2。
命令'/bin/sh -c gem install rails'返回非零代码:1

看起来在构建期间命令source /usr/local/rvm/scripts/rvm无法正常工作。
我不确定为什么会出现这种情况。

3
指令可以正常运行,但当指令完成后,终端会退出并且所有内容都会消失。 - tkausl
3
也许你不应该使用rvm来安装Rails,但如果你想使用它,你应该链接所有的RUN,因为每个RUN都会创建一个新的层,并且可能不知道你的bash源。 - bjhaid
你读过这个回答吗 https://dev59.com/JoPba4cB1Zd3GeqPnxsc#25685004? - Griffin
2个回答

12
Docker Builder参考文档可以得知,每个RUN命令都是独立运行的。因此,执行RUN source /usr/local/rvm/scripts/rvm对下一个RUN命令没有任何影响。
请尝试按照以下方式更改需要给定源文件的操作。
  RUN /bin/bash -c "source /usr/local/rvm/scripts/rvm ; gem install rails"

9
这并不能直接回答你的问题,但这是另一种解决问题的方法。
Docker提供了一个官方Ruby镜像。这是Docker Compose和Rails快速入门教程所使用的镜像。正如你可以从他们的示例(如下所示)中看到的那样,你可以将Gemfile.lock复制到你的镜像中,并运行bundle install,而不必担心RVM。
FROM ruby:2.2.0
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
ADD . /myapp

通常情况下,您只会在容器内运行一个 Rails 应用程序,使用特定版本的 Ruby,因此 RVM 管理多个 Ruby 版本的能力将不起作用。

如果您想知道官方镜像是如何制作的,请访问 Github 上的 Dockerfile


关于为什么会发生这种情况。正如其他人指出的那样,source 命令在当前 shell 中执行文件。每个 RUN 指令都会在当前镜像的新层上执行任何命令并提交结果。生成的提交镜像将用于 Dockerfile 中的下一步操作。每个 RUNADDCOPY 指令实际上都会在新容器中启动一个新的 shell 并执行命令。
1 RUN /bin/bash -c "source /usr/local/rvm/scripts/rvm"
2 RUN gem install rails

可以理解为

1 Start a brand new shell
  Execute: source /usr/local/rvm/scripts/rvm
  Save the state of the file system as an image
  Exit shell

2 Start a brand new shell
  Execute: gem install rails
  ...

当第一步完成时,shell(以及您引用的所有内容)都会消失。

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