Connecting inbound agents

5 minute read

When an administrator wants to connect an inbound (formerly known as “JNLP”) external agent to a Jenkins controller, such as a Windows virtual machine running outside the cluster and using the agent service wrapper, two connection types are available in CloudBees CI on modern cloud platforms.

Table 1. Connection types
Connection type Description

WebSocket for Agent Remoting Connections (available in CloudBees CI on modern cloud platforms version 2.222.2.1 and later)

This is the recommended method for all new inbound agent connections. It is a substitute for the older method and is simpler, more straightforward, and easier to establish. This feature allows for the agent to call back on the regular HTTP port, using WebSocket to set up a bidirectional channel. Using WebSocket, inbound agents can now be connected much more simply when a reverse proxy is present: if the HTTP(S) port is already serving traffic, most proxies will allow WebSocket connections with no additional configuration.

WebSocket for Agent Remoting Connections provides the following benefits:

  • Uses best practices to set up secure connections, enhancing overall security.

  • Increases productivity by simplifying a previously complex administrative task.

  • Provides easier and more comprehensive support for any agent type on any cloud platform.

Inbound TCP (formerly known as JNLP)

With this connection, the controller must expose a non-HTTP port (conventionally 50000) and then wait for an agent pod to call back to it. This can complicate network architectures. You can use a values.yaml file.

Connecting inbound agents using WebSocket for Agent Remoting Connections

CloudBees CI supports using WebSocket transport to connect inbound agents to controllers. This works for shared agents and clouds, as well.

This feature is available in CloudBees CI version 2.222.2.1 and later.

This functionality lets you make a connection via HTTP(S), then holds the connection open to create a bidirectional channel to send data back and forth between controllers and inbound agents.

No special network configuration is needed since the regular HTTP(S) port for your controller is used for all communications.

For additional details about WebSocket support in Jenkins, refer to JEP-222: WebSocket Support for Jenkins Remoting and CLI.

To connect inbound agents:

  1. On the Agent Configuration screen, in Launch method, select Launch agent by connecting it to the controller.

  2. Select Use WebSocket. Enabling the Use WebSocket option allows the agent to make a connection to the WebSocket.

  3. Follow the instructions on the Agent page to connect the agent. For more details, refer to Launching inbound agents.

Modern Cloud Platforms

This content applies only to CloudBees CI on modern cloud platforms.

Connecting inbound agents using the values.yaml file

Use this procedure only if Helm was used to install NGINX Ingress Controller.

The procedure is similar to the one allowing connection of external controllers to operations center using Helm.

To use the values.yaml file to configure ports for inbound agents:

  1. Type the following command:

    curl -Is https://$DOMAIN_NAME/$MASTER_NAME/tcpSlaveAgentListener/ | fgrep -i X-Jenkins-JNLP-Port
    On AWS, if you followed these instructions, proxy protocol will be enabled. It requires adding :PROXY at the end of each entry.

    This returns the advertised port for inbound agent traffic of a specific controller.

  2. Add the service mapping to the tcp section of the values.yaml file (replace occurrences of cloudbees-core with the namespace where CloudBees CI was installed, $JNLP_MASTER_PORT by the port determined above, and $MASTER_NAME by the controller name):

    tcp: $JNLP_MASTER_PORT: "cloudbees-core/$MASTER_NAME:$JNLP_MASTER_PORT"

    or (proxy protocol variant)

    tcp: $JNLP_MASTER_PORT: "cloudbees-core/$MASTER_NAME:$JNLP_MASTER_PORT:PROXY"
    Add a line for every controller that you want to allow external inbound agent connections to.
  3. Deploy the configuration:

    helm repo add ingress-nginx \https://kubernetes.github.io/ingress-nginx helm repo update helm upgrade ingress-nginx \ ingress-nginx/ingress-nginx \ --install \ --namespace ingress-nginx \ --values values.yaml \ --version 3.3.0
  4. These changes require a redeployment, but due to nginx issue #4804 this will happen only when creating the tcp section, not when updating it.

    To force a rolling update, use the following command:

    kubectl patch deployment ingress-nginx-controller -p \ "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"date\":\"`date +'%s'`\"}}}}}"

After you have configured ports, you should test the connection.

Configuring inbound agents using self-signed certificates

You can configure connections for agents using self-signed certificates or enterprise certificates that are not trusted by the shared agent. To configure inbound agents using self-signed certificates, you must use a Kubernetes deployment with a load balancer that supports websockets or inbound TCP. The self-signed certificate must be trusted by the client.

Complete the following steps:

  1. Type the following command to create a TrustStore called cacerts.jks and import the certificate:

    keytool -import -v -trustcacerts -alias cbci.example.com -file cbci.example.com-certificate.pem -keystore cacerts.jks -storepass changeit
  2. In the operations center, configure the JVM options with the TrustStore and TrustStore password using a location the inbound agent can access:

    JVM options
  3. Use the TrustStore when you execute the launch connection from the agent:

    java -Djavax.net.ssl.trustStore=/var/jenkins_home/cacerts.jks -Djavax.net.ssl.trustStorePassword=changeit -jar slave.jar -jnlpURL \https://cbci.example.com/cjoc/jnlpSharedSlaves/sharedagent/slave-agent.jnlp -secret xxx

Testing the connection for inbound agents

After you have configured the connection for inbound agents, you should confirm that controller is ready to receive external inbound agent requests.

To test the connection for inbound agents:

$ curl $DOMAIN_NAME:$JNLP_MASTER_PORT Jenkins-Agent-Protocols: Diagnostic-Ping, JNLP4-connect, OperationsCenter2, Ping Jenkins-Version: {core-version} Jenkins-Session: f4e6410a Client: 0:0:0:0:0:0:0:1 Server: 0:0:0:0:0:0:0:1 Remoting-Minimum-Version: 3.4

Once the connection is correctly configured in your cloud, you can then create a new 'node' in your controller under Manage Jenkins  Manage Nodes.

The node should be configured with: - Launch method: 'Launch agent by connecting it to the master'

Port 50000 in replicated managed controllers

On Kubernetes, CloudBees strongly recommends WebSocket transport for inbound agents connecting from outside the cluster.

You can use the older method of connecting inbound agents with the values.yaml file. In this way, you patch the ingress to forward port 50001, 50002, or similar, to the managed controller Service`s with each controller pod using container port 50000. You may need to define the Tunnel connection through option for the agent by setting the `tunnel field in Configuration as Code (CasC) to the ingress hostname; for example, to cbci.example.com:50001.

You can also use the NodePort service created when you select Allow external agents in controller provisioning. Be sure to set allowExternalAgents: true in CasC. If an inbound TCP agent connects to the incorrect replica, the connection is automatically proxied. You may need to define the Tunnel connection through option for the agent by setting the tunnel field (or for a Kubernetes cloud, the jenkinsTunnel field) in Configuration as Code to ${JNLP_NODE_NAME}:${JNLP_NODE_PORT}.

Troubleshooting inbound connections

When using the NGINX Ingress controller, and when an ingress is created, updated, or deleted, the NGINX Ingress controller reloads its configuration and any open connections are closed, following the timeout specified by the NGINX worker_shutdown_timeout directive. For example, this occurs when a controller is started or stopped. If you use a pipeline with durable tasks, the interruption is typically brief and any external agents quickly reconnect.

However, if you are using tasks that are not durable, such as freestyle, matrix, or maven jobs, the builds fail. CloudBees recommends that you migrate non-durable tasks to pipeline jobs.

If you are using Windows Agents that are controlled by the Windows Service Wrapper, the reconnection process prevents durable tasks from working (due to JENKINS-47657). In this scenario, the pipeline stops responding, the PowerShell process no longer exists on the Windows host, and you must abort the pipeline.

In August 2020, the Jenkins project voted to replace the term master with controller. We have taken a pragmatic approach to cleaning these up, ensuring the least amount of downstream impact as possible. CloudBees is committed to ensuring a culture and environment of inclusiveness and acceptance - this includes ensuring the changes are not just cosmetic ones, but pervasive. As this change happens, please note that the term master has been replaced through the latest versions of the CloudBees documentation with controller (as in managed controller, client controller, team controller) except when still used in the UI or in code.