Packaging a CI server into a Windows Docker image

Jenkins is a popular automation server that is used for CI/CD. It supports custom job workflows with multiple trigger types, including schedules, SCM polling, and manual starts. It's a Java application that is straightforward to package in Docker, although it's not so simple to fully automate the Jenkins setup.

In the source code for this chapter, I have a Dockerfile for the dockersamples/ch10-jenkins-base:2e image. This Dockerfile packages a clean installation of Jenkins, using Windows Server Core in the installation stage to download the Jenkins web archive. I use an argument to capture the Jenkins version, and the installer also downloads the SHA256 hash for the download and checks that the downloaded file hasn't been corrupted:

WORKDIR C:jenkins

RUN
Write-Host "Downloading Jenkins version: $env:JENKINS_VERSION"; `
Invoke-WebRequest "http://.../jenkins.war.sha256" -OutFile 'jenkins.war.sha256'; `
Invoke-WebRequest "http://../jenkins.war" -OutFile 'jenkins.war'

RUN $env:JENKINS_SHA256=$(Get-Content -Raw jenkins.war.sha256).Split(' ')[0]; `
if ((Get-FileHash jenkins.war -Algorithm sha256).Hash.ToLower() -ne $env:JENKINS_SHA256) {exit 1}
Checking the file hash for a download is an important security task to make sure that the file you download is the same as the one the publisher made available. It's a step that people typically leave out when they manually install software, but it's easy to automate in your Dockerfile and it gives you a more secure deployment.

The final stage of the Dockerfile uses the official OpenJDK image as the base, sets up the environment, and copies in the download from the installer stage:

FROM openjdk:8-windowsservercore-1809

ARG JENKINS_VERSION="2.150.3"
ENV JENKINS_VERSION=${JENKINS_VERSION} `
JENKINS_HOME="C:data"

VOLUME ${JENKINS_HOME}
EXPOSE 8080 50000
WORKDIR C:jenkins

ENTRYPOINT java -jar C:jenkinsjenkins.war
COPY --from=installer C:jenkins .

A clean Jenkins installation doesn't have many useful features; almost all functionality is provided by plugins that you install after Jenkins is set up. Some of these plugins also install the dependencies they need, but others don't. For my CI/CD pipeline, I need a Git client in Jenkins so that it can connect to the Git server running in Docker, and I also want the Docker CLI so that I can use Docker commands in my builds.

I can install these dependencies in the Jenkins Dockerfile, but that would make it large and difficult to manage. Instead, I'm going to fetch these tools from other Docker images. I'm using sixeyed/git and sixeyed/docker-cli, which are public images on Docker Hub. I use these along with the Jenkins base image to build my final Jenkins image.

The Dockerfile for dockeronwindows/ch10-jenkins:2e starts from the base and copies in the binaries from the Git and Docker CLI images:

# escape=`
FROM dockeronwindows/ch10-jenkins-base:2e

WORKDIR C:git
COPY --from=sixeyed/git:2.17.1-windowsservercore-ltsc2019 C:git .

WORKDIR C:docker
COPY --from=sixeyed/docker-cli:18.09.0-windowsservercore-ltsc2019 ["C:\Program Files\Docker", "."]

The final line just adds all the new tool locations to the system path so that Jenkins can find them:

RUN $env:PATH = 'C:docker;' + 'C:gitcmd;C:gitmingw64in;C:gitusrin;' + $env:PATH; `
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine)

Using public Docker images for the dependencies gives me a final Jenkins image with all the components I need, but with a manageable Dockerfile using a set of reusable source images. Now, I can run Jenkins in a container and finish the setup by installing plugins.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.181.252