-
Notifications
You must be signed in to change notification settings - Fork 879
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
296 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
name: aws-ts-lambda-efs | ||
runtime: nodejs | ||
description: Examples of using Lambda + EFS | ||
template: | ||
config: | ||
aws:region: | ||
description: The AWS region to deploy into | ||
default: us-east-2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new) | ||
|
||
# Using Amazon EFS with AWS Lambda | ||
|
||
This example shows how to use Amazon EFS with AWS Lambda in Pulumi. See the [Using AWS Lambda with Amazon Elastic File System (EFS)](https://www.pulumi.com/blog/aws-lambda-efs) blog post for a detailed walkthrough of this example. | ||
|
||
![Architecture Diagram](./lambdaefs.png) | ||
|
||
## Prerequisites | ||
|
||
- [Node.js](https://nodejs.org/en/download/) | ||
- [Download and install the Pulumi CLI](https://www.pulumi.com/docs/get-started/install/) | ||
- [Connect Pulumi with your AWS account](https://www.pulumi.com/docs/intro/cloud-providers/aws/setup/) (if your AWS CLI is configured, no further changes are required) | ||
|
||
## Running the Example | ||
|
||
After cloning this repo, `cd` into it and run these commands: | ||
|
||
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. 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 (demo): | ||
Type Name Status | ||
+ pulumi:pulumi:Stack aws-ts-lambda-efs-demo created | ||
+ ├─ awsx:x:ec2:Vpc vpc created | ||
+ │ ├─ aws:ec2:Vpc vpc created | ||
+ │ ├─ awsx:x:ec2:Subnet vpc-public-0 created | ||
+ │ │ ├─ aws:ec2:Subnet vpc-public-0 created | ||
+ │ │ ├─ aws:ec2:RouteTable vpc-public-0 created | ||
+ │ │ ├─ aws:ec2:Route vpc-public-0-ig created | ||
+ │ │ └─ aws:ec2:RouteTableAssociation vpc-public-0 created | ||
+ │ ├─ awsx:x:ec2:Subnet vpc-public-1 created | ||
+ │ │ ├─ aws:ec2:RouteTable vpc-public-1 created | ||
+ │ │ ├─ aws:ec2:Subnet vpc-public-1 created | ||
+ │ │ ├─ aws:ec2:RouteTableAssociation vpc-public-1 created | ||
+ │ │ └─ aws:ec2:Route vpc-public-1-ig created | ||
+ │ ├─ awsx:x:ec2:NatGateway vpc-1 created | ||
+ │ │ ├─ aws:ec2:Eip vpc-1 created | ||
+ │ │ └─ aws:ec2:NatGateway vpc-1 created | ||
+ │ ├─ awsx:x:ec2:Subnet vpc-private-0 created | ||
+ │ │ ├─ aws:ec2:RouteTable vpc-private-0 created | ||
+ │ │ ├─ aws:ec2:Subnet vpc-private-0 created | ||
+ │ │ ├─ aws:ec2:RouteTableAssociation vpc-private-0 created | ||
+ │ │ └─ aws:ec2:Route vpc-private-0-nat-0 created | ||
+ │ ├─ awsx:x:ec2:InternetGateway vpc created | ||
+ │ │ └─ aws:ec2:InternetGateway vpc created | ||
+ │ ├─ awsx:x:ec2:Subnet vpc-private-1 created | ||
+ │ │ ├─ aws:ec2:RouteTable vpc-private-1 created | ||
+ │ │ ├─ aws:ec2:Subnet vpc-private-1 created | ||
+ │ │ ├─ aws:ec2:RouteTableAssociation vpc-private-1 created | ||
+ │ │ └─ aws:ec2:Route vpc-private-1-nat-1 created | ||
+ │ └─ awsx:x:ec2:NatGateway vpc-0 created | ||
+ │ ├─ aws:ec2:Eip vpc-0 created | ||
+ │ └─ aws:ec2:NatGateway vpc-0 created | ||
+ ├─ aws:apigateway:x:API api created | ||
+ │ ├─ aws:apigateway:RestApi api created | ||
+ │ ├─ aws:apigateway:Deployment api created | ||
+ │ ├─ aws:lambda:Permission api-2c087c3e created | ||
+ │ ├─ aws:lambda:Permission api-c171fd88 created | ||
+ │ ├─ aws:lambda:Permission api-7857d17d created | ||
+ │ └─ aws:apigateway:Stage api created | ||
+ ├─ awsx:x:ecs:FargateService nginx created | ||
+ │ └─ aws:ecs:Service nginx created | ||
+ ├─ awsx:x:ecs:FargateTaskDefinition nginx created | ||
+ │ ├─ aws:iam:Role nginx-execution created | ||
+ │ ├─ aws:cloudwatch:LogGroup nginx created | ||
+ │ ├─ aws:iam:Role nginx-task created | ||
+ │ ├─ aws:iam:RolePolicyAttachment nginx-execution-9a42f520 created | ||
+ │ ├─ aws:iam:RolePolicyAttachment nginx-task-32be53a2 created | ||
+ │ ├─ aws:iam:RolePolicyAttachment nginx-task-fd1a00e5 created | ||
+ │ └─ aws:ecs:TaskDefinition nginx created | ||
+ ├─ awsx:x:ec2:SecurityGroup nginx-0 created | ||
+ ├─ awsx:x:ecs:Cluster cluster created | ||
+ │ ├─ aws:ecs:Cluster cluster created | ||
+ │ └─ awsx:x:ec2:SecurityGroup cluster created | ||
+ │ ├─ awsx:x:ec2:IngressSecurityGroupRule cluster-containers created | ||
+ │ │ └─ aws:ec2:SecurityGroupRule cluster-containers created | ||
+ │ ├─ awsx:x:ec2:EgressSecurityGroupRule cluster-egress created | ||
+ │ │ └─ aws:ec2:SecurityGroupRule cluster-egress created | ||
+ │ ├─ awsx:x:ec2:IngressSecurityGroupRule cluster-ssh created | ||
+ │ │ └─ aws:ec2:SecurityGroupRule cluster-ssh created | ||
+ │ └─ aws:ec2:SecurityGroup cluster created | ||
+ ├─ aws:iam:Role getHandler created | ||
+ ├─ aws:iam:Role execHandler created | ||
+ ├─ aws:efs:FileSystem filesystem created | ||
+ ├─ aws:iam:Role uploadHandler created | ||
+ ├─ aws:iam:RolePolicyAttachment execHandler-32be53a2 created | ||
+ ├─ aws:iam:RolePolicyAttachment execHandler-23f1a522 created | ||
+ ├─ aws:iam:RolePolicyAttachment getHandler-32be53a2 created | ||
+ ├─ aws:iam:RolePolicyAttachment getHandler-23f1a522 created | ||
+ ├─ aws:iam:RolePolicyAttachment uploadHandler-32be53a2 created | ||
+ ├─ aws:iam:RolePolicyAttachment uploadHandler-23f1a522 created | ||
+ ├─ aws:efs:MountTarget fs-mount-1 created | ||
+ ├─ aws:efs:MountTarget fs-mount-0 created | ||
+ ├─ aws:efs:AccessPoint ap created | ||
+ ├─ aws:lambda:Function getHandler created | ||
+ ├─ aws:lambda:Function uploadHandler created | ||
+ └─ aws:lambda:Function execHandler created | ||
|
||
Outputs: | ||
url: "https://280f2167f1.execute-api.us-east-1.amazonaws.com/stage/" | ||
|
||
Resources: | ||
+ 75 created | ||
|
||
Duration: 5m52s | ||
``` | ||
|
||
4. At this point, your app is running! The URL was published so it's easy to interact with: | ||
```bash | ||
$ curl -X POST -d '<h1>Hello world</h1>' $(pulumi stack output url)files/index.html | ||
$ curl -X GET $(pulumi stack output url)files/file.txt | ||
<h1>Hello world</h1> | ||
``` | ||
5. Once you are done, you can destroy all of the resources, and the stack: | ||
```bash | ||
$ pulumi destroy | ||
$ pulumi stack rm | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Copyright 2016-2019, Pulumi Corporation. All rights reserved. | ||
|
||
import * as aws from "@pulumi/aws"; | ||
import * as awsx from "@pulumi/awsx"; | ||
import * as fs from "fs"; | ||
import * as cp from "child_process"; | ||
|
||
export = async () => { | ||
|
||
// VPC | ||
const vpc = new awsx.ec2.Vpc("vpc", { subnets: [{ type: "private" }, { type: "public" }] }); | ||
const subnetIds = await vpc.publicSubnetIds; | ||
|
||
// EFS | ||
const filesystem = new aws.efs.FileSystem("filesystem"); | ||
const targets = []; | ||
for (let i = 0; i < subnetIds.length; i++) { | ||
targets.push(new aws.efs.MountTarget(`fs-mount-${i}`, { | ||
fileSystemId: filesystem.id, | ||
subnetId: subnetIds[i], | ||
securityGroups: [vpc.vpc.defaultSecurityGroupId], | ||
})); | ||
} | ||
const ap = new aws.efs.AccessPoint("ap", { | ||
fileSystemId: filesystem.id, | ||
posixUser: { uid: 1000, gid: 1000 }, | ||
rootDirectory: { path: "/www", creationInfo: { ownerGid: 1000, ownerUid: 1000, permissions: "755" } }, | ||
}, { dependsOn: targets }); | ||
|
||
// Lambda | ||
function efsvpcCallback(name: string, f: aws.lambda.Callback<awsx.apigateway.Request, awsx.apigateway.Response>) { | ||
return new aws.lambda.CallbackFunction(name, { | ||
policies: [aws.iam.ManagedPolicies.AWSLambdaVPCAccessExecutionRole, aws.iam.ManagedPolicies.AWSLambdaFullAccess], | ||
vpcConfig: { | ||
subnetIds: vpc.privateSubnetIds, | ||
securityGroupIds: [vpc.vpc.defaultSecurityGroupId], | ||
}, | ||
fileSystemConfigs: [{ arn: ap.arn, localMountPath: "/mnt/storage" }], | ||
callback: f, | ||
}); | ||
} | ||
|
||
// API Gateway | ||
const api = new awsx.apigateway.API("api", { | ||
routes: [ | ||
{ | ||
method: "GET", path: "/files/{filename+}", eventHandler: efsvpcCallback("getHandler", async (ev, ctx) => { | ||
try { | ||
const f = "/mnt/storage/" + ev.pathParameters!.filename; | ||
const data = fs.readFileSync(f) | ||
return { | ||
statusCode: 200, | ||
body: data.toString(), | ||
}; | ||
} catch { | ||
return { statusCode: 500, body: "" } | ||
} | ||
}), | ||
}, | ||
{ | ||
method: "POST", path: "/files/{filename+}", eventHandler: efsvpcCallback("uploadHandler", async (ev, ctx) => { | ||
try { | ||
const f = "/mnt/storage/" + ev.pathParameters!.filename; | ||
const data = new Buffer(ev.body!, 'base64'); | ||
fs.writeFileSync(f, data) | ||
return { | ||
statusCode: 200, | ||
body: "", | ||
}; | ||
} catch { | ||
return { statusCode: 500, body: "" } | ||
} | ||
}), | ||
}, | ||
{ | ||
method: "POST", path: "/", eventHandler: efsvpcCallback("execHandler", async (ev, ctx) => { | ||
const cmd = new Buffer(ev.body!, 'base64').toString() | ||
const buf = cp.execSync(cmd); | ||
return { | ||
statusCode: 200, | ||
body: buf.toString(), | ||
}; | ||
}), | ||
}, | ||
], | ||
}); | ||
|
||
// ECS Cluster | ||
const cluster = new awsx.ecs.Cluster("cluster", { vpc: vpc }); | ||
const efsVolumeConfiguration: aws.types.input.ecs.TaskDefinitionVolumeEfsVolumeConfiguration = { | ||
fileSystemId: filesystem.id, | ||
authorizationConfig: { accessPointId: ap.id, }, | ||
rootDirectory: "/www", | ||
}; | ||
|
||
// Fargate Service | ||
const nginx = new awsx.ecs.FargateService("nginx", { | ||
cluster: cluster, | ||
taskDefinitionArgs: { | ||
container: { | ||
image: "nginx", | ||
memory: 128, | ||
portMappings: [{ containerPort: 80, hostPort: 80, protocol: "tcp" }], | ||
mountPoints: [{ containerPath: "/usr/share/nginx/html", sourceVolume: "efs" }], | ||
}, | ||
volumes: [{ name: "efs", efsVolumeConfiguration }], | ||
}, | ||
securityGroups: [vpc.vpc.defaultSecurityGroupId, ...cluster.securityGroups], | ||
subnets: vpc.publicSubnetIds, | ||
platformVersion: "1.4.0", | ||
}); | ||
|
||
// Exports | ||
return { | ||
url: api.url, | ||
}; | ||
|
||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "aws-ts-lambda-efs", | ||
"version": "0.1.0", | ||
"dependencies": { | ||
"@pulumi/aws": "^2.10.0", | ||
"@pulumi/awsx": "^0.20.0", | ||
"@pulumi/pulumi": "^2.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"compilerOptions": { | ||
"outDir": "bin", | ||
"target": "es2016", | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"sourceMap": true, | ||
"experimentalDecorators": true, | ||
"pretty": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"noImplicitAny": true, | ||
"noImplicitReturns": true, | ||
"forceConsistentCasingInFileNames": true, | ||
"strictNullChecks": true | ||
}, | ||
"files": [ | ||
"index.ts" | ||
] | ||
} |