Building a gRPC Service with Ballerina —Part III (Docker)

Kevin Hoffman
4 min readAug 6, 2018

--

In my first two blog posts in this series, I showed some sample code that illustrated a few features of the new programming language Ballerina. In case you missed them:

The second post showed how to expand on the arguably trivial “hello world” sample by adding a few more services that communicate with each other, including a service that updates state by receiving events from a broker and reports on that state via gRPC.

In this post, I’ll talk about some of the language primitives and tooling enhancements that should, theoretically, make your life easier when dealing with Docker.

Many developers operate under the illusion (delusion?) that the majority of our time is spent coding the first version of the product. I’m guilty of this myself — we devote all of our resources and creative thinking to making the “drive to first production” possible and smooth. While in this race, we lose sight of the real goal, which is to produce a deliverable application that adds value for our customers that we can maintain, observe, and rapidly update.

The truth is harsh. Most of our time is actually spent after we’ve released to production. So when I see languages and tooling that integrates this realization into its core philosophy, I’m intrigued.

Whether you’re using Kubernetes or Azure or AWS, if you’re building anything that qualifies as “cloud native” these days, you’re probably deploying containerized workloads.

I can no longer count the number of times that I’ve been burned in production by a mismatch in the intention of the compiled code and the configuration of the associated Dockerfile.

Ballerina gives us a different way of thinking about this problem. Rather than maintaining docker files as bespoke artifacts, Ballerina wants to generate the file for you, generate the docker image and, if you choose, even push the image to the registry of your choice.

I’m a big proponent of automation. Any manual process you have that can produce errors — automate. The first thing I automate on new projects is the build pipeline. Getting this right is essential for being able to reliably build and deploy new releases to production on demand.

So how does Ballerina help with this? Instead of making the developer create their own Dockerfile, it generates one for you. I understand that manually creating a docker file isn’t difficult, but it’s manual and it’s error prone and it runs a high risk of divergence from the code intended to run inside it. This process should scream “automate me!” at you.

Let’s add some Docker annotations to the drone management service file I’ve been working with so far:

Docker annotations in Ballerina

The first annotation we see is @docker:expose{}. This annotation sits on top of an endpoint definition and will expose that endpoint in the resulting Dockerfile. This is subtle but vitally important. If I now change the port number for my endpoint, the Dockerfile will change accordingly. This type of divergence is the source of well over half of all my production docker problems.

The next annotation, @docker:Config defines some configuration for the intended docker image. Ballerina will use this to produce the docker image. I can even choose to have Ballerina push the docker image by supplying the push:true flag. This annotation sits on top of my service definition.

How does this help with automation? If you check in your code, your build pipeline should automatically trigger. In this build pipeline, you can simply fire up the Ballerina container to build your code, export secret values for DOCKER_USERNAME and DOCKER_PASSWORD, point the image name at your enterprise’s private repository, and Bob will literally come over to your house and offer to be your uncle.

From a productivity standpoint, this frees developers from having to worry about the intricacies of Docker file management. From what I can tell, nearly all the customizations you might need to make to the docker process can be handled by Ballerina’s annotations (see the full list in the samples here).

Finally, this also gets your services ready for being deployed into a higher level container orchestration platform like Kubernetes, which I’ll talk about in the next blog post in the series.

As an experiment, I recently took part in a lengthy “hackathon” where my colleagues and I built a command line tool that automated the provision, build, and deployment processes. This was a huge undertaking and the resulting tool is brittle and only works in very niche scenarios.

Having these kinds of annotations and built-in language support for Docker, Kubernetes, and other things traditionally reserved for “Day Two” consideration remains one of the most unique and intriguing aspects of Ballerina to me.

Other languages that wear the phrase “Just get stuff done” as a mantle may risk losing that throne if the “stuff” being done is building and deploying cloud native integration services.

--

--

Kevin Hoffman
Kevin Hoffman

Written by Kevin Hoffman

In relentless pursuit of elegant simplicity. Tinkerer, writer of tech, fantasy, and sci-fi. Converting napkin drawings into code for @CapitalOne

No responses yet