Giter Club home page Giter Club logo

abp-fargate's Introduction

abp-fargate

An aws-blueprint example for a ECS fargate based app, with or without an ELB

Prerequisites

There are a handful of steps necessary prior to executing the below to ensure a smooth sailing adventure as you setup your fargate configuration.

  1. Confirm you have wget on your machine. If you're running on OSX you'll need to install it (brew install wget).

  2. Confirm you have python installed. python --version should produce Python 3.7.2 or greater. AWS CLI isn't well supported on Python 2.x so it's worth noting you should upgrade.

    Assuming OSX:

  3. Confirm pip3 installed too. pip3 --version

    If you see command not found AND installed python through brew, postinstall might not have executed:

    • brew postinstall python3
    • Otherwise check your path to confirm pip3's location is on it.
  4. Install AWS CLI tool

    Once you've installed python and python --version is producing the correct version you can install aws cli:

  5. Since this setup configuration relys on you having an account profile locally, and you might be working with multiple AWS accounts, now is a good time to configure your aws profiles.

    aws configure --profile my-aws-profile-name
    

    This:

    • Will then ask for your AWS Account keys (which you can generate on your IAM account)
  6. Lastly, you need to make sure you've created an S3 bucket for your nested stack configurations.

Setup

  1. Run the setup script from your local git repo dir:

    wget -q https://raw.githubusercontent.com/rynop/abp-fargate/master/bin/setup.sh; bash setup.sh; rm setup.sh
    

    This:

    • Copies this code in this repo to yours
    • Sets NestedStacksS3Bucket and s3 versions of your nested-stacks in your vpc-ecs-cluster and aws-resources .
  2. Update the code to use your go package, by doing an extended find and replace of all occurances of rynop/abp-fargate with your golang package namespace.

  3. Follow Code Specifics below

  4. Define Environment variables below

  5. Create an ECR image repository. Naming convention <git repo name>/<branch>.

    Populate it with an inital image using your updated Dockerfile. Here is an example using your git master branch (run from git repo root):

    awsCliProfileName=default
    gitRepoName=abp-fargate
    ecrRepositoryURI=11111.dkr.ecr.us-east-1.amazonaws.com/abp-fargate/master
    $(aws ecr get-login --no-include-email --region us-east-1 --profile $awsCliProfileName)
    docker build --build-arg CODE_PATH=cmd/example-webservices -t $gitRepoName/master:initial .
    docker tag $gitRepoName/master:initial $ecrRepositoryURI:initial
    docker push $ecrRepositoryURI:initial
    
  6. One time step: Create ECS service linked role. Only need to do this once per AWS account.

    aws iam create-service-linked-role --aws-service-name ecs.amazonaws.com --profile
    
  7. Create an ECS Cluster, follow ECS Cluster Specifics below. Note: if you have multiple Docker services from multiple git repos, you may only have to do this one. See below.

  8. Create a Github user (acct will just be used to read repos for CI/CD), give it read auth to your github repo. Create a personal access token for this user at https://github.com/settings/tokens. This token will be used by the CI/CD to pull code.

  9. Create a CloudFormation stack for your resources (dynamo,s3, etc). You must also define an IAM role for your ECS tasks. Use ./aws/cloudformation/app-resources.yaml. A stack for each of: test, staging and prod. Naming convention [stage]--[repo]--[branch]--[eyecatcher]--r. Ex test--abp-fargate--master--imgManip--r

  10. Set stage specific parameters for each file in ./aws/cloudformation/parameters. The CI/CD (created below) will pass these params to fargate-[with|no]-elb.yaml to create each stage's CloudFormation stack. Param EcsCfClusterStackName is the CloudFormation output value of VpcEcsClusterStackName from step 6 above. You can delete the -elb.yaml file you don't need.

  11. Create an SNS topic for CI/CD code promotion approvals. Topic name: <git repo>-approval. Subscribe your email address to it.

  12. Use cloudformation-test-staging-prod.yaml to create a CodePipeline CI/CD that builds a docker image and updates ECS cluster with stage promotion approval. CloudFormation stack naming convention: [repo]--[branch]--[service]--cicd. The pipeline will create a CloudFormation stack for each stage (test,staging,prod).

    1. Param RelCloudFormationTemplatePath: if your app needs an ELB specify aws/cloudformation/fargate-with-elb.yaml otherwise, specify aws/cloudformation/fargate-no-elb.yaml.
    2. If using fargate-with-elb.yaml your app MUST:
      • accept health checks at /healthcheck
      • Verify the value of the X-From-CDN header matches the value you set in the VerifyFromCfHeaderVal parameter in <stage>--ecs-codepipeline-parameters.json
      • Edit your cloudfront > dist settings > change Security policy to TLSv1.1_2016. CloudFormation does not support this parameter yet.
      • Create a DNS entry in route53 for production that consumers will use. The cloud formation creates one for prod-- but you do not want to use this as the CloudFormation can be deleted.
    3. Param CodeEntryPointFilePath is cmd/example-webservices/main.go for this example
    4. Param RelDockerfilePath is Dockerfile (it is at the root of this repo)
  13. Make a source code change and git push to github. CodePipeline (CI/CD) will automatically run. Once test stage is successfully executed (This will take 45 minutes on first deploy because CloudFormation initial creation), test sample code via:

    curl -H 'Content-Type:application/json' -H 'Authorization: Bearer aaa' -H 'X-FROM-CDN: [your X_FROM_CDN env value]' -d '{"term":"wahooo"}' https://[CloudFormation Output CNAME from test--[repo]--[branch]-[service]--fargagte]/com.rynop.twirpl.publicservices.Image/CreateGiphy
    

Enviornment variables

AWS Blueprint uses Systems manager parameter store to define environment variables, using the namespace convention:

/<stage>/<repoName>/<branch>/ecsEnvs/<env var name>

The SsmEnvPrefix parameter in aws/cloudformation/parameters/*.json defines this path. aws-env is used to load the env vars from SSM into your container.

APP_STAGE and LISTEN_PORT will automatically be set inside your container when running in ECS.

X_FROM_CDN is required if using an ELB - remember to do this for staging and prod stages too.

aws ssm put-parameter --name '/test/abp-fargate/master/ecsEnvs/X_FROM_CDN' --type 'String' --value 'fromCDN'

You can use this helper script to generate a bash script that will run the aws ssm commands for you.

Code specifics

This example is using golang and the Twirp RPC framework. Project layout is based on golang-standards/project-layout

We recommend using retool to manage your tools (like dep). Why? If you work with anyone else on your project, and they have different versions of their tools, everything turns to shit.

  1. Update Dockerfile. Make sure to set GITHUB_ORG,REPO. Also take a look at .dockerignore
  2. Update ./aws/codebuild/go-lint-test.yaml to set your github org and repo (GO_PKG).
  3. Install protoc, the protobuf compiler. You need version 3+.
  4. Install retool: go get github.com/twitchtv/retool. Make sure to add $GOPATH/bin to your PATH
  5. Run:
    retool add github.com/golang/dep/cmd/dep origin/master
    retool add golang.org/x/lint/golint origin/master
    retool add github.com/golang/protobuf/protoc-gen-go origin/master
    retool add github.com/twitchtv/twirp/protoc-gen-twirp origin/v6_prerelease
    retool do dep init  #If this was existing code you'd run `retool do dep ensure`
    
  6. Auto-generate the code:
    retool do protoc --proto_path=$GOPATH/src:. --twirp_out=. --go_out=. ./rpc/publicservices/service.proto 
    retool do protoc --proto_path=$GOPATH/src:. --twirp_out=. --go_out=. ./rpc/adminservices/service.proto 
    
  7. For this example, the interface implementations have been hand created in pkg/. Take a look.
  8. Example to consume twirp API in this example:
    curl -H 'Content-Type:application/json' -H 'Authorization: Bearer aaa' -H 'X-FROM-CDN: <your VerifyFromCfHeaderVal>' -d '{"term":"wahooo"}' https://<--r output CNAME>/com.rynop.twirpl.publicservices.Image/CreateGiphy
    

ECS Cluster Specifics

Create an ECS cluster in its own VPC by using ./aws/cloudformation/vpc-ecs-cluster.yaml. This cluster will run your test,staging,prod stages (task per stage). CloudFormation stack naming convention: <eyeCatcher for logical grouping of applications>--ecs-cluster.

The naming convention here is a bit confusing, so let me explain a bit. It is my intention to allow multiple Docker containers to run in one ECR cluster. For example, if you are writing a blog platform you may have the following git repos - each with their own Dockerfile:

  • internal-api
  • external-api
  • batch-processing

This ECS cluster CloudFormation stack name could be: blog-platform--ecs-cluster. The 3 git repos above, would each follow the abp-blueprint steps in this readme EXCEPT for this step (creating the ECS cluster). They would each have their own CI/CD, have their own ECS service and task(s). However they would all run inside one ECS cluster. The "magic" of this is done by setting the param EcsCfClusterStackName in . The value of EcsCfClusterStackName is the CloudFormation output value of VpcEcsClusterStackName from the ECS Cluster CloudFormation (blog-platform--ecs-cluster in this example).

It is up to you which git repo houses ./aws/cloudformation/vpc-ecs-cluster.yaml.

To summarize, my intention was to leave it up to the architect to determine if he/she wants multiple docker containers running in the same ECS or not. You can absolutely run a 1:1 Docker (one git repo) container to ECS cluster - but it is not required.

Testing locally:

  1. Set LOCAL_LISTEN_PORT and X_FROM_CDN env vars. (Fish: set -gx LOCAL_LISTEN_PORT 8080; set -gx X_FROM_CDN localTest)
  2. Build & run: cd cmd/example-webservices; go run main.go
  3. Hit endpoint: curl -v -H 'Content-Type:application/json' -H 'Authorization: Bearer aaa' -H 'X-FROM-CDN: localTest' -d '{"term":"wahooo"}' http://localhost:8080/com.rynop.twirpl.publicservices.Image/CreateGiphy

Add dependency example:

retool do dep ensure -add github.com/apex/gateway github.com/aws/aws-lambda-go

Building docker image locally

docker build --build-arg CODE_PATH=cmd/example-webservices -t abp-fargate/master:initial .

abp-fargate's People

Contributors

doapp-jeremy avatar jeremymcjunkin avatar petrogad avatar rynop avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.