I have been spending a lot of the last year learning about Google Cloud Platform (GCP). Two of the best technologies on GCP are Container Engine and Cloud Functions (with an emphasis on the Firebase side for the latter). Both are powerful and as a developer it is easy to default to Cloud Functions because it takes a lot of administrative work out of my hands. This administrative work, albeit declarative yaml files is an important aspect to configuring Container Engine’s star technology, Kubernetes.
I was talking to a developer a couple weeks ago about these technologies and he asked a simple question, “when would you choose Kubernetes over Cloud Functions?”. It’s a question I have considered a lot myself since working with both of these, and so I think the best way to handle this is to default to Cloud Functions and explain the instances where Kubernetes and Container Engine would be a better choice. While I do not catalog every reason, here are the top several that play into choosing Kubernetes.
Node.js is not going to cut it
When using Cloud Functions at the moment you have only one development environment to work with and that is Node.js. This is an incredible technology and it is powerful. However, this might not fit your needs. Perhaps, you need to work in Go, Python, or some other language because it just makes sense.
I would rather build a neural network using Python versus JavaScript any day. I have entertained the idea of using the Core Foundation libraries from Apple in a service. That service will need to be written in Swift. These are just some of the cases that might involve using a different language and set of frameworks. In the future, I can see Cloud Functions supporting these technologies, but that will take quite a few years before it is in production.
Speed
Speed, and I mean right now, not in 200 ms. This is a fundamental difference. There are instances when you just want to get data and push it somewhere. If a Cloud Function is not used for sometime then all instances of that function are shut down. This is a good thing, you are not paying anything if you are not using it. However, there might be instances where you just don’t want to wait for that cold start time. If that isn’t an option then Kubernetes will have your back, you are already a cluster and you can have a couple pods running for that particular service ready to jump into action when the need arises.
I will admit this is a bit of grey area for me. I’ve used Cloud Functions on Firebase since they have went into beta, and I am not fully sure when the last instance is destroyed and if they would ever change that policy for the necessity of speed across all functions. Nevertheless, using the Cloud Functions you can see that if you don’t fire a database trigger for quite some time there is a slow start time the first time it runs. Afterwards every successive call runs 10x faster.
Invocation Madness
How many times are you invoking the function? Is it one hundred or one hundred thousand times in a day? It’s different if your cloud function is relying on a firebase database trigger, at that point it’s worth settling for the Cloud Function. However, if you are trying to build a service that is going to be validating emails and you need to validate a ridiculous amount of them, then it’s worth considering Kubernetes. First, you can always have a few instances running so your reducing any latency on the service. Second, with Cloud Functions part of the price is how many times a function is invoked. With Kubernetes you are able to scale up to more instances during peak times then scale back down. It doesn’t matter if your service is invoked ten thousand times, at this point you are paying for the number of nodes and pods that you are running which will reduce your overall costs.
Microservice Communication
Finally, we have service-to-service communication. Cloud functions have some really powerful triggers for both Firebase and GCP. For instance, you can setup a Cloud Pub/Sub trigger or trigger another function by uploading files to Cloud Storage. In addition, we have HTTP triggers which are helpful for creating web hooks.
However, what if you have several services that don’t need to be triggered, but you just want them to talk to each other? This is another compelling reason to choose Kubernetes over Cloud Functions. I have found gRPC to be amazing. The speed of serializing and deserializing with protocol buffers, and the small packet size that is sent over the wire is a compelling reason to adopt gRPC.
At the moment talking and communicating between services isn’t really an effective approach when using Cloud Functions. In fact, the best approach might be leveraging both technologies. You can use the Cloud Function HTTP trigger as a web hook which will then call into a bunch of microservices that are running on Kubernetes and communicating through gRPC. Ultimately, it depends on what you are building and what your needs are, but if you are juggling the idea of calling multiple HTTP function triggers based on one call into your Cloud Functions then you should step back and ask yourself whether Kubernetes is a better option for the 90% intercommunication that is occurring.
This list is not exhaustive and it is definitely open for interpretation. Again, it’s based on your needs as a company and organization. Kubernetes is still in its early days and not everyone has a developer on hand that can manage a Container Engine project for them. On the other hand, maybe you have a lot of .NET Core services that you want to deploy and Cloud Functions just won’t cut it because you need to use Node.js. It’s always worth taking a step back and thinking about the different technologies at play and how we can leverage them to be as productive as possible.