Posts Docker in Jenkins in Kubernetes
Post
Cancel

Docker in Jenkins in Kubernetes

Jenkins Kubernetes and Docker

I was recently trying to build Docker images with Jenkins. That sounds easy, but Jenkins was running on Kubernetes and so it was already in a container. To make things harder, I needed to then push the images into a private registry with a custom certificate.

Automating this is difficult, but it can be done efficiently.

The docker runner

I have the Jenkins Kubernetes plugin installed and configured. I will not cover that here since the documentation is clear to help you install it.

The first thing to do is decide how you will run Docker. One option is to use the dind image (docker in docker), which can be found on docker hub. I found that to be a challenge since I needed to use a custom certificate authority and I could not get that to work. There was also the option of mounting the docker sock to access docker on the host, but that was not an attractive option.

I created a new docker image with my root certificate authority.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
FROM ubuntu:22.04
LABEL maintainer="perrio.io"
RUN apt-get update && \
    apt-get install -y \
    ca-certificates \
    curl \
    wget \
    gnupg \
    lsb-release && \
    mkdir -p /etc/apt/keyrings
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
RUN echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

RUN apt-get update && \
    apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

RUN wget -O root-ca.crt --no-check-certificate https://files.lab.home/root-ca.crt && \
    mv root-ca.crt /usr/local/share/ca-certificates/root-ca.crt && \
    update-ca-certificates

Here I am installing docker, downloading the root certificate authority and updating the certificates. You might need to do this if you are not using custom certificates but this worked for me.

Jenkins Pipeline

To use this container I defined the agent in the Jenkinsfile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
pipeline {
    agent {
        kubernetes {
            yaml '''
        apiVersion: v1
        kind: Pod
        spec:
          volumes:
            - name: build-cache
              persistentVolumeClaim: 
                claimName: build-cache
          serviceAccountName: jenkins-agents
          containers:
         - name: docker
            image: myreg/docker:1
            volumeMounts:
            - name: build-cache
              mountPath: /var/lib/docker
              subPath: docker
            command:
            - cat
            tty: true
            securityContext:
              privileged: true
       '''
        }
    }
    stages {

        // checkout and test

        stage('Build UI Docker Image') {
            steps {
                container('docker') {
                      sh 'dockerd & > /dev/null'
                      sleep(time: 10, unit: "SECONDS")
                      sh "docker build  -t myreg/myapp/ui:$BUILD_NUMBER ."
                      sh "docker push myreg/myapp/ui:$BUILD_NUMBER"
                }
            }
        }
    }
}

Here I define a container called docker for the builds. Notice that I have set securityContext.privileged: true to allow the container to run docker. The other important step is the volume. I am using a peristentVolumeClaim to cache the contents of the /var/lib/docker` directory. This contains the docker layer cache and greatly speeds up the builds.

Notice the dockerd command, this is because docker will not automatically start with the container so we have to start it and give it a few seconds to be ready.

Summary

Jenkins on Kubernetes is an extremely powerful tool. Some elements are harder because you are running in containers but this approach is working for me.

This post is licensed under CC BY 4.0 by the author.