Skip to content

AWS Copilot v1.26: Automate rollbacks with CloudWatch alarms, storage init for env addons, and RDWS secrets support

Posted On: Feb 20, 2023

The AWS Copilot core team is announcing the Copilot v1.26 release.
Our public сommunity сhat is growing and has over 400 people online and over 2.6k stars on GitHub. Thanks to every one of you who shows love and support for AWS Copilot.

Copilot v1.26 brings several new features and improvements:

What’s AWS Copilot?

The AWS Copilot CLI is a tool for developers to build, release, and operate production-ready containerized applications on AWS. From getting started to releasing in production, Copilot can help manage the entire lifecycle of your application development. At the foundation of Copilot is AWS CloudFormation, which enables you to provision infrastructure as code. Copilot provides pre-defined CloudFormation templates and user-friendly workflows for different types of microservice architectures, enabling you to focus on developing your application instead of writing deployment scripts.

See the Overview section for a more detailed introduction to AWS Copilot.

Service alarm-based rollback

You can now monitor your ECS deployments with custom CloudWatch alarms! Configure your services to roll back to the last completed deployment if your alarms go into In alarm state during deployment. With the circuit breaker, Copilot has already been rolling back your failed deployments. Now, you can also roll back service deployments that aren't failing, but aren't performing in accordance with the metrics of your choice.

In your backend, worker, or load-balanced web service manifest, you may import your own existing CloudWatch alarms:

deployment:
  rollback_alarms: ["MyAlarm-ELB-4xx", "MyAlarm-ELB-5xx"]

Or have Copilot create a CPU and/or memory utilization alarm for you, with thresholds of your choice:

deployment:
  rollback_alarms:
    cpu_utilization: 70    // Percentage value at or above which alarm is triggered.
    memory_utilization: 50 // Percentage value at or above which alarm is triggered.

For worker services, you may also create an alarm to monitor ApproximateNumberOfMessagesDelayed:

deployment:
  rollback_alarms:
    messages_delayed: 5

When Copilot creates alarms for you, some defaults are set under the hood:

ComparisonOperator: 'GreaterThanOrEqualToThreshold'
DatapointsToAlarm: 2
EvaluationPeriods: 3
Period: 60
Statistic: 'Average'
With rollback alarms configured in your service manifest, each time you run svc deploy after the initial deployment (when there is no existing deployment to roll back to), ECS will poll your alarms and trigger a rollback if there is a breach.

storage init for environment addons

Previously, copilot storage init only supported storage addons attached to workloads: you need to run copilot svc deploy in order to deploy the storage, and the storage is deleted along with the service when you run copilot svc delete.

Now, you have the option to create environment storage addons: the storage is deployed when you run copilot env deploy, and isn't deleted until you delete the environment by running copilot env delete.

Similar to the workload storage, the environment storage is, under the hood, just another environment addon!

Database-Per-Service By Default

In the microservice world, it is generally recommended to set up data storage resources that are each private to a microservice, instead of monolith storages that are shared by multiple services. This pattern preserves the core characteristics of microservices - loose coupling. Copilot encourages you to follow this database-per-service pattern. By default, a storage resource that Copilot generates is assumed to be accessed by one service or job.

However, each user has its own unique situation. If you do need your data storage to be shared among multiple service, you can modify the Copilot-generated CloudFormation template in order to achieve your goal.

Here is an example of prompts that you might see.

$ copilot storage init
What type of storage would you like to create?
> DynamoDB            (NoSQL)
  S3                  (Objects)
  Aurora Serverless   (SQL)

Which workload needs access to the storage?
> api
  backend

What would you like to name this DynamoDB Table? movies

Do you want the storage to be created and deleted with the api service?
  Yes, the storage should be created and deleted at the same time as api
> No, the storage should be created and deleted at the environment level

You can skip the prompts using the flags. The following command is equivalent to the prompts above:

copilot storage init \
--storage-type "DynamoDB" \
--workload "api" \
--name "movies" \
--lifecycle "environment"

After you've answered all the prompts or skipped them by using flags, Copilot will generate the CloudFormation template that defines the DynamoDB storage resource under your copilot/environments directory. In addition, it will generate the necessary access policy; here is one that grants "api" service access to the "movies" storage. The access policy is created as a workload addon, meaning that it is deployed and deleted at the same time as the "api" service.

copilot/
├── environments/
│   ├── addons/         
│   │   └── movies.yml                # <- The CloudFormation template that defines the "movies" DynamoDB storage.
│   └── test/
│       └── manifest.yml
└── api
    ├── addons/
    │   └── movies-access-policy.yml  # <- The CloudFormation template that defines the access policy.
    └─── manifest.yml

Depending on the storage type, and the type of the workload that is fronting the storage, Copilot may generate different CloudFormation files.

Sample files generated for an Aurora Serverless fronted by a Request-Driven Web Service
# Example: an Aurora Serverless v2 storage whose lifecycle is at the environment-level, faced by a Request-Driven Web Service.
copilot/
├── environments/
│   └── addons/
│         ├── addons.parameters.yml   # The extra parameters required by the Aurora Serverless v2 storage.
│         └── user.yml                # An Aurora Serverless v2 storage
└── api                               # "api" is a Request-Driven Web Service
    └── addons/
        ├── addons.parameters.yml   # The extra parameters required by the ingress resource.
        └── user-ingress.yml        # A security group ingress that grants "api" access to the "api" storage"

Also check out our storage page for more information!

Request-Driven Web Service secrets support

You can now add your secrets (from SSM Parameter Store or AWS Secrets Manager) to your App Runner service as environment variables using Copilot.

Similar to other service types such as Load-Balanced Web Service, you need to first add the following tags to your secrets:

Key Value
copilot-application Application name from which you want to access the secret
copilot-environment Environment name from which you want to access the secret

Then simply update your Request-Driven Web Service manifest with:

  secrets:
    GITHUB_TOKEN: GH_TOKEN_SECRET
And deploy! Your service can now access the secret as an environment variable.

For more detailed use of the secrets field:

secrets:
  # To inject a secret from SecretsManager.
  # (Recommended) Option 1. Referring to the secret by name.
  DB:
    secretsmanager: 'mysql'
  # You can refer to a specific key in the JSON blob.
  DB_PASSWORD:
    secretsmanager: 'mysql:password::'
  # You can substitute predefined environment variables to keep your manifest succinct.
  DB_PASSWORD:
    secretsmanager: 'mysql:password::'

  # Option 2. Alternatively, you can refer to the secret by ARN.
  DB: 'arn:aws:secretsmanager:us-west-2:111122223333:secret:demo/test/mysql-Yi6mvL'

  # To inject a secret from SSM Parameter Store
  # Option 1. Referring to the secret by ARN.
  GITHUB_WEBHOOK_SECRET: 'arn:aws:ssm:us-east-1:615525334900:parameter/GH_WEBHOOK_SECRET'

  # Option 2. Referring to the secret by name.
  GITHUB_WEBHOOK_SECRET: GITHUB_WEBHOOK_SECRET
See the manifest specification. To learn more about injecting secrets into your services, see the secrets page

What’s next?

Download the new Copilot CLI version by following the link below and leave your feedback on GitHub or our Community Chat: