Skip to content

Instantly share code, notes, and snippets.

@efekarakus
Created December 9, 2021 18:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save efekarakus/e4d6f798138d30da60b069a7d5498026 to your computer and use it in GitHub Desktop.
Save efekarakus/e4d6f798138d30da60b069a7d5498026 to your computer and use it in GitHub Desktop.
Draft proposal to support Environment Addons in AWS Copilot

Today, users can associate new AWS resources to a single microservice through service addons [1]. However, there are resources such as Application Load Balancers or Elastic File Systems that are designed to be shared by multiple consumers. Today, Copilot provides a managed experience for sharable resources via the manifest file with the http, alias, or efs fields.

This document proposes a way for users to create their own sharable resources between microservices so that they are not blocked on the Copilot team to support the integration.

Target use cases

AWS resources that are meant to be shared typically (and ideally should) support a “decoupling layer”. For example, EFS::FileSystem is an environment stack resource while EFS::AccessPoint is a service stack resource. The EFS::AccessPoint allows services to share the EFS::FileSystem without impacting each other. In this document, we will refer to these resources as “env native” resources.

Sample use cases that environment addons should enable:

  1. As an application with loosely-coupled microservices, I’d like to define an Events::EventBus that services can share via Events::EventRules, so that I can have asynchronous communication between services.
  2. As an application with tightly-coupled microservices, I’d like to define an AppMesh::Mesh that services can share via AppMesh::Routes, so that I can have request-response communication between services.
  3. As an application with HTTP APIs, I’d like to define a shared ApiGatewayV2::Api that services can share via ApiGatewayV2::Routes, so that each one of my services listen on a separate path.

Constraints

In order to satisfy the Target use cases. The design needs to allow two new functionalities:

  1. The definition of “env native” resources, e.g. Events::EventsBus, such that they are independent from the lifecycle of any service stack.
  2. The definition of service resources, e.g. Events::EventsRule, that can import “env native” resources like Events::EventsBus and import any values from the parent service stack like the EventsQueue SQS queue in the Worker service so that we can wire the “env native” resource to a service resource.

Requirements

  1. [Manual deployments] Users can deploy their environment addons via a command.
  2. [Continuous delivery] Users can deploy their environment addons via our pipelines.
  3. [Connectable] Users can connect an environment addons resource to a service resource.
  4. [Feedback loop] Users should be able to view status updates during deployments just like services.

Tenets

  1. [Familiar] Environment addons should be easy to define if a user is already familiar with service addons [1].

Design

We will allow users to create a directory under copilot/<name>/ with a new manifest type "Environment Addons" so that users can write CloudFormation templates for their shared resources.

Specification

Directory structure Users will be able to place their CFN template with shared resources under addons/<filename>.yml just like service templates [Familiar].

.
└── copilot/
    ├── # ... existing workload directories
    └── <name>/ 
        ├── manifest.yml      
        └── addons/
            └── template.yml

If users want to define more than one env addons stack, they can create another directory like copilot/<other>/manifest.yml where the manifest type is also "Environment Addons".

Manifest The manifest file contains only two fields:

name: '<name>'
type: 'Environment Addons'

Template The template content will only require three Parameters that will be passed down by Copilot.

Parameters:
  App: 
    Type: String
  Env:
    Type: String
  Name:
    Type: String
Resources:  # Their resources go here.

The format is identical to service addons [Familiar]. The App and Env parameters can be used to import values from the environment stack. For example, !ImportValue ${App}-${Env}-VpcId. The Name field can be used if they want to fix names to their resources.

Evaluating requirements

  • ✅ [Feedback loop], users can add a aws:copilot:description field to their resources just like service addons and Copilot will display progress during deployments [Familiar].

Deployments

The result of deploying the environment addon will be a stack with the name <app>-<env>-<name> just like for service or job workloads [Familiar].

The content of the stack will be identical to the content of the merged template under addons/.

The stack will be tagged with the usual copilot-application and copilot-environment tags, but in addition we will also start tagging our stacks with copilot-workload-type in order to search for stacks that are “Load Balanced Web Service” or “Environment Addons”.

Note
Note that unlike service addons stacks, environment addons are not nested stacks. This is because you cannot assign a deterministic name to nested stacks [5]. We need the name of the stack to be fixed so that users can import environment addon resources from their service addons template. For example, !ImportValue eventbus-test-demo-EventBusName.

Users can run copilot deploy -n <name> in order to create the env addons CloudFormation stack [Manual deployments]. If the flag is not provided, we will prompt for it. In yellow, we’re highlighting the new deploy UX:

$ copilot deploy
Select the workload in your workspace to deploy:
> frontend          (Load Balanced Web Service)
> loadtester        (Backend Service)
> order-processor   (Worker Service)
> eventbus          (Environment Addons)

In order to support [Continuous delivery] we’re proposing the following changes:

  1. Add a new hidden flag to copilot env ls --addons --local that will return a list of available env addons in the workspace:

    {"addons": [{"name": "eventbus"}, {"name": "apigw"}]
    
  2. Add a new hidden command copilot package that can output the stack templates and parameters: copilot package -n eventbus -e test --output-dir ./infrastructure

  3. Update the buildspec.yml with the following pseudo-code:

    for each env in $(copilot env ls)
       for each addon in $(copilot env ls --addons --local)
          do $(copilot package -n ${addon} -e ${env} --output-dir ./infrastructure)
    

At this point the templates are generated and CodePipeline should be able to update the env addons stacks.

Evaluating requirements

  • ✅ [Connectable] We’re satisfying this requirement as users can pair it with customizable service addon parameters
  • ✅ [Manual deployments] Users can run copilot deploy -n to deploy their env addons.
  • ✅ [Continuous delivery] Users need to re-generate their buildspec by running copilot pipeline init and then update their pipeline with copilot pipeline update.

Deletions

We’re proposing to add the following new flag copilot env delete --addons <name> to delete env addons stacks. For copilot app delete the deletion order will be:

For each env:
   Delete service and job stacks
   Delete env addons # 🆕 operation
   Delete env
Delete app

Appendix

Customer Feedback

Env addons

Customizable service addons params

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment