visit
Anyone can make a tiny service. It’s the first thing you do when you make your “Hello World” express server. If you’ve made a “Hello World” express server before, then congratulations! You’ve made a microservice! It’s going from one, to many, that the questions start piling up. How should they talk to each other? REST? RPC? Messaging? And why choose one over another? Let’s say that you do manage to wire up a small system of a few services and you chose REST cause it seemed easiest, and you already knew it. Time to deploy them somewhere. If you’ve tried running microservices on a Platform as a Service (PaaS) like Modulus, or Heroku, this can get pretty time consuming, and pretty expensive. Not to mention latency from communicating over the internet instead of a private network. That’s a no go. Oh, and you’ll need to provide environment variables so you’ll know what endpoint to ping. Then you think about deployments. Deployments are always a pain, and now you need to do it seven times?! The above scenario is basically what my first attempt looked like. I was clever though, I used a unidirectional data flow! Too bad that’s only one of the pieces. What about logging? And monitoring? Where do you store secrets? Auto-scaling? You finally realize that you now, on top of just wanting to make tiny services, need to go learn how to build your own infrastructure in AWS.
Suddenly, our tiny services don’t feel so tiny.The following tools when combined have the potential to greatly increase the speed in which you develop services, the speed in which you deploy them, and the ease of running them in any environment. As a bonus, once they’ve been codified, they are quite reusable. It’s more tracking down resources and learning each, as well as how they interface that makes up the majority of the learning curve.
You can’t effectively build microservices without containerization. There are just too many pieces. I mean, you can, but it’s seriously going to be way more work.
Imagine if you wanted to buy some Oreo’s and they came separately. It would be, well, less convenient to say the least. When it comes to services, containers simplify development, testing, deployments, and running in production. All the things you need to do all day every day as your job, so might as well make it easier.Services need containers, just like Oreos.
Tools: Docker
Imagine if you had to carry all of your groceries home individually. It doesn’t make sense. So, you put them in bags. You put heavy ones on the bottom, so they don’t squish the bread, and cold ones (for the bros) with other cold stuff so they can all be cold together. Some stuff you double bag, for redundancy.
Bags are like servers, you need more than one, and they hold your services.Having more than one allows you to avoid failure scenarios, like if an availability zone went down. Or, your soup can broke and the paper bag ripped. Good thing you double bagged it! Give yourself a clap. You can use the button on the bottom. ;) You can get your servers at any of the major cloud providers. The important thing here is codifying that infrastructure. There are a few different ways to do this. In the past many people used Ansible for this, but given the requirements of fast scalability, it doesn’t make sense to have to wait for a server to be brought up, and provisioned. Instead you can “bake” an image of the machine with all of the tooling installed, and then use that image with Terraform or Cloudformation. Once you’ve designed your cluster for resiliency, a rolling update of a new AMI will allow you to update your entire infrastructure.
Servers: AWS, Azure, Digital OceanTools: Cloudformation, Terraform, Packer
An orchestrator is like the grocery bagger.The orchestrator knows the memory requirements of your services, and how much CPU needs to be allocated, and she carefully places each service into the appropriate server.
Tools: Docker Swarm, Kubernetes
Automate it, automate it, automate it.This directly contributes to the business making money. The whole Lean Startup is about build, measure, learn, and repeating that cycle. Continuous Deployment allows you to do this faster. The faster you can get things out the better, because then you can measure, and learn, and know what to build next.
I personally think you should strive to automate everything to a point where you can confidently commit to master. Git flow is too cumbersome when repeated 15 times across a bunch of tiny services. Make branches when you need, but, it’s ok to just commit to master if you have the proper safety checks in place.
Tools: Jenkins (With pipeline and Blue Ocean), TravisCI, CircleCI
Don’t expose your services directly to the internet!Instead, use a public facing reverse proxy. However, it needs to be one that is easily configurable, ideally, one that configures itself based on some configuration options defined on the service, so the team developing the service can decide best how to interface with the proxy without having to ssh into servers.
Tools: HAProxy, nginx, docker-flow-proxy
Sure, you could use a distributed key store like Consul and keep it up to date to avoid having to constantly reconfigure your service, or better still use an orchestrator’s DNS features and use REST, but, that’s still a lot of extra responsibility and configuration. This makes your services tightly coupled.
Use one-way fire and forget messages to make your services loosely coupled, and easy to scale.Instead, using a message queue, you can simply send or publish messages, in a “fire and forget” manner. Other services can easily be added or removed without affecting the original publishing service. This makes your architecture very easily scalable as well. Also, with features like retries, and error queues, you can stress less about services crashing. The message will simply be retried when the service comes back up.
Tools: RabbitMQ, ActiveMQ, AWSMQ, ZeroMQ
See everything in one place.
Furthermore, it should not be the responsibility of a service to know how to ship logs. Instead, always log to stdout
or stderr
and use a tool to collect all of those logs by running it globally on each node in your cluster. The log collector tools will then ship the logs to your Centralized Logging subsystem.
Tools: ELK Stack (ElasticSearch, Logstash, Kibana)
Use alerting to drive scaling or recovery events before alerting humans.You also don’t want to be chasing down that information if you don’t have to be. Ideally, you should only ever hear a peep when something is wrong. This means you need an alerting tool that can respond to the metrics collected from monitoring and alert a user. Better yet, it can alert a microservice to trigger a scaling event, or attempt to resolve the issue in other ways to avoid requiring human interaction.
Tools: Prometheus, Alertmanager, Grafana
Tools: meta, gitslave
For more details on Microservice Patterns, see my other article “Learning these 5 microservice patterns will make you a better engineer”. Where I teach you how to categorize your services, and talk about the overarching patterns, and how they relate to Domain Driven Design, CQRS, and Event Sourcing.
I’m currently developing a new course Microservice Driven Design, where you can learn how to build a modern microservices architecture using all of the above components. To be the first to access, sign up !
Thanks for reading! If you found this useful, please give me some claps! It would really help me reach more people!Interested in hearing MY DevOps Journey, WITHOUT useless AWS Certifications? Read it now on HackerNoon. DevOps is a prerequisite to effective microservices!
If you’d like to reach me, send me a message on or .