From 18430ae27973902b1d518f34b4fcd3fa2f72bd7a Mon Sep 17 00:00:00 2001 From: Parth909 Date: Fri, 21 Oct 2022 16:20:38 +0530 Subject: [PATCH] add example for aws manual database creation along with backup --- aws/aws_ec2_db_backup/README.md | 22 ++ .../example_install_postgres.sh | 43 ++++ aws/aws_ec2_db_backup/main.tf | 194 ++++++++++++++++++ aws/aws_ec2_db_backup/variables.tf | 51 +++++ 4 files changed, 310 insertions(+) create mode 100644 aws/aws_ec2_db_backup/README.md create mode 100644 aws/aws_ec2_db_backup/example_install_postgres.sh create mode 100644 aws/aws_ec2_db_backup/main.tf create mode 100644 aws/aws_ec2_db_backup/variables.tf diff --git a/aws/aws_ec2_db_backup/README.md b/aws/aws_ec2_db_backup/README.md new file mode 100644 index 0000000..a52648d --- /dev/null +++ b/aws/aws_ec2_db_backup/README.md @@ -0,0 +1,22 @@ +# aws_ec2_pg_database + +**Pre-requisites :-** + +1. The database should be created on ec2 instance and all the configured things have been done properly without using RDS. +2. Create an image from the database named **`any_name_of_your_choice`**. Note that this same name should be further used as a variable as well. + +**Goal :-** + +This module helps in taking with automated backup of the database on destroying so that when it is spun up again with the latest image can be obtained and the database can be initialized from that checkpoint onwards helping in preventing data loss & many redundant copies. + +**Main features :-** + +- Automated backups on destroy. +- Automated backups at regular interval. +- Automatic database creation from checkpoint. + +**Resources used :-** + +- EBS Snapshot +- AWS AMI +- AWS IAM ROLE diff --git a/aws/aws_ec2_db_backup/example_install_postgres.sh b/aws/aws_ec2_db_backup/example_install_postgres.sh new file mode 100644 index 0000000..212f1b7 --- /dev/null +++ b/aws/aws_ec2_db_backup/example_install_postgres.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +check_exec(){ + if [ "$?" -ne 0 ] + then + echo $1 + exit 1 + fi +} + +sudo apt update +sudo apt install curl gpg gnupg2 software-properties-common apt-transport-https lsb-release ca-certificates curl -y + +check_exec "===> Failed to update and install libraries" + +curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg + +check_exec "===> Failed obtain the key" + +echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list + +check_exec "===> Failed to add the key" + +sudo apt update + +sudo apt install postgresql-13 postgresql-client-13 -y + +check_exec "===> Postgresql-13 cannot be installed" + +echo -n "===> Do you want to start Postgres Database now ? (y|n) " +read input + +# converting to lowercase & comparing +if [ "${input,,}" = "y" -o "${input,,}" = "yes" ] +then + echo "===> Starting Postgres ........" + sudo systemctl start postgresql + check_exec "===> Postgres could not be started" +fi + +echo "===> Script ran successfully" + +exit 0 \ No newline at end of file diff --git a/aws/aws_ec2_db_backup/main.tf b/aws/aws_ec2_db_backup/main.tf new file mode 100644 index 0000000..e0020e1 --- /dev/null +++ b/aws/aws_ec2_db_backup/main.tf @@ -0,0 +1,194 @@ +// Creating the database + +resource "aws_security_group" "sg_db_primary" { + name = var.sg_db_primary_data.name + description = var.sg_db_primary_data.description + vpc_id = var.sg_db_primary_data.vpc_id + + # ingress is an object. + dynamic "ingress" { + for_each = var.sg_db_primary_data.ingress_rules + + content { + # An item consists of "KEY" & "VALUE" + # KEY is the MAP KEY or LIST ELEMENT INDEX for the current element + description = ingress.value.description + from_port = ingress.value.from_port + to_port = ingress.value.to_port + protocol = ingress.value.protocol + cidr_blocks = ingress.value.cidr_blocks + ipv6_cidr_blocks = ingress.value.ipv6_cidr_blocks + security_groups = ingress.value.security_groups + } + } + + dynamic "egress" { + for_each = var.sg_db_primary_data.egress_rules + + content { + description = egress.value.description + from_port = egress.value.from_port + to_port = egress.value.to_port + protocol = egress.value.protocol + cidr_blocks = egress.value.cidr_blocks + ipv6_cidr_blocks = egress.value.ipv6_cidr_blocks + security_groups = egress.value.security_groups + } + } + + tags = { + "Name" = "${var.sg_db_primary_data.name}" + } +} + +// Getting the latest snapshot +data "aws_ebs_snapshot" "xvda_snapshot" { + most_recent = true + + filter { + name = "tag:Name" + values = ["${var.cp_db_snapshot_data.tag_name}"] + } +} + +// Creating AWS AMI from the snapshot. Changes to +resource "aws_ami" "cp_db_ami" { + name = "cp_db_ami" + virtualization_type = "hvm" + root_device_name = "/dev/xvda" + + ebs_block_device { + device_name = "/dev/xvda" + snapshot_id = data.aws_ebs_snapshot.xvda_snapshot.id + volume_size = var.cp_db_ami_data.volume_size + volume_type = var.cp_db_ami_data.volume_type + } + + tags = { + Name = "cp_db_ami" + } +} + +// Creating an instance from the image +resource "aws_instance" "cp_db_primary" { + ami = aws_ami.cp_db_ami.id + instance_type = var.cp_db_primary_instance_data.instance_type + key_name = var.cp_db_primary_instance_data.key_name + + subnet_id = var.cp_db_primary_instance_data.subnet_id + vpc_security_group_ids = [aws_security_group.sg_db_primary.id] + + tags = { + Name = var.cp_db_primary_instance_data.name + } + + // Create snapshot of data volume before destroying + provisioner "local-exec" { + on_failure = fail + when = destroy + # attachment.device value "/dev/xvda" should be the same as the variable + # Tag "cp-db-snapshot" should be the same as the variable + command = "aws ec2 create-snapshot --description xvda-data-snapshot --volume-id $(aws ec2 describe-volumes --filters Name=attachment.instance-id,Values=${self.id} Name=attachment.device,Values=/dev/xvda --query 'Volumes[*].{ID:VolumeId}' --output text) --tag-specifications 'ResourceType=snapshot,Tags=[{Key=Name,Value=cp-db-snapshot},{Key=created-when,Value=on-destroy}]'" + } +} + +resource "aws_iam_role" "dlm_lifecycle_role" { + name = "dlm-lifecycle-role" + + assume_role_policy = < IST 00:00 AM + times = ["18:30"] + } + + retain_rule { + count = 14 + } + + tags_to_add = { + Name = "${var.cp_db_snapshot_data.tag_name}" + created-when = "daily-backup" + } + + copy_tags = false + } + + target_tags = { + Name = "${var.cp_db_snapshot_data.tag_name}" + } + } + + tags = { + Name = "cp_db_dlm_policy" + } +} + diff --git a/aws/aws_ec2_db_backup/variables.tf b/aws/aws_ec2_db_backup/variables.tf new file mode 100644 index 0000000..50213c1 --- /dev/null +++ b/aws/aws_ec2_db_backup/variables.tf @@ -0,0 +1,51 @@ +variable "sg_db_primary_data" { + type = object({ + name = string + description = string + vpc_id = string + ingress_rules = list(object({ + description = string + from_port = number + to_port = number + protocol = string + cidr_blocks = list(string) + ipv6_cidr_blocks = list(string) + security_groups = list(string) + })) + egress_rules = list(object({ + description = string + from_port = number + to_port = number + protocol = string + cidr_blocks = list(string) + ipv6_cidr_blocks = list(string) + security_groups = list(string) + })) + }) + description = "Security group data for Database EC2 Instance" +} + +variable "cp_db_snapshot_data" { + description = "This is the description that will be used to identify the snapshots of our data volume. We will filter against this value." + type = object({ + tag_name = string + }) +} + +variable "cp_db_ami_data" { + description = "The cp database ami data" + type = object({ + volume_size = number + volume_type = string + }) +} + +variable "cp_db_primary_instance_data" { + description = "Data for the primary database" + type = object({ + name = string + instance_type = string + key_name = string + subnet_id = string + }) +}