Skip to content

Commit

Permalink
Mitch/aws py wordpress fargate rds (pulumi#893)
Browse files Browse the repository at this point in the history
  • Loading branch information
MitchellGerdisch committed Jan 29, 2021
1 parent 88e52a4 commit 12b04c1
Show file tree
Hide file tree
Showing 8 changed files with 563 additions and 0 deletions.
3 changes: 3 additions & 0 deletions aws-py-wordpress-fargate-rds/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.pyc
venv/
.vscode/
6 changes: 6 additions & 0 deletions aws-py-wordpress-fargate-rds/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: wordpress-ecs-rds
runtime:
name: python
options:
virtualenv: venv
description: Deploys WordPress in ECS Fargate with RDS backend.
101 changes: 101 additions & 0 deletions aws-py-wordpress-fargate-rds/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# WordPress Site in AWS Fargate with RDS DB Backend

This example serves a WordPress site in AWS ECS Fargate using an RDS MySQL Backend.

It leverages the following Pulumi concepts/constructs:

- [Component Resources](https://www.pulumi.com/docs/intro/concepts/programming-model/#components): Allows one to create custom resources that encapsulate one's best practices. In this example, component resource is used to define a "VPC" custom resource, a "Backend" custom resource that sets up the RDS DB, and a "Frontend" resource that sets up the ECS cluster and load balancer and tasks.
- [Other Providers](https://www.pulumi.com/docs/reference/pkg/): Beyond the providers for the various clouds and Kubernetes, etc, Pulumi allows one to create and manage non-cloud resources. In this case, the program uses the Random provider to create a random password if necessary.

This sample uses the following AWS products (and related Pulumi providers):

- [Amazon VPC](https://aws.amazon.com/vpc): Used to set up a new virtual network in which the system is deployed.
- [Amazon RDS](https://aws.amazon.com/rds): A managed DB service used to provide the MySQL backend for WordPress.
- [Amazon ECS Fargate](https://aws.amazon.com/fargate): A container service used to run the WordPress frontend.

## Getting Started

There are no required configuration parameters for this project since the code will use defaults or generate values as needed - see the beginning of `__main__.py` to see the defaults.
However, you can override these defaults by using `pulumi config` to set the following values (e.g. `pulumi config set service_name my-wp-demo`).

- `service_name` - This is used as a prefix for resources created by the Pulumi program.
- `db_name` - The name of the MySQL DB created in RDS.
- `db_user` - The user created with access to the MySQL DB.
- `db_password` - The password for the DB user. Be sure to use `--secret` if creating this config value (e.g. `pulumi config set db_password --secret`).

## Deploying and running the program

Note: some values in this example will be different from run to run.

1. Create a new stack:

```bash
$ pulumi stack init lamp-test
```

1. Set the AWS region:

```bash
$ pulumi config set aws:region us-west-2
```

1. 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.

```bash
$ python3 -m venv venv
$ source venv/bin/activate
$ pip3 install -r requirements.txt
```

1. Run `pulumi up` to preview and deploy changes. After the preview is shown you will be
prompted if you want to continue or not. Note: If you set the `db_password` in the configuration as described above, you will not see the `RandomPassword` resource below.

```bash
$ pulumi up
+ pulumi:pulumi:Stack lamp-rds-wordpress-testing create
+ ├─ custom:resource:VPC wp-example-net create
+ │ ├─ aws:ec2:Vpc wp-example-net-vpc create
+ pulumi:pulumi:Stack lamp-rds-wordpress-testing create.
+ pulumi:pulumi:Stack lamp-rds-wordpress-testing create
+ │ ├─ aws:ec2:Subnet wp-example-net-subnet-us-west-2a create
+ │ ├─ aws:ec2:Subnet wp-example-net-subnet-us-west-2b create
+ │ ├─ aws:ec2:SecurityGroup wp-example-net-rds-sg create
+ │ ├─ aws:ec2:SecurityGroup wp-example-net-fe-sg create
+ │ ├─ aws:ec2:RouteTableAssociation vpc-route-table-assoc-us-west-2a create
+ │ └─ aws:ec2:RouteTableAssociation vpc-route-table-assoc-us-west-2b create
+ ├─ random:index:RandomPassword db_password create
+ ├─ custom:resource:Backend wp-example-be create
+ │ ├─ aws:rds:SubnetGroup wp-example-be-sng create
+ │ └─ aws:rds:Instance wp-example-be-rds create
+ └─ custom:resource:Frontend wp-example-fe create
+ ├─ aws:ecs:Cluster wp-example-fe-ecs create
+ ├─ aws:iam:Role wp-example-fe-task-role create
+ ├─ aws:lb:TargetGroup wp-example-fe-app-tg create
+ ├─ aws:iam:RolePolicyAttachment wp-example-fe-task-policy create
+ ├─ aws:lb:LoadBalancer wp-example-fe-alb create
+ ├─ aws:lb:Listener wp-example-fe-listener create
+ └─ aws:ecs:Service wp-example-fe-app-svc create
```

1. The program outputs the following values:

- `DB Endpoint`: This is the RDS DB endpoint. By default, the DB is deployed to disallow public access. This can be overriden in the resource declaration for the backend.
- `DB Password`: This is managed as a secret. To see the value, you can use `pulumi stack output --show-secrets`
- `DB User Name`: The user name for access the DB.
- `ECS Cluster Name`: The name of the ECS cluster created by the stack.
- `Web Service URL`: This is a link to the load balancer fronting the WordPress container. Note: It may take a few minutes for AWS to complete deploying the service and so you may see a 503 error initially.

1. To clean up resources, run `pulumi destroy` and answer the confirmation question at the prompt.

## Troubleshooting

### 503 Error for the Web Service

AWS can take a few minutes to complete deploying the WordPress container and connect the load balancer to the service. So you may see a 503 error for a few minutes right after launching the stack. You can see the status of the service by looking at the cluster in AWS.

## Deployment Speed

Since the stack creates an RDS instance, ECS cluster, load balancer, ECS service, as well as other elements, the stack can take about 4-5 minutes to launch and become ready.
64 changes: 64 additions & 0 deletions aws-py-wordpress-fargate-rds/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""
Deploys:
- Network: VPC, Subnets, Security Groups
- DB Backend: MySQL RDS
- FrontEnd: WordPress in Fargate
"""

import pulumi
import pulumi_random as random
import network
import backend
import frontend

# Get config data
config = pulumi.Config()
service_name = config.get('service_name') or 'wp-example'
db_name=config.get('db_name') or 'lampdb'
db_user=config.get('db_user') or 'admin'

# Get secretified password from config and protect it going forward, or create one using the 'random' provider.
db_password=config.get_secret('db_password')
if not db_password:
password=random.RandomPassword('db_password',
length=16,
special=True,
override_special='_%@',
)
# Pulumi knows this provider is used to create a password and thus automatically protects it going forward.
db_password=password.result

# Create an AWS VPC and subnets, etc
network=network.Vpc(f'{service_name}-net', network.VpcArgs())
subnet_ids=[]
for subnet in network.subnets:
subnet_ids.append(subnet.id)

# Create a backend DB instance
be=backend.Db(f'{service_name}-be', backend.DbArgs(
db_name=db_name,
db_user=db_user,
db_password=db_password,
# publicly_accessible=True, # Uncomment this to override for testing
subnet_ids=subnet_ids,
security_group_ids=[network.rds_security_group.id]
))

fe=frontend.WebService(f'{service_name}-fe', frontend.WebServiceArgs(
db_host=be.db.address,
db_port='3306',
db_name=be.db.name,
db_user=be.db.username,
db_password=be.db.password,
vpc_id=network.vpc.id,
subnet_ids=subnet_ids,
security_group_ids=[network.fe_security_group.id]
))

web_url=pulumi.Output.concat('https://', fe.alb.dns_name)
pulumi.export('Web Service URL', web_url)
pulumi.export('ECS Cluster Name', fe.cluster.name)

pulumi.export('DB Endpoint', be.db.address)
pulumi.export('DB User Name', be.db.username)
pulumi.export('DB Password', be.db.password)
71 changes: 71 additions & 0 deletions aws-py-wordpress-fargate-rds/backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from pulumi import ComponentResource, ResourceOptions
from pulumi_aws import rds


class DbArgs:

def __init__(self,
db_name=None,
db_user=None,
db_password=None,
subnet_ids=None,
security_group_ids=None,
allocated_storage=20,
engine='mysql',
engine_version='5.7',
instance_class='db.t2.micro',
storage_type='gp2',
skip_final_snapshot=True,
publicly_accessible=False):

self.db_name = db_name
self.db_user = db_user
self.db_password = db_password
self.subnet_ids = subnet_ids
self.security_group_ids = security_group_ids
self.allocated_storage = allocated_storage
self.engine = engine
self.engine_version = engine_version
self.instance_class = instance_class
self.storage_type = storage_type
self.skip_final_snapshot = skip_final_snapshot
self.publicly_accessible = publicly_accessible


class Db(ComponentResource):

def __init__(self,
name: str,
args: DbArgs,
opts: ResourceOptions = None):

super().__init__('custom:resource:Backend', name, {}, opts)

# Create RDS subnet group to put RDS instance on.
subnet_group_name = f'{name}-sng'
rds_subnet_group = rds.SubnetGroup(subnet_group_name,
subnet_ids=args.subnet_ids,
tags={
'Name': subnet_group_name
},
opts=ResourceOptions(parent=self)
)

rds_name = f'{name}-rds'
self.db = rds.Instance(rds_name,
name=args.db_name,
allocated_storage=args.allocated_storage,
engine=args.engine,
engine_version=args.engine_version,
instance_class=args.instance_class,
storage_type=args.storage_type,
db_subnet_group_name=rds_subnet_group.id,
username=args.db_user,
password=args.db_password,
vpc_security_group_ids=args.security_group_ids,
skip_final_snapshot=args.skip_final_snapshot,
publicly_accessible=args.publicly_accessible,
opts=ResourceOptions(parent=self)
)

self.register_outputs({})
Loading

0 comments on commit 12b04c1

Please sign in to comment.