Deploying An EKS Cluster Using Jenkins & Terraform

Prerequisites For The Project::
Aws account , Github account,
Terraform and Aws-Cli Installed ,Vs-code (optional) [as you can use the aws ec2 completely to execute terraform commands],Git install
Steps For The Project::
Create an Ec2 Instance with Jenkins Installed
Write the Terraform Code for Eks Cluster Setup
Push The Code to github
Create A Jenkins Declarative Pipeline to deploy the Eks cluster
Deploy the changes to AWS
As a first step Install Terraform and AWS-Cli and also Git (if its not installed) into the machine [it can be local or cloud platform, if it is cloud then launch the Ec2 instance for Ubuntu or any distribution of your choice then install both .
This Step is must ,configure aws to communicate with terraform using Aws-Access-Key & Secret-Access-Key.
[GoTo Aws -->Iam -->Create an User -->Attach the full admin permission -- >Create the user
Then GoTo the created User ,scroll down to Security-Credentials choose Create Access Key]

Choose First option CLI

After that you will get the both key for the integration .
Also don't forget to download the both key's or save it somewhere for the future use.
Then configure aws to communicate with terraform using aws-configure command in terminal and also set your default region whatever you want to [for me it's us-east-1]
Step 1:
Create a repository into the github .

Then Clone the repo into the terminal and go inside it .

Step 2:
Create the files as main.tf ,provider.tf ,terraform.tfvars,variables.tf, backend.tf

Step 3:
Add the provider "aws" into the provider.tf file
### provider block to install the aws plugin
provider "aws" {
region = "us-east-1"
}
Also Add the code to backend.tf file , here s3 is using as remote backend to store the terraform.tfstate file as its contains the sensitive info for terraform so cant store it into the github repository.
Create a bucket in S3 and write the code as:

terraform {
backend "s3" {
bucket = "terraform-jenkins-eks-bucket" ### bucket name
key = "jenkins/eks/terraform.tfstate" ### Key is where I want to store my tfstate files
region = "us-east-1"
}
}
Step 4:
As I want to create an Ec2 instance and within it Jenkins will be installed, so the ec2 will be created inside a vpc [virtual private cloud] .
To create the vpc ,security group I will use the already created module from terraform documentation.
This is an existing module for vpc ,in which everything will get created along with the vpc like the internet gateway,route-table,subnets etc,I dont have to create everything individually.

This is the code for module vpc and module security group in the main.tf file.
###Create VPC [[[ From terraform documentation use an existing module
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "jenkins-eks-vpc"
cidr = var.vpc_cidr
azs = data.aws_availability_zones.availability-zones.names
public_subnets = var.public_subnets
map_public_ip_on_launch = true
enable_dns_hostnames = true
tags = {
Name = "jenkins-eks-vpc"
Terraform = "true"
Environment = "dev"
}
public_subnet_tags = {
Name = "Jenkins_Public_Subnet"
}
}
### Security Group Creation From module
module "jenkins_sg" {
source = "terraform-aws-modules/security-group/aws"
name = "jenkins-sg"
description = "Security group For Jenkins-Eks-Server"
vpc_id = module.vpc.vpc_id
ingress_with_cidr_blocks = [
{
from_port = 8080
to_port = 8080
protocol = "tcp"
description = "Http"
cidr_blocks = "0.0.0.0/0"
},
{
from_port = 22
to_port = 22
protocol = "tcp"
description = "Ssh"
cidr_blocks = "0.0.0.0/0"
}
]
egress_with_cidr_blocks = [
{
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = "0.0.0.0/0"
}
]
tags = {
Name = "jenkins-sg"
}
}
Step 5:
This is the variable.tf file's code for vpc to declare the variables.
##Create variables for vpc
variable "vpc_cidr" {
type = string
description = "Vpc Cidr block"
}
## Public subnet
variable "public_subnets" {
type = list(string)
description = " Public Subnet Ranges"
}
and declare the values for the variables inside the terraform.tfvars file
vpc_cidr = "10.0.0.0/16"
public_subnets = ["10.0.1.0/24"]
Step 6:
Now create the ec2 instance for Jenkins using the resource block [as I was having some issues while using the ec2 module ] and the data-source to fetch the Ami[amazon machine image] details from the aws.
Data source is something which wont create any resources into the cloud but using data-source we can fetch some existing information by providing some details inside this block or filter the info .
or
Data sources are used to fetch the data from the provider end, so that it can be used as configuration in .tf files instead of hard-coding it.
Now ,write the code for ec2 in the same main.tf file.
And I want to install the terraform,jenkins and kubectl through an userdata script ,so for that I have created a shell script for the installing the packages and reference it to the userdata.
### Ec2 Creation
resource "aws_instance" "jenkins-eks-server" {
instance_type = var.instance_type
ami = data.aws_ami.ubuntu.image_id
key_name = "Linux-key" #alread created previously so just providing its refernce as key name
#monitoring = true
vpc_security_group_ids = [module.jenkins_sg.security_group_id]
subnet_id = module.vpc.public_subnets[0]
associate_public_ip_address = true
user_data = file("${path.module}/jenkins-install.sh") ## shell script file to use as userdatauserdata
availability_zone = data.aws_availability_zones.availability-zones.names[0]
tags = {
Name = "Jenkins-Eks-Server"
}
}
### Here Datasource is use for fetching the ami's for ubuntu , choose any ubuntu iamge
id and search for it in the ami section in aws and retrieve the details
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["${var.image_name}"]
}
filter {
name = "root-device-type"
values = ["ebs"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
output "image_id" {
description = "ami"
value = data.aws_ami.ubuntu.image_id
}
## Also I want the availability zone names
data "aws_availability_zones" "availability-zones" {
}
This is how you can get an ami's details for datasource block.

## Create the shell script
#!/bin/bash
##Install Jenkins
sudo apt-get update
sudo apt-get install openjdk-11-jre -y
curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | sudo tee \
/usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
https://pkg.jenkins.io/debian binary/ | sudo tee \
/etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update
sudo apt-get install jenkins -y
sudo systemctl enable jenkins
sudo systemctl start jenkins
## Install Terraform
sudo apt-get update && sudo apt-get install -y gnupg software-properties-common
wget -O- https://apt.releases.hashicorp.com/gpg | \
gpg --dearmor | \
sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null
gpg --no-default-keyring \
--keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \
--fingerprint
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update
sudo apt-get install terraform -y
## Install Kubectl
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubec
tl
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
###Entire variables.tf file For Jenkins only::
##Create variables for vpc
variable "vpc_cidr" {
type = string
description = "Vpc Cidr block"
}
## Public subnet
variable "public_subnets" {
type = list(string)
description = " Public Subnet Ranges"
}
### Variable For Ec2
variable "instance_type" {
type = string
}
variable "image_name" {
type = string
}
###Entire terraform.tfvars file For Jenkins only::
vpc_cidr = "10.0.0.0/16"
public_subnets = ["10.0.1.0/24"]
instance_type = "t2.medium"
image_name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-20240207.1"
Step 7:
Now run some terraform commands ,
terraform init to initialize the aws plugin provider,modules and backend also ...

terraform validate to check if there are any issues inside the code or not [if present then try to find and fix it ]
terraform plan command to check what are going to create before applying the changes .[if something is wrong in the code it will through an error].
Then apply the changes using terraform apply --auto-approve command.

Also If you want to push this codes to github then execute the commands as:[[[make sure git is installed in your system]]]
git add .
git status
git commit -m "Any message"
git push origin main or master ##[check the branch before pushing it]
Check the ec2 instance and copy its public ip ,,Jenkins port is 8080 :This is the Jenkins page .

Step 8:
Get the jenkins password by using sudo cat /var/lib/jenkins.... & then set the rest of the steps as instructed.
Step 9:
Now write the codes for Eks Cluster setup in the terminal,for that create a folder inside the same git repository as Eks-Install or give any name. Then create the same files as before like main.tf,provider.tf,variables.tf,backend.tf,terraform.tfvars .
Start writing codes for provider.tf same as before
provider "aws" {
region = "us-east-1"
}
And the backend.tf code to store the terraform state file:::
terraform {
backend "s3" {
bucket = "terraform-jenkins-eks-bucket" ### bucket name
key = "eks/terraform.tfstate" ### Key is where I want to store my tfstate files
region = "us-east-1"
}
}
Step 10::
This is the code for Eks cluster creation in the main.tf file, for Eks cluster only ::
## VPC For Eks
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "Eks-vpc"
cidr = var.vpc_cidr
azs = data.aws_availability_zones.availability-zones.names
private_subnets = var.private_subnets
public_subnets = var.public_subnets
enable_dns_hostnames = true ## required feilds
enable_nat_gateway = true
single_nat_gateway = true
tags = {
"kubernetes.io/cluster/my-eks-cluster" = "shared" ## these tags are required
### Get it from Aws Eks documentation
}
private_subnet_tags = {
"kubernetes.io/cluster/my-eks-cluster" = "shared"
"kubernetes.io/role/internal-elb" = 1
}
public_subnet_tags = {
"kubernetes.io/cluster/my-eks-cluster" = "shared"
"kubernetes.io/role/elb" = 1
}
}
data "aws_availability_zones" "availability-zones" {
}
## Eks Cluster Module
module "eks" {
source = "terraform-aws-modules/eks/aws"
cluster_name = "my-eks-cluster"
cluster_version = "1.24"
cluster_endpoint_public_access = true
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
eks_managed_node_groups = {
nodes = {
min_size = 1
max_size = 3
desired_size = 2
instance_types = ["t2.small"]
}
}
tags = {
Name = "Eks-Cluster"
Environment = "dev"
Terraform = "true"
}
}
##This variable.tf file contains only the variables for Eks cluster setup::
##Create variables for vpc
variable "vpc_cidr" {
type = string
description = "Vpc Cidr block"
}
## Public subnet
variable "public_subnets" {
type = list(string)
description = " Public Subnet Ranges"
}
###Private Subnets
variable "private_subnets" {
type = list(string)
description = " Public Subnet Ranges"
}
###This is terraform.tfvars file contains only the variable reference values for eks cluster::
vpc_cidr = "192.168.0.0/16"
private_subnets = ["192.168.1.0/24", "192.168.2.0/24", "192.168.3.0/24"]
public_subnets = ["192.168.4.0/24", "192.168.5.0/24", "192.168.6.0/24"]
Step 11:
Also create a .gitignore file outside of the Eks-folder ,that means inside the git repository where the jenkins installation files are present like this:: [[[ignore the .devcontainer one ]]]

### write down these two inside the .gitnore files as I dont want to push it to the
github::
.terraform/*
.terraform.lock.hcl
Before deploying it to the aws through Jenkins pipeline check once if everything is working file by executing the terraform commands::
terraform init ### initialize the aws plugin provider.
terraform validate ## to check if there are any issues inside the code or not [if present then try to find and fix it ]
terraform plan ##command to check what are going to create before applying the changes .[if something is wrong in the code it will through an error].
### Then apply the changes using command
terraform apply --auto-approve
### After that destroy the infra for eks only as of now::
terraform destroy --auto-approve
If everything is alright then you can push this codes to github again or can do it later.
Step 12::
Now ,go back to the Jenkins dashboard ::
Create a job in Jenkins,, select New item...

Give any name for the job and Select Pipeline ..

After creating the job, start writing the pipeline declarative scripts. [[Scroll down to the pipeline section]]
Now ,if I want to set some parameter I can do that as follows::
It will help me during the execution of the pipeline whether to select terraform apply or terraform destroy command ,according to that it will act .

Before that, store the AWS access key and secret access key to the Jenkins credentials, as these credentials will be required to communicate with Jenkins to the AWS for identification.
For that goto Jenkins Dashboard -->Manage Jenkins-->Credentials --> System -->Global Credentials
And Change the username & password to Secret text and store the access key's

This credentials will be required to the pipeline script ,these are the credentials which I stored previously.

Step 13::
This is the pipeline script::
pipeline {
agent any
environment {
AWS_ACCESS_KEY = credentials('Aws_access_key_id') ### Replace it with your's
AWS_SECRET_ACCESS_KEY = credentials ('Secret_access_key_id')
AWS_DEFAULT_REGION = "us-east-1"
}
stages {
stage('Git Checkout') {
steps {
git branch: 'main', url: 'https://github.com/tanaya-2023/Terraform-Jenkins-Eks.git'
}
}
stage('Initializing Terraform') {
steps {
dir('Eks-Install-folder') {
sh 'terraform init'
}
}
}
stage('Formatting Terraform') {
steps {
dir('Eks-Install-folder') {
sh 'terraform fmt'
}
}
}
stage('Validating Terraform') {
steps {
dir('Eks-Install-folder') {
sh 'terraform validate'
}
}
}
stage('Reviewing the Terraform Plan ') {
steps {
dir('Eks-Install-folder') {
sh 'terraform plan'
}
input(message: "Are you sure to Proceed?", ok: "Proceed")
}
}
stage('Create/Destroy the Eks Cluster ') {
steps {
dir('Eks-Install-folder') {
sh 'terraform $action --auto-approve' ## Create a parameter of choice with action variable and mention there apply or destroy then while executing build with parameter choose apply or destroy as per requirement
}
}
}
stage('Deploying nginx application through kubernetes ') { ### you can ignore these steps as well
steps {
dir('Eks-Install-folder/K8s-Manifest-files') {
sh 'aws eks update-kubeconfig --name my-eks-cluster --region us-east-1'
sh 'kubectl apply -f deployment.yml'
sh 'kubectl apply -f service.yml'
}
}
}
}
}
So, I have done only the Eks cluster deployment part to the AWS. After this, if anyone wants to do the Kubernetes manifests file deployment part for any simple application or whatever you want to do, you can do it.
I have skipped this step as I was facing some issues while deploying an application into my cluster.
Step 14:
After writing the script save the pipeline and click on Build Now ,,check the Console Output.
Choose the parameter during the build process whether to apply changes into AWS console or destroy resources.

Eks cluster creation takes time approx 12-15mnts or even more sometimes .
terraform plan command success.


After 15mints...creation complete

So this is my Eks Cluster,,..Deployed the cluster using Jenkins pipeline successfully..๐๐

Destroy the whole infra after the project including the Jenkins part.
Command is : terraform destroy --auto-approve
Refer to the amazing terraform documentation it's very helpful to create any infrastructure.
This is the link
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/


![AWS VPC Creation Using Terraform[ A Mini Project]](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1689934431510%2Ffb3ca82c-ada0-4f86-9223-80890ea51459.avif&w=3840&q=75)