Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

linux source command not working when building Dockerfile

I have a Dockerfile that defines a Ruby on Rails stack.

Here is the Dockerfile:

FROM ubuntu:14.04
MAINTAINER example <[email protected]>

# 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

When I execute the command docker build -t anotherapp/my-rails-app . I get the following error:

Removing intermediate container 3f8060cdc6f5
Step 8 : RUN gem install rails
---> Running in 8c1793414e63
ERROR: Error installing rails:
activesupport requires Ruby version >= 2.2.2.
The command '/bin/sh -c gem install rails' returned a non-zero code: 1

It looks like the command source /usr/local/rvm/scripts/rvm isn't working during the build.

I'm not sure exactly why this is happening.

like image 347
breaktop Avatar asked Oct 14 '16 13:10

breaktop


2 Answers

From the docker builder reference, each RUN command is run independently. So doing RUN source /usr/local/rvm/scripts/rvm does not have any effect on the next RUN command.

Try changing the operations which require the given source file as follows

  RUN /bin/bash -c "source /usr/local/rvm/scripts/rvm ; gem install rails"
like image 141
Nizar Malangadan Avatar answered Oct 13 '22 02:10

Nizar Malangadan


This doesn't directly answer your question, but it's another way to approach the problem.

Docker provides an official Ruby image. This is the image the Docker Compose and Rails quickstart tutorial uses. As you can see from their example (below), you can copy your Gemfile.lock into your image and run bundle install without having to worry about 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

You will normally only have one rails application running inside a container using a specific version of Ruby so RVM's ability to manage multiple version of Ruby won't be helpful.

If you are curious how the official images are made, the Dockerfile is on Github.


As to why this is happening. As others pointed out, source command executes the file in the current shell. Each RUN instruction

... will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.

Each RUN, ADD, COPY instruction essentially starts a new shell in a new container and executes a command.

1 RUN /bin/bash -c "source /usr/local/rvm/scripts/rvm"
2 RUN gem install rails

Can be read as

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
  ...

When step 1 finishes, the shell (and everything your sourced into it), goes away.

like image 29
Roman Avatar answered Oct 13 '22 00:10

Roman