There are a few advantages of installing Jenkins using Docker. These advantages include faster delivery, more scalability, and easier management. Here we will create a bash script to install Jenkins with that approach. Then, we will transform that script into an Ansible playbook with the shell module.
For this example, I will use CentOS 7. You can find specific instructions to install Docker on multiple platforms on the Docker official website. There are instructions available for Windows, several Linux distributions, and Mac
Let us begin by creating a bash script first for a “standard” Jenkins installation with Docker:
#!/bin/bash
# 1) Update Linux packages
yum update -y
# 2) Install Docker Engine and Docker Compose Pluging
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 3) Configuring Docker service
systemctl start docker
usermod -aG docker $USER
systemctl enable docker
# 4) Downloading Docker image for Jenkins
docker pull jenkins/jenkins
# 5) Creating docker-compose file for the Jenkins image
mkdir -p /var/jenkins/jenkins-data
mkdir -p /var/jenkins/jenkins-logs
cd /var/jenkins/jenkins-data
cat <<EOF > docker-compose.yaml
version: '3'
services:
jenkins:
image: jenkins/jenkins
container_name: jenkins
hostname: jenkins
ports:
- "8080:8080"
volumes:
- /var/jenkins/jenkins-data:/var/jenkins_home
- /var/jenkins/jenkins-logs:/var/jenkins_logs
labels:
service: "jenkins-master"
restart: unless-stopped
networks:
- net
networks:
net:
EOF
# 6) Executing docker compose
chown 1000:1000 /var/jenkins/jenkins-data
chown 1000:1000 /var/jenkins/jenkins-logs
cd /var/jenkins/jenkins-data
docker compose up -d
sleep 20
# 7) Finishing the installation
jenkinsIP=$(ip a s eth0 | grep "inet " | awk '{print $2}')
jenkinsIP=${jenkinsIP%/*}
echo "Jenkins will be available at http://$jenkinsIP:8080"
echo "..."
echo "Use the following password for the initial setup:"
cat /var/jenkins/jenkins-data/secrets/initialAdminPassword
Creating an Ansible playbook to install Jenkins
Now we can translate this script into an Ansible playbook. The easiest way will be to use the shell module since we already have the bash commands required for the installation. As it was stated earlier, this playbook will install everything in a CentOS 7 host. A few considerations about this playbook:
- It will run without an inventory file. Instead of that, we will provide the IP of the CentOS 7 target server when calling the ansible-playbook command.
- All the required variables will be in the playbook or passed in the command line.
- Privilege escalation will be activated (become=yes) with the “–ask-become-pass” option, so we will have to type the become password in the terminal.
- Using debug we registered the commands at the end of the playbook to show the IP and the initial password of the new Jenkins instance.
The playbook looks like this:
- name: Installing Jenkins with Docker
gather_facts: true
hosts: "{{ target }}"
tasks:
- name: Updating Linux
shell: |
yum update -y
- name: Installing Docker
shell: |
yum install -y yum-utils > /dev/null
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
- name: Configuring Docker service
shell: |
systemctl start docker
usermod -aG docker $USER
systemctl enable docker
- name: Downloading Docker image for Jenkins
shell: |
docker pull jenkins/jenkins
- name: Creating docker-compose file for the Jenkins image
shell: |
mkdir -p /var/jenkins/jenkins-data
mkdir -p /var/jenkins/jenkins-logs
cd /var/jenkins/jenkins-data
cat <<EOF > docker-compose.yaml
version: '3'
services:
jenkins:
image: jenkins/jenkins
container_name: jenkins
hostname: jenkins
ports:
- "8080:8080"
volumes:
- /var/jenkins/jenkins-data:/var/jenkins_home
- /var/jenkins/jenkins-logs:/var/jenkins_logs
labels:
service: "jenkins-master"
restart: unless-stopped
networks:
- net
networks:
net:
EOF
- name: Executing docker compose
shell: |
chown 1000:1000 /var/jenkins/jenkins-data
chown 1000:1000 /var/jenkins/jenkins-logs
cd /var/jenkins/jenkins-data
docker compose up -d
sleep 20
- name: Finishing installation
shell: |
jenkinsIP=$(ip a s eth0 | grep "inet " | awk '{print $2}')
jenkinsIP=${jenkinsIP%/*}
echo "Jenkins will be available at http://$jenkinsIP:8080"
echo "..."
echo "Use the following password for the initial setup:"
cat /var/jenkins/jenkins-data/secrets/initialAdminPassword
register: result
- name: Showing Jenkins information
debug:
msg: "{{ result.stdout_lines }}"
To call it, I used the following command (my Cent0S 7 had the 192.168.100.21 IP assigned)
ansible-playbook --ask-pass --ask-become-pass jenkins_playbook.yml -i 192.168.100.21, -e "target=192.168.100.21 ansible_user=zaratustra ansible_become=yes host_key_checking=false"
Let us break down the ansible-playbook call command:
- Ask pass and ask become pass for the SSH and the become password to execute the playbook.
- In the inventory, instead of a file, we used the IP. Notice the comma at the end of the IP after the -I switch.
- As extra vars we pass the IP of the Cent0S 7 target host, the ansible user, the become directive and the host key checking. You will want to modify those vars according to your requirements.
After we call the playbook, it will ask for the corresponding passwords. Successful output will look like this:
andreypicado@YourITGuy:/$ ansible-playbook --ask-pass --ask-become-pass jenkins_playbook.yml -i 192.168.100.21, -e "target=192.168.100.21 ansible_user=andreypicado ansible_become=yes host_key_checking=false"
SSH password:
BECOME password[defaults to SSH password]:
PLAY [Installing Jenkins with Docker] ************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************
ok: [192.168.100.21]
TASK [Updating Linux] ****************************************************************************************************************************************************
changed: [192.168.100.21]
TASK [Installing Docker] *************************************************************************************************************************************************
changed: [192.168.100.21]
TASK [Configuring Docker service] ****************************************************************************************************************************************
changed: [192.168.100.21]
TASK [Downloading Docker image for Jenkins] ******************************************************************************************************************************
changed: [192.168.100.21]
TASK [Creating docker-compose file for the Jenkins image] ****************************************************************************************************************
changed: [192.168.100.21]
TASK [Executing docker compose] ******************************************************************************************************************************************
changed: [192.168.100.21]
TASK [Finishing installation] ********************************************************************************************************************************************
changed: [192.168.100.21]
TASK [Showing Jenkins information] ***************************************************************************************************************************************
ok: [192.168.100.21] => {
"msg": [
"Jenkins will be available at http://192.168.100.21:8080",
"...",
"Use the following password for the initial setup:",
"deb7fd7aa4054b15a816a7a5f9e63978"
]
}
PLAY RECAP ***************************************************************************************************************************************************************
192.168.100.21 : ok=9 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0