Kubernetes环境下基于Telepresence开发调试实践

以Kubernetes为基础的微服务下开发本地调试面临的问题

微服务是随着领域驱动设计,持续交付,容器化技术,基础设施自动化,小型自治团队,大型集群系统的实践与流行,而总结出来的一种逐渐流行的模式;基于Kubernetes作为微服务应用载体的架构,Kubernetes提供了服务注册、配置管理、负载均衡、故障隔离、业务恢复、自动扩容等能力。相比于传统的Spring Cloud微服务体系,将更多的基础服务下层到基础设施上,让应用层更关注业务开发,同时对多平台语言有了更好的支持。

但是在以Kubernetes为基础的微服务下进行开发、调试;就会面临下面几个问题:

  • 由于服务依赖关系复杂,服务众多,本地进行调试的话需要把关联的服务都搭建-启动起来
  • 微服务依赖的基础设施也需要在本地环境进行搭建-启动,如消息队列、数据库、配置中心、调度中心…

一些解决方案

  1. 通过Docker Compose在本地运行整个多服务应用程序;这种方式并未在Kubernetes内部运行服务,一些基础设施也不容易在本地使用。
  2. 通过类似Telepresence的工具,通过将Kubernetes环境中的数据(连接、环境变量、volumes)代理到本地进程以方便本地进行调试。

Telepresence简介

Telepresence是CNCF 基金会下的一个项目,使用Telepresence可让您在本地运行单个服务,同时将该服务连接到远程Kubernetes群集。 这使在微服务下开发人员可以:

  1. 本地单个服务依赖于群集中的其他服务,也可以进行本地开发与调试
  2. 可以在本地使用IDE调试服务
  3. 使本地开发机器像Kubernetes集群一样运行

实现原理

Telepresence在Kubernetes集群中运行的Pod中部署了双向网络代理,将Kubernetes环境中的数据(连接、环境变量、volumes)代理到本地进程。本地进程的网络透明覆盖,因此DNS调用和TCP连接通过代理路由到远程Kubernetes集群。实现了:

  1. 本地服务具有对远程群集中其他服务的完全访问权限
  2. 本地服务可以访问Kubernetes的环境变量,secrets,ConfigMap
  3. 远程服务可以访问到本地服务

实现方式如下:

  1. 默认使用 --method vpn-tcp,默认情况下,使用程序创建类似VPN的隧道程序sshuttle,sshuttle通过SSH连接建立数据包的隧道,并将DNS查询转发到群集中的DNS代理。
  2. 使用 --method inject-tcp,使用在Linux / OSX上 机制来实现 LD_PRELOAD/ DYLD_INSERT_LIBRARIES ,其中可以将共享库注入到进程中并覆盖库调用;会覆盖DNS解析和TCP连接,并通过SOCKS代理将它们路由到群集。

安装

  • mac上安装Telepresence
brew install kubectl
# 配置相关的kube config...
brew cask install osxfuse
brew install datawire/blackbird/telepresence

Telepresence使用

连接到远程Kubernetes集群

场景

在context为dev的kubernetes集群内,服务A依赖于服务B,需要在本地对服务A进行调试。

操作

启动Telepresence,连接对应集群

telepresence --context dev

对应启动日志

T: Starting proxy with method 'vpn-tcp', which has the following limitations: All processes are affected, only one telepresence can run per machine, and you can't use other VPNs. You may need to add cloud hosts and headless services with --also-proxy. For a full list of
T: method limitations see https://telepresence.io/reference/methods.html
T: Volumes are rooted at $TELEPRESENCE_ROOT. See https://telepresence.io/howto/volumes.html for details.
T: Starting network proxy to cluster using new Pod telepresence-1611716361-290886-47290

T: No traffic is being forwarded from the remote Deployment to your local machine. You can use the --expose option to specify which ports you want to forward.

T: Connected. Flushing DNS cache.
T: Setup complete. Launching your command.

当运行 Telepresence 命令的时候,默认使用vpn-tcp模式;它创建了一个Deployment,对应的 Spec 是负责转发流量的代理容器;对应的pod为上面启动日志的telepresence-1611716361-290886-47290;同时Telepresence在本地创建了一个全局VPN;使得本地的所有程序都可以访问到集群中的服务。

这时候就可以把本地环境的Service A启动起来进行调试,所有的环境变量可以基于上文的dev环境配置。

image1

远程Kubernetes集群内部服务与本地服务联调

场景

在context为dev的kubernetes集群内,服务A依赖于服务B,需要在本地对服务B进行调试;这里调试的前提是我们要有真实的来自服务A的调用流量。

操作

使用Telepresence提供的参数--swap-deployment DEPLOYMENT_NAME[:CONTAINER], -s DEPLOYMENT_NAME[:CONTAINER] 将集群中的一个 Deployment 替换为本地的服务;使用 --expose PORT[:REMOTE_PORT]进行本地-集群Deployment绑定的端口转发。启动本地进程板顶对应expose的PORT进行调试。

# 这里替换了 context为dev、namespace为test的 service-a 到本地服务;并对集群内service-b:8080的流量转发到本地10080端口
telepresence --context dev --namespace test --swap-deployment service-b --expose 10080:8088

这里Telepresence操作的过程如下:

  1. 在集群中创建一个代理Deployment复制service-b的所有Label
  2. 建立一个路由通道,将代理容器的所有流量转发到本地 10080 端口
  3. 将service-b的 replicas 设置为0,kubernetes Service 的 selector 就只能匹配到刚刚创建的代理容器上

image2

一些参数

  • 帮助文档
telepresence --help
  • 新建一个deployment用于测试本地服务访问远程服务
# --new-deployment:创建一个名为 server-c 的 deployment
telepresence --new-deployment server-c --run-shell --also-proxy

参考

https://www.telepresence.io/