【发布时间】:2020-03-07 18:42:01
【问题描述】:
我有两个 Docker 容器:
- b-db - 包含我的数据库
- 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、here 和here 的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.yml 中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" ]
以下是我的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