Infra and Deployment for ECS Fargate (#4449)

* Infra and Deployment for ECS Fargate
---------

Co-authored-by: jpb80 <jordan.buttkevitz@gmail.com>
This commit is contained in:
Chris Weaver
2025-04-03 22:43:56 -07:00
committed by GitHub
parent b02af9b280
commit 2380c2266c
19 changed files with 2428 additions and 12 deletions

View File

@@ -0,0 +1,68 @@
# Onyx AWS ECS Fargate CloudFormation Deployment
This directory contains CloudFormation templates and scripts to deploy Onyx on AWS ECS Fargate.
## Configuration
All configuration parameters are stored in a single JSON file: `onyx_config.json`. This file contains all the parameters needed for the different CloudFormation stacks.
Example:
```json
{
"OnyxNamespace": "onyx",
"Environment": "production",
"EFSName": "onyx-efs",
"AWSRegion": "us-east-2",
"VpcID": "YOUR_VPC_ID",
"SubnetIDs": "YOUR_SUBNET_ID1,YOUR_SUBNET_ID2",
"DomainName": "YOUR_DOMAIN e.g ecs.onyx.app",
"ValidationMethod": "DNS",
"HostedZoneId": ""
}
```
### Required Parameters
- `Environment`: Used to prefix all stack names during deployment. This is required.
- `OnyxNamespace`: Namespace for the Onyx deployment.
- `EFSName`: Name for the Elastic File System.
- `AWSRegion`: AWS region where resources will be deployed.
- `VpcID`: ID of the VPC where Onyx will be deployed.
- `SubnetIDs`: Comma-separated list of subnet IDs for deployment.
- `DomainName`: Domain name for the Onyx deployment.
- `ValidationMethod`: Method for domain validation (typically "DNS").
- [optional] `HostedZoneId`: Route 53 hosted zone ID (only if using Route 53 for DNS).
The deployment script automatically extracts the needed parameters for each CloudFormation template based on the parameter names defined in the templates.
## Deployment Order
The deployment follows this order:
1. Infrastructure stacks:
- EFS
- Cluster
- ACM
2. Service stacks:
- Postgres
- Redis
- Vespa Engine
- Model Server (Indexing)
- Model Server (Inference)
- Backend API Server
- Backend Background Server
- Web Server
- Nginx
## Usage
To deploy:
```bash
./deploy.sh
```
To uninstall:
```bash
./uninstall.sh
```

View File

@@ -0,0 +1,194 @@
#!/bin/bash
# Function to remove comments from JSON and output valid JSON
remove_comments() {
sed 's/\/\/.*$//' "$1" | grep -v '^[[:space:]]*$'
}
# Variables
TEMPLATE_DIR="$(pwd)"
SERVICE_DIR="$TEMPLATE_DIR/services"
# Unified config file
CONFIG_FILE="onyx_config.jsonl"
# Try to get AWS_REGION from config, fallback to default if not found
AWS_REGION_FROM_CONFIG=$(remove_comments "$CONFIG_FILE" | jq -r '.AWSRegion // empty')
if [ -n "$AWS_REGION_FROM_CONFIG" ]; then
AWS_REGION="$AWS_REGION_FROM_CONFIG"
else
AWS_REGION="${AWS_REGION:-us-east-2}"
fi
# Get environment from config file
ENVIRONMENT=$(remove_comments "$CONFIG_FILE" | jq -r '.Environment')
if [ -z "$ENVIRONMENT" ] || [ "$ENVIRONMENT" == "null" ]; then
echo "Missing Environment in $CONFIG_FILE. Please add the Environment field."
exit 1
fi
# Try to get S3_BUCKET from config, fallback to default if not found
S3_BUCKET_FROM_CONFIG=$(remove_comments "$CONFIG_FILE" | jq -r '.S3Bucket // empty')
if [ -n "$S3_BUCKET_FROM_CONFIG" ]; then
S3_BUCKET="$S3_BUCKET_FROM_CONFIG"
else
S3_BUCKET="${S3_BUCKET:-onyx-ecs-fargate-configs}"
fi
INFRA_ORDER=(
"onyx_efs_template.yaml"
"onyx_cluster_template.yaml"
"onyx_acm_template.yaml"
)
# Deployment order for services
SERVICE_ORDER=(
"onyx_postgres_service_template.yaml"
"onyx_redis_service_template.yaml"
"onyx_vespaengine_service_template.yaml"
"onyx_model_server_indexing_service_template.yaml"
"onyx_model_server_inference_service_template.yaml"
"onyx_backend_api_server_service_template.yaml"
"onyx_backend_background_server_service_template.yaml"
"onyx_web_server_service_template.yaml"
"onyx_nginx_service_template.yaml"
)
# Function to validate a CloudFormation template
validate_template() {
local template_file=$1
echo "Validating template: $template_file..."
aws cloudformation validate-template --template-body file://"$template_file" --region "$AWS_REGION" > /dev/null
if [ $? -ne 0 ]; then
echo "Error: Validation failed for $template_file. Exiting."
exit 1
fi
echo "Validation succeeded for $template_file."
}
# Function to create CloudFormation parameters from JSON
create_parameters_from_json() {
local template_file=$1
local temp_params_file="${template_file%.yaml}_parameters.json"
# Convert the config file contents to CloudFormation parameter format
echo "[" > "$temp_params_file"
# Process all key-value pairs from the config file
local first=true
remove_comments "$CONFIG_FILE" | jq -r 'to_entries[] | select(.value != null and .value != "") | "\(.key)|\(.value)"' | while IFS='|' read -r key value; do
if [ "$first" = true ]; then
first=false
else
echo "," >> "$temp_params_file"
fi
echo " {\"ParameterKey\": \"$key\", \"ParameterValue\": \"$value\"}" >> "$temp_params_file"
done
echo "]" >> "$temp_params_file"
# Debug output - display the created parameters file
echo "Generated parameters file: $temp_params_file" >&2
echo "Contents:" >&2
cat "$temp_params_file" >&2
# Return just the filename
echo "$temp_params_file"
}
# Function to deploy a CloudFormation stack
deploy_stack() {
local stack_name=$1
local template_file=$2
echo "Checking if stack $stack_name exists..."
if aws cloudformation describe-stacks --stack-name "$stack_name" --region "$AWS_REGION" > /dev/null 2>&1; then
echo "Stack $stack_name already exists. Skipping deployment."
return 0
fi
# Create temporary parameters file for this template
local temp_params_file=$(create_parameters_from_json "$template_file")
# Special handling for SubnetIDs parameter if needed
if grep -q "SubnetIDs" "$template_file"; then
echo "Template uses SubnetIDs parameter, ensuring it's properly formatted..."
# Make sure we're passing SubnetIDs as a comma-separated list
local subnet_ids=$(remove_comments "$CONFIG_FILE" | jq -r '.SubnetIDs // empty')
if [ -n "$subnet_ids" ]; then
echo "Using SubnetIDs from config: $subnet_ids"
else
echo "Warning: SubnetIDs not found in config but template requires it."
fi
fi
echo "Deploying stack: $stack_name with template: $template_file and generated config from: $CONFIG_FILE..."
aws cloudformation deploy \
--stack-name "$stack_name" \
--template-file "$template_file" \
--parameter-overrides file://"$temp_params_file" \
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
--region "$AWS_REGION" \
--no-cli-auto-prompt > /dev/null
if [ $? -ne 0 ]; then
echo "Error: Deployment failed for $stack_name. Exiting."
exit 1
fi
# Clean up temporary parameter file
rm "$temp_params_file"
echo "Stack deployed successfully: $stack_name."
}
convert_underscores_to_hyphens() {
local input_string="$1"
local converted_string="${input_string//_/-}"
echo "$converted_string"
}
deploy_infra_stacks() {
for template_name in "${INFRA_ORDER[@]}"; do
# Skip ACM template if HostedZoneId is not set
if [[ "$template_name" == "onyx_acm_template.yaml" ]]; then
HOSTED_ZONE_ID=$(remove_comments "$CONFIG_FILE" | jq -r '.HostedZoneId')
if [ -z "$HOSTED_ZONE_ID" ] || [ "$HOSTED_ZONE_ID" == "" ] || [ "$HOSTED_ZONE_ID" == "null" ]; then
echo "Skipping ACM template deployment because HostedZoneId is not set in $CONFIG_FILE"
continue
fi
fi
template_file="$template_name"
stack_name="$ENVIRONMENT-$(basename "$template_name" _template.yaml)"
stack_name=$(convert_underscores_to_hyphens "$stack_name")
if [ -f "$template_file" ]; then
validate_template "$template_file"
deploy_stack "$stack_name" "$template_file"
else
echo "Warning: Template file $template_file not found. Skipping."
fi
done
}
deploy_services_stacks() {
for template_name in "${SERVICE_ORDER[@]}"; do
template_file="$SERVICE_DIR/$template_name"
stack_name="$ENVIRONMENT-$(basename "$template_name" _template.yaml)"
stack_name=$(convert_underscores_to_hyphens "$stack_name")
if [ -f "$template_file" ]; then
validate_template "$template_file"
deploy_stack "$stack_name" "$template_file"
else
echo "Warning: Template file $template_file not found. Skipping."
fi
done
}
echo "Starting deployment of Onyx to ECS Fargate Cluster..."
deploy_infra_stacks
deploy_services_stacks
echo "All templates validated and deployed successfully."

View File

@@ -0,0 +1,31 @@
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template to create an ACM Certificate.
Parameters:
DomainName:
Type: String
Description: The primary domain name for the certificate (e.g., example.com).
Default: example.com
Environment:
Type: String
Default: production
ValidationMethod:
Type: String
Default: DNS
Resources:
Certificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref DomainName
ValidationMethod: !Ref ValidationMethod
Tags:
- Key: env
Value: !Ref Environment
Outputs:
OutputAcm:
Description: ACM Cert Id
Value: !Ref Certificate
Export:
Name: !Sub ${AWS::StackName}-OnyxCertificate

View File

@@ -0,0 +1,156 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: The template used to create an ECS Cluster from the ECS Console.
Parameters:
Environment:
Type: String
Description: The environment that is used in the name of the cluster as well.
OnyxNamespace:
Type: String
Default: onyx
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
Resources:
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Sub ${Environment}-onyx-cluster
CapacityProviders:
- FARGATE
- FARGATE_SPOT
ClusterSettings:
- Name: containerInsights
Value: enhanced
ServiceConnectDefaults:
Namespace: !Sub ${Environment}-onyx-cluster
Tags:
- Key: env
Value: !Ref Environment
- Key: app
Value: onyx
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${Environment}-onyx-ecs-fargate-configs
AccessControl: Private
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
PrivateDnsNamespace:
Type: AWS::ServiceDiscovery::PrivateDnsNamespace
Properties:
Description: AWS Cloud Map private DNS namespace for resources for onyx website.
Vpc: !Ref VpcID
Name: !Ref OnyxNamespace
Properties:
DnsProperties:
SOA:
TTL: 50
ECSTaskRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${Environment}-OnyxEcsTaskRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: "EFSPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "VisualEditor0"
Effect: Allow
Action:
- "elasticfilesystem:*"
Resource:
- !Sub "arn:aws:elasticfilesystem:*:${AWS::AccountId}:access-point/*"
- !Sub "arn:aws:elasticfilesystem:*:${AWS::AccountId}:file-system/*"
- Sid: "VisualEditor1"
Effect: Allow
Action: "elasticfilesystem:*"
Resource: "*"
- PolicyName: "S3Policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "VisualEditor0"
Effect: Allow
Action:
- "s3:GetObject"
- "s3:ListBucket"
Resource:
- !Sub "arn:aws:s3:::${Environment}-onyx-ecs-fargate-configs/*"
- !Sub "arn:aws:s3:::${Environment}-onyx-ecs-fargate-configs"
ECSTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${Environment}-OnyxECSTaskExecutionRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Policies:
- PolicyName: "CloudWatchLogsPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "VisualEditor0"
Effect: Allow
Action: "logs:CreateLogGroup"
Resource: !Sub "arn:aws:logs:*:${AWS::AccountId}:log-group:*"
- PolicyName: "SecretsManagerPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Environment}/postgres/user/password-*
Outputs:
OutputEcsCluster:
Description: Onyx ECS Cluster
Value: !Ref ECSCluster
Export:
Name: !Sub ${AWS::StackName}-ECSClusterName
OutputECSTaskRole:
Description: Onyx ECS Task Role
Value: !Ref ECSTaskRole
Export:
Name: !Sub ${AWS::StackName}-ECSTaskRole
OutputECSTaskExecutionRole:
Description: Onyx ECS TaskExecutionRole
Value: !Ref ECSTaskExecutionRole
Export:
Name: !Sub ${AWS::StackName}-ECSTaskExecutionRole
OutputOnyxNamespace:
Description: Onyx CloudMap namespace ID for ECS service discvoery.
Value: !Ref PrivateDnsNamespace
Export:
Name: !Sub ${AWS::StackName}-OnyxNamespace
OutputOnyxNamespaceName:
Description: Onyx CloudMap namespace domain name for ECS service discvoery.
Value: !Ref OnyxNamespace
Export:
Name: !Sub ${AWS::StackName}-OnyxNamespaceName

View File

@@ -0,0 +1,16 @@
{
// Naming, likely doesn't need to be changed
"OnyxNamespace": "onyx",
"Environment": "production-1",
"EFSName": "onyx-efs-1",
// Region and VPC Stuff
"AWSRegion": "us-east-2",
"VpcID": "vpc-08822ab4927074015",
"SubnetIDs": "subnet-0c0c686bf71a9756e,subnet-0711d1a975b8a035c",
// Domain and ACM Stuff
"DomainName": "ecs-chris.danswer.dev",
"ValidationMethod": "DNS",
"HostedZoneId": "" // Only specify if using Route 53 for DNS
}

View File

@@ -0,0 +1,128 @@
Parameters:
EFSName:
Type: String
Default: onyx-efs
Environment:
Type: String
Default: production
VpcID:
Type: String
Default: vpc-0f230ca52bb04c722
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
Resources:
OnyxEfs:
Type: AWS::EFS::FileSystem
Properties:
BackupPolicy:
Status: ENABLED
Encrypted: True
PerformanceMode: generalPurpose
FileSystemTags:
- Key: Name
Value: !Sub ${Environment}-${EFSName}-${AWS::Region}-${AWS::AccountId}
FileSystemProtection:
ReplicationOverwriteProtection: ENABLED
ThroughputMode: elastic
VespaEngineTmpEfsAccessPoint:
Type: AWS::EFS::AccessPoint
Properties:
AccessPointTags:
- Key: Name
Value: vespaengine-tmp
FileSystemId: !Ref OnyxEfs
RootDirectory:
CreationInfo:
OwnerGid: "1000"
OwnerUid: "1000"
Permissions: "0755"
Path: /var/tmp
VespaEngineDataEfsAccessPoint:
Type: AWS::EFS::AccessPoint
Properties:
AccessPointTags:
- Key: Name
Value: vespaengine-data
FileSystemId: !Ref OnyxEfs
RootDirectory:
CreationInfo:
OwnerGid: "1000"
OwnerUid: "1000"
Permissions: "0755"
Path: /opt/vespa/var
PostgresDataEfsAccessPoint:
Type: AWS::EFS::AccessPoint
Properties:
AccessPointTags:
- Key: Name
Value: postgres-data
FileSystemId: !Ref OnyxEfs
RootDirectory:
CreationInfo:
OwnerGid: "1000"
OwnerUid: "1000"
Permissions: "0755"
Path: /var/lib/postgresql/data
EFSMountTarget1:
DependsOn: OnyxEfs
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref OnyxEfs
SubnetId: !Select [0, !Ref SubnetIDs]
SecurityGroups:
- !Ref EFSSecurityGroupMountTargets
EFSMountTarget2:
DependsOn: OnyxEfs
Type: AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref OnyxEfs
SubnetId: !Select [1, !Ref SubnetIDs]
SecurityGroups:
- !Ref EFSSecurityGroupMountTargets
EFSSecurityGroupMountTargets:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security Group for EFS Mount Targets
VpcId: !Ref VpcID
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 2049
ToPort: 2049
CidrIp: 0.0.0.0/0
Outputs:
OutputOnyxEfsId:
Description: Onyx Filesystem Id
Value: !Ref OnyxEfs
Export:
Name: !Sub ${AWS::StackName}-OnyxEfsId
OutputVespaEngineTmpEfsAccessPoint:
Description: VespaEngine Tmp AP
Value: !Ref VespaEngineTmpEfsAccessPoint
Export:
Name: !Sub ${AWS::StackName}-VespaEngineTmpEfsAccessPoint
OutputVespaEngineDataEfsAccessPoint:
Description: VespaEngine Data Ap
Value: !Ref VespaEngineDataEfsAccessPoint
Export:
Name: !Sub ${AWS::StackName}-VespaEngineDataEfsAccessPoint
OutputPostgresDataEfsAccessPoint:
Description: Postgres Data AP
Value: !Ref PostgresDataEfsAccessPoint
Export:
Name: !Sub ${AWS::StackName}-PostgresDataEfsAccessPoint
OutputEFSSecurityGroupMountTargets:
Description: EFS Security Group
Value: !Ref EFSSecurityGroupMountTargets
Export:
Name: !Sub ${AWS::StackName}-EFSSecurityGroupMountTargets

View File

@@ -0,0 +1,216 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for Onyx Backend Api Server TaskDefinition
Parameters:
Environment:
Type: String
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
ServiceName:
Type: String
Default: onyx-backend-api-server
TaskCpu:
Type: String
Default: "2048"
TaskMemory:
Type: String
Default: "4096"
TaskDesiredCount:
Type: Number
Default: 1
Resources:
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSClusterName"
CapacityProviderStrategy:
- CapacityProvider: FARGATE
Base: 0
Weight: 1
TaskDefinition: !Ref TaskDefinition
ServiceName: !Sub ${Environment}-${ServiceName}-service
SchedulingStrategy: REPLICA
DesiredCount: !Ref TaskDesiredCount
AvailabilityZoneRebalancing: ENABLED
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- Ref: SecurityGroup
Subnets: !Ref SubnetIDs
PlatformVersion: LATEST
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DeploymentCircuitBreaker:
Enable: true
Rollback: true
DeploymentController:
Type: ECS
ServiceConnectConfiguration:
Enabled: false
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscoveryService.Arn
Tags:
- Key: app
Value: onyx
- Key: service
Value: !Ref ServiceName
- Key: env
Value: !Ref Environment
EnableECSManagedTags: true
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub Onyx SecurityGroup access to EFS mount and ${ServiceName}.
GroupName: !Sub ${Environment}-ecs-${ServiceName}
VpcId: !Ref VpcID
SecurityGroupIngress:
- FromPort: 8080
ToPort: 8080
IpProtocol: tcp
CidrIp: 0.0.0.0/0
- FromPort: 8080
ToPort: 8080
IpProtocol: tcp
CidrIpv6: "::/0"
ServiceDiscoveryService:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: !Sub ${Environment}-${ServiceName}-service
DnsConfig:
DnsRecords:
- Type: "A"
TTL: 15
NamespaceId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespace"
HealthCheckCustomConfig:
FailureThreshold: 1
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${Environment}-${ServiceName}-TaskDefinition
TaskRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskRole"
ExecutionRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskExecutionRole"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
RuntimePlatform:
CpuArchitecture: ARM64
OperatingSystemFamily: LINUX
ContainerDefinitions:
- Name: onyx-backend
Image: onyxdotapp/onyx-backend:latest
Cpu: 0
Essential: true
Command:
- "/bin/sh"
- "-c"
- |
alembic upgrade head && echo "Starting Onyx Api Server" && uvicorn onyx.main:app --host 0.0.0.0 --port 8080
PortMappings:
- Name: backend
ContainerPort: 8080
HostPort: 8080
Protocol: tcp
AppProtocol: http
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Sub /ecs/${Environment}-${ServiceName}
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: "25m"
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
Environment:
- Name: REDIS_HOST
Value: !Sub
- "${Environment}-onyx-redis-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: MODEL_SERVER_HOST
Value: !Sub
- "${Environment}-onyx-model-server-inference-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: VESPA_HOST
Value: !Sub
- "${Environment}-onyx-vespaengine-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: POSTGRES_HOST
Value: !Sub
- "${Environment}-onyx-postgres-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: INDEXING_MODEL_SERVER_HOST
Value: !Sub
- "${Environment}-onyx-model-server-indexing-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: AUTH_TYPE
Value: disabled
Secrets:
- Name: POSTGRES_PASSWORD
ValueFrom: !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Environment}/postgres/user/password
VolumesFrom: []
SystemControls: []
ECSAutoScalingTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn: ECSService
Properties:
MaxCapacity: 5
MinCapacity: 1
ResourceId: !Sub
- "service/${ImportedCluster}/${Environment}-${ServiceName}-service"
- ImportedCluster: !ImportValue
'Fn::Sub': "${Environment}-onyx-cluster-ECSClusterName"
ServiceName: !Ref ServiceName
Environment: !Ref Environment
ScalableDimension: ecs:service:DesiredCount
ServiceNamespace: ecs
ECSAutoScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: !Sub ${Environment}-${ServiceName}-service-cpu-scaleout
ScalingTargetId: !Ref ECSAutoScalingTarget
PolicyType: TargetTrackingScaling
TargetTrackingScalingPolicyConfiguration:
TargetValue: 75
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageCPUUtilization
ScaleOutCooldown: 60
ScaleInCooldown: 60
ECSAutoScalingPolicyMemory:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: !Sub ${Environment}-${ServiceName}-service-mem-scaleout
ScalingTargetId: !Ref ECSAutoScalingTarget
PolicyType: TargetTrackingScaling
TargetTrackingScalingPolicyConfiguration:
TargetValue: 80
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageMemoryUtilization
ScaleOutCooldown: 60
ScaleInCooldown: 60

View File

@@ -0,0 +1,174 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for Onyx Backend Background Server TaskDefinition
Parameters:
Environment:
Type: String
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
ServiceName:
Type: String
Default: onyx-backend-background-server
TaskCpu:
Type: String
Default: "2048"
TaskMemory:
Type: String
Default: "4096"
TaskDesiredCount:
Type: Number
Default: 1
Resources:
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSClusterName"
CapacityProviderStrategy:
- CapacityProvider: FARGATE
Base: 0
Weight: 1
TaskDefinition: !Ref TaskDefinition
ServiceName: !Sub ${Environment}-${ServiceName}-service
SchedulingStrategy: REPLICA
DesiredCount: !Ref TaskDesiredCount
AvailabilityZoneRebalancing: ENABLED
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- Ref: SecurityGroup
Subnets: !Ref SubnetIDs
PlatformVersion: LATEST
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DeploymentCircuitBreaker:
Enable: true
Rollback: true
DeploymentController:
Type: ECS
ServiceConnectConfiguration:
Enabled: false
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscoveryService.Arn
Tags:
- Key: app
Value: onyx
- Key: service
Value: !Ref ServiceName
- Key: env
Value: !Ref Environment
EnableECSManagedTags: true
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub Onyx SecurityGroup access to EFS mount and ${ServiceName}.
GroupName: !Sub ${Environment}-ecs-${ServiceName}
VpcId: !Ref VpcID
SecurityGroupIngress:
- FromPort: 8080
ToPort: 8080
IpProtocol: tcp
CidrIp: 0.0.0.0/0
- FromPort: 8080
ToPort: 8080
IpProtocol: tcp
CidrIpv6: "::/0"
ServiceDiscoveryService:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: !Sub ${Environment}-${ServiceName}-service
DnsConfig:
DnsRecords:
- Type: "A"
TTL: 15
NamespaceId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespace"
HealthCheckCustomConfig:
FailureThreshold: 1
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${Environment}-${ServiceName}-TaskDefinition
TaskRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskRole"
ExecutionRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskExecutionRole"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
RuntimePlatform:
CpuArchitecture: ARM64
OperatingSystemFamily: LINUX
ContainerDefinitions:
- Name: onyx-backend-background
Image: onyxdotapp/onyx-backend:latest
Cpu: 0
Essential: true
Command:
- "/usr/bin/supervisord"
- "-c"
- "/etc/supervisor/conf.d/supervisord.conf"
PortMappings:
- Name: backend
ContainerPort: 8080
HostPort: 8080
Protocol: tcp
AppProtocol: http
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Sub /ecs/${Environment}-${ServiceName}
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: "25m"
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
Environment:
- Name: REDIS_HOST
Value: !Sub
- "${Environment}-onyx-redis-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: MODEL_SERVER_HOST
Value: !Sub
- "${Environment}-onyx-model-server-inference-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: VESPA_HOST
Value: !Sub
- "${Environment}-onyx-vespaengine-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: POSTGRES_HOST
Value: !Sub
- "${Environment}-onyx-postgres-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: INDEXING_MODEL_SERVER_HOST
Value: !Sub
- "${Environment}-onyx-model-server-indexing-service.${ImportedNamespace}"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
- Name: AUTH_TYPE
Value: disabled
Secrets:
- Name: POSTGRES_PASSWORD
ValueFrom: !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Environment}/postgres/user/password
VolumesFrom: []
SystemControls: []

View File

@@ -0,0 +1,163 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for Onyx Model Server Indexing TaskDefinition
Parameters:
Environment:
Type: String
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
ServiceName:
Type: String
Default: onyx-model-server-indexing
TaskCpu:
Type: String
Default: "2048"
TaskMemory:
Type: String
Default: "4096"
TaskDesiredCount:
Type: Number
Default: 1
Resources:
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSClusterName"
CapacityProviderStrategy:
- CapacityProvider: FARGATE
Base: 0
Weight: 1
TaskDefinition: !Ref TaskDefinition
ServiceName: !Sub ${Environment}-${ServiceName}-service
SchedulingStrategy: REPLICA
DesiredCount: !Ref TaskDesiredCount
AvailabilityZoneRebalancing: ENABLED
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- Ref: SecurityGroup
Subnets: !Ref SubnetIDs
PlatformVersion: LATEST
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DeploymentCircuitBreaker:
Enable: true
Rollback: true
DeploymentController:
Type: ECS
ServiceConnectConfiguration:
Enabled: false
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscoveryService.Arn
Tags:
- Key: app
Value: onyx
- Key: service
Value: !Ref ServiceName
- Key: env
Value: !Ref Environment
EnableECSManagedTags: true
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub Onyx SecurityGroup access to EFS mount and ${ServiceName}.
GroupName: !Sub ${Environment}-ecs-${ServiceName}
VpcId: !Ref VpcID
SecurityGroupIngress:
- FromPort: 9000
ToPort: 9000
IpProtocol: tcp
CidrIp: 0.0.0.0/0
- FromPort: 9000
ToPort: 9000
IpProtocol: tcp
CidrIpv6: "::/0"
ServiceDiscoveryService:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: !Sub ${Environment}-${ServiceName}-service
DnsConfig:
DnsRecords:
- Type: "A"
TTL: 15
NamespaceId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespace"
HealthCheckCustomConfig:
FailureThreshold: 1
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${Environment}-${ServiceName}-TaskDefinition
TaskRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskRole"
ExecutionRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskExecutionRole"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
RuntimePlatform:
CpuArchitecture: ARM64
OperatingSystemFamily: LINUX
ContainerDefinitions:
- Name: onyx-model-server-indexing
Image: onyxdotapp/onyx-model-server:latest
Cpu: 0
Essential: true
Command:
- "/bin/sh"
- "-c"
- >
if [ "${DISABLE_MODEL_SERVER:-false}" = "True" ]; then echo 'Skipping service...';
exit 0; else exec uvicorn model_server.main:app --host 0.0.0.0 --port 9000; fi
PortMappings:
- Name: model-server
ContainerPort: 9000
HostPort: 9000
Protocol: tcp
AppProtocol: http
Environment:
- Name: LOG_LEVEL
Value: info
- Name: INDEXING_ONLY
Value: True
- Name: VESPA_SEARCHER_THREADS
Value: "1"
MountPoints:
- SourceVolume: efs-volume
ContainerPath: /root/.cache/huggingface/
ReadOnly: false
VolumesFrom: []
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Sub /ecs/${Environment}-${ServiceName}
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: "25m"
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: "ecs"
SystemControls: []
Volumes:
- Name: efs-volume
EFSVolumeConfiguration:
FilesystemId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-OnyxEfsId"
RootDirectory: "/"

View File

@@ -0,0 +1,200 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for Onyx Model Server Inference TaskDefinition
Parameters:
Environment:
Type: String
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
ServiceName:
Type: String
Default: onyx-model-server-inference
TaskCpu:
Type: String
Default: "2048"
TaskMemory:
Type: String
Default: "4096"
TaskDesiredCount:
Type: Number
Default: 1
Resources:
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSClusterName"
CapacityProviderStrategy:
- CapacityProvider: FARGATE
Base: 0
Weight: 1
TaskDefinition: !Ref TaskDefinition
ServiceName: !Sub ${Environment}-${ServiceName}-service
SchedulingStrategy: REPLICA
DesiredCount: !Ref TaskDesiredCount
AvailabilityZoneRebalancing: ENABLED
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- Ref: SecurityGroup
Subnets: !Ref SubnetIDs
PlatformVersion: LATEST
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DeploymentCircuitBreaker:
Enable: true
Rollback: true
DeploymentController:
Type: ECS
ServiceConnectConfiguration:
Enabled: false
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscoveryService.Arn
Tags:
- Key: app
Value: onyx
- Key: service
Value: !Ref ServiceName
- Key: env
Value: !Ref Environment
EnableECSManagedTags: true
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub Onyx SecurityGroup access to EFS mount and ${ServiceName}.
GroupName: !Sub ${Environment}-ecs-${ServiceName}
VpcId: !Ref VpcID
SecurityGroupIngress:
- FromPort: 9000
ToPort: 9000
IpProtocol: tcp
CidrIp: 0.0.0.0/0
- FromPort: 9000
ToPort: 9000
IpProtocol: tcp
CidrIpv6: "::/0"
ServiceDiscoveryService:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: !Sub ${Environment}-${ServiceName}-service
DnsConfig:
DnsRecords:
- Type: "A"
TTL: 15
NamespaceId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespace"
HealthCheckCustomConfig:
FailureThreshold: 1
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${Environment}-${ServiceName}-TaskDefinition
TaskRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskRole"
ExecutionRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskExecutionRole"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
RuntimePlatform:
CpuArchitecture: ARM64
OperatingSystemFamily: LINUX
ContainerDefinitions:
- Name: onyx-model-server-inference
Image: onyxdotapp/onyx-model-server:latest
Cpu: 0
Essential: true
Command:
- "/bin/sh"
- "-c"
- >
if [ "${DISABLE_MODEL_SERVER:-false}" = "True" ]; then echo 'Skipping service...';
exit 0; else exec uvicorn model_server.main:app --host 0.0.0.0 --port 9000; fi
PortMappings:
- Name: model-server
ContainerPort: 9000
HostPort: 9000
Protocol: tcp
AppProtocol: http
Environment:
- Name: LOG_LEVEL
Value: info
MountPoints:
- SourceVolume: efs-volume
ContainerPath: /root/.cache/huggingface/
ReadOnly: false
VolumesFrom: []
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Sub /ecs/${Environment}-${ServiceName}
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: "25m"
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: "ecs"
SystemControls: []
Volumes:
- Name: efs-volume
EFSVolumeConfiguration:
FilesystemId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-OnyxEfsId"
RootDirectory: "/"
ECSAutoScalingTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn: ECSService
Properties:
MaxCapacity: 5
MinCapacity: 1
ResourceId: !Sub
- "service/${ImportedCluster}/${Environment}-${ServiceName}-service"
- ImportedCluster: !ImportValue
'Fn::Sub': "${Environment}-onyx-cluster-ECSClusterName"
ServiceName: !Ref ServiceName
Environment: !Ref Environment
ScalableDimension: ecs:service:DesiredCount
ServiceNamespace: ecs
ECSAutoScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: !Sub ${Environment}-${ServiceName}-service-cpu-scaleout
ScalingTargetId: !Ref ECSAutoScalingTarget
PolicyType: TargetTrackingScaling
TargetTrackingScalingPolicyConfiguration:
TargetValue: 75
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageCPUUtilization
ScaleOutCooldown: 60
ScaleInCooldown: 60
ECSAutoScalingPolicyMemory:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: !Sub ${Environment}-${ServiceName}-service-memory-scaleout
ScalingTargetId: !Ref ECSAutoScalingTarget
PolicyType: TargetTrackingScaling
TargetTrackingScalingPolicyConfiguration:
TargetValue: 80
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageMemoryUtilization
ScaleOutCooldown: 60
ScaleInCooldown: 60

View File

@@ -0,0 +1,288 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: "The template used to create an ECS Service from the ECS Console."
Parameters:
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
HostedZoneId:
Type: String
Default: ''
DomainName:
Type: String
Default: demo.danswer.ai
Environment:
Type: String
ServiceName:
Type: String
Default: onyx-nginx
OnyxNamespace:
Type: String
Default: onyx
OnyxBackendApiServiceName:
Type: String
Default: onyx-backend-api-server-service
OnyxWebServerServiceName:
Type: String
Default: onyx-web-server-service
TaskCpu:
Type: String
Default: "512"
TaskMemory:
Type: String
Default: "1024"
TaskDesiredCount:
Type: Number
Default: 1
GitHubConfigUrl:
Type: String
Default: "https://raw.githubusercontent.com/onyx-dot-app/onyx/main/deployment/data/nginx/app.conf.template.dev"
Description: "URL to the nginx configuration file on GitHub"
GitHubRunScriptUrl:
Type: String
Default: "https://raw.githubusercontent.com/onyx-dot-app/onyx/main/deployment/data/nginx/run-nginx.sh"
Description: "URL to the nginx run script on GitHub"
Conditions:
CreateRoute53: !Not
- !Equals
- !Ref HostedZoneId
- ''
Resources:
ECSService:
Type: "AWS::ECS::Service"
DependsOn: LoadBalancer
Properties:
Cluster:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSClusterName"
CapacityProviderStrategy:
- CapacityProvider: "FARGATE"
Base: 0
Weight: 1
TaskDefinition: !Ref TaskDefinition
ServiceName: !Sub ${Environment}-${ServiceName}
SchedulingStrategy: "REPLICA"
DesiredCount: !Ref TaskDesiredCount
AvailabilityZoneRebalancing: "ENABLED"
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: "ENABLED"
SecurityGroups:
- !Ref SecurityGroup
Subnets: !Ref SubnetIDs
PlatformVersion: "LATEST"
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DeploymentCircuitBreaker:
Enable: true
Rollback: true
DeploymentController:
Type: "ECS"
ServiceConnectConfiguration:
Enabled: false
ServiceRegistries:
- RegistryArn: !GetAtt
- "ServiceDiscoveryService"
- "Arn"
Tags:
- Key: app
Value: onyx
- Key: service
Value: !Ref ServiceName
- Key: env
Value: !Ref Environment
EnableECSManagedTags: true
LoadBalancers:
- ContainerName: nginx
ContainerPort: 80
TargetGroupArn: !Ref TargetGroup
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${Environment}-${ServiceName}-TaskDefinition
ContainerDefinitions:
- Name: nginx
Image: nginx:1.23.4-alpine
Cpu: 0
PortMappings:
- Name: nginx-80-tcp
ContainerPort: 80
HostPort: 80
Protocol: tcp
Essential: true
Command:
- /bin/sh
- -c
- dos2unix /etc/nginx/conf.d/run-nginx.sh && /etc/nginx/conf.d/run-nginx.sh app.conf.template.dev
Environment:
- Name: EMAIL
Value: ""
- Name: DOMAIN
Value: !Ref DomainName
- Name: ONYX_BACKEND_API_HOST
Value: !Sub ${Environment}-${OnyxBackendApiServiceName}.${OnyxNamespace}
- Name: ONYX_WEB_SERVER_HOST
Value: !Sub ${Environment}-${OnyxWebServerServiceName}.${OnyxNamespace}
MountPoints:
- SourceVolume: efs-volume
ContainerPath: /etc/nginx/conf.d
VolumesFrom: []
DependsOn:
- ContainerName: github-sync-container
Condition: SUCCESS
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Sub /ecs/${Environment}-OnyxNginxTaskDefinition
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: 25m
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
SystemControls: []
- Name: github-sync-container
Image: curlimages/curl:latest
Cpu: 128
MemoryReservation: 256
PortMappings: []
Essential: false
Command:
- sh
- -c
- !Sub |
curl -L ${GitHubConfigUrl} -o /etc/nginx/conf.d/app.conf.template.dev &&
curl -L ${GitHubRunScriptUrl} -o /etc/nginx/conf.d/run-nginx.sh &&
chmod 644 /etc/nginx/conf.d/app.conf.template.dev &&
chmod 755 /etc/nginx/conf.d/run-nginx.sh &&
exit 0 || exit 1
MountPoints:
- SourceVolume: efs-volume
ContainerPath: /etc/nginx/conf.d
VolumesFrom: []
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Sub /ecs/${Environment}-github-sync-configs-TaskDefinition
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: 25m
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
SystemControls: []
TaskRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskRole"
ExecutionRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskExecutionRole"
NetworkMode: awsvpc
Volumes:
- Name: efs-volume
EFSVolumeConfiguration:
FilesystemId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-OnyxEfsId"
RootDirectory: /
PlacementConstraints: []
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
EnableFaultInjection: false
SecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: !Sub "Security group for ${ServiceName}"
GroupName: !Sub ${Environment}-ecs-${ServiceName}
VpcId: !Ref VpcID
SecurityGroupIngress:
- FromPort: 80
ToPort: 80
IpProtocol: "tcp"
CidrIp: "0.0.0.0/0"
- FromPort: 80
ToPort: 80
IpProtocol: "tcp"
CidrIpv6: "::/0"
ServiceDiscoveryService:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: !Ref ServiceName
DnsConfig:
DnsRecords:
- Type: "A"
TTL: 15
NamespaceId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespace"
HealthCheckCustomConfig:
FailureThreshold: 1
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
DependsOn: SecurityGroup
Properties:
Type: application
Scheme: internet-facing
Subnets: !Ref SubnetIDs
SecurityGroups:
- !Ref SecurityGroup
LoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref LoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckEnabled: True
HealthCheckIntervalSeconds: 30
HealthCheckPort: 80
HealthCheckPath: /api/health
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 20
HealthyThresholdCount: 3
Port: 80
Protocol: HTTP
ProtocolVersion: HTTP1
VpcId: !Ref VpcID
TargetType: ip
Route53Record:
Type: AWS::Route53::RecordSet
Condition: CreateRoute53
Properties:
HostedZoneId: !Ref HostedZoneId
Name: !Ref DomainName
Type: A
AliasTarget:
DNSName: !GetAtt LoadBalancer.DNSName
HostedZoneId: !GetAtt LoadBalancer.CanonicalHostedZoneID
EvaluateTargetHealth: false
Outputs:
ECSService:
Description: "The created service."
Value: !Ref "ECSService"
ServiceDiscoveryService:
Value: !Ref "ServiceDiscoveryService"
OutputOnyxLoadBalancerDNSName:
Description: LoadBalancer DNSName
Value: !GetAtt LoadBalancer.DNSName
Export:
Name: !Sub ${AWS::StackName}-OnyxLoadBalancerDNSName

View File

@@ -0,0 +1,177 @@
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
Environment:
Type: String
Default: production
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
ServiceName:
Type: String
Default: onyx-postgres
TaskCpu:
Type: String
Default: "1024"
TaskMemory:
Type: String
Default: "2048"
TaskDesiredCount:
Type: Number
Default: 1
Resources:
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSClusterName"
CapacityProviderStrategy:
- CapacityProvider: FARGATE
Base: 0
Weight: 1
TaskDefinition: !Ref TaskDefinition
ServiceName: !Sub ${Environment}-${ServiceName}-service
SchedulingStrategy: REPLICA
DesiredCount: !Ref TaskDesiredCount
AvailabilityZoneRebalancing: DISABLED
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- !Ref SecurityGroup
Subnets: !Ref SubnetIDs
PlatformVersion: LATEST
DeploymentConfiguration:
MaximumPercent: 100
MinimumHealthyPercent: 0
DeploymentCircuitBreaker:
Enable: true
Rollback: true
DeploymentController:
Type: ECS
ServiceConnectConfiguration:
Enabled: false
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscoveryService.Arn
Tags:
- Key: app
Value: onyx
- Key: service
Value: !Ref ServiceName
- Key: env
Value: !Ref Environment
EnableECSManagedTags: true
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub Onyx SecurityGroup access to EFS mount and ${ServiceName}.
GroupName: !Sub ${Environment}-${ServiceName}
VpcId: !Ref VpcID
SecurityGroupIngress:
- FromPort: 5432
ToPort: 5432
IpProtocol: tcp
CidrIp: 0.0.0.0/0
- FromPort: 5432
ToPort: 5432
IpProtocol: tcp
CidrIpv6: "::/0"
- FromPort: 2049
ToPort: 2049
IpProtocol: tcp
SourceSecurityGroupId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-EFSSecurityGroupMountTargets"
ServiceDiscoveryService:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: !Sub ${Environment}-${ServiceName}-service
DnsConfig:
DnsRecords:
- Type: "A"
TTL: 15
NamespaceId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespace"
HealthCheckCustomConfig:
FailureThreshold: 1
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${Environment}-${ServiceName}-TaskDefinition
TaskRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskRole"
ExecutionRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskExecutionRole"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
RuntimePlatform:
CpuArchitecture: ARM64
OperatingSystemFamily: LINUX
Volumes:
- Name: efs-volume-data
EFSVolumeConfiguration:
FilesystemId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-OnyxEfsId"
RootDirectory: "/"
TransitEncryption: ENABLED
AuthorizationConfig:
AccessPointId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-PostgresDataEfsAccessPoint"
ContainerDefinitions:
- Name: !Ref ServiceName
Image: postgres:15.2-alpine
Cpu: 0
Essential: true
StopTimeout: 30
Command:
- "-c"
- "max_connections=250"
PortMappings:
- Name: postgres
ContainerPort: 5432
HostPort: 5432
Protocol: tcp
AppProtocol: http
Environment:
- Name: POSTGRES_USER
Value: postgres
- Name: PGSSLMODE
Value: require
- Name: POSTGRES_DB
Value: postgres
Secrets:
- Name: POSTGRES_PASSWORD
ValueFrom: !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Environment}/postgres/user/password
MountPoints:
- SourceVolume: efs-volume-data
ContainerPath: /var/lib/postgresql/data
ReadOnly: false
- SourceVolume: efs-volume-data
ContainerPath: /var/lib/postgresql
ReadOnly: false
User: "1000"
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: /ecs/OnyxPostgresTaskDefinition
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: "25m"
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs

View File

@@ -0,0 +1,146 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for Onyx Redis TaskDefinition
Parameters:
Environment:
Type: String
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
ServiceName:
Type: String
Default: onyx-redis
TaskCpu:
Type: String
Default: "1024"
TaskMemory:
Type: String
Default: "2048"
TaskDesiredCount:
Type: Number
Default: 1
Resources:
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSClusterName"
CapacityProviderStrategy:
- CapacityProvider: FARGATE
Base: 0
Weight: 1
TaskDefinition: !Ref TaskDefinition
ServiceName: !Sub ${Environment}-${ServiceName}-service
SchedulingStrategy: REPLICA
DesiredCount: !Ref TaskDesiredCount
AvailabilityZoneRebalancing: ENABLED
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- Ref: SecurityGroup
Subnets: !Ref SubnetIDs
PlatformVersion: LATEST
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DeploymentCircuitBreaker:
Enable: true
Rollback: true
DeploymentController:
Type: ECS
ServiceConnectConfiguration:
Enabled: false
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscoveryService.Arn
Tags:
- Key: app
Value: onyx
- Key: service
Value: !Ref ServiceName
- Key: env
Value: !Ref Environment
EnableECSManagedTags: true
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub Onyx SecurityGroup access to EFS mount and ${ServiceName}.
GroupName: !Sub ${Environment}-ecs-${ServiceName}
VpcId: !Ref VpcID
SecurityGroupIngress:
- FromPort: 6379
ToPort: 6379
IpProtocol: tcp
CidrIp: 0.0.0.0/0
- FromPort: 6379
ToPort: 6379
IpProtocol: tcp
CidrIpv6: "::/0"
ServiceDiscoveryService:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: !Sub ${Environment}-${ServiceName}-service
DnsConfig:
DnsRecords:
- Type: "A"
TTL: 15
NamespaceId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespace"
HealthCheckCustomConfig:
FailureThreshold: 1
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${Environment}-${ServiceName}-TaskDefinition
TaskRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskRole"
ExecutionRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskExecutionRole"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
RuntimePlatform:
CpuArchitecture: ARM64
OperatingSystemFamily: LINUX
ContainerDefinitions:
- Name: redis
Image: redis:7.4-alpine
Cpu: 0
Essential: true
Command:
- "redis-server"
- "--save"
- "\"\""
- "--appendonly"
- "no"
PortMappings:
- Name: redis_port
ContainerPort: 6379
HostPort: 6379
Protocol: tcp
AppProtocol: http
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Sub /ecs/${Environment}-${ServiceName}
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: "25m"
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
Environment: []
VolumesFrom: []
SystemControls: []

View File

@@ -0,0 +1,190 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for Onyx Vespa Engine TaskDefinition
Parameters:
Environment:
Type: String
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
ServiceName:
Type: String
Default: onyx-vespaengine
TaskCpu:
Type: String
Default: "4096"
TaskMemory:
Type: String
Default: "16384"
TaskDesiredCount:
Type: Number
Default: 1
Resources:
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSClusterName"
CapacityProviderStrategy:
- CapacityProvider: FARGATE
Base: 0
Weight: 1
TaskDefinition: !Ref TaskDefinition
ServiceName: !Sub ${Environment}-${ServiceName}-service
SchedulingStrategy: REPLICA
DesiredCount: !Ref TaskDesiredCount
AvailabilityZoneRebalancing: ENABLED
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- Ref: SecurityGroup
Subnets: !Ref SubnetIDs
PlatformVersion: LATEST
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DeploymentCircuitBreaker:
Enable: true
Rollback: true
DeploymentController:
Type: ECS
ServiceConnectConfiguration:
Enabled: false
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscoveryService.Arn
Tags:
- Key: app
Value: onyx
- Key: service
Value: !Ref ServiceName
- Key: env
Value: !Ref Environment
EnableECSManagedTags: true
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub Onyx SecurityGroup access to EFS mount and ${ServiceName}.
GroupName: !Sub ${Environment}-ecs-${ServiceName}
VpcId: !Ref VpcID
SecurityGroupIngress:
- FromPort: 19071
ToPort: 19071
IpProtocol: tcp
CidrIp: 0.0.0.0/0
- FromPort: 19071
ToPort: 19071
IpProtocol: tcp
CidrIpv6: "::/0"
- FromPort: 8081
ToPort: 8081
IpProtocol: tcp
CidrIp: 0.0.0.0/0
- FromPort: 8081
ToPort: 8081
IpProtocol: tcp
CidrIpv6: "::/0"
- FromPort: 2049
ToPort: 2049
IpProtocol: tcp
SourceSecurityGroupId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-EFSSecurityGroupMountTargets"
ServiceDiscoveryService:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: !Sub ${Environment}-${ServiceName}-service
DnsConfig:
DnsRecords:
- Type: "A"
TTL: 15
NamespaceId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespace"
HealthCheckCustomConfig:
FailureThreshold: 1
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${Environment}-${ServiceName}-TaskDefinition
TaskRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskRole"
ExecutionRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskExecutionRole"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
RuntimePlatform:
CpuArchitecture: ARM64
OperatingSystemFamily: LINUX
ContainerDefinitions:
- Name: vespaengine
Image: vespaengine/vespa:8.277.17
Cpu: 0
Essential: true
PortMappings:
- Name: vespaengine_port
ContainerPort: 19071
HostPort: 19071
Protocol: tcp
AppProtocol: http
- Name: vespaengine_port2
ContainerPort: 8081
HostPort: 8081
Protocol: tcp
AppProtocol: http
MountPoints:
- SourceVolume: efs-volume-data
ContainerPath: /opt/vespa/var
ReadOnly: false
- SourceVolume: efs-volume-tmp
ContainerPath: /var/tmp
ReadOnly: false
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: /ecs/OnyxVespaEngineTaskDefinition
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: "25m"
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
User: "1000"
Environment: []
VolumesFrom: []
SystemControls: []
Volumes:
- Name: efs-volume-tmp
EFSVolumeConfiguration:
FilesystemId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-OnyxEfsId"
RootDirectory: "/"
TransitEncryption: ENABLED
AuthorizationConfig:
AccessPointId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-VespaEngineTmpEfsAccessPoint"
- Name: efs-volume-data
EFSVolumeConfiguration:
FilesystemId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-OnyxEfsId"
RootDirectory: "/"
TransitEncryption: ENABLED
AuthorizationConfig:
AccessPointId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-efs-VespaEngineDataEfsAccessPoint"

View File

@@ -0,0 +1,190 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for Onyx Web Server TaskDefinition
Parameters:
Environment:
Type: String
SubnetIDs:
Type: CommaDelimitedList
Description: "Comma-delimited list of at least two subnet IDs in different Availability Zones"
VpcID:
Type: String
Default: vpc-098cfa79d637dabff
ServiceName:
Type: String
Default: onyx-web-server
TaskCpu:
Type: String
Default: "1024"
TaskMemory:
Type: String
Default: "2048"
TaskDesiredCount:
Type: Number
Default: 1
Resources:
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSClusterName"
CapacityProviderStrategy:
- CapacityProvider: FARGATE
Base: 0
Weight: 1
TaskDefinition: !Ref TaskDefinition
ServiceName: !Sub ${Environment}-${ServiceName}-service
SchedulingStrategy: REPLICA
DesiredCount: !Ref TaskDesiredCount
AvailabilityZoneRebalancing: ENABLED
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- Ref: SecurityGroup
Subnets: !Ref SubnetIDs
PlatformVersion: LATEST
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DeploymentCircuitBreaker:
Enable: true
Rollback: true
DeploymentController:
Type: ECS
ServiceConnectConfiguration:
Enabled: false
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscoveryService.Arn
Tags:
- Key: app
Value: onyx
- Key: service
Value: !Ref ServiceName
- Key: env
Value: !Ref Environment
EnableECSManagedTags: true
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub Onyx SecurityGroup access to EFS mount and ${ServiceName}.
GroupName: !Sub ${Environment}-ecs-${ServiceName}
VpcId: !Ref VpcID
SecurityGroupIngress:
- FromPort: 3000
ToPort: 3000
IpProtocol: tcp
CidrIp: 0.0.0.0/0
- FromPort: 3000
ToPort: 3000
IpProtocol: tcp
CidrIpv6: "::/0"
ServiceDiscoveryService:
Type: "AWS::ServiceDiscovery::Service"
Properties:
Name: !Sub ${Environment}-${ServiceName}-service
DnsConfig:
DnsRecords:
- Type: "A"
TTL: 15
NamespaceId:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespace"
HealthCheckCustomConfig:
FailureThreshold: 1
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${Environment}-${ServiceName}-TaskDefinition
TaskRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskRole"
ExecutionRoleArn:
Fn::ImportValue:
Fn::Sub: "${Environment}-onyx-cluster-ECSTaskExecutionRole"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
RuntimePlatform:
CpuArchitecture: ARM64
OperatingSystemFamily: LINUX
ContainerDefinitions:
- Name: onyx-webserver
Image: onyxdotapp/onyx-web-server:latest
Cpu: 0
Essential: true
PortMappings:
- Name: webserver
ContainerPort: 3000
HostPort: 3000
Protocol: tcp
Environment:
- Name: NEXT_PUBLIC_DISABLE_STREAMING
Value: "false"
- Name: NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA
Value: "false"
- Name: INTERNAL_URL
Value: !Sub
- "http://${Environment}-onyx-backend-api-server-service.${ImportedNamespace}:8080"
- ImportedNamespace: !ImportValue
Fn::Sub: "${Environment}-onyx-cluster-OnyxNamespaceName"
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Sub /ecs/${Environment}-${ServiceName}
mode: non-blocking
awslogs-create-group: "true"
max-buffer-size: "25m"
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
User: "1000"
VolumesFrom: []
SystemControls: []
ECSAutoScalingTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn: ECSService
Properties:
MaxCapacity: 5
MinCapacity: 1
ResourceId: !Sub
- "service/${ImportedCluster}/${Environment}-${ServiceName}-service"
- ImportedCluster: !ImportValue
'Fn::Sub': "${Environment}-onyx-cluster-ECSClusterName"
ServiceName: !Ref ServiceName
Environment: !Ref Environment
ScalableDimension: ecs:service:DesiredCount
ServiceNamespace: ecs
ECSAutoScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: !Sub ${Environment}-${ServiceName}-service-cpu-scaleout
ScalingTargetId: !Ref ECSAutoScalingTarget
PolicyType: TargetTrackingScaling
TargetTrackingScalingPolicyConfiguration:
TargetValue: 75
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageCPUUtilization
ScaleOutCooldown: 60
ScaleInCooldown: 60
ECSAutoScalingPolicyMemory:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: !Sub ${Environment}-${ServiceName}-service-memory-scaleout
ScalingTargetId: !Ref ECSAutoScalingTarget
PolicyType: TargetTrackingScaling
TargetTrackingScalingPolicyConfiguration:
TargetValue: 80
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageMemoryUtilization
ScaleOutCooldown: 60
ScaleInCooldown: 60

View File

@@ -0,0 +1,76 @@
#!/bin/bash
AWS_REGION="${AWS_REGION:-us-west-1}"
# Reference to consolidated config
CONFIG_FILE="onyx_config.json"
# Get environment from config file
ENVIRONMENT=$(jq -r '.Environment' "$CONFIG_FILE")
if [ -z "$ENVIRONMENT" ] || [ "$ENVIRONMENT" == "null" ]; then
echo "Missing Environment in $CONFIG_FILE. Please add the Environment field."
exit 1
fi
# Try to get S3_BUCKET from config, fallback to default if not found
S3_BUCKET_FROM_CONFIG=$(jq -r '.S3Bucket // empty' "$CONFIG_FILE")
if [ -n "$S3_BUCKET_FROM_CONFIG" ]; then
S3_BUCKET="$S3_BUCKET_FROM_CONFIG"
else
S3_BUCKET="${S3_BUCKET:-onyx-ecs-fargate-configs}"
fi
STACK_NAMES=(
"${ENVIRONMENT}-onyx-nginx-service"
"${ENVIRONMENT}-onyx-web-server-service"
"${ENVIRONMENT}-onyx-backend-background-server-service"
"${ENVIRONMENT}-onyx-backend-api-server-service"
"${ENVIRONMENT}-onyx-model-server-inference-service"
"${ENVIRONMENT}-onyx-model-server-indexing-service"
"${ENVIRONMENT}-onyx-vespaengine-service"
"${ENVIRONMENT}-onyx-redis-service"
"${ENVIRONMENT}-onyx-postgres-service"
"${ENVIRONMENT}-onyx-cluster"
"${ENVIRONMENT}-onyx-acm"
"${ENVIRONMENT}-onyx-efs"
)
delete_stack() {
local stack_name=$1
if [ "$stack_name" == "${ENVIRONMENT}-onyx-cluster" ]; then
echo "Removing all objects and directories from the onyx config s3 bucket."
aws s3 rm "s3://${ENVIRONMENT}-${S3_BUCKET}" --recursive
sleep 5
fi
echo "Checking if stack $stack_name exists..."
if aws cloudformation describe-stacks --stack-name "$stack_name" --region "$AWS_REGION" > /dev/null 2>&1; then
echo "Deleting stack: $stack_name..."
aws cloudformation delete-stack \
--stack-name "$stack_name" \
--region "$AWS_REGION"
echo "Waiting for stack $stack_name to be deleted..."
aws cloudformation wait stack-delete-complete \
--stack-name "$stack_name" \
--region "$AWS_REGION"
if [ $? -eq 0 ]; then
echo "Stack $stack_name deleted successfully."
sleep 10
else
echo "Failed to delete stack $stack_name. Exiting."
exit 1
fi
else
echo "Stack $stack_name does not exist, skipping."
return 0
fi
}
for stack_name in "${STACK_NAMES[@]}"; do
delete_stack "$stack_name"
done
echo "All stacks deleted successfully."

View File

@@ -31,11 +31,11 @@ upstream api_server {
# for a TCP configuration
# TODO: use gunicorn to manage multiple processes
server api_server:8080 fail_timeout=0;
server ${ONYX_BACKEND_API_HOST}:8080 fail_timeout=0;
}
upstream web_server {
server web_server:3000 fail_timeout=0;
server ${ONYX_WEB_SERVER_HOST}:3000 fail_timeout=0;
}
server {

View File

@@ -1,4 +1,4 @@
# Override log format to include request latency
# Log format to include request latency
log_format custom_main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
@@ -13,11 +13,11 @@ upstream api_server {
# for a TCP configuration
# TODO: use gunicorn to manage multiple processes
server api_server:8080 fail_timeout=0;
server ${ONYX_BACKEND_API_HOST}:8080 fail_timeout=0;
}
upstream web_server {
server web_server:3000 fail_timeout=0;
server ${ONYX_WEB_SERVER_HOST}:3000 fail_timeout=0;
}
server {
@@ -66,5 +66,5 @@ server {
proxy_redirect off;
proxy_pass http://web_server;
}
}
}

View File

@@ -1,5 +1,8 @@
# fill in the template
envsubst '$DOMAIN $SSL_CERT_FILE_NAME $SSL_CERT_KEY_FILE_NAME' < "/etc/nginx/conf.d/$1" > /etc/nginx/conf.d/app.conf
ONYX_BACKEND_API_HOST="${ONYX_BACKEND_API_HOST:-api_server}"
ONYX_WEB_SERVER_HOST="${ONYX_WEB_SERVER_HOST:-web_server}"
envsubst '$DOMAIN $SSL_CERT_FILE_NAME $SSL_CERT_KEY_FILE_NAME $ONYX_BACKEND_API_HOST $ONYX_WEB_SERVER_HOST' < "/etc/nginx/conf.d/$1" > /etc/nginx/conf.d/app.conf
# wait for the api_server to be ready
echo "Waiting for API server to boot up; this may take a minute or two..."
@@ -10,7 +13,7 @@ echo
while true; do
# Use curl to send a request and capture the HTTP status code
status_code=$(curl -o /dev/null -s -w "%{http_code}\n" "http://api_server:8080/health")
status_code=$(curl -o /dev/null -s -w "%{http_code}\n" "http://${ONYX_BACKEND_API_HOST}:8080/health")
# Check if the status code is 200
if [ "$status_code" -eq 200 ]; then