9

I have been using docker since some time now. I have encountered a situation wherein I need to execute instructions present in the Dockerfile based on some condition. For example here is the snippet of Dockerfile

FROM centos:centos7
MAINTAINER Akshay <akshay@dm.com>

# Update and install required binaries
RUN yum update -y \
    && yum install -y which wget openssh-server sudo java-1.8.0-openjdk \
    && yum clean all

#install Maven
RUN curl -Lf http://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz -o /tmp/apache-maven-3.3.9.tar.gz
RUN tar -xzf /tmp/apache-maven-3.3.9.tar.gz -C /opt \
        && rm /tmp/apache-maven-3.3.9.tar.gz

ENV M2_HOME "/opt/apache-maven-3.3.9"
ENV PATH ${PATH}:${M2_HOME}/bin:

# Install Ant
ENV ANT_VERSION 1.9.4
RUN cd && \
    wget -q http://archive.apache.org/dist/ant/binaries/apache-ant-${ANT_VERSION}-bin.tar.gz && \
    tar -xzf apache-ant-${ANT_VERSION}-bin.tar.gz && \
    mv apache-ant-${ANT_VERSION} /opt/ant && \
    rm apache-ant-${ANT_VERSION}-bin.tar.gz
ENV ANT_HOME /opt/ant
ENV PATH ${PATH}:/opt/ant/bin
......

So as you can see in my docker file that I have installation instructions for both maven and ant. But now I've to install either one of them based on a condition. I know that I can use ARG instruction in the Dockerfile to fetch the argument during the build time, but the problem is I couldn't find any docs on how to enclose them in an if/else block.

I have read few other stackoverflow posts too regarding this, but in those I see that they have asked to use conditional statements inside of an instruction eg RUN if $BUILDVAR -eq "SO"; then export SOMEVAR=hello; else export SOMEVAR=world; fiLink, or writing a separate script file like this But as you can see, my case is different. I can't make us of this since I would have a bunch of other instructions too which would be depended on that argument. I have to do something like this

ARG BUILD_TOOL  
if [ "${BUILD_TOOL}" = "MAVEN" ]; then
--install maven
elif [ "${BUILD_TOOL}" = "ANT" ]; then
--install ant
fi
.... other instructions ....
if [ "${BUILD_TOOL}" = "MAVEN" ]; then
    --some other dependent commands
elif [ "${BUILD_TOOL}" = "ANT" ]; then
    --some other dependent commands
fi
Community
  • 1
  • 1
DMA
  • 1,033
  • 1
  • 11
  • 22
  • Also see https://stackoverflow.com/questions/43654656/dockerfile-if-else-condition-with-external-arguments/60820156#60820156 for conditional docker files that do not require any bash – User12547645 Jul 22 '20 at 16:07

1 Answers1

9

If you don't want to use all those RUN if statements, you can instead create a bash script with the setup procedure and call it from the Dockerfile. For example:

FROM centos:centos7
MAINTAINER Someone <someone@email.com>

ARG BUILD_TOOL

COPY setup.sh /setup.sh

RUN ./setup.sh

RUN rm /setup.sh

And the setup.sh file (don't forget to make it executable):

if [ "${BUILD_TOOL}" = "MAVEN" ]; then
    echo "Step 1 of MAVEN setup";
    echo "(...)";
    echo "Done MAVEN setup";
elif [ "${BUILD_TOOL}" = "ANT" ]; then
    echo "Step 1 of ANT setup";
    echo "(...)";
    echo "Done ANT setup";
fi

You can then build it using docker build --build-arg BUILD_TOOL=MAVEN . (or ANT).

Note that I used a shell script here, but if you have other interpreters available (ex: python or ruby), you can also use them to write the setup script.

Salem
  • 12,808
  • 4
  • 34
  • 54
  • thanks for your comment. Yes, I thought about this solution too. But the problem is that I should have multiple scripts since checking for that condition should result in different docker instructions to be executed. So it would be like, after executing `setup.sh` then again based on that condition, it should execute `configure.sh` and also another `execute.sh` and so on. So it would be very tedious this way I feel. Hence thought if there were any other way to accomplish this. Please correct me if I am wrong. – DMA Mar 10 '17 at 15:47
  • "since checking for that condition should result in different docker instructions to be executed" can you give a concrete example? – Salem Mar 10 '17 at 19:40
  • What I meant is that I have to use the argument `BUILD_TOOL` to determine what other instructions have to be executed apart from the `setup.sh`. Like for instance after installing either MAVEN/ANT, I will have to execute some common instructions and again based on `BUILD_TOOL` I would have to determine other things that need to be configured, again common instructions and the pattern repeats. As per this approach, it would become this way `RUN ./setup.sh RUN ./configure.sh RUN ./execute.sh` and those files containing `if/else` as you had mentioned above. Hope you got what I am trying to say. – DMA Mar 10 '17 at 21:33
  • I know for sure that this would work, but I just do not know whether it's a good approach since there would be many shell scripts just for executing the commands(if/else). Hence was looking for a better approach/solution for this. – DMA Mar 10 '17 at 21:36
  • What stops you from having only a single if/else with every instructions in there (`if ANT then setupAnt; configureAnt; executeAnt; else setupMaven; configureMaven; executeMaven`)? – Salem Mar 10 '17 at 22:44
  • Yes, I could do this but, I would have some common instructions to be executed irrespective of the BUILD_TOOL argument. In this case, I would have to put those instructions both in if/else block and it would result in duplicate instructions. – DMA Mar 11 '17 at 08:15