I have a docker image that looks something like this:

FROM ubuntu:16.04

# Install packages for building ruby
RUN apt-get update && \
apt-get -y install build-essential git curl wget net-tools apt-utils sudo man \
libssl-dev libreadline-dev libyaml-dev nano gcc rubygems ruby-dev

# Install rbenv and ruby-build
ENV PATH /root/.rbenv/bin:$PATH
RUN git clone https://github.com/sstephenson/rbenv.git /root/.rbenv && \
git clone https://github.com/sstephenson/ruby-build.git /root/.rbenv/plugins/ruby-build && \
/root/.rbenv/plugins/ruby-build/install.sh && \
echo 'eval "$(rbenv init -)"' >> /etc/profile
echo 'eval "$(rbenv init -)"' >> ~/.profile && \
echo 'eval "$(rbenv init -)"' >> ~/.bashrc

# Install ruby and bundler
# Install Bundler
ENV CONFIGURE_OPTS --disable-install-doc
RUN rbenv install 2.4.1 && \
echo 'gem: --no-rdoc --no-ri' >> ~/.gemrc && \
rbenv global 2.4.1 && \
rbenv local 2.4.1 && \
gem install bundler

ENTRYPOINT /bin/bash

My problem is that when I build the image and start a container

docker build -t test .
docker run -it --name test-container test

If I run the commands directly in the container shell,
ruby is 2.4.1 (as I'd expect after running rbenv global 2.4.1)

ruby -v    # 2.4.1p111
which ruby # /root/.rbenv/shims/ruby

But if I open a new shell and use docker exec,
ruby is 2.3.1, which is the system default

docker exec test-container ruby -v    # 2.3.1p112
docker exec test-container which ruby # /usr/bin/ruby

I think it could have something to do with the bash profile not starting rbenv properly when using docker exec. The env command seems to have less output when using docker exec too, which is why I suspect something to do with .bashrc, .profile, or even /etc/profile not loading somehow.

How can I ensure docker exec produces the same result as running the command directly on the container?

Please refer to bash initialization process. https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html

In your Dockerfile, at lines 12-14 you are patching files, but do not activate any of rbenvs. Later at your last RUN call, you finally ARE activating an rbenv. This starts pointing at that specific version of ruby (I thin this patches root files) At that point you have different global shell initialization files vs. user initialization files.

Difference

  • entry point: "non-login" initialization process happens, then the file: /root/.bashrc is executed (a.k.a. "sourced"), it points to your cool ruby
  • exec of ruby: ruby executable is located using your default PATH. without running /root/.bash* files.

To validate all this you can append printouts to your shell's initialization files, and see what gets printed upon 2 cases.

Regards.

  • Thanks for your answer! That makes sense, but is there a way I can force docker exec to source .bashrc without actually prepending source ~/.bashrc && to every command I want to run? The reason this is an issue is that I have to start the container in detached mode, so I can only use exec to run commands. The only solution I've found so far is to force a symlink to /usr/bin/ruby ln -nsf ~/.rbenv/shims/ruby /usr/bin/ruby but that could break applications from ubuntu that rely on the system ruby version. – con-- Aug 10 at 8:34
  • @con-- I think you can create a wrapper script to do that for you, call it /arbitrary_exec.sh and do all the magic in it, executing everything as is at its bottom line: "${@}", invoke by exec /arbitrary_exec.sh mycmd bla bla bbla – mvk_il Aug 12 at 15:29

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.