The goal is to implement Devops best practices to use Terraform for provisioning and Ansible to configure your server in Jenkins Pipelines. We will go over the main concepts that need to be considered and a Jenkinsfile that runs Terraform and Ansible. The Jenkinsfile will consists of parameters that allows us to pass data as variables in our pipeline job.
- Install Terraform on Jenkins Server
- Install Python on Jenkins Server
- Install Ansible on Jenkins Server
- Install Terraform & Credentials Plugin on Jenkins
- Configure Terraform
- Store and Encrypt Credentials in Jenkins
- Setting up CD Pipeline with Terraform + Ansible to Deploy Nginx
- Playbook to Deploy Nginx
- Run Pipeline Job
Install Terraform on Jenkins Server
Use the following commands to install Terraform on Jenkins server and move the binaries to the correct path as shown below.
- sudo apt install unzip
- wget https://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_linux_amd64.zip
- unzip terraform_0.12.24_linux_amd64.zip
- sudo mv terraform /usr/bin/
Install Python on Jenkins Server
Use the following commands to install Python on Jenkins server
sudo apt-get update sudo apt-get install python-minimal -y python --version
Install Ansible on Jenkins Server
Use the following commands to install Ansible on Jenkins server
- sudo apt-get update
sudo apt-get install software-properties-common
- sudo apt-add-repository ppa:ansible/ansible
- sudo apt-get update
- sudo apt install ansible
- ansible --version
- (Note: Ansible version should show 2.9.27 or higher)
Install Terraform & Credentials plugin on Jenkins
Go to Manage Jenkins > Manage Plugins >Available > search Terraform as shown below:
As you can see, Terraform Plugin is already installed on my Jenkins hence why it's displayed in the Installed section.
Store and Encrypt Credentials in Jenkins (Access and Secret Key)
In this step, we will be storing and encrypting the access and secret key in Jenkins to maximize security and minimize the chances of exposing our credentials.
- Go to Manage Jenkins > Manage Credentials > Click on Jenkins the highlighted link as shown below
- Select Add Credentials
- Choose Secret text in the Kind field
- Enter the following below:
- Secret = EnterYourSecretKeyHere
- ID = AWS_SECRET_ACCESS_KEY
- Description = AWS_SECRET_ACCESS_KEY
- Secret = EnterYourAccessIDHere
- ID = AWS_ACCESS_KEY_ID
- Description = AWS_ACCESS_KEY_ID
Click OK
- Choose SSH Username with private key in the Kind field
- ID = ENTER-KEY-NAME
- DESCRIPTION = ENTER-KEY-NAME
- DESCRIPTION = ENTER-KEY-NAME
- PRIVATE KEY = ENTER-PRIVATE-KEY
Click OK
Configure Terraform
Go to Manage Jenkins > Global Tool Configuration > It will display Terraform on the list.
- Enter terraform in the Name field
- Provide the path /usr/bin/ as shown below

Setting up CD Pipeline with Terraform + Ansible to Deploy Nginx
- Go to Jenkins > New Items. Enter nginx-pipeline in name field > Choose Pipeline > Click OK
Bitbucket Changes
- Create a new Bitbucket Repo and call it nginx-pipeline
- Go to Repository Settings after creation and select Webhooks
- Click Add Webhooks
- Enter tf_token as the Title
- Copy and paste the url as shown below
- Status should be active
- Click on skip certificate verification
- triggers --> repository push
- Go back to Jenkins and select Configure
- Scroll down to Pipeline and click on the drop down to select Pipeline Script From SCM
- Enter credentials for Bitbucket, Leave the Branch master as the default, Make sure script path is Jenkinsfile
- Right click on Pipeline Syntax and open in a new tab.
- Choose Checkout from Version Control in the Sample Step field
- Enter Bitbucket Repository URL and Credentials, leave the branches blank
- Click GENERATE PIPELINE SCRIPT, copy credentialsId and url (This is required for Jenkinsfile script)
Create Workspace for Terraform and Ansible Pipeline
Open File Explorer, navigate to Desktop and create a folder
terraform_ansible
Once folder has been created, open Visual Code Studio and add folder to workspace
- Open a New Terminal
- Run the command before cloning repo: git init
- Navigate to nginx-pipeline repo in Bitbucket
- Clone the repo with SSH or HTTPS
Create S3 bucket in AWS to configure the backend and store terraform state files in storage. (Name the S3 Bucket whatever you prefer)
Create a new file main.tf and copy the below code in yellow color
provider "aws" {
region = var.region
version = "~> 2.0"
}
terraform {
backend "s3" {
bucket = "S3-BUCKET-NAME"
key = "nginx/terraform.tfstste"
region = "us-east-2"
}
}
locals {
ssh_user = "ubuntu"
key_name = "name-of-key"
private_key_path = "files/name-of-key.pem"
}
resource "aws_instance" "nginx" {
ami = data.aws_ami.ubuntu.id
subnet_id = "subnet-7ce9c814"
instance_type = "t2.micro"
associate_public_ip_address = true
security_groups = [aws_security_group.nginx.id]
key_name = local.key_name
provisioner "remote-exec" {
inline = [
"echo 'Wait until SSH is ready'",
]
## PASS PRIVATE KEY AS VARIABLE
connection {
type = "ssh"
user = local.ssh_user
private_key = file(local.private_key_path)
host = aws_instance.nginx.public_ip
}
}
provisioner "local-exec" {
command = "ansible-playbook -i ${aws_instance.nginx.public_ip}, --private-key ${local.private_key_path} nginx.yml"
}
tags = {
Name = "u2-${var.environment}-${var.application}"
CreatedBy = var.launched_by
Application = var.application
OS = var.os
Environment = var.environment
}
}
output "nginx_ip" {
value = aws_instance.nginx.public_ip
}
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
- Create a new file nginx.yml and copy the below code in yellow color
---
- name: Install Nginx
hosts: all
remote_user: ubuntu
become: yes
roles:
- nginx
- Create a new file security.tf and copy the below code in yellow color
name = "u2-${var.environment}-sg-${var.application}"
description = "EC2 SG"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
#Allow all outbound
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
- Create a new file variable.tf and copy the below code in yellow color.
type = string
default = "us-east-2"
}
variable "instance_type" {}
variable "application" {}
variable "environment" {}
############## tags
variable os {
type = string
default = "Ubuntu"
}
variable launched_by {
type = string
default = "USER"
}
############## end tags
Ansible Playbook to Deploy Nginx
- Create this folders roles/nginx/tasks in the same directory then create a file called main.yml and copy the below code in yellow color.
---
- name: Install Python Dependencies
raw: "{{ item }}"
loop:
- sudo apt-get update
- sudo apt-get -y install python
become: true
ignore_errors: true
- name: Ensure Nginx is at the latest version
apt:
name: nginx
state: latest
update_cache: yes
- name: Make sure Nginx is running
systemd:
state: started
name: nginx
- Create this folders roles/nginx/handlers in the same directory then create a file called main.yml and copy the below code in yellow color.
- name: restart nginx
service:
name: nginx
state: restarted
- Create a new file Jenkinsfile and copy the below code in yellow color.
- Commit and push code changes to Repo with the following:
- In Vscode, navigate to Source Code Icon on the right tabs on the side
- Enter commit message
- Click the + icon to stage changes
pipeline {
agent {
node {
label "master"
}
}
parameters {
string(name: 'AppName', defaultValue: 'Enter App Name', description: 'Name of application', )
choice(choices: ['master', 'dev', 'qa', 'prod'], description: 'Select lifecycle to Deploy', name: 'Branch')
choice(choices: ['t2.micro', 't2.small', 't2.medium'], description: 'Select Instance Size', name: 'InstanceSize')
booleanParam(name: 'autoApprove', defaultValue: false, description: 'Automatically run apply after generating plan?')
}
environment {
AWS_ACCESS_KEY_ID = credentials('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = credentials('AWS_SECRET_ACCESS_KEY')
TF_VAR_instance_type = "${params.InstanceSize}"
TF_VAR_environment = "${params.Branch}"
TF_VAR_application = "${params.AppName}"
}
//
stages {
stage('checkout') {
steps {
echo "Pulling changes from the branch ${params.Branch}"
git credentialsId: 'bitbucket', url: 'paste-url-here' , branch: "${params.Branch}"
}
}
stage('terraform plan') {
steps {
withCredentials([sshUserPrivateKey(credentialsId: 'name-of-key', keyFileVariable: 'SSH_KEY')])
{
sh 'mkdir -p files'
sh 'if [ -f "files/name-of-key.pem" ] ; then rm -rf files/name-of-key.pem; else echo "No entry found"; fi'
sh 'cp "$SSH_KEY" files/name-of-key.pem'
sh "pwd ; terraform init -input=true"
sh "terraform plan -input=true -out tfplan"
sh 'terraform show -no-color tfplan > tfplan.txt'
}
}
}
stage('terraform apply approval') {
when {
not {
equals expected: true, actual: params.autoApprove
}
}
steps {
script {
def plan = readFile 'tfplan.txt'
input message: "Do you want to apply the plan?",
parameters: [text(name: 'Plan', description: 'Please review the plan', defaultValue: plan)]
}
}
}
stage('terraform apply') {
steps {
sh "terraform apply -input=true tfplan"
}
}
stage('terraform destroy approval') {
steps {
input 'Run terraform destroy?'
}
}
stage('terraform destroy') {
steps {
sh 'terraform destroy -force'
}
}
}
}
- Push changes by clicking on the 🔄0 ⬇️ 1 ⬆️ as shown below
- Go to nginx-pipeline on Jenkins and run build
- Enter Nginx in the AppName field
- Select a Branch/Lifecycle to deploy server
- Choose t2.small or t2.medium for Nginx server.
- Go to Console Output to track progress












No comments:
Post a Comment