Last time, I brought up the concept of template services. Today I want to share more details on what we do with this concept.
Reference Architecture
Sometimes you will hear architects talk about a reference architecture. This is the concept of having an established pattern out in the wild with real examples. An architecture that you can… reference. This is popular for microservices. Microservices are small enough to be provided in bite-size, understandable pieces. They also embody a slew of difficult concepts around distributed computing. So they lend themselves well to this technique.
When we adopted a microservice architecture, we also saw that providing “living, breathing” reference architectures would be invaluable. So we created what we called “template services”. These are services that meet the minimum requirements we needed to impose, in the frameworks we knew would be used. The services have no business value; they don’t do anything. But they are still deployed, as a way to help ensure they are complete and kept up to date.
Our template services flush out certain “architectural” requirements, such as setting up a log format, pulling database connection strings, secret configs, APM agents, etc. They also contain our “support” endpoints, which are endpoints all of our services should contain, for supportability.
Support Endpoints
We have requirements and guidance around a handful of specific endpoints our services need to support.
- health
- Report on the health of the service, including any essential dependencies, such as a database connection
- info
- Provide generally useful info for the running service. This quite often includes the non-sensitive configuration properties and enabled feature flags.
- version
- Version information for the service, such as the “code” version, supported API versions, default API version, etc.
- metrics
- Runtime metric information, such as http response times, database query executions, garbage collections, etc. Supplied in the Prometheus format.
Having examples and frameworks/tools in place for each of these endpoints helped us to get much better adoption and consistency in these “support” endpoints.
Living Services
Even though these services do not serve any real business function, they still are deployed just like any of our other services. This helps to ensure that they are complete. We have confidence that the Dockerfiles, Kubernetes configs, and code are all functional and do not contain stupid mistakes. It also helps us to ensure that they are kept up to date. It is really easy to forget to update something in a service that doesn’t actually run somewhere.
Copy-Ready
These template services are meant to be ready to copy for any new microservice that needs to be introduced. A dev team just needs to pick the template that best meets their needs, and copy that. The templates even have “initialization” scripts in them to easily set the team name, service name, and other such changes. Ideally, the first deploy of any new service should be just the initialized version of the template service.
The templates also serve as good references to go back to when an older microservice needs updated. Forgot all the details on how to update from Sinon 2 to Sinon 28? Go check out how the template service did it. You need to support a new Kubernetes deployment file format? Check out how the template service did for that format.