Fixed: have `docker-compose build` fail when a RUN fails (it was, the shell script running it wasn't)

Admission: I do embedded C, not Docker, please be gentle with me :-).

We have a build/test system (for embedded FW), the “meat” of which runs inside an [Ubuntu] docker container [on Centos8 and Raspbian hosts]. The Dockerfile and docker-compose.yml file can be found here.

The Docker image needs to be re-built every so often (when we update some tool or other that is used by the embedded system under test); this is done through a Jenkins script (which is pretty much sudo -E /usr/local/bin/docker-compose build, issued in the directory linked above).

The issue I am having is that, should any of the RUN steps in the Dockerfile fail, the return code that ends up in Jenkins is still 0, requiring me to stare at the build log to confirm that the docker-compose build did actually work.

How can I make a failure of a RUN step in the Dockerfile propagate a non-zero error code to Jenkins?

It looks like you are using Docker Compose v1, at least based on the filename. I don’t know how that handled exit codes, but v1 is not supported anymore, so yoou should use v2.

It is also in the installation instruction of Docker CE

It is also important to know that the exit code in the RUN instructions must be a non-zero code. If you write multiple commands separated by “;” without making sure that all errors stops the execution and don’t let the next command to run, the exit code could be zero.

Oh, OK. A bit scary to up an entire major version: I hope none of the syntax has changed…?

The build does appear to exit when a RUN line fails. Here’s an example of a fail case; I’ve modified the very first RUN step in Dockerfile to try to download and install the package xxx, so that it fails:

# Include package xxx in the apt-get to cause a failure
RUN if [ "$(arch)" != "aarch64" ]; then                                \
        apt-get update && apt-get install --no-install-recommends -y \
            gcc-multilib g++-multilib xxx;                               \
    fi

With this, the end of the logged output from the docker-compose build is as follows:

Fetched 29.6 MB in 3s (10.9 MB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
Unable to locate package xxx
The command '/bin/bash -o pipefail -c if [ "$(arch)" != "aarch64" ]; then                                        apt-get update && apt-get install --no-install-recommends -y             gcc-multilib g++-multilib xxx;                                   fi' returned a non-zero code: 100
Service 'ubxlib_builder' failed to build : Build failed
Finished: SUCCESS

So the RUN stage has seen a non-zero error code but, at the end, Jenkins see’s a zero error code.

Here is the complete Jenkins shell script:

#!/bin/sh
echo Updating ubxlib Docker image on this agent.
echo Branch will be $UBXLIB_PRIV_REV, folder where the Docker files are found is assumed to be \"$WORKSPACE/ubxlib/$UBXLIB_DOCKER_FOLDER\".
cd $WORKSPACE/ubxlib/$UBXLIB_DOCKER_FOLDER
pwd
sudo -E /usr/local/bin/docker-compose build
if [ $? ]; then
    if [ -d /home/"$USER"/.docker ]; then
        sudo chown "$USER":"$USER" /home/"$USER"/.docker -R
        sudo chmod g+rwx "/home/$USER/.docker" -R
    fi
fi

Could the problem be with propagating the exit code in the shell script rather than docker-compose build?

Aha, yes, it must be the shell script, nothing to do with docker-compose build: if I add set -e to the shell script then Jenkins does get a non-zero error code on a failure.

Not a docker-compose issue after all, sorry for bothering, and thanks for the tip about V2.

The run instruction seems right, so you probably need to update compose, but this doesn’t seem right:

Since the exit code is number, you should check it this way:

if [ "$?" != "0" ]; then

Otherwise it will be always true regardless of the error code.

update:

I wrote my answer slowly and didn’t notice the last line in yours, but it is good to “hear” you solved it.

1 Like