Impossible to start a container service in jenkins pipeline via .inside?

1,739 views
Skip to first unread message

Roberto Fabrizi

unread,
May 30, 2018, 2:04:39 PM5/30/18
to Jenkins Users
Hello everyone, I have this very simple use case:

    my_container = docker.image("srrdr.it/isl-ds/${microserviceName}-prod:${my_build_number}")
    // do the following build steps inside a container started from the custom image above
    my_container
    .inside("-e \"SONARQUBE_HOST=${sonarqubeUrl}\"") {
     sh
    'sleep 20'
     sh
    'curl http://localhost:5000/keyserviceapi/api/v1/version >> ./output.txt'
     sh
    'grep OK output.txt'
    }

I didn't think that it'd be hard to do it, but apparently it's impossible.
If I have a dockerfile starting via CMD, like for example something along these lines:

  1. CMD ["./script.sh", "start"]

    1. then it gets replaced by the CMD that .inside() automatically adds, a cat:
    2.  docker run -t -d -u 0:0 -e SONARQUBE_HOST=http://srrdr.it:8091 -w /tmp/jenkins/workspace/isl-ds-keyserviceapi-pipeline-1 --volumes-from 0f5d48be8450a0eb5c324976ddb81483ef86edff20651dfb0d1350f7d065566c -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ********
      -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** srrdr.it/isl-ds/isl-ds-prod:1.0.0 cat

and therefore my service (npm start) doesn't start.
If I start my service via ENTRYPOINT, like this:

  1. CMD ["./script.sh", "start"]

then it also doesn't start, complaining that:


$ docker run -t -d -u 0:0 -e SONARQUBE_HOST=http://srrdr.it:8091 -w /tmp/jenkins/workspace/isl-ds-keyserviceapi-pipeline-1 --volumes-from 0f5d48be8450a0eb5c324976ddb81483ef86edff20651dfb0d1350f7d065566c -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** srrdr.it/isl-ds/isl-ds-prod:1.0.0 cat $ docker top 434266a0ba7ec69a960ec0ff3f544d1f771b3364f74b0763306a928b7ee87595 -eo pid,comm ERROR: The container started but didn't run the expected command. Please double check your ENTRYPOINT does execute the command passed as docker run argument, as required by official docker images (see https://github.com/docker-library/official-images#consistency for entrypoint consistency requirements). Alternatively you can force image entrypoint to be disabled by adding option `--entrypoint=''`.



I'm quite lost about this, apparently there is no way to start a service with .inside().

Can anyone enlighten me?
Thank you as always,
Roberto

nicolas de loof

unread,
May 30, 2018, 5:07:25 PM5/30/18
to jenkins...@googlegroups.com
ENTRYPOINT script can be used to setup some background service but has to end with some "exec $@" so that the command passed as argument is actually executed
read the document linked by the error message for more details

--
You received this message because you are subscribed to the Google Groups "Jenkins Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-users/a21ef152-9500-4ce1-98c6-fe00124c3b8a%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Roberto Fabrizi

unread,
May 31, 2018, 3:42:13 AM5/31/18
to Jenkins Users
Thanks for the reply Nicolas. This is my ENTRYPOINT script:

    #!/usr/bin/env sh
    # $0 is a script name,
    # $1, $2, $3 etc are passed arguments
    # $1 is our command
    CMD
    =$1
     
    case "$CMD" in
     
    "dev" )
     npm install
     
    export NODE_ENV=development
     
    exec npm run dev
     
    ;;
     
     
    "start" )
     
    # we can modify files here, using ENV variables passed in
     
    # "docker create" command. It can't be done during build process.
     echo
    "db: $DATABASE_ADDRESS" >> /app/config.yml
     
    export NODE_ENV=production
     
    exec npm start
     
    ;;
     
     
    * )
     
    # Run custom command. Thanks to this line we can still use
     
    # "docker run our_image /bin/bash" and it will work
     
    exec $CMD ${@:2}
     
    ;;
    esac

It does exactly what it's required to do. My ENTRYPOINT calls this script and passes "start" as the first input parameter. Jenkins passes cat as a second input parameter, but that is ignored by my launch script if the first parameter is "start", as it should since npm start cat is not a valid command. If my image is fired by <image_name> /bin/bash, it works because it goes into the default case and does exec $@.

I really don't see why this is not a correct way to handle ENTRYPOINT....
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-use...@googlegroups.com.

nicolas de loof

unread,
May 31, 2018, 4:45:00 AM5/31/18
to jenkins...@googlegroups.com
The question is not if this is a valid way to handle Entrypoints, but the requirements for docker.inside : we need to control the  process being ran in container so it stays in some "hung" state (so the cat command).

Rewrite your script so default is to run "npm start" in background then exec $@, and declare ENTRYPOINT script.sh without argument



To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-users/f195d930-62a6-48c2-aef0-796985a533e6%40googlegroups.com.

Roberto Fabrizi

unread,
May 31, 2018, 5:37:29 AM5/31/18
to Jenkins Users
My knowledge of this is surely not that great, but from my understanding and previous Docker experiences completely unrelated to Docker Pipeline, if I do this:

Rewrite your script so default is to run "npm start" in background then exec $@, and declare ENTRYPOINT script.sh without argument


then what happens when the image is run outside of Jenkins / Pipeline by using this command:

docker run -d <image>


If npm start is fired in background and nothing is passed to the image, therefore there is nothing to exec from the command line, won't the container stop right away?

nicolas de loof

unread,
May 31, 2018, 6:54:48 AM5/31/18
to jenkins...@googlegroups.com
Yes indeed, it's not that simple to create an image which supports both use cases.

You also can check in your script if there's more than just one arg in CMD and then run npm start in background the exec 

Roberto Fabrizi

unread,
May 31, 2018, 8:13:41 AM5/31/18
to Jenkins Users
Makes sense, although going for that route seems a bit at the opposite spectrum of the requirement linked in the error description, where it speaks of a consistent interface.

For everyone else interested, we've decided that having a launch script that has a certain login basically just because .inside() fires the container passing "cat" was not a good idea, so we've currently opted to replace inside() with withRun(), that doesn't happen to pass cat or complain about anything. 

The difference is that shell commands within withRun() are not executed inside the container, so in my example the curl localhost:<container_port> had to be slightly modified so that withRun() exposes the container port to the host, and then the curl can be done against localhost:<host_port>.

Roberto Fabrizi

unread,
May 31, 2018, 8:16:49 AM5/31/18
to Jenkins Users
To be more clear, we still use .inside() if we use a container as a build environment inside which we do mvn or similar commands, but we've moved to the withRun approach if we are in a test scenario where a "service" is started via ENTRYPOINT.

nicolas de loof

unread,
May 31, 2018, 8:22:26 AM5/31/18
to jenkins...@googlegroups.com
"inside" should indeed only be used when container is used to define build environment (i.e provide some tools), if you use a container to provide a service your build rely on (database, webserver, etc) just run a plain container. 

2018-05-31 14:16 GMT+02:00 Roberto Fabrizi <r.fab...@gmail.com>:
To be more clear, we still use .inside() if we use a container as a build environment inside which we do mvn or similar commands, but we've moved to the withRun approach if we are in a test scenario where a "service" is started via ENTRYPOINT.

--
You received this message because you are subscribed to the Google Groups "Jenkins Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-users/ce0a8193-581f-4d25-a965-963ea8a8175c%40googlegroups.com.

Roberto Fabrizi

unread,
May 31, 2018, 8:27:41 AM5/31/18
to Jenkins Users
Definitely agree, our scenario wasn't so much of a complex mesh of services tho, but rather the fact that testing the service from inside the container (hence the localhost:container_port test that we wanted to ran directly inside the container itself) would make it possible for us to avoid a few caveats that withRun poses, like binding container->host ports, which can be somewhat of a pain if the jenkins server is "multi tenant".

Anyways, you definitely cleared up so many things for us, so we thank you a lot for your time and help Nicolas!

nicolas de loof

unread,
May 31, 2018, 8:31:07 AM5/31/18
to jenkins...@googlegroups.com
Your welcome

about host port binding issue, I suggest you run your "npm start" container with -P so a random port is allocated, then use docker port to collect the allocated port number and use it in your further steps.

2018-05-31 14:27 GMT+02:00 Roberto Fabrizi <r.fab...@gmail.com>:
Definitely agree, our scenario wasn't so much of a complex mesh of services tho, but rather the fact that testing the service from inside the container (hence the localhost:container_port test that we wanted to ran directly inside the container itself) would make it possible for us to avoid a few caveats that withRun poses, like binding container->host ports, which can be somewhat of a pain if the jenkins server is "multi tenant".

Anyways, you definitely cleared up so many things for us, so we thank you a lot for your time and help Nicolas!

--
You received this message because you are subscribed to the Google Groups "Jenkins Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscribe@googlegroups.com.

Roberto Fabrizi

unread,
May 31, 2018, 8:47:32 AM5/31/18
to Jenkins Users
Excellent suggestion, we'll definitely implement that!

nicolas de loof

unread,
May 31, 2018, 8:54:07 AM5/31/18
to jenkins...@googlegroups.com
this can easily be implemented in pipeline DSL : the Container instance returned by docker-workflow-plugin when you run a container do offer a port(int) method for this exact purpose
(or you can just write some shell script for portability)





--
You received this message because you are subscribed to the Google Groups "Jenkins Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages