转自极客时间,仅供非商业用途或交流学习使用,如有侵权请联系删除
你好,我是王炜。
在上一节课,我为你介绍了 GitOps 开发循环反馈变慢的原因以及三种解决方案。在这三种解决方案中,我推荐你使用远程开发的方式来加速开发循环反馈。
这节课,我们就来学习如何借助 Nocalhost 实现 Kubernetes 应用秒级的开发体验,提升开发循环反馈效率。
Nocalhost 是腾讯云 CODING 在 2020 年开源的项目,同时它也是云原生开发领域下第一个由国人主导并进入 CNCF Sandbox 的项目。
我有幸参与了 Nocalhost 从 0 到 1 的研发过程,也深知其工作原理。所以,这节课除了带你了解 Nocalhost 的基本使用以外,我还会带你深入了解它的工作模式和原理,让你更深刻地理解“远程开发”这种创新的开发模式。
在开始今天的学习之前,你需要做好下面这些准备。
- 按照第一章第 2 讲的内容在本地通过配置文件创建 Kind 集群,并在集群内安装好 Ingress-Nginx。
- 配置 Kubectl 使其能够访问 Kind 集群。
远程开发概述
说起远程开发,我相信有一些同学会想到 VS Code 的 SSH Remote。它利用了 VS Code 客户端和 Server 解耦的特性,让 VS Code Server 运行在远端的 VM,本地 VS Code 客户端只起到了 UI 展示和交互的作用,两者通过 SSH Tunnel 进行数据交互,它的工作原理如下图所示。
这种开发方式主要有两个好处。首先,源代码并不会在本地保存,我们在本地编辑的代码实际上是远端机器上的代码,这对于源码安全性要求较高的团队来说是一种不错的实践。其次,由于应用的进程是运行在远端机器上的,所以我们可以借助云端的资源来编译和运行应用,这解决了大型单体应用在本地开发时的资源限制问题。
这种远程开发的思路具有创新性,那么,在云原生架构下我们能否参考这种思想呢?
在学习容器技术的时候,我们经常会把容器比作一台 VM 虚拟机,如果将虚拟机替换成 Pod,似乎就可以实现远程开发的效果了。
但事实真的是这样吗?我们来继续分析。在 Kubernetes 架构体系下,由于 Pod 并没有外网 IP,所以我们很难通过 SSH 的方式连接 Pod。其次,在镜像里内置 SSH Server 并开启 SSH 访问也容易造成安全隐患,我们需要用其他的连接方式取代 SSH。
我们来回顾一下上一节课中我提到的在容器内远程开发的方式,也就是 Nocalhost 的开发方式,如下图所示。
如果你仔细分析这两种开发方式的差异,你会发现,Nocalhost 用代码同步取代了 SSH,这样也就解决了我们上面说的 SSH 连接的问题。
Nocalhost 开发实战
到这里,远程开发的基本知识就介绍完了。接下来我们进入实战环节。
在进入实战之前,你需要先安装 Nocalhost IDE 插件。Nocalhost 支持 VS Code 和 Jetbrains 全系列的 IDE,你可以在市场中搜索。
安装 Nocalhost
接下来,我以 VS Code 为例简单介绍如何安装 Nocalhost 插件。Jetbrains 插件的安装你可以参考这个文档。
首先,在 VS Code 插件市场中搜索 Nocalhost,然后点击“安装”按钮进行安装,如下图所示。
在安装 IDE 插件之后,Nocalhost 会自动下载 nhctl 工具,你可以在 VS Code 的右下角查看下载进度,nhctl 是 Nocalhost 的核心组件,它为插件提供 Kubernetes API 调用能力。
添加 Kubernetes 集群
接下来,在 VS Code 左侧菜单栏中打开 Nocalhost 插件,如果你已经提前准备好了 Kind 集群,Nocalhost 就会自动识别,点击“Add Cluster”即可添加集群。
添加完成后,你可以点击集群名称来查看集群的命名空间,这里将以树状结构展示命名空间,如下图所示。
部署示例应用
添加完集群后,就可以部署 Nocalhost 提供的示例应用了。
将鼠标移动到“default”命名空间,点击右侧的“火箭”按钮,在弹出的对话框中,选择“Deploy Demo”选项来部署示例应用。
此时,Nocalhost 将自动从 GitHub 克隆示例应用仓库,并将它部署到集群的 default 命名空间下。同时,在 VS Code 输出栏中会出现等待 Pod 就绪的提示信息。
当弹出下面的提示时,说明示例应用已经就绪了。
这时候,点击“go”按钮来打开示例应用,Nocalhost 将自动进行端口转发,并打开浏览器访问 http://127.0.0.1:39080/productpage 示例应用页面,如下图所示。
这里我简单介绍一下这个示例应用,这是一个图书管理系统,展示了书籍的详情信息、评价、作者信息、评分。
每部分信息都是由不同的微服务输出的,示例应用一共有 5 个微服务组成,它们分别是 Productpage 服务、Reviews 服务、Details 服务、Rattings 服务和 Authors 服务。其中,Productpage 服务负责输出首页以及请求其他的微服务,也是应用的入口,其他服务根据字面意思分别输出了其他的内容。为了方便你理解它们之间的请求关系,我画了一张图放在了文稿中。
秒级开发循环反馈
在完成示例应用的部署后,假设我们现在有一个需求,我希望修改 Authors 服务输出的作者名信息。一般而言,我需要在本地找到对应的代码并修改,然后构建镜像,推送到镜像仓库,接着修改 Kubernetes 集群的 Authors 工作负载的镜像版本,然后等待新的镜像启动。
接下来我们来看一下如何使用 Nocalhost 打破传统的开发循环反馈,并获得秒级的 Kubernetes 应用开发体验。
我们在 Nocalhost 插件中点击 default 展开命名空间,然后点击 bookinfo 展开应用,点击 Workload 展开工作负载,最后,点击 Deployment 查看工作负载列表。
此时,将鼠标移动到 authors 服务,点击右侧的“绿色锤子”按钮进入该服务的开发模式。然后,在弹出的对话框中选择“Clone from Git Repo”,并选择一个本地目录用来存储源码。点击确认后, Nocalhost 将自动克隆 authors 服务的源码到所选择的目录下,并将源码通过新的 VS Code 窗口打开。
此时,在新的 VS Code 窗口的右下角你会看到 Nocalhost 进入开发模式的提示,等待片刻后,将获得一个远端容器的终端。
注意,这个终端并不是本地的终端,而是 authors 服务在开发模式下的终端。也就是说,在此终端下执行的所有命令实际上都是在 authors 服务的容器里执行的。此时,你可以在终端内执行 ls 命令来查看容器的文件目录。
root@authors-5c5457fbdc-5qlmq:/home/nocalhost-dev# lsDockerfile Makefile README.md app.go bin debug.sh go.mod go.sum run.sh vendor
通过观察我们会发现,容器内的文件目录和 VS Code 正在编辑的文件目录是一致的。
实际上,容器内的文件和目录就是从 VS Code 打开的源码同步过去的。
接下来,我们继续最开始提到的修改作者名称的需求。打开 app.go 文件,找到第 53 行,我们尝试将作者信息修改为“Geekbang”,并保存修改。接下来,在终端下运行下面的命令。
root@authors-5c5457fbdc-5qlmq:/home/nocalhost-dev#sh run.sh2023/01/30 16:58:49 Start listening http port 9080 ...
run.sh 脚本实际是 authors 服务的启动命令,它通过 go run app.go 启动了 authors 服务。
当服务启动完成后,接下来,重新返回浏览器并刷新页面,你将看到刚才的修改已经实时生效了。
怎么样,是不是觉得开发循环反馈又回到了单体应用时代了呢?
现在,你可以在终端下通过 Ctrl+C 来中断 authors 服务的进程。
然后,重新回到浏览器并刷新页面,你将看到 authors 服务当前不可用。
这意味着,我们在进入 authors 服务的开发模式并得到了远程终端之后,便能够直接在容器内控制业务进程的启停操作了。修改代码后,再次重启业务进程就可以得到编码效果,整个体验就像在本地开发一样,它颠覆了传统的开发过程需要构建镜像的操作,并实现了编码实时生效的效果。
容器热加载
通过上面的介绍,我们知道 Nocalhost 是通过文件同步的技术来实现本地和远端代码一致的,在实际编码过程中,每次在本地修改源码后,我们往往需要手动重启容器内的业务进程才能看到编码效果。
那么,能不能更进一步,实现修改代码后自动重载呢?
Nocalhost 同样也为我们提供了和语言无关的容器热加载,也就是说,当本地有任何代码变更时,Nocalhost 都会自动帮助我们重启容器内的业务进程,达到容器热加载的目的。
接下来,我们一起来体验这个功能。
首先,在当前 VS Code 窗口中重新打开 Nocalhost 插件,找到 authors 服务。此时,你将看到该服务左侧有一个“绿色锤子”图标,这表示这个服务正在开发模式当中,如下图所示。
接下来,右击 authors 服务,选择最后一个选项 Remote Run。
注意,在点击 Remote Run 之前,一定要先确保已经通过 Ctrl+C 的方式手动停止了容器内的业务进程,这可以避免重复运行业务进程导致的端口冲突。
现在,Nocalhost 将自动开启一个新的终端,并自动启动业务进程,你也可以通过右侧来切换不同的终端。
接下来,尝试继续修改 app.go 的 54 行,例如删除“bang”字符串并保存。此时,你将看到 Nocalhost 发现了修改并自动重启了容器内的业务进程,如下图所示。
然后,重新打开浏览器并刷新页面,你会发现新的修改已经实时生效了。
有一些同学可能会有疑问,Nocalhost 怎么知道我的业务的启动命令呢?答案是通过为 Nocalhost 配置启动命令。你可以通过点击 authors 服务右侧的“设置”按钮,在弹出的对话框中选择“取消”来查看配置文件中的 command.run 字段。实际上,Nocalhost 是通过运行配置的 run.sh 脚本来启动业务的。
最后,你可以在终端窗口中通过 Ctrl+C 的方式来中断容器热加载。
到这里,Nocalhost 容器热加载的全过程就已经体验完了。
一键调试
除了容器热加载以外,Nocalhost 还为我们提供了便利的一键远程调试功能。
同样地,找到 authors 服务,右击选择“Remote Debug”来进入远程调试。
接下来,Nocalhost 就会以调试模式启动业务进程,然后通过 Kubernetes 端口转发的方式将远端的调试端口转发到本地,并控制调试器连接到调试端口。
需要注意的是,由于 authors 服务是 Golang 编写的,所以调试依赖于本地的 Golang 开发工具,如果你的电脑里没有 Golang 开发环境,Nocalhost 将提示你安装相关工具和插件。
进入调试后,你将看到 VS Code 窗口右下角出现准备连接调试器,如下图所示。
大约等待十几秒钟后,如果弹出了 VS Code 的调试窗口,说明已经成功连接了远端的调试进程,调试界面如下图所示。
接下来,我们可以打开 app.go 文件,并在第 54 行右侧打一个端点,此时,在行数的右侧将出现一个红色的圈圈,代表我们打断点的位置。
现在,你可以重新返回浏览器并刷新页面,这时候,VS Code 调试器将停留在我们打断点的位置,并且在左侧调试菜单栏中展示相关的变量信息。
通过上面的操作,我们便完成了对 authors 服务的一键调试。
在这个调试例子中,如果你用的是 M1 芯片的 Mac,那么你可能会发现在调试过程中 VS Code 的调试器一直无法连接到远端容器,这时候,你还需要进行下面的操作。
在 Nocalhost 插件中点击 authors 服务的“设置”按钮进入服务的开发配置页,并将 image 字段修改为 okteto/golang:1.19,然后,点击“红色锤子”退出 authors 服务的开发模式,退出完成后,再点击“Remote Debug”来进入调试模式即可。
最后,要退出调试模式,你可以切换到 VS Code 终端菜单,并通过 Ctrl+C 的方式来终止调试进程。
原理解析
了解 Nocalhost 的基本使用后,我们来简单看一下它的基本原理。
你可以先思考这样一个问题:在进入开发模式后,我们为什么能以源码的方式在容器里启动业务进程呢?
这个问题看似简单,但却是 Nocalhost 远程开发的核心原理。实际上,我们之所以能在容器内以源码的方式启动业务进程,是因为容器的配置、Secret、服务依赖等并没有变,我们只是将二进制方式启动的业务进程替换成了以源码的方式启动,这是实现远程开发的基础。
在进入开发模式后,Nocalhost 会将容器的镜像替换为开发镜像,并增加用来进行文件同步的 Sidecar 容器,为了更好地帮助你理解,我结合 Kubernetes 画了一张架构图放在了文稿中,你可以看一下。
类似 authors 服务这种编译型语言编写的业务应用,在构建镜像的时候并不会将源码打包到镜像内,并且一般不包含特定的语言开发和编译工具。所以,为了解决这两个问题,在进入开发模式后,Nocalhost 将原来的业务镜像替换为了包含开发和编译工具的 Golang 镜像,并额外增加了 Sidecar 容器,用来将本地的源码同步到容器内。
此外,开发容器和 Sidecar 容器和共享同一个卷存储,这样,当本地代码同步到 Sidecar 容器后,开发容器同样也能够访问到源码,这么做的好处是能够将开发镜像和文件同步功能解耦,你可以随意更换任何开发镜像。
那么,本地又是如何连接到 Sidecar 容器以及进行文件同步的呢?答案是端口转发。
Sidecar 容器在启动后,将启动 Syncthing 文件同步服务,并监听在容器特定端口。随后,Nocalhost 将容器的文件同步服务通过端口转发的方式和本地打通,并同时在本地启动了 Syncthing 客户端,实现了文件的单向和双向同步的功能。
以上就是 Nocalhost 实现远程开发的基本原理了。
总结
总结一下,这节课,我向你介绍了 Nocalhost 的基本使用方法,包括容器热加载和一键调试。使用 Nocalhost 开发 Kubernetes 应用,可以大大地减少开发循环反馈所需要等待的时间,提升开发效率。
在实战环节中,我通过部署示例应用来向你介绍了使用 Nocalhost 的操作细节,当然,由于示例应用内置了开发配置,所以我们整个体验过程是相对顺畅的。当你需要使用 Nocalhost 来开发真实的业务应用时,你可以在 Nocalhost 插件中找到对应的工作负载,并点击“设置”按钮为它配置基本的开发参数就可以进入开发模式了,在配置的过程中,你还可以借助 Nocalhost 提供的网页配置工具来降低开发参数的配置门槛。
此外,我还为你简单介绍了 Nocalhost 的基本原理,它主要是通过替换容器镜像为开发镜像,并增加文件同步的 Sidecar 容器来提供开发工具链和源码。这样,你只需要为待开发的服务配置合适的开发镜像而不需要关注文件同步。
最后,除了远程开发模式,Nocalhost 还提供了 Proxy 代理模式、Service Mesh 和 Duplicate 复制开发模式,不过使用场景相对较少,感兴趣的同学可以在这个文档查看相关资料。
思考题
最后,给你留一道思考题吧。
除了 Nocalhost 这种开发方式以外,在 Kubernetes 环境下你还了解或实践过其他的开发方式吗?对比 Nocalhost 的开发方式,你认为它们有哪些优劣呢?
欢迎你给我留言交流讨论,你也可以把这节课分享给更多的朋友。我们下节课见。