How to Create a Kitchen Sink Jenkins Agent and Why It’s a Bad Idea

How to Create a Kitchen Sink Jenkins Agent and Why It’s a Bad Idea

·

3 min read

If you followed my last guide to spin up Jenkins in a brand new Google Kubernetes Engine cluster, you’re now probably itching to do something useful with it. The final goal will be to create a pipeline in Jenkins that manages our Terraform infrastructure, but before we get to that we’ll need to quickly pop through the looking glass into the world of custom Docker images.

Jenkins Agents

If you’re not familiar with Jenkins (oh, you lucky soul), it is an automation server that relies on agents to run jobs or complete tasks. These agents can be processes on the master server itself, or more traditionally they are separate standalone machines. Helpfully, the Helm chart we used to install Jenkins to our GKE cluster also set up the Kubernetes plugin for us. This plugin allows Jenkins to spin up agents as short-lived Kubernetes deployments inside the same cluster, so we don’t actually have to configure any agent machines or worry about managing them.

By default Jenkins images will use the jenkins/jnlp-slave docker image. Will this image contain the tools necessary for us to complete the tasks in our pipeline? Probably not. However with Docker it’s easy to inherit an image and build your own custom version of it.

The Custom Image

Create a new directory on your local machine and grab the jenkins-agent script that the original image uses. Save it in your new directory, then create the following Dockerfile:

FROM jenkins/slave

USER root

# Install docker
ENV DOCKER_VERSION 18.03.1-ce
ENV TF_VERSION 0.12.18

RUN set -x \
  && curl -fSL "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz" -o docker.tgz \
  && tar -xzvf docker.tgz \
  && mv docker/* /usr/local/bin/ \
  && rmdir docker \
  && rm docker.tgz \
  && docker -v

# Install kubectl
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl \
  && chmod +x ./kubectl \
  && mv ./kubectl /usr/local/bin/kubectl

# Install Terraform
RUN curl -LO https://releases.hashicorp.com/terraform/${TF_VERSION}/terraform_${TF_VERSION}_linux_amd64.zip \
  && unzip terraform_${TF_VERSION}_linux_amd64.zip \
  && rm terraform_${TF_VERSION}_linux_amd64.zip \
  && chmod +x ./terraform \
  && mv terraform /usr/local/bin/terraform

# Install gcloud SDK
RUN curl -sSL https://sdk.cloud.google.com | bash
RUN mv /root/google-cloud-sdk /usr/local/google-cloud-sdk

# Configure runtime
COPY jenkins-agent /usr/local/bin/jenkins-agent
RUN chmod +x /usr/local/bin/jenkins-agent &&\
    ln -s /usr/local/bin/jenkins-agent /usr/local/bin/jenkins-slave

ENV PATH="/usr/local/google-cloud-sdk/bin:$PATH"
ENTRYPOINT ["jenkins-agent"]

As you can see, we build on an existing image from Jenkins, then add the tools we want: Docker, Kubectl, Terraform and the GCloud SDK.

Let’s build our custom image:

docker build -t my-custom-agent .

You should now have a custom Jenkins agent docker image ready to go. We can push it to Docker Hub, or Google Container Registry, and update our Jenkins Helm deployment to use this image for agent deployments. But wait:

a kitchen sink

We’re Doing It Wrong

There is a better way. Creating a kitchen-sink Jenkins agent may be fine for experimenting with pipelines when you need every tool at your disposal quickly, but it’s actually an anti-pattern. Why?

  • Containers should be as lightweight as possible

  • Isolating tools allows you to manage them separately

  • Pipelines can use multiple containers inside the same pod

The last point there is worth restating: You can define multiple containers within the same pipeline to carry out the various tasks and stages.

Thanks to the way the Kubernetes plugin works, each container will share the Jenkins home directory (in other words, the workspace of the pipeline) as they all exist within the same pod in your Kubernetes cluster.

In the next part of this series we’ll create our Terraform pipeline, and use-off-the shelf lightweight containers to run each specific stage. In the meantime, I hope my experience of learning to build a custom agent and then discovering why I shouldn’t use it was helpful to you!