Skip to content

explicit-logic/ansible-module-15.7

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Module 15 - Configuration Management with Ansible

This repository contains a demo project created as part of my DevOps studies in the TechWorld with Nana – DevOps Bootcamp.

Demo Project: Ansible Integration in Jenkins

Technologies used: Ansible, Jenkins, DigitalOcean, AWS, Boto3, Docker, Java, Maven, Linux, Git

Project Description:

  • Create and configure a dedicated server for Jenkins
  • Create and configure a dedicated server for Ansible Control Node
  • Write Ansible Playbook, which configures 2 EC2 Instances
  • Add ssh key file credentials in Jenkins for Ansible Control Node server and Ansible Managed Node servers
  • Configure Jenkins to execute the Ansible Playbook on remote Ansible Control Node server as part of the CI/CD pipeline
  • So the Jenkinsfile configuration will do the following:
    • a.Connect to the remote Ansible Control Node server
    • b.Copy Ansible playbook and configuration files to the remote Ansible Control Node server
    • c.Copy the ssh keys for the Ansible Managed Node servers to the Ansible Control Node server
    • d.Install Ansible, Python3 and Boto3 on the Ansible Control Node server
    • e.With everything installed and copied to the remote Ansible Control Node server, execute the playbook remotely on that Control Node that will configure the 2 EC2 Managed Nodes

Overview

The pipeline runs on Jenkins, copies the Ansible files to a remote Ansible Control Node, and from there runs a playbook that configures 2 EC2 Managed Nodes. Ansible is agentless, so only the control node needs Ansible installed β€” the managed nodes are reached over plain SSH.

1. Create and configure a dedicated server for Jenkins

Install Jenkins on DigitalOcean following the earlier modules:

2. Create and configure a dedicated server for the Ansible Control Node

  • Create a droplet on DigitalOcean
Setting Value
CPU Option Regular
vCPU 2
RAM 2 GB
Disk 60 GB

Name it ansible-server.

Connect to the droplet and install Ansible. ansible-core ships the ansible-playbook binary used later in the pipeline:

ssh root@<PUBLIC-IP>
apt update
apt install ansible-core

πŸ“š Ansible installation guide

Install the AWS SDK packages boto3 / botocore. Ansible's aws_ec2 dynamic inventory plugin uses them to query AWS for the managed nodes at runtime, so you never hardcode the EC2 IP addresses:

apt install python3-boto3

πŸ“š amazon.aws.aws_ec2 inventory plugin

Configure AWS credentials so the plugin can authenticate against your account:

mkdir .aws
vim .aws/credentials

Copy in your local default credentials (view them with cat ~/.aws/credentials):

[default]
aws_access_key_id = <YOUR_ACCESS_KEY_ID>
aws_secret_access_key = <YOUR_SECRET_ACCESS_KEY>

πŸ“š AWS CLI β€” configuration and credential file settings

Exit the server.

3. Create 2 EC2 instances to be managed by Ansible

Launch 2 Amazon Linux EC2 instances. Create a new key pair named ansible-jenkins and download the .pem file β€” Ansible will use it to SSH into the managed nodes as user ec2-user.

4. Write the Ansible Playbook that configures the EC2 instances

Everything the control node needs lives in the ansible/ directory.

ansible.cfg β€” points Ansible at the dynamic inventory and sets the SSH user and key used to reach the managed nodes:

[defaults]
host_key_checking = False
inventory = inventory_aws_ec2.yaml

enable_plugins = aws_ec2

remote_user = ec2-user
private_key_file = ~/ssh-key.pem

πŸ“š Ansible configuration settings

inventory_aws_ec2.yaml β€” the dynamic inventory. Set regions to the region your instances run in:

---
plugin: aws_ec2
regions:
  - eu-central-1
keyed_groups:
  - key: tags
    prefix: tag
  - key: instance_type
    prefix: instance_type

my-playbook.yaml β€” installs Docker and the Docker Compose plugin on every managed node:

---
- name: Install Docker
  hosts: all
  become: yes
  tasks:
    - name: Install Docker
      yum:
        name: docker
        update_cache: yes
        state: present
    - name: Start docker daemon
      systemd:
        name: docker
        state: started

- name: Install Docker-compose
  hosts: all
  tasks:
    - name: Create docker-compose directory
      file:
        path: ~/.docker/cli-plugins
        state: directory
    - name: Get architecture of remote machine
      shell: uname -m
      register: remote_arch
    - name: Install docker-compose
      get_url:
        url: "https://github.com/docker/compose/releases/latest/download/docker-compose-linux-{{ remote_arch.stdout }}"
        dest: ~/.docker/cli-plugins/docker-compose
        mode: +x

πŸ“š Modules used: ansible.builtin.yum Β· ansible.builtin.systemd_service Β· ansible.builtin.file Β· ansible.builtin.get_url

5. Add SSH key credentials in Jenkins

The pipeline needs two SSH keys: one to reach the control node (DigitalOcean root key) and one to reach the managed nodes (the EC2 key pair).

a. Control Node key β€” add a global credential in Jenkins

  • Kind: SSH Username with private key
  • ID: ansible-server-key
  • Username: root

Jenkins requires the classic PEM (RSA) key format. Convert the key you used to create ansible-server in place:

ssh-keygen -p -f ~/.ssh/id_rsa -m pem -P "" -N ""

Verify the first line now reads -----BEGIN RSA PRIVATE KEY-----:

cat ~/.ssh/id_rsa

Copy the whole value into Jenkins.

πŸ“š Jenkins β€” using SSH credentials Β· SSH Credentials plugin

b. Managed Node key β€” add a second global credential

  • Kind: SSH Username with private key
  • ID: ec2-server-key
  • Username: ec2-user

Copy in the downloaded EC2 key:

cat ~/Downloads/ansible-jenkins.pem

6. Jenkinsfile β€” copy files to the Ansible Control Node

This stage uses an ANSIBLE_SERVER build parameter (the public IP of the control node) and the two credentials above. It scps the contents of ansible/ to the control node and drops the EC2 key there as ssh-key.pem (the path ansible.cfg expects).

      stage("copy files to ansible server") {
          steps {
              script {
                echo "copying all neccessary files to ansible control node"
                withCredentials([sshUserPrivateKey(credentialsId: 'ansible-server-key', keyFileVariable: 'PK')]) {
                  sh 'scp -o StrictHostKeyChecking=no -i $PK ansible/* root@$ANSIBLE_SERVER:/root'

                  withCredentials([sshUserPrivateKey(credentialsId: 'ec2-server-key', keyFileVariable: 'keyFile')]) {
                    sh 'scp -o StrictHostKeyChecking=no -i $PK $keyFile root@$ANSIBLE_SERVER:/root/ssh-key.pem'
                  }
                }
              }
          }
      }

⚠️ Note the single quotes around the sh steps. They let the shell β€” not Groovy β€” expand $PK / $keyFile, which keeps the secret out of the interpolated Groovy string (Jenkins warns about this otherwise).

πŸ“š withCredentials / sshUserPrivateKey Β· Handling credentials in a Jenkinsfile

7. Create the Jenkins pipeline

  • Create a new item in Jenkins
  • Name: ansible-pipeline
  • Type: Pipeline

Configure Pipeline script from SCM:

Run it with Build with Parameters, setting ANSIBLE_SERVER to the control node's public IP.

Connect to the Ansible server and confirm the files transferred:

ssh root@<ansible-server-ip>
ls

8. Jenkinsfile β€” execute the Ansible Playbook on the Control Node

Install the Jenkins plugin SSH Pipeline Steps β€” it provides the sshCommand and sshScript steps.

πŸ“š SSH Pipeline Steps plugin Β· step reference

Add the stage below. Start with ls -l to confirm the SSH connection to the control node works:

      stage("execute ansible playbook") {
        steps {
          script {
            echo "calling ansible playbook to configure ec2 instances"

            def remote = [:]
            remote.name = "ansible-server"
            remote.host = "$ANSIBLE_SERVER"
            remote.allowAnyHosts = true
            withCredentials([sshUserPrivateKey(credentialsId: 'ansible-server-key', keyFileVariable: 'keyFile', usernameVariable: 'user')]) {
              remote.user = user
              remote.identityFile = keyFile
              sshCommand remote: remote, command: "ls -l"
            }
          }
        }
      }

Once the connection works, replace ls -l with the playbook run:

sshCommand remote: remote, command: "ansible-playbook my-playbook.yaml"

9. (Optional) Prepare the Control Node automatically

Instead of installing Ansible/Boto3 on the control node by hand (step 2), let the pipeline do it. prepare-ansible-server.sh installs the prerequisites:

#!/usr/bin/env bash

apt update
apt install ansible -y
apt install python3-boto3

Run it from the pipeline with sshScript, just before the playbook command:

sshScript remote: remote, script: "prepare-ansible-server.sh"
sshCommand remote: remote, command: "ansible-playbook my-playbook.yaml"

Execute the pipeline.

Verify Docker landed on an EC2 managed node:

mv ~/Downloads/ansible-jenkins.pem ~/.ssh
chmod 400 ~/.ssh/ansible-jenkins.pem
ssh -i ~/.ssh/ansible-jenkins.pem ec2-user@<ec2-ip-address>
docker version
docker compose version

Clean up

To avoid ongoing charges once the demo is done:

  • Terminate the 2 EC2 instances
  • Delete the ansible-jenkins EC2 key pair
  • Destroy the ansible-server DigitalOcean droplet (and the Jenkins droplet if no longer needed)
  • Remove the ansible-server-key and ec2-server-key credentials from Jenkins

About

Ansible Integration in Jenkins

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors