• Stars
    star
    359
  • Rank 118,537 (Top 3 %)
  • Language HCL
  • License
    Apache License 2.0
  • Created almost 5 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Complete example of deploying complex web apps to AWS using Terraform, Ansible, and Packer

This is an example of how to deploy a real-world complex web app to AWS.

Full-featured apps in languages like Ruby on Rails have multiple components, e.g. web front end, background job handler, periodic jobs, maybe a separate server to handle API traffic or web sockets. They use a relational database, Redis or Memcached, Elasticsearch, CDN for static assets, SSL, S3 buckets, encryption. They need logging, metrics, and alerting.

They run in an autoscaling group or ECS and use a CI/CD pipeline to handle blue/green deployment. They need to run in multiple environments: dev, staging, prod, demo, with slight differences for each. They have some weird things to integrate with partners.

This framework handles all that :-)

It's built in in a modular way using Terraform, Ansible and Packer. We have used it to deploy multiple complex apps, so it handles many things that you will need, but it's also flexible enough to be tweaked when necessary for special requirements. It represents months of work.

The blog post Deploying complex apps to AWS with Terraform, Ansible, and Packer gives an example.

Scenarios

These modules cover the following scenarios:

EC2 + RDS

  • Virtual private cloud (VPC) with public, private and database subnets
  • App runs in EC2 instance(s) in the public subnet
  • RDS database
  • App data stored in S3
  • Route53 DNS with health checks directs traffic to app instances

This is good for a simple app, and is also a stepping stone when deploying more complex apps. EC2 instances can be used for development or as a canary. See the AWS docs for overview.

ECS with Fargate

This runs ECS applications with the same infrastructure as above, but running in containers in Fargate. It supports x86 and Arm.

An example app is here: https://github.com/cogini/phoenix_container_example

CloudFront for assets

Store app assets like JavaScript and CSS in CloudFront for performance

CodePipeline for CI/CD

Whenever code changes, pull from git, build in CodeBuild, run tests and deploy automatically using CodeDeploy. Run tests against resources such as RDS or Redis. Supports both GitHub and CodeCommit.

Auto Scaling Group and Load Balancer

  • App runs in an ASG in the private VPC subnet
  • Blue/Green deployment
  • SSL using Amazon Certificate Manager
  • Spot instances to reduce cost
  • Multiple deploy targets
  • Manual approval process
  • Notifications

Containers running in ECS

  • App is built in CodePipeline
  • Deployed to ECS using CodeDeploy Blue/Green deployment

Worker ASG

Worker runs background tasks in an ASG, with its own build and deploy pipeline.

Multiple front end apps

Route traffic between web apps using the Load Balancer, e.g. separate servers for API, customer admin, back end admin.

S3 buckets

  • Share data between apps using S3 buckets with access control
  • Use signed URLs to handle protected user content

Static website

Build the public website using a static site generator in CodeBuild, deploying to CloudFront CDN. Use Lambda@Edge to rewrite URLs.

Elasticache

Add Elasticache Redis or Memcached for app caching.

Elasticsearch

Add Elasticsearch for the app.

DevOps

Add a DevOps instance to handle deployment and management tasks.

Bastion host

Add Bastion host to control access to servers in the private subnet. Or use with AWS SSM Sessions.

Prometheus metrics

Add Prometheus for application metrics and monitoring

SES

Use SES for email.

How it works

It uses Terraform to create the infrastructure, Ansible and Packer to set up instances and AMIs. It uses AWS CodePipeline/CodeBuild/CodeDeploy to build and deploy code, running the app components in one or more autoscaling groups running EC2 instances.

The base of the system is Terraform and Terragrunt. Common Terraform modules can be enabled according to the specific application requirements. Similarly, it uses common Ansible playbooks which can be modified for specific applications. If an app needs something special, we can easily add a custom module for it.

We use the following terminology:

  • Apps are under an org, or organization, e.g. a company. org_unique is a globally unique identifier, used to name e.g. S3 buckets

  • An env is an environment, e.g. dev, stage, or prod. Each gets its own AWS account

  • An app is a single shared set of data, potentially accessed by multiple front end interfaces and back end workers. Each app gets it's own VPC. A separate VPC, generally one per environment, handles logging and monitoring using ELK and Prometheus

  • A comp is an application component

We have three standard types of components: web app, worker and cron.

Web apps process external client requests. Simple apps consist of only a single web app, but complex apps may have more, e.g. an API server, admin interface or instance per customer.

Workers handle asynchronous background processing driven by a job queue such as Sidekiq, SQS or a Kafka stream. They make the front end more responsive by offloading long running tasks. The number of worker instances in the ASG depends on the load.

Cron servers handle timed batch workloads, e.g. periodic jobs. From a provisioning perspective, there is not much difference between a worker and a cron instance, except that cron instances are expected to always be running so that they can schedule jobs. Generally speaking, we prefer to move periodic tasks to Lambda functions where possible.

We normally run application components in an auto scaling group, allowing them to start and stop according to load. This also provides high availability, as the ASG will start instances in a different availability zone if they die. This makes it useful even if we normally only have one instance running.

Running in an ASG requires that instances start from a "template" image AMI and be stateless, storing their data in S3 or RDS. We can also run components in standalone EC2 instances, useful for development and earlier in the process of migrating the app to the cloud.

We can also deploy the app to containers via ECS as part of the same system. Everything is tied together with a common ALB, so it's just a question of routing traffic.

When possible, we utilize managed AWS services such as RDS, ElastiCache, and Elasticsearch. When managed services lack functionality, are immature or are expensive at high load, we can run our own.

The system makes use of CloudFront to host application assets as well as static content websites or "JAM stack" apps using tools like Gatsby.

We deploy the application using AWS CodeDeploy using a blue/green deployment strategy. The CodeDeploy releases can be built using CodePipeline or a DevOps EC2 instance.

By default we use Route53 for DNS and ACM for certificates, though it can work with external DNS, certs and other CDNs like CloudFlare.

Getting started

Contact Us if you would like help deploying your complex app.

More Repositories

1

mix_deploy

Library of mix tasks to deploy an Elixir release to servers (cloud instance or bare metal, automated deploy)
Elixir
120
star
2

elixir-deploy-template

An example project for deploying Elixir
Python
83
star
3

mix_systemd

Library of mix tasks to generate a systemd unit file for an Elixir project
Elixir
63
star
4

phoenix_container_example_old

Full featured example of building a container for an Elixir Phoenix project, taking advantage of BuildKit caching and multi-platform builds (Arm). Shows raw docker, docker-compose, and Earthly; mirrored base images from Docker Hub to AWS ECR; deploys to AWS ECS using CodeBuild / CodeDeploy
Dockerfile
56
star
5

mix-deploy-example

Example Elixir app which uses mix_systemd and mix_deploy to deploy
HTML
40
star
6

phoenix_container_example

Production-quality example for Elixir/Phoenix building, testing, and running in containers
HCL
24
star
7

ansible-role-users

Ansible role to create user accounts for deploying apps and manage access to them with ssh keys
18
star
8

ansible-role-elixir-release

Ansible role to deploy an Elixir/Phoenix release using systemd
Shell
17
star
9

ecto_extract_migrations

Elixir library to generate Ecto migrations from a PostgreSQL schema SQL file. Uses NimbleParsec and macro-style code generation.
Elixir
17
star
10

chef-cookbooks

Ruby
13
star
11

ansible-role-prometheus-rpm

Ansible role to install Prometheus packages from RPMs on https://packagecloud.io/prometheus-rpm
12
star
12

prometheus_exometer

Elixir library which adds Prometheus support to Erlang Exometer metrics library
Elixir
11
star
13

nerves_system_ec2

Nerves system for AWS EC2
Elixir
9
star
14

avro_schema

Elixir convenience library for handling Avro schemas, useful for Kafka
Elixir
7
star
15

confluent_schema_registry

Elixir client for the Confluent Schema Registry API https://www.confluent.io/confluent-schema-registry
Elixir
7
star
16

mix-systemd-deploy-example

Example Elixir app which uses mix_systemd and mix_deploy to deploy
Elixir
6
star
17

storm

Storm ORM
Python
5
star
18

shutdown_flag

Elixir application which performs an orderly shutdown when a flag file appears
Elixir
5
star
19

buildroot_ec2

AWS EC2 board configuration for the Buildroot embedded Linux build system
Shell
5
star
20

logger_formatter_json

Erlang OTP logger formatter that outputs JSON
Erlang
4
star
21

nerves_init_ec2

Initialize Nerves system from EC2 metadata
Elixir
4
star
22

systemd_notify

Erlang library to notify systemd about start-up completion and other service status changes
Erlang
3
star
23

onvif

ONVIF protocol support for Elixir
Elixir
3
star
24

public_suffix_list

Elixir library which uses the https://publicsuffix.org/ list to parse DNS domains
Elixir
3
star
25

acme_client

Elixir client for ACME certificate protocol used by Let's Encrypt
Elixir
3
star
26

hello_nerves_ec2

Example Elixir Nerves app running on Amazon EC2
Elixir
2
star
27

code_deploy

Generate AWS CodeDeploy releases
Elixir
2
star
28

ansible-role-postgresql-ca

Ansible role to manage SSL certs for a PostgreSQL server
2
star
29

file_config

Elixir library to dynamically load application config from files to ETS, e.g. CSV, JSON
Elixir
2
star
30

opentelemetry_xray

OpenTelemetry AWS X-Ray for Erlang
Erlang
2
star
31

absinthe_federation_example

About An example of using Elixir Absinthe GraphQL with Apollo Federation
Dockerfile
2
star
32

http_structured_field

Elixir library to parse HTTP Structured Fields (RFC 8941)
Elixir
1
star
33

mix_deploy_local

Mix tasks to deploy an Elixir release to the local machine
Elixir
1
star
34

codebuild-pelican-example

Example of building a static site using Pelican and AWS CodeBuild
HCL
1
star