I'm back!
What do we have today, I'm in progress to systemize the process to create some machine types for my job.
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 usersSolution:
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!
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.
ReplyDeleteThanks for your note, Soumya! I will try to write more on devops
DeleteThanks - this was a very useful guide.
ReplyDeleteI 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!
Thanks! Maybe Jenkins has changed their security mode, CSRF is a security hole of it but we can't do automation without it.
DeleteMy notes here are the run book that keep my experience and it's very happy that they can help others.
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
ReplyDeleteI 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