使用Telepresence实现k8s集群服务的本地调试

1,021 阅读4分钟

K8s技术的出现促进了分布式微服务架构的流行,也成为了分布式服务治理的事实标准。但对于开发人员来说,基于k8s集群的开发、调试也遇到了新的挑战。一次典型的代码调试过程如下:

  1. 开发人员提交代码
  2. 触发持续集成系统,代码进行构建,生成docker镜像并推送到镜像仓库
  3. 触发持续发布系统,使用kubectl命令,或者helm chart将新版本服务部署到k8s集群
  4. 触发测试操作并判断服务是否正常运行。如果有问题,查看服务日志来分析原因

整个过程耗时且手段单一。那是否有其他方法可以让开发人员快速获得代码改动的反馈,并使用熟悉的手段,如IDE、断点、单步等来进行调试呢?

Telepresence是Ambassador公司开源的一款工具,可以实现以上需求。项目主页github.com/telepresenc…。下面用官方的示例程序把Telepresence的使用方式简单演示一下。

  1. 准备一个k8s集群,要求安装有ingress controler。
  2. 一台本地开发用的机器,Widnows、Mac或者Linux都行,以下用Windows为例。要求安装有kubectl,并能访问k8s集群;git及python3。
  3. 在开发机器上安装Telepresence。以管理员身份打开一个powershell窗口,并执行以下命令:
Invoke-WebRequest https://app.getambassador.io/download/tel2/windows/amd64/latest/telepresence.zip -OutFile telepresence.zip
Expand-Archive -Path telepresence.zip -DestinationPath telepresenceInstaller/telepresence
Remove-Item 'telepresence.zip'
cd telepresenceInstaller/telepresence
powershell.exe -ExecutionPolicy bypass -c " . '.\install-telepresence.ps1';"
cd ../..
Remove-Item telepresenceInstaller -Recurse -Confirm:$false -Force
  1. 在k8s集群上安装traffic manager。在开发机器powershell窗口中执行:
telepresence helm install

该命令会在远端的k8s集群的ambassador namespace中创建traffic-manager服务。查看服务是否安装完成:

kubectl get pod -n ambassador
  1. 测试Telepresence。在开发机器powershell窗口中执行:
telepresence connect
telepresence list

如果运行正常,应能看到远端k8s集群默认namespace下的所有服务。

  1. 在k8s集群上安装示例应用。在开发机器powershell窗口中执行:
kubectl apply -f https://raw.githubusercontent.com/datawire/edgey-corp-python/master/k8s-config/edgey-corp-web-app-no-mapping.yaml

命令执行成功后会安装3个服务:

dataprocessingservice
verylargedatastore
verylargejavaservice

查看服务是否安装完成:

kubectl get pod
  1. 在k8s集群上安装示例应用的ingress路由。在开发机器powershell窗口中执行:
kubectl apply -f ./demo.yaml

demo.yaml文件内容为:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$2
  name: demo
spec:
  rules:
  - http:
      paths:
      - path: /demo(/|$)(.*)
        pathType: Prefix
        backend:
          serviceName: verylargejavaservice
          servicePort: 8080
  1. 检查示例应用是否工作。打开浏览器,输入地址http://<k8s集群访问地址>/demo。如果应用工作正常,应该能看到如下文字,注意文字颜色是绿色的。

image.png

  1. 建立本机开发环境,我们将在开发机器上另外运行一个dataprocessingservice服务。

    • 克隆项目代码
    git clone https://github.com/datawire/edgey-corp-python.git
    
    • 修改代码。打开文件edgey-corp-python/DataProcessingService/app.py,将第16行的DEFAULT_COLOR改为orange
    • 安装依赖并运行服务。
    cd edgey-corp-python/DataProcessingService/
    pip install flask requests   
    python app.py
    
  2. 拦截流量到本地服务。有两种拦截方式:Global intercepts和Personal intercept。
    Global intercepts是将所有的请求都转到本地服务,而Personal intercept则可以根据http请求的header中的预设值进行有条件的拦截。

    • Global intercepts
    telepresence intercept dataprocessingservice --port 3000
    

    该命令会将远端k8s集群中,所有到dataprocessingservice服务的http请求拦截并转发到本地3000端口,也就是本机通过python app.py命令启动的服务的监听端口。
    注意:该命令会在远端k8s集群的dataprocessingservice服务中添加一个sidecar容器,如果网络不稳定,该命令可能会超时。这时候多试几次就可以了。

    现在刷新一下浏览器,应该能看到首行字的颜色从绿色变为了橙色。这说明流量已经成功被拦截到了本地。

    • Personal intercepts
    telepresence intercept dataprocessingservice --port 3000 --http-header=x-telepresence-intercept-id=myid
    

    与Global intercepts相比,这次的命令增加了--http-header=x-telepresence-intercept-id=myid这个参数。它的效果是,只有http请求的header中有x-telepresence-intercept-id=myid这个属性,请求才会被拦截转发到本地,这样就不会影响团队其他成员的使用。其中myid可以是任意能与其他人区分的值。
    注意:这条命令会拉起浏览器要求登录Ambassador Cloud。

    现在刷新一下浏览器,会发现首行字的颜色又变回了绿色,原因是浏览器发出的http请求的header中并没有我们需要的属性,也就不会被拦截转发到本地。

    现在我们需要让浏览器发出的http请求的header中加入我们需要的属性,这需要借助浏览器插件。
    Chrome用这个插件chrome.google.com/webstore/de…
    Firefox用这个插件addons.mozilla.org/firefox/add…

    以Chrome为例,安装完插件后,点击右上角扩展程序栏中image.png图标,并添加以下属性:

    image.png

    现在再刷新一下浏览器,应该能看到首行字的颜色从绿色变为了橙色。

    需要特别注意一下,personal intercepts的实现依赖于context propagation的概念,也就是一个服务收到http请求后,如果它需要接下来再调用下一个服务,它需要将收到请求的header内容复制到下一个http请求中。

    还是以我们的示例应用为例,浏览器发请求给VeryLargeJavaService服务,然后再调用dataprocessingservice服务。这就要求VeryLargeJavaService服务有context propagation的能力。如果我们打开文件edgey-corp-python/VeryLargeJavaService/src/main/resources/application.properties,就会发现这个定义:

    spring.sleuth.baggage.remote-fields=x-telepresence-intercept-id
    

    VeryLargeJavaService服务正是使用Spring Cloud Sleuth来实现context propagation能力的。

总结一下。Telepresence使用了一个比较有创意的方式来解决k8s微服务开发的调试问题,使用也比较简单,有兴趣的不妨一试。