Skip to content

Commit

Permalink
fix production builds
Browse files Browse the repository at this point in the history
  • Loading branch information
geclos committed Aug 30, 2024
1 parent 363af52 commit 950cded
Show file tree
Hide file tree
Showing 21 changed files with 252 additions and 278 deletions.
1 change: 0 additions & 1 deletion apps/gateway/docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm turbo build --filter="${PROJECT}..."

RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm prune --prod --no-optional
RUN rm -rf ./**/*/src

FROM alpine AS runner

Expand Down
12 changes: 6 additions & 6 deletions apps/gateway/docker/run-production.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ export REDIS_PORT=6379
export REDIS_HOST=redis

# Gateway hostname and port
export GATEWAY_HOSTNAME="0.0.0.0"
export GATEWAY_PORT='8080'
export HOST="0.0.0.0"
export PORT

docker compose run -it \
-p $GATEWAY_PORT:$GATEWAY_PORT \
-p $PORT:$PORT \
-e DATABASE_URL="$DATABASE_URL" \
-e REDIS_HOST="$REDIS_HOST" \
-e GATEWAY_HOSTNAME="$GATEWAY_HOSTNAME" \
-e GATEWAY_PORT="$GATEWAY_PORT" \
gateway dist/server.js -p $GATEWAY_PORT
-e HOST="$HOST" \
-e PORT="$PORT" \
gateway dist/server.js -p $PORT
11 changes: 5 additions & 6 deletions apps/gateway/src/common/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import { z } from 'zod'

const isDev = process.env.NODE_ENV === 'development'
const isTest = process.env.NODE_ENV === 'test'
const hasHardcodedEnv = isDev || isTest

let localEnv = {}
if (hasHardcodedEnv) {
if (isDev || isTest) {
localEnv = {
GATEWAY_HOSTNAME: 'localhost',
GATEWAY_PORT: isTest ? '8788' : '8787',
HOSTNAME: 'localhost',
PORT: isTest ? '8788' : '8787',
}
}

Expand All @@ -23,8 +22,8 @@ export default createEnv({
REDIS_HOST: z.string(),
REDIS_PORT: z.coerce.number().optional(),
REDIS_PASSWORD: z.string().optional(),
GATEWAY_HOSTNAME: z.string().optional().default('localhost'),
GATEWAY_PORT: z.coerce.number().optional(),
HOSTNAME: z.string().default('localhost'),
PORT: z.coerce.number(),
},
runtimeEnv: {
...process.env,
Expand Down
6 changes: 3 additions & 3 deletions apps/gateway/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ serve(
{
fetch: app.fetch,
overrideGlobalObjects: undefined,
port: env.GATEWAY_PORT,
hostname: env.GATEWAY_HOSTNAME,
hostname: env.HOSTNAME,
port: env.PORT,
},
(info) => {
console.log(`Listening on http://${env.GATEWAY_HOSTNAME}:${info.port}`)
console.log(`Listening on http://${env.HOSTNAME}:${info.port}`)
},
)

Expand Down
2 changes: 2 additions & 0 deletions apps/infra/Pulumi.core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ encryptionsalt: v1:K+dTqOgU40c=:v1:xzsAOOiJEEAsdCQ4:Oe7NKHjXdYdZrcrrBa1/0yolY5M3
config:
infra:DATABASE_PASSWORD:
secure: v1:WABt/tJjfsAKMplU:RRLtj5mTu301x4sn2Tr91u4O0Msd3mWVJutcDg==
infra:MAILER_API_KEY:
secure: v1:Br02wGwX0UOAZiNp:wIzQFfWCzWygBRCVJNDs/ZP65EXEAIFhduPOOniN6EOeXPyJ4UHjOefPyO2bhOBkR5E3CWLmQBsVjIGrGwAHZYZCQg==
infra:albSecurityGroup:
secure: v1:HCwWQvcrwQE9Py6E:U5ibuWwH2MNAooASzaHOnSS3pKNhuJHZTh2pnHcSYKRPuuMJ
infra:bastionAccountId:
Expand Down
25 changes: 25 additions & 0 deletions apps/infra/src/core/elasticCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,30 @@ const cacheCluster = new aws.elasticache.Cluster('LatitudeLLMCacheCluster', {
securityGroupIds: [SecurityGroup.id],
})

const queueParameterGroup = new aws.elasticache.ParameterGroup(
'LatitudeLLMQueueParameterGroup',
{
family: 'redis6.x',
description: 'Custom parameter group for queue cluster',
parameters: [
{
name: 'maxmemory-policy',
value: 'noeviction',
},
],
},
)

const queueCluster = new aws.elasticache.Cluster('LatitudeLLMQueueCluster', {
engine: 'redis',
nodeType: 'cache.t3.micro',
numCacheNodes: 1,
port: 6379,
subnetGroupName: subnetGroup.name,
securityGroupIds: [SecurityGroup.id],
parameterGroupName: queueParameterGroup.name,
})

// Export the cluster endpoint and port
export const cacheEndpoint = cacheCluster.cacheNodes[0].address
export const queueEndpoint = queueCluster.cacheNodes[0].address
1 change: 1 addition & 0 deletions apps/infra/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './elasticCache'
export * from './ec2'
export * from './ecs'
export * from './iam'
export * from './secrets'
16 changes: 16 additions & 0 deletions apps/infra/src/core/secrets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as aws from '@pulumi/aws'
import * as pulumi from '@pulumi/pulumi'

const cfg = new pulumi.Config()

const mailerApiKey = new aws.secretsmanager.Secret('MAILER_API_KEY', {
description: 'API key for the mailer service',
name: 'MAILER_API_KEY',
})

new aws.secretsmanager.SecretVersion('MAILER_API_KEY_VERSION', {
secretId: mailerApiKey.id,
secretString: cfg.requireSecret('MAILER_API_KEY'),
})

export const mailerApiKeyArn = mailerApiKey.arn
116 changes: 39 additions & 77 deletions apps/infra/src/deployments/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,107 +10,69 @@ import {
resolve,
vpcId,
} from '../shared'
import { coreStack, dbUrl } from './shared'
import { coreStack, environment } from './shared'

const DNS_ADDRESS = 'gateway.latitude.so'

// Create an ECR repository
const repo = new aws.ecr.Repository('latitude-llm-gateway-repo')

// Build and push the Docker image
const token = await aws.ecr.getAuthorizationToken()
const image = new docker.Image('LatitudeLLMGatewayImage', {
build: {
platform: 'linux/amd64',
context: resolve('../../../'),
dockerfile: resolve('../../../apps/gateway/docker/Dockerfile'),
},
imageName: pulumi.interpolate`${repo.repositoryUrl}:latest`,
registry: repo.registryId.apply(async (registryId) => {
const credentials = await aws.ecr.getCredentials({
registryId,
})
const decodedCredentials = Buffer.from(
credentials.authorizationToken,
'base64',
).toString('ascii')
const [username, password] = decodedCredentials.split(':')
return {
server: credentials.proxyEndpoint,
username,
password: pulumi.secret(password),
}
}),
registry: {
server: repo.repositoryUrl,
username: token.userName,
password: pulumi.secret(token.password),
},
})

// Create a Fargate task definition
const containerName = 'LatitudeLLMGatewayContainer'

// Create the log group
const logGroup = new aws.cloudwatch.LogGroup('LatitudeLLMGatewayLogGroup', {
name: '/ecs/LatitudeLLMGateway',
retentionInDays: 7,
})

const cacheEndpoint = coreStack.requireOutput('cacheEndpoint')
const taskDefinition = cacheEndpoint.apply((cacheEndpoint) =>
dbUrl.apply((dbUrl) =>
logGroup.name.apply(
(logGroupName) =>
new aws.ecs.TaskDefinition('LatitudeLLMGatewayTaskDefinition', {
family: 'LatitudeLLMTaskFamily',
cpu: '256',
memory: '512',
networkMode: 'awsvpc',
requiresCompatibilities: ['FARGATE'],
executionRoleArn: ecsTaskExecutionRole,
containerDefinitions: pulumi
.output(image.imageName)
.apply((imageName) =>
JSON.stringify([
{
name: containerName,
image: imageName,
essential: true,
portMappings: [
{
containerPort: 8080,
hostPort: 8080,
protocol: 'tcp',
},
],
environment: [
{
name: 'DATABASE_URL',
value: dbUrl,
},
{
name: 'REDIS_HOST',
value: cacheEndpoint,
},
{
name: 'GATEWAY_HOSTNAME',
value: '0.0.0.0',
},
{
name: 'GATEWAY_PORT',
value: '8080',
},
],
logConfiguration: {
logDriver: 'awslogs',
options: {
'awslogs-group': logGroupName,
'awslogs-region': 'eu-central-1',
'awslogs-stream-prefix': 'ecs',
},
},
},
]),
),
}),
),
),
)
const taskDefinition = pulumi
.all([logGroup.name, image.imageName, environment])
.apply(
([logGroupName, imageName, environment]) =>
new aws.ecs.TaskDefinition('LatitudeLLMGatewayTaskDefinition', {
family: 'LatitudeLLMTaskFamily',
cpu: '256',
memory: '512',
networkMode: 'awsvpc',
requiresCompatibilities: ['FARGATE'],
executionRoleArn: ecsTaskExecutionRole,
containerDefinitions: JSON.stringify([
{
name: containerName,
image: imageName,
essential: true,
portMappings: [
{ containerPort: 8080, hostPort: 8080, protocol: 'tcp' },
],
environment,
logConfiguration: {
logDriver: 'awslogs',
options: {
'awslogs-group': logGroupName,
'awslogs-region': 'eu-central-1',
'awslogs-stream-prefix': 'ecs',
},
},
},
]),
}),
)

const targetGroup = new aws.lb.TargetGroup('LatitudeLLMGatewayTg', {
port: 8080,
Expand Down
25 changes: 25 additions & 0 deletions apps/infra/src/deployments/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,30 @@ const dbPassword = dbPasswordSecretId.apply((secretId) =>
})
.then((secret) => secret.secretString),
)
const mailerApiKeyArn = coreStack.requireOutput('mailerApiKeyArn')
const cacheEndpoint = coreStack.requireOutput('cacheEndpoint')
const mailerApiKey = mailerApiKeyArn.apply((arn) => {
const secret = aws.secretsmanager.getSecretVersionOutput({
secretId: arn,
})

return secret.secretString
})

export const dbUrl = pulumi.interpolate`postgresql://${dbUsername}:${dbPassword}@${dbEndpoint}/${dbName}?sslmode=verify-full&sslrootcert=/app/packages/core/src/assets/eu-central-1-bundle.pem`
export const environment = pulumi
.all([cacheEndpoint, dbUrl, mailerApiKey])
.apply(() => {
return [
{ name: 'HOSTNAME', value: '0.0.0.0' },
{ name: 'PORT', value: '8080' },
{ name: 'DATABASE_URL', value: dbUrl },
{ name: 'REDIS_HOST', value: cacheEndpoint },
{ name: 'GATEWAY_HOSTNAME', value: 'gateway.latitude.so' },
{ name: 'GATEWAY_SSL', value: 'true' },
{ name: 'LATITUDE_DOMAIN', value: 'latitude.so' },
{ name: 'LATITUDE_URL', value: 'https://app.latitude.so' },
{ name: 'FROM_MAILER_EMAIL', value: '[email protected]' },
{ name: 'MAILER_API_KEY', value: mailerApiKey },
]
})
Loading

0 comments on commit 950cded

Please sign in to comment.