Jenkins trigger on-demand slaves in dockers - jenkins

I'm looking for a way to run Jenkins jobs/build inside Jenkins slaves, dynamically (on-demand) started docker. Attaching schema for visual understanding.
What I'm actually looking for and my flow looks like:
1) Triggering Jenkins job (manually/git/gerrit)
2) Jenkins master (running in docker) starts slave machine docker (and pass script/instructions of the build)
3) Build is running on Jenkins slave (or slaves if parallel/pipeline)
4) Result returned to Jenkins master
5) Jenkins slave docker stops
Is it possible to do it this way?

Docker slave image creation steps like installing openssh, user creation, mentioned in the below link. Install docker plugin from the below link.
Click here!
Go to jenkins global configuration, Under cloud headings, docker configuration will be there, enter docker host url with port number, credential not required. give some values for connection timeout & read timeout.
Under docker template - Enter the docker image name which we created in the point number 1.
Set Label number (Give this label name during Jenkins job creation and restrict to this slave name),
Select the usage option - > only build job with label restriction.
No of executor -> minimum 1. Select launch method as ssh, enter the user credential to login, which we created in docker image in the step number 1.
create a job restrict to docker slave label, run, ondemand it wil spun up container.

Use this plugin: https://wiki.jenkins-ci.org/display/JENKINS/Yet+Another+Docker+Plugin
After instalation (it requires Java 1.8) naviaget to configuration. There are two steps:
configure docker "cloud"
add "instances" (docker images) you want to run the build on
Every image should have label assigned - use this label in you job configuration to tell Jenkins explicitlyon which node the job should be run

Related

Jenkins concurrent builds on docker slaves

I have a Jenkins Server (2.204.1) with Docker plugin (1.1.9) and a docker cloud API.
I work with Jenkins docker agents (slaves)
And i map the docker slave build workspace between the container and the host in order to be able to path
Artifacts to the downstream jobs.
in Jenkins Configuration - Docker Cloud Details - Container settings:
Volumes /var/lib/jenkins:/var/lib/jenkins
This works fine for a single build , The problem starts when i run concurrent builds,
They are all mapped to the same workspace on the Docker host and interfering each other.
What would be the best practice when using docker slaves and mapping workspace as a volume ?
I wouldn't like to use $CustomWorkspace or coping artifacts during the build as this is hard to manage and purge.
I prefer the Jenkins regular slave approach of adding #2 to a second concurrent build but this is not the behavior when running concurrent builds on docker slaves
One remote Jenkins agent has no way of knowing whether a given workspace directory is in use by another agent running on the same machine. This is equally true for docker-based agents that share a common directory via volume mounting. Ideally, all agents working from the same machine would have some way of talking to each other to keep from stepping on each other's toes (e.g. a lockfile in the workspace that gets removed upon job termination), but this is not currently the case.
Solution #1: Unique Build Workspaces
If we are using Jenkins pipelines, we can append a unique subdirectory to the workspace directory on a per-build basis. This solution is clean, simple, and easy to implement.
agent {
node {
customWorkspace "${env.BUILD_NUMBER}"
}
}
Ref: https://www.jenkins.io/doc/book/pipeline/syntax/#agent
Solution #2: Unique Agent Workspaces
If this is not possible or desirable, another potential solution is to change the root working directory of the Jenkins agent itself, which can be done by supplying an additional argument to the agent's startup command:
-workDir FILE : Declares the working directory of the
remoting instance (stores cache and logs by
default)
Source: java -jar agent.jar -help
When spinning up multiple agents dynamically on the same machine, we can set this -workDir value to something with a bit more uniqueness to give each agent its own directory to work out of, effectively mitigating workspace collisions. Something like this should work well:
java -classpath agent.jar hudson.remoting.jnlp.Main -headless \
-workDir /var/lib/jenkins/workspace/$(date +%3N) ...
The magic is in the $(date +%3N), which returns the system clock nanoseconds to three digits of precision. We may want to use more or fewer digits because there's a tradeoff: more precision will result in a higher maximum number of workspace directories but decrease the risk of workspace collisions; less precision will have the opposite effect - fewer directories, increased collision risk.
How this command is configured will vary based on your Jenkins setup. For example, we are using the Docker Swarm plugin (v1.9) on Jenkins 2.249.3. Our agent command is configurable at Manage Jenkins >> Manage Nodes and Clouds >> Configure Clouds >> Docker Swarm Cloud Configuration >> Docker Agent templates >> Command.
Ref: https://man7.org/linux/man-pages/man1/date.1.html

How can I user docker image jenkins/jnlp-slave with Jenkins docker-swarm-plugin (pass agent name)

I have a swarm of three nodes (one manager, two workers). In my swarm, I am running a jenkins service with docker-swarm-plugin (https://github.com/jenkinsci/docker-swarm-plugin) installed. I want to use the plugin to create a build agent container in my swarm for every jenkins job. For the agents I want to user the jenkins/jnlp-slave docker image (https://hub.docker.com/r/jenkinsci/jnlp-slave/). The image expects two arguments for the start:
secret (can be set via JENKINS_SECRET environment variable)
agent name (can be set via JENKINS_AGENT_NAME environment variable)
The docker-swarm-plugin creates three environment variables:
$DOCKER_SWARM_PLUGIN_JENKINS_AGENT_SECRET (I use this to set the secret)
$DOCKER_SWARM_PLUGIN_JENKINS_AGENT_JAR_URL
$DOCKER_SWARM_PLUGIN_JENKINS_AGENT_JNLP_URL (this contains the agent name)
I pass the secret to the agent via JENKINS_SECRET environment variable (in ENV section of Jenkins plugin configuration):
JENKINS_SECRET=$DOCKER_SWARM_PLUGIN_JENKINS_AGENT_SECRET
I tried to pass the agent name by using a regular expression (also in ENV section of Jenkins plugin configuration):
JENKINS_AGENT_NAME=`echo $DOCKER_SWARM_PLUGIN_JENKINS_AGENT_JNLP_URL | sed ...`
But the command is not executed (I understand that this is for security reasons to avoid code injection).
What do I want to reach:
I want to run jenkins on my docker swarm and I want jenkins to run every job in an own build agent container that is dropped after the job finished. And I want the build agent containers to spread across the swarm (jenkins docker-plugin launches them on the node where the jenkins master is running). I understood that the docker-swarm-plugin should do exactly what I want to do. And I think the jenkins/jnlp-slave image is there to build agent containers as I want to use. But I can't find a solution how to get them work together.
Can anyone give me some advice?
Should I maybe use another image that is working better with the plugin?
I opened issue https://github.com/jenkinsci/docker-swarm-plugin/issues/37 on docker-swarm-plugin for this and now with PR https://github.com/jenkinsci/docker-swarm-plugin/pull/39 a new environment variable is added with the created agents name. This can be passed to the docker image and everything works fine!

Is there a way for a docker pipeline file to determine the image of the child node it runs on?

I'd like to be able to dynamically provision docker child nodes for builds and have the configuration / setup of those nodes be part of the Jenkinsfile groovy script it uses.
Limitations of the current setup of jobs means Jenkins has one node/executor (master) and I'd like to support using Docker for nodes to alleviate this bottleneck.
I've noticed there's two ways of using a docker container as a node:
You can use the agent section in your pipeline file which allows you to specify an image to use. As part of this, you can target a specific node which supports running docker images, but I haven't gotten that far as to see what happens.
You can use the Jenkins Docker Plugin which allows you to add a Docker Cloud in Jenkins' configuration. It allows you to specify a label which, when used as part of a build, will spawn a container in that "cloud" from the image chosen in the cloud configuration. In this case, the "cloud" is the docker instance running on the Jenkins server.
Unfortunately, it doesn't seem like you can use both together - using the label but specifying a docker image in the configuration (1) where the label matches a docker cloud template configuration (2) does not seem to work and instead produces a label not found error during the build.
Ideally I'd prefer the control to be in the pipeline groovy file so the configuration is stored with the application (1), not with the Jenkins server (2). However, it suggests that if I use the agent section and provide a docker image, it still must target an existing executor first (i.e. master) which will cause other builds to queue until the current build is complete.
I'm at a point of migrating builds, so not all builds can support using a docker container as the node yet, and builds will have issues when ran in parallel on the master node.
Is there a way for a docker pipeline file to determine the image of the child node it runs on?
There are a few options I have considered but not attempted yet:
Migrate jobs to run on the "docker cloud" until all jobs support running on child container nodes, then move the configuration from Jenkins to the pipeline build file for each job and turn on parallel builds on the master node.
Attempt to add a new node configuration which is effectively a copy of master (uses the same server, just different location). Configure it to support parallel builds, and have all migrated jobs target the node explicitly during builds.

How do I pass on my build file from Jenkins to Saltstack master

We have a Jenkins system to automate build from Github, now we are implementing a Saltstack system. So I need to integrate my Jenkins with Salt-master so that it passes all the new builds to the master which then sends it across the salt-clients(minions).
The saltstack setup is in AWS cloud and and the Jenkins machine is outside the cloud in a local setup.
You could enable the salt-api and using the following plugin: https://wiki.jenkins-ci.org/display/JENKINS/saltstack-plugin then all of your jenkins builds can execute states / orchestrations etc. to any minions on a per job basis.
Another way of doing this is to have a minion running on the salt-master and install the jenkins slave on the same box. Then restrict the jenkins jobs to that jenkins slave and execute the commands as if you were at the command line. NOTE: this option requires a bit more configuration.

Jenkins - Run job when new slave connects

I have a Jenkins installation uses SWARM to connect new slaves.
I bring up new instances in AWS and they use the SWARM Client to connect to the Jenkins master and register themselves as slaves.
Is it possible to have the Jenkins Master detect when a new slave is added and start to run some "init" job on that slave?
Thanks
We use the Slave Setup Plugin to mount a network drive and copy some files from the master whenever a slave connects.
If you want to run certain Jenkins jobs whenever a slave (or certain slave) connects, you could try the Startup Trigger Plugin.
There is the EC2 plugin which will spin up slaves on your behalf and run an init script on them for you.
Init script is the shell script to be run on the newly launched EC2
instance, before Jenkins starts launching a slave agent. If the AMI
doesn't have Java pre-installed, you can do this in the init script.
This is also a good place to install additional packages that you need
for your builds and tests. The init script is located at /tmp/init.sh
and is owned and run by the user account specified in the "Remote
User" field (so use of "sudo" may be required for non-root accounts).

Resources