├── .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 | 
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 | 
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 | IP Address |
24 | {{ ansible_default_ipv4.address }} |
25 |
26 |
27 | Operating System |
28 | {{ ansible_os_family }} |
29 |
30 |
31 | System Version |
32 | {{ ansible_distribution_version }} |
33 |
34 |
35 | Memory |
36 | {{ ansible_memtotal_mb }} MB |
37 |
38 |
39 | CPU |
40 | {{ ansible_processor_vcpus }} vCPUs |
41 |
42 |
43 |
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 | 
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 | IP Address |
24 | {{ ansible_default_ipv4.address }} |
25 |
26 |
27 | Operating System |
28 | {{ ansible_os_family }} |
29 |
30 |
31 | System Version |
32 | {{ ansible_distribution_version }} |
33 |
34 |
35 | Memory |
36 | {{ ansible_memtotal_mb }} MB |
37 |
38 |
39 | CPU |
40 | {{ ansible_processor_vcpus }} vCPUs |
41 |
42 |
43 |
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 | 
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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------