nice-appointment-99109
11/14/2024, 11:36 AMpackage application
import (
"fmt"
"strings"
"<http://github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ecs|github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ecs>"
ecsx "<http://github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ecs|github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ecs>"
lbx "<http://github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/lb|github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/lb>"
"<http://github.com/pulumi/pulumi/sdk/v3/go/pulumi|github.com/pulumi/pulumi/sdk/v3/go/pulumi>"
"<http://github.com/pulumi/pulumi/sdk/v3/go/pulumi/config|github.com/pulumi/pulumi/sdk/v3/go/pulumi/config>"
)
func DeployAndRunApplicationImages(ctx *pulumi.Context) error {
stackRef, err := pulumi.NewStackReference(ctx, fmt.Sprintf("organization/application/%s", ctx.Stack()), &pulumi.StackReferenceArgs{})
if err != nil {
return err
}
repoURIs := stackRef.GetOutput(pulumi.String("repositoryURIs"))
repos := repoURIs.ApplyT(func(val any) map[string]string {
output := make(map[string]string)
for k, v := range val.(map[string]any) {
output[k] = v.(string)
}
return output
}).(pulumi.StringMapOutput)
lbBackend, err := lbx.NewApplicationLoadBalancer(ctx, "application-app-lb-backend", &lbx.ApplicationLoadBalancerArgs{
Name: pulumi.String("application-app-lb-backend"),
DefaultTargetGroupPort: <http://pulumi.Int|pulumi.Int>(8080),
})
if err != nil {
return err
}
lbFrontend, err := lbx.NewApplicationLoadBalancer(ctx, "application-app-lb-frontend", &lbx.ApplicationLoadBalancerArgs{
Name: pulumi.String("application-app-lb-frontend"),
DefaultTargetGroupPort: <http://pulumi.Int|pulumi.Int>(3000),
})
if err != nil {
return err
}
cluster, err := ecs.NewCluster(ctx, "application-app-cluster", &ecs.ClusterArgs{
Name: pulumi.String("application-app-cluster"),
})
if err != nil {
return err
}
imageUrlBackend := pulumi.Sprintf("%s:%s", repos.MapIndex(pulumi.String("ecr-core-backend")), "v0.0.3")
imageUrlDB := pulumi.Sprintf("%s:%s", repos.MapIndex(pulumi.String("ecr-core-postgres")), "v0.0.2")
imageUrlFrontend := pulumi.Sprintf("%s:%s", repos.MapIndex(pulumi.String("ecr-core-frontend")), "v0.0.1")
imageUrlKafka := pulumi.Sprintf("%s:%s", repos.MapIndex(pulumi.String("ecr-core-redpanda")), "v0.0.2")
c := config.New(ctx, "application")
pgUser := c.RequireSecret("application_pg_user")
pgPass := c.RequireSecret("application_pg_pass")
pgDb := c.RequireSecret("application_pg_db")
_, err = ecsx.NewFargateService(ctx, "application-app-fargate", &ecsx.FargateServiceArgs{
Name: pulumi.String("application-app-fargate"),
Cluster: cluster.Arn,
DesiredCount: <http://pulumi.Int|pulumi.Int>(1),
AssignPublicIp: pulumi.Bool(true),
TaskDefinitionArgs: &ecsx.FargateServiceTaskDefinitionArgs{
Volumes: ecs.TaskDefinitionVolumeArray{
ecs.TaskDefinitionVolumeArgs{
Name: pulumi.String("application-app-volume"),
},
// ecs.TaskDefinitionVolumeArgs{
// Name: pulumi.String("application-app-db"),
// },
},
Containers: map[string]ecsx.TaskDefinitionContainerDefinitionArgs{
"application-app-backend": {
Name: pulumi.String("application-app-backend"),
Image: imageUrlBackend,
Cpu: <http://pulumi.Int|pulumi.Int>(128),
Memory: <http://pulumi.Int|pulumi.Int>(512),
Essential: pulumi.Bool(true),
// HealthCheck: ecsx.TaskDefinitionHealthCheckArgs{
// Command: pulumi.StringArray{
// pulumi.String("CMD-SHELL"),
// pulumi.String("curl -f <http://127.0.0.1:8080/metrics>"),
// },
// Interval: <http://pulumi.Int|pulumi.Int>(15),
// Retries: <http://pulumi.Int|pulumi.Int>(3),
// StartPeriod: <http://pulumi.Int|pulumi.Int>(5),
// Timeout: <http://pulumi.Int|pulumi.Int>(5),
// },
DependsOn: ecsx.TaskDefinitionContainerDependencyArray{
ecsx.TaskDefinitionContainerDependencyArgs{
ContainerName: pulumi.String("application-app-db"),
Condition: pulumi.String("HEALTHY"),
},
},
Environment: ecsx.TaskDefinitionKeyValuePairArray{
ecsx.TaskDefinitionKeyValuePairArgs{
Name: pulumi.Sprintf("DB"),
Value: pulumi.Sprintf("<postgres://%s:%s@127.0.0.1:5432/%s?sslmode=disable>", pgUser, pgPass, pgDb),
},
ecsx.TaskDefinitionKeyValuePairArgs{
Name: pulumi.Sprintf("APPLICATION_ALLOWED_ORIGINS"),
Value: lbBackend.LoadBalancer.DnsName().ApplyT(func(val string) string {
// Replacing the secret might not be needed.
modifiedDnsName := strings.Replace(val, "[secret]", "application", 1)
return fmt.Sprintf("<http://%s:%d>", modifiedDnsName, 3000)
}).(pulumi.StringOutput),
},
},
PortMappings: ecsx.TaskDefinitionPortMappingArray{
&ecsx.TaskDefinitionPortMappingArgs{
ContainerPort: <http://pulumi.Int|pulumi.Int>(8080),
TargetGroup: lbBackend.DefaultTargetGroup,
},
},
MountPoints: ecsx.TaskDefinitionMountPointArray{
&ecsx.TaskDefinitionMountPointArgs{
SourceVolume: pulumi.String("application-app-volume"),
ContainerPath: pulumi.String("/application"),
ReadOnly: pulumi.Bool(false),
},
},
},
"application-app-frontend": {
Name: pulumi.String("application-app-frontend"),
Image: imageUrlFrontend,
Cpu: <http://pulumi.Int|pulumi.Int>(128),
Memory: <http://pulumi.Int|pulumi.Int>(512),
Essential: pulumi.Bool(true),
// HealthCheck: ecsx.TaskDefinitionHealthCheckArgs{
// Command: pulumi.StringArray{
// pulumi.String("CMD-SHELL"),
// pulumi.String("curl -f <http://127.0.0.1:3000>"),
// },
// Interval: <http://pulumi.Int|pulumi.Int>(15),
// Retries: <http://pulumi.Int|pulumi.Int>(3),
// StartPeriod: <http://pulumi.Int|pulumi.Int>(5),
// Timeout: <http://pulumi.Int|pulumi.Int>(5),
// },
DependsOn: ecsx.TaskDefinitionContainerDependencyArray{
ecsx.TaskDefinitionContainerDependencyArgs{
ContainerName: pulumi.String("application-app-db"),
Condition: pulumi.String("HEALTHY"),
},
},
Environment: ecsx.TaskDefinitionKeyValuePairArray{
ecsx.TaskDefinitionKeyValuePairArgs{
Name: pulumi.String("APPLICATION_BACKEND_URL"),
Value: pulumi.Sprintf("<http://%s:%d/v1>", lbBackend.LoadBalancer.DnsName(), 8080),
},
},
PortMappings: ecsx.TaskDefinitionPortMappingArray{
&ecsx.TaskDefinitionPortMappingArgs{
TargetGroup: lbFrontend.DefaultTargetGroup,
ContainerPort: <http://pulumi.Int|pulumi.Int>(3000),
},
},
},
"application-app-db": {
Name: pulumi.String("application-app-db"),
Image: imageUrlDB,
Cpu: <http://pulumi.Int|pulumi.Int>(1024 * 2),
Memory: <http://pulumi.Int|pulumi.Int>(2048),
Essential: pulumi.Bool(true),
HealthCheck: &ecsx.TaskDefinitionHealthCheckArgs{
Command: pulumi.StringArray{
pulumi.String("CMD-SHELL"),
pulumi.Sprintf("pg_isready -U %s -d %s -h localhost", pgUser, pgDb),
},
Interval: <http://pulumi.Int|pulumi.Int>(15),
Retries: <http://pulumi.Int|pulumi.Int>(3),
StartPeriod: <http://pulumi.Int|pulumi.Int>(10),
Timeout: <http://pulumi.Int|pulumi.Int>(5),
},
Environment: ecsx.TaskDefinitionKeyValuePairArray{
ecsx.TaskDefinitionKeyValuePairArgs{
Name: pulumi.String("POSTGRES_USER"),
Value: pgUser,
},
ecsx.TaskDefinitionKeyValuePairArgs{
Name: pulumi.String("POSTGRES_PASSWORD"),
Value: pgPass,
},
ecsx.TaskDefinitionKeyValuePairArgs{
Name: pulumi.String("POSTGRES_DB"),
Value: pgDb,
},
},
PortMappings: ecsx.TaskDefinitionPortMappingArray{
&ecsx.TaskDefinitionPortMappingArgs{
ContainerPort: <http://pulumi.Int|pulumi.Int>(5432),
},
},
// MountPoints: ecsx.TaskDefinitionMountPointArray{
// &ecsx.TaskDefinitionMountPointArgs{
// SourceVolume: pulumi.String("application-app-db"),
// ContainerPath: pulumi.String("/var/lib/postgresql"),
// ReadOnly: pulumi.Bool(false),
// },
// },
},
"application-app-kafka": {
Name: pulumi.String("application-app-kafka"),
Image: imageUrlKafka,
Cpu: <http://pulumi.Int|pulumi.Int>(1024 * 2),
Memory: <http://pulumi.Int|pulumi.Int>(2048),
Essential: pulumi.Bool(true),
// HealthCheck: &ecsx.TaskDefinitionHealthCheckArgs{
// Command: pulumi.StringArray{
// pulumi.String("CMD-SHELL"),
// pulumi.String("curl -f <http://127.0.0.1:9644/v1/status/ready>"),
// },
// Interval: <http://pulumi.Int|pulumi.Int>(15),
// Retries: <http://pulumi.Int|pulumi.Int>(3),
// StartPeriod: <http://pulumi.Int|pulumi.Int>(10),
// Timeout: <http://pulumi.Int|pulumi.Int>(5),
// },
Environment: ecsx.TaskDefinitionKeyValuePairArray{},
PortMappings: ecsx.TaskDefinitionPortMappingArray{
&ecsx.TaskDefinitionPortMappingArgs{
ContainerPort: <http://pulumi.Int|pulumi.Int>(18081),
},
&ecsx.TaskDefinitionPortMappingArgs{
ContainerPort: <http://pulumi.Int|pulumi.Int>(18082),
},
&ecsx.TaskDefinitionPortMappingArgs{
ContainerPort: <http://pulumi.Int|pulumi.Int>(19092),
},
&ecsx.TaskDefinitionPortMappingArgs{
ContainerPort: <http://pulumi.Int|pulumi.Int>(9644),
},
},
},
"application-app-prometheus": {
Name: pulumi.String("application-app-prometheus"),
Image: pulumi.String("prom/prometheus:v2.55.0@sha256:378f4e03703557d1c6419e6caccf922f96e6d88a530f7431d66a4c4f4b1000fe"),
Cpu: <http://pulumi.Int|pulumi.Int>(1024 * 2),
Memory: <http://pulumi.Int|pulumi.Int>(2048),
Essential: pulumi.Bool(true),
// HealthCheck: &ecsx.TaskDefinitionHealthCheckArgs{
// Command: pulumi.StringArray{
// pulumi.String("CMD-SHELL"),
// pulumi.String("curl -f <http://127.0.0.1:9090>"),
// },
// Interval: <http://pulumi.Int|pulumi.Int>(15),
// Retries: <http://pulumi.Int|pulumi.Int>(3),
// StartPeriod: <http://pulumi.Int|pulumi.Int>(10),
// Timeout: <http://pulumi.Int|pulumi.Int>(5),
// },
Environment: ecsx.TaskDefinitionKeyValuePairArray{},
PortMappings: ecsx.TaskDefinitionPortMappingArray{
&ecsx.TaskDefinitionPortMappingArgs{
ContainerPort: <http://pulumi.Int|pulumi.Int>(9090),
},
},
},
},
},
})
if err != nil {
return err
}
ctx.Export("url-backend", pulumi.Sprintf("<http://%s>", lbBackend.LoadBalancer.DnsName()))
ctx.Export("url-frontend", pulumi.Sprintf("<http://%s>", lbFrontend.LoadBalancer.DnsName()))
return nil
}
Hello 👋,
First time using pulumi and somewhat AWS newbie here. I'm trying to deploy a ECS service with some containers so we can have a simple application running on the cloud. The current state is not final just to learn and get familiar with Pulumi. After setting this up I got a few questions:
• Right now as a workaround I have seperate loadbalancers for the frontend and backend. Is there a way to have a single loadbalancer for both? Really can't find how to implement this with the ecsx package... It should be supported from my understanding.
• Is there a way to have one port exposed to the internet and a different internal port in the container like docker? For example 443 (external) => 4443 (container port)
• Do I handle the repoURIs
in the right way with Apply? I export them as type pulumi.StringMap
. It works just questioning if this is the right way to do it.
• When exporting the URL, in the console it shows [secret] instead of the name (url-frontend : "http://[secret]-app-lb-frontend-12345.eu.elb.amazonaws.com"). Do I need to replace when using it in code? Check the below code snippet. I assume its just the console and I'm overthinking it, just want to be sure.
Value: lbBackend.LoadBalancer.DnsName().ApplyT(func(val string) string {
// Replacing the secret might not be needed.
modifiedDnsName := strings.Replace(val, "[secret]", "application", 1)
return fmt.Sprintf("<http://%s:%d>", modifiedDnsName, 3000)
}).(pulumi.StringOutput),
Thanks for the time, and +1 rep for a pretty solid program. Just pretty steep learning curve, but also suck at AWS so that does not help 🙂.