Код завершения Docker-compose кажется нулевым, когда он должен быть ненулевым - PullRequest
1 голос
/ 12 ноября 2019

У меня есть два контейнера Docker:

  1. b-db - содержит мою базу данных
  2. b-комбинированный - содержит мой вебприложение и тесты, которые запускаются после запуска контейнера.

Я использую файл docker-compose.yml для запуска обоих контейнеров.

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:

Яиспользуя Jenkins для запуска моих контейнеров и запуска тестов с помощью следующей команды. Я использую --exit-code-from, как указано в SO сообщениях от здесь , здесь и здесь .

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

Ниже приводится то, что мойJenkinsfile выглядит следующим образом.

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

Когда мои тесты запускаются, кажется, что b-комбинированный завершается, как и ожидалось, с ненулевым кодом ошибки, который отображается на консоли, как показано ниже. Это вызывает отключение обоих контейнеров, что также является ожидаемым поведением.

b-комбинированный, выход с кодом 2

Остановка b-комбинированного ...

Остановка b-db ...

Остановка b-db ... выполнено Отмена при выходе из контейнера ...

Почему Дженкинс все еще показывает, что тесты пройдены(см. скриншот ниже)? Разве Дженкинсу не удалось после ненулевого выхода из команды docker-compose up --build --exit-code-from combined?

enter image description here

Кроме того, когда явыполнить следующее сразу же после того, как я локально запустил вышеупомянутую команду docker-compose в моей командной строке (не в Jenkins), я получаю код ошибки 0, который подтверждает, что проблема не в Jenkins, а скорее в том, что docker-compose не распознает, что яЯ завершаю работу init.sh с ненулевым кодом выхода.

$ echo $?
0

Согласно приведенному ниже предложению @LinPy, я выполнил следующую команду локально на своей машине и в Jenkins.

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

Вывод, который я получил, выглядит следующим образом. Последняя строка представляет собой вывод echo $?, который показывает, что скрипт по-прежнему завершается с кодом ошибки 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

Ниже приведен снимок экрана Jenkins после выполнения вышеуказанной команды:

enter image description here

Чтобы помочь с отладкой, ниже приведен Dockerfile для службы combined в 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" ]

Ниже приводится то, чтов моем файле init.sh.

#!/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"

Ниже приведен файл Docker для моей службы db. Все, что он делает, это копирует некоторые локальные данные в контейнер Docker и затем инициализирует базу данных с этими данными.

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

Ниже приведено то, что находится в mongo_restore.sh.

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

Следуя обновленному решению @LinPy, я попытался выполнить следующие шаги.

Ниже показано, как выглядит мой новый combined Dockerfile:

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)"]

Ниже показан мой новый init.sh файл.

#!/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"

Наконец, я выполнил следующую команду:

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

Вывод выглядит следующим образом- последняя строка (из вывода echo $?) имеет код выхода 0.

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

РЕШЕНИЕ:

Я использовал более старую версию docker-compose(до v1.23.0). Как вы можете видеть в заметках о выпуске docker-compose, было несколько исправлений ошибок вокруг --exit-code-from начиная с v1.23.0.

Ответы [ 2 ]

1 голос
/ 13 ноября 2019

Как уже упоминалось в комментариях, я не смог воспроизвести вашу проблему с помощью простого файла композиции. Если в следующем примере по-прежнему отображается код выхода 0, проблема, вероятно, связана с вашей установкой docker-compose. И если это сработает, то проблема будет в том, что ваш контейнер фактически не завершает работу с правильным кодом выхода. Вы также должны запустить docker container ls -a, чтобы увидеть вышедшие контейнеры и их коды выхода, и docker logs в остановленных контейнерах, чтобы проверить вывод. Вот мой рабочий пример:

$ 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
1 голос
/ 12 ноября 2019

Я думаю, что ваша команда должна быть:

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

, таким образом, вы получите код выхода из combined

, поскольку служба combined зависит от db, которыйтакже запустит службу БД.

Я думаю, что код выхода всегда 0, потому что --exit-code-from подразумевает --abort-on-container-exit, а db вернет 0 при выходе

--abort-on-container-exit  Stops all containers if any container was
                           stopped. Incompatible with -d. ...
--exit-code-from SERVICE   Return the exit code of the selected service
                           container. Implies --abort-on-container-exit.

update

попробуйте добавить это в ваш скрипт, заменив последнюю строку:

#!/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"
echo "$test_exit_code" > /scripts/exit_code
exec "$@"

, затем добавьте CMD к вашемуDockerfile:

CMD ["sh", "-c",  "exit $(cat /scripts/exit_code)"]

RUN it

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