I have a Gitlab CI job that is failing, depite last command returning 0. The run of a minimal script (just doing ps -a
and echo $?
) logs as follows:
$ 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
I narrowed the issue down to Docker image used - the same job run on the same runner but with another image succeeds as expected.
Here's the Dockerfile (of the problematic image):
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
Any idea what might be wrong, or how to debug this further? Running on local runner with --debug
doesn't provide any more insight unfortunately.
You should delete your Dockerfile's ENTRYPOINT
line.
You currently have
ENTRYPOINT exec /bin/bash -l
Note that this is a shell-form command (there is no JSON-array syntax), so Docker automatically wraps it in /bin/sh -c
. This is especially problematic, since the CMD
is passed as arguments to the entrypoint, but sh -c
generally ignores its arguments. If your automation runs for example
docker run --rm your-image ls /app
then the main container command becomes
/bin/sh -c 'exec /bin/bash -l' ls /app
and the arguments after the sh -c
string are visible as positional arguments $0
and $1
inside the string, but they're not executed themselves, unless your ENTRYPOINT
value takes care to use it.
It sounds like you might be trying to build a collection of tools, in a way that could be used by some other entity (say, as a Jenkins builder container) without having a specific single application packaged in it. In this case, you can leave out ENTRYPOINT
and CMD
entirely; you'll inherit these settings from the base image (which often will still default to running a shell) and expect whatever entity runs the container to provide its own command.
More generally, I'd suggest that, if you do include ENTRYPOINT
, it always should use JSON-array syntax, lest you lose any caller-provided command. I tend to prefer putting the actual command the container is going to run in Dockerfile CMD
, and if you do include ENTRYPOINT
, make it be a shell script that ends in exec "$@"
to run whatever command the container is given.