I have two Docker containers:
- b-db - contains my database
- 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?
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:
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.