├── .gitignore ├── 01-jenkins-setup ├── README.md ├── ansible │ ├── jenkins-agent.yaml │ ├── jenkins-controller.yaml │ ├── roles │ │ ├── jenkins-agent │ │ │ └── tasks │ │ │ │ ├── java.yaml │ │ │ │ ├── main.yaml │ │ │ │ ├── ssh.yaml │ │ │ │ └── tools.yaml │ │ └── jenkins-controller │ │ │ ├── tasks │ │ │ ├── base.yaml │ │ │ ├── efs.yaml │ │ │ ├── jenkins.yaml │ │ │ └── main.yaml │ │ │ └── templates │ │ │ └── override.conf.j2 │ └── scripts │ │ └── get-ssh-pub.py ├── jenkins-agent.pkr.hcl ├── jenkins-controller.pkr.hcl └── terraform │ ├── agent │ └── main.tf │ ├── efs │ └── main.tf │ ├── iam │ └── main.tf │ ├── lb-asg │ └── main.tf │ └── modules │ ├── ec2 │ ├── main.tf │ └── variable.tf │ ├── efs │ ├── main.tf │ └── variable.tf │ ├── iam │ ├── main.tf │ └── variables.tf │ └── lb-asg │ ├── main.tf │ └── variable.tf ├── 02-consul-sevice-discovery ├── README.md ├── ansible │ ├── backends.yaml │ ├── configs │ │ ├── ansible.cfg │ │ └── inventory.ini │ ├── consul-server.yaml │ ├── load-balancer.yaml │ └── roles │ │ ├── backends │ │ ├── tasks │ │ │ ├── consul.yaml │ │ │ ├── main.yaml │ │ │ └── nginx.yaml │ │ ├── templates │ │ │ ├── backend.json.j2 │ │ │ ├── config.json.j2 │ │ │ ├── consul.service.j2 │ │ │ └── index.html.j2 │ │ └── vars │ │ │ └── main.yaml │ │ ├── consul │ │ ├── tasks │ │ │ └── main.yaml │ │ ├── templates │ │ │ ├── consul.hcl.j2 │ │ │ └── consul.service.j2 │ │ └── vars │ │ │ └── main.yaml │ │ └── load-balancer │ │ ├── files │ │ └── load-balancer.conf.ctmpl │ │ ├── handlers │ │ └── main.yaml │ │ ├── tasks │ │ ├── consul.yaml │ │ ├── main.yaml │ │ └── nginx.yaml │ │ ├── templates │ │ └── consul-template.hcl.j2 │ │ └── vars │ │ └── main.yaml └── terraform │ ├── provision.tf │ └── variable.tf ├── 03-scalable-java-app ├── Jenkinsfile ├── README.md ├── ansible │ ├── files │ │ ├── application.properties │ │ ├── properties.py │ │ └── start.sh │ ├── java-app.pkr.hcl │ ├── java-app.yml │ ├── roles │ │ └── java │ │ │ └── tasks │ │ │ ├── app.yml │ │ │ ├── backends.yml │ │ │ ├── cloudwatch.yml │ │ │ ├── java.yml │ │ │ ├── main.yml │ │ │ └── python.yml │ └── templates │ │ ├── config.json.j2 │ │ └── index.html.j2 └── terraform │ ├── alb-asg │ ├── main.tf │ └── variable.tf │ ├── modules │ ├── alb-asg │ │ ├── alb.tf │ │ ├── asg.tf │ │ ├── iam-policy.tf │ │ └── variable.tf │ └── rds │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── rds │ ├── main.tf │ └── variables.tf │ └── vars │ ├── alb-asg.tfvars │ └── rds.tfvars ├── 04-prometheus-observability-stack ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── alertmanager │ └── alertmanager.yml ├── docker-compose.yml ├── prometheus │ ├── alertrules.yml │ ├── prometheus.yml │ └── targets.json └── terraform-aws │ ├── README.md │ ├── modules │ ├── ec2 │ │ ├── main.tf │ │ ├── outputs.tf │ │ ├── user-data.sh │ │ └── variables.tf │ └── security-group │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── prometheus-stack │ ├── main.tf │ ├── outputs.tf │ └── variables.tf │ └── vars │ └── ec2.tfvars ├── 05-aws-vpc-design-and-automation └── README.md ├── 06-aws-client-vpn-setup └── README.md ├── 07-pritunl-vpn-setup ├── OpenVPN.png └── README.md ├── 08-fargate-app-deployment ├── eks-fargate.yaml ├── fp-game.yaml ├── helm │ └── game-2048 │ │ ├── Chart.yaml │ │ ├── templates │ │ ├── deployment.yaml │ │ └── service.yaml │ │ └── values.yaml └── tf-vpc │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── vpc.tfvars ├── README.md ├── generic-infra-code ├── README.md └── terraform │ ├── dev │ └── ec2 │ │ └── main.tf │ └── modules │ └── ec2 │ ├── main.tf │ └── variable.tf └── platform-tools └── aws-amis ├── ansible ├── grafana.yml ├── nexus.yaml ├── prometheus.yml └── roles │ ├── nexus │ ├── tasks │ │ └── main.yaml │ └── templates │ │ └── nexus.service.j2 │ └── prometheus │ ├── tasks │ ├── configuration.yml │ ├── installation.yml │ └── main.yml │ └── templates │ └── prometheus.service.j2 ├── grafana └── grafana.pkr.hcl ├── nexus └── nexus.pkr.hcl └── prometheus └── vm.pkr.hcl /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | .DS_Store 3 | **/.DS_Store 4 | **/.terraform.lock.hcl 5 | .AppleDouble 6 | .LSOverride 7 | **/manifest.json 8 | .vscode 9 | **/..vscode 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | # Thumbnails 15 | ._* 16 | 17 | # Files that might appear in the root of a volume 18 | .DocumentRevisions-V100 19 | .fseventsd 20 | .Spotlight-V100 21 | .TemporaryItems 22 | .Trashes 23 | .VolumeIcon.icns 24 | .com.apple.timemachine.donotpresent 25 | 26 | # Directories potentially created on remote AFP share 27 | .AppleDB 28 | .AppleDesktop 29 | Network Trash Folder 30 | Temporary Items 31 | .apdisk 32 | *.retry 33 | # Local .terraform directories 34 | **/.terraform/* 35 | 36 | # .tfstate files 37 | *.tfstate 38 | *.tfstate.* 39 | 40 | # Crash log files 41 | crash.log 42 | crash.*.log 43 | 44 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 45 | # password, private keys, and other secrets. These should not be part of version 46 | # control as they are data points which are potentially sensitive and subject 47 | # to change depending on the environment. 48 | *.tfvars.json 49 | 50 | # Ignore override files as they are usually used to override resources locally and so 51 | # are not checked in 52 | override.tf 53 | override.tf.json 54 | *_override.tf 55 | *_override.tf.json 56 | 57 | # Include override files you do wish to add to version control using negated pattern 58 | # !example_override.tf 59 | 60 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 61 | # example: *tfplan* 62 | 63 | # Ignore CLI configuration files 64 | .terraformrc 65 | terraform.rc -------------------------------------------------------------------------------- /01-jenkins-setup/README.md: -------------------------------------------------------------------------------- 1 | ## Project Course 2 | 3 | **Detailed Video/Walkthrough Course (Free):** [techiescamp.com/courses/deploying-jenkins-aws/](https://techiescamp.com/p/project-jenkins-ha-setup-on-aws-terraform-ansible-packer) 4 | 5 | ## Setup Architecture 6 | 7 | ![jenkins-ha](https://user-images.githubusercontent.com/106984297/226690774-66731923-a2cd-45cc-b387-c959e5b713c1.png) 8 | 9 | 10 | ## Project Documentation. 11 | 12 | Refer [Jenkins Setup Using AWS Autoscaling Group](https://devopscube.com/jenkins-autoscaling-setup/) for the entire setup walkthrough. 13 | -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/jenkins-agent.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Jenkins on servers 3 | hosts: all 4 | become: true 5 | remote_user: ubuntu 6 | 7 | vars: 8 | public_key_path: "/devops-tools/jenkins/id_rsa.pub" 9 | 10 | roles: 11 | - jenkins-agent 12 | -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/jenkins-controller.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Jenkins on servers 3 | hosts: all 4 | become: true 5 | remote_user: ubuntu 6 | 7 | vars: 8 | efs_mount_dir: "/data" 9 | jenkins_data_dir: "/data/jenkins" 10 | jenkins_lts_version: "2.492.1" 11 | 12 | 13 | roles: 14 | - jenkins-controller 15 | -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/roles/jenkins-agent/tasks/java.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Update apt cache 3 | apt: 4 | update_cache: yes 5 | 6 | - name: Install Java JDK 17 7 | apt: 8 | name: openjdk-17-jdk 9 | state: present 10 | -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/roles/jenkins-agent/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - include_tasks: java.yaml 3 | - include_tasks: tools.yaml 4 | - include_tasks: ssh.yaml -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/roles/jenkins-agent/tasks/ssh.yaml: -------------------------------------------------------------------------------- 1 | 2 | - name: Retrieve secret value from AWS Parameter Store 3 | script: "{{ playbook_dir }}/scripts/get-ssh-pub.py {{ public_key_path }}" 4 | args: 5 | executable: /usr/bin/python3 6 | register: secret_value 7 | 8 | - name: Print registered variable 9 | debug: 10 | var: secret_value 11 | 12 | - name: Add public key to authorized_keys for ubuntu user 13 | authorized_key: 14 | user: ubuntu 15 | state: present 16 | key: "{{ secret_value.stdout }}" -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/roles/jenkins-agent/tasks/tools.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Python 3 3 | apt: 4 | name: python3 5 | state: present 6 | 7 | - name: Install pip 8 | apt: 9 | name: python3-pip 10 | state: present 11 | 12 | - name: Install boto3 using apt 13 | apt: 14 | name: python3-boto3 15 | state: present 16 | become: yes 17 | 18 | - name: Install dependencies 19 | apt: 20 | name: 21 | - curl 22 | - unzip 23 | state: present 24 | 25 | - name: Download AWS CLI installation script 26 | shell: curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip" 27 | 28 | - name: Unzip AWS CLI installation package 29 | unarchive: 30 | src: /tmp/awscliv2.zip 31 | dest: /tmp/ 32 | remote_src: yes 33 | 34 | - name: Install AWS CLI 35 | shell: sudo /tmp/aws/install 36 | 37 | - name: Install Ansible 38 | apt: 39 | name: ansible 40 | state: latest 41 | 42 | - name: Download and convert HashiCorp GPG key in one step 43 | shell: | 44 | curl -fsSL https://apt.releases.hashicorp.com/gpg | gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg 45 | args: 46 | creates: /usr/share/keyrings/hashicorp-archive-keyring.gpg 47 | 48 | - name: Add HashiCorp APT repository 49 | become: yes 50 | shell: "echo 'deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com {{ ansible_distribution_release }} main' | sudo tee /etc/apt/sources.list.d/hashicorp.list" 51 | 52 | - name: Update apt cache 53 | become: yes 54 | become_method: sudo 55 | apt: 56 | update_cache: yes 57 | 58 | - name: Install Terraform 59 | apt: 60 | name: terraform 61 | state: present 62 | 63 | - name: Install Packer 64 | apt: 65 | name: packer 66 | state: present 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/roles/jenkins-controller/tasks/base.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Update apt cache 3 | apt: 4 | update_cache: yes 5 | 6 | - name: Install Python 3 7 | apt: 8 | name: python3 9 | state: present 10 | 11 | - name: Install pip 12 | apt: 13 | name: python3-pip 14 | state: present 15 | 16 | - name: Install boto3 using apt 17 | apt: 18 | name: python3-boto3 19 | state: present 20 | become: yes 21 | 22 | - name: Install dependencies 23 | apt: 24 | name: 25 | - curl 26 | - unzip 27 | state: present 28 | 29 | - name: Download AWS CLI installation script 30 | shell: curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip" 31 | 32 | - name: Unzip AWS CLI installation package 33 | unarchive: 34 | src: /tmp/awscliv2.zip 35 | dest: /tmp/ 36 | remote_src: yes 37 | 38 | - name: Install AWS CLI 39 | shell: sudo /tmp/aws/install 40 | 41 | - name: Install Java JDK 17 42 | apt: 43 | name: openjdk-17-jdk 44 | state: present 45 | -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/roles/jenkins-controller/tasks/efs.yaml: -------------------------------------------------------------------------------- 1 | - name: Install NFS client 2 | apt: 3 | name: nfs-common 4 | state: present 5 | 6 | - name: Ensure mount directory exists. 7 | file: 8 | path: "{{ efs_mount_dir }}" 9 | state: directory 10 | mode: 0755 11 | 12 | - name: Ensure EFS volume is mounted. 13 | mount: 14 | name: "{{ efs_mount_dir }}" 15 | src: "{{ efs_mount_point }}:/" 16 | fstype: nfs4 17 | opts: nfsvers=4.1 18 | state: mounted -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/roles/jenkins-controller/tasks/jenkins.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Add Jenkins apt repository key. 3 | ansible.builtin.get_url: 4 | url: "https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key" 5 | dest: /etc/apt/trusted.gpg.d/jenkins.asc 6 | mode: '0644' 7 | force: true 8 | 9 | - name: Add Jenkins apt repository. 10 | apt_repository: 11 | repo: "deb https://pkg.jenkins.io/debian-stable binary/" 12 | state: present 13 | update_cache: true 14 | 15 | - name: Install Jenkins 16 | apt: 17 | name: jenkins={{ jenkins_lts_version }} 18 | state: present 19 | 20 | - name: Stop Jenkins service 21 | systemd: 22 | name: jenkins.service 23 | state: stopped 24 | 25 | - name: Move Jenkins data to new directory 26 | copy: src=/var/lib/jenkins/ dest={{ jenkins_data_dir }} remote_src=yes directory_mode=yes 27 | 28 | - name: Change directory owner 29 | file: 30 | path: "{{ jenkins_data_dir }}" 31 | owner: jenkins 32 | group: jenkins 33 | recurse: yes 34 | 35 | - name: Remove old Jenkins data directory 36 | file: 37 | path: /var/lib/jenkins/ 38 | state: absent 39 | 40 | - name: Create override directory for Jenkins service 41 | become: true 42 | file: 43 | path: /etc/systemd/system/jenkins.service.d 44 | state: directory 45 | 46 | - name: Add override file for Jenkins 47 | template: 48 | src: override.conf.j2 49 | dest: /etc/systemd/system/jenkins.service.d/override.conf 50 | owner: root 51 | group: root 52 | mode: '0644' 53 | 54 | - name: Reload systemd daemon configuration 55 | systemd: 56 | daemon_reload: yes 57 | 58 | - name: Start Jnekins Service 59 | systemd: 60 | name: jenkins 61 | state: started 62 | 63 | -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/roles/jenkins-controller/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - include_tasks: base.yaml 3 | - include_tasks: efs.yaml 4 | - include_tasks: jenkins.yaml -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/roles/jenkins-controller/templates/override.conf.j2: -------------------------------------------------------------------------------- 1 | [Service] 2 | Environment="JENKINS_HOME={{ jenkins_data_dir }}" 3 | WorkingDirectory={{ jenkins_data_dir }} -------------------------------------------------------------------------------- /01-jenkins-setup/ansible/scripts/get-ssh-pub.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import json 3 | import sys 4 | 5 | client = boto3.client('ssm', region_name='us-east-1') 6 | response = client.get_parameter(Name=sys.argv[1], WithDecryption=True) 7 | print(response['Parameter']['Value']) 8 | -------------------------------------------------------------------------------- /01-jenkins-setup/jenkins-agent.pkr.hcl: -------------------------------------------------------------------------------- 1 | variable "ami_id" { 2 | type = string 3 | default = "ami-04b4f1a9cf54c11d0" 4 | } 5 | 6 | variable "public_key_path" { 7 | type = string 8 | default = "/devops-tools/jenkins/id_rsa.pub" 9 | } 10 | 11 | locals { 12 | app_name = "jenkins-agent" 13 | } 14 | 15 | source "amazon-ebs" "jenkins" { 16 | ami_name = "${local.app_name}" 17 | instance_type = "t2.micro" 18 | region = "us-east-1" 19 | availability_zone = "us-east-1c" 20 | source_ami = "${var.ami_id}" 21 | ssh_username = "ubuntu" 22 | iam_instance_profile = "jenkins-instance-profile" 23 | tags = { 24 | Env = "dev" 25 | Name = "${local.app_name}" 26 | } 27 | } 28 | 29 | build { 30 | sources = ["source.amazon-ebs.jenkins"] 31 | 32 | provisioner "ansible" { 33 | playbook_file = "ansible/jenkins-agent.yaml" 34 | extra_arguments = [ "--extra-vars", "public_key_path=${var.public_key_path}", "--scp-extra-args", "'-O'", "--ssh-extra-args", "-o IdentitiesOnly=yes -o HostKeyAlgorithms=+ssh-rsa" ] 35 | } 36 | 37 | post-processor "manifest" { 38 | output = "manifest.json" 39 | strip_path = true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /01-jenkins-setup/jenkins-controller.pkr.hcl: -------------------------------------------------------------------------------- 1 | variable "ami_id" { 2 | type = string 3 | default = "ami-04b4f1a9cf54c11d0" 4 | } 5 | 6 | variable "efs_mount_point" { 7 | type = string 8 | default = "" 9 | } 10 | 11 | locals { 12 | app_name = "jenkins-controller-updated" 13 | } 14 | 15 | source "amazon-ebs" "jenkins" { 16 | ami_name = "${local.app_name}" 17 | instance_type = "t2.micro" 18 | region = "us-east-1" 19 | availability_zone = "us-east-1d" 20 | source_ami = "${var.ami_id}" 21 | ssh_username = "ubuntu" 22 | tags = { 23 | Env = "dev" 24 | Name = "${local.app_name}" 25 | } 26 | } 27 | 28 | build { 29 | sources = ["source.amazon-ebs.jenkins"] 30 | 31 | provisioner "ansible" { 32 | playbook_file = "ansible/jenkins-controller.yaml" 33 | extra_arguments = [ "--extra-vars", "ami-id=${var.ami_id} efs_mount_point=${var.efs_mount_point}", "--scp-extra-args", "'-O'", "--ssh-extra-args", "-o IdentitiesOnly=yes -o HostKeyAlgorithms=+ssh-rsa" ] 34 | } 35 | 36 | post-processor "manifest" { 37 | output = "manifest.json" 38 | strip_path = true 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/agent/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | module "ec2_instance" { 6 | source = "../modules/ec2" 7 | instance_name = "jenkins-agent" 8 | ami_id = "ami-0fe5ed92a8c77d79f" 9 | instance_type = "t2.small" 10 | key_name = "jenkinskey" 11 | subnet_ids = ["subnet-046c3f4390fc51b7e", "subnet-02727435b393c516c", "subnet-0ed1c80066f1be7ed"] 12 | instance_count = 1 13 | } 14 | -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/efs/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | module "efs_module" { 6 | source = "../modules/efs" 7 | vpc_id = "vpc-0872a2ffd55e763ca" 8 | subnet_ids = ["subnet-046c3f4390fc51b7e", "subnet-02727435b393c516c", "subnet-0ed1c80066f1be7ed"] 9 | } -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/iam/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | module "jenkins_iam" { 6 | source = "../modules/iam" 7 | instance_profile_name = "jenkins-instance-profile" 8 | iam_policy_name = "jenkins-iam-policy" 9 | role_name = "jenkins-role" 10 | } 11 | -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/lb-asg/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | module "lb-asg" { 6 | source = "../modules/lb-asg" 7 | subnets = ["subnet-046c3f4390fc51b7e", "subnet-02727435b393c516c", "subnet-0ed1c80066f1be7ed"] 8 | ami_id = "ami-0e9419006a1fc1387" 9 | instance_type = "t2.small" 10 | key_name = "jenkinskey" 11 | environment = "dev" 12 | vpc_id = "vpc-0872a2ffd55e763ca" 13 | } -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/modules/ec2/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "jenkins-agent" { 2 | name = "jenkins-agent" 3 | description = "Allow SSH inbound traffic from everywhere and all outbound traffic" 4 | 5 | ingress { 6 | from_port = 22 7 | to_port = 22 8 | protocol = "tcp" 9 | cidr_blocks = ["0.0.0.0/0"] 10 | } 11 | 12 | egress { 13 | from_port = 0 14 | to_port = 0 15 | protocol = "-1" 16 | cidr_blocks = ["0.0.0.0/0"] 17 | } 18 | } 19 | 20 | 21 | resource "aws_instance" "example" { 22 | count = var.instance_count 23 | 24 | ami = var.ami_id 25 | instance_type = var.instance_type 26 | key_name = var.key_name 27 | vpc_security_group_ids = [aws_security_group.jenkins-agent.id] 28 | 29 | tags = { 30 | Name = "${var.instance_name}-${count.index + 1}" 31 | } 32 | 33 | subnet_id = element(var.subnet_ids, count.index % length(var.subnet_ids)) 34 | } 35 | -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/modules/ec2/variable.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | variable "instance_name" { 6 | type = string 7 | default = "live-test-instance" 8 | } 9 | 10 | variable "ami_id" { 11 | type = string 12 | default = "ami-0735c191cf914754d" 13 | } 14 | 15 | variable "instance_type" { 16 | type = string 17 | default = "t2.small" 18 | } 19 | 20 | variable "key_name" { 21 | type = string 22 | default = "jenkinskey" 23 | } 24 | 25 | variable "security_group_ids" { 26 | type = list(string) 27 | default = ["sg-01ce819e8d65269f0"] 28 | } 29 | 30 | variable "instance_count" { 31 | type = number 32 | default = 1 33 | } 34 | 35 | variable "subnet_ids" { 36 | type = list(string) 37 | default = ["subnet-058a7514ba8adbb07", "subnet-0dbcd1ac168414927", "subnet-032f5077729435858"] 38 | } -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/modules/efs/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "efs_sg" { 2 | name_prefix = "efs-sg" 3 | vpc_id = var.vpc_id 4 | 5 | ingress { 6 | from_port = 2049 7 | to_port = 2049 8 | protocol = "tcp" 9 | cidr_blocks = ["0.0.0.0/0"] 10 | } 11 | egress { 12 | from_port = 0 13 | to_port = 0 14 | protocol = "-1" 15 | cidr_blocks = ["0.0.0.0/0"] 16 | } 17 | } 18 | 19 | resource "aws_efs_file_system" "jenkins" { 20 | creation_token = "jenkins" 21 | encrypted = true 22 | performance_mode = "generalPurpose" 23 | throughput_mode = "bursting" 24 | tags = { 25 | Name = "jenkins-efs" 26 | } 27 | } 28 | 29 | resource "aws_efs_mount_target" "jenkins" { 30 | count = length(var.subnet_ids) 31 | file_system_id = aws_efs_file_system.jenkins.id 32 | subnet_id = var.subnet_ids[count.index] 33 | security_groups = [aws_security_group.efs_sg.id] 34 | } 35 | -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/modules/efs/variable.tf: -------------------------------------------------------------------------------- 1 | variable "vpc_id" {} 2 | 3 | variable "subnet_ids" { 4 | type = list 5 | } -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/modules/iam/main.tf: -------------------------------------------------------------------------------- 1 | 2 | # Create an IAM policy 3 | resource "aws_iam_policy" "jenkins_iam_policy" { 4 | name = var.iam_policy_name 5 | 6 | policy = jsonencode({ 7 | Version = "2012-10-17" 8 | Statement = [ 9 | { 10 | Effect = "Allow" 11 | Action = [ 12 | "ssm:GetParameter", 13 | "ssm:GetParameters", 14 | "ssm:GetParametersByPath" 15 | ] 16 | Resource = "*" 17 | } 18 | ] 19 | }) 20 | } 21 | 22 | # Create an IAM role 23 | resource "aws_iam_role" "jenkins_role" { 24 | name = var.role_name 25 | 26 | assume_role_policy = jsonencode({ 27 | Version = "2012-10-17" 28 | Statement = [ 29 | { 30 | Effect = "Allow" 31 | Principal = { 32 | Service = "ec2.amazonaws.com" 33 | } 34 | Action = "sts:AssumeRole" 35 | } 36 | ] 37 | }) 38 | } 39 | 40 | # Attach the IAM policy to the IAM role 41 | resource "aws_iam_policy_attachment" "jenkins_role_policy_attachment" { 42 | name = "Policy Attachement" 43 | policy_arn = aws_iam_policy.jenkins_iam_policy.arn 44 | roles = [aws_iam_role.jenkins_role.name] 45 | } 46 | 47 | # Create an IAM instance profile 48 | resource "aws_iam_instance_profile" "jenkins_instance_profile" { 49 | name = var.instance_profile_name 50 | role = aws_iam_role.jenkins_role.name 51 | } 52 | -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/modules/iam/variables.tf: -------------------------------------------------------------------------------- 1 | variable "instance_profile_name" { 2 | type = string 3 | default = "example-instance-profile" 4 | } 5 | 6 | variable "iam_policy_name" { 7 | type = string 8 | default = "example-policy" 9 | } 10 | 11 | variable "role_name" { 12 | type = string 13 | default = "example-role" 14 | } 15 | -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/modules/lb-asg/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "alb_sg" { 2 | name_prefix = "alb-sg" 3 | 4 | ingress { 5 | from_port = 80 6 | to_port = 80 7 | protocol = "tcp" 8 | cidr_blocks = ["0.0.0.0/0"] 9 | } 10 | 11 | egress { 12 | from_port = 0 13 | to_port = 0 14 | protocol = "-1" 15 | cidr_blocks = ["0.0.0.0/0"] 16 | } 17 | 18 | tags = { 19 | Name = "jenkins-alb-sg" 20 | } 21 | } 22 | 23 | resource "aws_lb" "jenkins" { 24 | name = "jenkins-alb" 25 | internal = false 26 | load_balancer_type = "application" 27 | 28 | subnets = var.subnets 29 | security_groups = [aws_security_group.alb_sg.id] 30 | 31 | tags = { 32 | Environment = var.environment 33 | Terraform = "true" 34 | } 35 | } 36 | 37 | resource "aws_security_group" "instance_sg" { 38 | name_prefix = "jenkins-controller-sg" 39 | 40 | ingress { 41 | from_port = 22 42 | to_port = 22 43 | protocol = "tcp" 44 | cidr_blocks = ["0.0.0.0/0"] 45 | } 46 | 47 | ingress { 48 | from_port = 8080 49 | to_port = 8080 50 | protocol = "tcp" 51 | cidr_blocks = ["0.0.0.0/0"] 52 | } 53 | 54 | egress { 55 | from_port = 0 56 | to_port = 0 57 | protocol = "-1" 58 | cidr_blocks = ["0.0.0.0/0"] 59 | } 60 | 61 | tags = { 62 | Name = "jenkins-controller-sg" 63 | } 64 | } 65 | 66 | 67 | resource "aws_lb_target_group" "jenkins" { 68 | name_prefix = "jks-lb" 69 | port = 8080 70 | protocol = "HTTP" 71 | vpc_id = var.vpc_id 72 | target_type = "instance" 73 | 74 | health_check { 75 | path = "/login" 76 | port = 8080 77 | protocol = "HTTP" 78 | interval = 30 79 | timeout = 5 80 | healthy_threshold = 2 81 | unhealthy_threshold = 2 82 | } 83 | 84 | tags = { 85 | Environment = var.environment 86 | Terraform = "true" 87 | } 88 | } 89 | 90 | resource "aws_lb_listener" "jenkins" { 91 | load_balancer_arn = aws_lb.jenkins.arn 92 | port = 80 93 | protocol = "HTTP" 94 | 95 | default_action { 96 | target_group_arn = aws_lb_target_group.jenkins.arn 97 | type = "forward" 98 | } 99 | } 100 | 101 | resource "aws_launch_template" "jenkins" { 102 | name_prefix = "jenkins-controller-lt" 103 | image_id = var.ami_id 104 | instance_type = var.instance_type 105 | key_name = var.key_name 106 | 107 | network_interfaces { 108 | associate_public_ip_address = true 109 | security_groups = [aws_security_group.instance_sg.id] 110 | } 111 | } 112 | 113 | resource "aws_autoscaling_group" "jenkins" { 114 | name = "jenkins-controller-asg" 115 | max_size = 1 116 | min_size = 1 117 | desired_capacity = 1 118 | vpc_zone_identifier = var.subnets 119 | launch_template { 120 | id = aws_launch_template.jenkins.id 121 | version = aws_launch_template.jenkins.latest_version 122 | } 123 | 124 | tag { 125 | key = "Name" 126 | value = "jenkins-controller" 127 | propagate_at_launch = true 128 | } 129 | 130 | lifecycle { 131 | create_before_destroy = true 132 | ignore_changes = [load_balancers, target_group_arns] 133 | } 134 | 135 | # instance_refresh { 136 | # strategy = "Rolling" 137 | # triggers = ["launch_template"] 138 | # } 139 | } 140 | 141 | 142 | resource "aws_autoscaling_attachment" "jenkins" { 143 | autoscaling_group_name = aws_autoscaling_group.jenkins.name 144 | lb_target_group_arn = aws_lb_target_group.jenkins.arn 145 | } -------------------------------------------------------------------------------- /01-jenkins-setup/terraform/modules/lb-asg/variable.tf: -------------------------------------------------------------------------------- 1 | variable "ami_id" { 2 | description = "The ID of the Amazon Machine Image (AMI) to use for the EC2 instances." 3 | } 4 | 5 | variable "instance_type" { 6 | description = "The type of EC2 instance to use for the ASG." 7 | } 8 | 9 | variable "key_name" { 10 | description = "The name of the EC2 key pair to use for the instances." 11 | } 12 | 13 | variable "environment" { 14 | description = "The environment name for the resources." 15 | } 16 | 17 | variable "vpc_id" { 18 | description = "The ID of the VPC to use for the resources." 19 | } 20 | 21 | variable "subnets" { 22 | description = "A list of subnet IDs to use for the resources." 23 | type = list(string) 24 | } 25 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/README.md: -------------------------------------------------------------------------------- 1 | ## Project Architecture 2 | 3 | ![service-discovery](https://user-images.githubusercontent.com/106984297/219394737-6f41c9f3-6c34-420b-9da2-9cc819f9c076.png) 4 | 5 | ## Manual Setup 6 | 7 | If you want to practically learn service discovery, I suggest you set up Nginx load balancing using consul service discovery setup manually and learn all the components and workflows involved in it. 8 | 9 | **Checkout the Prctical Guide:** [Service Discovery Example Using Consul & Nginx](https://devopscube.com/service-discovery-example/) 10 | 11 | ## Automation Prerequisites 12 | 13 | - You need to have a valid AWS account 14 | - A workstation or AWS instance configured with AWS CLI, Ansbile and Terrform with full access to provision ec2 instances. 15 | 16 | 17 | ## Provision Instances Using Terraform 18 | 19 | ### Prepare the variable file 20 | 21 | Repalce the parameters in the terraform.tfvars. 22 | 23 | Primarily you need to replace the key name `techiescamp` to the pem key you have in your AWS account. 24 | Other parameters are common or AWS oregon region with default VPC. If you are using a different region and VPC, replace it accordingly. 25 | 26 | ``` 27 | instance_type = "t2.micro" 28 | region = "us-west-2" 29 | ami = "ami-0735c191cf914754d" 30 | key_name = "techiescamp" 31 | ingress_cidr_block = "172.31.0.0/16" 32 | ``` 33 | 34 | ### Initialize terraform 35 | 36 | ``` 37 | terraform init 38 | ``` 39 | ### Dry Run Terraform 40 | 41 | Perform "dry run" of the terraform apply to check what changes will be made to your infrastructure when you apply your configuration. 42 | 43 | ``` 44 | terraform plan -var-file=terraform.tfvars 45 | 46 | ``` 47 | 48 | ### Provision Instances 49 | 50 | Provision the instances by applying the configuration. 51 | ``` 52 | terraform apply -var-file=terraform.tfvars -auto-approve 53 | ``` 54 | 55 | ## Configure Instances Using Ansible 56 | 57 | ### Create a inventory file to configure the instances 58 | 59 | Get all the IP addresses. 60 | 61 | ``` 62 | aws ec2 describe-instances \ 63 | --filters "Name=tag:Name,Values=consul-server,loadbalancer,backend-app" \ 64 | --query 'Reservations[].Instances[].[PrivateIpAddress,PublicIpAddress,Tags[?Key==`Name`].Value[]]' \ 65 | --output text 66 | ``` 67 | 68 | Modify the Ansible Inventory file as shown below. Repalce the IPs and pem key file location as per your Anisble configurations. 69 | 70 | ``` 71 | [consul] 72 | 54.188.111.53 73 | 74 | [load-balancer] 75 | 35.87.82.33 76 | 77 | [backends] 78 | 35.92.38.123 79 | 35.87.82.33 80 | 81 | [all:vars] 82 | ansible_user=ubuntu 83 | ansible_private_key_file=/home/vagrant/.ssh/techiescamp.pem 84 | ``` 85 | 86 | Cd in to ansible directory. 87 | 88 | ### Configure Consul Server 89 | 90 | ``` 91 | ansible-playbook consul-server.yaml 92 | ``` 93 | 94 | 95 | ### Configure Backends. 96 | 97 | Get the Consul server Private IP address and save it in the PRIVATE_IP variable. 98 | 99 | ``` 100 | PRIVATE_IP=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=consul-server" --query "Reservations[].Instances[].PrivateIpAddress" --output text) 101 | ``` 102 | 103 | Exeute the backend playbook 104 | 105 | ``` 106 | ansible-playbook -e "consul_server_address=$PRIVATE_IP" backends.yaml 107 | ``` 108 | ### Configure Load Balancer. 109 | 110 | Get the Consul server Private IP address and save it in the PRIVATE_IP variable. 111 | 112 | ``` 113 | PRIVATE_IP=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=consul-server" --query "Reservations[].Instances[].PrivateIpAddress" --output text) 114 | ``` 115 | Execute the load-balancer playbook 116 | 117 | ``` 118 | ansible-playbook -e "consul_server_address=$PRIVATE_IP:8500" load-balancer.yaml 119 | ``` 120 | 121 | 122 | ## validate the Setup 123 | 124 | If you visit the Loadblancer Ip you should be able to get the custom HTML page with backend server information. 125 | 126 | ## Tear Down the Servers 127 | 128 | cd in to terraform directory and run the following command 129 | 130 | ``` 131 | terraform destroy 132 | ``` 133 | 134 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/backends.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: backends 3 | remote_user: ubuntu 4 | become: yes 5 | 6 | # use command "consul keygen" to generate a new encryption key: 7 | 8 | vars: 9 | encrypt: "ZENZNrsXU336Uma+S4XUj9sxvICj32N7XdEzrbYbRpY=" 10 | 11 | roles: 12 | - backends 13 | 14 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/configs/ansible.cfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiescamp/devops-projects/4bd247b4df794262d88c9b7ee2594cffc34812fd/02-consul-sevice-discovery/ansible/configs/ansible.cfg -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/configs/inventory.ini: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiescamp/devops-projects/4bd247b4df794262d88c9b7ee2594cffc34812fd/02-consul-sevice-discovery/ansible/configs/inventory.ini -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/consul-server.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: consul 3 | remote_user: ubuntu 4 | become: yes 5 | 6 | roles: 7 | - consul 8 | 9 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/load-balancer.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: load-balancer 3 | remote_user: ubuntu 4 | become: yes 5 | 6 | roles: 7 | - load-balancer 8 | 9 | vars: 10 | consul_template_url: "https://releases.hashicorp.com/consul-template/0.30.0/consul-template_0.30.0_linux_amd64.zip" 11 | 12 | consul_server_address: 172.31.31.142:8500 -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/backends/tasks/consul.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Update apt cache 3 | apt: 4 | update_cache: yes 5 | 6 | - name: Install required packages 7 | apt: 8 | name: 9 | - wget 10 | - gnupg 11 | 12 | - name: Add HashiCorp GPG key and repository 13 | shell: | 14 | wget -qO - https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg 15 | 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 16 | 17 | - name: Update apt cache and install Consul 18 | apt: 19 | update_cache: yes 20 | name: consul 21 | state: present 22 | 23 | - name: Render Consul Configuration Template 24 | template: 25 | src: config.json.j2 26 | dest: /etc/consul.d/config.json 27 | vars: 28 | server: "false" 29 | datacenter: "dc1" 30 | 31 | - name: Render Consul Backend Template 32 | template: 33 | src: backend.json.j2 34 | dest: /etc/consul.d/backend.json 35 | 36 | - name: Create Consul systemd service unit 37 | template: 38 | src: consul.service.j2 39 | dest: /etc/systemd/system/consul.service 40 | 41 | - name: Reload systemd 42 | systemd: 43 | daemon_reload: yes 44 | 45 | - name: Start and enable Consul service 46 | systemd: 47 | name: consul 48 | state: started 49 | enabled: yes 50 | 51 | 52 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/backends/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: nginx.yaml 3 | - include: consul.yaml 4 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/backends/tasks/nginx.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check operating system 3 | debug: 4 | msg: "The operating system is {{ ansible_facts['os_family'] }}" 5 | when: ansible_facts['os_family'] == "Debian" 6 | 7 | - name: Update and upgrade apt packages 8 | become: true 9 | apt: 10 | upgrade: yes 11 | update_cache: yes 12 | 13 | - name: Install Nginx on Server 14 | apt: 15 | name: nginx 16 | state: latest 17 | 18 | - name: Copy Nginx Index HTML 19 | template: 20 | src: index.html.j2 21 | dest: /var/www/html/index.html 22 | 23 | - name: Start and enable a service 24 | service: 25 | name: nginx 26 | state: started 27 | enabled: yes 28 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/backends/templates/backend.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "Name": "backend", 4 | "Port": 80, 5 | "check": { 6 | "args": ["curl", "localhost"], 7 | "interval": "3s" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/backends/templates/config.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "server": {{ server }}, 3 | "datacenter": "{{ datacenter }}", 4 | "data_dir": "/var/consul", 5 | "encrypt": "{{ encrypt }}", 6 | "log_level": "INFO", 7 | "enable_script_checks": true, 8 | "enable_syslog": true, 9 | "leave_on_terminate": true, 10 | "start_join": [{{ consul_server_address | to_json }}] 11 | } -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/backends/templates/consul.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Consul service 3 | After=network.target 4 | 5 | [Service] 6 | ExecStart=/usr/bin/consul agent -dev -config-dir /etc/consul.d 7 | Restart=always 8 | User=root 9 | Group=nogroup 10 | LimitNOFILE=65536 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/backends/templates/index.html.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Server Information 8 | 9 | 10 | 17 |
18 |
19 |

Server Information

20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
IP Address{{ ansible_default_ipv4.address }}
Operating System{{ ansible_os_family }}
System Version{{ ansible_distribution_version }}
Memory{{ ansible_memtotal_mb }} MB
CPU{{ ansible_processor_vcpus }} vCPUs
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/backends/vars/main.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiescamp/devops-projects/4bd247b4df794262d88c9b7ee2594cffc34812fd/02-consul-sevice-discovery/ansible/roles/backends/vars/main.yaml -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/consul/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Update apt cache 3 | apt: 4 | update_cache: yes 5 | 6 | - name: Install required packages 7 | apt: 8 | name: 9 | - wget 10 | - gnupg 11 | 12 | - name: Add HashiCorp GPG key and repository 13 | shell: | 14 | wget -qO - https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg 15 | 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 16 | 17 | - name: Update apt cache and install Consul 18 | apt: 19 | update_cache: yes 20 | name: consul 21 | state: present 22 | 23 | - name: Render Consul Configuration Template 24 | template: 25 | src: consul.hcl.j2 26 | dest: /etc/consul.d/consul.hcl 27 | vars: 28 | bind_addr: 0.0.0.0 29 | client_addr: 0.0.0.0 30 | data_dir: /var/consul 31 | encrypt: "ZENZNrsXU336Uma+S4XUj9sxvICj32N7XdEzrbYbRpY=" 32 | datacenter: dc1 33 | ui: "true" 34 | leave_on_terminate: "true" 35 | server: "true" 36 | log_level: INFO 37 | 38 | - name: Create Consul systemd service unit 39 | template: 40 | src: consul.service.j2 41 | dest: /etc/systemd/system/consul.service 42 | 43 | - name: Reload systemd 44 | systemd: 45 | daemon_reload: yes 46 | 47 | - name: Start and enable Consul service 48 | systemd: 49 | name: consul 50 | state: started 51 | enabled: yes 52 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/consul/templates/consul.hcl.j2: -------------------------------------------------------------------------------- 1 | bind_addr = "{{ bind_addr }}" 2 | client_addr = "{{ client_addr }}" 3 | data_dir = "{{ data_dir }}" 4 | encrypt = "{{ encrypt }}" 5 | datacenter = "{{ datacenter }}" 6 | ui = {{ ui }} 7 | leave_on_terminate = {{ leave_on_terminate }} 8 | server = {{ server }} 9 | log_level = "{{ log_level }}" 10 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/consul/templates/consul.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Consul service 3 | After=network.target 4 | 5 | [Service] 6 | ExecStart=/usr/bin/consul agent -dev -config-dir /etc/consul.d 7 | Restart=always 8 | User=root 9 | Group=nogroup 10 | LimitNOFILE=65536 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/consul/vars/main.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiescamp/devops-projects/4bd247b4df794262d88c9b7ee2594cffc34812fd/02-consul-sevice-discovery/ansible/roles/consul/vars/main.yaml -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/load-balancer/files/load-balancer.conf.ctmpl: -------------------------------------------------------------------------------- 1 | upstream backend { 2 | {{- range service "backend" }} 3 | server {{ .Address }}:{{ .Port }}; 4 | {{- end }} 5 | } 6 | 7 | server { 8 | listen 80; 9 | 10 | location / { 11 | proxy_pass http://backend; 12 | } 13 | } -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/load-balancer/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart nginx 3 | service: 4 | name: nginx 5 | state: restarted -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/load-balancer/tasks/consul.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # In this example, the get_url module is used to download the remote file from the URL 4 | 5 | - name: Download zip file 6 | get_url: 7 | url: "{{ consul_template_url }}" 8 | dest: /tmp/consul-template.zip 9 | mode: 0644 10 | 11 | - name: Unpack zip file 12 | apt: 13 | name: unzip 14 | state: latest 15 | 16 | 17 | # Note that remote_src is set to yes in the unarchive module, which means the archive file is located on the remote host, not on the control node. 18 | 19 | - name: Unpack zip file 20 | unarchive: 21 | src: /tmp/consul-template.zip 22 | dest: /usr/local/bin 23 | remote_src: yes 24 | 25 | - name: Copy file from files directory to destination 26 | copy: 27 | src: "files/load-balancer.conf.ctmpl" 28 | dest: "/etc/nginx/conf.d/load-balancer.conf.ctmpl" 29 | remote_src: no 30 | 31 | - name: Copy Nginx Consul Template 32 | template: 33 | src: consul-template.hcl.j2 34 | dest: /etc/nginx/conf.d/consul-template.hcl 35 | 36 | - name: Start Consul Agent Template 37 | shell: consul-template -config=/etc/nginx/conf.d/consul-template.hcl & 38 | 39 | - name: Remove default sites-enabled file 40 | file: 41 | path: "/etc/nginx/sites-enabled/default" 42 | state: absent 43 | notify: 44 | - restart nginx 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/load-balancer/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: nginx.yaml 3 | - include: consul.yaml 4 | 5 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/load-balancer/tasks/nginx.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check operating system 3 | debug: 4 | msg: "The operating system is {{ ansible_facts['os_family'] }}" 5 | when: ansible_facts['os_family'] == "Debian" 6 | 7 | - name: Update and upgrade apt packages 8 | become: true 9 | apt: 10 | upgrade: yes 11 | update_cache: yes 12 | 13 | - name: Install Nginx on Server 14 | apt: 15 | name: nginx 16 | state: latest 17 | 18 | - name: Start and enable a service 19 | service: 20 | name: nginx 21 | state: started 22 | enabled: yes 23 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/load-balancer/templates/consul-template.hcl.j2: -------------------------------------------------------------------------------- 1 | consul { 2 | address = "{{ consul_server_address }}" 3 | 4 | retry { 5 | enabled = true 6 | attempts = 12 7 | backoff = "250ms" 8 | } 9 | } 10 | template { 11 | source = "/etc/nginx/conf.d/load-balancer.conf.ctmpl" 12 | destination = "/etc/nginx/conf.d/load-balancer.conf" 13 | perms = 0600 14 | command = "service nginx reload" 15 | } -------------------------------------------------------------------------------- /02-consul-sevice-discovery/ansible/roles/load-balancer/vars/main.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiescamp/devops-projects/4bd247b4df794262d88c9b7ee2594cffc34812fd/02-consul-sevice-discovery/ansible/roles/load-balancer/vars/main.yaml -------------------------------------------------------------------------------- /02-consul-sevice-discovery/terraform/provision.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | } 4 | 5 | resource "aws_security_group" "consul_server_sg" { 6 | name = "consul_server_security_group" 7 | description = "Security group for the consul server" 8 | 9 | ingress { 10 | from_port = 22 11 | to_port = 22 12 | protocol = "tcp" 13 | cidr_blocks = ["0.0.0.0/0"] 14 | } 15 | 16 | ingress { 17 | from_port = 8500 18 | to_port = 8500 19 | protocol = "tcp" 20 | cidr_blocks = ["0.0.0.0/0"] 21 | } 22 | 23 | ingress { 24 | from_port = 0 25 | to_port = 65000 26 | protocol = "tcp" 27 | cidr_blocks = [var.ingress_cidr_block] 28 | } 29 | 30 | egress { 31 | from_port = 0 32 | to_port = 0 33 | protocol = "-1" 34 | cidr_blocks = ["0.0.0.0/0"] 35 | } 36 | 37 | tags = { 38 | Name = "consul-server-sg" 39 | } 40 | } 41 | 42 | resource "aws_security_group" "load_balancer_sg" { 43 | name = "load_balancer_security_group" 44 | description = "Security group for the load balancer" 45 | 46 | ingress { 47 | from_port = 22 48 | to_port = 22 49 | protocol = "tcp" 50 | cidr_blocks = ["0.0.0.0/0"] 51 | } 52 | 53 | ingress { 54 | from_port = 80 55 | to_port = 80 56 | protocol = "tcp" 57 | cidr_blocks = ["0.0.0.0/0"] 58 | } 59 | 60 | egress { 61 | from_port = 0 62 | to_port = 0 63 | protocol = "-1" 64 | cidr_blocks = ["0.0.0.0/0"] 65 | } 66 | 67 | tags = { 68 | Name = "loadbalancer-sg" 69 | } 70 | } 71 | 72 | resource "aws_security_group" "backends_sg" { 73 | name = "backends_security_group" 74 | description = "Security group for the backends" 75 | 76 | ingress { 77 | from_port = 22 78 | to_port = 22 79 | protocol = "tcp" 80 | cidr_blocks = ["0.0.0.0/0"] 81 | } 82 | 83 | ingress { 84 | from_port = 80 85 | to_port = 80 86 | protocol = "tcp" 87 | cidr_blocks = ["0.0.0.0/0"] 88 | } 89 | 90 | egress { 91 | from_port = 0 92 | to_port = 0 93 | protocol = "-1" 94 | cidr_blocks = ["0.0.0.0/0"] 95 | } 96 | 97 | tags = { 98 | Name = "backend-sg" 99 | } 100 | } 101 | 102 | resource "aws_instance" "consul_server" { 103 | ami = var.ami 104 | instance_type = var.instance_type 105 | vpc_security_group_ids = [aws_security_group.consul_server_sg.id] 106 | key_name = var.key_name 107 | 108 | tags = { 109 | Name = "consul-server" 110 | } 111 | } 112 | 113 | resource "aws_instance" "load_balancer" { 114 | ami = var.ami 115 | instance_type = var.instance_type 116 | vpc_security_group_ids = [aws_security_group.load_balancer_sg.id] 117 | key_name = var.key_name 118 | 119 | tags = { 120 | Name = "loadbalancer" 121 | } 122 | } 123 | 124 | resource "aws_instance" "backends" { 125 | count = 2 126 | ami = var.ami 127 | instance_type = var.instance_type 128 | vpc_security_group_ids = [aws_security_group.backends_sg.id] 129 | key_name = var.key_name 130 | 131 | tags = { 132 | Name = "backend-app" 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /02-consul-sevice-discovery/terraform/variable.tf: -------------------------------------------------------------------------------- 1 | variable "instance_type" { 2 | type = string 3 | description = "EC2 Instance Type" 4 | } 5 | 6 | variable "region" { 7 | type = string 8 | description = "The project region" 9 | default = "us-west-2" 10 | } 11 | 12 | variable "ami" { 13 | type = string 14 | description = "The amazon machine image" 15 | } 16 | 17 | variable "key_name" { 18 | type = string 19 | description = "Key Name" 20 | } 21 | 22 | variable "ingress_cidr_block" { 23 | type = string 24 | description = "The ingress CIDR block" 25 | } 26 | -------------------------------------------------------------------------------- /03-scalable-java-app/Jenkinsfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiescamp/devops-projects/4bd247b4df794262d88c9b7ee2594cffc34812fd/03-scalable-java-app/Jenkinsfile -------------------------------------------------------------------------------- /03-scalable-java-app/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Scalable Java Application on AWS Using Terraform 3 | 4 | ![java-aws](https://user-images.githubusercontent.com/106984297/219648306-42c0d544-f6e6-423d-9802-9f3d5eca43e8.png) 5 | 6 | ## Project Documentation & Walkthrough 7 | 8 | Refer the following document for the step by step project walkthrough. 9 | 10 | **Project Documentation:** [Deploy Scalable Java Applications on AWS Using Terraform](https://devopscube.com/deploy-java-applications-aws-autoscaling/) 11 | 12 | ## Java Application 13 | 14 | For this project you can use the open source pet clinic application (Java Spring Boot) 15 | 16 | ``` 17 | https://github.com/spring-projects/spring-petclinic 18 | ``` 19 | 20 | ## Tools/Services 21 | 22 | - DevOps Tools 23 | - Jenkins 24 | - Packer 25 | - Ansible 26 | - Terraform 27 | 28 | - AWS Services 29 | - Application Load Balancer (L7) 30 | - Autoscaling Group 31 | - AWS secrets manager 32 | - RDS (MySQL) 33 | 34 | ## Project Workflow 35 | 36 | - Build Java application 37 | - Use Packer & Ansible to build the AMI With application code 38 | - configure application logging 39 | - configure cloudwatch agent with the application log location. 40 | - Use Teraaform to provision the following 41 | - MySQL RDS instance and store the username and password in AWS secrets manager 42 | - Provision Application Load Blancer 43 | - Create a launch template With the Application AMI 44 | - Provision Autoscaling Group with Launch tempalate that use AMI built by packer and attach it to Loadbalancer. 45 | - Verify application by accessing it using Load Balancer endpoint. 46 | - Verify application logs in Cloudwatch 47 | 48 | ## Other Useful Resources 49 | 50 | 1. [RDS password Rotation With Terraform](https://advancedweb.hu/how-to-set-up-amazon-rds-password-rotation-with-terraform/) 51 | -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/files/application.properties: -------------------------------------------------------------------------------- 1 | # database init, supports mysql too 2 | 3 | # database init, supports mysql too 4 | database=mysql 5 | spring.datasource.url=jdbc:mysql://localhost:3306/petclinic 6 | spring.datasource.username=petclinic 7 | spring.datasource.password=petclinic 8 | # SQL is written to be idempotent so this is safe 9 | spring.sql.init.mode=always 10 | 11 | # Web 12 | spring.thymeleaf.mode=HTML 13 | 14 | # JPA 15 | spring.jpa.hibernate.ddl-auto=none 16 | spring.jpa.open-in-view=true 17 | 18 | # Internationalization 19 | spring.messages.basename=messages/messages 20 | 21 | # Actuator 22 | management.endpoints.web.exposure.include=* 23 | # Logging 24 | #logging.config=classpath:logback-spring.xml 25 | logging.level.org.springframework=INFO 26 | # logging.level.org.springframework.web=DEBUG 27 | # logging.level.org.springframework.context.annotation=TRACE 28 | 29 | # Maximum time static resources should be cached 30 | spring.web.resources.cache.cachecontrol.max-age=12h -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/files/properties.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import json 3 | 4 | region = 'us-west-2' 5 | parameter_store = '/dev/petclinic/rds_endpoint' 6 | secret_name_tag = 'dev-rds-db' 7 | file_path = "/opt/application.properties" 8 | 9 | ssm = boto3.client('ssm', region_name=region) 10 | 11 | rds_endpoint = ssm.get_parameter(Name=parameter_store)['Parameter']['Value'] 12 | 13 | secrets_client = boto3.client('secretsmanager', region_name=region) 14 | 15 | secrets_list = secrets_client.list_secrets() 16 | secret_arn = None 17 | for secret in secrets_list['SecretList']: 18 | if 'Tags' in secret: 19 | for tag in secret['Tags']: 20 | if tag['Key'] == 'Name' and tag['Value'] == secret_name_tag: 21 | secret_arn = secret['ARN'] 22 | break 23 | 24 | if secret_arn is None: 25 | print(f"Secret with name tag '{secret_name_tag}' not found.") 26 | exit(1) 27 | 28 | response = secrets_client.get_secret_value(SecretId=secret_arn) 29 | secret_value = response['SecretString'] 30 | 31 | secret_data = json.loads(secret_value) 32 | 33 | with open(file_path, 'r') as f: 34 | file_contents = f.read() 35 | 36 | file_contents = file_contents.replace("spring.datasource.url=jdbc:mysql://localhost:3306/petclinic", f"spring.datasource.url=jdbc:mysql://{rds_endpoint}") 37 | file_contents = file_contents.replace("spring.datasource.username=petclinic", f"spring.datasource.username={secret_data['username']}") 38 | file_contents = file_contents.replace("spring.datasource.password=petclinic", f"spring.datasource.password={secret_data['password']}") 39 | 40 | 41 | with open(file_path, 'w') as f: 42 | f.write(file_contents) -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/files/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | JAR_FILE=/home/ubuntu/pet-clinic-1.0.1.jar 4 | APP_PROPERTIES=/opt/application.properties 5 | PROPERTIES_SCRIPT=/home/ubuntu/properties.py 6 | 7 | sudo python3 ${PROPERTIES_SCRIPT} 8 | 9 | sudo java -jar "${JAR_FILE}" --spring.config.location="${APP_PROPERTIES}" --spring.profiles.active=mysql & -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/java-app.pkr.hcl: -------------------------------------------------------------------------------- 1 | variable "ami_id" { 2 | type = string 3 | default = "ami-03f65b8614a860c29" 4 | } 5 | 6 | locals { 7 | app_name = "java-app-1.0.1" 8 | } 9 | 10 | source "amazon-ebs" "java-app" { 11 | ami_name = "PACKER-${local.app_name}" 12 | instance_type = "t2.medium" 13 | region = "us-west-2" 14 | source_ami = "${var.ami_id}" 15 | ssh_username = "ubuntu" 16 | tags = { 17 | Env = "DEMO" 18 | Name = "PACKER-${local.app_name}" 19 | } 20 | } 21 | 22 | build { 23 | sources = ["source.amazon-ebs.java-app"] 24 | 25 | provisioner "ansible" { 26 | playbook_file = "java-app.yml" 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/java-app.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Java 3 | hosts: all 4 | become: yes 5 | remote_user: ubuntu 6 | 7 | vars: 8 | source_dir: files 9 | dest_dir: /home/ubuntu/ 10 | files: 11 | - properties.py 12 | - start.sh 13 | 14 | roles: 15 | - java -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/roles/java/tasks/app.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Copy files 3 | copy: 4 | src: "{{ source_dir }}/{{ item }}" 5 | dest: "{{ dest_dir }}/{{ item }}" 6 | with_items: "{{ files }}" 7 | 8 | - name: Copy files 9 | copy: 10 | src: files/application.properties 11 | dest: /opt/application.properties 12 | 13 | - name: Make start.sh script executable 14 | become: true 15 | file: 16 | path: /home/ubuntu/start.sh 17 | mode: '+x' -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/roles/java/tasks/backends.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check operating system 3 | debug: 4 | msg: "The operating system is {{ ansible_facts['os_family'] }}" 5 | when: ansible_facts['os_family'] == "Debian" 6 | 7 | - name: Install Nginx on Server 8 | apt: 9 | name: nginx 10 | state: latest 11 | 12 | - name: Copy Nginx Index HTML 13 | template: 14 | src: index.html.j2 15 | dest: /var/www/html/index.html 16 | 17 | - name: Start and enable a service 18 | service: 19 | name: nginx 20 | state: started 21 | enabled: yes 22 | -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/roles/java/tasks/cloudwatch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Downloading packages 4 | command: wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb 5 | 6 | - name: Install CloudWatch 7 | command: dpkg -i amazon-cloudwatch-agent.deb 8 | 9 | - name: Create CloudWatch Agent configuration file 10 | template: 11 | src: config.json.j2 12 | dest: /opt/aws/amazon-cloudwatch-agent/bin/config.json 13 | 14 | - name: Install collectd 15 | apt: 16 | name: collectd 17 | state: latest 18 | 19 | - name: Start CloudWatch 20 | command: amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json -s 21 | -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/roles/java/tasks/java.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Update and upgrade apt packages 3 | become: true 4 | apt: 5 | upgrade: yes 6 | update_cache: yes 7 | 8 | - name: Install JRE 9 | become: true 10 | apt: 11 | name: openjdk-17-jre 12 | state: latest 13 | 14 | - name: Create log file 15 | file: 16 | path: /var/log/petclinic.log 17 | state: touch 18 | mode: '0777' -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/roles/java/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include_tasks: java.yml 3 | - include_tasks: python.yml 4 | - include_tasks: backends.yml 5 | - include_tasks: cloudwatch.yml 6 | - include_tasks: app.yml 7 | 8 | -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/roles/java/tasks/python.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Python3, pip3, and AWS CLI 3 | become: true 4 | apt: 5 | name: "{{ item }}" 6 | state: present 7 | loop: 8 | - python3 9 | - python3-pip 10 | - awscli 11 | 12 | - name: Install boto3 using pip3 13 | become: true 14 | pip: 15 | name: boto3 16 | state: present 17 | -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/templates/config.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "agent": { 3 | "metrics_collection_interval": 10, 4 | "run_as_user": "root" 5 | }, 6 | "logs": { 7 | "logs_collected": { 8 | "files": { 9 | "collect_list": [ 10 | { 11 | "file_path": "/var/log/petclinic.log", 12 | "log_group_name": "petclinic-log", 13 | "log_stream_name": "{instance_id}", 14 | "retention_in_days": 14 15 | } 16 | ] 17 | } 18 | } 19 | }, 20 | "metrics": { 21 | "aggregation_dimensions": [ 22 | [ 23 | "InstanceId" 24 | ] 25 | ], 26 | "append_dimensions": { 27 | "AutoScalingGroupName": "${aws:AutoScalingGroupName}", 28 | "ImageId": "${aws:ImageId}", 29 | "InstanceId": "${aws:InstanceId}", 30 | "InstanceType": "${aws:InstanceType}" 31 | }, 32 | "metrics_collected": { 33 | "collectd": { 34 | "metrics_aggregation_interval": 60 35 | }, 36 | "disk": { 37 | "measurement": [ 38 | "used_percent" 39 | ], 40 | "metrics_collection_interval": 10, 41 | "resources": [ 42 | "*" 43 | ] 44 | }, 45 | "mem": { 46 | "measurement": [ 47 | "mem_used_percent" 48 | ], 49 | "metrics_collection_interval": 10 50 | }, 51 | "statsd": { 52 | "metrics_aggregation_interval": 60, 53 | "metrics_collection_interval": 10, 54 | "service_address": ":8125" 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /03-scalable-java-app/ansible/templates/index.html.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Server Information 8 | 9 | 10 | 17 |
18 |
19 |

Server Information

20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
IP Address{{ ansible_default_ipv4.address }}
Operating System{{ ansible_os_family }}
System Version{{ ansible_distribution_version }}
Memory{{ ansible_memtotal_mb }} MB
CPU{{ ansible_processor_vcpus }} vCPUs
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/alb-asg/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | } 4 | 5 | module "alb-asg" { 6 | source = "../modules/alb-asg" 7 | ingress_alb_from_port = var.ingress_alb_from_port 8 | ingress_alb_to_port = var.ingress_alb_to_port 9 | ingress_alb_protocol = var.ingress_alb_protocol 10 | ingress_alb_cidr_blocks = var.ingress_alb_cidr_blocks 11 | egress_alb_from_port = var.egress_alb_from_port 12 | egress_alb_to_port = var.egress_alb_to_port 13 | egress_alb_protocol = var.egress_alb_protocol 14 | egress_alb_cidr_blocks = var.egress_alb_cidr_blocks 15 | internal = var.internal 16 | loadbalancer_type = var.loadbalancer_type 17 | subnets = var.subnets 18 | target_group_port = var.target_group_port 19 | target_group_protocol = var.target_group_protocol 20 | vpc_id = var.vpc_id 21 | target_type = var.target_type 22 | health_check_path = var.health_check_path 23 | health_check_port = var.health_check_port 24 | health_check_protocol = var.health_check_protocol 25 | health_check_interval = var.health_check_interval 26 | health_check_timeout = var.health_check_timeout 27 | health_check_healthy_threshold = var.health_check_healthy_threshold 28 | health_check_unhealthy_threshold = var.health_check_unhealthy_threshold 29 | load_balancing_algorithm = var.load_balancing_algorithm 30 | ingress_asg_cidr_from_port = var.ingress_asg_cidr_from_port 31 | ingress_asg_cidr_to_port = var.ingress_asg_cidr_to_port 32 | ingress_asg_cidr_protocol = var.ingress_asg_cidr_protocol 33 | ingress_asg_cidr_blocks = var.ingress_asg_cidr_blocks 34 | ingress_asg_sg_from_port = var.ingress_asg_sg_from_port 35 | ingress_asg_sg_to_port = var.ingress_asg_sg_to_port 36 | ingress_asg_sg_protocol = var.ingress_asg_sg_protocol 37 | egress_asg_from_port = var.egress_asg_from_port 38 | egress_asg_to_port = var.egress_asg_to_port 39 | egress_asg_protocol = var.egress_asg_protocol 40 | egress_asg_cidr_blocks = var.egress_asg_cidr_blocks 41 | public_access = var.public_access 42 | max_size = var.max_size 43 | min_size = var.min_size 44 | desired_capacity = var.desired_capacity 45 | listener_port = var.listener_port 46 | listener_protocol = var.listener_protocol 47 | listener_type = var.listener_type 48 | ami_id = var.ami_id 49 | instance_type = var.instance_type 50 | key_name = var.key_name 51 | user_data = var.user_data 52 | instance_warmup_time = var.instance_warmup_time 53 | target_value = var.target_value 54 | owner = var.owner 55 | environment = var.environment 56 | cost_center = var.cost_center 57 | application = var.application 58 | } -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/alb-asg/variable.tf: -------------------------------------------------------------------------------- 1 | variable "tags" { 2 | default = {} 3 | type = map(string) 4 | description = "Extra tags to attach to the resources" 5 | } 6 | 7 | variable "region" { 8 | description = "The AWS region where it will be created." 9 | type = string 10 | } 11 | 12 | variable "ingress_alb_from_port" { 13 | type = number 14 | description = "Ingress alb from port" 15 | } 16 | 17 | variable "ingress_alb_to_port" { 18 | type = number 19 | description = "Ingress alb to port" 20 | } 21 | 22 | variable "ingress_alb_protocol" { 23 | type = string 24 | description = "Ingress alb protocol" 25 | } 26 | 27 | variable "ingress_alb_cidr_blocks" { 28 | type = list(string) 29 | description = "List of starting ports for cidr ingress rules of the security group." 30 | } 31 | 32 | variable "egress_alb_from_port" { 33 | type = number 34 | description = "egress alb from port" 35 | } 36 | 37 | variable "egress_alb_to_port" { 38 | type = number 39 | description = "egress alb to port" 40 | } 41 | 42 | variable "egress_alb_protocol" { 43 | type = string 44 | description = "egress alb protocol" 45 | } 46 | 47 | variable "egress_alb_cidr_blocks" { 48 | type = list(string) 49 | description = "List of starting ports for cidr egress rules of the security group." 50 | } 51 | 52 | variable "internal" { 53 | description = "Whether the load balancer is internal or not" 54 | type = bool 55 | } 56 | 57 | variable "loadbalancer_type" { 58 | description = "Load balancer type" 59 | type = string 60 | } 61 | 62 | variable "ami_id" { 63 | description = "The ID of the Amazon Machine Image (AMI) to use for the EC2 instances." 64 | } 65 | 66 | variable "instance_type" { 67 | description = "The type of EC2 instance to use for the ASG." 68 | } 69 | 70 | variable "key_name" { 71 | description = "The name of the EC2 key pair to use for the instances." 72 | } 73 | 74 | variable "vpc_id" { 75 | description = "The ID of the VPC to use for the resources." 76 | } 77 | 78 | variable "subnets" { 79 | description = "A list of subnet IDs to use for the resources." 80 | type = list(string) 81 | } 82 | 83 | variable "target_group_port" { 84 | description = "Target group port" 85 | type = number 86 | } 87 | 88 | variable "target_group_protocol" { 89 | description = "Target group protocol" 90 | type = string 91 | } 92 | 93 | variable "target_type" { 94 | description = "Target type" 95 | type = string 96 | } 97 | 98 | variable "load_balancing_algorithm" { 99 | description = "Specify the load balancing algorithm type" 100 | type = string 101 | } 102 | 103 | variable "health_check_path" { 104 | description = "Health check path" 105 | type = string 106 | } 107 | 108 | variable "health_check_port" { 109 | description = "Health check port" 110 | type = number 111 | } 112 | 113 | variable "health_check_protocol" { 114 | description = "Health check protocol" 115 | type = string 116 | } 117 | 118 | variable "health_check_interval" { 119 | description = "Health check interval" 120 | type = number 121 | } 122 | 123 | variable "health_check_timeout" { 124 | description = "Health check timeout" 125 | type = number 126 | } 127 | 128 | variable "health_check_healthy_threshold" { 129 | description = "Health check healthy threshold" 130 | type = number 131 | } 132 | 133 | variable "health_check_unhealthy_threshold" { 134 | description = "Health check unhealthy threshold" 135 | type = number 136 | } 137 | 138 | variable "ingress_asg_cidr_from_port" { 139 | type = number 140 | description = "Ingress asg from port" 141 | } 142 | 143 | variable "ingress_asg_cidr_to_port" { 144 | type = number 145 | description = "Ingress asg to port" 146 | } 147 | 148 | variable "ingress_asg_cidr_protocol" { 149 | type = string 150 | description = "Ingress asg protocol" 151 | } 152 | 153 | variable "ingress_asg_cidr_blocks" { 154 | type = list(string) 155 | description = "List of starting ports for cidr ingress rules of the security group." 156 | } 157 | 158 | variable "ingress_asg_sg_from_port" { 159 | type = number 160 | description = "Ingress asg from port" 161 | } 162 | 163 | variable "ingress_asg_sg_to_port" { 164 | type = number 165 | description = "Ingress asg to port" 166 | } 167 | 168 | variable "ingress_asg_sg_protocol" { 169 | type = string 170 | description = "Ingress asg protocol" 171 | } 172 | 173 | variable "egress_asg_from_port" { 174 | type = number 175 | description = "egress asg from port" 176 | } 177 | 178 | variable "egress_asg_to_port" { 179 | type = number 180 | description = "egress asg to port" 181 | } 182 | 183 | variable "egress_asg_protocol" { 184 | type = string 185 | description = "egress asg protocol" 186 | } 187 | 188 | variable "egress_asg_cidr_blocks" { 189 | type = list(string) 190 | description = "List of starting ports for sg egress rules of the security group." 191 | } 192 | 193 | variable "public_access" { 194 | description = "Whether the instance is public or not" 195 | type = bool 196 | } 197 | 198 | variable "max_size" { 199 | description = "Maximum size of something" 200 | type = number 201 | } 202 | 203 | variable "min_size" { 204 | description = "Minimum size of something" 205 | type = number 206 | } 207 | 208 | variable "desired_capacity" { 209 | description = "Desired capacity of something" 210 | type = number 211 | } 212 | 213 | variable "listener_port" { 214 | description = "Listener port" 215 | type = number 216 | } 217 | 218 | variable "listener_protocol" { 219 | description = "Listener protocol" 220 | type = string 221 | } 222 | 223 | variable "user_data" { 224 | description = "user data script" 225 | type = string 226 | } 227 | 228 | variable "listener_type" { 229 | description = "Listener type" 230 | type = string 231 | } 232 | 233 | variable "instance_warmup_time" { 234 | description = "Time required to warm up a new instance" 235 | type = number 236 | } 237 | 238 | variable "target_value" { 239 | description = "Threshold value of asg to start scaling" 240 | type = number 241 | } 242 | 243 | variable "environment" { 244 | type = string 245 | description = "The environment name for the resources." 246 | } 247 | 248 | variable "owner" { 249 | type = string 250 | description = "Name of the owner" 251 | } 252 | 253 | variable "application" { 254 | type = string 255 | description = "Name of the application" 256 | } 257 | 258 | variable "cost_center" { 259 | type = string 260 | description = "Name of cost-center" 261 | } -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/modules/alb-asg/alb.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "alb_sg" { 2 | name_prefix = "${var.environment}-${var.application}-alb-sg" 3 | 4 | ingress { 5 | from_port = var.ingress_alb_from_port 6 | to_port = var.ingress_alb_to_port 7 | protocol = var.ingress_alb_protocol 8 | cidr_blocks = var.ingress_alb_cidr_blocks 9 | } 10 | 11 | egress { 12 | from_port = var.egress_alb_from_port 13 | to_port = var.egress_alb_to_port 14 | protocol = var.egress_alb_protocol 15 | cidr_blocks = var.egress_alb_cidr_blocks 16 | } 17 | 18 | tags = merge( 19 | { 20 | Name = "${var.environment}-${var.application}-alb-sg", 21 | Environment = var.environment, 22 | Owner = var.owner, 23 | CostCenter = var.cost_center, 24 | Application = var.application 25 | }, 26 | var.tags 27 | ) 28 | } 29 | 30 | resource "aws_alb" "application_load_balancer" { 31 | name = "${var.environment}-${var.application}-alb" 32 | internal = var.internal 33 | load_balancer_type = var.loadbalancer_type 34 | 35 | subnets = var.subnets 36 | security_groups = [aws_security_group.alb_sg.id] 37 | 38 | tags = merge( 39 | { 40 | Name = "${var.environment}-${var.application}-alb", 41 | Environment = var.environment, 42 | Owner = var.owner, 43 | CostCenter = var.cost_center, 44 | Application = var.application 45 | }, 46 | var.tags 47 | ) 48 | } 49 | 50 | resource "aws_alb_target_group" "petclinic" { 51 | name_prefix = "pc-alb" 52 | port = var.target_group_port 53 | protocol = var.target_group_protocol 54 | vpc_id = var.vpc_id 55 | target_type = var.target_type 56 | 57 | health_check { 58 | path = var.health_check_path 59 | port = var.health_check_port 60 | protocol = var.health_check_protocol 61 | interval = var.health_check_interval 62 | timeout = var.health_check_timeout 63 | healthy_threshold = var.health_check_healthy_threshold 64 | unhealthy_threshold = var.health_check_unhealthy_threshold 65 | } 66 | 67 | load_balancing_algorithm_type = var.load_balancing_algorithm 68 | 69 | tags = merge( 70 | { 71 | Name = "${var.environment}-${var.application}-alb-target-group" 72 | Environment = var.environment, 73 | Owner = var.owner, 74 | CostCenter = var.cost_center, 75 | Application = var.application 76 | }, 77 | var.tags 78 | ) 79 | } 80 | 81 | resource "aws_alb_listener" "application_listener" { 82 | load_balancer_arn = aws_alb.application_load_balancer.arn 83 | port = var.listener_port 84 | protocol = var.listener_protocol 85 | 86 | default_action { 87 | target_group_arn = aws_alb_target_group.petclinic.arn 88 | type = var.listener_type 89 | } 90 | } -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/modules/alb-asg/asg.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_instance_profile" "instance_profile" { 2 | name = "${var.environment}-${var.application}-instance_profile" 3 | 4 | role = aws_iam_role.iam_role.id 5 | } 6 | 7 | resource "aws_security_group" "instance_sg" { 8 | name_prefix = "${var.environment}-${var.application}-instance-sg" 9 | 10 | ingress { 11 | from_port = var.ingress_asg_cidr_from_port 12 | to_port = var.ingress_asg_cidr_to_port 13 | protocol = var.ingress_asg_cidr_protocol 14 | cidr_blocks = var.ingress_asg_cidr_blocks 15 | } 16 | 17 | ingress { 18 | from_port = var.ingress_asg_sg_from_port 19 | to_port = var.ingress_asg_sg_to_port 20 | protocol = var.ingress_asg_sg_protocol 21 | security_groups = [aws_security_group.alb_sg.id] 22 | } 23 | 24 | egress { 25 | from_port = var.egress_asg_from_port 26 | to_port = var.egress_asg_to_port 27 | protocol = var.egress_asg_protocol 28 | cidr_blocks = var.egress_asg_cidr_blocks 29 | } 30 | 31 | tags = merge( 32 | { 33 | Name = "${var.environment}-${var.application}-asg-sg" 34 | Environment = var.environment, 35 | Owner = var.owner, 36 | CostCenter = var.cost_center, 37 | Application = var.application 38 | }, 39 | var.tags 40 | ) 41 | } 42 | 43 | 44 | resource "aws_launch_template" "petclinic_lt" { 45 | name_prefix = "${var.environment}-${var.application}-petclinic-lt" 46 | image_id = var.ami_id 47 | instance_type = var.instance_type 48 | key_name = var.key_name 49 | 50 | iam_instance_profile { 51 | name = "${var.environment}-${var.application}-instance_profile" 52 | } 53 | 54 | network_interfaces { 55 | associate_public_ip_address = var.public_access 56 | security_groups = [aws_security_group.instance_sg.id] 57 | } 58 | 59 | user_data = base64encode(var.user_data) 60 | } 61 | 62 | locals { 63 | asg_tags = merge( 64 | var.tags, 65 | { "Name" = "${var.environment}-${var.application}-asg" } 66 | ) 67 | } 68 | 69 | resource "aws_autoscaling_group" "petclinic" { 70 | name = "${var.environment}-${var.application}-asg" 71 | max_size = var.max_size 72 | min_size = var.min_size 73 | desired_capacity = var.desired_capacity 74 | vpc_zone_identifier = var.subnets 75 | 76 | launch_template { 77 | id = aws_launch_template.petclinic_lt.id 78 | version = aws_launch_template.petclinic_lt.latest_version 79 | } 80 | 81 | lifecycle { 82 | ignore_changes = [load_balancers, target_group_arns] 83 | } 84 | 85 | dynamic "tag" { 86 | for_each = local.asg_tags 87 | content { 88 | key = tag.key 89 | value = tag.value 90 | propagate_at_launch = true 91 | } 92 | } 93 | } 94 | 95 | resource "aws_autoscaling_policy" "cpu_scaling_policy" { 96 | name = "${var.environment}-${var.application}-cpu-scaling-policy" 97 | policy_type = "TargetTrackingScaling" 98 | estimated_instance_warmup = var.instance_warmup_time 99 | autoscaling_group_name = aws_autoscaling_group.petclinic.name 100 | 101 | target_tracking_configuration { 102 | predefined_metric_specification { 103 | predefined_metric_type = "ASGAverageCPUUtilization" 104 | } 105 | 106 | target_value = var.target_value 107 | } 108 | } 109 | 110 | resource "aws_autoscaling_attachment" "petclinic" { 111 | autoscaling_group_name = aws_autoscaling_group.petclinic.name 112 | lb_target_group_arn = aws_alb_target_group.petclinic.arn 113 | } 114 | -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/modules/alb-asg/iam-policy.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "iam_role" { 2 | name = "${var.environment}-${var.application}-iam-role" 3 | assume_role_policy = jsonencode({ 4 | Version = "2012-10-17" 5 | Statement = [ 6 | { 7 | Action = "sts:AssumeRole" 8 | Effect = "Allow" 9 | Principal = { 10 | Service = "ec2.amazonaws.com" 11 | } 12 | }, 13 | { 14 | Action = "sts:AssumeRole" 15 | Effect = "Allow" 16 | Principal = { 17 | Service = "iam.amazonaws.com" 18 | } 19 | } 20 | ] 21 | }) 22 | tags = merge( 23 | { 24 | Name = "${var.environment}-${var.application}-iam-role", 25 | Environment = var.environment, 26 | Owner = var.owner, 27 | CostCenter = var.cost_center, 28 | Application = var.application 29 | }, 30 | var.tags 31 | ) 32 | } 33 | 34 | resource "aws_iam_policy" "iam_policy" { 35 | name = "${var.environment}-${var.application}-iam-policy" 36 | policy = jsonencode({ 37 | Version = "2012-10-17", 38 | Statement = [ 39 | { 40 | Sid = "Stmt1693214608532", 41 | Action = "*", 42 | Effect = "Allow", 43 | Resource = "*", 44 | }, 45 | ], 46 | }) 47 | } 48 | 49 | 50 | resource "aws_iam_role_policy_attachment" "iam_role_policy_attachment" { 51 | role = aws_iam_role.iam_role.name 52 | policy_arn = aws_iam_policy.iam_policy.arn 53 | } -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/modules/alb-asg/variable.tf: -------------------------------------------------------------------------------- 1 | variable "tags" { 2 | default = {} 3 | type = map(string) 4 | description = "Extra tags to attach to the resources" 5 | } 6 | 7 | variable "ingress_alb_from_port" { 8 | type = number 9 | description = "Ingress alb from port" 10 | } 11 | 12 | variable "ingress_alb_to_port" { 13 | type = number 14 | description = "Ingress alb to port" 15 | } 16 | 17 | variable "ingress_alb_protocol" { 18 | type = string 19 | description = "Ingress alb protocol" 20 | } 21 | 22 | variable "ingress_alb_cidr_blocks" { 23 | type = list(string) 24 | description = "List of starting ports for cidr ingress rules of the security group." 25 | } 26 | 27 | variable "egress_alb_from_port" { 28 | type = number 29 | description = "egress alb from port" 30 | } 31 | 32 | variable "egress_alb_to_port" { 33 | type = number 34 | description = "egress alb to port" 35 | } 36 | 37 | variable "egress_alb_protocol" { 38 | type = string 39 | description = "egress alb protocol" 40 | } 41 | 42 | variable "egress_alb_cidr_blocks" { 43 | type = list(string) 44 | description = "List of starting ports for cidr egress rules of the security group." 45 | } 46 | 47 | variable "internal" { 48 | description = "Whether the load balancer is internal or not" 49 | type = bool 50 | } 51 | 52 | variable "loadbalancer_type" { 53 | description = "Load balancer type" 54 | type = string 55 | } 56 | 57 | variable "ami_id" { 58 | description = "The ID of the Amazon Machine Image (AMI) to use for the EC2 instances." 59 | } 60 | 61 | variable "instance_type" { 62 | description = "The type of EC2 instance to use for the ASG." 63 | } 64 | 65 | variable "key_name" { 66 | description = "The name of the EC2 key pair to use for the instances." 67 | } 68 | 69 | variable "vpc_id" { 70 | description = "The ID of the VPC to use for the resources." 71 | } 72 | 73 | variable "subnets" { 74 | description = "A list of subnet IDs to use for the resources." 75 | type = list(string) 76 | } 77 | 78 | variable "target_group_port" { 79 | description = "Target group port" 80 | type = number 81 | } 82 | 83 | variable "target_group_protocol" { 84 | description = "Target group protocol" 85 | type = string 86 | } 87 | 88 | variable "target_type" { 89 | description = "Target type" 90 | type = string 91 | } 92 | 93 | variable "load_balancing_algorithm" { 94 | description = "Specify the load balancing algorithm type" 95 | type = string 96 | } 97 | 98 | variable "health_check_path" { 99 | description = "Health check path" 100 | type = string 101 | } 102 | 103 | variable "health_check_port" { 104 | description = "Health check port" 105 | type = number 106 | } 107 | 108 | variable "health_check_protocol" { 109 | description = "Health check protocol" 110 | type = string 111 | } 112 | 113 | variable "health_check_interval" { 114 | description = "Health check interval" 115 | type = number 116 | } 117 | 118 | variable "health_check_timeout" { 119 | description = "Health check timeout" 120 | type = number 121 | } 122 | 123 | variable "health_check_healthy_threshold" { 124 | description = "Health check healthy threshold" 125 | type = number 126 | } 127 | 128 | variable "health_check_unhealthy_threshold" { 129 | description = "Health check unhealthy threshold" 130 | type = number 131 | } 132 | 133 | variable "ingress_asg_cidr_from_port" { 134 | type = number 135 | description = "Ingress asg from port" 136 | } 137 | 138 | variable "ingress_asg_cidr_to_port" { 139 | type = number 140 | description = "Ingress asg to port" 141 | } 142 | 143 | variable "ingress_asg_cidr_protocol" { 144 | type = string 145 | description = "Ingress asg protocol" 146 | } 147 | 148 | variable "ingress_asg_cidr_blocks" { 149 | type = list(string) 150 | description = "List of starting ports for cidr ingress rules of the security group." 151 | } 152 | 153 | variable "ingress_asg_sg_from_port" { 154 | type = number 155 | description = "Ingress asg from port" 156 | } 157 | 158 | variable "ingress_asg_sg_to_port" { 159 | type = number 160 | description = "Ingress asg to port" 161 | } 162 | 163 | variable "ingress_asg_sg_protocol" { 164 | type = string 165 | description = "Ingress asg protocol" 166 | } 167 | 168 | variable "egress_asg_from_port" { 169 | type = number 170 | description = "egress asg from port" 171 | } 172 | 173 | variable "egress_asg_to_port" { 174 | type = number 175 | description = "egress asg to port" 176 | } 177 | 178 | variable "egress_asg_protocol" { 179 | type = string 180 | description = "egress asg protocol" 181 | } 182 | 183 | variable "egress_asg_cidr_blocks" { 184 | type = list(string) 185 | description = "List of starting ports for sg egress rules of the security group." 186 | } 187 | 188 | variable "public_access" { 189 | description = "Whether the instance is public or not" 190 | type = bool 191 | } 192 | 193 | variable "max_size" { 194 | description = "Maximum size of something" 195 | type = number 196 | } 197 | 198 | variable "min_size" { 199 | description = "Minimum size of something" 200 | type = number 201 | } 202 | 203 | variable "desired_capacity" { 204 | description = "Desired capacity of something" 205 | type = number 206 | } 207 | 208 | variable "listener_port" { 209 | description = "Listener port" 210 | type = number 211 | } 212 | 213 | variable "listener_protocol" { 214 | description = "Listener protocol" 215 | type = string 216 | } 217 | 218 | variable "user_data" { 219 | description = "user data script" 220 | type = string 221 | } 222 | 223 | variable "listener_type" { 224 | description = "Listener type" 225 | type = string 226 | } 227 | 228 | variable "instance_warmup_time" { 229 | description = "Time required to warm up a new instance" 230 | type = number 231 | } 232 | 233 | variable "target_value" { 234 | description = "Threshold value of asg to start scaling" 235 | type = number 236 | } 237 | 238 | variable "environment" { 239 | type = string 240 | description = "The environment name for the resources." 241 | } 242 | 243 | variable "owner" { 244 | type = string 245 | description = "Name of the owner" 246 | } 247 | 248 | variable "application" { 249 | type = string 250 | description = "Name of the application" 251 | } 252 | 253 | variable "cost_center" { 254 | type = string 255 | description = "Name of cost-center" 256 | } -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/modules/rds/main.tf: -------------------------------------------------------------------------------- 1 | # Create a DB security group 2 | resource "aws_security_group" "rds_security_group" { 3 | name = "${var.environment}-${var.application}-rds-sg" 4 | vpc_id = var.vpc_id 5 | description = "Security group for RDS instance" 6 | 7 | ingress { 8 | from_port = var.ingress_from_port 9 | to_port = var.ingress_to_port 10 | protocol = var.ingress_protocol 11 | cidr_blocks = var.ingress_cidr_blocks 12 | } 13 | 14 | egress { 15 | from_port = var.egress_from_port 16 | to_port = var.egress_to_port 17 | protocol = var.egress_protocol 18 | cidr_blocks = var.egress_cidr_blocks 19 | } 20 | 21 | tags = merge( 22 | { 23 | Name = "${var.environment}-${var.application}-rds-sg", 24 | Environment = var.environment, 25 | Owner = var.owner, 26 | CostCenter = var.cost_center, 27 | Application = var.application, 28 | }, 29 | var.tags 30 | ) 31 | } 32 | 33 | resource "aws_db_subnet_group" "rds_subnet_group" { 34 | name = "${var.environment}-${var.application}-subnet-group" 35 | subnet_ids = var.subnet_ids 36 | } 37 | 38 | resource "aws_db_instance" "rds_instance" { 39 | identifier = "${var.environment}-${var.application}-db" 40 | engine = var.db_engine 41 | instance_class = var.db_instance_class 42 | allocated_storage = var.db_storage_size 43 | storage_type = var.db_storage_type 44 | manage_master_user_password = var.set_secret_manager_password ? true : null 45 | username = var.db_username 46 | password = var.set_db_password ? var.db_password : null 47 | db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.name 48 | vpc_security_group_ids = [aws_security_group.rds_security_group.id] 49 | backup_retention_period = var.backup_retention_period 50 | multi_az = var.multi_az 51 | delete_automated_backups = var.delete_automated_backups 52 | copy_tags_to_snapshot = var.copy_tags_to_snapshot 53 | publicly_accessible = var.publicly_accessible 54 | skip_final_snapshot = var.skip_final_snapshot 55 | apply_immediately = var.apply_immediately 56 | 57 | tags = merge( 58 | { 59 | Name = "${var.environment}-${var.application}-db", 60 | Environment = var.environment, 61 | Owner = var.owner, 62 | CostCenter = var.cost_center, 63 | Application = var.application, 64 | }, 65 | var.tags 66 | ) 67 | } 68 | 69 | resource "aws_ssm_parameter" "rds_endpoint" { 70 | name = var.parameter_store_secret_name 71 | description = "RDS endpoint for /dev environment" 72 | type = var.type 73 | value = aws_db_instance.rds_instance.endpoint 74 | 75 | tags = merge( 76 | { 77 | Name = "${var.environment}-${var.application}-ssm", 78 | Environment = var.environment, 79 | Owner = var.owner, 80 | CostCenter = var.cost_center, 81 | Application = var.application, 82 | }, 83 | var.tags 84 | ) 85 | } 86 | 87 | -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/modules/rds/outputs.tf: -------------------------------------------------------------------------------- 1 | output "rds_address" { 2 | description = "The address of the RDS instance" 3 | value = aws_db_instance.rds_instance.address 4 | } 5 | 6 | output "rds_endpoint" { 7 | description = "The address of the RDS instance" 8 | value = aws_db_instance.rds_instance.endpoint 9 | } 10 | 11 | output "master_user_secret" { 12 | description = "The address of the RDS instance" 13 | value = aws_db_instance.rds_instance.master_user_secret[0].secret_arn 14 | } 15 | -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/modules/rds/variables.tf: -------------------------------------------------------------------------------- 1 | variable "tags" { 2 | default = {} 3 | type = map(string) 4 | description = "Extra tags to attach to the RDS resources" 5 | } 6 | 7 | variable "update_rds_endpoint" { 8 | type = bool 9 | default = true 10 | } 11 | 12 | variable "region" { 13 | type = string 14 | description = "Region of the rds" 15 | } 16 | 17 | variable "environment" { 18 | type = string 19 | description = "The environment name for the resources." 20 | } 21 | 22 | variable "owner" { 23 | type = string 24 | description = "Name of the owner for this RDS" 25 | } 26 | 27 | variable "application" { 28 | type = string 29 | description = "Name of the application" 30 | } 31 | 32 | variable "cost_center" { 33 | type = string 34 | description = "Name of cost-center for this RDS" 35 | } 36 | 37 | variable "db_username" { 38 | description = "The username for the RDS database" 39 | type = string 40 | } 41 | 42 | variable "set_secret_manager_password" { 43 | description = "To enable master user password or not" 44 | type = bool 45 | default = false 46 | } 47 | 48 | variable "db_password" { 49 | description = "Password for RDS" 50 | type = string 51 | } 52 | 53 | variable "db_instance_class" { 54 | description = "The RDS instance class" 55 | type = string 56 | } 57 | 58 | variable "set_db_password" { 59 | description = "Condition to check for custom password" 60 | type = string 61 | } 62 | 63 | variable "db_storage_size" { 64 | description = "The allocated storage size for the RDS instance." 65 | type = number 66 | } 67 | 68 | variable "backup_retention_period" { 69 | description = "The number of days to retain automated backups." 70 | type = number 71 | } 72 | 73 | variable "multi_az" { 74 | description = "Enable multi-AZ deployment for the RDS instance." 75 | type = bool 76 | } 77 | 78 | variable "delete_automated_backups" { 79 | description = "Enable deletion of automated backups when the RDS instance is deleted." 80 | type = bool 81 | } 82 | 83 | variable "copy_tags_to_snapshot" { 84 | description = "Copy tags to DB snapshots created from the RDS instance." 85 | type = bool 86 | } 87 | 88 | variable "publicly_accessible" { 89 | description = "Allow the RDS instance to be publicly accessible." 90 | type = bool 91 | } 92 | 93 | variable "skip_final_snapshot" { 94 | description = "Skip the creation of a final DB snapshot when the RDS instance is deleted." 95 | type = bool 96 | } 97 | 98 | variable "apply_immediately" { 99 | description = "Apply changes immediately to the RDS instance." 100 | type = bool 101 | } 102 | 103 | variable "db_engine" { 104 | description = "The database engine" 105 | type = string 106 | } 107 | 108 | variable "db_storage_type" { 109 | description = "The storage type for the database" 110 | type = string 111 | } 112 | 113 | variable "ingress_from_port" { 114 | description = "The starting port for ingress rules" 115 | type = number 116 | } 117 | 118 | variable "ingress_cidr_blocks" { 119 | type = list(string) 120 | description = "CIDR block for RDS security group" 121 | } 122 | 123 | variable "ingress_to_port" { 124 | description = "The ending port for ingress rules" 125 | type = number 126 | } 127 | 128 | variable "ingress_protocol" { 129 | description = "The protocol for ingress rules" 130 | type = string 131 | } 132 | 133 | variable "egress_from_port" { 134 | description = "The starting port for ingress rules" 135 | type = number 136 | } 137 | 138 | variable "egress_cidr_blocks" { 139 | type = list(string) 140 | description = "CIDR block for RDS security group" 141 | } 142 | 143 | variable "egress_to_port" { 144 | description = "The ending port for egress rules" 145 | type = number 146 | } 147 | 148 | variable "egress_protocol" { 149 | description = "The protocol for egress rules" 150 | type = string 151 | } 152 | 153 | 154 | variable "subnet_ids" { 155 | description = "The IDs of the subnets" 156 | type = list(string) 157 | } 158 | 159 | variable "vpc_id" { 160 | description = "Vpc ID in which it needs to create" 161 | type = string 162 | } 163 | 164 | variable "parameter_store_secret_name" { 165 | description = "Name of the parameter store secret" 166 | type = string 167 | } 168 | 169 | variable "type" { 170 | description = "Parameter store type" 171 | type = string 172 | } -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/rds/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | } 4 | 5 | module "rds" { 6 | source = "../modules/rds" 7 | region = var.region 8 | vpc_id = var.vpc_id 9 | subnet_ids = var.subnet_ids 10 | db_engine = var.db_engine 11 | db_storage_type = var.db_storage_type 12 | db_username = var.db_username 13 | set_secret_manager_password = var.set_secret_manager_password 14 | set_db_password = var.set_db_password 15 | db_password = var.db_password 16 | db_instance_class = var.db_instance_class 17 | db_storage_size = var.db_storage_size 18 | ingress_from_port = var.ingress_from_port 19 | ingress_to_port = var.ingress_to_port 20 | ingress_protocol = var.ingress_protocol 21 | ingress_cidr_blocks = var.ingress_cidr_blocks 22 | egress_from_port = var.egress_from_port 23 | egress_to_port = var.egress_to_port 24 | egress_protocol = var.egress_protocol 25 | egress_cidr_blocks = var.egress_cidr_blocks 26 | backup_retention_period = var.backup_retention_period 27 | multi_az = var.multi_az 28 | delete_automated_backups = var.delete_automated_backups 29 | copy_tags_to_snapshot = var.copy_tags_to_snapshot 30 | publicly_accessible = var.publicly_accessible 31 | skip_final_snapshot = var.skip_final_snapshot 32 | apply_immediately = var.apply_immediately 33 | parameter_store_secret_name = var.parameter_store_secret_name 34 | type = var.type 35 | owner = var.owner 36 | cost_center = var.cost_center 37 | environment = var.environment 38 | application = var.application 39 | } 40 | -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/rds/variables.tf: -------------------------------------------------------------------------------- 1 | variable "tags" { 2 | default = {} 3 | type = map(string) 4 | description = "Extra tags to attach to the RDS resources" 5 | } 6 | 7 | variable "update_rds_endpoint" { 8 | type = bool 9 | default = true 10 | } 11 | 12 | variable "region" { 13 | type = string 14 | description = "Region of the rds" 15 | } 16 | 17 | variable "environment" { 18 | type = string 19 | description = "The environment name for the resources." 20 | } 21 | 22 | variable "owner" { 23 | type = string 24 | description = "Name of the owner for this RDS" 25 | } 26 | 27 | variable "application" { 28 | type = string 29 | description = "Name of the application" 30 | } 31 | 32 | variable "cost_center" { 33 | type = string 34 | description = "Name of cost-center for this RDS" 35 | } 36 | 37 | variable "db_username" { 38 | description = "The username for the RDS database" 39 | type = string 40 | } 41 | 42 | variable "set_secret_manager_password" { 43 | description = "To enable master user password or not" 44 | type = bool 45 | default = false 46 | } 47 | 48 | variable "db_password" { 49 | description = "Password for RDS" 50 | type = string 51 | } 52 | 53 | variable "db_instance_class" { 54 | description = "The RDS instance class" 55 | type = string 56 | } 57 | 58 | variable "set_db_password" { 59 | description = "Condition to check for custom password" 60 | type = string 61 | } 62 | 63 | variable "db_storage_size" { 64 | description = "The allocated storage size for the RDS instance." 65 | type = number 66 | } 67 | 68 | variable "backup_retention_period" { 69 | description = "The number of days to retain automated backups." 70 | type = number 71 | } 72 | 73 | variable "multi_az" { 74 | description = "Enable multi-AZ deployment for the RDS instance." 75 | type = bool 76 | } 77 | 78 | variable "delete_automated_backups" { 79 | description = "Enable deletion of automated backups when the RDS instance is deleted." 80 | type = bool 81 | } 82 | 83 | variable "copy_tags_to_snapshot" { 84 | description = "Copy tags to DB snapshots created from the RDS instance." 85 | type = bool 86 | } 87 | 88 | variable "publicly_accessible" { 89 | description = "Allow the RDS instance to be publicly accessible." 90 | type = bool 91 | } 92 | 93 | variable "skip_final_snapshot" { 94 | description = "Skip the creation of a final DB snapshot when the RDS instance is deleted." 95 | type = bool 96 | } 97 | 98 | variable "apply_immediately" { 99 | description = "Apply changes immediately to the RDS instance." 100 | type = bool 101 | } 102 | 103 | variable "db_engine" { 104 | description = "The database engine" 105 | type = string 106 | } 107 | 108 | variable "db_storage_type" { 109 | description = "The storage type for the database" 110 | type = string 111 | } 112 | 113 | variable "ingress_from_port" { 114 | description = "The starting port for ingress rules" 115 | type = number 116 | } 117 | 118 | variable "ingress_cidr_blocks" { 119 | type = list(string) 120 | description = "CIDR block for RDS security group" 121 | } 122 | 123 | variable "ingress_to_port" { 124 | description = "The ending port for ingress rules" 125 | type = number 126 | } 127 | 128 | variable "ingress_protocol" { 129 | description = "The protocol for ingress rules" 130 | type = string 131 | } 132 | 133 | variable "egress_from_port" { 134 | description = "The starting port for ingress rules" 135 | type = number 136 | } 137 | 138 | variable "egress_cidr_blocks" { 139 | type = list(string) 140 | description = "CIDR block for RDS security group" 141 | } 142 | 143 | variable "egress_to_port" { 144 | description = "The ending port for egress rules" 145 | type = number 146 | } 147 | 148 | variable "egress_protocol" { 149 | description = "The protocol for egress rules" 150 | type = string 151 | } 152 | 153 | 154 | variable "subnet_ids" { 155 | description = "The IDs of the subnets" 156 | type = list(string) 157 | } 158 | 159 | variable "vpc_id" { 160 | description = "Vpc ID in which it needs to create" 161 | type = string 162 | } 163 | 164 | variable "parameter_store_secret_name" { 165 | description = "Name of the parameter store secret" 166 | type = string 167 | } 168 | 169 | variable "type" { 170 | description = "Parameter store type" 171 | type = string 172 | } -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/vars/alb-asg.tfvars: -------------------------------------------------------------------------------- 1 | #Network 2 | region = "us-west-2" 3 | vpc_id = "vpc-0a5ca4a92c2e10163" 4 | subnets = ["subnet-058a7514ba8adbb07", "subnet-032f5077729435858", "subnet-0dbcd1ac168414927"] 5 | 6 | #alb_sg 7 | ingress_alb_from_port = 80 8 | ingress_alb_to_port = 80 9 | ingress_alb_protocol = "tcp" 10 | ingress_alb_cidr_blocks = ["0.0.0.0/0"] 11 | egress_alb_from_port = 0 12 | egress_alb_to_port = 0 13 | egress_alb_protocol = "-1" 14 | egress_alb_cidr_blocks = ["0.0.0.0/0"] 15 | 16 | #alb 17 | internal = false 18 | loadbalancer_type = "application" 19 | 20 | #target_group 21 | target_group_port = 8080 22 | target_group_protocol = "HTTP" 23 | target_type = "instance" 24 | load_balancing_algorithm = "round_robin" 25 | health_check_path = "/" 26 | health_check_port = 8080 27 | health_check_protocol = "HTTP" 28 | health_check_interval = 30 29 | health_check_timeout = 5 30 | health_check_healthy_threshold = 2 31 | health_check_unhealthy_threshold = 2 32 | 33 | #instance_sg 34 | ingress_asg_cidr_from_port = 22 35 | ingress_asg_cidr_to_port = 22 36 | ingress_asg_cidr_protocol = "tcp" 37 | ingress_asg_cidr_blocks = ["0.0.0.0/0"] 38 | ingress_asg_sg_from_port = 8080 39 | ingress_asg_sg_to_port = 8080 40 | ingress_asg_sg_protocol = "tcp" 41 | egress_asg_from_port = 0 42 | egress_asg_to_port = 0 43 | egress_asg_protocol = "-1" 44 | egress_asg_cidr_blocks = ["0.0.0.0/0"] 45 | 46 | #asg 47 | max_size = 3 48 | min_size = 1 49 | desired_capacity = 2 50 | 51 | #listener 52 | listener_port = 80 53 | listener_protocol = "HTTP" 54 | listener_type = "forward" 55 | 56 | #launch_template 57 | ami_id = "ami-0f7a74cccd5a223bc" 58 | instance_type = "t2.medium" 59 | key_name = "techiescamp" 60 | user_data = <<-EOF 61 | #!/bin/bash 62 | bash /home/ubuntu/start.sh 63 | EOF 64 | public_access = true 65 | instance_warmup_time = 30 66 | target_value = 50 67 | 68 | owner = "techiescamp" 69 | environment = "dev" 70 | cost_center = "techiescamp-commerce" 71 | application = "pet-clinic" -------------------------------------------------------------------------------- /03-scalable-java-app/terraform/vars/rds.tfvars: -------------------------------------------------------------------------------- 1 | # Network Vars 2 | region = "us-west-2" 3 | vpc_id = "vpc-0a5ca4a92c2e10163" 4 | subnet_ids = ["subnet-058a7514ba8adbb07", "subnet-032f5077729435858", "subnet-0dbcd1ac168414927"] 5 | multi_az = false 6 | publicly_accessible = true 7 | 8 | # DB Vars 9 | db_engine = "mysql" 10 | db_storage_type = "gp2" 11 | db_username = "techiescamp" 12 | db_instance_class = "db.t2.micro" 13 | db_storage_size = 20 14 | set_secret_manager_password = true 15 | set_db_password = false 16 | db_password = "rdssecret" 17 | 18 | # Security Group Vars 19 | ingress_from_port = 3306 20 | ingress_to_port = 3306 21 | ingress_protocol = "tcp" 22 | ingress_cidr_blocks = ["0.0.0.0/0"] 23 | 24 | egress_from_port = 0 25 | egress_to_port = 0 26 | egress_protocol = "-1" 27 | egress_cidr_blocks = ["0.0.0.0/0"] 28 | 29 | # Backup vars 30 | backup_retention_period = 7 31 | delete_automated_backups = true 32 | copy_tags_to_snapshot = true 33 | skip_final_snapshot = true 34 | apply_immediately = true 35 | 36 | # Parameter store 37 | parameter_store_secret_name = "/dev/petclinic/rds_endpoint" 38 | type = "String" 39 | 40 | # Tag Vars 41 | owner = "techiescamp" 42 | environment = "dev" 43 | cost_center = "techiescamp-commerce" 44 | application = "rds" -------------------------------------------------------------------------------- /04-prometheus-observability-stack/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all service-discovery 2 | 3 | pub_ip := $(shell curl -s ifconfig.io) 4 | file := ./prometheus/prometheus.yml 5 | file2 := ./prometheus/targets.json 6 | local := 127.0.0.1 7 | 8 | service-discovery: 9 | 10 | @echo "***************************************" 11 | @echo "****SERVICE DISCOVERY OF PUBLIC IP*****" 12 | @echo "*****PUBLIC IPADDRESS : $(pub_ip)******" 13 | @echo "******LOOPBACK ADDRESS : $(local)******" 14 | @sed -i "s/$(local)/$(pub_ip)/g" $(file) 15 | @echo "******UPDATED FILE prometheus.yml******" 16 | @cat "$(file)" 17 | @sed -i "s/$(local)/$(pub_ip)/g" $(file2) 18 | @echo "*******UPDATED FILE targets.json*******" 19 | @cat "$(file2)" 20 | @echo "***************************************" 21 | 22 | rollback: 23 | 24 | @echo "***************************************" 25 | @echo "*****ROLLBACK OF SERVICE DISCOVERY*****" 26 | @echo "******PUBLIC IPADDRESS : $(pub_ip)*****" 27 | @echo "******LOOPBACK ASSRESS : $(local)******" 28 | @sed -i "s/$(pub_ip)/$(local)/g" $(file) 29 | @echo "******UPDATED FILE prometheus.yml******" 30 | @cat "$(file)" 31 | @sed -i "s/$(pub_ip)/$(local)/g" $(file2) 32 | @echo "*******UPDATED FILE targets.json*******" 33 | @cat "$(file2)" 34 | @echo "****************************************" 35 | 36 | all: service-discovery 37 | 38 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/README.md: -------------------------------------------------------------------------------- 1 | ## Prometheus Observability Stack Using Docker 2 | 3 | 4 | ![image](https://github.com/techiescamp/devops-projects/assets/106984297/6a9f9d90-e56f-4038-82c7-e8eae29d8bcf) 5 | 6 | 7 | ## Project Documentation. 8 | 9 | Refer [Setting Up Prometheus Observability Stack](https://devopscube.com/setup-prometheus-using-docker/) for the entire setup walkthrough. 10 | 11 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/alertmanager/alertmanager.yml: -------------------------------------------------------------------------------- 1 | global: 2 | resolve_timeout: 2m 3 | 4 | route: 5 | receiver: 'email-notifications' # Change the receiver to the email configuration 6 | 7 | receivers: 8 | - name: 'email-notifications' # Define the email receiver 9 | email_configs: 10 | - to: 'your-email@example.com' # Replace with your email address 11 | from: 'prometheus@example.com' # Replace with the sender email address 12 | smarthost: 'smtp.example.com:587' # Replace with your SMTP server address and port 13 | auth_username: 'your-username' # Replace with your SMTP username 14 | auth_password: 'your-password' # Replace with your SMTP password 15 | send_resolved: true 16 | 17 | - name: 'slack-notifications' 18 | slack_configs: 19 | - api_url: "https://hooks.slack.com/services/YOUR-SLACK-API-URL" # Replace with your Slack Incoming Webhook URL 20 | channel: '#general' # Replace with the Slack channel or user where you want to send notifications 21 | send_resolved: true # Set to true to send resolved alerts as well 22 | 23 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | 3 | services: 4 | prometheus: 5 | image: prom/prometheus:latest 6 | container_name: prometheus 7 | ports: 8 | - 9090:9090 9 | volumes: 10 | - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml 11 | - ./prometheus/alertrules.yml:/etc/prometheus/alertrules.yml 12 | - ./prometheus/targets.json:/etc/prometheus/targets.json 13 | command: 14 | - '--storage.tsdb.path=/prometheus' 15 | - '--storage.tsdb.retention.time=7d' 16 | - '--config.file=/etc/prometheus/prometheus.yml' 17 | restart: always 18 | networks: 19 | - monitor 20 | 21 | grafana: 22 | image: grafana/grafana:latest 23 | container_name: grafana 24 | ports: 25 | - 3000:3000 26 | depends_on: 27 | - prometheus 28 | restart: always 29 | networks: 30 | - monitor 31 | 32 | node-exporter: 33 | image: prom/node-exporter:latest 34 | container_name: node-exporter 35 | ports: 36 | - 9100:9100 37 | restart: always 38 | networks: 39 | - monitor 40 | 41 | alertmanager: 42 | image: prom/alertmanager:latest 43 | container_name: alert-manager 44 | ports: 45 | - 9093:9093 46 | volumes: 47 | - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml 48 | command: 49 | - --config.file=/etc/alertmanager/alertmanager.yml 50 | restart: always 51 | networks: 52 | - monitor 53 | 54 | networks: 55 | monitor: 56 | driver: bridge 57 | 58 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/prometheus/alertrules.yml: -------------------------------------------------------------------------------- 1 | groups: 2 | - name: test 3 | rules: 4 | - alert: InstanceDown 5 | expr: up == 0 6 | for: 1m 7 | - name: HighCPUUsage 8 | rules: 9 | - alert: HighCpuUsage 10 | expr: sum by(instance)(irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100 < 10 11 | for: 1m 12 | labels: 13 | severity: warning 14 | annotations: 15 | summary: High CPU usage detected 16 | description: "CPU usage on instance {{ $labels.instance }} has been above 90% for the last 5 minute." 17 | - name: HighMemoryUsage 18 | rules: 19 | - alert: HighMemoryUsage 20 | expr: sum(container_memory_usage_bytes) by (namespace) > 90 * 1024 * 1024 * 1024 21 | for: 1m 22 | labels: 23 | severity: warning 24 | annotations: 25 | summary: High Memory Usage in {{ $labels.namespace }} 26 | description: 'The {{ $labels.namespace }} namespace is experiencing high memory usage.' 27 | - name: HighStorageUsage 28 | rules: 29 | - alert: HighStorageUsage 30 | expr: (node_filesystem_size_bytes - node_filesystem_free_bytes) / node_filesystem_size_bytes > 0.9 31 | for: 1m 32 | labels: 33 | severity: warning 34 | annotations: 35 | summary: High Storage Usage on {{ $labels.instance }} 36 | description: 'The {{ $labels.instance }} host is experiencing high storage usage.' 37 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | 5 | alerting: 6 | alertmanagers: 7 | - static_configs: 8 | - targets: 9 | - "127.0.0.1:9093" 10 | rule_files: 11 | - alertrules.yml 12 | 13 | scrape_configs: 14 | - job_name: 'Host' 15 | file_sd_configs: 16 | - files: 17 | - 'targets.json' 18 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/prometheus/targets.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "labels": { 4 | "job": "Host" 5 | }, 6 | "targets": [ 7 | "127.0.0.1:9100" 8 | ] 9 | } 10 | ] 11 | 12 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/README.md: -------------------------------------------------------------------------------- 1 | # terraform-aws 2 | Terraform AWS EC2 provisioning 3 | 4 | ## Hit the Star! ⭐ 5 | If you are planning to use this Terraform repo for learning, please hit the star. Thanks! 6 | 7 | ## EC2 Instance Provisioning 8 | 9 | 1. Navigate to the `environment/dev/ec2` folder: 10 | 11 | ```bash 12 | cd prometheus-stack/ 13 | ``` 14 | 15 | 2. Open the `ec2.tfvars` file and modify it with your desired details. This file contains variables used in the Terraform configuration. 16 | 17 | ### Deployment 18 | 19 | 1. Format Terraform code per HCL canonical standards in the working directory: 20 | 21 | ```bash 22 | terraform fmt 23 | ``` 24 | 25 | 2. Validate Terraform code in the working directory: 26 | 27 | ```bash 28 | terraform validate 29 | ``` 30 | 31 | 3. Initialize Terraform in the working directory: 32 | 33 | ```bash 34 | terraform init 35 | ``` 36 | 37 | 4. Create an execution plan: 38 | 39 | ```bash 40 | terraform plan --var-file=../vars/ec2.tfvars 41 | ``` 42 | 43 | 5. Apply the changes to create the EC2 instance: 44 | 45 | ```bash 46 | terraform apply --var-file=../vars/ec2.tfvars 47 | ``` 48 | 49 | 6. To destroy the EC2 instance and associated resources: 50 | 51 | ```bash 52 | terraform destroy --var-file=../vars/ec2.tfvars 53 | ``` 54 | 55 | **Note**: Always review the execution plan (`terraform plan`) before applying changes to avoid unintended modifications. 56 | 57 | 58 | ## Terraform Command Reference 59 | 60 | Update all outputs: 61 | 62 |
terraform refresh
63 | 64 | Show all outputs: 65 | 66 |
terraform show
67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/modules/ec2/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_instance" "ec2_instance" { 2 | ami = var.ami_id 3 | instance_type = var.instance_type 4 | key_name = var.key_name 5 | count = var.instance_count 6 | user_data = base64encode(file("${path.module}/user-data.sh")) 7 | 8 | root_block_device { 9 | volume_size = var.volume-size # Size in GB 10 | volume_type = "gp2" # EBS volume type 11 | } 12 | 13 | vpc_security_group_ids = var.security_group_ids 14 | 15 | subnet_id = element(var.subnet_ids, count.index % length(var.subnet_ids)) 16 | 17 | tags = merge( 18 | { 19 | Name = "${var.environment}-${var.application}" 20 | Environment = var.environment 21 | Owner = var.owner 22 | CostCenter = var.cost_center 23 | Application = var.application 24 | }, 25 | var.tags 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/modules/ec2/outputs.tf: -------------------------------------------------------------------------------- 1 | output "instance_state" { 2 | description = "The state of the ec2 instance " 3 | value = aws_instance.ec2_instance.*.instance_state 4 | } 5 | 6 | output "instance_public_dns" { 7 | description = "The Public DNS address of the ec2 instance" 8 | value = aws_instance.ec2_instance.*.public_dns 9 | } 10 | 11 | output "instance_public_ip" { 12 | description = "The Public Ip address of the ec2 instance" 13 | value = aws_instance.ec2_instance.*.public_ip 14 | } 15 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/modules/ec2/user-data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Update the package list and upgrade the installed packages 4 | sudo apt-get update -y 5 | 6 | # Add Swap Memory of 2GB 7 | sudo swapon --show 8 | free -h 9 | df -h 10 | sudo fallocate -l 2G /swapfile 11 | ls -lh /swapfile 12 | sudo chmod 600 /swapfile 13 | ls -lh /swapfile 14 | sudo mkswap /swapfile 15 | sudo swapon /swapfile 16 | sudo swapon --show 17 | free -h 18 | cat /proc/sys/vm/swappiness 19 | sudo sysctl vm.swappiness=10 20 | cat /proc/sys/vm/vfs_cache_pressure 21 | sudo sysctl vm.vfs_cache_pressure=50 22 | 23 | # Install essential packages 24 | sudo apt-get install -y curl net-tools wget unzip tree make 25 | 26 | # Install Docker 27 | sudo apt-get install -y docker.io 28 | 29 | # Install Docker Compose 30 | sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 31 | sudo chmod +x /usr/local/bin/docker-compose 32 | 33 | # Start the Docker service 34 | sudo systemctl start docker 35 | sudo systemctl enable docker 36 | 37 | # Output Docker and Docker Compose versions 38 | docker --version 39 | docker-compose --version -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/modules/ec2/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | type = string 3 | description = "Region of the ec2 instance" 4 | } 5 | 6 | variable "volume-size" { 7 | type = number 8 | } 9 | 10 | variable "ami_id" { 11 | type = string 12 | description = "AMI Id of the ec2 instance" 13 | } 14 | 15 | variable "instance_type" { 16 | type = string 17 | description = "Instance type of the ec2 instance" 18 | } 19 | 20 | variable "key_name" { 21 | type = string 22 | description = "Key name of the ec2 instance" 23 | } 24 | 25 | variable "instance_count" { 26 | type = number 27 | description = "Count of the ec2 instances" 28 | } 29 | 30 | variable "subnet_ids" { 31 | type = list(string) 32 | description = "Subnet ids of the ec2 instance" 33 | } 34 | 35 | variable "tags" { 36 | default = {} 37 | type = map(string) 38 | description = "Extra tags to attach to the ec2-sg resources" 39 | } 40 | 41 | variable "name" { 42 | type = string 43 | description = "The name of the resources." 44 | } 45 | 46 | variable "environment" { 47 | type = string 48 | description = "The environment name for the resources." 49 | } 50 | 51 | variable "owner" { 52 | type = string 53 | description = "Owner's name for the resource." 54 | } 55 | 56 | variable "cost_center" { 57 | type = string 58 | description = "Cost center identifier for the resource." 59 | } 60 | 61 | variable "application" { 62 | type = string 63 | description = "Name of the application related to the resource." 64 | } 65 | 66 | variable "security_group_ids" { 67 | description = "List of security group IDs to attach to the EC2 instance." 68 | type = list(string) 69 | } 70 | 71 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/modules/security-group/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "instance_sg" { 2 | name = "${var.environment}-${var.application}" 3 | description = "Security Group for Instance" 4 | vpc_id = var.vpc_id 5 | 6 | # Ingress rules for CIDR blocks 7 | dynamic "ingress" { 8 | for_each = var.create_ingress_cidr ? toset(range(length(var.ingress_cidr_from_port))) : [] 9 | content { 10 | from_port = var.ingress_cidr_from_port[ingress.key] 11 | to_port = var.ingress_cidr_to_port[ingress.key] 12 | protocol = var.ingress_cidr_protocol[ingress.key] 13 | cidr_blocks = var.ingress_cidr_block 14 | description = var.ingress_cidr_description[ingress.key] 15 | } 16 | } 17 | 18 | 19 | # Egress rules for CIDR blocks 20 | dynamic "egress" { 21 | for_each = var.create_egress_cidr ? toset(range(length(var.egress_cidr_from_port))) : [] 22 | content { 23 | from_port = var.egress_cidr_from_port[egress.key] 24 | to_port = var.egress_cidr_to_port[egress.key] 25 | protocol = var.egress_cidr_protocol[egress.key] 26 | cidr_blocks = var.egress_cidr_block 27 | } 28 | } 29 | 30 | 31 | tags = merge( 32 | { 33 | Name = "${var.environment}-${var.application}" 34 | Environment = var.environment 35 | Owner = var.owner 36 | CostCenter = var.cost_center 37 | Application = var.application 38 | }, 39 | var.tags 40 | ) 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/modules/security-group/outputs.tf: -------------------------------------------------------------------------------- 1 | output "security_group_ids" { 2 | description = "ID of the security group." 3 | value = aws_security_group.instance_sg.*.id 4 | } -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/modules/security-group/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | type = string 3 | description = "Region of the security group." 4 | } 5 | 6 | variable "vpc_id" { 7 | type = string 8 | description = "ID of the VPC associated with the security group." 9 | } 10 | 11 | variable "tags" { 12 | default = {} 13 | type = map(string) 14 | description = "Extra tags to attach to the EC2 security group resources." 15 | } 16 | 17 | variable "name" { 18 | type = string 19 | description = "The name of the resources." 20 | } 21 | 22 | variable "environment" { 23 | type = string 24 | description = "The environment name for the resources." 25 | } 26 | 27 | variable "owner" { 28 | type = string 29 | description = "Owner's name for the resource." 30 | } 31 | 32 | variable "cost_center" { 33 | type = string 34 | description = "Cost center identifier for the resource." 35 | } 36 | 37 | variable "application" { 38 | type = string 39 | description = "Name of the application related to the resource." 40 | } 41 | 42 | variable "ingress_cidr_from_port" { 43 | type = list(number) 44 | description = "List of starting ports for cidr ingress rules of the EC2 security group." 45 | } 46 | 47 | variable "ingress_cidr_to_port" { 48 | type = list(number) 49 | description = "List of ending ports for cidr ingress rules of the EC2 security group." 50 | } 51 | 52 | variable "ingress_cidr_protocol" { 53 | type = list(string) 54 | description = "List of protocols for cidr ingress rules of the EC2 security group." 55 | } 56 | 57 | variable "ingress_cidr_description" { 58 | type = list(string) 59 | description = "Description for this ingress rule" 60 | } 61 | 62 | 63 | variable "ingress_cidr_block" { 64 | type = list(string) 65 | description = "List of CIDR blocks for cidr ingress rules of the EC2 security group." 66 | } 67 | 68 | variable "egress_cidr_from_port" { 69 | type = list(number) 70 | description = "List of starting ports for cidr egress rules of the EC2 security group." 71 | } 72 | 73 | variable "egress_cidr_to_port" { 74 | type = list(number) 75 | description = "List of ending ports for cidr egress rules of the EC2 security group." 76 | } 77 | 78 | variable "egress_cidr_protocol" { 79 | type = list(any) 80 | description = "List of protocols for cidr egress rules of the EC2 security group." 81 | } 82 | 83 | variable "egress_cidr_block" { 84 | type = list(string) 85 | description = "List of CIDR blocks for cidr egress rules of the EC2 security group." 86 | } 87 | 88 | variable "create_ingress_cidr" { 89 | type = bool 90 | description = "Enable or disable CIDR block ingress rules." 91 | } 92 | 93 | 94 | variable "create_egress_cidr" { 95 | type = bool 96 | description = "Enable or disable CIDR block egress rules." 97 | } 98 | 99 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/prometheus-stack/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | } 4 | 5 | module "ec2" { 6 | source = "../modules/ec2" 7 | region = var.region 8 | ami_id = var.ami_id 9 | instance_type = var.instance_type 10 | key_name = var.key_name 11 | instance_count = var.instance_count 12 | subnet_ids = var.subnet_ids 13 | name = var.name 14 | environment = var.environment 15 | owner = var.owner 16 | cost_center = var.cost_center 17 | application = var.application 18 | security_group_ids = module.security-group.security_group_ids 19 | volume-size = var.volume-size 20 | } 21 | 22 | module "security-group" { 23 | source = "../modules/security-group" 24 | region = var.region 25 | tags = var.tags 26 | name = var.name 27 | environment = var.environment 28 | owner = var.owner 29 | cost_center = var.cost_center 30 | application = var.application 31 | vpc_id = var.vpc_id 32 | 33 | ingress_cidr_from_port = var.ingress_cidr_from_port 34 | ingress_cidr_to_port = var.ingress_cidr_to_port 35 | ingress_cidr_protocol = var.ingress_cidr_protocol 36 | ingress_cidr_block = var.ingress_cidr_block 37 | ingress_cidr_description = var.ingress_cidr_description 38 | create_ingress_cidr = var.create_ingress_cidr 39 | 40 | egress_cidr_from_port = var.egress_cidr_from_port 41 | egress_cidr_to_port = var.egress_cidr_to_port 42 | egress_cidr_protocol = var.egress_cidr_protocol 43 | egress_cidr_block = var.egress_cidr_block 44 | create_egress_cidr = var.create_egress_cidr 45 | 46 | } 47 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/prometheus-stack/outputs.tf: -------------------------------------------------------------------------------- 1 | output "instance_state" { 2 | description = "The state of the ec2 instance " 3 | value = module.ec2.instance_state 4 | } 5 | 6 | output "instance_public_dns" { 7 | description = "The Public DNS address of the ec2 instance" 8 | value = module.ec2.instance_public_dns 9 | } 10 | 11 | output "instance_public_ip" { 12 | description = "The Public Ip address of the ec2 instance" 13 | value = module.ec2.instance_public_ip 14 | } 15 | 16 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/prometheus-stack/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | type = string 3 | description = "Region of the EC2 instance" 4 | } 5 | 6 | variable "volume-size" { 7 | type = number 8 | } 9 | 10 | variable "ami_id" { 11 | type = string 12 | description = "AMI ID of the EC2 instance" 13 | } 14 | 15 | variable "instance_type" { 16 | type = string 17 | description = "Instance type of the EC2 instance" 18 | } 19 | 20 | variable "key_name" { 21 | type = string 22 | description = "Key name of the EC2 instance" 23 | } 24 | 25 | variable "instance_count" { 26 | type = number 27 | description = "Count of the EC2 instances" 28 | } 29 | 30 | variable "subnet_ids" { 31 | type = list(string) 32 | description = "Subnet IDs of the EC2 instance" 33 | } 34 | 35 | variable "vpc_id" { 36 | type = string 37 | description = "VPC ID for the security group" 38 | } 39 | 40 | variable "tags" { 41 | default = {} 42 | type = map(string) 43 | description = "Extra tags to attach to the security group resources" 44 | } 45 | 46 | variable "name" { 47 | type = string 48 | description = "The name of the resources" 49 | } 50 | 51 | variable "environment" { 52 | type = string 53 | description = "The environment name for the resources" 54 | } 55 | 56 | variable "owner" { 57 | type = string 58 | description = "Owner's name for the resource" 59 | } 60 | 61 | variable "cost_center" { 62 | type = string 63 | description = "Cost center identifier for the resource" 64 | } 65 | 66 | variable "application" { 67 | type = string 68 | description = "Name of the application related to the resource" 69 | } 70 | 71 | 72 | variable "ingress_cidr_from_port" { 73 | type = list(number) 74 | description = "List of starting ports for cidr ingress rules of the EC2 security group." 75 | } 76 | 77 | variable "ingress_cidr_to_port" { 78 | type = list(number) 79 | description = "List of ending ports for cidr ingress rules of the EC2 security group." 80 | } 81 | 82 | variable "ingress_cidr_protocol" { 83 | type = list(string) 84 | description = "List of protocols for cidr ingress rules of the EC2 security group." 85 | } 86 | 87 | variable "ingress_cidr_description" { 88 | type = list(string) 89 | description = "Description for this ingress rule" 90 | } 91 | 92 | variable "ingress_cidr_block" { 93 | type = list(string) 94 | description = "List of CIDR blocks for cidr ingress rules of the EC2 security group." 95 | } 96 | 97 | variable "egress_cidr_from_port" { 98 | type = list(number) 99 | description = "List of starting ports for cidr egress rules of the EC2 security group." 100 | } 101 | 102 | variable "egress_cidr_to_port" { 103 | type = list(number) 104 | description = "List of ending ports for cidr egress rules of the EC2 security group." 105 | } 106 | 107 | variable "egress_cidr_protocol" { 108 | type = list(any) 109 | description = "List of protocols for cidr egress rules of the EC2 security group." 110 | } 111 | 112 | variable "egress_cidr_block" { 113 | type = list(string) 114 | description = "List of CIDR blocks for cidr egress rules of the EC2 security group." 115 | } 116 | 117 | variable "create_ingress_cidr" { 118 | type = bool 119 | description = "Enable or disable CIDR block ingress rules." 120 | } 121 | 122 | variable "create_egress_cidr" { 123 | type = bool 124 | description = "Enable or disable CIDR block egress rules." 125 | } 126 | 127 | -------------------------------------------------------------------------------- /04-prometheus-observability-stack/terraform-aws/vars/ec2.tfvars: -------------------------------------------------------------------------------- 1 | # EC2 Instance Variables 2 | region = "us-west-2" 3 | ami_id = "ami-03fd0aa14bd102718" 4 | instance_type = "t4g.micro" 5 | key_name = "techiescamp" 6 | instance_count = 1 7 | volume-size = 20 8 | 9 | # VPC id 10 | vpc_id = "vpc-0a5ca4a92c2e10163" 11 | subnet_ids = ["subnet-058a7514ba8adbb07"] 12 | 13 | # Ec2 Tags 14 | name = "prometheus-stack" 15 | owner = "techiescamp" 16 | environment = "dev" 17 | cost_center = "techiescamp-commerce" 18 | application = "monitoring" 19 | 20 | # CIDR Ingress Variables 21 | create_ingress_cidr = true 22 | ingress_cidr_from_port = [22, 80, 443, 9090, 9100, 9093, 3000] # List of from ports 23 | ingress_cidr_to_port = [22, 80, 443, 9090, 9100, 9093, 3000] # List of to ports 24 | ingress_cidr_protocol = ["tcp", "tcp", "tcp", "tcp", "tcp", "tcp", "tcp"] # Protocol for all rules (you can add more if needed) 25 | ingress_cidr_block = ["0.0.0.0/0", "0.0.0.0/0", "0.0.0.0/0", "0.0.0.0/0", "0.0.0.0/0", "0.0.0.0/0", "0.0.0.0/0"] 26 | ingress_cidr_description = ["SSH", "HTTP", "HTTPS", "Prometheus", "Node-exporter", "Alert manager", "Grafana"] 27 | 28 | # CIDR Egress Variables 29 | create_egress_cidr = true 30 | egress_cidr_from_port = [0] 31 | egress_cidr_to_port = [0] 32 | egress_cidr_protocol = ["-1"] 33 | egress_cidr_block = ["0.0.0.0/0"] 34 | 35 | -------------------------------------------------------------------------------- /05-aws-vpc-design-and-automation/README.md: -------------------------------------------------------------------------------- 1 | # Design a AWS VPC For Application and Automate VPC Creation Using Terraform 2 | 3 | Lets first understand how VPCs are managed in organizations. 4 | 5 | In large organizations, the network is managed by a dedicated network team. 6 | 7 | However, it's crucial for DevOps engineers to understand AWS network concepts to collaborate more effectively with network teams. 8 | 9 | It specicailly helps during troubleshooting. 10 | 11 | For example, 12 | 13 | There is a big difference when you say “It’s not working, can you look into this” and “Hey, I have done my initial network troubleshooting, and here are my findings. Can you look into this further and help us understand what’s causing the issue” 14 | 15 | In small to medium-sized organizations or startups, network management is typically handled by DevOps engineers or developers. 16 | 17 | ## Design a VPC 18 | 19 | In the design section, you'll learn how to create an AWS VPC for the following application architecture. 20 | 21 | ![image](https://github.com/techiescamp/devops-projects/assets/106984297/5b855e54-1980-4a00-b2e7-44b689a986cd) 22 | 23 | The architecture includes the following application categories: 24 | 25 | - Web Application (Java App) 26 | - Automation Tools (App/Infra CI/CD) 27 | - Platform Tools (e.g., Prometheus, Grafana) 28 | - Managed Services (e.g., RDS Database, S3, Secrets Manager) 29 | - Additionally, you will document the necessary VPC CIDR, subnets, etc. This is a standard practice in organizations 30 | 31 | **Design Documentation:** [AWS VPC Design: A Practical Approach](https://devopscube.com/aws-vpc-design/) 32 | 33 | ## Automate VPC Creation Using Terraform 34 | 35 | Once you grasp VPC design and documentation, the next step is to automate VPC management, enabling reproducibility and simplified management with a single click. 36 | 37 | We will be creating the VPC with the following 38 | 39 | - **CIDR Block:** 10.0.0.0/16 40 | - **Region**: us-west-2 41 | - **Availability Zones:** us-west-2a, us-west-2b, us-west-2c 42 | - **Subnets**: 15 Subnets (One per availability Zone) 43 | - Public Sunets (3) 44 | - App Subets (3) 45 | - DB Subnets (3) 46 | - Management Subnets (3) 47 | - Platform Subnet (3) 48 | - **NAT Gateway** for Private subnets 49 | - **Internet Gateway** for public subnets. 50 | - **Enabled Endpoints:** s3, Cloudwatch & Secrets Manager 51 | - **Dedicated NACLs** for 4 set of subnets. 52 | 53 | We have created Terraform VPC modules for the requirements we outlined in the Design. 54 | 55 | **Terraform VPC Creation Documentation:** [Create AWS VPC Using Terraform](https://devopscube.com/terraform-aws-vpc/) 56 | 57 | ## Further Learning References 58 | 59 | 1. [One to Many: Evolving VPC Design](https://aws.amazon.com/blogs/architecture/one-to-many-evolving-vpc-design/) 60 | 2. [AWS Network Connectivity Models](https://docs.aws.amazon.com/whitepapers/latest/hybrid-connectivity/connectivity-models.html) 61 | 3. [AWS Hybrid Network Design Pattern](https://aws.amazon.com/blogs/apn/vmware-cloud-on-aws-hybrid-network-design-patterns/) 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /06-aws-client-vpn-setup/README.md: -------------------------------------------------------------------------------- 1 | # AWS Client VPN Setup 2 | One of the essential concepts for DevOps engineers is VPN connectivity. 3 | 4 | Every organization uses VPN connectivity to securely connect to cloud resources. 5 | 6 | The best way to understand VPN is by setting up one. 7 | 8 | In this DevOps project, you will gain practical knowledge of the following concepts: 9 | 10 | - Client to Site VPN 11 | - Client and Server Certificates Genration using EasyRSA 12 | - Mutual TLS Authentication (mTLS) 13 | 14 | The following topic is covered in a theoretical format: 15 | 16 | - SAML/Active Directory-based authentication. 17 | - TCP vs UDP 18 | 19 | ## Setup Architecture 20 | ![aws-client-vpn-project](https://github.com/techiescamp/devops-projects/assets/106984297/02585ff0-b666-474d-9ca7-565b3828c4e3) 21 | 22 | ## Setup Documentation 23 | 24 | The following documentation has the step-by-step tutorial on AWS Client VPN Endpoint setup to achieve secure, scalable, and highly available remote VPC connectivity. 25 | 26 | **Full Documentation:** [AWS Cleint VPN With mTLS Setup](https://devopscube.com/aws-client-vpn/) 27 | -------------------------------------------------------------------------------- /07-pritunl-vpn-setup/OpenVPN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiescamp/devops-projects/4bd247b4df794262d88c9b7ee2594cffc34812fd/07-pritunl-vpn-setup/OpenVPN.png -------------------------------------------------------------------------------- /07-pritunl-vpn-setup/README.md: -------------------------------------------------------------------------------- 1 | # Pritunl VPN Setup 2 | One of the essential concepts for DevOps engineers is VPN connectivity. 3 | 4 | Every organization uses VPN connectivity to securely connect to cloud resources. 5 | 6 | The best way to understand VPN is by setting up one. 7 | 8 | In this DevOps project, you will gain practical knowledge of the following concepts: 9 | 10 | - Installation and configuration of Pritunl 11 | - Create and setup VPN users (Clients) 12 | - Authenticate users using VPN client 13 | 14 | ## Setup Architecture 15 | ![Pritunl VPN](/07-pritunl-vpn-setup/OpenVPN.png) 16 | 17 | ## Setup Documentation 18 | 19 | The following documentation has the step-by-step tutorial on Pritunl VPN setup to achieve secure, scalable, and highly available remote VPC connectivity. 20 | 21 | **Full Documentation:** [Pritunl VPN Setup](https://devopscube.com/setup-pritunl-vpn-on-ec2/) 22 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/eks-fargate.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: eksctl.io/v1alpha5 2 | kind: ClusterConfig 3 | 4 | metadata: 5 | name: private-fargate-cluster 6 | region: us-west-2 7 | 8 | vpc: 9 | id: "vpc-09cda2c938e687f27" 10 | cidr: "10.0.0.0/16" 11 | subnets: 12 | private: 13 | us-west-2a: { id: subnet-045d0562c6a1d8233 } 14 | us-west-2b: { id: subnet-06dd483abe9150717 } 15 | 16 | clusterEndpoints: 17 | publicAccess: false 18 | privateAccess: true 19 | 20 | iam: 21 | withOIDC: true 22 | 23 | fargateProfiles: 24 | - name: fp-default 25 | selectors: 26 | - namespace: default 27 | - namespace: kube-system 28 | 29 | - name: fp-game 30 | selectors: 31 | - namespace: game-ns 32 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/fp-game.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: eksctl.io/v1alpha5 2 | kind: ClusterConfig 3 | 4 | metadata: 5 | name: private-fargate-cluster 6 | region: us-west-2 7 | 8 | fargateProfiles: 9 | - name: fp-game 10 | selectors: 11 | - namespace: game-ns 12 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/helm/game-2048/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: 2048-game 3 | description: A Helm chart to deploy the 2048 game 4 | version: 0.1.0 5 | appVersion: "1.0" 6 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/helm/game-2048/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | namespace: {{ .Values.namespace }} 5 | name: deployment-2048 6 | spec: 7 | selector: 8 | matchLabels: 9 | app.kubernetes.io/name: app-2048 10 | replicas: {{ .Values.replicas }} 11 | template: 12 | metadata: 13 | labels: 14 | app.kubernetes.io/name: app-2048 15 | spec: 16 | containers: 17 | - image: {{ .Values.image.repository }}:{{ .Values.image.tag }} 18 | imagePullPolicy: Always 19 | name: app-2048 20 | ports: 21 | - containerPort: 80 22 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/helm/game-2048/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | namespace: {{ .Values.namespace }} 5 | name: service-2048 6 | annotations: 7 | service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip" 8 | service.beta.kubernetes.io/aws-load-balancer-type: external 9 | service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing 10 | spec: 11 | ports: 12 | - port: {{ .Values.service.port }} 13 | targetPort: 80 14 | protocol: TCP 15 | type: {{ .Values.service.type }} 16 | selector: 17 | app.kubernetes.io/name: app-2048 18 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/helm/game-2048/values.yaml: -------------------------------------------------------------------------------- 1 | replicas: 3 2 | image: 3 | repository: public.ecr.aws/l6m2t8p7/docker-2048 4 | tag: latest 5 | service: 6 | port: 80 7 | type: LoadBalancer 8 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/tf-vpc/main.tf: -------------------------------------------------------------------------------- 1 | /*==== 2 | The VPC 3 | ======*/ 4 | 5 | resource "aws_vpc" "vpc" { 6 | cidr_block = "${var.vpc_cidr}" 7 | enable_dns_hostnames = true 8 | enable_dns_support = true 9 | 10 | tags = { 11 | Name = "${var.environment}-vpc" 12 | Environment = "${var.environment}" 13 | } 14 | } 15 | 16 | /*==== 17 | Subnets 18 | ======*/ 19 | /* Internet gateway for the public subnet */ 20 | resource "aws_internet_gateway" "ig" { 21 | vpc_id = "${aws_vpc.vpc.id}" 22 | 23 | tags = { 24 | Name = "${var.environment}-igw" 25 | Environment = "${var.environment}" 26 | } 27 | } 28 | 29 | 30 | /* Elastic IP for NAT */ 31 | resource "aws_eip" "nat_eip" { 32 | vpc = true 33 | depends_on = [aws_internet_gateway.ig] 34 | } 35 | 36 | /* NAT */ 37 | resource "aws_nat_gateway" "nat" { 38 | allocation_id = "${aws_eip.nat_eip.id}" 39 | subnet_id = "${element(aws_subnet.public_subnet.*.id, 0)}" 40 | depends_on = [aws_internet_gateway.ig] 41 | 42 | tags = { 43 | Name = "nat" 44 | Environment = "${var.environment}" 45 | } 46 | } 47 | 48 | /* Public subnet */ 49 | resource "aws_subnet" "public_subnet" { 50 | vpc_id = "${aws_vpc.vpc.id}" 51 | count = "${length(var.public_subnets_cidr)}" 52 | cidr_block = "${element(var.public_subnets_cidr, count.index)}" 53 | availability_zone = "${element(var.availability_zones, count.index)}" 54 | map_public_ip_on_launch = true 55 | 56 | tags = { 57 | Name = "${var.environment}-${element(var.availability_zones, count.index)}-public-subnet" 58 | Environment = "${var.environment}" 59 | } 60 | } 61 | 62 | /* Private subnet */ 63 | resource "aws_subnet" "private_subnet" { 64 | vpc_id = "${aws_vpc.vpc.id}" 65 | count = "${length(var.private_subnets_cidr)}" 66 | cidr_block = "${element(var.private_subnets_cidr, count.index)}" 67 | availability_zone = "${element(var.availability_zones, count.index)}" 68 | map_public_ip_on_launch = false 69 | 70 | tags = { 71 | Name = "${var.environment}-${element(var.availability_zones, count.index)}-private-subnet" 72 | Environment = "${var.environment}" 73 | "kubernetes.io/role/elb" = "1" 74 | } 75 | } 76 | 77 | /* Routing table for private subnet */ 78 | resource "aws_route_table" "private" { 79 | vpc_id = "${aws_vpc.vpc.id}" 80 | 81 | tags = { 82 | Name = "${var.environment}-private-route-table" 83 | Environment = "${var.environment}" 84 | } 85 | } 86 | 87 | /* Routing table for public subnet */ 88 | resource "aws_route_table" "public" { 89 | vpc_id = "${aws_vpc.vpc.id}" 90 | 91 | tags = { 92 | Name = "${var.environment}-public-route-table" 93 | Environment = "${var.environment}" 94 | } 95 | } 96 | 97 | resource "aws_route" "public_internet_gateway" { 98 | route_table_id = "${aws_route_table.public.id}" 99 | destination_cidr_block = "0.0.0.0/0" 100 | gateway_id = "${aws_internet_gateway.ig.id}" 101 | } 102 | 103 | resource "aws_route" "private_nat_gateway" { 104 | route_table_id = "${aws_route_table.private.id}" 105 | destination_cidr_block = "0.0.0.0/0" 106 | nat_gateway_id = "${aws_nat_gateway.nat.id}" 107 | } 108 | 109 | /* Route table associations */ 110 | resource "aws_route_table_association" "public" { 111 | count = "${length(var.public_subnets_cidr)}" 112 | subnet_id = "${element(aws_subnet.public_subnet.*.id, count.index)}" 113 | route_table_id = "${aws_route_table.public.id}" 114 | } 115 | 116 | resource "aws_route_table_association" "private" { 117 | count = "${length(var.private_subnets_cidr)}" 118 | subnet_id = "${element(aws_subnet.private_subnet.*.id, count.index)}" 119 | route_table_id = "${aws_route_table.private.id}" 120 | } 121 | 122 | /*==== 123 | VPC's Default Security Group 124 | ======*/ 125 | resource "aws_security_group" "default" { 126 | name = "${var.environment}-default-sg" 127 | description = "Default security group to allow inbound/outbound from the VPC" 128 | vpc_id = "${aws_vpc.vpc.id}" 129 | depends_on = [aws_vpc.vpc] 130 | 131 | ingress { 132 | from_port = "0" 133 | to_port = "0" 134 | protocol = "-1" 135 | self = true 136 | } 137 | 138 | egress { 139 | from_port = "0" 140 | to_port = "0" 141 | protocol = "-1" 142 | self = "true" 143 | } 144 | 145 | tags = { 146 | Environment = "${var.environment}" 147 | } 148 | } 149 | 150 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/tf-vpc/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc_id" { 2 | value = "${aws_vpc.vpc.id}" 3 | } 4 | 5 | output "public_subnets_id" { 6 | value = ["${aws_subnet.public_subnet.*.id}"] 7 | } 8 | 9 | output "private_subnets_id" { 10 | value = ["${aws_subnet.private_subnet.*.id}"] 11 | } 12 | 13 | output "public_subnet_1" { 14 | value = "${aws_subnet.public_subnet.0.id}" 15 | } 16 | 17 | output "public_subnet_2" { 18 | value = "${aws_subnet.public_subnet.1.id}" 19 | } 20 | 21 | output "private_subnet_1" { 22 | value = "${aws_subnet.private_subnet.0.id}" 23 | } 24 | 25 | output "private_subnet_2" { 26 | value = "${aws_subnet.private_subnet.1.id}" 27 | } 28 | 29 | output "default_sg_id" { 30 | value = "${aws_security_group.default.id}" 31 | } 32 | 33 | output "security_groups_ids" { 34 | value = ["${aws_security_group.default.id}"] 35 | } 36 | 37 | output "public_route_table" { 38 | value = "${aws_route_table.public.id}" 39 | } 40 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/tf-vpc/variables.tf: -------------------------------------------------------------------------------- 1 | variable "environment" { 2 | description = "The Deployment environment" 3 | } 4 | 5 | variable "vpc_cidr" { 6 | description = "The CIDR block of the vpc" 7 | } 8 | 9 | variable "public_subnets_cidr" { 10 | type = list 11 | description = "The CIDR block for the public subnet" 12 | } 13 | 14 | variable "private_subnets_cidr" { 15 | type = list 16 | description = "The CIDR block for the private subnet" 17 | } 18 | 19 | variable "region" { 20 | description = "The region to launch the bastion host" 21 | } 22 | 23 | variable "availability_zones" { 24 | type = list 25 | description = "The az that the resources will be launched" 26 | } 27 | 28 | -------------------------------------------------------------------------------- /08-fargate-app-deployment/tf-vpc/vpc.tfvars: -------------------------------------------------------------------------------- 1 | #tfvars 2 | 3 | environment = "fargate" 4 | vpc_cidr = "10.0.0.0/16" 5 | region = "us-west-2" 6 | public_subnets_cidr = ["10.0.1.0/24", "10.0.2.0/24"] 7 | private_subnets_cidr = ["10.0.3.0/24", "10.0.4.0/24"] 8 | availability_zones = ["us-west-2a", "us-west-2b"] 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Real-World DevOps Projects For Learning 2 | 3 | DevOps Real World Projects for Aspiring DevOps Engineers [Beginner to Advanced] 4 | 5 | ## Hit the Star! ⭐ 6 | If you are planning to use this repo for learning, please hit the star. Thanks! 7 | 8 | ## Kubernetes Certification Voucher (UpTo 38% OFF) 🎉 9 | 10 | As part of our commitment to helping the DevOps community save money on Kubernetes Certifications, we continuously update the latest voucher codes from the Linux Foundation 11 | 12 | > [!IMPORTANT] 13 | > 🚀 Kubernetes Certification aspirants can **save 30%** today using code **DCUBE30** at https://kube.promo/devops. It is a limited-time offer from the Linux Foundation. 14 | 15 | The following are the best bundles to **save 38% (up to $788)** with code **DCUBE30** 16 | 17 | - KCNA + KCSA + CKA + CKAD + CKS ($788 Savings): [kube.promo/kubestronaut](https://kube.promo/kubestronaut) 18 | - CKA + CKAD + CKS Exam bundle ($528 Savings): [kube.promo/k8s-bundle](https://kube.promo/k8s-bundle) 19 | - CKA + CKS Bundle ($355 Savings) [kube.promo/bundle](https://kube.promo/bundle) 20 | - KCNA + CKA ( $288 Savings) [kube.promo/kcka-bundle](https://kube.promo/kcna-cka) 21 | - KCSA + CKS Exam Bundle ($229 Savings) [kube.promo/kcsa-cks](https://kube.promo/kcsa-cks) 22 | - KCNA + KCSA Exam Bundle ($203 Savings) [kube.promo/kcna-kcsa](https://kube.promo/kcna-kcsa) 23 | 24 | ## Real-World DevOps Projects 25 | 26 | 1. [Jenkins HA Setup On AWS](https://github.com/techiescamp/devops-projects/tree/main/01-jenkins-setup) 27 | 2. [Implementing Service Discovery Using Consul](https://github.com/techiescamp/devops-projects/tree/main/02-consul-sevice-discovery) 28 | 3. [Deploying a Scalable Java Application on AWS](https://github.com/techiescamp/devops-projects/tree/main/03-scalable-java-app) 29 | 4. [Deploy Prometheus Observability stack using Docker Compose](https://github.com/techiescamp/devops-projects/tree/main/04-prometheus-observability-stack) 30 | 5. [Design and Automate AWS VPC Creation Using Terraform](https://github.com/techiescamp/devops-projects/tree/main/05-aws-vpc-design-and-automation) 31 | 6. [AWS Client to Site VPN Setup](https://github.com/techiescamp/devops-projects/tree/main/06-aws-client-vpn-setup) 32 | 7. [Selft Hosted Pritunl VPN Setup on AWS](https://github.com/techiescamp/devops-projects/tree/main/07-pritunl-vpn-setup) 33 | 34 | 35 | > All the DevOps Real World Projects ideas and planned projects are Documented in [Real World DevOps Projects](https://devopscube.com/devops-projects/) Blog 36 | 37 | ## $300 AWS Free POC Cloud Credits 38 | 39 | Utilize the $300 AWS POC credits to try the projects comfortably without any limitations. Every project is associated with an automation script to provision resources. So you can create and destroy them when not needed. 40 | 41 | Apply Here: [AWS $300 free POC creditsCloud Platform](https://pages.awscloud.com/GLOBAL_NCA_LN_ARRC-program-A300-2023.html) 42 | 43 | ## DevOps Project Videos 44 | 45 | All the project videos will be available on Youtube. Following are the published Videos 46 | 47 | 1. [Jenkins HA Setup on AWS Using Autoscaling Group Using Packer, Ansible, and Terraform](https://www.youtube.com/watch?v=GLMJhF_cZ5M) 48 | 49 | -------------------------------------------------------------------------------- /generic-infra-code/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Ansible Commands 3 | 4 | ``` 5 | ansible-playbook playbook.yml" 6 | ``` 7 | 8 | ## Terraform Commands 9 | 10 | ``` 11 | terraform plan -var="reinstance_name=aswin-test-vm" -var="instance_type=t2.micro" 12 | 13 | terraform apply -var="reinstance_name=aswin-test-vm" -var="instance_type=t2.micro" --auto-approve 14 | 15 | terraform destroy -var="reinstance_name=aswin-test-vm" -var="instance_type=t2.micro" --auto-approve 16 | 17 | ``` -------------------------------------------------------------------------------- /generic-infra-code/terraform/dev/ec2/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-west-2" 3 | } 4 | 5 | module "ec2_instance" { 6 | source = "../../modules/ec2" 7 | 8 | instance_name = "instance-name" 9 | ami_id = "ami-047fe714e6e0ac977" 10 | instance_type = "t2.small" 11 | key_name = "techiescamp" 12 | subnet_ids = ["subnet-058a7514ba8adbb07", "subnet-0dbcd1ac168414927", "subnet-032f5077729435858"] 13 | instance_count = 1 14 | } 15 | -------------------------------------------------------------------------------- /generic-infra-code/terraform/modules/ec2/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "instance-sg" { 2 | name = "instance-sg" 3 | description = "Security Group for Instance" 4 | 5 | ingress { 6 | from_port = 22 7 | to_port = 22 8 | protocol = "tcp" 9 | cidr_blocks = ["0.0.0.0/0"] 10 | } 11 | 12 | egress { 13 | from_port = 0 14 | to_port = 0 15 | protocol = "-1" 16 | cidr_blocks = ["0.0.0.0/0"] 17 | } 18 | } 19 | 20 | 21 | resource "aws_instance" "example" { 22 | count = var.instance_count 23 | 24 | ami = var.ami_id 25 | instance_type = var.instance_type 26 | key_name = var.key_name 27 | vpc_security_group_ids = [aws_security_group.instance-sg.id] 28 | 29 | tags = { 30 | Name = "${var.instance_name}-${count.index + 1}" 31 | } 32 | 33 | subnet_id = element(var.subnet_ids, count.index % length(var.subnet_ids)) 34 | } 35 | -------------------------------------------------------------------------------- /generic-infra-code/terraform/modules/ec2/variable.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-west-2" 3 | } 4 | 5 | variable "instance_name" { 6 | type = string 7 | default = "live-test-instance" 8 | } 9 | 10 | variable "ami_id" { 11 | type = string 12 | default = "ami-0735c191cf914754d" 13 | } 14 | 15 | variable "instance_type" { 16 | type = string 17 | default = "t2.small" 18 | } 19 | 20 | variable "key_name" { 21 | type = string 22 | default = "techiescamp" 23 | } 24 | 25 | variable "security_group_ids" { 26 | type = list(string) 27 | default = ["sg-01ce819e8d65269f0"] 28 | } 29 | 30 | variable "instance_count" { 31 | type = number 32 | default = 1 33 | } 34 | 35 | variable "subnet_ids" { 36 | type = list(string) 37 | default = ["subnet-058a7514ba8adbb07", "subnet-0dbcd1ac168414927", "subnet-032f5077729435858"] 38 | } -------------------------------------------------------------------------------- /platform-tools/aws-amis/ansible/grafana.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install and Configure Grafana 3 | hosts: ubuntu 4 | become: true 5 | remote_user: ubuntu 6 | 7 | tasks: 8 | - name: Install nessesary package 9 | apt: 10 | name: apt-transport-https 11 | state: present 12 | update_cache: yes 13 | 14 | - name: add grafana gpg key 15 | shell: curl https://packages.grafana.com/gpg.key | sudo apt-key add - 16 | 17 | - name: add grafana repo 18 | apt_repository: 19 | repo: deb https://packages.grafana.com/oss/deb stable main 20 | state: present 21 | filename: grafana 22 | 23 | - name: Install grafana 24 | apt: 25 | name: grafana 26 | state: present 27 | update_cache: yes 28 | 29 | - name: Enable and start grafana service 30 | service: 31 | name: grafana-server 32 | enabled: yes 33 | state: started 34 | -------------------------------------------------------------------------------- /platform-tools/aws-amis/ansible/nexus.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install and configure Nexus Repository Manager 3 3 | hosts: ubuntu 4 | become: true 5 | remote_user: ubuntu 6 | 7 | vars: 8 | nexus_version: "3.37.0-01" 9 | 10 | tasks: 11 | # Install JRE 12 | 13 | - name: Update apt cache 14 | apt: 15 | update_cache: yes 16 | 17 | - name: Install Java JDK 8 18 | apt: 19 | name: openjdk-8-jdk 20 | state: present 21 | 22 | # Download Nexus Repository Manager 3 23 | - name: Download Nexus 24 | get_url: 25 | url: "https://download.sonatype.com/nexus/3/nexus-{{ nexus_version }}-unix.tar.gz" 26 | dest: "/tmp/nexus-{{ nexus_version }}-unix.tar.gz" 27 | 28 | # Extract Nexus 29 | - name: Extract Nexus 30 | unarchive: 31 | src: "/tmp/nexus-{{ nexus_version }}-unix.tar.gz" 32 | dest: "/opt/" 33 | remote_src: yes 34 | creates: "/opt/nexus-{{ nexus_version }}/" 35 | 36 | # Create a new group 37 | - name: Create new group 38 | group: 39 | name: nexus 40 | state: present 41 | system: true 42 | 43 | # Create a new user and add to the new group 44 | - name: Create new user and add to new group 45 | user: 46 | name: nexus 47 | state: present 48 | system: true 49 | group: nexus 50 | shell: /bin/bash 51 | createhome: yes 52 | 53 | # Set the owner of the Nexus directory to the nexus user and group 54 | - name: Set ownership of Nexus directory 55 | file: 56 | path: "/opt/nexus-{{ nexus_version }}/" 57 | owner: nexus 58 | group: nexus 59 | recurse: yes 60 | 61 | - name: Set ownership of sonatype-work directory 62 | file: 63 | path: "/opt/sonatype-work/" 64 | owner: nexus 65 | group: nexus 66 | recurse: yes 67 | 68 | # Configure Nexus to run as the nexus user 69 | - name: Configure Nexus to run as nexus user 70 | lineinfile: 71 | path: "/opt/nexus-{{ nexus_version }}/bin/nexus.rc" 72 | line: 'run_as_user="nexus"' 73 | 74 | # Create a new Nexus service file 75 | - name: Create Nexus service file 76 | template: 77 | src: "nexus.service.j2" 78 | dest: "/etc/systemd/system/nexus.service" 79 | 80 | - name: Start service 81 | shell: | 82 | sudo systemctl daemon-reload 83 | sudo systemctl start nexus 84 | sudo systemctl enable nexus -------------------------------------------------------------------------------- /platform-tools/aws-amis/ansible/prometheus.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install and Configure Prometheus 3 | hosts: all 4 | become: true 5 | remote_user: ubuntu 6 | 7 | vars: 8 | 9 | directories: 10 | - "/etc/prometheus" 11 | - "/var/lib/prometheus" 12 | 13 | owner: prometheus 14 | 15 | group: prometheus 16 | 17 | source_directories: 18 | - "/tmp/prometheus-files/consoles" 19 | - "/tmp/prometheus-files/console_libraries" 20 | 21 | source_files: 22 | - "/tmp/prometheus-files/prometheus" 23 | - "/tmp/prometheus-files/promtool" 24 | 25 | paths: 26 | - "/etc/prometheus/consoles" 27 | - "/etc/prometheus/console_libraries" 28 | 29 | files: 30 | - "/usr/local/bin/prometheus" 31 | - "/usr/local/bin/promtool" 32 | - "/etc/prometheus/prometheus.yml" 33 | 34 | roles: 35 | - prometheus -------------------------------------------------------------------------------- /platform-tools/aws-amis/ansible/roles/nexus/tasks/main.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiescamp/devops-projects/4bd247b4df794262d88c9b7ee2594cffc34812fd/platform-tools/aws-amis/ansible/roles/nexus/tasks/main.yaml -------------------------------------------------------------------------------- /platform-tools/aws-amis/ansible/roles/nexus/templates/nexus.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=nexus service 3 | After=network.target 4 | 5 | [Service] 6 | Type=forking 7 | LimitNOFILE=65536 8 | User=nexus 9 | Group=nexus 10 | ExecStart=/opt/nexus-{{ nexus_version }}/bin/nexus start 11 | ExecStop=/opt/nexus-{{ nexus_version }}/bin/nexus stop 12 | WorkingDirectory=/opt/nexus-{{ nexus_version }} 13 | Restart=on-abort 14 | 15 | [Install] 16 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /platform-tools/aws-amis/ansible/roles/prometheus/tasks/configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create directories 3 | file: 4 | path: "{{ item }}" 5 | state: directory 6 | with_items: "{{ directories }}" 7 | 8 | - name: Change ownership of directories 9 | file: 10 | path: "{{ item }}" 11 | owner: "{{owner}}" 12 | group: "{{group}}" 13 | recurse: yes 14 | state: directory 15 | with_items: "{{ directories }}" 16 | 17 | - name: Copy Directories 18 | copy: 19 | src: "{{ item }}" 20 | dest: "/etc/prometheus" 21 | remote_src: yes 22 | with_items: "{{ source_directories }}" 23 | 24 | - name: Copy files 25 | copy: 26 | src: "{{ item }}" 27 | dest: /usr/local/bin/ 28 | remote_src: yes 29 | with_items: "{{ source_files }}" 30 | 31 | - name: Create file 32 | file: 33 | path: /etc/prometheus/prometheus.yml 34 | state: touch 35 | 36 | - name: Add lines to file 37 | blockinfile: 38 | path: /etc/prometheus/prometheus.yml 39 | block: | 40 | global: 41 | scrape_interval: 15s 42 | evaluation_interval: 15s 43 | 44 | alerting: 45 | alertmanagers: 46 | - static_configs: 47 | - targets: 48 | 49 | scrape_configs: 50 | - job_name: 'jmx_exporter' 51 | consul_sd_configs: 52 | - server: "{{consul_server_address}}" 53 | services: ['backend'] 54 | metrics_path: '/metrics' 55 | 56 | - name: Change ownership of directories 57 | file: 58 | path: "{{ item }}" 59 | owner: "{{owner}}" 60 | group: "{{group}}" 61 | recurse: yes 62 | with_items: "{{ paths }}" 63 | 64 | - name: Change ownership of files 65 | file: 66 | path: "{{ item }}" 67 | owner: "{{owner}}" 68 | group: "{{group}}" 69 | with_items: "{{ files }}" 70 | 71 | - name: Replace file content 72 | lineinfile: 73 | dest: /etc/prometheus/prometheus.yml 74 | line: "{{ item }}" 75 | state: present 76 | loop: 77 | - "global:" 78 | - " scrape_interval: 15s" 79 | - " evaluation_interval: 15s" 80 | - "" 81 | - "alerting:" 82 | - " alertmanagers:" 83 | - " - static_configs:" 84 | - " - targets:" 85 | - "" 86 | - "scrape_configs:" 87 | - " - job_name: 'jmx_exporter'" 88 | - " consul_sd_configs:" 89 | - " - server: '35.92.72.191:8500'" 90 | - " services: ['backend']" 91 | - " metrics_path: '/metrics'" 92 | 93 | - name: Make prometheus executable 94 | become: true 95 | file: 96 | path: /usr/local/bin/prometheus 97 | mode: '+x' 98 | 99 | - name: Create Prometheus service file 100 | template: 101 | src: "prometheus.service.j2" 102 | dest: "/etc/systemd/system/prometheus.service" 103 | 104 | - name: Start service 105 | shell: | 106 | sudo systemctl daemon-reload 107 | sudo systemctl start prometheus 108 | sudo systemctl enable prometheus 109 | -------------------------------------------------------------------------------- /platform-tools/aws-amis/ansible/roles/prometheus/tasks/installation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Update and upgrade apt packages 3 | become: true 4 | apt: 5 | upgrade: yes 6 | update_cache: yes 7 | 8 | - name: Download Prometheus 9 | get_url: 10 | url: "https://github.com/prometheus/prometheus/releases/download/v2.42.0/prometheus-2.42.0.linux-amd64.tar.gz" 11 | dest: "/tmp/prometheus-2.42.0.linux-amd64.tar.gz" 12 | 13 | - name: Extract Prometheus 14 | unarchive: 15 | src: "/tmp/prometheus-2.42.0.linux-amd64.tar.gz" 16 | dest: "/tmp/" 17 | remote_src: yes 18 | 19 | - name: copy directory 20 | command: cp -r /tmp/prometheus-2.42.0.linux-amd64 /tmp/prometheus-files 21 | 22 | - name: Create new group 23 | group: 24 | name: "{{group}}" 25 | state: present 26 | system: true 27 | 28 | - name: Create new user and add to new group 29 | user: 30 | name: "{{owner}}" 31 | state: present 32 | system: true 33 | group: "{{group}}" 34 | shell: /bin/bash 35 | createhome: yes -------------------------------------------------------------------------------- /platform-tools/aws-amis/ansible/roles/prometheus/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include_tasks: installation.yml 3 | - include_tasks: configuration.yml -------------------------------------------------------------------------------- /platform-tools/aws-amis/ansible/roles/prometheus/templates/prometheus.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Prometheus 3 | Wants=network-online.target 4 | After=network-online.target 5 | 6 | [Service] 7 | User=prometheus 8 | Group=prometheus 9 | Type=simple 10 | ExecStart=/usr/local/bin/prometheus \ 11 | --config.file /etc/prometheus/prometheus.yml \ 12 | --storage.tsdb.path /var/lib/prometheus/ \ 13 | --web.console.templates=/etc/prometheus/consoles \ 14 | --web.console.libraries=/etc/prometheus/console_libraries 15 | 16 | [Install] 17 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /platform-tools/aws-amis/grafana/grafana.pkr.hcl: -------------------------------------------------------------------------------- 1 | variable "ami_id" { 2 | type = string 3 | default = "ami-0735c191cf914754d" 4 | } 5 | 6 | locals { 7 | app_name = "grafana" 8 | } 9 | 10 | source "amazon-ebs" "grafana" { 11 | ami_name = "packer-${local.app_name}" 12 | instance_type = "t2.micro" 13 | region = "us-west-2" 14 | source_ami = "${var.ami_id}" 15 | ssh_username = "ubuntu" 16 | tags = { 17 | Env = "dev" 18 | Name = "${local.app_name}" 19 | } 20 | } 21 | 22 | build { 23 | sources = ["source.amazon-ebs.nexus"] 24 | 25 | provisioner "ansible" { 26 | playbook_file = "grafana.yml" 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /platform-tools/aws-amis/nexus/nexus.pkr.hcl: -------------------------------------------------------------------------------- 1 | variable "ami_id" { 2 | type = string 3 | default = "ami-0735c191cf914754d" 4 | } 5 | 6 | locals { 7 | app_name = "Nexus" 8 | } 9 | 10 | source "amazon-ebs" "nginx" { 11 | ami_name = "PACKER-${local.app_name}" 12 | instance_type = "t2.micro" 13 | region = "us-west-2" 14 | source_ami = "${var.ami_id}" 15 | ssh_username = "ubuntu" 16 | tags = { 17 | Env = "DEMO" 18 | Name = "${local.app_name}" 19 | } 20 | } 21 | 22 | build { 23 | sources = ["source.amazon-ebs.nginx"] 24 | 25 | provisioner "ansible" { 26 | playbook_file = "../ansible/nexus.yml" 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /platform-tools/aws-amis/prometheus/vm.pkr.hcl: -------------------------------------------------------------------------------- 1 | variable "ami_id" { 2 | type = string 3 | default = "ami-0735c191cf914754d" 4 | } 5 | 6 | locals { 7 | app_name = "Prometheus" 8 | } 9 | 10 | source "amazon-ebs" "prometheus" { 11 | ami_name = "packer-${local.app_name}" 12 | instance_type = "t2.micro" 13 | region = "us-west-2" 14 | source_ami = "${var.ami_id}" 15 | ssh_username = "ubuntu" 16 | tags = { 17 | Env = "DEMO" 18 | Name = "${local.app_name}" 19 | } 20 | } 21 | 22 | build { 23 | sources = ["source.amazon-ebs.prometheus"] 24 | 25 | provisioner "ansible" { 26 | playbook_file = "../ansible/prometheus.yml" 27 | extra_vars = { 28 | consul_server_address = var.consul.server.ip 29 | } 30 | } 31 | 32 | } 33 | --------------------------------------------------------------------------------