dockergitlabdockerfilegitlab-ci-runner

Gitlab CI job failing despite return 0 - faulty Docker image


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.


Solution

  • 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.