Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Creating A Basic Jenkins Pipeline

This tutorial is tied to this template GitHub repository I created, for projects that require a Jenkins Pipeline.

Required Plugins

Steps

Create your repository, or clone the the template on GitHub I created.

Create one of each of the following files (you will see they already exist in the template repository):

  • Jenkinsfile
  • Dockerfile

Create branches for production and staging

git branch production && git push -u origin production
git branch staging && git push -u origin staging

Create a project access token and use that in the url for authentication before plugging into jenkins.

Fill the Jenkinsfile with the following content:

pipeline {
    agent none

    stages {
        stage("build") {
            agent {
                docker { image 'docker:dind' }
            }
            steps {
                echo "building docker image..."

                configFileProvider([configFile(fileId: 'fc6ad96f-c364-4b59-b24b-5eddee5b41f6', variable: 'BRANCH_SETTINGS')]) {
                    echo "Branch ${env.BRANCH_NAME}"
                    echo "Branch Settings: ${BRANCH_SETTINGS}"

                    script {
                        def config = readJSON file:"$BRANCH_SETTINGS"
                        def branchConfig = config."${env.BRANCH_NAME}"

                        if (branchConfig) {
                            echo "using config for branch ${env.BRANCH_NAME}"

                            def DOCKER_REGISTRY = branchConfig.DOCKER_REGISTRY
                            def dockerImage = docker.build(branchConfig.IMAGE_NAME)

                            docker.withRegistry("https://${branchConfig.DOCKER_REGISTRY}", 'docker-registry-credentials') {
                                dockerImage.push("${env.BUILD_NUMBER}")
                                dockerImage.push("latest")
                            }
                        }
                        else {
                            error("Build failed because failed to fetch settings for branch")
                        }
                    }
                }
            }
        }

        stage("deploy") {
            agent {
                docker { image 'ubuntu:focal' }
            }
            steps {
                sh "apt-get update && apt-get install ssh -y"

                configFileProvider([configFile(fileId: 'fc6ad96f-c364-4b59-b24b-5eddee5b41f6', variable: 'BRANCH_SETTINGS')]) {
                    echo "Branch ${env.BRANCH_NAME}"
                    echo "Branch Settings: ${BRANCH_SETTINGS}"

                    script {
                        def config = readJSON file:"$BRANCH_SETTINGS"

                        def branchConfig = config."${env.BRANCH_NAME}"

                        if (branchConfig) {
                            echo "using config for branch ${env.BRANCH_NAME}"

                            def SSH_USER = branchConfig.SSH_USER
                            def DOCKER_HOST = branchConfig.DOCKER_HOST
                            def DOCKER_REGISTRY = branchConfig.DOCKER_REGISTRY
                            def IMAGE_NAME = branchConfig.IMAGE_NAME

                            sshagent(credentials : ['master.pem']) {
                                withCredentials([usernamePassword(credentialsId: 'docker-registry-credentials', passwordVariable: 'DOCKER_REGISTRY_PASSWORD', usernameVariable: 'DOCKER_REGISTRY_USER')]) {
                                    sh 'ssh -o StrictHostKeyChecking=no ' + branchConfig.SSH_USER + '@' + branchConfig.DOCKER_HOST + ' "docker login -u ' + DOCKER_REGISTRY_USER + ' -p ' + DOCKER_REGISTRY_PASSWORD + ' ' + branchConfig.DOCKER_REGISTRY + '"'
                                    sh 'ssh -o StrictHostKeyChecking=no ' + branchConfig.SSH_USER + '@' + branchConfig.DOCKER_HOST + ' "docker pull ' + branchConfig.DOCKER_REGISTRY + '/' + IMAGE_NAME + ' && docker kill hello-world || true && docker rm hello-world || true && docker run -d --name hello-world -p80:80 ' + branchConfig.DOCKER_REGISTRY + '/' + branchConfig.IMAGE_NAME + '"'
                                }
                            }
                        }
                        else {
                            error("Build failed because failed to fetch settings for branch")
                        }
                    }
                }

            }
        }

    }
}

In your Jenkins Server, create a new multi-branch project for this codebase.

Branch Settings Config File

Create a config file in that project with the name: my-config-file.json, or use an alternative name, and update the Jenkinsfile in this codebase accordingly.

That config file should have the following contents (a block per environment branch).

{
    "staging": {
        "DOCKER_HOST": "my.staging-server.com",
        "IMAGE_NAME": "my-docker-image",
        "DOCKER_REGISTRY": "docker-registry.mydomain.com",
        "SSH_USER": "programster"
    },
    "production": {
        "DOCKER_HOST": "my.production-server.com",
        "IMAGE_NAME": "my-docker-image",
        "DOCKER_REGISTRY": "docker-registry.mydomain.com",
        "SSH_USER": "programster"
    }
}

Create Credentials

Create a credential of type usernamePassword called "docker-registry-credentials" for which you provide the username and password to your docker registry.

Create a credential of type file called master.pem that contains the private SSH key that will allow logging into the remote server (DOCKER_HOST).

Configure Triggering From GitHub

Now we have a pipeline that will build and deploy our project, it would be ideal if this would get automatically triggered whenever a change was made. In order to do this, follow this post on how to Integrate Jenkins Multibranch Pipeline With Git / GitHub

Last updated: 29th June 2021
First published: 29th June 2021

This blog is created by Stuart Page

I'm a freelance web developer and technology consultant based in Surrey, UK, with over 10 years experience in web development, DevOps, Linux Administration, and IT solutions.

Need support with your infrastructure or web services?

Get in touch