sketchboard blog

Serverless image resize with Amazon Lambda function

By Saiki Tanabe May 25, 2017

Did you know that you can implement image resize on the fly without maintaining your servers, just by deploying a logic how to resize images.

With Amazon AWS Lambda you can achieve that. There are some natural benefits when you use Lambda functions. E.g., you don’t need to apply security patches to the operating system, and you can just concentrate on the logic.

The following mixed architecture and flow chart diagram describes how we implemented user profile image resize with AWS CloudFront, Amazon API Gateway, S3 and AWS Lambda.

Sketchboard Profile Image Architecture

You can copy and paste this sketch diagram to Sketchboard.

  1. Browser requests resized image from Amazon CloudFront
  2. Image is not in CloudFront Cache, and Cloud Front fetches it from S3
  3. Resized image is not found in S3 and request is redirected to Amazon API Gateway
  4. Browser follows redirect to Amazon API Gateway
  5. API Gateway triggers Lambda function to resize the image
  6. Lambda function gets an original image from S3 and resizes it to the desired size. Lambda function puts the resized image to S3.
  7. Lambda function permanently redirects (301) request back to CloudFront using the original key
  8. Resized image is requested again from CloudFront
  9. Now CloudFront gets the image from S3 and puts it to the cache and image is served to the browser.

Configuration

Here you can find the Amazon blog post how to implement image resizing with AWS. Their example source code is available on serverless-image-resizing repository.

Amazon blog post describes how to set up

  • AWS Lambda function that implements the resize logic
  • AWS S3 needs to be configured as a static website. Then S3 supports redirect rules.
  • IAM configuration to allow Lambda function to put resized images on S3
  • Amazon API Gateway to trigger the Lambda function

Amazon CloudFront configuration

Sketchboard requires all images to be served through HTTPS. Currently, S3 static website hosting does not directly provide access through HTTPS. We use CloudFront in front of S3 to serve images with HTTPS, and also to get the benefit of serving images faster for the users.

To setup Amazon CloudFront

  1. Create Distribution
  2. Pick “Get Started” under web distribution
  3. Setup origin to be fetched through S3 static website endpoint. Otherwise, S3 redirect rules are not working.
    • Go to Amazon S3
    • Choose bucket that is configured for static website hosting
    • Select Properties tab
    • Open Static website hosting, and copy Endpoint URL

S3 static website property tab

S3 static website endpoint

  1. Paste S3 endpoint as Origin Domain Name
  2. Optionally define Origin Path

Having CloudFront in front of S3 brings one extra challenge when requesting an image that is not found in S3, the not found response is cached, and you will end up in a redirect loop, and resized image is not generated and uploaded to S3.

You can overcome this by defining a behavior for image types that are resized. With behaviors, you can set up a default TTL to be 0 for the pictures that are supported. Setup means that

  • On the first time when image is requested from CloudFront, CloudFront uses Default TTL that is 0 and doesn’t cache the not found response from S3
  • On the second occasion, CloudFront uses Default TTL from max-age that is defined for the image in S3

Create Behaviour on CloudFront

Create Behaviour on CloudFront

Following JavaScript snippet defines CacheControl max-age to 14 days when uploading a resized image to S3, see Example Lambda Function for details.

// how many days in seconds
const maxAge = 14 * 24 * 60 * 60

return S3.putObject({
  Body: buffer,
  Bucket: bucket,
  ContentType: 'image/jpeg',
  CacheControl: `max-age=${maxAge}`,
  Key: key
})

Thoughts on Writing the Lambda resize logic

You can choose between multiple languages to write the logic. We selected Node.js environment with JavaScript. Plain JavaScript is not our preferred choice when we can choose a statically typed language since we are huge fans of statically typed languages due to the tooling and many times easier maintenance. We decided to write the logic in TypeScript that is compiled to JavaScript.

When choosing Node.js, you can also use Sharp, a high-performance image processing library. Sharp makes on the fly image resizing fast and simple.

There is some penalty when using custom Node.js libraries; you need to build your Lambda function on a Linux machine and deploy a function.zip file that includes the custom libraries. The function.zip file becomes easily over 20 MB when it is deployed, and you cannot edit the plain JavaScript file on Lambda console.

Deployment takes some time (depending on a network connection speed), and you cannot thoroughly test AWS Lambda function functionality on a development machine. Even for simple logic, it is a good idea to use unit tests, to verify also small logic changes to avoid multiple test deployments that take some time.

Deploying Lambda Code

You can deploy function in a number of different ways, e.g. uploading zip file directly from the Lambda console, but that is a little bit time consuming or using S3. We chose to update function using AWS Command Line interface.

The following command line command deploys service to Lambda. We use Makefile, and this gets an own deploy target in there.

aws lambda update-function-code --function-name arn:aws:lambda:region:your-lambda-function --zip-file fileb://dist/function.zip --publish

Summary of AWS services roles

Summary of used AWS services to scale images on the fly