Selecting an agent for your Pipeline job

6 minute read

Agents, directed by controllers, handle and complete the tasks of running builds. Selecting the right agent according to your target platform, operating system, tools, and architecture, is essential when running the build.

You can connect and use different types of agents as described in Connecting build agents. By using agent or node, you select the agent you desire for your build or one stage within your build.

The examples provided in the previous document page, Creating your first Pipeline , work if you have the right agents for the labels used. However, the syntax for using Kubernetes pods or Docker containers as ephemeral agents is different as you need to use additional directives, like the container directive. Ephemeral agents are provisioned, used for the build, and deprovisioned later. For information on how to select and use these types of agents, see the following sections.

Using Kubernetes pods as agents

If you plan to use Kubernetes to provide ephemeral agents, you need the following:

  • A Kubernetes cloud connected to your CloudBees CI instance.

  • The Kubernetes plugin installed in your CloudBees CI instance.

The Kubernetes cloud is provided out-of-the-box in CloudBees CI on modern cloud platforms, but must be added and connected for CloudBees CI on traditional platforms. You can find detailed instructions for that in the Shared cloud configuration documentation page and also in the Kubernetes plugin for Jenkins website.

Once the Kubernetes shared cloud and the Kubernetes plugin are installed, ephemeral agents for the builds are provided as pods according to pod templates defined using the UI or in the Pipeline definitions. The plugin provisions, uses, and deprovisions the pod when the build is finished.

You can find additional information about pod templates, how to create and use them, and pod template inheritance in this Knowledge Base article, and on the link: [Kubernetes plugin for Jenkin] page.

Agents are launched as inbound agents in a Pod container named jnlp to manage the connection between the controller and the pod. By default, the jnlp container is automatically injected in the pod template by the Kubernetes plugin in addition to any container templates defined in the pod template.

By default, commands during the build process are executed in the jnlp container. If you want to run commands in another container of the pod template definition (for example, the container with the build tools) you must wrap the sh steps into a container step. To launch these sh commands in the container, the controller sends requests to the Kubernetes API. Other tasks, like streaming logs, publishing test results, and so on, are performed by the jnlp container.

using cloud agents
Figure 1. Multi-container pod templates as Kubernetes agents
  1. The controller asks Kubernetes for a cloud agent.

  2. The Kubernetes shared cloud provides the ephemeral agent as a pod template. This pod template has two containers, the jnlp container injected by the Kubernetes plugin, and the container with the tools needed for tasks like building or testing your application.

  3. The controller sends commands to the container with the build tools using the Kubernetes API requests.

  4. The jnlp container streams the logs, test results, and so on, to the controller.

In the following examples, we will assume that there is a pod template with the linux label and, within that pod, there is a container with the name maven.

Declarative syntax
Scripted syntax
pipeline { agent { label 'linux'} (1) stages { stage('Build') { steps { container('maven') { (2) sh 'java --version' sh 'mvn --version' } } } } }
1 Selects the agent for the build. The pod template has the label linux.
2 Sets the container to execute the commands. The container has the name maven. This container must be part of the linux pod template definition.
node('linux') { (1) stage('Build') { container('maven') { (2) sh 'java --version' sh 'mvn --version' } } }
1 Selects the agent for the build. The pod template has the label linux.
2 Sets the container to execute the commands. The container has the name maven. This container must be part of the linux pod template definition.

If the container step is not defined, commands will be executed in the jnlp container, and will fail as the default jnlp container does not contain Maven (or your desired build tool).

Pod template definition embedded in the Pipeline definition

The previous examples rely on the existance of a pod template with the label linux and a maven container inside this template. You can also embed the pod template description in the Pipeline as it is described in the examples below.

Declarative syntax
Scripted syntax
pipeline { agent { kubernetes { (1) yaml ''' apiVersion: v1 kind: Pod spec: containers: - name: mymaven image: maven command: (2) - sleep args: - infinity ''' } } stages { stage('Build') { steps { container('mymaven') { (3) sh 'java --version' sh 'mvn --version' } } } } }
1 Define the pod template.
2 Execute the sleep command to keep the container alive and make the connection between the controller and the agent.
3 Set the container to execute the commands. The container has the name mymaven and is part of the pod template YAML definition.
podTemplate(containers: [ containerTemplate(name: 'mymaven', image: 'maven', command: 'sleep', args: 'infinity'), (1) ]) { node(POD_LABEL) { (2) stage('Build') { container('mymaven') { (3) sh 'java --version' sh 'mvn --version' } } } }
1 Pod template definition that contains the container description and supports the node step.
2 POD_LABEL as the node selector because the node step is used inside a podTemplate step.
3 Set the container to execute the commands. The container has the name mymaven as defined above.

Overriding the default jnlp container

As described in the previous sections, ephemeral agents are provided as pod templates. In addition to the image with the required tool, the plugin injects the jnlp container.

If the container step is not used, commands are executed by default in the jnlp container. If you want to execute commands in other containers, you must use the container step in the Pipeline, and controllers use Kubernetes API requests to run those commands within the step.

Kubernetes API requests are slow, and if you have many requests to agents, this situation might impact your cluster performance. This is because the Kubernetes plugin interacts with the Kubernetes share cloud that uses an active Kubernetes client that has a limitation in the number of concurrent connections to the Kubernetes API-server, and becasue some Kubernetes API requests keep the connections alive while the commands are executed on the container. You can find more information here.

To solve this situation, use a pattern of "All-in-One" containers (also known as "kitchen sink image") by overriding the injected jnlp container template in your pod templates with your own container template named jnlp. This container must specify a container image with all the required resources to run an inbound agent and all the additional tools you may need to build or test your application. In this use case, no other container is created or injected in the pod.

You can build these container images on top of the default CloudBees agent images.

The following example shows an example that uses the All-in-one agent image used by the Jenkins infrastructure team.

pipeline { agent { kubernetes { (1) yaml ''' apiVersion: v1 kind: Pod spec: containers: - name: jnlp image: <custom image> (2) command: - /usr/local/bin/jenkins-agent (3) args: envVars: (4) - envVar: key: JENKINS_JAVA_BIN value: /opt/jdk-11/bin/java - envVar: key: JAVA_HOME value: /opt/jdk-17 label: all jnlp-all ''' } } stages { stage('Main') { (5) steps { sh 'java -version' sh 'mvn --version' } } } }
1 Pod template definition using a YAML block inside the Kubernetes block within the agent directive.
2 An "all-in-one" image named jnlp. It overwrites the default jnlp container created by the Kubernetes plugin.
3 Command to launch the inbound agent when the container starts. Different from the sleep command previously used.
4 ENV_VARS to be created in the container. Be aware that the Agent JDK and the tools JDK can be different.
5 Stage executing command in the overwritten jnlp container.

Docker agents

As described here, Docker containers are another alternative for ephemeral agents. To use Docker containers as ephemeral agents, you must do the following:

  • Install the Docker engine on the server running your CloudBees CI agent.

  • Install the Docker Pipeline plugin in the instance.

After all of these requirements are satisfied, you can use Docker containers as ephemeral agents in the following way.

Declarative syntax
Scripted syntax
pipeline { agent { docker { image 'node:16-alpine' } (1) } stages { stage('Test') { steps { sh 'node --version' (2) } } } }
1 docker block within the agent directive to select a Docker image for the Docker containers used as agents.
2 Command executed inside the Docker container.
docker.image('node:lts-slim').inside { (1) sh 'node --version' (2) }
1 Docker step to set the image an the commands to be executed inside the running container.
2 Command executed inside the Docker container.

For more information about Docker containers as ephemeral agents, refer to here.

All of the Pipeline examples, declarative or scripted, in the rest of this documentation assume that the examples are correctly selecting an available agent with the right tools to complete the build execution.