Skip to main content

Command Palette

Search for a command to run...

Deploying An EKS Cluster Using Jenkins & Terraform

Published
โ€ข11 min read
Deploying An EKS Cluster Using Jenkins & Terraform

Prerequisites For The Project::

  1. Aws account , Github account,

  2. 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::

  1. Create an Ec2 Instance with Jenkins Installed

  2. Write the Terraform Code for Eks Cluster Setup

  3. Push The Code to github

  4. Create A Jenkins Declarative Pipeline to deploy the Eks cluster

  5. 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/