Setup Jenkins with Docker

2 minute read

Jenkins is one of the most popular continuous integration solution, I use it both for work and personal project, it provides webUI interface, to save to configure it, I prefer using Configuration as Code.

Docker is great for service management, it avoids making my work envrironment a mess, for jenkins, I use docker image too, based on official image.

Preparation for Jenkins setup

Jenkins plugins

cat << EOF >> plugins.txt
authorize-project:latest
build-pipeline-plugin:latest
build-timeout:latest
configuration-as-code:latest
credentials
credentials-binding:latest
docker-plugin:latest
email-ext:latest
git:latest
github:latest
job-dsl:latest
mailer:latest
matrix-auth:latest
pam-auth:latest
pipeline-stage-view:latest
repo:latest
role-strategy:latest
timestamper:latest
workflow-aggregator:latest
workflow-cps:latest
workflow-job:latest
ws-cleanup:latest
EOF

Create Seed Job

cat << EOF >> seedjob.groovy
#!groovy

job('seed_job') {
  scm {
    git {
      remote {
        url('https://github.com/fudongbai/jenkins.git')
      }
      branch('master')
    }
  }
  steps {
    dsl {
      external('adduser.groovy')
    }
  }
}


// create an array with our two pipelines
pipelines = ["test-build", "pipeline2"]

// iterate through the array and call the create_pipeline method
pipelines.each { pipeline ->
    println "Creating pipeline ${pipeline}"
    create_pipeline(pipeline)
}

// a method that creates a basic pipeline with the given parameter name
def create_pipeline(String name) {
    pipelineJob(name) {
        definition {
            cps {
                sandbox(true)
                script("""
// this is an example declarative pipeline that says hello and goodbye
pipeline {
    agent any
    stages {
        stage("Hello") {
            steps {
                echo "Hello from pipeline ${name}"
            }
        }
        stage("Goodbye") {
            steps {
                echo "Goodbye from pipeline ${name}"
            }
        }
    }
}

""")
            }
        }
    }
}
EOF

Configuration as Code

cat << EOF >> casc.yml
jenkins:
  securityRealm:
    local:
      allowsSignup: false
      users:
       - id: ${JENKINS_ADMIN_ID}
         password: ${JENKINS_ADMIN_PASSWORD}
       - id: "dev"
         password: "dev"
  authorizationStrategy:
    globalMatrix:
      permissions:
        - "GROUP:Overall/Read:authenticated"
        - "USER:Overall/Administer:admin"
        - "USER:Job/Build:dev"
        - "USER:Job/Cancel:dev"
        - "USER:Job/Read:dev"
        - "USER:Job/Workspace:dev"
        - "USER:Run/Replay:dev"
        - "USER:Run/Update:dev"
security:
  queueItemAuthenticator:
    authenticators:
    - global:
        strategy: triggeringUsersAuthorizationStrategy
  scriptApproval:
    approvedScriptHashes:
      - 9c73fa61c4e96ec7148e209c14cf16c150f85f4e

unclassified:
  location:
    url: http://23.94.104.70:8080/

# specify the seedjob groovy script that will create the  pipelines for us
jobs:
    - file: /usr/local/seedjob.groovy
EOF

Generate Customized Docker Image

cat << EOF >> Dockerfile
FROM jenkins/jenkins:lts
ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false
ENV CASC_JENKINS_CONFIG /var/jenkins_home/casc.yml
COPY --chown=jenkins:jenkins plugins.txt /usr/share/jenkins/ref/plugins.txt
COPY --chown=jenkins:jenkins casc.yml /var/jenkins_home/casc.yml
COPY seedjob.groovy /usr/local/seedjob.groovy
ADD init.groovy.d /usr/share/jenkins/ref/init.groovy.d
RUN jenkins-plugin-cli -f /usr/share/jenkins/ref/plugins.txt
EOF

Build docker jenkins docker image with:

docker build -t jenkins:jcasc .

Run Jenkins Service

Now, all required jobs were done, it’s time to play with jenkins, issue below command to get Jenkins running:

docker run --name jenkins --rm -p 8080:8080 -p 50000:50000 \
     -v /var/run/docker.sock:/var/run/docker.sock \
     --env JENKINS_ADMIN_ID=admin \
     --env JENKINS_ADMIN_PASSWORD=123456 \
     jenkins:jcasc

Troubleshooting

Processing a permission assignment in the legacy format (without explicit TYPE prefix)

2022-10-15 22:56:46.981+0000 [id=28]	WARNING	o.j.p.m.AuthorizationContainer#add: Processing a permission assignment in the legacy format (without explicit TYPE prefix): Overall/Administer:admin

A: Add GROUP/USER' prefix in casc.yml

ERROR: script not yet approved for use

Processing DSL script adduser.groovy
ERROR: script not yet approved for use
Finished: FAILURE

A: For one script:

(printf "groovy:" && cat adduser.groovy) | shasum

For bunch of scripts:

$ find -maxdepth 1 -name "*.groovy" | sort | xargs -I {} sh -c 'HASH=`(printf "groovy:" && cat {}) | shasum | awk '"'"'{print $1}'"'"'`; echo - $HASH \# jobs-dsl/{}'

Setting AdminWhitelistRule no longer has any effect.

2022-10-16 00:08:46.926+0000 [id=29]	INFO	j.s.s2m.AdminWhitelistRule#setMasterKillSwitch: Setting AdminWhitelistRule no longer has any effect. See https://www.jenkins.io/redirect/AdminWhitelistRule to learn more.

A: See API Compatibility Remove the following from casc.yml

  remotingSecurity:
    enabled: true

References