Using Jenkins and the Anka Build Cloud

Instructions on how to use Jenkins with Anka Build Cloud

The Jenkins Anka Plugin provides a quick way to integrate Anka Build Cloud with Jenkins. The plugin helps Jenkins jobs dynamically provision Anka VM instances (based on the label used) for building, testing, and more.

  • Support for both Pipeline and Freestyle Jenkins jobs.
  • Supports both Jenkins Node/Agent Templates and Labels (under Configure Clouds) and Dynamic Labelling (in your repo's Jenkinsfile).
  • The VMs become deleted after every job finishes.
  • Supports automated VM Tag creation after your jobs run. This “Anka VM Template/Tag Creation” feature helps optimize subsequent builds as the dependencies are already on the VM.
  • Supports both JNLP and SSH based connections to Anka VMs.

In order to follow these instructions, you will need to install the Anka CLI and an understanding of how to start the VM and launch the viewer.

VM Template & Tag Requirements

The Jenkins Anka Plugin requires a VM with Java, SSH Remote Login, and port forwarding:

  1. In the VM, install the proper OpenJDK version.
    • Within Jenkins, visit /systemInfo (System Properties) and look for java.version.
    • Use the value to determine the proper OpenJDK version you need to download and install in your VM Template. For example if the java.version is set to 1.8.0_242, you can download and install the AdoptOpenJDK jdk8u242-b08.pkg.

You can run any version of JAVA you want as long as the version inside of the VM matches your Jenkins server

  1. In the VM, make sure remote login is enabled (System Preferences > Sharing).
  2. On the host, enable port forwarding for your VM Template using the Anka CLI. We recommend not specifying –host-port.
  3. sudo anka suspend <VM Template name>
  4. sudo anka registry push <VM Template name> <Tag name>

Install and Configure the Anka Plugin in Jenkins

These steps are based on Jenkins 2.289.1 and the Anka Jenkins Plugin v2.6.0. Your version/UI may differ slightly.

  1. Navigate to Manage Jenkins > Manage Plugins and click on the Available tab. Search in Filter for “Anka”, then install it. You won't see any results if it's already installed.

  2. Now you can configure the Anka Cloud. Navigate to Manage Jenkins > Manage Nodes and Clouds and find the section called Configure Clouds. Inside of Configure Clouds, click on Add a new Cloud at the bottom of the page and then click on Anka Build Cloud Plugin.

  3. You now have an Anka Build Cloud Plugin panel exposed to do your configuration. You can set Cloud Name to be anything you want. However, you'll need to set Full Anka Build Cloud Controller URL to the proper URL of your controller, and make sure you include the port: http://<ip/domain>:80. Once you're done, click Save.

At this point you can either setup Static Labels or use Dynamic Labelling in your Jenkinsfile.

  • Static Labels are attached to Agent/Node Templates and can then be referenced in your pipeline or job definitions.
  • Dynamic Labels are set up inside of the Jenkinsfile inside of a pipeline, stage, or step-level definition.

Creating Static Labels

  1. Return to Manage Nodes and Clouds > Configure Clouds. You should now see a Jenkins Node/Agent Templates and Labels section. Make sure Show Agent/Node Templates is checked and click on Add. This creates a new Template you can edit.

  2. Under the Template, you want to select the proper Anka VM Template and Anka VM Template's Tag or leave the tag selection to the default value to select the latest Tag in the Registry.

  3. (Optional) Set Node/Agent Description

  4. Select the SSH or JNLP method for connection between Jenkins and your Anka VMs.

    • SSH: You'll need to add the proper user credentials to Jenkins. If you're using the default user on the VM, use the user: anka and pass: admin.
    • JNLP: This method downloads an agent.jar and the slave-agent.jnlp file from the Jenkins URL you've set in your System Configuration into the VM. If the Jenkins URL doesn't resolve inside of the VM (like if it's set to http://localhost), you won't be able to use JNLP. If you're seeing any problems post-creation of the agent inside of Jenkins, check the running VMs /tmp/log.txt for errors.
  5. (Optional) Set Maximum Allowed Nodes/Agents if you need to limit the amount of agents that any jobs are allowed to start.

  6. (Optional) Set Allowed Executors if you want to allow a single agent to be used for multiple jobs.

  7. (Optional) Set Anka VM Workspace Path if you'd like for the job to work within a specific path inside of the VM.

  8. (Optional) Set any Environment Variables necessary for your jobs

  9. There are several other configs under Advanced that may interest you. These include the Node Group, Priority, and timeouts for Jenkins to communication with the starting Anka VM/agent.

Using Dynamic Labelling

Dynamic Labelling requires two plugins: GitHub Authentication plugin and Pipeline.

This section describes the steps to create dynamic labels inside of your Jenkinsfile using the createDynamicAnkaNode function.

  • The createDynamicAnkaNode function starts a VM and returns a unique label for it.
  • The returned label can be interpolated in your pipeline, stage, or step-level definitions. (Example)
  • createDynamicAnkaNode has all the configuration options that the UI configured Static Slave Template has.
  • This allows you to have only a minimal Anka Cloud configuration and define Anka Nodes on the fly.

Jenkins has a Pipeline Snippet Generator, which helps you craft your createDynamicAnkaNode definition. You can find it in your Jenkins instance at /pipeline-syntax.

CreateDynamicAnkaNode Parameters

You can obtain the “masterVmId” (VM UUID) using: sudo anka show <Template name> uuid

NameTypeDefault ValueDescriptionRequired
masterVmIdString-UUID of the VM TemplateYes
tagString-VM Template Tag name-
remoteFSStringUsers/ankaRemote node workspace-
launchMethodStringjnlpNode launch method: ‘ssh’ or ‘jnlp’-
credentialsIdString-Jenkins credential ID for ssh launch method-
extraArgsString-String to be appended to JNLP command-
javaArgsString-String to append to JNLP java args-
jnlpJenkinsOverrideUrlString-Override the Jenkins server url set in the Jenkins configuration-
jnlpTunnelString-JNLP tunnel to use for node launcher-
keepAliveOnErrorbooleanfalseKeep the VM instance alive after a failed build-
timeoutint1200Timeout for starting the instance (in seconds)-
environmentsList of tuples-List of environment variables to add for the build: [[name: 'FOO', value: 'BAR'], [name: 'OR', value: 'IS']]-
nameTemplatestring-Label to use in VM instance names (There are several variables available for interpolation: $Template_name, $Template_id, or $ts)-
priorityint1000Override the default priority (lower is more urgent). Available only in Enterprise and Enterprise Plus Tiers-
saveImagebooleanfalseSave the VM as a Tag before terminating it-
suspendbooleanfalseWhen saving the Tag, suspend the VM before the push-
TemplateIdstring-When saving the Tag, push onto a specific Template UUID-
pushTagstring-When saving the Tag, set the Tag name (A timestamp will be appended)-
deleteLatestbooleanfalseWhen saving the Tag, delete the latest Tag for the Template out of the registry before pushing (Dangerous: only use if the Template isn't holding other project tags)-
TemplateDescriptionstring-When saving the Tag, set a description for the new Tag-
groupstring-Group ID to start the instance in (Available only in Enterprise and Enterprise Plus Tiers)-
numberOfExecutorsint1Number of Jenkins executors to run on the Node (we recommend 1)-
descriptionstring-On creation of the instance, set the description-
labelStringstring-Override the returned label (not recommended)-
dontAppendTimestampbooleanfalseDo not append timestamp to the tag being pushed-

Dynamic Jenkinsfile Example

def NODE_LABEL = createDynamicAnkaNode(
  masterVmId: 'e1173284-39df-458c-b161-a54123409280'
)
pipeline {
  agent {
    label "${NODE_LABEL}"
  }
  stages {
    stage("hello") {
      steps {
        sh "echo hello"
      }
    }
  }
}
  • In this example, the pipeline uses the “NODE_LABEL” variable defined at the beginning of the file.
  • The function call starts an instance with the Template UUID ‘e1173284-39df-458c-b161-a54123409280’ and returns a unique label, preventing any other external step or pipeline from using it. Any unspecified parameters have their default values, as indicated in the parameter list above.
  • The sh step waits until the instance is up and the node is connected to Jenkins before it runs.
Other examples:

Using Anka VM Template/Tag Creation (Optional)

Anka VM Template/Tag Creation is useful when you need to automate the preparation of a VM with dependencies. You can setup a separate Jenkins job/pipeline to execute preparation scripts inside of a VM and then push to the registry with a specific tag. Other jobs can then target the latest tag and immediately start using the new VM template/tag.

The plugin will push to the Registry for any buildStatus except for FAILURE, ABORTED, or UNSTABLE. You can wrap your step-level commands in catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') or use the Build Execute shell advanced Exit code to set build unstable setting to prevent the VM from pushing.

Configuring for Static Labels

You can find the Anka VM Template/Tag Creation in the Jenkins Node/Agent Templates and Labels section under Manage Jenkins > Manage Nodes and Clouds > Configure Clouds.

Using the Post Build Step with Static Slave Templates

image12

Fail build : Will set the build as failed if the image save request failed (or timed out). If this is not selected, the Post Build Step does nothing.

Timeout : Sets the minutes to wait for the Tag push to Registry to cowmplete (this needs to be determined manually or with trial and error).

Using a Jenkinsfile with the Static Slave Template

Pipelines can have multiple agents running in one build (also in parallel). Therefore, the plugin relies on the buildResult to tell if it needs to execute the “save image request”. You have two options to prevent pushing the new Tag prematurely:

  1. Wrap your step-level commands in a catchError (from our Nested Cache Builder Example):
    stage("run-on-NESTED_LABEL-vm") {
      agent { label "${NESTED_LABEL}" }
      steps {
        // If buildResults == 'FAILURE', Anka will not push the NESTED_LABEL VM. Example:
        catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
          sh 'uname -r;'
        }
      }
    }
    
  2. Enable Wait For Build Finish

Configuring Templat/Tag Creation with Dynamic Labelling

Please review our Nested Cache Builder Example.

  • The AGENT_LABEL VM instance is created to handle the first stage.
  • The second stage creates a second VM instance that is configured to push to the Registry once the buildResult is a successful status.

If buildResult receives any of the failed statuses (FAILURE, ABORTED, or UNSTABLE), the ankaGetSaveImageResult outputs Checking save image status… Done! in the Jenkins job logs/console since there is no push operation to wait on.

Using the Post Build Step with Dynamic Labelling

Create an ankaGetSaveImageResult Pipeline step:

stage("check-generated-tag-from-nested-vm") {
  steps {
    script {
      def getPushResult = ankaGetSaveImageResult( shouldFail: true, timeoutMinutes: 120 )
      echo "ankaGetSaveImageResult Returned: $getPushResult"
    }
  }
}

If you're creating multiple cache Tags in a single pipeline, The ankaGetSaveImageResult function returns true if all previous image save calls for this particular build have executed.

NameTypeDefault ValueDecriptionRequired
shouldFailbooleantrueFails the job if one of the image save requests has failed or timed out
timeoutMinutesint120Stops waiting for the result of the Tag -> Registry push after x minutes.

Remember, ankaGetSaveImageResult returns true immediately if nothing pushes to the Registry in a failed build.

Notes on using the Template/Tag Creation

  • How often should I run this? : The answer depends on the VM size after you prepare it and also the density of your builds.
  • The template/tag creation should have a job or pipeline of its own. Creation after every “regular” build might not make sense as the time that it takes to download code or artifacts is usually the same or shorter than the time it takes to push the Tag to the Registry.
  • You should run it once and check how much time the operation takes. The push can be a few gigabytes and might take some time on slower networks.
  • Only one Tag can push at a time. You can execute multiple creations for the same Template, but those requests end up executing serially.
  • If your build/preparation is fast and resulting templates/tags small, you can consider running creation a few times a day or even based on commits. If your creation is slow, consider running one per day (you can schedule it for a time that Jenkins is not busy).


Last modified August 18, 2021 : 2.5.0 (8cf0cc3) by Nathan Pierce