【问题标题】:Docker-compose exit code appears to be zero when it should be non-zeroDocker-compose 退出代码应为非零时似乎为零
【发布时间】:2020-03-07 18:42:01
【问题描述】:

我有两个 Docker 容器:

  1. b-db - 包含我的数据库
  2. b-combined - 包含我的 Web 应用程序和在容器启动并运行后运行的测试。

我正在使用 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,正如hereherehere 的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-combined 似乎按预期退出并带有非零错误代码,该代码显示在控制台中,如下所示。这会触发两个容器关闭,这也是预期的行为。

b-combined 以代码 2 退出

停止 b-combined ...

正在停止 b-db ...

正在停止 b-db ...完成 容器退出时中止...

为什么 Jenkins 仍然显示测试已通过(见下面的截图)?在docker-compose up --build --exit-code-from combined 命令非零退出后,Jenkins 不应该失败吗?

此外,当我在本地(不在 Jenkins 中)在命令行中运行上述 docker-compose 命令后立即运行以下命令时,我收到错误代码 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截图:

为了帮助调试,下面是docker-compose.ymlcombined 服务的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" ]

以下是我的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"

下面是我的db 服务的 Dockerfile。它所做的只是将一些本地数据复制到 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(pre v1.23.0)。正如您在 docker-compose 的 release notes 中看到的那样,自 v1.23.0 以来,围绕 --exit-code-from 已经修复了几个错误。

【问题讨论】:

  • 您能否将问题隔离为特定错误,而不是要求我们一起调试 Jenkins、docker、docker-compose 和您的脚本?如果您的詹金斯脚本只是“退出 2”,那会失败吗?如果您在本地运行 docker-compose,是否会给出预期的返回码?如果您在没有 compose 的 docker 容器中运行命令,它们会按预期工作吗?
  • 无论我在 Jenkins 中还是在本地运行 docker-compose 命令,都会出现零退出代码,正如我在问题中所阐明的那样。在我看来,以非零退出代码退出我的 init.sh 脚本不会导致 docker-compose 命令以非零退出代码退出。正如您可能从 @LinPy 的解决方案中观察到的那样,我们还尝试使用非零退出代码而不是从 init.sh 退出 combined 的 Dockerfile,但问题仍然存在。
  • 回答您的子问题,如果 Jenkins 脚本只是“退出 2”,它确实会失败(因此问题不在于 Jenkins 识别退出代码)。如果我的init.sh 脚本仅包含“exit 2”而没有其他内容,则 docker-compose 命令仍会以 0 退出代码退出。如果我只运行combined 服务(换句话说,从docker-compose.yml 中删除db 服务),我仍然会以0 退出代码退出。
  • 我只使用 docker-compose 和一个简单的 yml 文件在本地重新创建您的问题没有成功。您正在运行什么版本的 docker-compose,您是否尝试过更新到最新版本的 not on the latest stable?

标签: docker jenkins testing docker-compose continuous-integration


【解决方案1】:

正如 cmets 中所述,我无法使用简单的 compose 文件重现您的问题。如果以下示例仍然为您提供退出代码 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

【讨论】:

  • 是的,我相信这可能与 docker-compose 的版本有关。我已经更新了我的 docker-compose 及其吐出错误代码,但是当测试同时成功完成时,我遇到了另一个 docker-compose 吐出 137 个错误代码的问题。一旦我有更多时间来调试实际发生的事情,我会回复...感谢您的所有帮助!
  • 再次感谢您与我分享那篇文章。它对调试有很大帮助,但我仍然无法确定为什么我不断收到 137 错误代码。我已经在此处单独发布了一个关于问题here 的 SO 帖子,所以如果您有时间,如果您能帮我看看,我将不胜感激 :) 再次感谢您帮助我解决此问题。
【解决方案2】:

我认为你的命令应该是:

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

这样你会得到combined的退出码

因为combined 服务依赖于db,它也将启动 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.

更新

尝试将此添加到您的脚本中,替换最后一行:

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

运行它

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

【讨论】:

  • 感谢您的回答!试一试,不幸的是它似乎没有完成这项工作:(错误代码仍然是 0,詹金斯仍然认为一切正常。我认为你可能是正确的关于 db 与退出代码混淆......嗯
  • 感谢更新的解决方案。我也试了一下,但它仍然有一个零退出代码。我实际上已经更新了我的问题,详细说明了我为尝试更新的解决方案和收到的输出所采取的步骤。我还添加了有关我的 Dockerfile 和初始化脚本的更多详细信息。希望这可以帮助您发现导致这种情况的原因......我自己似乎无法发现任何东西,因为我对 Docker 很陌生 :(
  • 是的,没错。刚刚在我的机器上本地尝试过,我仍然收到 0 错误代码。如果对我使用 Docker 版本 18.09.1 有帮助,请构建 4c52b90。据我所知,这应该不是问题
  • 非常感谢您更新您的解决方案!我对您建议的代码行的定位有点不清楚。我已经更新了我的问题,以显示我尝试合并您的更改;但是,您能否确认我是否已将新行放置在正确的位置?如果没有,请随时告诉我应该在哪里添加代码。您还可以确认您使用docker-compose up -d --build db && docker-compose up --build combined || exit 2 在您的机器上进行了测试吗?非常感谢你对我这么有耐心。
  • 完全按照您的说明进行操作,但我仍然得到零退出代码 :( 除了您建议的命令之外,我还尝试了一堆其他命令,但那些也没有用。我是会为您的解决方案投票,因为对其他人来说有很多有用的信息,但不幸的是,我仍然坚持使用 docker-compose 命令退出,退出代码为 0 ......真令人沮丧!我现在所处的位置真的很晚了所以现在无法尝试其他任何东西,但是如果您想到什么我会在明天早上尝试。感谢您的所有帮助!
猜你喜欢
  • 2019-12-21
  • 2020-10-28
  • 2015-07-02
  • 2019-02-28
  • 2021-08-23
  • 2019-12-03
  • 2021-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多