├── .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
│ │ │ └── index.html.j2
│ │ └── vars
│ │ │ └── main.yaml
│ │ ├── consul
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ ├── templates
│ │ │ └── config.json.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
│ ├── ami.yml
│ ├── ansible.cfg
│ ├── files
│ │ ├── application.properties
│ │ ├── properties.py
│ │ └── start.sh
│ ├── inventory.ini
│ ├── roles
│ │ └── java
│ │ │ └── tasks
│ │ │ ├── app.yaml
│ │ │ ├── cloudwatch.yml
│ │ │ ├── java.yml
│ │ │ ├── main.yml
│ │ │ ├── node_exporter.yml
│ │ │ └── python.yml
│ ├── templates
│ │ ├── config.json.j2
│ │ └── node_exporter.service.j2
│ └── vm.pkr.hcl
└── terraform
│ ├── lb-asg
│ └── main.tf
│ ├── modules
│ ├── lb-asg
│ │ ├── main.tf
│ │ ├── scripts
│ │ │ └── user_data.sh
│ │ └── variable.tf
│ └── rds
│ │ ├── main.tf
│ │ └── variables.tf
│ └── rds
│ ├── main.tf
│ └── variables.tf
├── README.md
├── dev-vms
└── ubuntu-22
│ └── Vagrantfile
└── generic-scripts
├── README.md
└── terraform
└── ec2
└── instance.tf
/.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
49 | *.tfvars.json
50 |
51 | # Ignore override files as they are usually used to override resources locally and so
52 | # are not checked in
53 | override.tf
54 | override.tf.json
55 | *_override.tf
56 | *_override.tf.json
57 |
58 | # Include override files you do wish to add to version control using negated pattern
59 | # !example_override.tf
60 |
61 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
62 | # example: *tfplan*
63 |
64 | # Ignore CLI configuration files
65 | .terraformrc
66 | terraform.rc
--------------------------------------------------------------------------------
/01-jenkins-setup/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Setup Architecture
3 |
4 |
5 |
6 |
7 |
8 |
9 | ## Setup Workflow
10 |
11 | EFS is setup in us-west-2a
12 | Jenkins should be launchd in us-west-2a to access EFS
13 |
14 | ## Packer
15 |
16 | Get AMI ID
17 |
18 | ```
19 |
20 | #!/bin/bash
21 |
22 | AMI_ID=$(jq -r '.builds[-1].artifact_id' manifest.json | cut -d ":" -f2)
23 | echo $AMI_ID
24 | ```
25 |
26 |
--------------------------------------------------------------------------------
/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.387.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 | remote_src: yes
7 | register: secret_value
8 |
9 | - name: Print registered variable
10 | debug:
11 | var: secret_value
12 |
13 | - name: Add public key to authorized_keys for ubuntu user
14 | authorized_key:
15 | user: ubuntu
16 | state: present
17 | 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 pip3
13 | become: true
14 | pip:
15 | name: boto3
16 | state: present
17 |
18 | - name: Install AWS CLI using pip
19 | become: true
20 | pip:
21 | name: awscli
22 | state: latest
23 | executable: pip3
24 |
25 | - name: Install Ansible
26 | pip:
27 | name: ansible
28 | state: latest
29 |
30 | - name: Add HashiCorp GPG key
31 | become: yes
32 | shell: "wget -qO- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg"
33 |
34 | - name: Add HashiCorp APT repository
35 | become: yes
36 | 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"
37 |
38 | - name: Update apt cache
39 | become: yes
40 | become_method: sudo
41 | apt:
42 | update_cache: yes
43 |
44 | - name: Install Terraform
45 | apt:
46 | name: terraform
47 | state: present
48 |
49 | - name: Install Packer
50 | apt:
51 | name: packer
52 | state: present
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/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 pip3
17 | become: true
18 | pip:
19 | name: boto3
20 | state: present
21 |
22 | - name: Install AWS CLI using pip
23 | become: true
24 | pip:
25 | name: awscli
26 | state: latest
27 | executable: pip3
28 |
29 | - name: Install Java JDK 17
30 | apt:
31 | name: openjdk-17-jdk
32 | state: present
33 |
--------------------------------------------------------------------------------
/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 key
3 | apt_key:
4 | url: https://pkg.jenkins.io/debian-stable/jenkins.io.key
5 |
6 | - name: Add Jenkins APT repository
7 | apt_repository:
8 | repo: deb https://pkg.jenkins.io/debian-stable binary/
9 | state: present
10 |
11 | - name: Install Jenkins
12 | apt:
13 | name: jenkins={{ jenkins_lts_version }}
14 | state: present
15 |
16 | - name: Stop Jenkins service
17 | systemd:
18 | name: jenkins.service
19 | state: stopped
20 |
21 | - name: Move Jenkins data to new directory
22 | copy: src=/var/lib/jenkins/ dest={{ jenkins_data_dir }} remote_src=yes directory_mode=yes
23 |
24 | - name: Change directory owner
25 | file:
26 | path: "{{ jenkins_data_dir }}"
27 | owner: jenkins
28 | group: jenkins
29 | recurse: yes
30 |
31 | - name: Remove old Jenkins data directory
32 | file:
33 | path: /var/lib/jenkins/
34 | state: absent
35 |
36 | - name: Create override directory for Jenkins service
37 | become: true
38 | file:
39 | path: /etc/systemd/system/jenkins.service.d
40 | state: directory
41 |
42 | - name: Add override file for Jenkins
43 | template:
44 | src: override.conf.j2
45 | dest: /etc/systemd/system/jenkins.service.d/override.conf
46 | owner: root
47 | group: root
48 | mode: '0644'
49 |
50 | - name: Reload systemd daemon configuration
51 | systemd:
52 | daemon_reload: yes
53 |
54 | - name: Start Jnekins Service
55 | systemd:
56 | name: jenkins
57 | state: started
58 |
59 |
--------------------------------------------------------------------------------
/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-west-2')
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-0735c191cf914754d"
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-west-2"
19 | availability_zone = "us-west-2a"
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}" ]
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-0735c191cf914754d"
4 | }
5 |
6 | variable "efs_mount_point" {
7 | type = string
8 | default = ""
9 | }
10 |
11 | locals {
12 | app_name = "jenkins-controller"
13 | }
14 |
15 | source "amazon-ebs" "jenkins" {
16 | ami_name = "${local.app_name}"
17 | instance_type = "t2.micro"
18 | region = "us-west-2"
19 | availability_zone = "us-west-2a"
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}" ]
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-west-2"
3 | }
4 |
5 | module "ec2_instance" {
6 | source = "../modules/ec2"
7 |
8 | instance_name = "jenkins-agent"
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 |
--------------------------------------------------------------------------------
/01-jenkins-setup/terraform/efs/main.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = "us-west-2"
3 | }
4 |
5 | module "efs_module" {
6 | source = "../modules/efs"
7 | vpc_id = "vpc-0a5ca4a92c2e10163"
8 | subnet_ids = ["subnet-058a7514ba8adbb07", "subnet-0dbcd1ac168414927", "subnet-032f5077729435858"]
9 | }
--------------------------------------------------------------------------------
/01-jenkins-setup/terraform/iam/main.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = "us-west-2"
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-west-2"
3 | }
4 |
5 | module "lb-asg" {
6 | source = "../modules/lb-asg"
7 | subnets = ["subnet-058a7514ba8adbb07", "subnet-0dbcd1ac168414927", "subnet-032f5077729435858"]
8 | ami_id = "ami-0f7cbb73797d9f23d"
9 | instance_type ="t2.small"
10 | key_name = "techiescamp"
11 | environment = "dev"
12 | vpc_id = "vpc-0a5ca4a92c2e10163"
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-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 | }
--------------------------------------------------------------------------------
/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 | lifecycle {
113 | create_before_destroy = true
114 | }
115 | }
116 |
117 | resource "aws_autoscaling_group" "jenkins" {
118 | name = "jenkins-controller-asg"
119 | max_size = 1
120 | min_size = 1
121 | desired_capacity = 1
122 | vpc_zone_identifier = var.subnets
123 | launch_template {
124 | id = aws_launch_template.jenkins.id
125 | version = "$Latest"
126 | }
127 |
128 | tag {
129 | key = "Name"
130 | value = "jenkins-controller"
131 | propagate_at_launch = true
132 | }
133 |
134 | lifecycle {
135 | create_before_destroy = true
136 | }
137 | }
138 |
139 |
140 | resource "aws_autoscaling_attachment" "jenkins" {
141 | autoscaling_group_name = aws_autoscaling_group.jenkins.name
142 | lb_target_group_arn = aws_lb_target_group.jenkins.arn
143 | }
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/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/AWS-Devops-Projects/devops-projects/6fb5ede7e776fb4401be2dd01cf4f4078a98f8cc/02-consul-sevice-discovery/ansible/configs/ansible.cfg
--------------------------------------------------------------------------------
/02-consul-sevice-discovery/ansible/configs/inventory.ini:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWS-Devops-Projects/devops-projects/6fb5ede7e776fb4401be2dd01cf4f4078a98f8cc/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 and upgrade apt packages
3 | become: true
4 | apt:
5 | upgrade: yes
6 | update_cache: yes
7 |
8 | - name: Install Consul Server
9 | apt:
10 | name: consul
11 | state: latest
12 |
13 | - name: Render Consul Configuration Template
14 | template:
15 | src: config.json.j2
16 | dest: /etc/consul.d/config.json
17 | vars:
18 | server: "false"
19 | datacenter: "dc1"
20 |
21 | - name: Render Consul Backend Template
22 | template:
23 | src: backend.json.j2
24 | dest: /etc/consul.d/backend.json
25 |
26 | - name: Start Consul Agent Template
27 | shell: sudo consul agent -config-dir /etc/consul.d/ &
28 | register: consul_start
29 | ignore_errors: true
30 |
31 |
32 |
--------------------------------------------------------------------------------
/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/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/AWS-Devops-Projects/devops-projects/6fb5ede7e776fb4401be2dd01cf4f4078a98f8cc/02-consul-sevice-discovery/ansible/roles/backends/vars/main.yaml
--------------------------------------------------------------------------------
/02-consul-sevice-discovery/ansible/roles/consul/tasks/main.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Update and upgrade apt packages
3 | become: true
4 | apt:
5 | upgrade: yes
6 | update_cache: yes
7 |
8 | - name: Install Consul Server
9 | apt:
10 | name: consul
11 | state: latest
12 |
13 | - name: Render Consul Configuration Template
14 | template:
15 | src: config.json.j2
16 | dest: /etc/consul.d/consul.json
17 | vars:
18 | bind_addr: 0.0.0.0
19 | client_addr: 0.0.0.0
20 | data_dir: /var/consul
21 | encrypt: "ZENZNrsXU336Uma+S4XUj9sxvICj32N7XdEzrbYbRpY="
22 | datacenter: dc1
23 | ui: "true"
24 | leave_on_terminate: "true"
25 | server: "true"
26 | log_level: INFO
27 |
28 | # register is a keyword that allows you to capture the output of a task and store it in a variable for later use.
29 |
30 | - name: Start Consul Server
31 | shell: consul agent -dev -config-dir /etc/consul.d/ &
32 | register: consul_start
33 | ignore_errors: true
34 |
35 | # .rc attribute in register variable is used to access the exit code
36 |
37 | - name: Check if Consul agent started
38 | shell: ps -ef | grep consul | grep -v grep
39 | register: consul_check
40 | ignore_errors: true
41 | when: consul_start.rc == 0
42 |
43 | - name: Fail if Consul agent not started
44 | fail:
45 | msg: "Consul agent failed to start in the background"
46 | when: consul_check.rc != 0
47 |
--------------------------------------------------------------------------------
/02-consul-sevice-discovery/ansible/roles/consul/templates/config.json.j2:
--------------------------------------------------------------------------------
1 | {
2 | "bind_addr": "{{ bind_addr }}",
3 | "client_addr": "{{ client_addr }}",
4 | "data_dir": "{{ data_dir }}",
5 | "encrypt": "{{ encrypt }}",
6 | "datacenter": "{{ datacenter }}",
7 | "ui": {{ ui }},
8 | "leave_on_terminate": {{ leave_on_terminate }},
9 | "server": {{ server }},
10 | "log_level": "{{ log_level }}"
11 | }
12 |
--------------------------------------------------------------------------------
/02-consul-sevice-discovery/ansible/roles/consul/vars/main.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWS-Devops-Projects/devops-projects/6fb5ede7e776fb4401be2dd01cf4f4078a98f8cc/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/AWS-Devops-Projects/devops-projects/6fb5ede7e776fb4401be2dd01cf4f4078a98f8cc/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/AWS-Devops-Projects/devops-projects/6fb5ede7e776fb4401be2dd01cf4f4078a98f8cc/03-scalable-java-app/Jenkinsfile
--------------------------------------------------------------------------------
/03-scalable-java-app/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Project Architecture
3 |
4 | 
5 |
6 |
7 | # Java Application
8 |
9 | For this project you can use the open source pet clinic application (Java Spring Boot)
10 |
11 | ```
12 | https://github.com/spring-projects/spring-petclinic
13 | ```
14 |
15 | # Tools/Services
16 |
17 | - DevOps Tools
18 | - Jenkins
19 | - Packer
20 | - Ansible
21 | - Terraform
22 |
23 | - AWS Services
24 | - Application Load Balancer (L7)
25 | - Autoscaling Group
26 | - AWS secrets manager
27 | - RDS (MySQL)
28 |
29 | # Project Workflow
30 |
31 | - Build Java application
32 | - Use Packer & Ansible to build the AMI With application code
33 | - configure application logging
34 | - configure cloudwatch agent with the application log location.
35 | - Use Teraaform to provision the following
36 | - MySQL RDS instance and store the username and password in AWS secrets manager
37 | - Provision Application Load Blancer
38 | - Create a launch template With the Application AMI
39 | - Provision Autoscaling Group with Launch tempalate that use AMI built by packer and attach it to Loadbalancer.
40 | - Verify application by accessing it using Load Balancer endpoint.
41 | - Verify application logs in Cloudwatch
42 |
43 | ## Java Application
44 |
45 | Spring boot Petclinic application
46 |
47 | ```
48 | git clone https://github.com/techiescamp/java-spring-petclinic
49 | ```
50 |
51 | Starting the application with externalized properties file.
52 |
53 | ```
54 | java -jar spring-petclinic.jar --spring.config.location=/path/to/application.properties --spring.profiles.active=mysql
55 | ```
56 |
57 | Log Location
58 |
59 | ```
60 | /opt/petclinic.log
61 | ```
62 |
63 | Change folder persmissions
64 |
65 | ```
66 | sudo chown -R petclinic:petclinic /opt
67 | sudo chmod -R u+w /opt
68 | ```
69 |
70 | ## Useful Resources
71 |
72 | 1. [RDS password Rotation With Terraform](https://advancedweb.hu/how-to-set-up-amazon-rds-password-rotation-with-terraform/)
73 |
74 |
75 |
--------------------------------------------------------------------------------
/03-scalable-java-app/ansible/ami.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 | - application.properties
12 | - properties.py
13 | - script.sh
14 |
15 | roles:
16 | - java
--------------------------------------------------------------------------------
/03-scalable-java-app/ansible/ansible.cfg:
--------------------------------------------------------------------------------
1 | [defaults]
2 | inventory = /vagrant/devops-projects/03-scalable-java-app/ansible/inventory.ini
3 | host_key_checking = false
4 | stdout_callback = yaml
5 | callback_enabled = timer
6 |
--------------------------------------------------------------------------------
/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://loacalhost: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 = "rds!db-8f23e7a9-e9f8-4b50-a059-f0e310e18134"
7 | file_path = "/home/ubuntu/application.properties"
8 |
9 | ssm = boto3.client('ssm', region_name=region)
10 |
11 | redis_endpoint = ssm.get_parameter(Name=parameter_store)['Parameter']['Value']
12 |
13 | secrets_client = boto3.client('secretsmanager')
14 |
15 | response = secrets_client.get_secret_value(SecretId=secret_name)
16 |
17 | secret_value = response['SecretString']
18 |
19 | database_details = json.loads(secret_value)
20 |
21 | with open(file_path, 'r') as f:
22 | file_contents = f.read()
23 |
24 | file_contents = file_contents.replace("spring.datasource.url=jdbc:mysql://localhost:3306/petclinic", f"spring.datasource.url={redis_endpoint}")
25 | file_contents = file_contents.replace("spring.datasource.username=petclinic", f"spring.datasource.username={database_details['username']}")
26 | file_contents = file_contents.replace("spring.datasource.password=petclinic", f"spring.datasource.password={database_details['password']}")
27 |
28 | with open(file_path, 'w') as f:
29 | f.write(file_contents)
30 |
--------------------------------------------------------------------------------
/03-scalable-java-app/ansible/files/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | JAR_FILE=/home/ubuntu/spring-petclinic.jar
4 | APP_PROPERTIES=/home/ubuntu/application.properties
5 | PROPERTIES_SCRIPT=/home/ubuntu/properties.py
6 |
7 | python3 ${PROPERTIES_SCRIPT}
8 |
9 | sudo java -jar ${JAR_FILE} --spring.config.location= ${APP_PROPERTIES} --spring.profiles.active=mysql &
--------------------------------------------------------------------------------
/03-scalable-java-app/ansible/inventory.ini:
--------------------------------------------------------------------------------
1 |
2 | [all:vars]
3 | ansible_user=ubuntu
4 | ansible_private_key_file=/home/vagrant/.ssh/aswin-key.pem
--------------------------------------------------------------------------------
/03-scalable-java-app/ansible/roles/java/tasks/app.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Copy files
3 | copy:
4 | src: "{{ source_dir }}/{{ item }}"
5 | dest: "{{ dest_dir }}/{{ item }}"
6 | with_items: "{{ files }}"
7 |
8 | - name: Make start.sh script executable
9 | become: true
10 | file:
11 | path: /home/ubuntu/start.sh
12 | mode: '+x'
--------------------------------------------------------------------------------
/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: Make start.sh script executable
15 | become: true
16 | file:
17 | path: /home/ubuntu/start.sh
18 | mode: '+x'
--------------------------------------------------------------------------------
/03-scalable-java-app/ansible/roles/java/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - include_tasks: java.yml
3 | - include_tasks: python.yml
4 | - include_tasks: cloudwatch.yml
5 | - include_tasks: node_exporter.yml
6 | - include_tasks: app.yaml
7 |
8 |
--------------------------------------------------------------------------------
/03-scalable-java-app/ansible/roles/java/tasks/node_exporter.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Download node_exporter
3 | get_url:
4 | url: "https://github.com/prometheus/node_exporter/releases/download/v1.5.0/node_exporter-1.5.0.linux-amd64.tar.gz"
5 | dest: "/tmp/node_exporter-1.5.0.linux-amd64.tar.gz"
6 |
7 | - name: Extract node_exporter
8 | unarchive:
9 | src: "/tmp/node_exporter-1.5.0.linux-amd64.tar.gz"
10 | dest: "/tmp/"
11 | remote_src: yes
12 |
13 | - name: Move file
14 | command:
15 | cmd: mv /tmp/node_exporter-1.5.0.linux-amd64/node_exporter /usr/local/bin
16 |
17 | - name: Create new group
18 | group:
19 | name: node_exporter
20 | state: present
21 | system: true
22 |
23 | - name: Create new user and add to new group
24 | user:
25 | name: node_exporter
26 | state: present
27 | system: true
28 | group: node_exporter
29 | shell: /bin/bash
30 | createhome: yes
31 |
32 | - name: Create node_exporter service file
33 | template:
34 | src: "node_exporter.service.j2"
35 | dest: "/etc/systemd/system/node_exporter.service"
36 |
37 | - name: Start service
38 | shell: |
39 | sudo systemctl daemon-reload
40 | sudo systemctl start node_exporter
41 | sudo systemctl enable node_exporter
42 |
--------------------------------------------------------------------------------
/03-scalable-java-app/ansible/roles/java/tasks/python.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Install Python3
3 | become: true
4 | apt:
5 | name: python3
6 | state: present
7 |
8 | - name: Install pip3
9 | become: true
10 | apt:
11 | name: python3-pip
12 | state: present
13 |
14 | - name: Install boto3 using pip3
15 | become: true
16 | pip:
17 | name: boto3
18 | state: present
19 |
20 | - name: Install AWS CLI using pip
21 | become: true
22 | pip:
23 | name: awscli
24 | state: latest
25 | executable: pip3
--------------------------------------------------------------------------------
/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/node_exporter.service.j2:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Node Exporter
3 | After=network.target
4 |
5 | [Service]
6 | User=node_exporter
7 | Group=node_exporter
8 | Type=simple
9 | ExecStart=/usr/local/bin/node_exporter
10 |
11 | [Install]
12 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/03-scalable-java-app/ansible/vm.pkr.hcl:
--------------------------------------------------------------------------------
1 | variable "ami_id" {
2 | type = string
3 | default = "ami-0735c191cf914754d"
4 | }
5 |
6 | locals {
7 | app_name = "pet-clinic"
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 = "PACKER-${local.app_name}"
19 | }
20 | }
21 |
22 | build {
23 | sources = ["source.amazon-ebs.nginx"]
24 |
25 | provisioner "file" {
26 | source = "${WORKSPACE}/target/spring-petclinic.jar"
27 | destination = "/home/ubuntu/spring-petclinic.jar"
28 | }
29 |
30 | provisioner "ansible" {
31 | playbook_file = "ami.yml"
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/03-scalable-java-app/terraform/lb-asg/main.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = "us-west-2"
3 | }
4 |
5 | module "lb-asg" {
6 | source = "../modules/lb-asg"
7 | subnets = ["subnet-058a7514ba8adbb07", "subnet-04b1f595ef8c29542", "subnet-0dbcd1ac168414927"]
8 | ami_id = "ami-1234567890abcdef"
9 | instance_type ="t2.small"
10 | key_name = "techiescamp"
11 | environment = "dev"
12 | vpc_id = "vpc-0a5ca4a92c2e10163"
13 | }
--------------------------------------------------------------------------------
/03-scalable-java-app/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 = "petclinic-alb-sg"
20 | }
21 | }
22 |
23 | resource "aws_lb" "petclinic" {
24 | name = "petclinic-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 | enable_deletion_protection = true
37 | }
38 |
39 | resource "aws_security_group" "instance_sg" {
40 | name_prefix = "instance-sg"
41 |
42 | ingress {
43 | from_port = 22
44 | to_port = 22
45 | protocol = "tcp"
46 | cidr_blocks = ["0.0.0.0/0"]
47 | }
48 |
49 | ingress {
50 | from_port = 8080
51 | to_port = 8080
52 | protocol = "tcp"
53 | security_groups = [aws_security_group.alb_sg.id]
54 | }
55 |
56 | egress {
57 | from_port = 0
58 | to_port = 0
59 | protocol = "-1"
60 | cidr_blocks = ["0.0.0.0/0"]
61 | }
62 |
63 | tags = {
64 | Name = "petclinic-instance-sg"
65 | }
66 | }
67 |
68 |
69 | resource "aws_lb_target_group" "petclinic" {
70 | name_prefix = "pc-lb"
71 | port = 8080
72 | protocol = "HTTP"
73 | vpc_id = var.vpc_id
74 | target_type = "instance"
75 |
76 | health_check {
77 | path = "/health"
78 | port = 8080
79 | protocol = "HTTP"
80 | interval = 30
81 | timeout = 5
82 | healthy_threshold = 2
83 | unhealthy_threshold = 2
84 | }
85 |
86 | tags = {
87 | Environment = var.environment
88 | Terraform = "true"
89 | }
90 | }
91 |
92 | resource "aws_autoscaling_group" "petclinic" {
93 | name = "petclinic-asg"
94 | max_size = 3
95 | min_size = 1
96 | desired_capacity = 2
97 | vpc_zone_identifier = var.subnets
98 | launch_configuration = aws_launch_configuration.petclinic.id
99 |
100 | tag {
101 | key = "Name"
102 | value = "petclinic-app"
103 | propagate_at_launch = true
104 | }
105 |
106 | lifecycle {
107 | create_before_destroy = true
108 | }
109 | }
110 |
111 | resource "aws_launch_configuration" "petclinic" {
112 | name_prefix = "petclinic-lc"
113 | image_id = var.ami_id
114 | instance_type = var.instance_type
115 | security_groups = [aws_security_group.instance_sg.id]
116 | key_name = var.key_name
117 | user_data = filebase64("${path.module}/scripts/user_data.sh")
118 |
119 | lifecycle {
120 | create_before_destroy = true
121 | }
122 | }
123 |
124 | resource "aws_autoscaling_attachment" "petclinic" {
125 | autoscaling_group_name = aws_autoscaling_group.petclinic.name
126 | alb_target_group_arn = aws_lb_target_group.petclinic.arn
127 | }
128 |
--------------------------------------------------------------------------------
/03-scalable-java-app/terraform/modules/lb-asg/scripts/user_data.sh:
--------------------------------------------------------------------------------
1 | nohup java -jar petclinic-app.jar --spring.config.location=/ubuntu/deployment/application.properties --spring.profiles.active=mysql &
--------------------------------------------------------------------------------
/03-scalable-java-app/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 |
--------------------------------------------------------------------------------
/03-scalable-java-app/terraform/modules/rds/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_secretsmanager_secret" "rds_secret" {
2 | name = "/dev/petclinic/db"
3 | }
4 |
5 | resource "random_password" "password" {
6 | length = 8
7 | special = true
8 | override_special = "_@%"
9 | }
10 |
11 | resource "aws_secretsmanager_secret_version" "rds_secret_value" {
12 | secret_id = aws_secretsmanager_secret.rds_secret.id
13 | secret_string = jsonencode({
14 | username = "petclinic",
15 | password = random_password.password.result,
16 | })
17 | }
18 |
19 | # Create a DB security group
20 | resource "aws_security_group" "rds_security_group" {
21 | name = "rds-security-group"
22 | description = "Security group for RDS instance"
23 |
24 | ingress {
25 | from_port = 3306
26 | to_port = 3306
27 | protocol = "tcp"
28 | cidr_blocks = ["0.0.0.0/0"]
29 | }
30 |
31 | egress {
32 | from_port = 0
33 | to_port = 0
34 | protocol = "-1"
35 | cidr_blocks = ["0.0.0.0/0"]
36 | }
37 | }
38 |
39 |
40 | resource "aws_db_instance" "rds_instance" {
41 | identifier = "petclinic-mysql-rds"
42 | engine = "mysql"
43 | instance_class = "db.t2.micro"
44 | allocated_storage = 10
45 | storage_type = "gp2"
46 | username = jsondecode(aws_secretsmanager_secret_version.rds_secret_value.secret_string)["username"]
47 | password = jsondecode(aws_secretsmanager_secret_version.rds_secret_value.secret_string)["password"]
48 | db_subnet_group_name = "default"
49 | vpc_security_group_ids = [aws_security_group.rds_security_group.id]
50 | backup_retention_period = 7
51 | delete_automated_backups = true
52 | copy_tags_to_snapshot = true
53 | publicly_accessible = true
54 | skip_final_snapshot = true
55 | apply_immediately = true
56 |
57 | tags = {
58 | Name = "petclinic-rds"
59 | }
60 |
61 | }
62 |
63 | # Data source to retrieve RDS endpoint
64 | data "aws_db_instance" "rds_instance" {
65 | db_instance_identifier = aws_db_instance.rds_instance.id
66 | }
67 |
68 |
69 | resource "aws_ssm_parameter" "rds_endpoint" {
70 | name = "/dev/petclinic/rds_endpoint"
71 | type = "String"
72 | value = data.aws_db_instance.rds_instance.endpoint
73 | }
74 |
--------------------------------------------------------------------------------
/03-scalable-java-app/terraform/modules/rds/variables.tf:
--------------------------------------------------------------------------------
1 | variable "update_rds_endpoint" {
2 | type = bool
3 | default = true
4 | }
--------------------------------------------------------------------------------
/03-scalable-java-app/terraform/rds/main.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = "us-west-2"
3 | }
4 |
5 | module "rds" {
6 | source = "../modules/rds"
7 | }
--------------------------------------------------------------------------------
/03-scalable-java-app/terraform/rds/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | default = "us-west-2"
3 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DevOps Projects
2 |
3 | DevOps Real World Projects for Aspiring DevOps Engineers [Beginner to Advanced]
4 |
5 | ## List of DevOps Project Ideas
6 |
7 | All the DevOps Real World Projects are Documented in [Real World DevOps Projects](https://devopscube.com/devops-projects/) blog
8 |
--------------------------------------------------------------------------------
/dev-vms/ubuntu-22/Vagrantfile:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWS-Devops-Projects/devops-projects/6fb5ede7e776fb4401be2dd01cf4f4078a98f8cc/dev-vms/ubuntu-22/Vagrantfile
--------------------------------------------------------------------------------
/generic-scripts/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-scripts/terraform/ec2/instance.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 |
31 | resource "aws_instance" "example" {
32 | ami = var.ami_id
33 | instance_type = var.instance_type
34 | key_name = var.key_name
35 | vpc_security_group_ids = var.security_group_ids
36 | tags = {
37 | Name = var.instance_name
38 | }
39 |
40 | subnet_id = data.aws_subnet.default.id
41 |
42 | }
43 |
44 | data "aws_subnet" "default" {
45 | vpc_id = data.aws_vpc.default.id
46 | cidr_block = "172.31.32.0/20"
47 | }
48 |
49 |
50 | data "aws_vpc" "default" {
51 | default = true
52 | }
53 |
54 |
55 |
--------------------------------------------------------------------------------