No, Cloud Run is not better than Google Cloud Functions

Beranger Natanelic
Google Cloud - Community
11 min readApr 12, 2023

--

The right questions to ask

For more than a year, I am reading tons of articles presenting Google Cloud Run, some of them comparing Cloud Run and Cloud Functions.

The conclusion is always the same ⇒ Cloud Run is better, more complete, with more languages, more coffee and more everything.

Still, I waited more than a year before launching my first Cloud Run instance in production.

Even though this article naturally compares Cloud Run and Cloud Function, its main goal is to strike back against Cloud Run lobbyists.

Here, I will be showing why Cloud Functions is still a very good product that should be used in some cases.

Summary

Simple presentation

Comparison is not reason enough

Cloud Run advantages you might not care about

Cloud Run is not perfect

Cloud Functions is not perfect

Why I still use Cloud Functions?

Simple presentation

If you are not so familiar with Cloud Function and Cloud Run, see this presentation:

Cloud Functions: A piece of code deployed online. Responding to HTTP calls or Google Cloud events.

Cloud Run: Multiple bigger pieces of code deployed online, big enough to create a server or anything containerisable.

Both have these things in common: From a code working locally, it’s easy to go online and the rest is managed by Google Cloud. Thanks for that buddy!

Comparison is not reason enough

“This is better!”

Comparing the technical specs is catchy, we feel like we learned a lot about the product itself, and “Oh I could get a certification”!

But we don’t care about what the product does or does not.

We are not looking for a product. We are addressing a use case!

For example, in terms of timeout, we could compare the following specs:

  • Cloud Run: 60 minutes
  • Cloud Functions (1st gen): 9 minutes

Wow, Cloud Run is so cool!

The thing is, in 95% of the cases, my Cloud Functions are terminated within 2 secs.

And I think I have never seen a Cloud Functions/Cloud Run instance lasting longer than 5 minutes. It could be possible when processing files or huge data! That concerns a minority of cases.

From many aspects, Cloud Run is “more” than Cloud Functions. You can compare the specs and see. But do we need that more?

Comparing Cloud Run and Cloud Functions could make us think a product is better than another, but both fit my needs 100%. And except for a certification or a catchy blog post, comparing the two is pointless.

A truck is cooler!

Let me tell you a short story.

The story of someone looking for something to transport him from A to B.

Truck lobbyists are explaining the following things:

  • “With my truck, you can ride thousands of kilometers!”
  • “With my truck, you can carry a bear!”
  • “With my truck, you can set a bed and go for a road trip for days!”

All these advantages are cool indeed (except they didn’t mention the environmental impact of having a truck).

The thing is, the someone was looking for a something to transport him to go to work only a mile away from his house…

A truck is cool, but has multiple features not needed at all by this lost guy!!

A skateboard is a perfect fit too!

With a skateboard:

  • You can’t go thousands of kilometers away
  • You can barely carry a cat
  • You are lucky if your feet fit totally over the board

But the need to go to work a mile away is satisfied!!

The need is addressed and there are many more advantages: saved money, polluted less, no insurance, no garage, no cleaning, no driving license, no mechanical issues…

The same happens when comparing Cloud Functions and Cloud Run.

See this schema:

STOP

This schema is more complex than it seems, to deeply understand it, read this next section.

Where are we going?

The comparison between Truck-Skate and Cloud Run — Cloud Functions stops here.

Because in real life, you can use a skateboard on weekdays and a truck on weekends. No problem.

But with Cloud Functions and Cloud Run, it’s not making much sense to use both products.

As guillaume blaquiere pointed out (Thanks again!):

The simplest is to use a single product.

Because when using Cloud Functions, we will create deployment pipelines, testing processes, best practices, terraforms.

And all this setup can’t be used for Cloud Run. We have to create new pipelines, tests, best practices, new terraforms…

As Cloud Functions and Cloud Run do approximately the same job, better to pick one of them and master it.

And to know which one should be chosen, check the previous schema:

  • Are you in the yellow zone or the blue zone?
  • Will you be in the yellow zone or the blue zone in less than a year?
  • Do you have to go fast, avoid traffic jams and containers or go far with something more robust and customisable?

If you are not much of a developer and want to deploy quickly very simple services, you are in the yellow zone.

If you are discovering Google Cloud tools and want to perform various tasks with GCloud. You may be in the yellow zone.

If your services are expected to grow and you are building something big, you surely are in the blue zone, even if, at first, Cloud Functions is covering the needs.

Oh! Also: skateboarding is way cooler!

Cloud Run advantages you might not care about

Any language

With Cloud Run, you can use any language that you want!

I have seen that many times and… it’s true! It’s true and it’s awesome!

We can deploy a Groovy API using Cloud Run 🥳🍹

With Cloud Functions, we are completely stuck it’s terrible, we can only use Nodejs, Python, Go, Java, Ruby, PHP and .NET.

If we have a look at the 2022 Stackoverflow survey, these languages only represent what everybody is using daily.

The situation is the same as for the timeouts I mentioned before, my needs (and knowledge) fit 100% with Cloud Functions and Cloud Run.

Bigger server

Cloud Run is a perfect fit to deploy an API, deploy a webserver with multiple endpoints, POST, PUT, GET, LINK, PURGE, LOCK…

With Cloud Run, deploy a python server takes only a few minutes.

Frankly speaking, deploying an API using Cloud Functions only is a bit painful and a loss of time if the API has more than 3 endpoints.

Do you need to deploy an API? Will you need to?

Many needs and many requirements don’t need an API.

For instance:

Many situations require small to a very small pieces of code.

Many situations are simple, could be handled by simple Cloud Functions.

Sometimes, creating an HTTP REST web server makes no sense and is even more confusing.

Others

There are many other advantages of using Cloud Run that we care about! Like testing, containerised… We see that now!

Cloud Run is not perfect

“The learning gap is small”

In an article from a lobbyist, I read that.

The learning gap is small, true. But still, there is one.

Let’s say we have a simple function (in a Jupyter notebook for instance) responding Hello!

The function is working locally and we want to have it online.

To deploy it using Cloud Functions, here are the steps:

  • Put the dependencies into a requirements.txt file
  • Paste the function into a main.py file
  • Run this command line to deploy
gcloud functions deploy hello --region=europe-west2 --trigger-http --entry-point main --runtime python310

Puff, we are done!

Now… If we want to use Cloud Run

  • Put the dependencies into a requirements.txt file
  • Paste the function into a main.py file
  • Wrap your function into a Rest Server Framework of your choice
  • Install Docker
  • Create a Dockerfile
  • Create a container and test that your web server and container are set up correctly.
  • Run this command line to deploy
gcloud run deploy hello --region=europe-west2 --source=$(pwd)

This ain’t much if you are used to Docker and servers.

But it’s a few hours of additional learnings for someone who isn’t used to these technologies.

And, sometimes, it’s not required.

A minor change can break everything

With Cloud Run, we can deploy servers.

And when deploying a new version of route GET /books, we also have to deploy a new version of route POST /books. Even if nothing has changed, we still have to deploy the full container!

What if there is an issue with a package? It could happen that you didn’t choose a fixed package version. The server was using version 1 of Flask, after deployment, it’s using version 2 of Flask! And this can (will actually) cause an issue.

Another reason for failure could come from a common function used by POST /books and GET /books. Like a generic function for authentication.

A change in this common function could make another part crash (if the response format changes for instance.

This is normal for a server, right? It works that way.

With Cloud Functions, this thing never happens, and for a 2 endpoints API, I think I would hesitate between Cloud Run and Cloud Functions for this exact reason.

No execution ID

With Cloud Run, all logs from all endpoints from all callers arrive at the same place.

If 3 API calls arrive at the same time at the same endpoint, we could have the following logs:

date-time: Call A

date-time: Call B

date-time: success

date-time: Call C

date-time: success

date-time: failure

And there is absolutely no way to know what call failed!

Again, it’s normal for a server.

But…, you see it coming, with Cloud Functions, this thing never happens!

For every execution, there is a built-in feature of execution id attribution!

For every execution, you can get the ID and check what happens for this very execution.

It looks like that:

date-time: 1az23r Call A

date-time: 4df1As Call B

date-time: 1az23r success

date-time: 78eu3e Call C

date-time: 78eu3e success

date-time: 4df1As failure

(if you want to know how to use this ID with Cloud Functions check that)

BUT

I do exist and I did explain how to artificially create an execution id with Cloud Run.

It represents some additional dev (and reasons to crash), but it’s doable.

Log splitting

Another proof of the non-perfection of Cloud Run is when it comes to multiple API calls from multiple endpoints.

Let’s say we have endpoint GET /books, PUT /books and POST /books. We could have the following logs:

date-time: 1az23r Call to GET /books

date-time: 4df1As Call B PUT /books

date-time: 1az23r success

date-time: 78eu3e Call C POST /books

date-time: 78eu3e success

date-time: 4df1As failure

With Cloud Run, we can’t check alllll logs related to a single endpoint.

Let’s say I want to see how the POST /books endpoint is going, our only solution is to get the execution ID and check the executions one by one. But that’s not efficient.

Of course, Cloud Functions does that natively 🥳

And for this Cloud Run situation, dear reader, I didn’t find any way to split logs according to endpoints. Maybe create a specific ID for each endpoint or create structured logs. But all this setup becomes a bit complex. (if you have a clue, please comment here)

Cloud Functions is not perfect

We are stuck

Deploying many Google Cloud Functions using Google Cloud locks us into Google Cloud.

The structure is different between Cloud Functions, Lambda or Azure Functions. Switching from one to another is painful.

And we might want to quit Google Cloud to move to Lambda… Good luck with that!

Whereas with a nicely crafted container, it’s a piece of cake.

…well, no, but it’s way easier!

Functions run independently

As seen before, the more complex the project is, the more Cloud Functions are needed.

For the same project, many Cloud Functions could be needed, causing code repetition and no session, or cache management.

Not ideal, even though it’s possible to create some generic Cloud Functions called by many others as we saw here.

Cold start

Yey, Cloud Functions has to deal with a cold start. Due to its serverless condition, the function goes to sleep after a short period of inactivity.

This is okay if the Cloud Function is used for background tasks.

But for user-facing functions, it could be frustrating.

Though, cold start could be reduced, following advice listed here :

Testability

Testability is not so ideal with Cloud Functions.

Although you can use functions-framework, you are never sure it’s gonna be the same web server configuration as it is once deployed…

With Cloud Run, at least, you define your own web server.

But still, functions-framework is ok, learn more about testing and deployment of Cloud Functions here.

Why I still use Cloud Functions

Even after all these drawbacks, I am still using Cloud Functions and I really like it.

(First reason is because I started with them and still have some in production.)

The main advantages are easy scalability, cost efficiency, and low maintenance.

What I also really like is the separation between things.

I could deploy a function that crashes every time, that uses 1Gb memory, that prints terrible logs. It has no impact on anything else.

When deploying a new endpoint to a regular server, even after testing it for hours, there is still a chance that another part is affected and change its behavior (versions, dependencies…).

With Cloud Functions, this risk doesn’t exist. At all.

Above all these technical advantages, the thing I like the most about Cloud Functions is the power it gives us.

Realising that any piece of code could be online after 2 little minutes is so hhuuuuuuuuuuuuuuuggggeeeeeee!

With Cloud Functions, we need a short period to deploy the backend of “The Facemash” that Mark Zuckerberg deployed in a few days. Without the scalability issues that he faced!

Huge!

Now you know everything I know.

I hope it helps and it’s accurate.

Bi!

--

--

Beranger Natanelic
Google Cloud - Community

Daily Google Cloud Platform user. I am sharing learnings of my tries, struggle and success.