Docker-compose 退出代码应该为非零时似乎为零

标签 docker jenkins testing docker-compose continuous-integration

我有两个 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 正如来自 here 的 SO 帖子所概述的那样, herehere .

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 exited with code 2

Stopping b-combined ...

Stopping b-db ...

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

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

enter image description here

此外,当我在本地命令行中(不是在 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的截图:

enter image description here

为了帮助调试,下面是 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 更新的解决方案,我尝试了以下步骤。

下面是我的 组合 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 之前)。正如您在 release notes 中看到的那样在 docker-compose 中,自 v1.23.0 以来,围绕 --exit-code-from 修复了多个错误。

最佳答案

如评论中所述,我无法使用简单的撰写文件重现您的问题。如果以下示例仍然为您提供退出代码 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 退出代码应该为非零时似乎为零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58812179/

相关文章:

linux - docker for windows 相当于 "-v/var/run/docker.sock:/var/run/docker.sock"

maven - MVN : command not found

javascript - Node.js 测试后清理数据库

testing - 旧 C++Builder 版本上的 DUnit?

docker - 的区别是什么?和./在RUN中

docker - 为什么我无法为 docker 获取 go sdk ?

docker - 从服务器端(从另一个容器)和从客户端(浏览器)使用相同的 URL 引用 Docker 容器

java - 强制 Maven 使用内部和外部依赖 jar

jenkins - 在 Kubernetes 上的 Jenkins 中安装卷

objective-c - cocoa 应用程序 : How distribute beta versions?