Table of Contents
In this article, I will walk you through the steps on how we can easily leverage Terraform to provision an EC2 instance on AWS running with Redhat and install Jenkins using remote commands.
Terraform — An IaC tool
Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. It can manage existing and popular service providers as well as custom in-house solutions. Configuration files describe to Terraform the components needed to run a single application or your entire datacentre. Terraform is revolutionising DevOps by changing how infrastructure is managed, making it fast and efficient to execute DevOps projects.
Environment
Terraform v0.15.5
AWS Account —AWS Free Tier is enough to test.
AWS CLI
Key Pair — To access the EC2 instance.
Let’s Provision our EC2 Instance!
I have created a separate working directory for my Jenkins installation. To create my main.tf file for this demo, I am going to keep all the coding in a single file. I am not using modules or other terraform futures to keep it simple.
Working Directory : D:\terraform\jenkins
Open main.tf in your favorite text editor, here I am using VS Code:
provider "aws" {
profile = "terraform"
region = "us-east-1"
}
In Provider block, I am defining which provider to use and associated aws profile and the region. I have configured my local aws profile, which is “terraform” and I will keep my resources on the us-east-1 region.
To Configure AWS-cli, you can refer to the below link:
https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html
Next let’s configure our Security Group…
# Security Group
variable "ingressrules" {
type = list(number)
default = [8080, 22]
}
resource "aws_security_group" "web_traffic" {
name = "Allow web traffic"
description = "inbound ports for ssh and standard http and everything outbound"
dynamic "ingress" {iterator = port
for_each = var.ingressrules
content {
from_port = port.value
to_port = port.value
protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"]
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
"Terraform" = "true"
}
}
In the Security Group block, we will configure to make our EC2 instance publicly accessible.
For the ingress rule list of ports, we are using (8080, 22). Port 22 for ssh connections and port 8080 to access Jenkins URL publicly. We will configure the egress rule to allow traffic for everything.
Next configure our data block…
# Data Block
data "aws_ami" "redhat" {
most_recent = true
filter {
name = "name"
values = ["RHEL-7.5_HVM_GA*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["309956199498"]
}
The data block uses aws_ami data source, passes a few filter options as specified, and returns an object; this is useful to pull the latest AMI and keeps launching configuration up to date. Here we are pulling latest AMI image of Redhat 7.5.
Resource Block…!
# resource block
resource "aws_instance" "jenkins" {
ami = data.aws_ami.redhat.id
instance_type = "t2.micro"
security_groups = [aws_security_group.web_traffic.name]
key_name = "ashnikdev_key"
In the resource block, we have defined terraform to provision ec2 aws_instance, and refer to it as Jenkins inside this resource block specifying ami by calling our data block ami image and instance_type t2.micro and attaching the security group to aws_instance.
Also, we need to add the key pair to communicate with the server using ssh. Here I am adding my existing key pair “ key_name = “ashnikdev_key
Reference to create key pair :-
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#having-ec2-create-your-key-pair
Next, we are going to add provisioner and connection block within our resource block.
Execute Remote Commands
The remote-exec provisioner invokes a script on a remote resource after it is created. This can be used to run a configuration management tool, bootstrap into a cluster, etc. To invoke a local process, see the local-exec provisioner instead. The remote-exec provisioner supports both ssh and winrm type connections.
In the argument inline parameter, we can list all our commands strings that are executed in an order. We will install Java, Jenkins.
provisioner "remote-exec" {
inline = [
"sudo yum install -y jenkins java-11-openjdk-devel",
"sudo yum -y install wget",
"sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo",
"sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key",
"sudo yum upgrade -y",
"sudo yum install jenkins -y",
"sudo systemctl start jenkins",
]
}
connection {
type = "ssh"
host = self.public_ip
user = "ec2-user"
private_key = file("color:#CE9178">".\ashnikdev_key.pem" )
}
tags = {
"Name" = "Jenkins"
}
}
We specify the connection type, host, user, and path to our private key inside the connection block. That’s how Terraform will connect to the instance after it has been provisioned and run our commands.
Save our main.tf file and run init and validate the code.
Terraform init
The terraform init command is used to initialize a working directory containing the Terraform configuration files. This is the first command that should run after writing a new Terraform configuration or cloning an existing one. It is safe to run this command multiple times.
Terraform validate
The terraform validate command validates the configuration files in a directory, referring only to the configuration and not accessing remote services such as remote state, provider APIs, and others.
Terraform plan
The terraform plan command creates an execution plan. By default, creating a plan consists of:
- Reading the current state of any already-existing remote objects to make sure that the Terraform state is up-to-date.
- Comparing the current configuration to the prior state and noting any differences.
- Proposing a set of change actions should, if applied, make the remote objects match the configuration.
The plan command alone will not carry out the proposed changes, and so you can use this command to check whether the proposed changes match what you expected before you apply the changes.
➜
Terraform apply
The terraform apply command executes the actions proposed in a Terraform plan:
By running terraform apply it will ask for the confirmation to perform action by entering yes :
➜
➜
Now, let’s go to our AWS console and verify the new EC2 instance.
You should see the attached security group on the EC2 instance inside the AWS Console.
We can connect to our EC2 instance over SSH via public DNS name. On the Networking tab, you can find the public DNS name address. The username is “ec2-user” by default.
So, since all looks good now, we will access Jenkins via web browser using the public DNS name/ipaddress:8080.
Access the Jenkins Web portal
Access the URL : https://
Admin password is created and stored in the log file “/var/lib/jenkins/secrets/initialAdminPassword “. Run the below command to get the password.
Copy the password and paste it in above window on “Administrator password” and click on Continue…
As we can see required plugin installation is in progress for Jenkins. Once it is done with plugin installation, it will ask to create Admin User:
Click on Save and Continue…
Summary
Using Terraform, we have created EC2 Instance on aws and using remote command future in no time. We have executed list of commands on the created resource to install Jenkins:
In this article, we touched upon the basics of Terraform’s capabilities. It has various features for building, changing, and versioning infrastructure in secure way. Terraform manages existing and popular service providers along with custom in-house solutions.
Refer to checking out the Terraform documentation to deep dive into Terraform offerings.