Reputation: 549
I am installing ROS as instructed at http://wiki.ros.org/noetic/Installation/Ubuntu in a dockerfile. After installing, you set up the environment with 'source /opt/ros/noetic/setup.bash'. However, after I do that, every RUN command in the dockerfile stops working correctly.
In the dockerfile below, the first 'ls /' produces the expected output, but the second one does not. This is not specific to 'ls', that's just a demo of the problem; every command I RUN after the ROS environment does not have the effect expected. What is happening in the ROS environment setup to break it and how do I prevent it? I have a lot of other setup that needs to happen after setting up ROS.
FROM ubuntu:20.04
# Dependencies
RUN apt-get update && apt-get install -y lsb-release && apt-get clean all
RUN apt-get install -y gnupg2
# Set timezone so tzdata is not interactive during install
ENV TZ=America/New_York
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# Install ROS, from http://wiki.ros.org/noetic/Installation/Ubuntu
RUN sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
RUN apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 && \
apt-get update && \
apt install -qq -y ros-noetic-ros-base
RUN apt-get install -y python3-pip
RUN python3 -m pip install rospkg
RUN echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
# This DOES produce what you would think
RUN ls /
SHELL ["/bin/bash", "-c", "source ~/.bashrc"]
# This DOES NOT produce what you would think
RUN ls /
Upvotes: 0
Views: 455
Reputation: 158714
The Dockerfile SHELL
directive changes the shell that's used to interpret RUN
commands. The default is ["/bin/sh", "-c"]
, so you get
# These two commands are identical with the default SHELL
RUN ls /
RUN ["/bin/sh", "-c", "ls /"]
When you write SHELL
as you've done, you instead get
SHELL ["/bin/bash", "-c", "source ~/.bashrc"]
RUN ls /
# Equivalently:
RUN ["/bin/bash", "-c", "source ~/.bashrc", "ls /"]
However, the sh -c
option reads a single command word and executes it; any further options are ignored (mostly; the command word sees them as $1
positional parameters).
Mostly in Docker, shell dotfiles like .bashrc
are completely ignored. Setting up environment variables using ENV
directives is better. For the single main container process, you can also use an entrypoint wrapper script to load a file of variables, but this doesn't work during the container build or in docker exec
debug shells.
You can possibly take advantage of sh -c
's specific semantics, and knowing the command will be passed as a single additional argument, and say
SHELL ["/bin/bash", "-c", ". ~/.bashrc && $1"]
source in every Dockerfile RUN call instead suggests:
# Tell bash these are "login" shells and _should_ read shell dotfiles
SHELL ["/bin/bash", "--login", "-c"]
Upvotes: 1