K8s技术的出现促进了分布式微服务架构的流行,也成为了分布式服务治理的事实标准。但对于开发人员来说,基于k8s集群的开发、调试也遇到了新的挑战。一次典型的代码调试过程如下:
- 开发人员提交代码
- 触发持续集成系统,代码进行构建,生成docker镜像并推送到镜像仓库
- 触发持续发布系统,使用kubectl命令,或者helm chart将新版本服务部署到k8s集群
- 触发测试操作并判断服务是否正常运行。如果有问题,查看服务日志来分析原因
整个过程耗时且手段单一。那是否有其他方法可以让开发人员快速获得代码改动的反馈,并使用熟悉的手段,如IDE、断点、单步等来进行调试呢?
Telepresence是Ambassador公司开源的一款工具,可以实现以上需求。项目主页github.com/telepresenc…。下面用官方的示例程序把Telepresence的使用方式简单演示一下。
- 准备一个k8s集群,要求安装有ingress controler。
- 一台本地开发用的机器,Widnows、Mac或者Linux都行,以下用Windows为例。要求安装有kubectl,并能访问k8s集群;git及python3。
- 在开发机器上安装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
- 在k8s集群上安装traffic manager。在开发机器powershell窗口中执行:
telepresence helm install
该命令会在远端的k8s集群的ambassador namespace中创建traffic-manager服务。查看服务是否安装完成:
kubectl get pod -n ambassador
- 测试Telepresence。在开发机器powershell窗口中执行:
telepresence connect
telepresence list
如果运行正常,应能看到远端k8s集群默认namespace下的所有服务。
- 在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
- 在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
- 检查示例应用是否工作。打开浏览器,输入地址
http://<k8s集群访问地址>/demo。如果应用工作正常,应该能看到如下文字,注意文字颜色是绿色的。
-
建立本机开发环境,我们将在开发机器上另外运行一个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 -
拦截流量到本地服务。有两种拦截方式: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为例,安装完插件后,点击右上角扩展程序栏中
图标,并添加以下属性:
现在再刷新一下浏览器,应该能看到首行字的颜色从绿色变为了橙色。
需要特别注意一下,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-idVeryLargeJavaService服务正是使用Spring Cloud Sleuth来实现context propagation能力的。
总结一下。Telepresence使用了一个比较有创意的方式来解决k8s微服务开发的调试问题,使用也比较简单,有兴趣的不妨一试。