Before microservices, the standard way of developing applications was with the Monolith architecture. This means all the components of the application the whole code is basically is part of a single unit. For example, if we had an all line of application all this part like user authentication, shopping cart, product catalog, sales complaints notifications, and so on; all code for this functionality would be in one codebase is part of 1 monolith application. Everything is developed, deployed & scaled as 1 unit. This means that the application must be written in single language with 1 technology stack with a single runtime. If we have different teams working on different parts of applications, they only to coordinate to make sure they don’t affect each other’s work. Also if developers change code for the payment functionality, you’ll need to build the whole application and deploy as one package. You can just update and deploy only the payment functionality changes separately.
So this was the standard way of developing applications but this application grew in size and complexities which led to different challenges:
1. First of all, the coordination between teams became more difficult because the code was much bigger and the parts of application were more tangled into each other.
2. Also, if suddenly you have a usage spike in shopping cart for example on holiday dates, and you want to scale only that part of the application; you cant do it. You need to scale whole application. This in turn means higher infrastructure cause in less flexibility scaling your application up and down.
3. Another issues is for example if a payment function is a third party mojo way a version of 1.8 while notification feature may be the same feature mojo but required the version of 1.7 instead. In a monolith application you would have to peek one or the other. Because it’s the single application you can only have one dependency of the same mojo.
4. Another major issue with monolith application is that the release process of such applications takes longer. Because for changes in any part of the application in any feature you need to test and built to the whole application to the deployed docs changes. An answer to all these issues was in microservices architecture.
So, what is Microservices exactly?
With microservices, we breakdown the application in essentially multiple smaller applications. So we have several small or micro applications that make up one big application. Now we have a couple of very important questions when we create a microservice architecture?
First of all, how do we decide how to breakdown the application?
What code goes where?
And how many such micro application or micro services do we create?
How big/small should these micro services be?
And finally how do these services then talk to each other?
First of all, the best practices is to breakdown the application into components where microservices based on the business functionalities and not technical functionality. So the microservices on the online shopping applications will be products, shopping cart, user accounts, checkouts and so on. There is always are basically business features. An term of its size, each microservice must do just one isolated thing. So you should have a microservice that is responsible for shopping cart logic in the checkout. You should always strive through keep one service doing one specific job.
In the very important characteristics of each microservice is that they should be self-contained and independent from each other. This means each service must be able to developed, deployed and scaled separately without any type dependency on any other services, even though they are part of the same application. And this is called “loose coupled”. So we face best practice approach if we change something in payment service. You will only be built and deployed the payment service, nothing else will be effected. This means the services have their own individual versions which are not dependent on others. So if I release one service, I don’t need to release other service. And this release cycle has to be completed independent.
How Microservices communicate with each other?
So if the services are isolated and self-contained, how do they connect to each another? Because obviously, the payment service will meet something from user account to process the payment! Or the checkout service will need something from shopping cart. In every common way the microservice communication is using API calls. So its service has an in point on which is accept request from other services. So services can talk to each other by sending each other HTTP request on these in points. This is a synchronous communication. Where one service sends requests to another service and waits for the response. So the user account service can send an HTTP request to payment service on its API in point or vice versa.
Another common way of communication between microservices is using a message broker. We have an asynchronous communication. Here services will send messages first to an intermediate message service or broker such as Rabbit Mq for example and then the message broker will forward that message to the respective service. So again the user account will send message to the broker saying please pass this message on to the payment services and message broker will then forward that message to the payment service. And the third way of communication between microservices which is becoming pretty popular especially in the field of kubernetes is using a “service mesh”. With service mesh have kind of help service which takes over the complete communication logic. So here have to code this logic into the microservices and have this communication logic kind of delicated to this external service.
So these are different communication options and since the service are all isolated and talk to each other either we have an API calls or using additional services; you can even develop each service with a different programming languages. And you can have dedicated teams for each service that can choose their own technology stack and work on their services without effecting or being effected by other service teams. And this is exactly the most important advantage of microservices architecture compared to monolith.
Downsides of microservices
However this benefit comes with the price. So well microservices may developing and deploying applications each year in many aspects. It also introduce some other challenges then weren’t there before.
When you breakdown the application into this multiple pieces, this introduces a lots of complexities and challenges. One of the main complexities may be configuring the communication part between the services because the microservices may be down or inhealthy or not responding yet while another service starts sending request to its API expecting it to fill response in which is you may get it an unexpected results. Also with microservices, deployed and scaled separately, it may become difficult to keep an overview and find out when a microservice is down or which the service is actually down when something in the application is not working properly. So you definitely need a proper configuration of your application setup and its pieces to make sure your application has a whole functions well.
For there are various tools for making all these easier so even though the microservice architecture is complex there are lot of tools and steal more being develop regularly to make running microservice applications easier.
The most popular one to probably over one is “kubernetes” which is a perfect platform for running large microservices applications. Now before moving on I’m very excited to give a short on to the ‘Hashicorp’ which is the company that many of you probably know about and has a lot of really cool technology. Many of those that actually saw various challenges when working with microservices applications from the ‘infrastructure proportioning’ to ‘terraform’ to its secret management tool ‘vault’ which is pretty much becoming standard already in this industry for managing protecting your sensitive data.
Hashicrop also has a service mesh product called ‘consul’ which helps you to securely connect and observe your microservices running in any environment. So we have various stores in Hashicorp offers you can actually probation secure connect and run cloud infrastructure for your most important applications and specifically for your microservices applications. If you want to learn more about any of these technologies, be sure to checkout the white board sessions of Hashicorp co-founder and CTO who gives a really good introduction of all these technologies on YouTube. And now lets move on and now obviously this important element of deploying microservices is the…
CI/CD Pipeline for Microservices
In fact there are many companies with microservices applications that deploy multiple times a day. Companies like Amazon, Google and Netflix they have applications with 100s of microservices that are deployed thousands of times per day. To can imagine the complexities and the sophistication of CI/CD pipelines. So in the modern world workplace, you’ll be most probably working with microservices and in this case you would need to know how to configure with these process with a CI/CD pipeline for microservices.
Monorepo vs Polyrepo
Now we said microservices is when application components gets developed and deployed separately is individual micro applications. So the question is how we manage the code for microservices applications in a git repository? Like in gitlab for example with one project in simple which is a one application and it gets own git repository. With microservice application, we have 2 options for how the code is manage? Monorepo which sense for single repository and polyrepo also multi repository. So monorepo or single repository is having 1 git repository for all the services. So we would create 1 project for 1 repo, so what’s the difference here or how do we structure multiple micro applications inside one application repository?
Well a common way is using ‘folders’. They have folders for each service shopping cart, payment, notifications etc and all the code for those services are in those respective folders. A having a monorepo meaning all the services still in one repository makes the code management and development easier. Because you only have to clone and work with 1 repository so its simplifies things. Plus if you have some shared codes between the services like kubernetes services or helm chart or docker compose. You can keep them in the woods of projects then all the services can basically reels them.
But monorepo also comes with some challenges, it’s mentioned the most important criteria of microservices is to be completely independent & isolated. So no tight coupling between the services inside the code and it’s become easy to break this criterion and when you’ve monorepo.
So you’ve junior developers with less experience in the monorepo setup, its easier to makes such mistakes and developed tightly coupled logic and code in your services.
In other downside of monorepo is when the application becomes really big cloning, fetching and pushing becomes slow because your project is huge. In terms of the CI/CD pipelines in most of the CI/CD platforms, like Gitlab CI/CD or Jenkins, you can only create 1 pipeline for 1 project. So you are building multiple services with a single project pipeline. In that means you need to add additional logic in your pipeline code that makes sure to only built and deploy services which has changed. So if you make code changes in the payment service, your pipeline code should detect that in only that service should be built, tested and deployed. And its possible to do that but it’s a little bit more challenging.
One more issue with monorepo is that since you have just one main branch because you’ve one repository if the developers of 1 of the services break the main branch other services and their pipelines will be blocked this well.
But there are lot of companies included big ones like Google who actually uses monorepo for their applications.
The second option which is probably a big more preferred one is polyrepo or multiple repository. With this approach each service for each service we create a separate key project. So the code is completely isolated. You can clone or work on them separately because they are in separate repositories. Now even though separate application repositories they are still part of the bigger application. So of course you would want to still have some kind of connection of these repulse for an easy management overview.
So if you are hosting your code repositories on gitlab for example, you can use gitlabs features of groups in order to groups call for all microservices belong to same application in one group to make managing those repository easier. So essentially, you will create a gitlab repository group for your application called ‘my online shop’ inside this group, you can create a separate project for each microservice that belongs to the application. If your company has multiple microservices applications ofcourse this will help keep an overview of what project belongs together. But also within the group you can actually create secrets or others variables that can be shared by all the projects in that group. Now whatever, the CI/CD pipelines for the polyrepo work for polyrepo; this is the configuration is more straightforward because you just have all pipeline for repository so no extra logic is needed to differentiate between the services.
Now ofcourse everything has an advantages and disadvantages, so for polyrepo as well, you have some downsides:
Like having applications code in multiple repository can be working on a projects is a whole harder. Especially if you need to change two or more services at once because its features or bug fix effects multiple services. If you need to switch between services often, this can also be tedious plus things like searching something across between projects from the code editor can be difficult or possible. Also in the polyrepo, you can share files in the projects like kubernetes, docker compose and so on, you’ll either have to duplicate them in each project repository or have to create dedicated project and reference them from there.
So you see both options have their advantages and disadvantages but the general rule is if you have a small project with just a several microservices you should seek to monorepo & save the overhead of creating & managing & checking all multiple repositories. On the other hand, if you have separate teams for each service, if you want to have complete isolation, small code based clone, own pipelines and so on then ofcourse the polyrepo would be better option.
Now I hope this help a great introduction to microservices and now you understand what it is and why everyone is using it. If you interested to know how to build CI/CD pipelines for microservice applications, then you can checkout my complete gitlab CI/CD course to which I actually show demo on how to build CI/CD pipelines for microservice applications in a monorepo as well as in polyrepo as well as deploying the microservices applications to kubernetes cluster.