Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docker-compose exit code appears to be zero when it should be non-zero

I have two Docker containers:

  1. b-db - contains my database
  2. b-combined - contains my web application and tests that run once the container is up and running.

I'm using a docker-compose.yml file to start both containers.

version: '3'
services:
    db:
        build:
            context: .
            dockerfile: ./docker/db/Dockerfile
        container_name: b-db
        restart: unless-stopped
        volumes:     
            - dbdata:/data/db
        ports:
            - "27017:27017"
        networks:
            - app-network

    combined:
        build:
            context: .
            dockerfile: ./docker/combined/Dockerfile
        container_name: b-combined
        restart: unless-stopped
        env_file: .env
        ports:
            - "5000:5000"
            - "8080:8080"
        networks:
            - app-network
        depends_on:
            - db

networks:
    app-network:
        driver: bridge

volumes:
    dbdata:
    node_modules:

I'm using Jenkins to launch my containers and start running tests using the following command. I'm using --exit-code-from as outlined by SO posts from here, here and here.

docker-compose up --build --exit-code-from combined

Below is what my Jenkinsfile looks like.

pipeline {
    agent any
    environment {
        CI = 'true'
    }
    stages {
        stage('Test') {
            steps {
                sh 'docker-compose up --build --exit-code-from combined'
            }
        }
    }
}

When my tests run it appears that b-combined exits as expected with a non-zero error code, which is displayed to the console as shown below. This triggers both containers to shutdown, which is also expected behaviour.

b-combined exited with code 2

Stopping b-combined ...

Stopping b-db ...

Stopping b-db ... done Aborting on container exit...

Why is it that Jenkins still displays the tests has having passed (see below screenshot)? Shouldn't Jenkins have failed following a non-zero exit of the docker-compose up --build --exit-code-from combined command?

enter image description here

Furthermore, when I run the following immediately after I run the above docker-compose command in my command line locally (not in Jenkins) I get an error code of 0, which confirms the problem does not lie with Jenkins but rather with docker-compose not recognising that I'm exiting init.sh with a non-zero exit code.

$ echo $?
0

As per the below suggestion from @LinPy, I ran the following command locally on my machine and in Jenkins.

docker-compose up -d --build db && docker-compose up --build combined || exit 2; echo $?

The output I received is as follows. The last line is the output of echo $?, which shows that the script still exits with error code of 0.

b-combined | Mongoose disconnected
b-combined | TEST ENDED WITH EXIT CODE OF: 2
b-combined | EXITING SCRIPT WITH EXIT CODE OF: 2
b-combined exited with code 2
0

Below is a screenshot of Jenkins after the above command is run:

enter image description here

To help with debugging, below is the Dockerfile for the combined service in docker-compose.yml.

RUN npm install

COPY . .

EXPOSE 5000

RUN npm install -g history-server nodemon

RUN npm run build-test

EXPOSE 8080

COPY ./docker/combined/init.sh /scripts/init.sh

RUN ["chmod", "+x", "/scripts/init.sh"]

ENTRYPOINT [ "/scripts/init.sh" ]

Below is what is in my init.sh file.

#!/bin/bash
# Start front end server
history-server dist -p 8080 &
front_pid=$!

# Start back end server that interacts with DB
nodemon -L server &
back_pid=$!

# Run tests
NODE_ENV=test $(npm bin)/cypress run --config video=false --browser chrome

# Error code of the test
test_exit_code=$?

echo "TEST ENDED WITH EXIT CODE OF: $test_exit_code"

# End front and backend server
kill -9 $front_pid
kill -9 $back_pid

# Exit with the error code of the test
echo "EXITING SCRIPT WITH EXIT CODE OF: $test_exit_code"
exit "$test_exit_code"

Below is the Dockerfile for my db service. All its doing is copying some local data into the Docker container and then initialising the database with this data.

FROM  mongo:3.6.14-xenial

COPY ./dump/ /tmp/dump/

COPY mongo_restore.sh /docker-entrypoint-initdb.d/

RUN chmod 777 /docker-entrypoint-initdb.d/mongo_restore.sh

Below is what is in mongo_restore.sh.

#!/bin/bash
# Creates db using copied data
mongorestore /tmp/dump

Following the updated solution from @LinPy, I tried the following steps.

Below is what my new combined Dockerfile looks like:

RUN npm install

COPY . .

EXPOSE 5000

RUN npm install -g history-server nodemon

RUN npm run build-test

EXPOSE 8080

COPY ./docker/combined/init.sh /scripts/init.sh

RUN ["chmod", "+x", "/scripts/init.sh"]

ENTRYPOINT [ "/scripts/init.sh" ]

# NEW LINE ADDED HERE
CMD ["sh", "-c",  "exit $(cat /scripts/exit_code)"]

Below is what my new init.sh file looks like.

#!/bin/bash
# Start front end server
history-server dist -p 8080 &
front_pid=$!

# Start back end server that interacts with DB
nodemon -L server &
back_pid=$!

# Run tests
NODE_ENV=test $(npm bin)/cypress run --config video=false --browser chrome

# Error code of the test
test_exit_code=$?

echo "TEST ENDED WITH EXIT CODE OF: $test_exit_code"

# End front and backend server
kill -9 $front_pid
kill -9 $back_pid

# NEW LINES ADDED HERE
echo "$test_exit_code" > /scripts/exit_code
exec "$@"

# Exit with the error code of the test
echo "EXITING SCRIPT WITH EXIT CODE OF: $test_exit_code"
exit "$test_exit_code"

Finally, I ran the following command:

docker-compose up -d --build db && docker-compose up --build combined || exit 2; echo $?

The output is as follows - last line (from output of echo $?) has exit code of 0.

b-combined | TEST ENDED WITH EXIT CODE OF: 2 ===========================
b-combined exited with code 2
0

SOLUTION:

I was using an older version of docker-compose (pre v1.23.0). As you can see in the release notes of docker-compose, there have been several bug fixes around --exit-code-from since v1.23.0.

like image 994
p4t Avatar asked Sep 17 '25 00:09

p4t


1 Answers

As mentioned in the comments, I've been unable to reproduce your issue with a simple compose file. If the following example still gives you exit code 0, then the issue is likely with your install of docker-compose. And if it works, then the issue will be with your container not actually exiting with the proper exit code. You should also run a docker container ls -a to see the exited containers and their exit codes, and docker logs on the stopped containers to verify the output. Here's my working example:

$ cat docker-compose.exit-code.yml
version: '3'

services:
  good:
    image: busybox
    command: /bin/sh -c "exit 0"

  bad:
    image: busybox
    command: /bin/sh -c "exit 42"

$ docker-compose -f docker-compose.exit-code.yml up --exit-code-from bad
Starting test_good_1_69c61ee0bdc6 ... done
Starting test_bad_1_fbe3194c1994  ... done
Attaching to test_bad_1_fbe3194c1994, test_good_1_69c61ee0bdc6
test_bad_1_fbe3194c1994 exited with code 42
Aborting on container exit...

$ echo $?
42

$ docker-compose -f docker-compose.exit-code.yml up --exit-code-from good
Starting test_good_1_69c61ee0bdc6 ... done
Starting test_bad_1_fbe3194c1994  ... done
Attaching to test_good_1_69c61ee0bdc6, test_bad_1_fbe3194c1994
test_good_1_69c61ee0bdc6 exited with code 0
Aborting on container exit...

$ echo $?
0
like image 80
BMitch Avatar answered Sep 18 '25 17:09

BMitch