Hi,
I’am new to rancher and Docker and I’d like to start on the right way. I have a multi-container application which is a composition of 4 REST microservices :
A talks to B which talks to C and then A talks to D
A is my entrypoint (on port 80). I have a docker-compose.yml which looks like this :
A:
ports:
- 80:80
image: registry/foo/A
links:
- B
- D
B:
image: registry/foo/B
links:
- C
C:
image: registry/foo/C
D:
image: registry/foo/D
In the Rancher “lexical”, this kind of application is called a “stack” isn’t it? From my point of view I consider this multi-container application like a “big” service I’d like to scale on many nodes.
All I see in rancher is the possibility to scal each container of the stack individually but not the whole stack.
So, ok, why not. But In my case what happens if I scale my “B” container up to 3? How my service “A” can load balance to these 3 instances automatically? Because, actually, the A service makes an HTTP call to http://B:1234/doTheJob.
That’s why I though that it was possible to scale an entire Stack the same way I scale a simple container.
What is the best practice when you have to implement this kind of “microservice” composition architecture with rancher ? Is there any documentation anywhere?
You are in for a very pleasant surprise. Just create a stack, add all services A,B,C,D to said stack and you are DONE. Service A will talk to Service B just calling it by name (yay service discovery!) and what is actually happening is that Rancher creates a Network Agent that will do said load balancing: A calls B, B resolves to this “invisible” LB which then redirect to one of the containers in the service so they can have different scales.
Then you entry point could be a Load Balancer service (look it up) bound to your host in port 80 and just pointing to your microservice in Service A. No need for links or anything special, quite sweet.
Ok, but there is something I do not understand very well. Just focus on A to B communication. In the NodeJS code of A I have an HTTP call to B that point to this url : http://B:1234/helloworld
So what you mean is if I scale my B service up to 3, the call to http://B:1234 will be catch by an “inivible” LB which will load balance to the new B containers? Is that right?
Well, invisible was poor wording on my behalf. What really happens is that it does load balancing round robin via DNS records, you can easily try it out, create the stacks and do a dig on the name of a service and watch it in action.
Being able to scale each service (collection of containers from the same image) independently within a given stack (collection of services) is nice, because you may not always need to have a 1:1 mapping for each of those. As long as you internally use the magic rancher host names as indicated by alexR.
However, sometimes you may need to ensure that you have each service within the stack at the same scale. I had some odd requirement for this. The solution is to mark B, C, and D as “side kicks”.
@alexR : Does it mean that Ineed to modify the URL call from A to B ? Actually I call my B service on a specific port (http://b:1234/helloworld). Do I need to implement a “discovery” logic in my service A ?
The hostname “B” will resolve to multiple DNS A-records, one for each instance of service B. So as long as you simply call “http://b:1234” it will somewhat randomize which instance of the “B”-service it will hit.
If you wanted some tighter control, you could add an internal load balancer in front of service B. Assuming the service for the load balancer was called “lb-b” then you’d call “http://lb-b:1234”.
Due to Rancher’s internal networking, you don’t have to discover ports or even expose them explicitly if you only need them accessible internally. Any port EXPOSEd by a service will automatically be accessible by any other service in your environment.
DNS based service discovery is great, because it requires literally no client software.