Kubernetes Networking: Behind the Scenes
itnext.io
itnext.io
1. Global node addressing - Given a region + node ID you can query any node from any other node.
2. Global allocation (pod) addressing - Given a region + allocation ID you can interact with individual allocations and tasks (metrics, files, logs, remote exec, etc).
3. Global name-based service addressing (via Consul) - whether via Consul's DNS interface, catalog API, or Connect service mesh, services discover one another by name instead of by IP or port. The service's address (ip+port) is hopefully an opaque implementation detail that never needs to be externally observed.
With all 3 of these taken together there's no need for overlays, distinct subnets, or unique IPs-per-allocation. Datacenters may even have overlapping subnets and Consul Connect will still allow services to communicate via global name based addressing. Even without Consul, almost all Nomad commands will route to a remote region and execute on the correct node regardless of subnet overlapping.
This does cause some friction at the edge: when translating from external IP based routing to internal services (aka ingress). However, there are lots of load balancers that integrate with Consul and therefore translate between IP and name based routing adequately.
Really any service unhappy with our "route by name, not by ip" design is going to be a bit awkward to use, but routable IPs and ports are selected and exposed by Nomad's scheduler - or advertised in Consul if the address is overridden at runtime.
In general actually, I've found TGIK really useful in improving my understanding of the underpinnings of k8s. They have a load of deep dive episodes that focus on a specific part of the solution and generally have a load of hands-on examples.
I think it's because they still want to use the socket API, but to "pretend" you can open a socket to a pod, or to a service, etc.
Instead, they should have defined a new API, like "connect('k8s:service:foobar?selectionstrategy=leastloaded')"
Then they could have made simple LD_PRELOAD shims to get their magic API to work with existing software without modification.
There would be no need for millions of IPtables rules, virtual IP addresses, port remapping, proxy processes, etc.
Secure dynamic overlay networking, plus egress is inherently not a trivial thing. Then add customization/extendability on top.
The important thing to get is that it uses really simple building blocks, very UNIX-y. Every time a new container starts it starts a program (the CNI driver) and pipes in a JSON. And the driver does what it wants (executes iptables, BGP announces a prefix, commits something to its internal DB) and spits out some JSON that tells what IP the container got.
And .. that's it. No magic. Everything has to be configured, arguments passed to some daemon at cluster setup time, and so on. Yes, kubelet and apiserver both have hundreds of command line args, but [almost] all of them are very clearly associated with tuning a functionality (or passing some data forward to some daemon/driver/component) - and thus if you don't touch it but it works, yaay, you don't have to care about it (though of course it might turn out that you'll need to scale up/down/faster/lighter).
The socket API is fine, even with a new shiny API the network fundamentals would have to be managed just the same way. The Linux kernel would be the same, just as Ethernet, IP and so on. Reinventing all of those wheels just to provide transparent pod-to-pod networking doesn't seem to ever worth it.
Kubernetes' networking would arguably have been less complex (multiple CIDR subnets, proxying, etc.) if they'd embraced IPv6. But Google doesn't seem big on IPv6.
// Create an instance representing this service. "my-service" is the
// name of _this_ service. The service should be cleaned up via Close.
svc, _ := connect.NewService("my-service", client)
and when http is used:> The hostname used in the request URL is used to identify the logical service discovery mechanism for the target. It's not actually resolved via DNS but used as a logical identifier for a Consul service discovery mechanism. It has the following specific limitations:
Soon to hit beta though: https://github.com/kubernetes/enhancements/issues/508
Most internal networks still run IPv4, and will continue to do so for a long time.
v6 should've simply been v4 with more bits
We've been deploying IPv6 for at least 10 years and have hosts that are exclusively IPv6. Then along comes Docker and Kubernetes with their retro IPv4 only stack and now customer wonder why we're struggling to make containers work or suppliers that can't understand why we can't easily deploy the latest version of their software, which is only distributed as a Docker image.
Yes, the network effects are strong with this one.
But soon. Bit by bit, I hope the true dualstack will come, and then the v4 will fade away over generations.
Dual stack are not really needed and usually add complexity for few little benefits.
The main problem of IPv6 is the lack of people willing to learn it, teach it and adopt it.
Something brand new like Kubernetes should have from the start been IPv6 only , with IPv4 at the egress parts only.
Edit: added one more link
Thanks for the links.
https://mailarchive.ietf.org/arch/msg/hackathon/PjbOkxx-5O0o...