Go-Micro

Go-Micro

So, all my blogs so far have been high-level blah blah. So, it’s now time to start delving into the actual architecture of the solution.

The backend we are developing is written in go, and we are fans of microservices. Go is pretty good with its standard libraries of being fairly capable without any frameworks at all. Our first microservices in my last gig written in go followed this belief, and what I saw was an accumulation of boilerplate.

A good microservice addresses a number of concerns, and the 12 Factor Apps approach is a good place to start getting an idea of what those should be. So, by the time you have added configuration, service discovery, logging, tracing, scaling, authentication, queueing and RPC, along with numerous other concerns, you are getting quite a bit of boilerplate. You can template that, which is what another team did, or you can adopt a framework. The challenge with templates is tracking changes. You adopt a new logging service, and you have umpteen microservices derived from an out-of-date template to update. Or, you update a library reference? We have adopted the "update a library" approach.

The gig I referred to above had, in other teams, adopted go-micro as the framework library to cover these bases. In the early days, go-micro was fairly un-opinionated and you could switch out most of the layers I mention above. But, I guess it was hard keeping many choices current so they have become somewhat more opinionated in recent times.

The reason I decided to go with the current version (1.11 at the time) was that it had sensible, workable, defaults for the base requirements.

  • Can run out of a scratch container
  • Can run in kubernetes
  • Can be configured from environment variables mapped to configmaps or secrets
  • Has reasonable logging that can be integrated to fluentd/elk
  • Has middleware options for tracing
  • Has reasonable pub/sub out the box, with pluggable options such as NATS
  • Has built-in service discovery can use MDNS (local dev), consul or even k8s services
  • Out the box API gateway
  • Health endpoint for Kubernetes

In addition, there are a set of support utilities. Micro web allows exploration of the services and RPC and micro CLI allows automation.

The bottom line is that the “hello world” example already meets most requirements, and as a service gets richer, those requirements come along for the ride. I had to add three wrappers to our default setup, which I packaged as a library:

  • Authentication support passing through claims via rpc metadata
  • Automated logging of error responses
  • Call tracing