Please enable Javascript to view the contents

重新思考云原生时代的开发环境——从 Dev-to-Cloud 到 Dev@Cloud

 ·  ☕ 7 分钟

大背景

滾滾長江東逝水,浪花淘盡英雄。

作为一个一直在底层苦苦挣扎多年程序员,保持一分学习的好奇心,对技术时势的感知,由为重要。因为这最终决定了技术方向。如果你是个在组织中有话语权的人,那么这影响到你组织的技术方向。而在技术驱动型的公司中,这个直接影响到公司的前途。

开发环境作为一个开发周期的基础架构,本应走在技术的前面去演化。程序员每天为业务,为老板服务的同时,更应该考虑提高开发效率,让更多时间可以在诗和远方上,而非等待打包、等待环境。

下面我尝试分阶段分析一下现状,最后,写写我的想法。

我的黑胶时代

对于开发期的流程,在微服务化前的,过去的 20 年里,程序员已经习惯于:

开发流程:

  1. 本地开发、连接开发用的数据库、调试
  2. 提交代码、跑 CI 测试

CD/DVD 光碟 时代

基于直线的改进思维,微服务化后,程序员自然地探索出:

开发流程:

  1. 本地开发、本地Mock依赖服务、调试
  2. 提交代码、跑 CI 测试
  3. 打包开发期服务 Docker Image

测试环境流程:

  1. 测试人员拉起测试环境、运行测试
  2. 测试中发现问题,通知开发
  3. 开发通过日志、高级一点就动态注入探针、 来定位问题
  4. 开发走上面的“开发流程”尝试修正。
  5. 测试安装新服务 Docker Image,重跑测试
  6. 如果还是有问题,跳回步骤 3

显然,上面有很大的工作效率问题,和不确定性。

网盘时代

为了减少上面的 的成分,加快开发到部署的效率,同时继续把这条思维线拉直。程序员不懈努力。于是新的云开发环境思路出来了,主要线路有两点:

  1. 打通本地开发到测试环境的部署,实现一键完成
  2. 打通本地开发到测试环境的网络,实现测试环境流量引流和互通,有两个目标场景
    • Debug 本地运行的应用,但连接到 K8s 网络
    • Debug K8s Pod 中运行的应用,本地 IDE 远程 debug。

这类型的方法有两个代表项目:

  • telepresence
  • nocalhost

telepresence

其中 telepresence 主要解决网络问题,即打通本机到 k8s 的网络。然后可以在本地运行各种应用来接收和发送流量。当然也可以本地 debug 服务了。

nocalhost

nocalhost 的野心更大,具有开发环境的管理体系。深度整合 vscode / IntelliJ IDEA 实现了一键部署上云,一键远程 debug 等式开发的贴心功能。其设计的核心就是自动同步:

  • 自动同步和热加载代码
  • 文件
  • 终端


图片来源:https://nocalhost.dev/docs/introduction

重新思考

dev-to-cloud 的定义

用架构设计、API设计的思维思考一下。以上方法主要是在为云环境与开发者本机环境间设计一个接口。核心的代码、IDE、开发工具均安置或运行于本机。即,核心开发环境还是以前的样子。以上方法主要带给我们好处是:

  • 一键操作糖、自动同步糖
    • 不可否认,糖很 Sweet 。代价是复杂的工具环境、学习曲线、工具本身的各种环境兼容性问题
  • 网络的连通性
    • 而这个网络连通性是个临时的 vpn tunnel,其稳定性和带宽均难保证,当然,还得面对工具本身的各种环境兼容性问题。

如果我们坐下来想想,我们用云技术把生产环境和集成测试环境上云了,实现了灵活性和伸缩性的需求。而程序员自己的核心开发环境,还一直留在“本机”:

从 High Level 看,这样的结构有其高复杂性、兼容性的问题:

  1. 需要保持两端的同步,对 POD 的注入显然有 POD 的兼容性要求,也对“本地”机器的环境有要求。
  2. Network Tunnel 的复杂性也产生了对“本地”和云端的环境要求。如果云环境
  3. 做得再好的 Brigde 毕竟是 Brigde,很多本地原生开发环境高效完成的事情,变得困难或不可能。
    • jstat, jcmd…

从 Low Level 看:

  1. “本地” 到 “云端”的网络延迟、带宽、可靠性一般不理想。卡壳是常见问题, Troubleshooting 同时,还得 troubleshooting 工具本身,是件痛苦的事情。
    • 现有的 debug 网络协议如:Java Debug Wire Protocol (JDWP) ,均是基于低网络延迟的本地网设计的,IntelliJ IDEA 下默认的远程 debug 慢的感人。
    • 试想要调查一个 heap dump,文件要传多久,本地的机器可能因内存太少根本打不开 heap dump。

我们把这种开发环境的设计方案定义为:dev-to-cloud

dev@cloud 的定义

Remote VSCode

在重新思考时, Remote VSCode 的设计给予了我一点启示:


图片来源:https://code.visualstudio.com/docs/remote/ssh

和之前的重要分别是,本地运行的只是个 UI 壳。文件存储与读写,编译、打包、运行、debug 均发生在远端。每个 UI 中的按键触发一个远端事件。
这个设计当然好,但有两个问题:

  1. VSCode 虽好,但我们还有其它更适合具体语言的 IDE 和工具集。
  2. 要求对端安装 sshd 服务。这有时会是个问题。

kubectl debug

相信大家有听过或用过 kubectl debug。其核心就是在被 debug 的 POD 中拉起一个新的 debugger 容器。并提供一个终端用户界面给用户去控制容器。

The Idea

如何让工具更贴近应用运行,让更多本地开发时用到的功能在云上同时可用?如何提高工具的运行效率,减少远程来回传输?如何提供新手友好、IDE 友好的 GUI 环境?如何方便开发者的接入,只要一个浏览器即可?如果:

  1. 把工具容器(Debugger Container)放在被 debug 的 container 中运行
  2. 两个 container 共享 pid & network namespace
  3. Debugger Container 提供 X Server/ HTTP VNC 服务
  4. 需要更深度整合的话,Debugger Container与被debug的 container 共享目录

从使用者角度看,说得直白点,就是远程桌面到 POD。而且,连接这个远程桌面只需要一个浏览器。

我们把这种开发环境的设计方案定义为:dev@cloud

💡 对于不了解什么是 vnc 的读者,可以看:https://en.wikipedia.org/wiki/Virtual_Network_Computing , 简单来说,就是个远程桌面服务端。
💡 对于不了解什么是 novnc 的读者,可以看:https://novnc.com/info.html , 简单来说,就是个让用户可以通过浏览器,连接到 vnc 服务的界面。

我们可以预期开发端看到的样子大概是:

从我实测看,novnc 用 intellij IDEA 的卡壳比真正由开发机 remote debug 到云端的卡壳少很多。网络临时断开等问题可以轻松自动恢复。想想,下班前未 Troubleshooting 完的问题 ,明天上班简单浏览器一连上就可以继续了。如果自己 Troubleshooting 解决不了,把 novnc 的 URL 一发给同事,对方就可以开工了,不会问你一堆的环境如何连接等问题。

优点:

  • 功能性
    • 靠近应用运行,原有的本地 troubleshooting 手段大部分可以用上:jcmd、jstat…
    • 用你喜欢的 GUI 工具。想想 wireshark、jconsole、eclipse memory analyzer、IDEs
  • 便利性
    • 本地只需要一个浏览器
    • 会话共享给他人协同解决问题方便,只需要一个 URL
    • 会话持久可用,重连方便,不存在数据同步问题
  • 可靠性
    • 保持了应用容器的独立性,资源限制。你大概不敢在一个有 memory limit 的容器中使用 kubectl exec $POD -- wireshark
    • 不存在本机和云间数据不一致问题,不存在来回手工传输大文件等问题。
  • 安全/隐私性
    • 大量数据只保存在云,不存在本机和云间手工传输大文件等问题。只有部分在 GUI 中展示。

to be fair,说说缺点:

  • 安全性与连通性
    • 为桌面设计的 GUI 应用在云端运行,可能有一些互联网访问等问题需要考虑
    • GUI 运行于云端,当然需要云资源。如果公有云的资源昂贵,这是个问题,这个方案可能只适合私有云
    • 由于不同类型应用需要共享的目录不同,mount --bind share directory 可能需要定制

实现 dev@cloud

到现在为止,我是手工实现自己的 dev@cloud 环境的,还未自动化和工具化。现实方法还未有可移植性等考虑。现在的手工步骤是:

  1. docker build 自己的 image。其中包括 xvnc 和 novnc 和一些工具
  2. 被 debug container 的 pid & network namespace 下启动一个 debugger 容器。
    • 这里的方法很多,可以是在 node 中打命令启动,也可以是 kubectl debug
  3. mount --bind share directory 是个可选的步骤。如果打算用 jstat/jcmd 等,共享 /tmp 几乎是必须的。这步暂时无优雅的实现。只能在 node 用 mount --bind
  4. debugger 容器 中启动 xvnc 和 novnc
  5. 通过 k8s nodeport service 等方式,让开发者本机可以访问 novnc 的端口

这里有很多具体细节,我只能在下一编中细说。

总结

写本文的目的不是踩什么和捧什么。方案没有好坏,只有哪个适合你的需求。本文是想开阔一下思路,换个角度,实现真正的 dev@cloud 。谢谢阅读。

是非成敗轉頭空。
青山依舊在,幾度夕陽紅。
白髮漁樵江渚上,慣看秋月春風。
一壺濁酒喜相逢。
古今多少事,都付笑談中。
—— 明代:楊慎

分享

Mark Zhu
作者
Mark Zhu
An old developer