Skip to content

Commit

Permalink
feature: commit inicial
Browse files Browse the repository at this point in the history
  • Loading branch information
guillevalin committed Nov 9, 2024
1 parent 4287f0f commit 74ed2be
Show file tree
Hide file tree
Showing 8 changed files with 1,703 additions and 0 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Parte 1: Infraestructura e IaC

## Diagrama Infraestructura
- Base de Datos: Se utilizará una base de datos relacional dado que es más compatible para procesar analítica avanzada y conectarla en un futuro con alguna solución de Data Analytics como Google BigQuery, Amazon Redshift o Snowflake, que es parte del requerimiento. Dado que en este caso estamos proponiendo una arquitectura en AWS, la tecnología escogida será Aurora PostgreSQL.
- Tecnología Pub/Sub: Existen diversas tecnologías para lograr este propósito, en particular por experiencia personal he utilizado SNS/SQS, RabbitMQ y Redis, sintiendo que todas en general cumplen el propósito y la elección en particular tiene que ir por decisiones previas (si ya se cuenta con una tecnología para Pub/Sub utilizada es mejor mantenerla para evitar fragmentación de tecnologías) o features específicos de una cola de mensajería (como AMQP). Dado que estamos proponiendo una solución simple administrada por AWS, escogeremos SNS/SQS para este ejemplo.
- Endpoint HTTP para servir datos almacenados: Soy muy fanático de armar arquitecturas de microservicios basadas en contenedores orquestadas por Kubernetes, utilizando las opciones administradas en la nube como Google Cloud GKE o Amazon EKS, si bien la curva de aprendizaje no es menor, permiten mucha flexibilidad y escalabilidad, y con un buen pipeline de CI/CD se pueden abstraer lo suficiente de los desarrolladores para que solo se centren en escribir código y no preocuparse por la infraestructura. En este caso sin embargo, por simplicidad escogeremos implementar funciones AWS Lambda para lograr el propósito, dado que por ejemplo, en un contexto de piloto, puede ser muy útil levantar una prueba de concepto de bajo costo antes de hacer un deploy más altamente disponible y enterprise grade.

Finalmente, esto se ve representado en el siguiente diagrama de arquitectura de la solución:
![Diagrama](diagrama-infra.png)

## Código Terraform
DISCLAIMER: Los códigos Terraform fueron generados mediante ChatGPT.

- VPC: Este código despliega una VPC con dos subnets privadas y dos públicas, en las zonas 1A y 1B de Virginia del Norte (us-east-1).
- SNS/SQS: Se utilizará SNS/SQS de AWS como tecnología para tener una arquitectura Pub/Sub. Existen otras tecnologías como Apache Kafka, RabbitMQ o Redis
Binary file added diagrama-infra.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
94 changes: 94 additions & 0 deletions pregunta-1-infraestructura/rds.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
provider "aws" {
region = "us-east-1"
}

# Parámetros para la base de datos
variable "db_name" {
default = "airports"
}

variable "db_master_username" {
default = "admin"
}

variable "db_master_password" {
default = "latam" # Cambia a una contraseña segura
}

# Crear un clúster de base de datos RDS Aurora Serverless v2 con PostgreSQL 16.4
resource "aws_rds_cluster" "aurora_postgresql" {
cluster_identifier = "aurora-postgres-cluster"
engine = "aurora-postgresql"
engine_version = "16.4"
database_name = var.db_name
master_username = var.db_master_username
master_password = var.db_master_password
storage_encrypted = true
backup_retention_period = 7
preferred_backup_window = "07:00-09:00"

# Configuración de escalado automático de Aurora Serverless v2
serverlessv2_scaling_configuration {
min_capacity = 0.5
max_capacity = 1
}

# Parámetros adicionales de la base de datos
db_cluster_parameter_group_name = "default.aurora-postgresql16"
skip_final_snapshot = true
}

# Crear instancias de base de datos asociadas al clúster RDS
resource "aws_rds_cluster_instance" "aurora_postgres_instance" {
count = 2
identifier = "aurora-postgres-instance-${count.index}"
cluster_identifier = aws_rds_cluster.aurora_postgresql.id
instance_class = "db.serverless" # Serverless
engine = aws_rds_cluster.aurora_postgresql.engine
engine_version = aws_rds_cluster.aurora_postgresql.engine_version
}

# Crear un grupo de seguridad para la base de datos
resource "aws_security_group" "db_security_group" {
name = "db_security_group"
description = "Permitir acceso a la base de datos desde la red permitida"

# Regla de entrada (Ejemplo: Permitir acceso desde una IP específica)
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Reemplaza con el rango de IPs permitidas
}

# Regla de salida
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

# Asociar el grupo de seguridad al clúster de base de datos
resource "aws_rds_cluster_instance" "aurora_postgres_cluster_instance" {
count = 1
cluster_identifier = aws_rds_cluster.aurora_postgresql.id
instance_class = "db.serverless" # Serverless
engine = aws_rds_cluster.aurora_postgresql.engine
engine_version = aws_rds_cluster.aurora_postgresql.engine_version
publicly_accessible = false
apply_immediately = true
db_subnet_group_name = aws_db_subnet_group.db_subnet_group.name
vpc_security_group_ids = [aws_security_group.db_security_group.id]
}

# Crear un subnet group para la base de datos
resource "aws_db_subnet_group" "db_subnet_group" {
name = "db_subnet_group"
subnet_ids = ["subnet-xxxxxx", "subnet-yyyyyy"] # Reemplaza con los IDs de tus subnets

tags = {
Name = "DB Subnet Group"
}
}
136 changes: 136 additions & 0 deletions pregunta-1-infraestructura/vpc.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
provider "aws" {
region = "us-east-1"
}

# Crear la VPC con un bloque CIDR /16
resource "aws_vpc" "main_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true

tags = {
Name = "main-vpc"
}
}

# Crear un Internet Gateway para las subnets públicas
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main_vpc.id

tags = {
Name = "main-igw"
}
}

# Crear un Elastic IP para el NAT Gateway
resource "aws_eip" "nat_eip" {
vpc = true
}

# Crear una subnet pública en us-east-1a
resource "aws_subnet" "public_subnet_1" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.0.0/18"
availability_zone = "us-east-1a"
map_public_ip_on_launch = true

tags = {
Name = "public-subnet-1"
}
}

# Crear una subnet pública en us-east-1b
resource "aws_subnet" "public_subnet_2" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.64.0/18"
availability_zone = "us-east-1b"
map_public_ip_on_launch = true

tags = {
Name = "public-subnet-2"
}
}

# Crear una subnet privada en us-east-1a
resource "aws_subnet" "private_subnet_1" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.128.0/18"
availability_zone = "us-east-1a"
map_public_ip_on_launch = false

tags = {
Name = "private-subnet-1"
}
}

# Crear una subnet privada en us-east-1b
resource "aws_subnet" "private_subnet_2" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.192.0/18"
availability_zone = "us-east-1b"
map_public_ip_on_launch = false

tags = {
Name = "private-subnet-2"
}
}

# Crear el NAT Gateway en una de las subnets públicas
resource "aws_nat_gateway" "nat" {
allocation_id = aws_eip.nat_eip.id
subnet_id = aws_subnet.public_subnet_1.id

tags = {
Name = "main-nat-gateway"
}
}

# Crear la tabla de rutas para las subnets públicas
resource "aws_route_table" "public_route_table" {
vpc_id = aws_vpc.main_vpc.id

route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}

tags = {
Name = "public-route-table"
}
}

# Crear la tabla de rutas para las subnets privadas
resource "aws_route_table" "private_route_table" {
vpc_id = aws_vpc.main_vpc.id

route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat.id
}

tags = {
Name = "private-route-table"
}
}

# Asociar las subnets públicas a la tabla de rutas pública
resource "aws_route_table_association" "public_subnet_1_association" {
subnet_id = aws_subnet.public_subnet_1.id
route_table_id = aws_route_table.public_route_table.id
}

resource "aws_route_table_association" "public_subnet_2_association" {
subnet_id = aws_subnet.public_subnet_2.id
route_table_id = aws_route_table.public_route_table.id
}

# Asociar las subnets privadas a la tabla de rutas privada
resource "aws_route_table_association" "private_subnet_1_association" {
subnet_id = aws_subnet.private_subnet_1.id
route_table_id = aws_route_table.private_route_table.id
}

resource "aws_route_table_association" "private_subnet_2_association" {
subnet_id = aws_subnet.private_subnet_2.id
route_table_id = aws_route_table.private_route_table.id
}
49 changes: 49 additions & 0 deletions pregunta-2-aplicaciones-cicd/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Define custom function directory
ARG FUNCTION_DIR="/function"

FROM node:20-buster as build-image

# Include global arg in this stage of the build
ARG FUNCTION_DIR

# Install build dependencies
RUN apt-get update && \
apt-get install -y \
g++ \
make \
cmake \
unzip \
libcurl4-openssl-dev

# Copy function code
RUN mkdir -p ${FUNCTION_DIR}
COPY . ${FUNCTION_DIR}

WORKDIR ${FUNCTION_DIR}

# Install Node.js dependencies
RUN npm install

# Install the runtime interface client
RUN npm install aws-lambda-ric

# Grab a fresh slim copy of the image to reduce the final size
FROM node:20-buster-slim

# Required for Node runtimes which use [email protected]+ because
# by default npm writes logs under /home/.npm and Lambda fs is read-only
ENV NPM_CONFIG_CACHE=/tmp/.npm

# Include global arg in this stage of the build
ARG FUNCTION_DIR

# Set working directory to function root directory
WORKDIR ${FUNCTION_DIR}

# Copy in the built dependencies
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}

# Set runtime interface client as default command for the container runtime
ENTRYPOINT ["/usr/local/bin/npx", "aws-lambda-ric"]
# Pass the name of the function handler as an argument to the runtime
CMD ["index.handler"]
7 changes: 7 additions & 0 deletions pregunta-2-aplicaciones-cicd/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
exports.handler = async (event) => {
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
Loading

0 comments on commit 74ed2be

Please sign in to comment.