AWS Copilot v1.27: Extend Copilot templates, additional routing rule supports, preview differences, and sidecar improvements!
Posted On: Mar 28, 2023
The AWS Copilot core team is announcing the Copilot v1.27 release π.
Our public Ρommunity Ρhat is growing and has over 400 people online and over 2.7k stars on GitHub.
Thanks to every one of you who shows love and support for AWS Copilot.
Copilot v1.27 is a big release with several new features and improvements:
- Extend Copilot templates: You can now customize any properties in Copilot-generated AWS CloudFormation templates with the AWS Cloud Development Kit (CDK) or YAML Patch overrides. See detailed section.
- Enable multiple listeners and listener rules: You can define multiple host-based or path listener rules for application load balancers
or multiple listeners on different ports and protocols for network load balancers.
See detailed section. - Preview CloudFormation template changes: You can now run
copilot [noun] package
orcopilot [noun] deploy
commands with the--diff
flag to show differences between the last deployed CloudFormation template and local changes. See detailed section. - Build and push container images for sidecars: Add support for
image.build
to build and push sidecar containers from local Dockerfiles. See detailed section. - Environment file support for sidecars: Add support for
env_file
to push a local.env
file for sidecar containers. See detailed section.
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.
Extend Copilot-generated AWS CloudFormation templates
AWS Copilot enables builders to quickly get started with containerized applications through the copilot init
command and following prompts.
Developers can then grow their applications by editing and deploying manifest infrastructure-as-code files.
And now with v1.27, developers can extend any Copilot-generated CloudFormation template with the copilot [noun] override
command, enabling them to fully customize their infrastructure.
AWS Cloud Development Kit (CDK) Overrides
You can use the CDK to extend your CloudFormation templates when you need the expressive power and safety of a
programming language. After running the copilot [noun] override
command, Copilot will generate a CDK application
under the copilot/[name]/override
directory:
.
βββ bin/
β βββ override.ts
βββ .gitignore
βββ cdk.json
βββ package.json
βββ README.md
βββ stack.ts
βββ tsconfig.json
You can get started with adding, removing, or replacing properties by editing the stack.ts
file or following the instructions in the README.md
.
View sample stack.ts
import * as cdk from 'aws-cdk-lib';
import * as path from 'path';
import { aws_elasticloadbalancingv2 as elbv2 } from 'aws-cdk-lib';
import { aws_ec2 as ec2 } from 'aws-cdk-lib';
interface TransformedStackProps extends cdk.StackProps {
readonly appName: string;
readonly envName: string;
}
export class TransformedStack extends cdk.Stack {
public readonly template: cdk.cloudformation_include.CfnInclude;
public readonly appName: string;
public readonly envName: string;
constructor (scope: cdk.App, id: string, props: TransformedStackProps) {
super(scope, id, props);
this.template = new cdk.cloudformation_include.CfnInclude(this, 'Template', {
templateFile: path.join('.build', 'in.yml'),
});
this.appName = props.appName;
this.envName = props.envName;
this.transformPublicNetworkLoadBalancer();
}
/**
* transformPublicNetworkLoadBalancer removes the "Subnets" properties from the NLB,
* and adds a SubnetMappings with predefined elastic IP addresses.
*/
transformPublicNetworkLoadBalancer() {
const elasticIPs = [new ec2.CfnEIP(this, 'ElasticIP1'), new ec2.CfnEIP(this, 'ElasticIP2')];
const publicSubnets = cdk.Fn.importValue(`${this.appName}-${this.envName}-PublicSubnets`);
// Apply the override.
const nlb = this.template.getResource("PublicNetworkLoadBalancer") as elbv2.CfnLoadBalancer;
nlb.addDeletionOverride('Properties.Subnets');
nlb.subnetMappings = [{
allocationId: elasticIPs[0].attrAllocationId,
subnetId: cdk.Fn.select(0, cdk.Fn.split(",", publicSubnets)),
}, {
allocationId: elasticIPs[1].attrAllocationId,
subnetId: cdk.Fn.select(1, cdk.Fn.split(",", publicSubnets)),
}]
}
}
Once you run copilot [noun] deploy
or your continuous delivery pipeline is triggered, Copilot will deploy the overriden template.
To learn more about extending with the CDK, checkout the guide.
YAML Patch Overrides
You can use YAML Patch overrides for a more lightweight experience when 1) you do not want to have a dependency
on any other tooling and framework, or 2) you have to write only a handful of modifications.
After running the copilot [noun] override
command, Copilot will generate a sample cfn.patches.yml
file
under the copilot/[name]/override
directory:
.
βββ cfn.patches.yml
βββ README.md
You can get started with adding, removing, or replacing properties by editing the cfn.patches.yaml
file.
View sample cfn.patches.yml
- op: add
path: /Mappings
value:
ContainerSettings:
test: { Cpu: 256, Mem: 512 }
prod: { Cpu: 1024, Mem: 1024}
- op: remove
path: /Resources/TaskRole
- op: replace
path: /Resources/TaskDefinition/Properties/ContainerDefinitions/1/Essential
value: false
- op: add
path: /Resources/Service/Properties/ServiceConnectConfiguration/Services/0/ClientAliases/-
value:
Port: !Ref TargetPort
DnsName: yamlpatchiscool
Once you run copilot [noun] deploy
or your continuous delivery pipeline is triggered, Copilot will deploy the overriden template.
To learn more about extending with YAML patches, check out the guide.
Preview AWS CloudFormation template changes
copilot [noun] package --diff
You can now run copilot [noun] package --diff
to see the diff between your local changes and the latest deployed template.
The program will exit after it prints the diff.
The exit codes when using copilot [noun] package --diff
0 = no diffs found
1 = diffs found
2 = error-producing diffs
$ copilot env deploy --diff
~ Resources:
~ Cluster:
~ Properties:
~ ClusterSettings:
~ - (changed item)
~ Value: enabled -> disabled
If the diff looks good to you, you can run copilot [noun] package
again to write the template file and parameter file
to your designated directory.
copilot [noun] deploy --diff
Similar to copilot [noun] package --diff
, you can run copilot [noun] deploy --diff
to see the same diff.
However, instead of exiting after printing the diff, Copilot will follow up with the question: Continue with the deployment? [y/N]
.
$ copilot job deploy --diff
~ Resources:
~ TaskDefinition:
~ Properties:
~ ContainerDefinitions:
~ - (changed item)
~ Environment:
(4 unchanged items)
+ - Name: LOG_LEVEL
+ Value: "info"
Continue with the deployment? (y/N)
If the diff looks good to you, enter "y" to deploy. Otherwise, enter "N" to make adjustments as needed!
Enable multiple listeners and listener rules for Load Balancers
You can now configure additional listener rules for Application Load Balancer as well as additional listeners for Network Load Balancer.
Add multiple host-based or path-based listener rules to your Application Load Balancer
You can configure additional listener rules for ALB with the new field http.additional_rules
.
Let's learn through an example.
If you want your service to handle traffic to paths customerdb
, admin
and superadmin
with different container ports.
name: 'frontend'
type: 'Load Balanced Web Service'
image:
build: Dockerfile
port: 8080
http:
path: '/'
additional_rules: # The new field "additional_rules".
- path: 'customerdb'
target_port: 8081 # Optional. Defaults to the `image.port`.
- path: 'admin'
target_container: nginx # Optional. Defaults to the main container.
target_port: 8082
- path: 'superAdmin'
target_port: 80
sidecars:
nginx:
port: 80
image: public.ecr.aws/nginx:latest
It is also possible to configure the container port that handles the requests to β/β via the new field http.target_port
Add multiple port and protocol listeners to your Network Load Balancers
You can configure additional listeners for NLB with the new field nlb.additional_listeners
.
Let's learn through an example.
name: 'frontend'
type: 'Load Balanced Web Service'
image:
build: Dockerfile
http: false
nlb:
port: 8080/tcp
additional_listeners:
- port: 8081/tcp
- port: 8082/tcp
target_port: 8085 # Optional. Default is set 8082.
target_container: nginx # Optional. Default is set to the main container.
sidecars:
nginx:
port: 80
image: public.ecr.aws/nginx:latest
Sidecar improvements
You can now build and push container images for sidecar containers just like you can for your main container. Additionally, you can now specify the paths to local environment files for sidecar containers.
Build and push container images for sidecar containers
Copilot now allows users to build sidecar container images natively from Dockerfiles and push them to ECR. In order to take advantage of this feature, users can modify their workload manifests in several ways.
The first option is to simply specify the path to the Dockerfile as a string.
sidecars:
nginx:
image:
build: path/to/dockerfile
Alternatively, you can specify build
as a map, which allows for more advanced customization.
This includes specifying the Dockerfile path, context directory, target build stage, cache from images, and build arguments.
sidecars:
nginx:
image:
build:
dockerfile: path/to/dockerfile
context: context/dir
target: build-stage
cache_from:
- image: tag
args: value
Another option is to specify an existing image URI instead of building from a Dockerfile.
sidecars:
nginx:
image: 123457839156.dkr.ecr.us-west-2.amazonaws.com/demo/front:nginx-latest
Or you can provide the image URI using the location field.
sidecars:
nginx:
image:
location: 123457839156.dkr.ecr.us-west-2.amazonaws.com/demo/front:nginx-latest
Upload local environment files for sidecar containers
You can now specify an environment file to upload to any sidecar container in your task. Previously, you could only specify an environment file for your main task container:
# in copilot/{service name}/manifest.yml
env_file: log.env
Now, you can do the same in a sidecar definition:
sidecars:
nginx:
image: nginx:latest
env_file: ./nginx.env
port: 8080
It also works with the managed logging
sidecar:
logging:
retention: 1
destination:
Name: cloudwatch
region: us-west-2
log_group_name: /copilot/logs/
log_stream_prefix: copilot/
env_file: ./logging.env
If you specify the same file more than once in different sidecars, Copilot will only upload the file to S3 once.