Skip to content

feat: infra #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions deployment/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Terraform local dependencies
.terraform/

# Terraform state files
terraform.tfstate
terraform.tfstate.backup

# Logs and crash files
crash.log

# Override files (not versionable)
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Dismiss hcl lock files
*.lock.hcl

# Terraform CLI local configuration
.terraformrc
terraform.rc

# Sensitive variables
*.tfvars
*.tfvars.json
59 changes: 59 additions & 0 deletions deployment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Deployment Infrastructure Documentation

## Overview

The deployment directory contains a complete blue-green deployment infrastructure managed through Terraform. For detailed deployment operations and workflow configurations, please refer to .github/README.md.

## Directory Structure

The deployment infrastructure is organized into three main directories:

1. environments/

- Contains environment-specific configurations
- Currently includes production environment
- Manages deployment state and active environment variables
- Coordinates all infrastructure modules

2. modules/

- networking: VPC, subnets, and security groups
- compute: ECS services for blue and green environments
- storage: RDS database configuration
- load_balancer: Application Load Balancer for traffic management
- api-gw: API Gateway configuration
- iam: IAM roles and policies
- bastion: Bastion host setup

3. state/
- Manages Terraform state configuration
- Configures S3 backend for state storage

## Key Features

- Blue-Green Deployment Management

- Two deployment states: "single" or "deploying"
- Active environment tracking (blue/green)
- Automated traffic switching through ALB

- Database Management

- Separate blue and green databases
- Automated database creation
- Cache data synchronization between environments
- Managed through scripts in scripts/migrations/

- Infrastructure Components

- Load balancer with health checks
- ECS tasks for API and processing services
- RDS PostgreSQL database
- VPC networking with public/private subnets

- Configuration Management
- Environment-specific variables
- Sensitive data handling
- Service-specific configurations for both blue and green environments

For deployment operations and workflow details, please refer to the GitHub Actions workflow documentation in .github/README.md
15 changes: 15 additions & 0 deletions deployment/bastion_scripts/install_dependencies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash
# --- System Setup: Update packages and install Node.js tools ---
apt update
apt install -y nodejs npm

# Install "n", the Node.js version manager globally
npm install -g n

# Install Node.js version 20 using "n"
n i 20

# Install pnpm (version 10.0.0) via the installer script
wget -qO- https://get.pnpm.io/install.sh | env PNPM_VERSION=10.0.0 sh -

echo "Dependencies installed successfully."
176 changes: 176 additions & 0 deletions deployment/environments/production/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.84.0"
}
}
backend "s3" {}
}

provider "aws" {
region = "us-east-2"
}


data "aws_caller_identity" "current" {}


module "networking" {
source = "../../modules/networking"
app_environment = var.APP_ENVIRONMENT
app_name = var.APP_NAME
region = var.AWS_REGION
}

module "iam" {
source = "../../modules/iam"
app_name = var.APP_NAME
app_environment = var.APP_ENVIRONMENT
region = var.AWS_REGION
account_id = data.aws_caller_identity.current.account_id
}

module "storage" {
source = "../../modules/storage"
app_name = var.APP_NAME
app_environment = var.APP_ENVIRONMENT
region = var.AWS_REGION
rds_username = var.DATALAYER_PG_USER
rds_password = var.DATALAYER_PG_PASSWORD
rds_security_group_id = module.networking.rds_security_group_id
rds_subnet_ids = module.networking.private_subnets
rds_subnet_group_name = module.networking.rds_subnet_group_name
}

module "bastion" {
source = "../../modules/bastion"
app_environment = var.APP_ENVIRONMENT
app_name = var.APP_NAME
subnet_id = module.networking.private_subnets[0]
bastion_instance_profile_name = module.iam.bastion_instance_profile_name
bastion_security_group_id = module.networking.processing_security_group_id
}

module "load_balancer" {
source = "../../modules/load_balancer"
app_name = var.APP_NAME
app_environment = var.APP_ENVIRONMENT
vpc_id = module.networking.vpc_id
public_subnets = module.networking.public_subnets
load_balancer_security_group_id = module.networking.load_balancer_security_group_id
active_deployment = var.ACTIVE_DEPLOYMENT
}

module "api_gateway" {
source = "../../modules/api-gw"
app_name = var.APP_NAME
app_environment = var.APP_ENVIRONMENT
lb_dns_name = module.load_balancer.lb_dns_name
}


module "blue_compute" {
color = "blue"
should_deploy_module = var.ACTIVE_DEPLOYMENT == "blue" || var.DEPLOYMENT_STATE == "deploying"
is_active_deployment = var.ACTIVE_DEPLOYMENT == "blue"
source = "../../modules/compute"
app_name = var.APP_NAME
app_environment = var.APP_ENVIRONMENT
region = var.AWS_REGION
processing_repository_url = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.AWS_REGION}.amazonaws.com/${var.APP_NAME}-processing"
processing_service_role_arn = module.iam.processing_service_role_arn
processing_image_tag = var.BLUE_PROCESSING_IMAGE_TAG
processing_security_group_id = module.networking.processing_security_group_id
api_image_tag = var.BLUE_API_IMAGE_TAG
api_repository_url = var.BLUE_API_REPOSITORY_URL
api_service_role_arn = module.iam.api_service_role_arn
api_security_group_id = module.networking.api_security_group_id
lb_target_group_arn = module.load_balancer.lb_blue_target_group_arn
NODE_ENV = var.BLUE_NODE_ENV
RETRY_BASE_DELAY_MS = var.BLUE_RETRY_BASE_DELAY_MS
RETRY_MAX_DELAY_MS = var.BLUE_RETRY_MAX_DELAY_MS
RETRY_FACTOR = var.BLUE_RETRY_FACTOR
RETRY_MAX_ATTEMPTS = var.BLUE_RETRY_MAX_ATTEMPTS
DATALAYER_HASURA_DATABASE_URL = "postgresql://${var.DATALAYER_PG_USER}:${var.DATALAYER_PG_PASSWORD}@${module.storage.rds_endpoint}/${var.BLUE_DATALAYER_PG_DB_NAME}"
DATALAYER_HASURA_EXPOSED_PORT = var.BLUE_DATALAYER_HASURA_EXPOSED_PORT
DATALAYER_HASURA_ENABLE_CONSOLE = var.BLUE_DATALAYER_HASURA_ENABLE_CONSOLE
DATALAYER_HASURA_ADMIN_SECRET = var.BLUE_DATALAYER_HASURA_ADMIN_SECRET
DATALAYER_HASURA_UNAUTHORIZED_ROLE = var.BLUE_DATALAYER_HASURA_UNAUTHORIZED_ROLE
DATALAYER_HASURA_CORS_DOMAIN = var.BLUE_DATALAYER_HASURA_CORS_DOMAIN
DATALAYER_HASURA_ENABLE_TELEMETRY = var.BLUE_DATALAYER_HASURA_ENABLE_TELEMETRY
DATALAYER_HASURA_DEV_MODE = var.BLUE_DATALAYER_HASURA_DEV_MODE
DATALAYER_HASURA_ADMIN_INTERNAL_ERRORS = var.BLUE_DATALAYER_HASURA_ADMIN_INTERNAL_ERRORS
DATALAYER_HASURA_CONSOLE_ASSETS_DIR = var.BLUE_DATALAYER_HASURA_CONSOLE_ASSETS_DIR
DATALAYER_HASURA_ENABLED_LOG_TYPES = var.BLUE_DATALAYER_HASURA_ENABLED_LOG_TYPES
DATALAYER_HASURA_DEFAULT_NAMING_CONVENTION = var.BLUE_DATALAYER_HASURA_DEFAULT_NAMING_CONVENTION
DATALAYER_HASURA_BIGQUERY_STRING_NUMERIC_INPUT = var.BLUE_DATALAYER_HASURA_BIGQUERY_STRING_NUMERIC_INPUT
DATALAYER_HASURA_EXPERIMENTAL_FEATURES = var.BLUE_DATALAYER_HASURA_EXPERIMENTAL_FEATURES
DATALAYER_HASURA_ENABLE_ALLOW_LIST = var.BLUE_DATALAYER_HASURA_ENABLE_ALLOW_LIST
CHAINS = var.BLUE_CHAINS

DATABASE_URL = "postgresql://${var.DATALAYER_PG_USER}:${var.DATALAYER_PG_PASSWORD}@${module.storage.rds_endpoint}/${var.BLUE_DATALAYER_PG_DB_NAME}"
INDEXER_GRAPHQL_URL = var.BLUE_INDEXER_GRAPHQL_URL
# INDEXER_ADMIN_SECRET = var.INDEXER_ADMIN_SECRET
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this fine to be commented out?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, we don't need an admin secret to query envio graphql api. We will whitelist IP on envio hosting service

PUBLIC_GATEWAY_URLS = var.BLUE_PUBLIC_GATEWAY_URLS
METADATA_SOURCE = var.BLUE_METADATA_SOURCE
PRICING_SOURCE = var.BLUE_PRICING_SOURCE
COINGECKO_API_KEY = var.BLUE_COINGECKO_API_KEY
COINGECKO_API_TYPE = var.BLUE_COINGECKO_API_TYPE
LOG_LEVEL = var.BLUE_LOG_LEVEL
public_subnets = module.networking.public_subnets
private_subnets = module.networking.private_subnets
}


module "green_compute" {
color = "green"
source = "../../modules/compute"
should_deploy_module = var.ACTIVE_DEPLOYMENT == "green" || var.DEPLOYMENT_STATE == "deploying"
is_active_deployment = var.ACTIVE_DEPLOYMENT == "green"
app_name = var.APP_NAME
app_environment = var.APP_ENVIRONMENT
region = var.AWS_REGION
processing_repository_url = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.AWS_REGION}.amazonaws.com/${var.APP_NAME}-processing"
processing_service_role_arn = module.iam.processing_service_role_arn
processing_image_tag = var.GREEN_PROCESSING_IMAGE_TAG
processing_security_group_id = module.networking.processing_security_group_id
api_image_tag = var.GREEN_API_IMAGE_TAG
api_repository_url = var.GREEN_API_REPOSITORY_URL
api_service_role_arn = module.iam.api_service_role_arn
api_security_group_id = module.networking.api_security_group_id
lb_target_group_arn = module.load_balancer.lb_green_target_group_arn
NODE_ENV = var.GREEN_NODE_ENV
RETRY_BASE_DELAY_MS = var.GREEN_RETRY_BASE_DELAY_MS
RETRY_MAX_DELAY_MS = var.GREEN_RETRY_MAX_DELAY_MS
RETRY_FACTOR = var.GREEN_RETRY_FACTOR
RETRY_MAX_ATTEMPTS = var.GREEN_RETRY_MAX_ATTEMPTS
DATALAYER_HASURA_DATABASE_URL = "postgresql://${var.DATALAYER_PG_USER}:${var.DATALAYER_PG_PASSWORD}@${module.storage.rds_endpoint}/${var.GREEN_DATALAYER_PG_DB_NAME}"
DATALAYER_HASURA_EXPOSED_PORT = var.GREEN_DATALAYER_HASURA_EXPOSED_PORT
DATALAYER_HASURA_ENABLE_CONSOLE = var.GREEN_DATALAYER_HASURA_ENABLE_CONSOLE
DATALAYER_HASURA_ADMIN_SECRET = var.GREEN_DATALAYER_HASURA_ADMIN_SECRET
DATALAYER_HASURA_UNAUTHORIZED_ROLE = var.GREEN_DATALAYER_HASURA_UNAUTHORIZED_ROLE
DATALAYER_HASURA_CORS_DOMAIN = var.GREEN_DATALAYER_HASURA_CORS_DOMAIN
DATALAYER_HASURA_ENABLE_TELEMETRY = var.GREEN_DATALAYER_HASURA_ENABLE_TELEMETRY
DATALAYER_HASURA_DEV_MODE = var.GREEN_DATALAYER_HASURA_DEV_MODE
DATALAYER_HASURA_ADMIN_INTERNAL_ERRORS = var.GREEN_DATALAYER_HASURA_ADMIN_INTERNAL_ERRORS
DATALAYER_HASURA_CONSOLE_ASSETS_DIR = var.GREEN_DATALAYER_HASURA_CONSOLE_ASSETS_DIR
DATALAYER_HASURA_ENABLED_LOG_TYPES = var.GREEN_DATALAYER_HASURA_ENABLED_LOG_TYPES
DATALAYER_HASURA_DEFAULT_NAMING_CONVENTION = var.GREEN_DATALAYER_HASURA_DEFAULT_NAMING_CONVENTION
DATALAYER_HASURA_BIGQUERY_STRING_NUMERIC_INPUT = var.GREEN_DATALAYER_HASURA_BIGQUERY_STRING_NUMERIC_INPUT
DATALAYER_HASURA_EXPERIMENTAL_FEATURES = var.GREEN_DATALAYER_HASURA_EXPERIMENTAL_FEATURES
DATALAYER_HASURA_ENABLE_ALLOW_LIST = var.GREEN_DATALAYER_HASURA_ENABLE_ALLOW_LIST
CHAINS = var.GREEN_CHAINS

DATABASE_URL = "postgresql://${var.DATALAYER_PG_USER}:${var.DATALAYER_PG_PASSWORD}@${module.storage.rds_endpoint}/${var.GREEN_DATALAYER_PG_DB_NAME}"
INDEXER_GRAPHQL_URL = var.GREEN_INDEXER_GRAPHQL_URL
PUBLIC_GATEWAY_URLS = var.GREEN_PUBLIC_GATEWAY_URLS
METADATA_SOURCE = var.GREEN_METADATA_SOURCE
PRICING_SOURCE = var.GREEN_PRICING_SOURCE
COINGECKO_API_KEY = var.GREEN_COINGECKO_API_KEY
COINGECKO_API_TYPE = var.GREEN_COINGECKO_API_TYPE
LOG_LEVEL = var.GREEN_LOG_LEVEL
public_subnets = module.networking.public_subnets
private_subnets = module.networking.private_subnets
}

11 changes: 11 additions & 0 deletions deployment/environments/production/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
output "active_deployment" {
value = var.ACTIVE_DEPLOYMENT
}

output "deployment_state" {
value = var.DEPLOYMENT_STATE
}

output "api_gateway_url" {
value = module.api_gateway.api_gateway_url
}
Loading
Loading