Skip to content

Commit

Permalink
Adding aws-py-fargate example (pulumi#552)
Browse files Browse the repository at this point in the history
  • Loading branch information
stack72 committed Feb 14, 2020
1 parent e7a8d6a commit 8480e6e
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 0 deletions.
2 changes: 2 additions & 0 deletions aws-py-fargate/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.pyc
venv/
3 changes: 3 additions & 0 deletions aws-py-fargate/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: aws-py-fargate
description: A container running in AWS ECS Fargate, using Python infrastructure as code
runtime: python
148 changes: 148 additions & 0 deletions aws-py-fargate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new)

# NGINX on AWS ECS Fargate using Python

This example shows authoring Infrastructure as Code in Python. It
provisions a full [Amazon Elastic Container Service (ECS) "Fargate"](https://aws.amazon.com/ecs) cluster and
related infrastructure, running a load-balanced NGINX web server accessible over the Internet on port 80.
This example is inspired by [Docker's Getting Started Tutorial](https://docs.docker.com/get-started/).

## Prerequisites

* [Install Pulumi](https://www.pulumi.com/docs/get-started/install/)
* [Configure Pulumi to Use AWS](https://www.pulumi.com/docs/intro/cloud-providers/aws/setup/) (if your AWS CLI
is configured, this will just work)

## Running the Example

Clone this repo and `cd` into it.

Next, to deploy the application and its infrastructure, follow these steps:

1. Create a new stack, which is an isolated deployment target for this example:

```bash
$ pulumi stack init dev
```

2. Set your desired AWS region:

```bash
$ pulumi config set aws:region us-east-1 # any valid AWS region will work
```

3. Create a Python virtualenv, activate it, and install dependencies:

This installs the dependent packages [needed](https://www.pulumi.com/docs/intro/concepts/how-pulumi-works/) for our Pulumi program.

```
$ virtualenv -p python3 venv
$ source venv/bin/activate
$ pip3 install -r requirements.txt
```

4. Deploy everything with a single `pulumi up` command. This will show you a preview of changes first, which
includes all of the required AWS resources (clusters, services, and the like). Don't worry if it's more than
you expected -- this is one of the benefits of Pulumi, it configures everything so that so you don't need to!

```bash
$ pulumi up
```

After being prompted and selecting "yes", your deployment will begin. It'll complete in a few minutes:

```
Updating (dev):
Type Name Status
+ pulumi:pulumi:Stack aws-py-fargate-dev created
+ ├─ aws:ecs:Cluster cluster created
+ ├─ aws:ec2:SecurityGroup web-secgrp created
+ ├─ aws:iam:Role task-exec-role created
+ ├─ aws:lb:TargetGroup app-tg created
+ ├─ aws:ecs:TaskDefinition app-task created
+ ├─ aws:iam:RolePolicyAttachment task-exec-policy created
+ ├─ aws:lb:LoadBalancer app-lb created
+ ├─ aws:lb:Listener web created
+ └─ aws:ecs:Service app-svc created
Outputs:
url: "app-lb-ad43707-1433933240.us-west-2.elb.amazonaws.com"
Resources:
+ 10 created
Duration: 2m56s
Permalink: https://app.pulumi.com/acmecorp/aws-python-fargate/dev/updates/1
```

Notice that the automatically assigned load-balancer URL is printed as a stack output.

6. At this point, your app is running -- let's curl it. The CLI makes it easy to grab the URL:

```bash
$ curl http:https://$(pulumi stack output url)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http:https://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http:https://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```

**Please Note**: It may take a few minutes for the app to start up. Until that point, you may receive a 503 error response code.

7. Try making some changes, and rerunning `pulumi up`. For example, let's scale up to 3 instances:

Running `pulumi up` will show you the delta and then, after confirming, will deploy just those changes:

```bash
$ pulumi up
```

Notice that `pulumi up` redeploys just the parts of the application/infrastructure that you've edited.

```
Updating (dev):
Type Name Status Info
pulumi:pulumi:Stack aws-py-fargate-dev
~ └─ aws:ecs:Service app-svc updated [diff: ~desiredCount]
Outputs:
url: "app-lb-ad43707-1433933240.us-west-2.elb.amazonaws.com"
Resources:
~ 1 updated
9 unchanged
Duration: 14s
Permalink: https://app.pulumi.com/acmecorp/aws-python-fargate/dev/updates/2
```

8. Once you are done, you can destroy all of the resources, and the stack:

```bash
$ pulumi destroy
$ pulumi stack rm
```
109 changes: 109 additions & 0 deletions aws-py-fargate/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
from pulumi import export, ResourceOptions
import pulumi_aws as aws
import json

# Create an ECS cluster to run a container-based service.
cluster = aws.ecs.Cluster('cluster')

# Read back the default VPC and public subnets, which we will use.
default_vpc = aws.ec2.get_vpc(default='true')
default_vpc_subnets = aws.ec2.get_subnet_ids(vpc_id=default_vpc.id)

# Create a SecurityGroup that permits HTTP ingress and unrestricted egress.
group = aws.ec2.SecurityGroup('web-secgrp',
vpc_id=default_vpc.id,
description='Enable HTTP access',
ingress=[{
'protocol': 'tcp',
'from_port': 80,
'to_port': 80,
'cidr_blocks': ['0.0.0.0/0'],
}],
egress=[{
'protocol': '-1',
'from_port': 0,
'to_port': 0,
'cidr_blocks': ['0.0.0.0/0'],
}]
)

# Create a load balancer to listen for HTTP traffic on port 80.
alb = aws.lb.LoadBalancer('app-lb',
security_groups=[group.id],
subnets=default_vpc_subnets.ids
)

atg = aws.lb.TargetGroup('app-tg',
port=80,
protocol='HTTP',
target_type='ip',
vpc_id=default_vpc.id
)

wl = aws.lb.Listener('web',
load_balancer_arn=alb.arn,
port=80,
default_actions=[{
'type': 'forward',
'target_group_arn': atg.arn
}]
)

# Create an IAM role that can be used by our service's task.
role = aws.iam.Role('task-exec-role',
assume_role_policy=json.dumps({
'Version': '2008-10-17',
'Statement': [{
'Sid': '',
'Effect': 'Allow',
'Principal': {
'Service': 'ecs-tasks.amazonaws.com'
},
'Action': 'sts:AssumeRole',
}]
})
)

rpa = aws.iam.RolePolicyAttachment('task-exec-policy',
role=role.name,
policy_arn='arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
)

# Spin up a load balanced service running our container image.
task_definition = aws.ecs.TaskDefinition('app-task',
family='fargate-task-definition',
cpu='256',
memory='512',
network_mode='awsvpc',
requires_compatibilities=['FARGATE'],
execution_role_arn=role.arn,
container_definitions=json.dumps([{
'name': 'my-app',
'image': 'nginx',
'portMappings': [{
'containerPort': 80,
'hostPort': 80,
'protocol': 'tcp'
}]
}])
)

service = aws.ecs.Service('app-svc',
cluster=cluster.arn,
desired_count=3,
launch_type='FARGATE',
task_definition=task_definition.arn,
network_configuration={
'assign_public_ip': 'true',
'subnets': default_vpc_subnets.ids,
'security_groups': [group.id]
},
load_balancers=[{
'target_group_arn': atg.arn,
'container_name': 'my-app',
'container_port': 80
}],
opts=ResourceOptions(depends_on=[wl]),
)

export('url', alb.dns_name)
2 changes: 2 additions & 0 deletions aws-py-fargate/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pulumi>=1.0.0
pulumi-aws>=1.0.0

0 comments on commit 8480e6e

Please sign in to comment.