DEV Community

Cover image for How to Autoscale Node.js Image Transformations Using Sharp and Express
Rémy Apfelbacher
Rémy Apfelbacher

Posted on

How to Autoscale Node.js Image Transformations Using Sharp and Express

Automation of application scaling is one of the key benefits of PaaS. The following example shows how you can use this ability in Zerops, a developer-first app platform – specifically, when transforming images by scaling or rotating them using Node.js.

Note: Please be aware that the example code is not meant to have production code quality. The purpose is to demonstrate the scaling feature of Zerops. In the following, we assume that you have a Zerops account and an installed zcli (Zerops command line tool) available.

Writing your code

The code is fairly simple. It uses Express and Sharp to perform the actual work. Thus please execute the following in a folder of your choice:

npm i express sharp
Enter fullscreen mode Exit fullscreen mode

This will install all dependencies in a folder node_modules and more importantly create files package.json and package-lock.json.

Then please create the file index.js and insert the following code:

const sharp = require("sharp")
const express = require('express')
const expressServer = express()

expressServer.get('/image', (request, response) => {

  const requestedWidth = request.query.width ? parseInt(request.query.width) : 300;
  const requestedHeight = request.query.height ? parseInt(request.query.height) : 300;
  const requestedAngle = request.query.angle ? parseInt(request.query.angle) : 0;
  const format = 'jpg';

  console.log(`Handling image: size to ${requestedWidth}x${requestedHeight} and rotation to ${requestedAngle}`)

  sharp('example.jpg')
    .resize(requestedWidth, requestedHeight, {
      fit: sharp.fit.inside,
    })
    .rotate(requestedAngle)
    .toFormat(format)
    .toBuffer()
    .then(function (outputBuffer) {
      response.type(format);
      response.end(outputBuffer)
    });
})

expressServer.listen(3000, () => {
  console.log(`Listening on port 3000.`)
})
Enter fullscreen mode Exit fullscreen mode

You can use any jpg image as example.jpg. Please put one in that folder.
That's it. Just regular code (and an image).

Setting up the project in Zerops

Once you have the code ready, you need to create a project in Zerops. For that purpose, please:

  1. login to Zerops
  2. create a project by clicking on Add new project
  3. specify a project name e.g. image
  4. choose Node.js as service to be added
  5. click Set to high availability?
  6. click add

This sets your Node.js runtime to high availability meaning it will perform vertical and horizontal scaling automatically. Vertical scaling means simply adjusting the amount of resources in your container whereas horizontal scaling adjusts the number of containers. You can read more about it here.

Build and deploy on Zerops

The following steps describe how you can build and deploy the example as a Zerops application.

  • For Zerops to know which files to use please also create a zerops.yml file next the other files:
nodejs0:
  build:
    base: [ nodejs@16 ]
    build:
      - npm ci
    cache: [ node_modules ]
    deploy: [ index.js, example.jpg, node_modules ]
  run:
    start: node index.js
Enter fullscreen mode Exit fullscreen mode
  • Simply deploy your file
zcli push "image" nodejs0
Enter fullscreen mode Exit fullscreen mode
  • Enable Zerops subdomain access via Public access & internal ports on the nodejs0 service and invoke the pre-generated URL in your browser.

Autoscaling in action

So far we deployed the code only without seeing the autoscaling in action. For that purpose we will use k6 to generate some load.

No worries, Zerops won't scale to infinity without keeping your expenses under control. You can adjust the maximum and minimum resources for both vertical and horizontal scaling easily every time you see fit. Zerops will do the rest.

Here the script to generate some load k6.js:

import http from 'k6/http';
import { check } from 'k6';

export default function () {
  const baseUrl = "https://<your-generated-subdomain>.usc1.contabozerops.com"
  const width = 300 + Math.random() * 1000
  const height = 300 + Math.random() * 1000
  const angle = Math.random() * 360
  const res = http.get(`${baseUrl}/image?width=${width}&height=${height}&angle=${angle}`)
  check(res, {
    'is status 200': (r) => r.status === 200,
  });
}
Enter fullscreen mode Exit fullscreen mode

And then run it by invoking

k6 run --vus 100 --duration 120s k6.js
Enter fullscreen mode Exit fullscreen mode

This will simulate a 100 users requesting the image service as fast as possible during 120 seconds.

Our example is mainly a CPU-intensive task so you will see the number of vCPUs (virtual CPUs) rise -- vertical scaling -- and after a short time also see more containers being created -- horizontal scaling. Please refer to the following screenshot where you see many vCPUs and 4 containers.
Zerops Scaling up -- vertically and horizontally

After the k6 script finished generating the load, Zerops will wait for a moment to make sure the demand has really gone down. Then you'll first see the vertical autoscaling taking action by reducing vCPUs (due to the nature of our example). The number of vCPUs has dramatically decreased.
Zerops Scaling -- vertical cool down

After a while, Zerops will perform the horizontal autoscaling as well. As the k6 script finished generating load and we don't have any more coming, the starting point with two containers will be reached as shown in the screenshot.
Zerops Scaling -- horizontal cool down

Summary

Zerops is performing both vertical and horizontal autoscaling out of the box with a single click. Just like shown in the example above. No need to have a special code or knowledge. It both saves money and gives you more power when required.

For a deeper dive into what’s happening behind the scenes of Zerops autoscaling, check out my previous article.

Top comments (0)