微服务作为一种全新的软件架构现在正变得越来越火。基本原因我觉得有两点:一方面软件系统越做越复杂,通过拆分将一个大系统解耦成一个个独立的子系统,我们就降低了整个系统的复杂性。另一方面,Kubernetes 的出现使得编排这么多子系统变得简单,可以说 Kubernetes 是目前为止微服务最好的载体。
Kubernetes 解决了微服务运行时的环境问题,但对开发环境就不那么友好了。比方说如果我们要在本地开发调试一个服务 A,但服务 A 可能依赖服务B、C,而服务 B 又有一层依赖 D,我们就需要在本地把服务 B、C、D 都搭建起来才能调试服务 A。这显然是一个很痛苦的过程。
业界有朋友用 docker-compose
来模拟集群中的场景。这个方案的不足之处在于它需要把 Kubernetes
的那一套逻辑用 docker-compose.yml
文件重写一遍,这给我们带来了维护成本。另一方面,有的时候依赖树太大,本地机器完全无法同时运行这么多服务。
1 | ratesvc: |
另一种解决方案就是我这里要介绍的 Telepresence
了,它能够在不修改程序代码的情况下,让本地应用程序无感的接入到 Kubernetes
集群中,这样你就可以直接在本地开发调试微服务了。
Telepresence 简介
Telepresence
是一个 CNCF
基金会下的项目。它的工作原理是在本地和 Kubernetes
集群中搭建一个透明的双向代理,这使得我们可以在本地用熟悉的 IDE
和调试工具来运行一个微服务,同时该服务还可以无缝的与 Kubernetes
集群中的其他服务进行交互,好像它就运行在这个集群中一样。
这是一个 Telepresence
工作原理图,它将集群中的数据卷、环境变量、网络都代理到了本地(除了数据卷外,其他两个对应用程序来说都是透明的):
有了这些代理之后:
-
本地的服务就可以完整的访问到远程集群中的其他服务。
-
本地的服务直接访问到 Kubernetes 里的各种资源,包括环境变量、Secrets、Config map 等。
-
甚至集群中的服务还能直接访问到本地暴露出来的接口。
Telepresence 安装
这里只说一下如何在 macOS
下进行安装。
1 | $ brew cask install osxfuse # required by sshfs to mount the pod's filesystem |
如果官方的安装包没有覆盖到你的平台,其实也可以从源代码安装,因为它本身就是用 Python 3
写的,熟悉 Python
的朋友安装这个程序应该不难,我自己就在 CentOS 7
上安装成功了。
Telepresence 使用场景
假设我们有两个服务 A 和 B,服务 A 是依赖于服务 B 的。下面分两个场景来看看如何用 Telepresence 来调试 A 和 B。
调试服务 A
服务 A 在本地运行,服务 B 运行在远端集群中。借助 Telepresence
搭建的代理,A 就能直接访问到 B。比方说我们的服务 B 是这样一个程序,它监听在 8000 端口上。每当有人访问时它就返回 Hello, world!
。
1 | $ kubectl run service-b --image=datawire/hello-world --port=8000 --expose |
现在在本地用默认参数启动 Telepresence
,等它连接好集群:
1 | $ telepresence |
这时候就可以开始调试服务 A 了,因为服务 B 暴露出来的接口本地已经可以直接访问到:
1 | $ curl http://service-b:8000/ |
这里要说明一下这背后发生的事情:
-
当运行
Telepresence
命令的时候,它创建了一个Deployment
,这个Deployment
又创建了一个用来做代理的Pod
,我们可以这样查看到它kubectl get pod -l telepresence
。 -
同时它还在本地创建了一个全局的
VPN
,使得本地的所有程序都可以访问到集群中的服务。Telepresence
其实还支持其他的网络代理模式(使用--method
切换),vpn-tcp
是默认的方式,其他的好像用处不大,inject-tcp
甚至要在后续的版本中取消掉。 -
当本地的
curl
访问http://service-b:8000/
时,对应的DNS
查询和HTTP
请求都被VPN
路由到集群中刚刚创建的Pod
去处理。
除此之外 Telepresence
还将远端的文件系统通过 sshfs
挂载到本地 $TELEPRESENCE_ROOT
下面(你也可以用参数 --mount <MOUNT_PATH>
指定挂载的路径)。这样,我们的应用程序就可以在本地访问到远程的文件系统:
1 | $ ls $TELEPRESENCE_ROOT/var/run/secrets/kubernetes.io/serviceaccount |
如果我们退出 Telepresence
对应的 Shell,它也会做一些清理工作,比如取消本地 VPN
、删除刚刚创建的 Deployment
等。
调试服务 B
服务 B 与刚才的不同之处在于,它是被别人访问的,要调试它,首先得要有真实的访问流量。我们如何才能做到将别人对它的访问路由到本地来,从而实现在本地捕捉到集群中的流量呢?
Telepresence 提供这样一个参数,--swap-deployment <DEPLOYMENT_NAME[:CONTAINER]>
,用来将集群中的一个 Deployment
替换为本地的服务。对于上面的 service-b
,我们可以这样替换:
1 | $ telepresence --swap-deployment service-b --expose 8000:8000 |
这个时候集群中的服务 A 再想访问服务 B 的 8000 端口时,Telepresence
就会将这个请求转发到本地的 8000 端口。它的工作原理就是将集群中的 service-b
替换为 Telepresence
创建的 Proxy ,然后这个 Proxy 再将请求转发到本地客户端。
即,将原始的网络:
替换为这个结构:
这样我们就有机会在本地查看具体的请求数据,调试逻辑,以及生成新的回复。
总结
这篇文章里我先提出了微服务开发中一个常见的问题,然后介绍了 Telepresence
项目,并且举例说明了怎样用它来调试两种常见的微服务场景。当然,Telepresence 还在不断的演进,本文中使用的是 v0.101 版本,后续版本很可能有些不一样的地方,也欢迎大家不断指正。
来源:喵叔没话说
题图:来自谷歌图片搜索
版权:本文版权归原作者所有
投稿:欢迎投稿,邮箱: editor@hi-linux.com