I have been interested playing around with Linkerd, but we use Rancher for our orchestration which there currently isn’t a namer for. It seems I’m not alone, since there is an issue about adding support for it: https://github.com/linkerd/linkerd/issues/1146
I’ve never written a line of Scala - but I was fairly adamant about not letting small details like that stop me. So I set out yesterday, and I think I have something roughly in the right direction now. But there’s something I don’t understand about how Linkerd/Finagle works. But do keep in my that I have a veeeeery basic understanding of the intricacies of Scala when you reply
So first things first - for those that don’t know, Rancher organises containers into stacks and services - a service consists of one or more instances of the same container, and stacks are used to organise one ore more services into a logical unit (and is basically what your describe using
So, I’ve created a case class for containing information about a single container running in Rancher (which includes the ip and the various exposed ports). I’ve also created a class that uses a Finagle Service to query the metadata-API and used the Jackson JSON parser to get the response into the above mentioned case class.
This class ends up exposing a
Activity[List[RancherContainer]] instance based on
Var.async - right now it simply requeries the API every n seconds, but in time should use the long-polling supported by the Rancher metadata-API to get more real-time updates.
In the namer itself, I’ve added the
lookup(path: Path):Activity[NameTree[Name]] method so it uses a
.transform() on the above mentioned
Activity[List[RancherContainer]] to transform the
List[RancherContainer]] into a
I do this by popping the first two parts of the path off into
service and then filter the list of contains down to those from that stack and service. I then create a set of
Address's based on the ip and port of those containers.
My transform then simply returns
NameTree.Leaf( Name.Bound( Var.value(Addr.Bound(addresses)), prefix ++ path.take(2), path.drop(2) ) )
However, even when my set of addresses change change (I have a
println inside my
.transform which gets called every n seconds), Linkerd doesn’t update the destination of the path. I’ve been testing locally with a mock metadata-API and manually editing the response between two ports on my local host - so it’s easy to see that it keeps using the initial port.
Does anyone have any hints as to what I could be doing wrong? Is it because the
Name.Bound I return ought to be a
Var.async instead of a
Var.value, or? The
lookup-method doesn’t seem to be called again, so clearly the
NameTree I return needs to update itself - but how do I achieve that?
I can also push my very Work-in-Progress work to a repo if that makes it easier to help out!
(Yes, I know it’s a bit silly implementing all these things for Rancher when their next version will be Kubernetes-based, but it seemed like a fun weekend project)