DocsTelepresence
1.0
How it works
How it works
Goals
Our goals for Telepresence are:
- Transparency: make the local proxied process match the Kubernetes environment as closely as possible.
- Isolation: only the proxied process has its environment modified. This goal is much like that of a container: an isolated process-specific environment.
- Cross-platform: Linux and macOS work the same way, when possible. Linux provides far more capabilities (mount namespaces, bind mounts, network namespaces) than macOS.
- Compatibility: works with any program.
Achieving all these goals at the same time is not always possible. We've therefore chosen to support more than one method of proxying, with the different methods each having its own benefits and limitations.
How it works
Telepresence works by building a two-way network proxy (bootstrapped using kubectl port-forward
or oc port-forward
) between a custom pod running inside a remote (or local) Kubernetes cluster and a process running on your development machine.
The custom pod is substituted for your normal pod that would run in production.
Typically you'd want to do this to a testing or staging cluster, not your production cluster.
Environment variables from the remote pod are made available to your local process. In addition, the local process has its networking transparently overridden such that DNS calls and TCP connections are routed over the proxy to the remote Kubernetes cluster. This happens one of two ways:
- When using
--method vpn-tcp
, the default, a VPN-like tunnel is created using a program called sshuttle, which tunnels the packets over the SSH connection, and forwards DNS queries to a DNS proxy in the cluster. - When using
--method inject-tcp
this is implemented usingLD_PRELOAD
/DYLD_INSERT_LIBRARIES
mechanism on Linux/OSX, where a shared library can be injected into a process and override library calls. In particular, it overrides DNS resolution and TCP connection and routes them via a SOCKS proxy to the cluster. We wrote a blog post explaining LD_PRELOAD in more detail.
(Technically there is a third method, for proxying containers, that is based on the vpn-tcp
method.)
Volumes are proxied using sshfs, with their location available to the container as an environment variable.
The result is that your local process has a similar environment to the remote Kubernetes cluster, while still being fully under your local control.
vpn-tcp method in detail
Telepresence figures out the CIDR for Kubernetes Pods and Services, and any cloud hosts specified with --also-proxy
, and tells sshuttle
to forward traffic to those IPs via the proxy Pod running in Kubernetes.
sshuttle
effectively acts as a VPN for these packets.
For DNS the implementation is more complex, since base sshuttle
is insufficient.
sshuttle
will capture all packets going to your default nameservers, and instead forward them to a custom DNS server running inside the Telepresence Pod in the Kubernetes cluster.
For now we'll assume this is a remote cluster.
Some examples can help explain the process.
Whenever you do a DNS lookup your DNS client library may add a suffix, try to resolve that, and if that fails try the original hostname you provided.
For example, if you're working at the offices of Example.com then the DHCP server in your office may tell clients to add example.com
to DNS lookups.
Thus, when you lookup the domain myservice
your DNS client will first try myservice.example.com
and then myservice
if that doesn't work.
On startup:
telepresence
does a lookup ofhellotelepresence
.- Your DNS client library turns this into a lookup of
hellotelepresence.example.com
. sshuttle
forwards this to the custom Telepresence DNS server.- The Telepresence DNS server recognizes the
hellotelepresence
marker, and so now it knows the suffix it needs to filter isexample.com
.
Next let's say you do:
inside a Telepresence-proxied shell.
- Your DNS client library turns this into a lookup of
myservice.example.com
. sshuttle
forwards this to the custom Telepresence DNS server.- The custom Telepresence DNS server strips off
example.com
, and does a local DNS lookup ofmyservice
. - The Kubernetes DNS server replies with the IP of the
myservice
Service. - The custom Telepresence DNS server hands this back,
sshuttle
forwards it back, and eventuallycurl
gets the Service IP. curl
opens connection to that IP,sshuttle
forwards it to the Kubernetes cluster.
minikube/minishift and Docker Desktop
There is an additional complication when running a cluster locally in a VM, using something like minikube, minishift, or Docker Desktop.
Let's say you lookup google.com
.
sshuttle
forwardsgoogle.com
to Kubernetes (via Telepresence DNS server).- Kubernetes DNS server doesn't know about any such Service, so it does normal DNS lookup.
- The normal DNS lookup might get routed via the host machine.
sshuttle
captures all DNS lookups going from the host machine.- Your DNS lookup is now in an infinite loop.
To solve this Telepresence will detect minikube, minishift, and Docker Desktop.
When it does, the Telepresence DNS server will forward DNS requests that aren't Kubernetes-specific to an external DNS server that is different than the ones your host machine is using.
E.g. it might use Google's public DNS if your host isn't.
As a result these DNS lookups aren't captured by sshuttle
and the infinite loop is prevented.
inject-tcp method in detail
A custom SOCKS proxy is run on the Kubernetes pod, which uses Tor's extended SOCKSv5 protocol which adds support for DNS lookups.
kubectl port-forward
creates a tunnel to this SOCKS proxy.
A subprocess is then run using torsocks
, a library that uses LD_PRELOAD
to override TCP and (most) DNS lookups so that they get routed via the SOCKSv5 proxy.
Docker method in detail
Telepresence can also proxy a Docker container, using a variant on the vpn-tcp
method: sshuttle
is run inside a Docker container.
The user's specified Docker container is then run using the same network namespace as the proxy container with sshuttle
.
(In typical Docker usage, in contrast, each container gets its own separate network namespace by default.)