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

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

ยท

17 min read

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

                                      +-----------------------------+
                                      |         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: Description

Step 2: Instructions of deployment

Step 3: Results

Step 4: Clean up

II - Terraform Script

Step 1: Description

Step 2: Instructions of deployment

Step 3: Results

Step 4: Clean Up

III - Bash Script

Step 1: Description

Step 2: Instructions of deployment

Step 3: Results

Step 4: 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

      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

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

ubuntu stack

After launching both stacks you will get the complete stage

Step 3: RESULTS

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

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

Linux instance

ubuntu instance

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" .

โœจ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

      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

      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
    terraform init
  1. Check the correct syntax of the file
    terraform fmt
  1. Valid the status of the file
    terraform validate
  1. Plan to see which resources will be create
    terraform plan
  1. Create the resources with command
    terraform apply

After all this we will get to the result images

  • Linux instance

    In the console you have

    Ubutntu

    In the console

    After SSM connect to each instances we have the result of different version

    For Linux instance

  • For Ubuntu instance

    Step 4: CLEAN UP

    Use the command destroy to delete all the infrastructures

      terraform destroy
    

For the Linux instance

For the ubuntu instance

โœจ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). 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.

      #!/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

#!/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

#!/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

aws configure

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

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

./launch-instance.sh

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

Linux instance

Ubuntu instance

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.

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

Linux instance

Ubuntu instance

Step 4: CLEAN UP

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

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

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

๐Ÿ“Œ 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

ย