Setup Jenkins worker node that support building Docker Image.
devops AWS cloud

Setup Jenkins worker node that support building Docker Image.

COPPER Nguyen

Usually when we setup a Jenkins server, we usually use the master to build jobs. The master node is in charge of scheduling jobs, assigning slave nodes, and sending builds to slave nodes for execution. It will also keep track of the slave node state (offline or online), retrieve build results from slave nodes, and display them on the terminal output. This setup work but not recommended due to some security problem, the job ran on master can touch some sensitive on master node.

So in this post i will guide you to create a Jenkins worker node, this node is for building docker image. I assume that we already have a master node up and running. For me i already deployed it to.

https://c9fc-2405-4802-911d-4a10-cb5c-22f7-ca0e-f68a.ap.ngrok.io

Jenkins server

As you can see that we only have master node, there is no agent beside this. To create new agent i will use docker compose. We will install docker, docker-compose. The worker node's architecture is same as.

Create a worker node on Console

From Jenkins UI, go to  Dashboard > Manage Jenkins > Nodes and create a node.

I will name it copper. Choose Permanent Agent. Then click Create button. After that we need to edit some parameter, for me i will set Number of executors = 10

The agent will connect to master (controller) by websocket.

Then save and you will saw the manual show how to connect the agent to controller. Ignore it, we just need to grab the secret and host name.

Setup Agent using Docker Compose

The docker file is same as above. Remember to update your secret , host name and JENKINS_AGENT_NAME , make sure it match with the worker name.

version: "3.9"

networks:
  default:
    name: copper
    driver: bridge

volumes:
  agentworkdir:
  dockercerts:


services:
  docker:
    image: docker:23.0.1-dind
    volumes:
      - dockercerts:/certs
      - agentworkdir:/home/jenkins
    privileged: true
    environment:
      DOCKER_TLS_CERTDIR: /certs
    restart: always
  agent:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      JENKINS_SECRET: beec63a670cb8d7d8d119a358d0118acbee102a82c422f5d2172c28c7b1a1be6
      JENKINS_AGENT_WORKDIR: /home/jenkins/agent
      JENKINS_WEB_SOCKET: true
      JENKINS_URL: https://c9fc-2405-4802-911d-4a10-cb5c-22f7-ca0e-f68a.ap.ngrok.io
      JENKINS_AGENT_NAME: copper
      DOCKER_HOST: tcp://docker:2376
      DOCKER_CERT_PATH: /certs/client
      DOCKER_TLS_VERIFY: 1
    volumes:
      - dockercerts:/certs
      - agentworkdir:/home/jenkins
    restart: always
docker-compose.yml

In this compose file, we defined two services, the first one is docker:dind. Our agent will use this docker server to build image, start container with predefined image and so on.

Start docker by running docker compose up -d docker

Check docker log using docker compose logs -f docker to make sure it's running.

Next time we need to start agent by running docker compose up -d agent and also need to check the log of this service. The agent need to include docker cli it seft, we can do that define build block and using custom Dockerfile for agent.
The agent Dockerfile content is

FROM jenkins/inbound-agent
USER root
RUN apt-get update && apt-get install -y lsb-release
RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \
    https://download.docker.com/linux/debian/gpg
RUN echo "deb [arch=$(dpkg --print-architecture) \
    signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \
    https://download.docker.com/linux/debian \
    $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
RUN apt-get update && apt-get install -y docker-ce-cli
USER jenkins
Dockerfile
agent:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      JENKINS_SECRET: beec63a670cb8d7d8d119a358d0118acbee102a82c422f5d2172c28c7b1a1be6
      JENKINS_AGENT_WORKDIR: /home/jenkins/agent
      JENKINS_WEB_SOCKET: true
      JENKINS_URL: https://c9fc-2405-4802-911d-4a10-cb5c-22f7-ca0e-f68a.ap.ngrok.io
      JENKINS_AGENT_NAME: copper
      DOCKER_HOST: tcp://docker:2376
      DOCKER_CERT_PATH: /certs/client
      DOCKER_TLS_VERIFY: 1
    volumes:
      - dockercerts:/certs
      - agentworkdir:/home/jenkins
    restart: always
Agent Service

Start the service.

docker compose up -d agent

Check the log.

docker compose logs -f agent

Verify the worker node

Go back to the web console, open Manage nodes and clouds you will see the worker node is active.

Test the worker node

I will create a Multibranch Pipeline job, in the Jenkinsfile i will update the lable to copper so it can run on the new worker node that we created.

The content of Jenkinsfile is like this

pipeline {
    agent { node { label 'agent' } } 
    stages {
        stage("Build") {
            when {
                beforeAgent true
                anyOf {
                    branch "master"
                    buildingTag()
                }
            }
            steps {
                script {
                    checkout scm
                    IMAGE_TAG=BUILD_ID
                    if(env.TAG_NAME){
                        IMAGE_TAG = TAG_NAME
                    }
                    env.IMAGE_TAG =  IMAGE_TAG
                    def image = docker.build("$JOB_BASE_NAME:$IMAGE_TAG","-f pipeline/Dockerfile .")
                }
            }
        }
        stage("Deploy") {
            steps {
                script {
                    if(env.TAG_NAME) {
                        env.TARGET_ENVIRONMENT = input message: "Which version do you want to deploy ?",
                        parameters:[
                            choice(name: 'TARGET_ENVIRONMENT', choices : ["staging","production"])
                        ]
                    } else {
                        env.TARGET_ENVIRONMENT = "development"
                    }
                    checkout scm
                    sh """
                    echo "deploy to: $TARGET_ENVIRONMENT with tag ${env.IMAGE_TAG}"
                    """
                }
            }
        }
    }
}
Jenkinsfile

After pushing to code, it will triggered the Jenkins to scan respository then run the pipeline, and in the Console Output we can see that the job ran on copper worker node.

Let take a look to Build job, we can see that the docker build process is sucessfully.

That's all, thank for reading.