user2448122
user2448122

Reputation: 345

How to keep the ENTRYPOINT but replace CMD of a docker image from a gitlab pipeline

I have the following Dockerfile:

FROM ubuntu:latest

# Prepare the operating system
RUN apt-get update && \
apt-get install --yes openjdk-11-jre

# Copy the CNES pluging
COPY ./src/sonar-cnes-report-4.1.3.jar /opt/cnes-report/sonar-cnes-report-4.1.3.jar

WORKDIR /opt/cnes-report

ENTRYPOINT [ "java", "-jar", "sonar-cnes-report-4.1.3.jar" ]
CMD [ "-h" ]

Running a container from this image works the way I want. For example: docker run <image> gives me the help:

user@server:~/workspace$ docker run 8215b6dcc57b
usage: java -jar cnesreport.jar [-a <arg>] [-b <arg>] [-c] [-d <arg>] [-e] [-f] [-h] [-l <arg>] [-m] [-n <arg>] [-o <arg>] [-p
       <arg>] [-r <arg>] [-s <arg>] [-t <arg>] [-v] [-w] [-x <arg>]
Generate editable reports for SonarQube projects.

 -a,--author <arg>                 Name of the report writer.
 -b,--branch <arg>                 Branch of the targeted project. Requires Developer Edition or
                                   sonarqube-community-branch-plugin. Default: usage of main branch.
 -c,--disable-conf                 Disable export of quality configuration used during analysis.
 -d,--date <arg>                   Date for the report. Format: yyyy-MM-dd. Default: current date.
 -e,--disable-spreadsheet          Disable spreadsheet generation.
 -f,--disable-csv                  Disable CSV generation
 -h,--help                         Display this message.
 -l,--language <arg>               Language of the report. Values: en_US, fr_FR. Default: en_US.
 -m,--disable-markdown             Disable Markdown generation
 -n,--template-markdown <arg>      Path to the report template in markdown. Default: usage of internal template.
 -o,--output <arg>                 Output path for exported resources.
 -p,--project <arg>                SonarQube key of the targeted project.
 -r,--template-report <arg>        Path to the report template. Default: usage of internal template.
 -s,--server <arg>                 Complete URL of the targeted SonarQube server.
 -t,--token <arg>                  SonarQube token of the SonarQube user who has permissions on the project.
 -v,--version                      Display current version.
 -w,--disable-report               Disable report generation.
 -x,--template-spreadsheet <arg>   Path to the spreadsheet template. Default: usage of internal template.


Please report issues at https://github.com/cnescatlab/sonar-cnes-report/issues

If I pass an extra parameter, that is nicely overwriting the CMD part of the images. For example: docker run 8215b6dcc57b -v gives me this:

user@server:~/workspace$ docker run 8215b6dcc57b -v
Current version: 4.1.3
user@server:~/workspace$

Or generating an actual report for a project is also works: docker run 8215b6dcc57b -t <mytoken> -s https://<sqserver> -f -m -p winformsapp2 -b develop

I want to use this image in a gitlab-ci file, and overwrite the CMD part of the image. I've tried this gitlab-ci.yml:

cnes:
  stage: report
  image: 
    name: "<mydockerregistry>/cnes-report-generator:v1.0.0"
  script:
    - -v

But this fails with the following error:

[ERROR] Please provide a project with the -p argument, you can also use -h argument to display help.

After some research I came across this post, so I gave it a try. I've modified my gitlab-ci.yml:

cnes:
  stage: report
  image: 
    name: "<mydockerregistry>/cnes-report-generator:v1.0.0"
    entrypoint: ["/bin/bash"]
  script:
    - java -jar sonar-cnes-report-4.1.3.jar -v

But this one error out with the following:

/usr/bin/sh: /usr/bin/sh: cannot execute binary file

So how can I make this work? Ideally I want the image to be usable on the command line and in the gitlab pipeline as well, but if I need to make a choice, the gitlab pipeline has the preference. Ideally the image/container already have the 'java -jar xyz.jar' command, so I only need to add the -t -s -p parameters within the gitlab-ci.yml file.

Upvotes: 6

Views: 5557

Answers (1)

sytech
sytech

Reputation: 41139

Why a custom ENTRYPOINT does not work in GitLab CI

The problem you're experiencing is that GitLab CI expects your image to have no entrypoint or an entrypoint equivalent to something like /bin/bash -c. Generally, you should not deviate from this when using docker images with GitLab CI.

Even if we wanted to abuse the ENTRYPOINT, the other disconnect is that script portions in your CI configuration are not actually passed as command arguments. GitLab passes its own command to your container to discover the appropriate shell binary, then uses that to consume the text from stdin, which is an eval command that gets passed to /bin/bash -c containing, in part, your before_script:/script: code.

If you want to see this in action, you can run this configuration:

# examples to expose inner-machinery of docker executor...

show-container-command:
  image:
    name: ubuntu
    entrypoint: ["/bin/bash", "-c", "echo $@"]
    # echo the command passed to the job container by the executor
  script:
    - echo does not matter -- will not appear in command

show-stdin-script:
  image:
    name: ubuntu
    entrypoint: ["/bin/bash", "-c", "while read line; do echo \"$line\"; done < /dev/stdin"]
    # this will show the crafted script the executor passes to stdin
    # warning: may expose secret env variables!
  script:  # script steps will appear in the command passed via stdin
    - echo "first line"
    - echo "second line"

The outputs of these jobs will help you understand what is actually happening with the GitLab CI docker executor (and demonstrate why you must not use your own entrypoint).


What you should do instead

All that to say: your entrypoint as it currently exists won't work with GitLab CI. Your best bet to use this image would be to override the entrypoint and write out the full command, e.g. java ... -v in your script:

cnes:
  stage: report
  image: 
    name: "<mydockerregistry>/cnes-report-generator:v1.0.0"
    entrypoint: [""]
  script:
    - java -jar /opt/cnes-report/sonar-cnes-report-4.1.3.jar -v

Making it easier to use

If you want to make this easier for users of this image, you can include a wrapper script in your image:

#!/usr/bin/env bash

# /usr/local/bin/generate-cnes-report

set -eou pipefail

exec java -jar /opt/cnes-report/sonar-cnes-report-4.1.3.jar "$@"

Then your dockerfile might do something like:

# ...
# copy the wrapper script to a location on PATH, ensuring executable bit is set
COPY --chmod=755 generate-cnes-report /usr/local/bin/generate-cnes-report
ENTRYPOINT ["generate-cnes-report"]
# ...

Then your GitLab CI could look like this:

cnes:
  stage: report
  image: 
    name: "<mydockerregistry>/cnes-report-generator:v1.0.0"
    entrypoint: [""]
  script:
    - generate-cnes-report -v

Upvotes: 8

Related Questions