Conditionally copy files in multistage dockerfile

This was asked on docker - Conditionally copy files in multistage dockerfile - Stack Overflow as well but has no responses (yet).

I need to copy files from previous docker stage and from base folder of Dockerfile. This is my COPY

COPY if [ "$BASE_IMAGE" = "external" ] ; then COPY --from=BUILD $TMP_LOCATION/*.properties $DEPLOYMENT_LOCATION \
               ; COPY --from=BUILD $TMP_LOCATION/*.xml $DEPLOYMENT_LOCATION \
               ; COPY standalone.conf /opt/wildfly/bin ; fi

getting #6 0.410 /bin/sh: COPY: command not found . Please find my Dockerfile

#########
# BUILD #
#########

ARG BASE_IMAGE
FROM maven:3.6.3-jdk-11 AS BUILD
RUN mkdir /opt/trunk
RUN mkdir /opt/tmp
WORKDIR /opt/trunk
RUN --mount=target=/root/.m2,type=cache
RUN --mount=source=.,target=/opt/trunk,type=bind,rw mvn clean package && cp -r /opt/trunk/out/app.ear /opt/tmp

##################
# Dependencies #
##################

FROM $BASE_IMAGE
ARG IMAGE_TYPE
ENV DEPLOYMENT_LOCATION /opt/wildfly/standalone/deployments/app.ear
ENV TMP_LOCATION /opt/tmp/app.ear

ARG BASE_IMAGE
			
COPY if [ "$BASE_IMAGE" = "external" ] ; then COPY --from=BUILD $TMP_LOCATION/*.properties $DEPLOYMENT_LOCATION \
			   ; COPY --from=BUILD $TMP_LOCATION/*.xml $DEPLOYMENT_LOCATION \
			   ; COPY standalone.conf /opt/wildfly/bin ; fi

May I ask where conditional operations in COPY instructions are addressed in the docs? I can not find anything like that in the COPY section of the Dockerfile referece…

The only instruction I am aware of that supports conditional operations is the RUN instruction.

1 Like

Hi Meyay, Yeah COPY instructions are not present in docs.
However, i tried with RUN also but it says #17 0.571 /bin/sh: COPY: command not found

RUN if [ "$BASE_IMAGE" = "external" ] ; then COPY --from=BUILD $TMP_LOCATION/*.properties $DEPLOYMENT_LOCATION \
               ; COPY --from=BUILD $TMP_LOCATION/*.xml $DEPLOYMENT_LOCATION \
               ; COPY standalone.conf /opt/wildfly/bin ; fi

Now this part is at least valid syntax. Note: since RUN executes in sh/bsah the condition operation is brought from sh/bash to the table, not from the RUN instruction itself!

This part is still invalid. You can not wrap other instructions in instructions.

What you want to do is simply not supported.

1 Like

What about this:
RUN if [ "$BASE_IMAGE" = "idit-external" ] ; COPY --from=BUILD $TMP_LOCATION/*.xml $DEPLOYMENT_LOCATION ; fi
If this work, i can make some repetition.
Or else please suggest any other wrokaround for this.

Replacing multiple occourences of the problem to a single occourance, doesn’t make it less of a problem… does it? :slight_smile:

1 Like

:slight_smile: Thanks for clarification.

By the way, this code is working:
RUN if [ "$BASE_IMAGE" = "external" ] ; then mkdir -p /opt/app.ear ; fi

Likewise, you could probably use Bash cp (as in RUN cp ...) to copy things around. But I doubt you’d know where the result of the temporary build image is stored on disk (to replace the part --from=BUILD with a Bash equivalent).

Yep. that’s what I ment with:

1 Like

Any suggestions for a workaround since it seems conditional COPY is not supported? I too am bumping up against this.

I ended up copying my entire Dockerfile in a subdirectory, deleting two lines for copies I didn’t want in that case, and calling that file in my Makefile - ugly! Please support conditional COPY!

1 Like

it deepends on what you are looking for. You could leverate buildkit syntax to “unlock” features, like Build Mounts and copy the files in a RUN instruction to the mount and copy them conditionaly back inside a shell if condition wrapped in a RUN instruction.

Or if it’s just about conditionaly using different paths, then its even simpler.
You can use conditional values for MY_SRC_PATH and DST_PATH to pass in values on each build. The conditional part has to happen outside the build:
docker build --build-arg MY_SRC_PATH=${src} --build-arg MY_DST_PATH=${dst} ...

Then in you Dockerfile use the passed-in values as args in your COPY instruction:

...
ARG MY_SRC_PATH
ARG MY_DST_PATH
COPY --from=extract ${MY_SRC_PATH} ${MY_DST_PATH}

Both solutions are probably not what you want. The ARG one can actualy be quite powerfull if used right. Though, there is no way to skip the COPY instruction conditionaly.

1 Like