Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docs): Updated examples topic to use ECS L2 construct #1195

Merged
merged 17 commits into from
Dec 7, 2018
Merged
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 117 additions & 147 deletions docs/src/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,205 +14,175 @@
|cdk| Examples
##############

This topic contains some usage examples to help you get started understanding
the |cdk|.
This topic contains some examples to help you get started using some of the advanced constructs
offered by the |cdk|.

.. We'll include this if we ever implement DeploymentPipeline
_multiple_stacks_example:
.. _creating_ecs_l2_example:

Creating an App with Multiple Stacks
====================================
Creating an |ECS| Construct
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't call it "creating an ECS construct", that implies you're building a reusable thing.

Maybe "Writing an |ECS| CDK app" ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

===========================

The following example creates the following stacks and one deployment pipeline:
|ECSlong| (|ECS|) is a highly scalable, fast, container management service
that makes it easy to run, stop, and manage Docker containers on a cluster.
You can host your cluster on a serverless infrastructure that is managed by
|ECS| by launching your services or tasks using the Fargate launch type.
For more control you can host your tasks on a cluster of
|EC2long| (|EC2|) instances that you manage by using the EC2 launch type.

- **Dev** uses the default environment
- **PreProd** in the **us-west-2** Region
- **NAEast** in the **us-east-1** Region
- **NAWest** in the **us-west-2** Region
- **EU** in the **eu-west-1** Region
- **DeploymentPipeline** in the **us-east-1** Region
Since |ECS| can be used with a number of AWS services,
you should understand how the |ECS| construct that we use in this example
gives you a leg up on using AWS services:

Implement the class **MyStack** in the *my-stack* sub-folder,
that extends the |stack-class| class
(this is the same code as shown in the :doc:`concepts` topic).
* Automatic security group opening for load balancers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are not sentences, maybe rephrase to a list of the form "it will open up ..." etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. I wrote these based on some notes and forgot to re-visit.

* Automatic ordering dependency between service and load balancer attaching to a target group
* Automatic userdata configuration on auto-scaling group
* Early validation of parameter combinations,
which exposes |CFN| issues earlier,
thus saving you deployment time
* Automatically adds permissions for |ECR| if you use an image from |ECR|
* Convenient API for autoscaling
* Asset support, so that you can deploy source from your machine to |ECS| in one step

code-block:: js
.. _creating_ecs_l2_example_1:

import { Stack, StackProps } from '@aws-cdk/cdk'
Step 1: Create the Directory and Initialze the |cdk|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo. Wouldn't capitalize Directory and Initialize here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is AWS docs style. We capitalize pretty much everything but articles (the, and, etc.).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still typo

----------------------------------------------------

interface MyStackProps extends StackProps {
encryptedStorage: boolean;
}
Let's start with creating a new directory to hold our |cdk| code
and create a new app in that directory.

export class MyStack extends Stack {
constructor(parent: Construct, name: string, props?: MyStackProps) {
super(parent, name, props);
.. code-block:: sh

new MyStorageLayer(this, 'Storage', { encryptedStorage: props.encryptedStorage });
new MyControlPlane(this, 'CPlane');
new MyDataPlane(this, 'DPlane');
}
}
mkdir MyEcsConstruct
cd MyEcsConstruct

Implement the class **DeploymentPipeline** in the *my-deployment* sub-folder,
that extends the |stack-class| class
(this is the same code as shown in the :doc:`concepts` topic).
.. tabs::

code-block:: js
.. group-tab:: TypeScript

Use **MyStack** and **DeploymentPipeline** to create the stacks and deployment pipeline.
.. code-block:: sh

code-block:: js
cdk init --language typescript

import { App } from '@aws-cdk/cdk'
import { MyStack } from './my-stack'
import { DeploymentPipeline } from './my-deployment'
Update *my_ecs_construct.ts* in the *bin* directory to only contain the following code:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will have gotten changed to lib/my_ecs_construct_stack.ts by the time this goes out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the typo (sheesh); I just tested cdk init --language typescript in 0.18.1 and it still creates the TS file in the bin folder.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know. The change is not released yet. That's why I wrote:

by the time this goes out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this part as the template has changed.


const app = new App();
.. code-block:: ts

// Use the default environment
new MyStack(app, { name: 'Dev' });
import cdk = require('@aws-cdk/cdk');

// Pre-production stack
const preProd = new MyStack(app, {
name: 'PreProd',
env: { region: 'us-west-2' },
preProd: true
});
class MyEcsConstructStack extends cdk.Stack {
constructor(parent: cdk.App, name: string, props?: cdk.StackProps) {
super(parent, name, props);

// Production stacks
const prod = [
new MyStack(app, {
name: 'NAEast',
env: { region: 'us-east-1' }
}),

new MyStack(app, {
name: 'NAWest',
env: { region: 'us-west-2' }
}),
}
}

new MyStack(app, {
name: 'EU',
env: { region: 'eu-west-1' },
encryptedStorage: true
})
]
const app = new cdk.App();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact these lines will also be gone.

These lines will live in a file in the bin directory, the other lines will live in a file in the lib directory.

Here's the new version of the app template: https://github.com/awslabs/aws-cdk/tree/master/packages/aws-cdk/lib/init-templates/app/typescript


// CI/CD pipeline stack
new DeploymentPipeline(app, {
env: { region: 'us-east-1' },
strategy: DeploymentStrategy.Waved,
preProdStages: [ preProd ],
prodStages: prod
});
new MyEcsConstructStack(app, 'MyEcsConstructStack');

app.run();
app.run();

.. _dynamodb_example:
Save it and make sure it builds and creates an empty stack.

Creating a |DDB| Table
======================
.. code-block:: sh

The following example creates a
|DDB| table with the partition key **Alias**
and sort key **Timestamp**.
npm run build
cdk synth

.. code-block:: js
You should see a stack like the following,
where CDK-VERSION is the version of the CDK.

import dynamodb = require('@aws-cdk/aws-dynamodb');
import cdk = require('@aws-cdk/cdk');
.. code-block:: sh

class MyStack extends cdk.Stack {
constructor(parent: cdk.App, name: string, props?: cdk.StackProps) {
super(parent, name, props);
Resources:
CDKMetadata:
Type: 'AWS::CDK::Metadata'
Properties:
Modules: @aws-cdk/cdk=CDK-VERSION,@aws-cdk/cx-api=CDK-VERSION,my_ecs_construct=0.1.0

const table = new dynamodb.Table(this, 'Table', {
tableName: 'MyAppTable',
readCapacity: 5,
writeCapacity: 5
});
.. _creating_ecs_l2_example_2:

table.addPartitionKey({ name: 'Alias', type: dynamodb.AttributeType.String });
table.addSortKey({ name: 'Timestamp', type: dynamodb.AttributeType.String });
}
}
Step 2: Add the |EC2| and |ECS| Packages
----------------------------------------

const app = new cdk.App();
Install support for |EC2| and |ECS|.

new MyStack(app, 'MyStack');
.. tabs::

app.run();
.. group-tab:: TypeScript

.. _creating_rds_example:
.. code-block:: sh

Creating an |RDS| Database
==========================
npm install @aws-cdk/aws-ec2 @aws-cdk/aws-ecs

The following example creates the Aurora database **MyAuroraDatabase**.
.. _creating_ecs_l2_example_3:

.. code-block:: js
Step 3: Create a Fargate Service
--------------------------------

import ec2 = require('@aws-cdk/aws-ec2');
import rds = require('@aws-cdk/aws-rds');
import cdk = require('@aws-cdk/cdk');
There are two different ways of creating a serverless infrastructure with |ECS|:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would write "two different ways of running your container tasks"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


class MyStack extends cdk.Stack {
constructor(parent: cdk.App, name: string, props?: cdk.StackProps) {
super(parent, name, props);
- Using the **Fargate** launch type, where |ECS| manages your cluster resources
- Using the **EC2** launch type, where you manage your cluster resources

const vpc = new ec2.VpcNetwork(this, 'VPC');
This example creates a Fargate service,
which requires a VPC, a cluster, a task definition, and a security group.
Later on we'll show you how to launch an EC2 service.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how to launch services on EC2 instances you manage yourself

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


new rds.DatabaseCluster(this, 'MyRdsDb', {
defaultDatabaseName: 'MyAuroraDatabase',
masterUser: {
username: 'admin',
password: '123456'
},
engine: rds.DatabaseClusterEngine.Aurora,
instanceProps: {
instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.Burstable2, ec2.InstanceSize.Small),
vpc: vpc,
vpcPlacement: {
subnetsToUse: ec2.SubnetType.Public
}
}
});
}
}
.. tabs::

const app = new cdk.App();
.. group-tab:: TypeScript

new MyStack(app, 'MyStack');
Add the following import statements:

app.run();
.. code-block:: typescript

.. _creating_s3_example:
import ec2 = require('@aws-cdk/aws-ec2');
import ecs = require('@aws-cdk/aws-ecs');

Creating an |S3| Bucket
=======================
Add the following code to the end of the constructor:

The following example creates the |S3| bucket **MyS3Bucket** with server-side KMS
encryption provided by |S3|.
.. code-block:: typescript

.. code-block:: js
const vpc = new ec2.VpcNetwork(this, 'MyVpc', {
maxAZs: 2 // Default is all AZs in region
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 is actually a better default if we're going to teach people best practices. 2 is just for tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

});

import s3 = require('@aws-cdk/aws-s3');
import cdk = require('@aws-cdk/cdk');
// Create an ECS cluster
const cluster = new ecs.Cluster(this, 'MyCluster', {
vpc: vpc
});

class MyStack extends cdk.Stack {
constructor(parent: cdk.App, name: string, props?: cdk.StackProps) {
super(parent, name, props);
const taskDefinition = new ecs.FargateTaskDefinition(this, 'MyFargateTaskDefinition', {
cpu: '256', // Default
memoryMiB: '2048' // Default is 512
});

new s3.Bucket(this, 'MyBucket', {
bucketName: 'MyS3Bucket',
encryption: s3.BucketEncryption.KmsManaged
});
}
}
// The task definition must have at least one container.
// Otherwise you cannot synthesize or deploy your app.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds like a constraint if you put it like this. But also, if you don't add a container, WHAT are you even launching? Empty tasks that do nothing? That's not very useful.

So I wouldn't call attention to it in this way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rewrote the first comment line and removed the second comment line.

taskDefinition.addContainer('MyContainer', {
image: ecs.ContainerImage.fromDockerHub('MyDockerImage') // Required
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe launch amazon/amazon-ecs-sample, that's a container that at least does something.

});

const app = new cdk.App();
const securityGroup = new ec2.SecurityGroup(this, 'MySecurityGroup', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually not necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

vpc: vpc
});

new MyStack(app, 'MyStack');
new ecs.FargateService(this, 'MyFargateService', {
taskDefinition: taskDefinition, // Required
cluster: cluster, // Required
desiredCount: 6, // Default is 1
securityGroup: securityGroup, // Required
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it's not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep

platformVersion: ecs.FargatePlatformVersion.Latest // Default
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't even call attention to this, just leave it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

});

app.run()
Save it and make sure it builds and creates a stack.

.. code-block:: sh

npm run build
cdk synth

You should see a stack of about 300 lines, so we won't show it here.