我有一个 Gitlab CI 作业失败,尽管最后一个命令返回 0。最小脚本的运行(仅执行
ps -a
和 echo $?
)日志如下:
$ ps -A
PID TTY TIME CMD
1 ? 00:00:00 bash
9 ? 00:00:00 bash
19 ? 00:00:00 ps
$ echo $?
0
Cleaning up file based variables 00:01
ERROR: Job failed: exit code 1
我将问题范围缩小到使用的 Docker 映像 - 同一个作业在同一个运行器上运行,但使用另一个映像按预期成功。
这是(有问题的图像的)Dockerfile:
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -qq -y \
locales sudo python3 \
python3-pip python3-pexpect python3-git python3-jinja2 python3-subunit \
binutils build-essential bzip2 chrpath cpio cpp curl debianutils diffstat \
file g++ gawk gcc git iputils-ping libacl1 libgnutls28-dev liblz4-tool \
libtinfo5 make patch socat unzip wget xz-utils zstd zip
RUN locale-gen "en_US.UTF-8" && update-locale LANG=en_US.UTF-8
RUN useradd -m bb && \
usermod -aG sudo bb && \
mkdir -p /home/bb && \
chown -R bb:bb /home/bb && \
usermod --shell /bin/bash bb && \
echo "bb ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/no_password
ENTRYPOINT exec /bin/bash -l
WORKDIR /home/bb
USER bb
知道可能出了什么问题,或者如何进一步调试吗?不幸的是,使用
--debug
在本地运行器上运行并不能提供更多的见解。
您应该删除 Dockerfile 的
ENTRYPOINT
行。
您目前拥有
ENTRYPOINT exec /bin/bash -l
请注意,这是一个 shell 形式的命令(没有 JSON 数组语法),因此 Docker 自动将其包装在
/bin/sh -c
中。 这是特别有问题的,因为 CMD
作为参数传递给入口点,但 sh -c
通常会忽略它的参数。 例如,如果您的自动化运行
docker run --rm your-image ls /app
那么主容器命令就变成了
/bin/sh -c 'exec /bin/bash -l' ls /app
以及
sh -c
字符串后面的参数在字符串内作为位置参数 $0
和 $1
可见,但它们不会自行执行,除非您的 ENTRYPOINT
值小心使用它。
听起来您可能正在尝试构建一组工具,以某种其他实体可以使用的方式(例如,作为 Jenkins 构建器容器),而无需在其中打包特定的单个应用程序。 在这种情况下,您可以完全省略
ENTRYPOINT
和 CMD
;您将从基本映像继承这些设置(通常仍默认运行 shell),并期望运行容器的任何实体提供自己的命令。
更一般地说,我建议,如果您确实包含
ENTRYPOINT
,则它 always 应使用 JSON 数组语法,以免丢失任何调用者提供的命令。 我倾向于将容器将要运行的实际命令放在 Dockerfile CMD
中,如果您确实包含 ENTRYPOINT
,请使其成为以 exec "$@"
结尾的 shell 脚本,以运行容器给出的任何命令。