The case against serverless

Has lambda been superseded by kubernetes? Are we better off with the versatility of just instantiating a docker image than being forced into lambda protocols?

The case against serverless

Has lambda been superseded by kubernetes? Are we better off with the versatility of just instantiating a docker image than being forced into lambda protocols?

There has been a movement towards serverless for some time now. The argument is that horizontal scaling of services is something that humans should not spend their valuable time concerning themselves with.

There are a large number of solutions out there to autoscale services on demand.

Say, you want to create a "Hello World" service (who wouldn't) and make it able to service arbitrarily many requests on demand, but you don't want to spend money running a lot of servers which will just be idling between load peaks.

The service could look something like this:

import express, { Request, Response } from 'express';

const app = express();

app.get('/', (res: Request, res: Response) => {
  res.send('Hello World!');


This is a nice web service which has the clear benefit that you can run it locally, test it, and debug it in your local development environment without any changes to your usual setup.

AWS Lambda

If you want to be able to achieve the same with lambda, won't be able to simply run it locally any more. At least not without extensive extra setup in your local development environment.

For starters, the "Hello World" service now looks like this:

import { 
} from 'aws-lambda';

export const lambdaHandler = async (
  event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
  return {
    statusCode: 200,
    body: `Hello World!`

This obviously means that you won't be able to simply start the service and hit it with curl to run a test query.

You will also need to deal with AWS Lambda setup, which I won't get into details with, but suffice to say that it is rather involved.

To be fair, you can get a local development environment up and running with hot reload for easier development, once you have gone through all of this pain, but to be honest it all really seems rather pointless, when all you really want is to scale the number of instances you are running up on demand, and not have to deal with server provisioning and configuration.

On top of all the hurdles, you will have vendor lockin on top of that, so porting your services out of AWS and into Google Cloud or other competing services will be a significant pain.


There are, of course, alternatives out there, which will mitigate issues such as vendor lockin.


Fission, for instance, has a developer experience which is almost identical to AWS Lambda, but running on top of Kubernetes, to make it vendor agnostic, and to make it relatively easy to run on Docker Desktop if you want to run your setup locally (which is nice).


Knative, allows you to run a webservice with zero changes to the actual service, so you get all the benefits of easy local development, with something that is actually still just a web server, along with all the benefits of serverless.

The configuration needed to deploy your webserver is relatively simple (once you dockerize your webservice and push it to docker hub):

kind: Service
 name: helloworld
 namespace: default
    - image: my-user/hello-world
        - name: TARGET
          value: "Hello World!"


These alternatives do come with their own sets of configuration hurdles which you need to take care of if you want to customize your endpoint or your load balancer configuration (e.g. if you want to know the client IP behind a load balancer, then you will most likely need to set up proxy protocol).


These alternatives do require that you have a Kubernetes setup running with your hosting provider (which is usually relatively simple to get). As long as you are already setting up Kubernetes then you might as well do the slight extra step and get the full flexibility of specifying your Ingress and endpoint configuration yourself. It's really not a lot of extra work, with a lot of extra gained value:

apiVersion: apps/v1
kind: Deployment
  name: my-project
  replicas: 1
      app: my-project
        app: my-project
      - name: my-project
        image: my-user/my-project
        - containerPort: 8080
apiVersion: v1
kind: Service
  name: my-service
  type: ClusterIP
  - port: 80
    targetPort: 8080
    app: my-service
kind: Ingress
  name: my-ingress
  annotations: nginx letsencrypt-prod
  - hosts:
    secretName: my-tls
  - host:
      - path: /
        pathType: Prefix
            name: my-service
              number: 80


Why would I want to deal with the added complexity of Kubernetes, when I can "just" use lambdas?

It turns out that defining the services and describing an image is a one-shot kind of endeavour, whereas running a service locally happens every time you update a line of code and re-run your tests.

I would much rather optimise for ease of running curl or using Postman as opposed to needing special client software to test my software just because it needs some esoteric environment to be spun up.

It is really all about optimising for minimising developer time, rather than optimising for making it easy for the computers.