Getting started with Jenkins: Language Agent
Tags: jenkins, devops, tutorial, docker
Published: 2021-04-26 07:18:11

This post is going to get you running a language specific Jenkins Agent. In the example we are going to follow, we will setup a Jenkins Agent running [Go](https://golang.org). This means you will be able to run Go builds within your local Jenkins instance. This method can then be extrapolated to other languages.

All of the example code used throughout this post is in a [GitHub Repo](https://github.com/benmatselby/jenkins-example).

## The Dockerfile

Since we are building our own agent, we need to define a `Dockerfile` that is based on a Jenkins agent. From that base, we will then install Go.

From the [example repo](https://github.com/benmatselby/jenkins-example), let's look at the `Dockerfile`:

```dockerfile
# Source: https://github.com/benmatselby/jenkins-example/blob/main/agents/go/Dockerfile
# Base Dockerfile image: https://hub.docker.com/r/jenkins/inbound-agent/dockerfile
FROM jenkins/inbound-agent:4.7-1-jdk11

# Where we are going to install Go.
ENV GO_INSTALL_PATH /home/jenkins/go

# We need to add the GO_INSTALL_PATH to the PATH so `go` works.
ENV PATH /home/jenkins/bin:${GO_INSTALL_PATH}/bin:/usr/local/go/bin:$PATH

# The version of Go we want to install
ENV GO_VERSION 1.16

# Define the GOPATH
ENV GOPATH ${GO_INSTALL_PATH}

# CI/CD platforms normally define CI=true, so let's follow suit
ENV CI true

# Install Go
RUN curl -sL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz > /tmp/go.tar.gz && \
  tar -C /tmp -xf /tmp/go.tar.gz && \
  mv /tmp/go ${GO_INSTALL_PATH} && \
  rm -rf \
    ${GO_INSTALL_PATH}/pkg/*/cmd \
    ${GO_INSTALL_PATH}/pkg/bootstrap \
    ${GO_INSTALL_PATH}/pkg/obj \
    ${GO_INSTALL_PATH}/pkg/tool/*/api \
    ${GO_INSTALL_PATH}/pkg/tool/*/go_bootstrap \
    ${GO_INSTALL_PATH}/src/cmd/dist/dist \
    /tmp/go.tag.gz
```

Although the above code is curated, let's explain each stage.

- To save us from installing a Jenkins Agent within the container, we are going to start with a Jenkins Agent as the base Docker image.
- We then define 5 environment variables that:
  - Explain where we are going to install Go.
  - Puts the Go binaries in the `PATH`.
  - Define the version of Go we want to build.
    - Arguably you could define an `ARG` here and override at build time.
  - Define the `GOPATH` using the `GO_INSTALL_PATH` environment variable.
  - Most CI/CD systems will define `CI=true`, so we are following suit.
- The last block of code defines the installation commands required to install Go. Extra points for trying to streamline the image we are building by removing unnecessary files.

## Building the image

Now we have defined the image, we want to build it. The easiest way to build the image, is to run this command:

```shell
docker build -f agents/go/Dockerfile -t jenkins-agent:go agents/go
```

This command will take the Dockerfile defined by `-f`, and call the image `jenkins-agent:go` using the `-t` argument. The last aspect of the command `agents/go` explains the context that `docker build` should build in (which is the folder the Dockerfile is defined in).

In the [benmatselby/jenkins-example](https://github.com/benmatselby/jenkins-example) repo, I've created a Make target that is agnostic of the language you may be using:

```make
# Source: https://github.com/benmatselby/jenkins-example/blob/main/Makefile
# Find all the agents, which are all folders in the `agents` folder.
AGENTS=$(shell cd ${AGENT_PATH} && find * -type d)

# We then define a build target, which depends on the make targets defined by
# the $(AGENTS) variable.
.PHONY: build $(AGENTS)
build: $(AGENTS) ## Build the Jenkins agents

# This is the Make targets for each image found
$(AGENTS): ## Build each Jenkins agent
  # This is the docker command defined above, but with variables
  cd ${AGENT_PATH}/${@} && docker build -t ${AGENT_NAME}:${@} .
```

The more `Dockerfile`s we add into the repo, e.g. Node, Python, PHP, etc, the command will still work.

## Running the agent

Not to cover old ground, at this point you can re-use the "[Getting started with Jenkins: Agents](https://dev.to/benmatselby/getting-started-with-jenkins-agents-5b5e)" post to connect your agent.

Differences I would recommend:

- Name your node after the language, so instead of `smith` this would be called `go`.

## Pulling the solution together

If you have followed the previous post to setup your agent, you should now be able to define a new job with the `go` label.

Let's create a Freestyle project called `go-project`. This time let's set the **Restrict where this project can be run** to `go`.

![Jenkins project for Go builds](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uue20t5jaylyjmyv442f.png)

Leave everything else as default (for this post, but feel free to play around later), and set the shell command to `go version`.

![Jenkins project for Go builds - The command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wkr119u1kq8glfu81xps.png)

Now click **Save**, and you will be taken back to the Job. Click **Build Now**. After a few moments, you will See **#1** appear in the **Build History** on the left hand side. Click on the blue ball. You will see the version details for Go.

![Jenkins project for Go builds - The output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bz2kgcdrpsr5eksrm8qy.png)

Congratulations, you've now successfully:

- Defined a language specific agent: Go.
  - This could be any language or environment you require.
- Built the docker image for the language specific agent.
- Connected the language specific agent to the Jenkins Controller.
- Run a job that has executed Go, in your agent.

## What's next

Want to go further? Then you could:

- Define more languages and play around with "tags" to make sure builds get directed to the correct agents.
- Use something like `ngrok` to expose your installation back to GitHub, to get GitHub Events.

## Summary

This was a quick overview for getting a language specific Jenkins agent connected to the Jenkins controller application.

---

Photo by [Alexander Schimmeck](https://unsplash.com/@alschim?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/choice?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText).

---

### See also

- [Getting started with Jenkins](https://dev.to/benmatselby/getting-started-with-jenkins-3a81)
- [Getting started with Jenkins: Agents](https://dev.to/benmatselby/getting-started-with-jenkins-agents-5b5e)
- [Docker knowledge to get you through the day](https://dev.to/benmatselby/docker-knowledge-to-get-you-through-the-day-47bl)
- [Comparison: AWS CodePipeline, GitHub Actions, and Jenkins](https://benmatselby.dev/post/build-tool-comparison/)