Live data from Hacker News

Connecting Kubernetes services with linkerd

lwn.net

31–40 of 49 posts

Re: Connecting Kubernetes services with linkerd

#31

I appreciate the sentiment behind linkerd et al but I think we are really over-complicating things and tying ourselves into knots by going head-first into this world. I can't help but think we're going to regret it in a few years. The complexity introduced not only by Docker, but also k8s and all of the other things competing for a spot in the middle of your cluster, is immense and widely underestimated. Your applica…

It's perfectly normal to use base images and build your own. We do this for most things.

One simple reason is control: You want to be able to follow CVEs and upgrade your images in line with patches. If every image branches off some random Docker Hub image, the only way to do that would be some kind of image vulnerability scanner, which I believe exists, but wouldn't help you actually patch anything easily.

Public images are still super nice to bootstrap things. You can start with a public image, then move to a custom-built one.

Lastly: I wouldn't conflate the Docker image challenge with the operational complexity of using Kubernetes and microservices. They are completely orthogonal in my mind. Docker has all sorts of issues that we need to solve sooner rather than later; Kubernetes' design, on the other hand, is sound.

Re: Connecting Kubernetes services with linkerd

#32

Earlier quoted context omitted.

> If you want Ruby, the habit is to go find someone's "pre-configured" alpine-ruby image (for instance) I think the habit for most folks (and the best practice) is to use one of the "official" Ruby images[0]. Similar official repositories exist for many server daemons, language runtimes, and command-line tools[1]. > My understanding is that most public image repositories are unmoderated. To the best of my understandi…

>I think the habit for most folks (and the best practice) is to use one of the "official" Ruby images. Ah, I didn't realize there was a blessed subset of repositories for which the Docker team has independently verified the identity. Are these signed with some sort of crypto and known-good keys, similar to package signing keys attached to a package repo, or are we taking Docker's word for it? Is there a way to filter…

I believe most of your questions have a (mostly) positive answer. Admittedly the Docker project moves fast, so I've tried to provide a link or two for each:

> Are these signed with some sort of crypto and known-good keys, similar to package signing keys attached to a package repo, or are we taking Docker's word for it?

The official images are all signed with Notary[0] (released > I had to go 3 levels up from the link on the Docker Hub page to get to this one because most of the images are FROM:something.

There is a helpful Chrome extension, OctoLinker[2], that makes the `FROM parent` clickable (among other non-Docker things). I'm sure there are similar extensions, but this is the one I currently use.

> a) still derived from some other upstream Dockerfile (must this file also be validated by Docker to qualify as an "official repo"?)

The `FROM` line in the Dockerfile would likely be the first thing to undergo scrutiny, for obvious reasons. Also, all the layers go through security scanning[3], some issues can be fixed[4] and others are tracked upstream (e.g. by Debian in the case of the Ruby image you linked[5]).

> you end up with an image that is very bloated due to the way Docker's caching layer functions

You can now use `docker build --squash`[6] to combine multiple image layers while still benefiting from layer caching during builds. Also, the final image won't contain files that are added in previous layers and removed in later ones. (And with multi-stage builds recently merged, soon multiple inheritance will be easier.)

> Is this "transparency" only the case on "official" images? As far as I can see Docker Hub just stores the pushed binary blob and not the Dockerfile required to build it

I would say groups or sole developers that want others to use their images will usually provide documentation and links to the Dockerfiles. Of course, this isn't always possible or desired (e.g. see closed-source projects like Windows Server Core[7], or the countless people using Docker Hub as a free image host.)

[0]: https://github.com/docker/notary

[1]: https://docs.docker.com/engine/security/trust/trust_key_mng/

[2]: https://octolinker.github.io/

[3]: https://docs.docker.com/docker-hub/official_repos/#how-do-i-...

[4]: https://github.com/docker-library/official-images/pulls?utf8...

[5]: https://github.com/docker-library/ruby/issues/117

[6]: https://docs.docker.com/engine/reference/commandline/build/#...

[7]: https://hub.docker.com/r/microsoft/windowsservercore/

Re: Connecting Kubernetes services with linkerd

#33

> Facilities that linkerd provides to assist with this include service discovery, load balancing, encryption, tracing and logging, handling retries, expiration and timeouts, back-offs, dynamic routing, and metrics. Why not use SRV records and TLS? Retries, expiration, timeouts, and back-offs can all be placed into the networking library, and are, commonly. Also, regarding https://linkerd.io/ , what's with landing pag…

The whole point of Linkerd is moving logic out of your app. Linkerd is like a library but, instead of being in-process, it inserts itself between the app and whatever the app needs to talk to. The app just dials http://foo.svc/, and Linkerd sends the connection to the right place; it doesn't need to know where foo.svc is.

Many companies, including mine, already run an internal load-balancer (such as HAProxy) that takes care of routing traffic between microservices. Linkerd replaces this with something that is explicitly designed to deal with inter-app communication. (I believe one way to run Linkerd is as a small sidecar app inside the same Docker container the man app, as opposed to a big central server, which is also a neat way of doing it.)

Re "why not a library" — sure, you can build all sorts of discovery, distribution and resilience into the client itself. But that consolidates all of this intelligence into just that client. What if you use multiple languages? What about third-party client libs (e.g. Memcached, Redis, PostgreSQL) that you don't control and that you don't want to reimplement? You'll find yourself reimplementing the same thing over and over.

> you can't "drop in" resiliency

I recommend reading the documentation, because drop-in resilience is really the whole point. The guys who built Linkerd previously developed Finagle [1], which is Twitter's RPC library, and when they talk about network resilience, they actually know what they're talking about [2].

[1] https://blog.twitter.com/2011/finagle-a-protocol-agnostic-rp...

[2] https://monkey.org/~marius/funsrv.pdf

Re: Connecting Kubernetes services with linkerd

#34

Earlier quoted context omitted.

I would not take the claims of scale at face value. People make this claim to boost their own egos, and the reality is that many of the people who do this would be more than fine on a handful of servers. They just want to feel important. My frank take is that k8s was developed at Google by the seat of their pants (and yes, I know it's their third-gen orchestration platform), they talked about it with outsiders here a…

Just FYI, over 50% of contributions come from !Google, and that's part of the reason that so many people (CoreOS, Redhat, Apprenda, Deis, thousands of internal folks) have rebased on it. I saw some of your other comments - I'd love to understand better what we could do to either a) make it feel like not an internal tool and b) if you didn't use Kubernetes or containers, how you'd prefer to run distributed workloads.…

So I actually answered this question for you when you asked it in December: https://news.ycombinator.com/item?id=13241681 . ;)

Not to toot the same horn.

I have more experience with Kubernetes now than I did then, though I think a lot of those interface snafus, which is most of what the old post discussed, are still valid complaints.

You mentioned back then that if people aren't aware of some kube featureset, they end up reimplementing it. You mentioned logging. Can you tell me what you recommend for logging?

Right now, we have everything writing logs to stdout in the container, which gets recorded by kube in something like /var/log/kube/containers/ * . Then we have a fluentd container that reads the logs and uploads them to an external machine, which is running fluentd containers that receive the input stream, transform it according to rules, and pipe it out to a cloud-based log aggregator.

Is that how it's supposed to work? I know we used to do it somewhat differently, but had trouble with resource consumption that was disrupting our pods.

And here's a potentially legitimate Kubernetes issue: the scheduler is only reading the load generated from containers administered by Kubernetes, so even though the box is being thrashed, k8s will not be aware of the problem and continues to report the node's resources as healthy. In our case, the dockerd process was using 4.5 cores. Kubernetes seemed unaware and it was affecting our performance because another busy pod was on the server and was not getting clamped by its quota (since it, technically, was not hitting the quota for itself). Shouldn't these be defined relative to overall system resources, and not just the containers that kube can see?

It's possible Kubernetes was aware, but that we didn't know how to see it. A colleague told me the interface I was looking at for pod performance data reflects only the quotas, not the actual utilization, so maybe k8s knew (why isn't there a `kubetop` that can be run on the host to supervise?). I also hear that automatic rescheduling is still in draft stage, so if k8s detects high load on a kubelet, instead of moving the pod, it will just not assign new pods to it.

About addressing. Right now, we have dev, stage, and prod. We have a container that takes all traffic targeting the kubelet on port 80 and proxies it out to the pod using servicelb. It's set up to forward from http://app-label.env-name.example.com to a pod matching that label. It's annoying that we have to run an external container for this in the first place and do extra configuration on it, but it's also annoying that since servicelb is not aware of the beta label attempting to simulate hostnames, we can't individually address instances of apps. Is that how this is supposed to work, or is there a ready-built solution that makes this much easier that we're overlooking?

----

>I saw some of your other comments - I'd love to understand better what we could do to either a) make it feel like not an internal tool and b) if you didn't use Kubernetes or containers, how you'd prefer to run distributed workloads.

The best way to improve Kubernetes would be to:

a) simplify the terminology;

b) simplify the kubectl command, and particularly make it follow semi-standard Unix utility conventions (examples: -f should mean force or not be used (and yes, I know some other tools commit this sin too, but the association with "force" is nerve-wracking on a production environment), should probably be -r or -o; --from-file is ambiguous, and should be --read-literal or -r --raw or something like that);

c) simplify the configuration syntax and files;

d) provide simple ways to get real storage and real IPs (I haven't thoroughly investigated StatefulSets, so it may do this). I know that Google has long ago gone into a plane where these are irrelevant, but normal companies haven't, and IMO there's no reason they necessarily should;

e) provide simple backup and restoration methods (afaik, this involves multiple steps, including backing up the etcd cluster (not allowed to run on the master, or just conventionally doesn't?)).

My suggestion for distributed workloads is:

a) script your machine in Ansible or similar, and make a base image from that;

b) use your cloud provider of choice to deploy new instances under the circumstances considered necessary;

c) register the new node with haproxy or whatever sits at your front end (often a cloud-provided LB);

d) use conventional administrative and monitoring tooling to administer.

All of that is fully scriptable, in far less time than it takes to convert to Docker/k8s.

-----

>TBC, I totally agree with you - if you're running 1-2 nodes, and don't care about downtime, you should NEVER use Kubernetes or any orchestrator. Once you get to 3+, however, I can't imagine using anything else.

Why is the above-recommended distributed systems strategy inadequate, even for people with more than 3 nodes who care about downtime? What's fundamentally wrong with it? What unique value does k8s bring to the table?

What's the k8s replacement for htop? tcpdump? df? and all the other utilities, and why are they better, and what benefit does k8s provide, that we didn't already have, that warrants giving up everything? I know it's not TRYING to replace all of that per se, but the practicalities make kubernetes the authority for such information, and you're not supposed to have to get onto the kubelet itself to diagnose these types of issues so you can't even use root on the Docker host to try and do some of this.

In our deployment, the main k8s jockey just kills pods if they're acting up and hopes that will magically fix it, because the devs don't want to get near the setup with a 10-foot pole. Before, they would SSH in and go over the issues. Now, since not only can't you SSH in but there's a convoluted process to get a shell, and then the container will not have any diagnosis tools in it anyway, it's very hard to have them collaboratively troubleshoot a problem we're seeing in the wild.

I can't tell you how many times I've had someone tell me "They must have a better answer for that; Google uses it after all...". These people are under the mistaken impression that if Google is using it, it must be robust and stable, when in fact the opposite is usually true, and I don't think Google tries to pretend it's not. It's probably just misinterpreted the signal from the developer community as meaningful approbation, when it's really just blindly following the cool kid on the block.

It's not that k8s isn't a neat thing. It's just that it's solving a problem that pretty much only Google had, and now everyone else is plummeting down the rabbit hole.

We've spent probably 1.5 man-years getting our infrastructure containerized and kubed up. We're not at 100% in prod yet but getting pretty close. It's clear that I'm really dumb but I haven't even been the main one doing this, so can't blame it on me. That's a huge project, and how does k8s/Docker justify the cost? It lets us cut down on AWS usage? Sure, but nowhere near the proportion of cost. It "makes it easier" to administer the cluster? Nope, not a chance. It's fun to kill pods but that's living on the edge, most apps written by non-Google can't take that. Solution? Write an "operator", which appears to be any random program that intercepts the k8s API and does stuff to support pods, etc. That sucks, why don't I just keep the init script that works fine?

One could argue that k8s is about resource utilization, which is sort-of-but-not-really-true. And that has a downside; we've essentially turned our environment into a shared host now, and despite k8s quotas, we still have pods that are bad neighbors; this is turning out to be quite difficult to control.

So I'm just really at a loss here. Google wanted it and they built it and it's working for them, that's great. That's an internal tool. How does this help anyone who wants to run a normal site this way? I haven't heard a single success story that had a moral or goal behind it other than "I'm cool like Google now too."

And on top of all of this, before k8s even comes into the picture, you have to make a Dockerfile and run your application in Docker, which is a PITA itself, in terms of stability, security, and configuration (see above-mentioned dockerd hammering the box, dockerd hangs or breakages that render a box useless, having to deal with port forwards, name collisions, large Docker caches, docker's inability to remove old images or containers on its own, Dockerfile lameness, culture of importing unknown images, etc.).

I like the ideas of containers (and have liked them when they were called "jails" in past eras ;) ) and I like the idea of orchestrators like kubernetes. But I think it's very early days right now for both, and that they will need radically improved simplification and stability before they are appropriate for general use.

Re: Connecting Kubernetes services with linkerd

#35
post #8
post #2

Great article, I've been able to learn more about why a cluster setup could utilize linkerd. However this statement confused me a little: However, Finagle is written in Scala, which Gould concedes is "not for everyone". linkerd is written in Scala [1] and linkerd is written in Rust [2]. If he is optimizing for other people’s contributions, is this really the best way to go? [1] https://github.com/linkerd/linkerd [2]…

> linkerd is written in Scala [1] and linkerd is written in Rust [2] Though your links are correct your statement isn't. Linkerd is written in Scala, but the Rust bit is linkerd-tcp, a TCP loadbalancer, which linkerd (the Scala one) doesn't handle as that covers HTTP and gRPC with optionally encrypting connections between linkers using TLS. > If he is optimizing for other people’s contributions, is this really the be…

Yep! That is exactly what I meant by that ;)

Re: Connecting Kubernetes services with linkerd

#36

I appreciate the sentiment behind linkerd et al but I think we are really over-complicating things and tying ourselves into knots by going head-first into this world. I can't help but think we're going to regret it in a few years. The complexity introduced not only by Docker, but also k8s and all of the other things competing for a spot in the middle of your cluster, is immense and widely underestimated. Your applica…

It's perfectly normal to use base images and build your own. We do this for most things. One simple reason is control: You want to be able to follow CVEs and upgrade your images in line with patches. If every image branches off some random Docker Hub image, the only way to do that would be some kind of image vulnerability scanner, which I believe exists, but wouldn't help you actually patch anything easily. Public im…

I recognize that Docker and k8s are distinct, and I think rkt looks much smarter than Docker. Now that k8s has released a stable version capable of running non-Docker containers (as of last week), it's fair to separate them.

However, I'm still struggling to see the real value proposition offered by either.

The story on Docker or Docker-style containers without orchestration is that they're supposed to be easy to ensure you get an identical environment everywhere and more fully utilize your hardware resources. While that does seem to happen if you incorporate docker-compose or some other metadata about what ports to map and volumes to mount, the pains associated with using Docker have far, far outweighed the one-time cost of configuring a new application or getting a new build to work for me. And we already had pretty good tooling for this pre-container, with things like Ansible. It wasn't exact, but it was much more comfortable.

Re: Connecting Kubernetes services with linkerd

#37

Earlier quoted context omitted.

It's perfectly normal to use base images and build your own. We do this for most things. One simple reason is control: You want to be able to follow CVEs and upgrade your images in line with patches. If every image branches off some random Docker Hub image, the only way to do that would be some kind of image vulnerability scanner, which I believe exists, but wouldn't help you actually patch anything easily. Public im…

I recognize that Docker and k8s are distinct, and I think rkt looks much smarter than Docker. Now that k8s has released a stable version capable of running non-Docker containers (as of last week), it's fair to separate them. However, I'm still struggling to see the real value proposition offered by either. The story on Docker or Docker-style containers without orchestration is that they're supposed to be easy to ensu…

Being a Puppet user (until we've finally retired that nightmare), I couldn't be happier with this migration to containers.

Docker itself is problematic for all sorts of reasons, but it at least does the most important thing, which is to run pre-packaged code in isolated containers. With Puppet, as with Ansible, you just can't guarantee an isolated environment, nor is the environment easily "replicable", in the sense that if you need more instances of the exact same thing (e.g. more data processing workers), there's nothing in the system built to treat things as N-of-anything. The only unit of provisioning is the VM. Puppet/Salt/Ansible are highly static systems.

Meanwhile, Kubernetes smoothes over a lot of the rough parts of Docker: Ports, IPs, DNS/discovery, monitoring and volume management are all neatly captured by Kubernetes, where in Docker Engine they're just low-level primitives you need to manage manually. It also handles exec'ing into an existing container. The pod as the unit of orchestration is also much nicer than Docker's single-process containers.

For me, the value proposition is the cloud. When I boot up N nodes, I know that Kubernetes will optimally pack them with my container, and if I boot up N+1 nodes, I know that the containers will spread to the new node, and back down again if I go down to N (either intentionally or accidentally). Orchestration, scheduling, autoscaling etc. take care of this "cloud of containers", if you will, and since every container is an isolated, identical, versioned, stateless (for the most part!), fully redundant thing, I rest assured that what is running is what I deployed.

Then there are all the other nice things, like rolling deploys, cordoning, self-healing, job scheduling, secret management, being able to boot up a parallel, different version of a stack without clobbering everything else, etc. We run production and staging in the same Kubernetes cluster (different namespaces), and we can use things like resource requests/limits and node affinities to ensure that they're scheduled differently, but still using the same underlying hardware resources.

Docker, to me, isn't particularly interesting without Kubernetes, although it has its uses. It's terrific to be able to "boot" a temporary Ubuntu or Elasticsearch or whatever in order to do something that I can just tear down afterwards. Build/test containers are great, both locally and in a CI environment.

What pains are you referring to, specifically?

Re: Connecting Kubernetes services with linkerd

#38

> Facilities that linkerd provides to assist with this include service discovery, load balancing, encryption, tracing and logging, handling retries, expiration and timeouts, back-offs, dynamic routing, and metrics. Why not use SRV records and TLS? Retries, expiration, timeouts, and back-offs can all be placed into the networking library, and are, commonly. Also, regarding https://linkerd.io/ , what's with landing pag…

The whole point of Linkerd is moving logic out of your app. Linkerd is like a library but, instead of being in-process, it inserts itself between the app and whatever the app needs to talk to. The app just dials http://foo.svc/ , and Linkerd sends the connection to the right place; it doesn't need to know where foo.svc is. Many companies, including mine, already run an internal load-balancer (such as HAProxy) that ta…

> The whole point of Linkerd is moving logic out of your app. Linkerd is like a library but, instead of being in-process, it inserts itself between the app and whatever the app needs to talk to. The app just dials http://foo.svc/, and Linkerd sends the connection to the right place; it doesn't need to know where foo.svc is.

That's just DNS.

> Many companies, including mine, already run an internal load-balancer (such as HAProxy) that takes care of routing traffic between microservices.

Why not DNS round-robin?

> I recommend reading the documentation, because drop-in resilience is really the whole point.

Fundamentally, the application itself needs to be resilient. No proxy will make it so. It could help, but it can't do it.

Re: Connecting Kubernetes services with linkerd

#39
post #10

> Facilities that linkerd provides to assist with this include service discovery, load balancing, encryption, tracing and logging, handling retries, expiration and timeouts, back-offs, dynamic routing, and metrics. Why not use SRV records and TLS? Retries, expiration, timeouts, and back-offs can all be placed into the networking library, and are, commonly. Also, regarding https://linkerd.io/ , what's with landing pag…

> > Latency-aware load-balancing > Balances request traffic using real-time performance, reducing tail latencies across your application. > Sounds like it requires a lot of cross-talk on my network, eating up bandwidth. That doesn't sound lightweight. Why does that require eating bandwidth? It's a proxy. It can derive statistics from past and current connections and make decisions based on that data for new ones with…

> Why does that require eating bandwidth? It's a proxy. It can derive statistics from past and current connections and make decisions based on that data for new ones without talking to anyone else.

Wouldn't those stats get out of date really quickly if you're not constantly talking to that machine?

> For many a component like this means it's 10 less things to deal with and more time to focus on building features that'll matter to their end users.

But now you have a new component that you need to test and get to know. You didn't get rid of those 10 things, you just compartmentalized them in something else that needs to be maintained.

> Besides, just because it can already be solved doesn't mean it's not worth trying out other approaches.

Very true, I just don't see the particular advantages to using more basic and well-known tools like DNS and TLS.

Re: Connecting Kubernetes services with linkerd

#40
post #29

> Facilities that linkerd provides to assist with this include service discovery, load balancing, encryption, tracing and logging, handling retries, expiration and timeouts, back-offs, dynamic routing, and metrics. Why not use SRV records and TLS? Retries, expiration, timeouts, and back-offs can all be placed into the networking library, and are, commonly. Also, regarding https://linkerd.io/ , what's with landing pag…

I don't think SRV records are the right answer; your networking layer should be k8s aware and issue a watch command on Endpoints; it'll be updated immediately-ish when the servers changes. This is similar to how finagle's zookeeper server set is supposed to work. What linkerd buys you is you don't have to write this type k8s-aware, zipkin logging library for every language you're running in production. But I think it…

> I don't think SRV records are the right answer;

OK, A/AAAA are more common.

> your networking layer should be k8s aware and issue a watch command on Endpoints;

Or, I could use standard networking concepts and not build my entire app to suit one new thing that I may not want to stay with forever, or even more than just test.

> What linkerd buys you is you don't have to write this type k8s-aware, zipkin logging library for every language you're running in production

There are already TCP/IP, DNS, DHCP, &c libraries for all languages, and that aren't tied to a specific stack. Why should I build into this stack and not into a more common subset?

Post reply on HN