Installs and completely configures Jenkins using Ansible.
This role is used when you want all your Jenkins configuration in version control so you can deploy Jenkins repeatably and reliably and you can treat your Jenkins as a Cow instead of a Pet.
If you are looking for a role to install Jenkins and you want to configure everything through the web interface and you don't care about being able to repeatably deploy this same fully-configured Jenkins, then you don't need this role. Instead, have a look at the geerlingguy/ansible-role-jenkins role instead.
If deploying using Docker, then you need Docker installed on the server. Docker, apt-get, and yum are the only supported ways at the moment although more ways can easily be added, PRs welcome.
Install using Ansible Galaxy:
$ ansible-galaxy install emmetog.jenkins
The following variables influence how Jenkins is installed:
jenkins_install_via
: Controls how Jenkins is installed. Important: This
variable must be defined to one of the following values:
docker
: Install in a Docker containerapt
: Install Jenkins directly on Ubuntu/Debian Linux systemsyum
: Install Jenkins directly on RedHat/CentOS Linux systemsjenkins_version
: The exact version of Jenkins to installThe following variables influence how Jenkins is configured:
jenkins_url
: The URL that Jenkins will be accessible onjenkins_port
: The port that Jenkins will listen onjenkins_home
: The directory on the server where the Jenkins configs will
livejenkins_admin
: The administrator's email address for the Jenkins serverjenkins_java_opts
: Options passed to the Java executablejenkins_config_owner
: Owner of Jenkins configuration filesjenkins_config_group
: Group of Jenkins configuration filesjenkins_auth
: How Ansible should authenticate itself with Jenkins, (see the
"Authentication and Security" section below)jenkins_url_health_check
: which url to use for the health check after jenkins is started (defaults to jenkins_url
)jenkins_health_check_user
: if defined, uses basic auth (see API token section) for health check with this username (useful if you set up e.g. Google OAuth)jenkins_health_check_password
: if defined, uses basic auth (see API token section) for health check with this password (useful if you set up e.g. Google OAuth)The following list variables influence the jobs/plugins that will be installed in Jenkins:
jenkins_jobs
: List of names of the jobs to copy to Jenkins. The config.xml
file must exist under jenkins_source_dir_jobs/<job_name>
jenkins_plugins
: List of plugin IDs to install on Jenkins.jenkins_custom_plugins
: List of custom plugins to install on Jenkins.For a complete list of variables, see defaults/main.yml
.
- hosts: jenkins
vars:
jenkins_version: "2.73.1"
jenkins_hostname: "jenkins.example.com"
jenkins_port: 8080
jenkins_install_via: "docker"
jenkins_jobs:
- "my-first-job"
- "another-awesome-job"
jenkins_include_secrets: true
jenkins_include_custom_files: true
jenkins_custom_files:
- src: "jenkins.plugins.openstack.compute.UserDataConfig.xml"
dest: "jenkins.plugins.openstack.compute.UserDataConfig.xml"
jenkins_plugins:
- git
- blueocean
jenkins_custom_plugins:
- "openstack-cloud-plugin/openstack-cloud.jpi"
roles:
- emmetog.jenkins
The example above will look for job configuration files in
{{ playbook_dir }}/jenkins-configs/jobs/my-first-job/config.xml
and
{{ playbook_dir }}/jenkins-configs/jobs/another-awesome-job/config.xml
.
NOTE: These directories are customizable, see the
jenkins_source_dir_configs
and jenkins_source_dir_jobs
role variables.
The role will also look for {{ playbook_dir }}/jenkins-configs/config.xml
This config.xml
file will be copied to the server and used as the job
configuration template.
The above example will also upload the entire secrets directory under
{{ playbook_dir }}/jenkins-configs/secrets
, and also copy custom files
defined in the {{ jenkins_custom_files }}
variable. Note that
{{ jenkins_include_secrets }}
and {{ jenkins_include_custom_files }}
variables should be set to true
for features these to work. Additionally,
the role can install custom plugins by providing the .jpi or .hpi files in the
{{ jenkins_custom_plugins }}
list variable.
The config.xml
and the custom files are treated as templates so you can put
variables in them, including sensitive data from the Ansible vault.
When you want to make a change in a configuration file, or you want to add a new item (such as a job, plugin, etc) the normal workflow is:
jenkins_jobs
jenkins_include_custom_files
jenkins_custom_plugins
In {{ jenkins_source_dir_configs }}/config.xml
you put your global Jenkins
configuration, for example:
<?xml version='1.1' encoding='UTF-8'?>
<hudson>
<disabledAdministrativeMonitors/>
<version>2.176.1</version>
<installStateName>RESTART</installStateName>
<numExecutors>1</numExecutors>
<mode>EXCLUSIVE</mode>
<useSecurity>true</useSecurity>
<authorizationStrategy class="hudson.security.AuthorizationStrategy$Unsecured"/>
<securityRealm class="hudson.security.HudsonPrivateSecurityRealm">
<disableSignup>false</disableSignup>
<enableCaptcha>false</enableCaptcha>
</securityRealm>
<disableRememberMe>false</disableRememberMe>
<projectNamingStrategy class="jenkins.model.ProjectNamingStrategy$DefaultProjectNamingStrategy"/>
<workspaceDir>${JENKINS_HOME}/workspace/${ITEM_FULLNAME}</workspaceDir>
<buildsDir>${ITEM_ROOTDIR}/builds</buildsDir>
<markupFormatter class="hudson.markup.EscapedMarkupFormatter"/>
<jdks/>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<myViewsTabBar class="hudson.views.DefaultMyViewsTabBar"/>
<clouds/>
<quietPeriod>0</quietPeriod>
<scmCheckoutRetryCount>0</scmCheckoutRetryCount>
<views>
<hudson.model.AllView>
<owner class="hudson" reference="../../.."/>
<name>all</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
</hudson.model.AllView>
</views>
<primaryView>all</primaryView>
<slaveAgentPort>0</slaveAgentPort>
<disabledAgentProtocols>
<string>JNLP-connect</string>
<string>JNLP2-connect</string>
</disabledAgentProtocols>
<label>master</label>
<crumbIssuer class="hudson.security.csrf.DefaultCrumbIssuer">
<excludeClientIPFromCrumb>false</excludeClientIPFromCrumb>
</crumbIssuer>
<nodeProperties/>
<globalNodeProperties/>
</hudson>
Here's an example of what you could put in
{{ playbook_dir }}/jenkins-configs/jobs/my-first-job/config.xml
:
<?xml version='1.0' encoding='UTF-8'?>
<project>
<actions/>
<description>My first job, it says "hello world"</description>
<keepDependencies>false</keepDependencies>
<properties/>
<scm class="hudson.scm.NullSCM"/>
<canRoam>true</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers/>
<concurrentBuild>false</concurrentBuild>
<builders>
<hudson.tasks.Shell>
<command>echo "Hello World!"</command>
</hudson.tasks.Shell>
</builders>
<publishers/>
<buildWrappers/>
</project>
This role supports the following authentication mechanisms for Jenkins:
API token-based authentication
API token-based authentication is recommended, but requires a bit of extra effort to configure. The advantage of API tokens is that they can be easily revoked in Jenkins, and their usage is also tracked. API tokens also do not require getting a crumb token, which has become more difficult since Jenkins version 2.172.2 (see this security bulletin.
To create an API token, you'll need to do the following:
jenkins_auth: "api"
jenkins_api_token: "(defined in the Anible vault)"
jenkins_api_username: "(defined in the Ansible vault)"
$JENKINS_HOME/users/the_username/config.xml
,
where the_username
corresponds to the user which owns the API token you
just created.jenkins_custom_files
list, like so:jenkins_custom_files:
- src: "users/the_username/config.xml"
dest: "users/the_username/config.xml"
Note that you may need to change the src
value, depending on where you save
the file on the control machine relative to the playbook.
Crumb-based authentication
Crumb-based authentication can be used to prevent cross-site request forgery attacks and is recommended if API tokens are impractical. Note: crumb-based authentication only works with the "Anyone can do anything" access control setting. If your Jenkins configuration requires a stricter security setup, you should use API tokens (documented above).
Crumb-based authentication can also be a bit tricky to configure due to recent security fixes in Jenkins. To configure CSRF, you'll need to do the following:
strict-crumb-issuer
ID to the jenkins_plugins
list.config.xml
file to the control host.Likewise, for the above to work, you'll need at least Ansible 2.9.0pre5 or 2.10 (which are, at the time of this writing, both in development. See this Ansible issue for more details).
If you want to enable HTTPS on Jenkins, this can be done as follows:
jenkins_port_https
to the port that Jenkins should listen onjenkins_https_keystore
: Path to the keystore file on the control host,
which will be copied to the Jenkins server by this role.jenkins_https_keystore_password
: Password for said JKS keystore. Use of
the Ansible vault is recommended for this. IMPORTANT: This string
will be written in plaintext to the Jenkins configuration file on the
server. It will also be visible in the server's process list. Consider
migrating your certificate to a signed certificate file (see below).jenkins_https_certificate
: Path to the certificate file, which will be
copied to the Jenkins server by this role. Use of the Ansible vault is
recommended for this file.jenkins_https_private_key
: Private key for said CA signed certificate.
Use of the Ansible vault is recommended for this file.jenkins_https_validate_certs
should be defined to false
if
you are using a self-signed certificate.If you are deploying Jenkins with Docker, then using a reverse proxy such as jwilder/nginx-proxy or traefik is recommended instead of configuring Jenkins itself. This gives a bit more flexibility and allows for separation of responsibilities. See the documentation in those projects for more details on how to deploy the proxies and configure HTTPS.
If using a reverse proxy in front of the Jenkins instance and deploying using
Docker you probably want to set the jenkins_docker_expose_port
variable to
false so that the port is not exposed on the host, only to the reverse proxy.
MIT
Made with love by Emmet O'Grady.
I am the founder of NimbleCI which builds Docker containers for feature branch workflow projects in Github.
I blog on my personal blog and about Docker related things on the NimbleCI blog.