Fargate Container

Overview Infrastructure

overview

We have three components:

  1. A VPC for the container to run: Stack vpc
  2. A DynamodDB Table to provide some data: Stack table
  3. An Application Load Balances fargate container: Stack container

The components are decoupled with the AWS Systems Manager (SSM) Parameter Store. You could create all within one CDK App. But when you couple the CDK stacks together, deployment from stak A clould automatically deploy a dependent Stack B.

Most of the time that is OK, but sometimes you do not want the dependent stack automatically deployed. An example would be an EC2 instance stack, where the AMI of the instances is dynamically created. If the next time you deploy another stack, the EC2 instance stack would terminate the instances, because the AMI has changed, if there is a new AMI, e.g. of Amazon Linux.

So I decouple the stacks with the SSM Parameter Store.

  • the VPC Stack writes the VPC ID into /go-on-aws/vpc
	vpcParm := "/go-on-aws/vpc"
	awsssm.NewStringParameter(stack, &vpcParm,
		&awsssm.StringParameterProps{
			AllowedPattern: new(string),
			Description:    aws.String("VPC id go on aws architecture"),
			ParameterName:  &vpcParm,
			StringValue:    vpc.VpcId(),
		})

To communicate with the ECS service from a private subnet, the vpc Stack is deployed with a NAT gateway. This costs 30$…40$ a month.

See infra/1-vpc/vpc.go.

  • the table uses /go-on-aws/table This value is also read by the application itself
func GetTableName(client *ssm.Client) *string {
	parms := &ssm.GetParameterInput{
		Name: aws.String("/go-on-aws/table"),
	}
	resp, err := client.GetParameter(context.TODO(), parms)
	if err != nil {
		panic("ssm error, " + err.Error())
	}
	value := resp.Parameter.Value
	return value
}

See app/parameter.go.

Overview App

The app uses the Gin web framework.

The container authentices with a basic web authentication:

	basicAuth := gin.BasicAuth(gin.Accounts{
        "go-on-aws": "hugo2021",
    })

Therefore the health check of the load balancer has to interpret “401 Unauthorized” as healthy:

	// 401 Unauthorized
	stethoscope := albv2.HealthCheck{
		Enabled:          aws.Bool(true),
		HealthyHttpCodes: aws.String("200,401"),
	}

	service.TargetGroup().ConfigureHealthCheck(&stethoscope)

See infra/3-container/fargate.go.

Then a request /query is routed to a query function. This query calls Scan on dynamob.

sequenceDiagram participant main participant query main->>query: showtable.Query query->>parameter: GetTableName activate query query->>query: QueryDDB query->>DynamoDB: scan deactivate query

Installation

Prequesites

Have docker running.

Create and distribute Application

task build-app

This will build the app for target Linux with:

CGO_ENABLED=0  GOOS=linux GOARCH=amd64 go build -o ../dist/dosshow -ldflags '-w' main/main.go

And copies the binary together with some static assets like the html and css files to a “dist” distribution directory. The CDK will call docker to build an image from the dist directory.

Create Infrastructure

Export Account number for CDK

Get Account number:

aws sts get-caller-identity

Export as CDK_DEFAULT_ACCOUNT

export CDK_DEFAULT_ACCOUNT=555555555555

Replace the number with your account number.

Now you can call the tasks from the base directory, which is architectures/container from the github repository.

1) VPC

task deploy-vpc

Calls an deploy inside directory infra/1-vpc

2) Dynamodb Table

task deploy-table

Calls an deploy inside directory infra/2-table

3) Container

task deploy-container

Calls an deploy inside directory infra/3-container

Call Website

From the output of the fargate Service:

Cluster 


 ✅  cluster

Outputs:
cluster.ALBFargoServiceLoadBalancerDNSD5AE4891 = clust-ALBFa-15F1YQU1QRKTS-498204716.eu-central-1.elb.amazonaws.com
cluster.ALBFargoServiceServiceURL4147A41A = http://clust-ALBFa-15F1YQU1QRKTS-498204716.eu-central-1.elb.amazonaws.com
cluster.LoadBalancerDNS = clust-ALBFa-15F1YQU1QRKTS-498204716.eu-central-1.elb.amazonaws.com

Stack ARN:
arn:aws:cloudformation:eu-central-1:669453403305:stack/cluster/409e7160-545d-11ec-a1b4-06686f469054

Call the cluster.ALBFargoServiceServiceURL… to get the password field. Use the credentials from app/main/main.go.

Do not hardcode credentials in any app. This is just for educational purposes and is not meant to be used in production.

You could get the credentials from an encrypted Systems Manager Parameter.

To see data, you hav to put entries in the created DynamoDB.

Cleanup

Reverse order

task destroy-container
task destroy-table
task destroy-vpc

See also

Source

See the full source on github.

Sources