Containers on AWS with SST
Create and deploy a container to AWS with SST.
We are going to build Express app in a container, add an S3 Bucket for file uploads, and deploy it to AWS using SST.
Before you get started, make sure to configure your AWS credentials.
1. Create a project
Let’s start by creating our Express app.
mkdir my-express-app && cd my-express-appnpm init -ynpm install express
Init Express
Create your app by adding an index.mjs
to the root.
import express from "express";
const PORT = 80;
const app = express();
app.get("/", (req, res) => { res.send("Hello World!")});
app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`);});
Init SST
Now let’s initialize SST in our app. Make sure to add the @ion
part.
npx sst@ion initnpm install
This’ll create a sst.config.ts
file in your project root.
2. Add a Cluster
To deploy our Express app, let’s add an AWS Fargate container with Amazon ECS. Update your sst.config.ts
.
async run() { const vpc = new sst.aws.Vpc("MyVpc");
const cluster = new sst.aws.Cluster("MyCluster", { vpc });
cluster.addService("MyService", { public: { ports: [ { listen: "80/http" }, ], dev: { command: "node --watch index.mjs", }, }, });}
This creates a VPC, uses it for a new ECS Cluster, adds a Fargate service to it, and exposes it through http.
The dev.command
tells SST to run our Express app locally in dev mode.
Create a Dockerfile
Let’s add a Dockerfile
in the root with the following.
FROM node:18-bullseye-slim
WORKDIR /app/
COPY package.json /appRUN npm install
COPY index.mjs /app
ENTRYPOINT ["node", "index.mjs"]
3. Add an S3 Bucket
Let’s add a public
S3 Bucket for file uploads. Update your sst.config.ts
.
const bucket = new sst.aws.Bucket("MyBucket", { public: true});
Link the bucket
Now, link the bucket to the container service.
cluster.addService("MyService", { // ... link: [bucket],});
This will allow us to reference the bucket in our Express app.
Start dev mode
Start your app in dev mode.
npx sst dev
Once complete, click on MyService in the sidebar for your local Express app.
4. Upload a file
We want the /
route of our API to upload a file to our S3 Bucket. Let’s start by installing the npm packages we’ll use for the upload.
npm install multer @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner
Add the relevant imports.
import multer from "multer";import { Resource } from "sst";import { Upload } from "@aws-sdk/lib-storage";import { getSignedUrl } from "@aws-sdk/s3-request-presigner";import { S3Client, GetObjectCommand, ListObjectsV2Command } from "@aws-sdk/client-s3";
const s3 = new S3Client({});const upload = multer({ storage: multer.memoryStorage() });
And add the route to your index.mjs
.
app.post("/", upload.single("file"), async (req, res) => { const file = req.file; const params = { Bucket: Resource.MyBucket.name, Key: file.originalname, Body: file.buffer };
const upload = new Upload({ params, client: s3, });
await upload.done();
res.status(200).send("File uploaded successfully.");});
5. Download a file
We want the /latest
route of our app to generate a pre-signed URL to download the last uploaded file in our S3 Bucket. Add this to your index.mjs
.
app.get("/latest", async (req, res) => { const objects = await s3.send( new ListObjectsV2Command({ Bucket: Resource.MyBucket.name, }) );
const latestFile = objects.Contents.sort((a, b) => b.LastModified - a.LastModified)[0];
const command = new GetObjectCommand({ Key: latestFile.Key, Bucket: Resource.MyBucket.name, }); const url = await getSignedUrl(s3, command);
res.redirect(url);});
Test your app
Let’s try uploading a file from your project root.
curl -F file=@package.json http://localhost:80
Now head over to http://localhost:80/latest
in your browser and it’ll download the file you just uploaded.
6. Deploy your app
Now let’s deploy your app.
npx sst deploy --stage production
You can use any stage name here but it’s good to create a new stage for production. This’ll give the URL of your Express app deployed as a Fargate service.
+ Complete MyService: http://jayair-MyServiceLoadBala-592628062.us-east-1.elb.amazonaws.com
Connect the console
As a next step, you can setup the SST Console to git push to deploy your app and monitor it for any issues.
You can create a free account and connect it to your AWS account.