Set up Jenkins with Ansible

I'm back!

What do we have today, I'm in progress to systemize the process to create some machine types for my job. 

Use Case:

We will have a plan to have build each type of machine via ansible. The target is using ansible role but for now, I will build each piece first then the integration will be under ansible role. So now, a simple mission is to build up a Jenkins master and prepare from basic configuration such as plugin, jobs and admin users

Solution:

Create a bare machine that ansible server can connect to run the remote command. Then we can use the installation steps from Jenkins to implement a playbook in ansible. So there are some steps as below:

  • Include the sudo password from vault secret
  • Install jre8
  • Add jenkins repo to source list
  • Add jenkins repo key
  • Install jenkins
  • Install git
Below is a sample playbook


---
- hosts: jenkins
  vars_files:
   - credentials.yml
  tasks:
  - name: install jre8
    apt:
     name: openjdk-8-jre
     state: present
     update_cache: yes
    become: true

  - name: add jenkins repo key
    apt_key:
     url: https://pkg.jenkins.io/debian/jenkins.io.key
     state: present
    become: true

  - name: add jenkins repo list file into sources.list.d
    apt_repository:
     repo: deb http://pkg.jenkins.io/debian-stable binary/
     state: present
    become: true

  - name: install jenkins
    apt:
     name: jenkins=[version]
     state: present
     update_cache: yes
    become: true

  - name: install git
    apt:
     name: git
     state: present
    become: true


Then Jenkins is ready now, unless you open http://[jenkins]:8080 and do manual step in the wizard to complete the setup progress. How to bypass those manual steps that we have to do the same every time, here come the good part. I read from here for get over it. So this script is good in order to put into the groovy startup under init.groovy.d as this recommendation to get away the Unlock Jenkins step and create an admin user (first user but not 'admin' user)

#!groovy

import jenkins.model.*
import hudson.security.*

def instance = Jenkins.getInstance()

println "--> creating local user 'admin'"

def hudsonRealm = new HudsonPrivateSecurityRealm(false)
hudsonRealm.createAccount('{{ jenkins_admin_username }}','{{ jenkins_admin_password }}')
instance.setSecurityRealm(hudsonRealm)

def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
strategy.setAllowAnonymousRead(false)
instance.setAuthorizationStrategy(strategy)
instance.save()
 
However, since ansible 2.4, they have jenkins_script module that supports running a groovy script on remote machine, so why bother to do a lot of stuffs to create the init directory, copy a groovy script file where we can have just a small script into our playbook. But, again, although this has set the user but we still can't complete setup wizard yet, I found this great comment to fix this up.

import static jenkins.model.Jenkins.instance as jenkins
import jenkins.install.InstallState
if (!jenkins.installState.isSetupComplete()) {
  InstallState.INITIAL_SETUP_COMPLETED.initializeState()
}

Then the next step is to install the Jenkins plugin as the wizard, so I follow this note to read all the plugins that we have on the current Jenkins to have a standard plugin list and we have this guide show how to use script to install Jenkins plugin then I can put this script within the init groovy for the installation. 

import jenkins.model.* 

def installed = false 
def plugins = ['script-security', 'command-launcher']

def instance =Jenkins.getInstance() 
def pm = instance.getPluginManager() 
def uc = instance.getUpdateCenter() 
uc.updateAllSites()

plugins.each {
  if(!pm.getPlugin(it)) {
    def plugin = uc.getPlugin(it)
    if (plugin) {
      plugin.deploy()
      installed = true
    }
  }
}

if (installed) {  
  instance.save()  
  //instance.doSafeRestart() // do not restart here as we put this in the init script, it will run into an infinite loop
}


Again, ansible has gives us a hand, there is jenkins_plugin module since ansible 2.2 that will do what we need. So those tasks can be like this in the playbook (read the admin password $JENKINS_HOME/secrets/initialAdminPassword)

  - name: read admin pwd
    shell: cat /var/lib/jenkins/secrets/initialAdminPassword
    register: adminpwd

  - name: unlock and add admin user
    jenkins_script:
     script: |
      import jenkins.model.*
      import hudson.security.*
      def instance = Jenkins.getInstance()
      def hudsonRealm = new HudsonPrivateSecurityRealm(false)
      hudsonRealm.createAccount('jenkins', '${user_pwd}')
      instance.setSecurityRealm(hudsonRealm)
      def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
      strategy.setAllowAnonymousRead(false)
      instance.setAuthorizationStrategy(strategy)
      instance.save()
     args:
      user_pwd: "{{ admin_user_pass }}"
     user: admin
     password: "{{ adminpwd.stdout }}"

  - name: complete setup wizard
    jenkins_script:
     script: |
      import static jenkins.model.Jenkins.instance as jenkins
      import jenkins.install.InstallState
      if (!jenkins.installState.isSetupComplete()) {
        InstallState.INITIAL_SETUP_COMPLETED.initializeState()
      }
     user: admin
     password: "{{ adminpwd.stdout }}"

  - name: install plugin
    jenkins_plugin:
     name: "{{ item }}"
     state: latest
     url_username: admin
     url_password: "{{ adminpwd.stdout }}"
    with_items: "{{ jenkins_plugins }}"

I define a plugin list jenkins_plugins in group_vars.

Then, what next? Alright, I will copy the config.xml and jobs config from a stable (source template to this new jenkins. How I should implement this? Let keep a stable jenkins configuration and job configuration into Git, then at least we have a source template then now I clone those configuration from Git and copy it into $JENKINS_HOME. Before doing that, I have to set up this machine that can connect to Git. For my case, I will copy the ssh keys of the git user into this machine, make sure the git machine rsa key will be added into known_hosts of my new jenkins (under .ssh directory). So those tasks below are specific to my environment then I just list out the task but not the playbook code
  • Copy git ssh key and known_hosts to discover git server
  • Clone git data (config.xml and job configuration)
  • Stop jenkins service
  • Copy git data to $JENKINS_HOME
  • Start jenkins service
So now, you have to do some minor setup to make it ready for production.

Sure, there should be some more tasks to fine tune this setup. But you can start from here!

Good luck!


Comments

  1. I read this blog it's really good, I would like to say thanks to you for sharing this valuable content on Devops Online Training Hyderabad, Please share more content on devops.

    ReplyDelete
    Replies
    1. Thanks for your note, Soumya! I will try to write more on devops

      Delete
  2. Thanks - this was a very useful guide.
    I needed a few tweaks to get it working, including a Jenkins JAVA_ARG setting to bypass a CSRF issue in the latest version:

    - name: Ensure groovy csrf error is bypassed
    become: yes
    lineinfile:
    path: /etc/default/jenkins
    line: 'JAVA_ARGS="$JAVA_ARGS -Dhudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID=true"'
    create: yes

    And I needed to re-start Jenkins after doing this before I ran your unlock and complete steps above.

    But your guide gave me 90% of what I needed. Nice job!

    ReplyDelete
    Replies
    1. Thanks! Maybe Jenkins has changed their security mode, CSRF is a security hole of it but we can't do automation without it.
      My notes here are the run book that keep my experience and it's very happy that they can help others.

      Delete
  3. jenkins_script module can we run on https jenkins connection. I tried with url and validate_certs: no but didnt work,it fails with an error DH_Key_TOO_SMALL

    ReplyDelete
    Replies
    1. I haven't tried to use jenkins setup or execute jenkins_script via HTTPS. If your question on execute jenkins_script module to a jenkins server under TLS then I'm doubt of it because you have to setup a valid key cert in Ansible to talk with your jenkins server.

      Delete

Post a Comment