# Three ways of launching Amazon Linux 2 and Ubuntu Ec2 instances and install Docker and Jenkins on them

# Three Methods for Launching Amazon Linux 2 and Ubuntu EC2 Instances with Docker and Jenkins installed

# 🚀 Overview:

This project aims to demonstrate three different approaches to launching Amazon Linux 2 and Ubuntu EC2 instances on AWS and installing Docker and Jenkins on them. The three methods include using AWS CloudFormation, Terraform, and direct Bash scripting with user data.

## 🔧 Problem Statement

This project demonstrates three distinct methods to deploy Amazon Linux 2 and Ubuntu EC2 instances with Docker and Jenkins installed. Each approach showcases different infrastructure-as-code and automation techniques commonly used in DevOps practices.

## 💽 Techonology Stack

The architecture consists of the following three tiers:

* **VPC**: AWS VPC
    
* **EC2 Instances**: AWS EC2
    
* **Containerization**: Docker
    
* **Cl/CD:** Jenkins
    
* **Scripting:** Bashscript
    

## 📌 Architecture Diagram

```bash
                                      +-----------------------------+
                                      |         AWS Region          |
                                      |                             |
                                      | +-------------------------+ |
                                      | |       VPC               | |
                                      | |                         | |
                                      | | +-------------------+   | |
                                      | | | Availability Zone |   | |
                                      | | |         A         |   | |
                                      | | |                   |   | |
                                      | | | +-------------+   |   | |
                                      | | | |  Subnet A   |   |   | |
                                      | | | |             |   |   | |
                                      | | | | +--------+  |   |   | |
                                      | | | | | EC2     |  |   |   | |
                                      | | | | | Amazon  |  |   |   | |
                                      | | | | | Linux 2 |  |   |   | |
                                      | | | | +--------+  |   |   | |
                                      | | | +-------------+   |   | |
                                      | | +-------------------+   | |
                                      | |                         | |
                                      | | +-------------------+   | |
                                      | | | Availability Zone |   | |
                                      | | |         B         |   | |
                                      | | |                   |   | |
                                      | | | +-------------+   |   | |
                                      | | | |  Subnet B   |   |   | |
                                      | | | |             |   |   | |
                                      | | | | +--------+  |   |   | |
                                      | | | | | EC2     |  |   |   | |
                                      | | | | | Ubuntu  |  |   |   | |
                                      | | | | +--------+  |   |   | |
                                      | | | +-------------+   |   | |
                                      | | +-------------------+   | |
                                      | |                         | |
                                      | +-------------------------+ |
                                      |                             |
                                      +-----------------------------+
```

## 🌟 Project Requirements

Before you get started, make sure you have the following prerequisites in place:

* AWS account with an IAM user credentials configured in.
    
* An Infrastructure (VPC, Subnets, route table, Security groups, NACL...) ready to be use for the lab.
    
* An Amazon Linux 2 and Ubuntu EC2 instance running for the part for the bash scripting
    
* To install Jenkins on a server you must have minimum hardware requirements:
    
    256 MB of RAM 1 GB of drive space (although 10 GB is a recommended minimum if running Jenkins as a Docker container) Recommended hardware configuration for a small team: 4 GB+ of RAM 50 GB+ of drive space
    
* To install Jenkins on a server you must have minimum hardware requirements:
    

OS: 64-bit version of Ubuntu RAM: At least 2 GB, but Docker recommends more for larger deployments or resource-intensive applications Disk space: 100 GB of free space CPU: Sufficient amount, depending on the applications Kernel: 64-bit kernel with support for virtualization Virtualization: Support for KVM virtualization technology QEMU: Version 5.2 or later Init system: systemd init system Desktop environment: Gnome, KDE, or MATE Firewall: Firewall rulesets created with iptables or iptables6, and added to the DOCKER-USER chai.

## 📋 Table of Contents

I - **AWS CloudFormation Template**

[**Step 1:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-VPC-Configuration) Description

[**Step 2:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-VPC-Configuration) Instructions of deployment

[**Step 3:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-web-page-output) Results

[**Step 4:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-Checking-Logs) Clean up

II - **Terraform Script**

[**Step 1:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-IAM-Role-Creation) Description

[**Step 2:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-Log-Group-Creation) Instructions of deployment

[**Step 3:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-Flow-Logs_creation) Results

[**Step 4:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-Checking-Logs) Clean Up

III - **Bash Script**

[**Step 1:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-IAM-Role-Creation) Description

[**Step 2:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-Log-Group-Creation) Instructions of deployment

[**Step 3:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-Flow-Logs_creation) Results

[**Step 4:**](http://127.0.0.1:8000/vpc-flow-logs-on-aws/#-Checking-Logs) Clean Up

## ✨AWS CLOUDFORMATION TEMPLATE

##### Step 1: **DESCRIPTION**

AWS CloudFormation allows you to define your infrastructure as code. We will create a CloudFormation template that launches Amazon Linux 2 and Ubuntu EC2 instances and uses user data scripts to install Docker and Jenkins.

##### Step 2: **INSTRUCTIONS OF DEPLOYMENT**

* Create a CloudFormation template
    
    Use your VS Code to create both files "Linux\_Docker\_jenkins.yml" and "ubntu-docker-jenkins.yml"
    
* Define the resources for Amazon Linux 2 and Ubuntu EC2 instances. Here Use the `UserData` property to specify a script that installs Docker and Jenkins.
    
    Linux-Docker-Jenkins.yml
    
    ```bash
    AWSTemplateFormatVersion: '2010-09-09'
    
    Metadata:
     License: Apache-2.0
     Authors:
        Description: Joseph Mbatchou  
     Description: " This template launches an amazon Linux 2 ec2 instance in a custom VPC, with an IAM assume role attached to it
                  for SSM, then with the user data it will install Docker and Jenkins"
    
    Parameters:
      InstanceType:
        Description: EC2 instance type.
        Type: String
        AllowedValues:
          - t2.nano
          - t2.micro
          - t2.small
          - t2.medium
          - t2.large
      KeyName:
        Description: Name of an existing EC2 key pair for SSH access to the EC2 instance.
        Type: AWS::EC2::KeyPair::KeyName
      SSHLocation:
        Description: The IP address range that can be used to SSH to the EC2 instances
        Type: String
        MinLength: '9'
        MaxLength: '18'
        AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})" # IP Address
        ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
      ImageId:
        Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
        Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
      VpcId:
        Type: AWS::EC2::VPC::Id
        Description: Select an existing VPC
      SubnetId:
        Type: AWS::EC2::Subnet::Id
        Description: Select an existing subnet within the selected VPC
    Resources:
      IamRole:
        Type: 'AWS::IAM::Role'
        Properties:
          RoleName: Ec2RoleForSSM
          Description: EC2 IAM role for SSM access
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Principal:
                  Service:
                    - ec2.amazonaws.com
                Action:
                  - 'sts:AssumeRole'
          Path: /
          ManagedPolicyArns:
            - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
      Ec2InstanceProfile:
        Type: 'AWS::IAM::InstanceProfile'
        Properties:
          InstanceProfileName: Ec2RoleForSSM
          Path: /
          Roles:
            - Ref: IamRole
      WebServer:
        Type: AWS::EC2::Instance
        Properties:
          IamInstanceProfile: !Ref Ec2InstanceProfile
          ImageId: !Ref ImageId
          InstanceType: !Ref InstanceType 
          KeyName: !Ref KeyName
          NetworkInterfaces: 
          - AssociatePublicIpAddress: "true"
            DeviceIndex: "0"
            GroupSet: 
              - !Ref WebServerSecurityGroup
            SubnetId: !Ref SubnetId
          UserData:
            Fn::Base64: !Sub |
              #!/bin/bash
              sudo yum update -y
              sudo yum install python3-pip
              sudo amazon-linux-extras install docker
              sudo yum install -y docker
              sudo service docker start
              sudo systemctl enable docker
              sudo systemctl restart docker
              sudo usermod -aG docker ec2-user
              sudo yum update -y
              sudo 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-2023.key
              sudo yum upgrade
              sudo yum install java-17-amazon-corretto -y
              sudo yum install jenkins -y
              sudo systemctl start jenkins
              sudo systemctl enable jenkins
              sudo systemctl restart jenkins
              sudo usermod -aG jenkins ec2-user
              sudo reboot
              
          Tags:
           - Key: Name
             Value: Linux-Docker-Jenkins-Server
      WebServerSecurityGroup: 
        Type: AWS::EC2::SecurityGroup
        Properties:
          GroupDescription: 'Enable HTTP access via port 80 SSH access'
          VpcId: !Ref VpcId
          SecurityGroupIngress:
            - CidrIp: 0.0.0.0/0
              FromPort: 8080
              IpProtocol: tcp
              ToPort: 8080
            - CidrIp: !Ref SSHLocation
              FromPort: 22
              IpProtocol: tcp
              ToPort: 22
            - CidrIp: 0.0.0.0/0
              FromPort: 80
              IpProtocol: tcp
              ToPort: 80 
    
    Outputs:
      InstanceId:
        Description: ID of the EC2 instance
        Value: !Ref WebServer
      PublicDNS:
        Description: Public DNS name of the EC2 instance
        Value: !GetAtt WebServer.PublicDnsName
      PublicIP:
        Description: Public IP address of the EC2 instance
        Value: !GetAtt WebServer.PublicIp 
    ```
    
    ubuntu-docker-jenkins.yml
    

```bash
AWSTemplateFormatVersion: '2010-09-09'

Metadata:
  License: Apache-2.0
  Authors:
    Description: Joseph Mbatchou  # The writer of this template
  Description: " This template launches an ubuntu ec2 instance in a custom VPC, with an IAM assume role attached to it
              for SSM, then with the user data it will install Docker and Jenkins"

Parameters:
  InstanceType:
    Description: EC2 instance type.
    Type: String
    AllowedValues:
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
  KeyName:
    Description: Name of an existing EC2 key pair for SSH access to the EC2 instance.
    Type: AWS::EC2::KeyPair::KeyName
  SSHLocation:
    Description: Place to enter your IP address. The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: '9'
    MaxLength: '18'
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  ImageId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: '/aws/service/canonical/ubuntu/server/jammy/stable/current/amd64/hvm/ebs-gp2/ami-id'
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: Select an existing VPC
  SubnetIds:
    Type: AWS::EC2::Subnet::Id
    Description: Select at least one subnet within the selected VPC  

Resources:
  IamRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: !Sub "${AWS::StackName}-Ec2RoleForSSM"
      Description: EC2 IAM role for SSM access
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'

  Ec2InstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      InstanceProfileName: !Sub "${AWS::StackName}-Ec2RoleForSSM"
      Path: /
      Roles:
        - !Ref IamRole

  WebServer:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref Ec2InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      KeyName: !Ref KeyName
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          GroupSet: 
            - !Ref WebServerSecurityGroup
          SubnetId: !Ref SubnetIds
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          sudo apt-get update 
          sudo apt-get install -y ca-certificates curl gnupg
          sudo install -m 0755 -d /etc/apt/keyrings
          curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
          sudo chmod a+r /etc/apt/keyrings/docker.gpg
          echo \
             "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
             $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
             sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
          sudo apt-get update 
          sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
          sudo systemctl start docker.service
          sudo systemctl enable docker.service
          sudo usermod -aG docker ubuntu
          sudo apt-get update -y
          sudo apt-get install openjdk-17-jdk -y
          sudo curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee   /usr/share/keyrings/jenkins-keyring.asc > /dev/null
          sudo echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]   https://pkg.jenkins.io/debian-stable binary/ | sudo tee   /etc/apt/sources.list.d/jenkins.list > /dev/null
          sudo apt-get update  
          sudo apt-get install jenkins -y
          sudo systemctl start jenkins
          sudo systemctl enable jenkins
          sudo usermod -aG jenkins ubuntu
          sudo ufw allow 8080
          sudo ufw allow OpenSSH
          sudo ufw enable
      Tags:     
        - Key: Name
          Value: Ubuntu-Docker-jenkins-server

  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: 'Enable HTTP access via port 80 SSH access'
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          FromPort: 8080
          IpProtocol: tcp
          ToPort: 8080
        - CidrIp: !Ref SSHLocation
          FromPort: 22
          IpProtocol: tcp
          ToPort: 22
        - CidrIp: 0.0.0.0/0
          FromPort: 80
          IpProtocol: tcp
          ToPort: 80 

Outputs:
  InstanceId:
    Description: ID of the EC2 instance
    Value: !Ref WebServer
  PublicDNS:
    Description: Public DNS name of the EC2 instance
    Value: !GetAtt WebServer.PublicDnsName
  PublicIP:
    Description: Public IP address of the EC2 instance
    Value: !GetAtt WebServer.PublicIp
```

* Deploy the stack using the AWS Management Console.
    

On the console you must open CloudFormation option then hit on "Create Stack"

Linux-stack

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722046619365/23cf4de3-3c7a-4398-bf26-f05ed64d027e.png align="center")

ubuntu stack

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722046672398/2fb5c490-00ea-4edf-b861-529700600dd7.png align="center")

After launching both stacks you will get the complete stage

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722046781914/4b3d7e2f-5e84-452a-b084-9bf04b7194d9.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722046804013/78498d08-03d3-4a52-bd28-473d8751a6c8.png align="center")

Step 3: **RESULTS**

As result you will get first both instances running in the console

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722046884640/0ff4eaab-149a-49c4-a8be-e3295279b4e3.png align="center")

After connecting to each servers via Session manager or SSH you can check status and version of each application installed.

Linux instance

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722046924620/a8ef9ee1-b54f-44b2-a373-135961d76baa.png align="center")

ubuntu instance

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722046959586/63479337-4d03-4f0b-bae0-3657cf871f36.png align="center")

Step 4: **CLEAN UP**

You can clean up all resources created by just delete them via the CloudFormation stack . You just need to go back in the CloudFormation window select the stack and hit delete button till you get to the message saying "Delete Complete" .

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722047012373/e6dbac77-5810-4832-962b-8d199fbe704d.png align="center")

## ✨TERRAFORM SCRIPT

##### Step 1: **DESCRIPTION**

Terraform is an open-source infrastructure as code software tool. We will create Terraform scripts to launch Amazon Linux 2 and Ubuntu EC2 instances and use user data to install Docker and Jenkins.

##### Step 2: **INSTRUCTIONS OF DEPLOYMENT**

Create a Terraform script

* Here you will have to create both (Linux-main.tf and ubuntu-main.tf) files and you will put each of them in a folder.
    
* Define the resources for Amazon Linux 2 and Ubuntu EC2 instances. Use the `UserData` property to specify a script that installs Docker and Jenkins.
    
    Here are the contains of each files
    
    Linux-main.tf
    
    ```bash
    terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 4.0"
        }
      }
    
    }
    variable "aws_region" {
      type        = string
      description = "region where to launch"
      default = "us-west-2"
    }
    variable "instance_type" {
      type        = string
      description = "instance type of the instance"
      default = "ansible-key"
    }
    
    variable "key_name" {
      type        = string
      description = "rkey name of the instance"
      default = "t2.micro"
    }
    #Configure the AWS Provider
    provider "aws" {
      region = var.aws_region
    }# Data source for latest Amazon Linux 2 AMI
    data "aws_ami" "amazon_linux_2" {
      most_recent = true
      owners      = ["amazon"]
    
      filter {
        name   = "name"
        values = ["amzn2-ami-hvm-*-x86_64-gp2"]
      }
    }
    data "aws_vpc" "custom_vpc" {
      filter {
        name   = "tag:Name"
        values = ["c@licost-vpc"] # Replace with your VPC's name tag
      }
    }
    data "aws_subnet" "custom_subnet" {
      vpc_id = data.aws_vpc.custom_vpc.id
    
      filter {
        name   = "tag:Name"
        values = ["c@licost-subnet-public2-us-west-2b"] # Replace with your subnet's name tag
      }
    }
    
    # IAM Role
    resource "aws_iam_role" "ec2_ssm_role" {
      name = "Ec2RoleForSSM"
      assume_role_policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Action = "sts:AssumeRole"
            Effect = "Allow"
            Principal = {
              Service = "ec2.amazonaws.com"
            }
          }
        ]
      })
    }
    
    resource "aws_iam_role_policy_attachment" "ssm_policy_attachment" {
      role       = aws_iam_role.ec2_ssm_role.name
      policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
    }
    
    resource "aws_iam_instance_profile" "ec2_profile" {
      name = "Ec2RoleForSSM"
      role = aws_iam_role.ec2_ssm_role.name
    }
    
    # Security Group
    resource "aws_security_group" "web_server_sg" {
      name        = "WebServerSecurityGroup"
      description = "Enable HTTP access via port 80 SSH access"
      vpc_id      = data.aws_vpc.custom_vpc.id
    
      ingress {
        from_port   = 8080
        to_port     = 8080
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
      }
    
      ingress {
        from_port   = 22
        to_port     = 22
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
      }
    
      ingress {
        from_port   = 80
        to_port     = 80
        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"]
      }
    }
    
    # EC2 Instance
    resource "aws_instance" "web_server" {
      ami                    = data.aws_ami.amazon_linux_2.id
      instance_type          = var.instance_type
      key_name               = var.key_name
      subnet_id              = data.aws_subnet.custom_subnet.id
      vpc_security_group_ids = [aws_security_group.web_server_sg.id]
      iam_instance_profile   = aws_iam_instance_profile.ec2_profile.name
      associate_public_ip_address = "true"
    
      user_data = base64encode(<<-EOF
        #!/bin/bash
        sudo yum update -y
        sudo yum install python3-pip
        sudo amazon-linux-extras install docker
        sudo yum install -y docker
        sudo service docker start
        sudo systemctl enable docker
        sudo systemctl restart docker
        sudo usermod -aG docker ec2-user
        sudo yum update -y
        sudo 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-2023.key
        sudo yum upgrade
        sudo yum install java-17-amazon-corretto -y
        sudo yum install jenkins -y
        sudo systemctl start jenkins
        sudo systemctl enable jenkins
        sudo systemctl restart jenkins
        sudo usermod -aG jenkins ec2-user
        sudo reboot
      EOF
      )
    
      tags = {
        Name = "Linux-Docker-Jenkins-server"
      }
    }
    output "instance_id" {
      description = "ID of the EC2 instance"
      value       = aws_instance.web_server.id
    }
    
    output "public_dns" {
      description = "Public DNS name of the EC2 instance"
      value       = aws_instance.web_server.public_dns
    }
    
    output "public_ip" {
      description = "Public IP address of the EC2 instance"
      value       = aws_instance.web_server.public_ip
    }
    ```
    
    ubuntu-main.tf
    
    ```bash
    terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 4.0"
        }
      }
    }
    #Configure the AWS Provider
    provider "aws" {
      region = var.aws_region
    }
    variable "aws_region" {
      type        = string
      description = "region where to launch"
      default = "us-west-2"
    }
    variable "instance_type" {
      type        = string
      description = "instance type of the instance"
      default = "ansible-key"
    }
    
    variable "key_name" {
      type        = string
      description = "rkey name of the instance"
      default = "t2.micro"
    }
    
    #Data source for latest Amazon Linux 2 AMI
    data "aws_ami" "ubuntu" {
      most_recent = true
      owners      = ["amazon"]
    
      filter {
        name   = "name"
        values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
      }
    }
    data "aws_vpc" "custom_vpc" {
      filter {
        name   = "tag:Name"
        values = ["c@licost-vpc"] # Replace with your VPC's name tag
      }
    }
    data "aws_subnet" "custom_subnet" {
      vpc_id = data.aws_vpc.custom_vpc.id
    
      filter {
        name   = "tag:Name"
        values = ["c@licost-subnet-public2-us-west-2b"] # Replace with your subnet's name tag
      }
    }
    
    # IAM Role
    resource "aws_iam_role" "ec2_ssm_role" {
      name = "Ec2RoleForSSM"
      assume_role_policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Action = "sts:AssumeRole"
            Effect = "Allow"
            Principal = {
              Service = "ec2.amazonaws.com"
            }
          }
        ]
      })
    }
    
    resource "aws_iam_role_policy_attachment" "ssm_policy_attachment" {
      role       = aws_iam_role.ec2_ssm_role.name
      policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
    }
    
    resource "aws_iam_instance_profile" "ec2_profile" {
      name = "Ec2RoleForSSM"
      role = aws_iam_role.ec2_ssm_role.name
    }
    
    # Security Group
    resource "aws_security_group" "web_server_sg" {
      name        = "WebServerSecurityGroup"
      description = "Enable HTTP access via port 80 SSH access"
      vpc_id      = data.aws_vpc.custom_vpc.id
    
      ingress {
        from_port   = 8080
        to_port     = 8080
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
      }
    
      ingress {
        from_port   = 22
        to_port     = 22
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
      }
    
      ingress {
        from_port   = 80
        to_port     = 80
        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"]
      }
    }
    
    # EC2 Instance
    resource "aws_instance" "web_server" {
      ami                         = data.aws_ami.ubuntu.id
      instance_type               = var.instance_type
      key_name                    = var.key_name
      subnet_id                   = data.aws_subnet.custom_subnet.id
      vpc_security_group_ids      = [aws_security_group.web_server_sg.id]
      iam_instance_profile        = aws_iam_instance_profile.ec2_profile.name
      associate_public_ip_address = "true"
    
      user_data = base64encode(<<-EOF
        #!/bin/bash
        sudo apt-get update 
        sudo apt-get install -y ca-certificates curl gnupg
        sudo install -m 0755 -d /etc/apt/keyrings
        curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
        sudo chmod a+r /etc/apt/keyrings/docker.gpg
        echo \
           "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
           $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
           sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
        sudo apt-get update 
        sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
        sudo systemctl start docker.service
        sudo systemctl enable docker.service
        sudo usermod -aG docker ubuntu
        sudo apt-get update -y
        sudo apt-get install openjdk-17-jdk -y
        sudo curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee   /usr/share/keyrings/jenkins-keyring.asc > /dev/null
        sudo echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]   https://pkg.jenkins.io/debian-stable binary/ | sudo tee   /etc/apt/sources.list.d/jenkins.list > /dev/null
        sudo apt-get update  
        sudo apt-get install jenkins -y
        sudo systemctl start jenkins
        sudo systemctl enable jenkins
        sudo usermod -aG jenkins ubuntu
        sudo ufw allow 8080
        sudo ufw allow OpenSSH
        sudo ufw enable
      EOF
      )
    
      tags = {
        Name = "Ubuntu-Docker-jenkins-server"
      }
    }
    output "instance_id" {
      description = "ID of the EC2 instance"
      value       = aws_instance.web_server.id
    }
    
    output "public_dns" {
      description = "Public DNS name of the EC2 instance"
      value       = aws_instance.web_server.public_dns
    }
    
    output "public_ip" {
      description = "Public IP address of the EC2 instance"
      value       = aws_instance.web_server.public_ip
    }
    ```
    
    Step 3: **RESULTS**
    
    After putting each files in a folder we have to go through the process of running terraform
    
    1. Initialise the folder
        
    
    ```bash
    terraform init
    ```
    
    2. Check the correct syntax of the file
        
    
    ```bash
    terraform fmt
    ```
    
    3. Valid the status of the file
        
    
    ```bash
    terraform validate
    ```
    
    4. Plan to see which resources will be create
        
    
    ```bash
    terraform plan
    ```
    
    5. Create the resources with command
        
    
    ```bash
    terraform apply
    ```
    
    After all this we will get to the result images
    
* Linux instance
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722054773493/1a4f5eb4-6c87-4c1e-9c1e-f22ef3fde155.png align="center")
    
    In the console you have
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722054919286/3363b58c-0f7d-4d36-bf6c-e00322819559.png align="center")
    
    Ubutntu
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722055495059/4ed0c3a8-8237-4bee-98e1-b9558407c6ae.png align="center")
    
    In the console
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722055539062/b29bf4b5-084d-456c-8878-5d20c2d179ca.png align="center")
    
    After SSM connect to each instances we have the result of different version
    
    For Linux instance
    
* ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722054877835/2f83c283-61bb-49aa-bba3-f7920258a5a6.png align="center")
    
* For Ubuntu instance
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722055441701/1556b03d-2651-45a1-a58d-8b22f23bf6d5.png align="center")
    
    Step 4: **CLEAN UP**
    
    Use the command destroy to delete all the infrastructures
    
    ```bash
    terraform destroy
    ```
    

For the Linux instance

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722054958008/771058a2-3567-456e-9b8f-001f870119d2.png align="center")

For the ubuntu instance

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722055357434/d1ba2f0a-e54a-47ef-b071-73e7514b753a.png align="center")

## ✨BASH SCRIPT

##### Step 1: **DESCRIPTION**

A Bash script can be used to manually launch EC2 instances and configure them using the AWS CLI. We will write a Bash script that launches Amazon Linux 2 and Ubuntu EC2 instances and uses user data to install Docker and Jenkins.

##### Step 2: **INSTRUCTIONS OF DEPLOYMENT**

* Create a Bash script ([`launch-instances.sh`](http://launch-instances.sh)). This with contains the process of creating both Amazon linux and Ubuntu EC2 instances. The script included default value you can customize to your values.
    
    ```bash
    #!/bin/bash
    
    # Variables
    REGION="us-west-2"
    INSTANCE_TYPE="t2.micro"
    KEY_NAME="ansible-key"
    SECURITY_GROUP_ID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=DevOps-SG --query 'SecurityGroups[0].GroupId' --output text --region $REGION)
    
    # Subnet IDs - replace these with your actual subnet IDs
    SUBNET_ID_1="subnet-0afe31980b7b724ac"
    SUBNET_ID_2="subnet-099fca76d17b2fd4f"
    
    # Launch Amazon Linux 2 Instance
    aws ec2 run-instances \
        --image-id ami-0648742c7600c103f \
        --count 1 \
        --instance-type $INSTANCE_TYPE \
        --associate-public-ip-address \
        --key-name $KEY_NAME \
        --security-group-ids $SECURITY_GROUP_ID \
        --subnet-id $SUBNET_ID_1 \
        --region $REGION \
        --user-data file:///users/josephmbatchou/amazon-linux-user-data.sh \
        --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=AmazonLinux2-Instance},{Key=OS,Value=AmazonLinux2}]'
    
    # Launch Ubuntu Instance
    aws ec2 run-instances \
        --image-id ami-0075013580f6322a1 \
        --count 1 \
        --instance-type $INSTANCE_TYPE \
        --key-name $KEY_NAME \
        --associate-public-ip-address \
        --security-group-ids $SECURITY_GROUP_ID \
        --subnet-id $SUBNET_ID_2 \
        --region $REGION \
        --user-data file:///users/josephmbatchou/ubuntu-user-data.sh \
        --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=Ubuntu-Instance},{Key=OS,Value=Ubuntu}]'
    ```
    
* Create both Bash script user data scripts to install Docker and Jenkins on the instances. Files are "amazon-linux-user-data.sh" and "ubuntu-user-data.sh"
    

amazon-linux-user-data.sh

```bash
#!/bin/bash

# install Jenkins
sudo yum update -y
sudo 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-2023.key
sudo yum upgrade
sudo yum install java-17-amazon-corretto -y
sudo yum install jenkins -y
sudo systemctl start jenkins
sudo systemctl enable jenkins
sudo systemctl restart jenkins
sudo usermod -aG jenkins ec2-user

#install Docker
sudo yum update -y
sudo yum install python3-pip
sudo amazon-linux-extras install docker
sudo yum install -y docker
sudo service docker start
sudo systemctl enable docker
sudo systemctl restart docker
sudo usermod -aG docker ec2-user
```

ubuntu-user-data.sh

```bash
#!/bin/bash

#Install Jenkins
sudo apt-get update -y
sudo apt-get install openjdk-17-jdk -y
sudo curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee   /usr/share/keyrings/jenkins-keyring.asc > /dev/null
sudo echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]   https://pkg.jenkins.io/debian-stable binary/ | sudo tee   /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update
sudo apt-get install jenkins -y
sudo systemctl start jenkins
sudo systemctl enable jenkins
sudo usermod -aG jenkins ubuntu
sudo ufw allow 8080
sudo ufw allow OpenSSH
sudo ufw enabley

#install Docker
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
   "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
   $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
   sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl start docker.service
sudo systemctl enable docker.service
sudo usermod -aG docker ubuntu
```

* Use the AWS CLI to launch Amazon Linux 2 and Ubuntu EC2 instances:
    
    In order to run the script to provision the infrastructure by using CLI you must be in the prompt where your AWS CLI is configure and in the default region. Our Default region here is "us-west-2" You can verify this by using command
    

```bash
aws configure
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722042265708/3cc8df96-a595-4eac-875e-3a37b23418b3.png align="center")

Once you are set up you will have to make each script to be executable by changing modification command.

```bash
chmod +x launch-instances.sh
chmod +x amazon-linux-user-data.sh
chmod +x ubuntu-user-data.sh
```

As the both user data script are incorporated in the instance script you will only have to run the launch instance script with the command

```bash
./launch-instance.sh
```

The process of launching resources will follow and you will get results succeeded.

Linux instance

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722043508802/6818a1ef-451a-4bb4-9aac-2cb099b1b28b.png align="center")

Ubuntu instance

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722043521991/54055292-cb61-4478-b33d-5035382bbd66.png align="center")

step 3: RESULTS

You can go to the console and see that two instances were created and by connecting to them via SSH you will check for tools installed.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722042283193/d98d38b3-9ecc-403c-933b-dd792b375ac4.png align="center")

As you will ssh to each instances you will now check for each applications version to confirm the installation.

Linux instance

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722043482461/a18ae084-30e6-4b4a-9e5e-fbb7fd38c603.png align="center")

Ubuntu instance

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722042426063/f925f37b-dbdb-41a0-af8b-479c268b02e5.png align="center")

Step 4: CLEAN UP

To delete both instances you can only check for each instances Id and use command terminate-instance to destroy them.

```bash
aws ec2 terminate-instances --instance-ids <instance-id>
```

By using the command with the right instances id you will terminated the both instances.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1722043453972/916763d0-ce8d-4490-9c77-57d3986b69b2.png align="center")

## 📌 Conclusion

This project showcases three different approaches to launching and configuring EC2 instances with Docker and Jenkins. Each method has its advantages and can be chosen based on specific requirements and preferences. The use of infrastructure as code tools like CloudFormation and Terraform ensures reproducibility and ease of management, while Bash scripting provides flexibility and simplicity.

## **🤝 Contributing**

Your perspective is valuable! Whether you see potential for improvement or appreciate what's already here, your contributions are welcomed and appreciated. Thank you for considering joining us in making this project even better. Feel free to follow me for updates on this project and others, and to explore opportunities for collaboration. Together, we can create something amazing!

## 📄 License

This project is licensed under the Joebaho Cloud License
