Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jenkins 2.0: Running SBT in a docker container

I have the following Jenkinsfile:

def notifySlack = { String color, String message ->
    slackSend(color: color, message: "${message}: Job ${env.JOB_NAME} [${env.BUILD_NUMBER}] (${env.BUILD_URL})")
}

node {
    try {
        notifySlack('#FFFF00', 'STARTED')
        stage('Checkout project') {
            checkout scm
        }
        scalaImage = docker.image('<myNexus>/centos-sbt:2.11.8')
        stage('Test project') {
            docker.withRegistry('<myNexus>', 'jenkins-nexus') {
                scalaImage.inside('-v /var/lib/jenkins/.ivy2:/root/.ivy2') { c ->
                    sh 'sbt clean test'
                }
            }
        }
        if (env.BRANCH_NAME == 'master') {
            stage('Release new version') {
                docker.withRegistry('<myNexus>', 'jenkins-nexus') {
                    scalaImage.inside('-v /var/lib/jenkins/.ivy2:/root/.ivy2') { c ->
                        sh 'sbt release'
                    }
                }
            }
        }
        notifySlack('#00FF00', 'SUCCESSFUL')
    } catch (e) {
        currentBuild.result = "FAILED"
        notifySlack('#FF0000', 'FAILED')
        throw e
    }

}

Unfortunately when I reach the sbt clean test line I end up with the following error:

java.lang.IllegalArgumentException: URI has a query component
    at java.io.File.<init>(File.java:427)
    at sbt.IO$.uriToFile(IO.scala:160)
    at sbt.IO$.toFile(IO.scala:135)
    at sbt.Classpaths$.sbt$Classpaths$$bootRepository(Defaults.scala:1942)
    at sbt.Classpaths$$anonfun$appRepositories$1.apply(Defaults.scala:1912)
    at sbt.Classpaths$$anonfun$appRepositories$1.apply(Defaults.scala:1912)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
    at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
    at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:34)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
    at scala.collection.AbstractTraversable.map(Traversable.scala:105)
    at sbt.Classpaths$.appRepositories(Defaults.scala:1912)
    at sbt.Classpaths$$anonfun$58.apply(Defaults.scala:1193)
    at sbt.Classpaths$$anonfun$58.apply(Defaults.scala:1190)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
    at sbt.EvaluateSettings$MixedNode.evaluate0(INode.scala:175)
    at sbt.EvaluateSettings$INode.evaluate(INode.scala:135)
    at sbt.EvaluateSettings$$anonfun$sbt$EvaluateSettings$$submitEvaluate$1.apply$mcV$sp(INode.scala:69)
    at sbt.EvaluateSettings.sbt$EvaluateSettings$$run0(INode.scala:78)
    at sbt.EvaluateSettings$$anon$3.run(INode.scala:74)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

If I run the simple docker run ... followed by docker exec I get what I want but I would like to work with the defined Jenkins functionality.

So this seems to be an SBT issue. I use version 0.13.16 inside the docker image. From what I understand the classpath contains a query parameter that SBT:

  • doesn't like
  • doesn't know how to handle
  • is illegal

I put no such query parameters myself so I thought that this .inside method does that. I checked the env in the container and found a single entry RUN_CHANGES_DISPLAY_URL=<my_ip>/job/scheduler/job/fix-jenkins-pipeline/23/display/redirect?page=changes. I tried to unset it but didn't manage to.

I'm out of ideas and am not really sure I'm in the right direction. Any help would be appreciated.

like image 486
zaxme Avatar asked Nov 16 '17 10:11

zaxme


People also ask

Can Jenkins run Docker container?

Just use a pre-configured Docker container and your Jenkins builds get access to all of those resources, without the headache of managing and maintaining all of that peripheral software.

What are the advantages of running Jenkins in a Docker container?

For Jenkins usage, it's faster and easier to deploy/install in the docker way. Maybe you don't need the scale more easily feature right now. And since the docker is quite lightweight, so you can run more workloads.

Can we use Docker container as a node in Jenkinsfile?

Docker plugin for Jenkins The aim of this docker plugin is to be able to use a Docker host to dynamically provision a docker container as a Jenkins agent node, let that run a single build, then tear-down that node, without the build process (or Jenkins job definition) requiring any awareness of docker.


2 Answers

I spent a lot of time tracing this down through the code.

It looks like the easiest solution is to just pass -Duser.home=<path> to sbt, or to set it in the SBT_OPTS environment variable; then all the rest of the directories will be built as if the <path> is the user's home directory.

like image 79
Loki Avatar answered Oct 26 '22 23:10

Loki


So after long and tedious searches what finally worked for me is setting explicitly the .sbt and .ivy2 folder like this inside the docker container:

sbt -Dsbt.global.base=.sbt -Dsbt.boot.directory=.sbt -Dsbt.ivy.home=.ivy2 clean test

That somehow prevents sbt from generating the ? folder and directly puts the aforementioned folders in the root of the directory checkout.

like image 42
zaxme Avatar answered Oct 27 '22 00:10

zaxme