-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4287f0f
commit 74ed2be
Showing
8 changed files
with
1,703 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
Oops, something went wrong.