金融投资公司网站建设论文,范县网站建设费用,深圳网站建设优化服务,营销计划前言
从 Kubernetes 诞生以来#xff0c;以 DevOps、容器化、可观测、微服务、Serverless 等技术为代表的云原生#xff0c;催生了应用架构新一轮的升级。有意思的是#xff0c;与以往的技术迭代更新不同#xff0c;原本是一个技术圈常规的一次技术实践#xff0c;在千行…前言
从 Kubernetes 诞生以来以 DevOps、容器化、可观测、微服务、Serverless 等技术为代表的云原生催生了应用架构新一轮的升级。有意思的是与以往的技术迭代更新不同原本是一个技术圈常规的一次技术实践在千行百业数字化转型大背景叠加持续疫情冲击的双重影响之下加上部分传统行业科技自主政策的催化这一次的技术迭代几乎变成了 IT 从业人员全民参与的一次盛宴。但是陡峭的学习曲线、复杂的技术体系、瞬态的基础资源形态让企业的信息体系建设在研发、构建、交付、运维等多方面都带来了不少的挑战。这些挑战也加深了日益更新的技术栈与习惯于聚焦在一线业务开发的开发者之间矛盾这个矛盾直接催生了最近的平台工程理念的诞生。
这个理念抓住这个冲突点提出了“内部研发自助平台”的构想“企业应该以平台化建设的方式提供一系列的自助型工具协助开发者在各个环节中解决遇到的各种技术问题”。这个说法一下戳中众多开发者的痒点这也是这一概念突然之间大火的原因之一。理念背后又引申出来了一个更为直接的问题这个工具里面应该有点啥
揭开问题的面纱
早在 2018 年EDAS 产研团队拜访一家具有百人研发团队的客户当时客户正在进行微服务拆分和迁移上云他们遇到了一些新问题
本地因为依赖问题没法起动完整的环境导致开发困难。云上环境调用关系复杂无法做调试。
客户期望将特定的实例启动到本地云端能调本地本地调云端实现微服务端云联调。对于这些问题我们没有任何准备于是回来后赶紧开始调研分析于是慢慢揭开了藏在水面下的冰山。
客户的诉求很简单就是想把微服务应用起在本地应用能跟云端微服务互相调用如下所示 迁移上云后客户的网关、应用、消息队列、缓存、数据库等组件模块都部署在云端网络内本地需要经过堡垒机才能进行访问。在这种情况下本地节点是不可能正常启动的因为连不通数据库等关键组件也是不可能跟云端服务互相调用的。采取了云原生架构之后客户却再也回不去原来简单高效的本地开发方式了。
这个问题只有这个客户遇到吗不是的这几年我们跟很多客户聊下来他们都有这个问题。但其实也不是一点解决办法都没有最直接的办法是通过架设私有网络的方式连通本地办公网跟云端网络实现网络互通。但实际上这个办法有三大缺陷导致并不是很多客户采用。 成本高昂搭建专线网络的投入相当大相比于收益来说并不划算。安全性低打通本地到云上网络对本地办公网和云上生产网都带来了不稳定因素本质上扩大了安全域也扩大了攻击面。运维复杂网络运维是相当复杂的在高度可伸缩的云原生架构下打平本地和云端网络这个是很多网络工程师的噩梦。本地和云端两张网络必须做好规划两边网段不可冲突同时双向网络路由和安全策略都需要人工管理复杂费力且容易出现问题。
对于这些问题有的企业采取折中的办法在云端找一台机器作为 VPN 服务器搭建本地到云端的 VPN 链路。这个方案同样需要维护网络路由以实现网络互通另外 OpenVPN 虽便宜但不稳定专用 VPN 性能高但费用昂贵鱼与熊掌不可兼得。
意识到这些问题之后我们便开始了“路漫漫其修远兮”的探索之路。
端云互联问题的初解答
在一开始我们就确定两个目标一是双向打通本地和云端链路二是不需要对网络架构进行伤筋动骨的改造。
在历经三个月的闭关研发之后我们在 2018 年底研发出来了这个工具。它支持双向联通而且是插件化开箱即用支持 Windows 和 MacOS 系统。我们把它命名为端云互联其整体组成如下所示 端云互联插件会在启动微服务的时候拉起一个sidecar进程--通道服务通道服务负责接收本地微服务的流量并通过堡垒机转发至云端目标微服务。下面进一步说明其中三个核心要点。
本地微服务调用转发到 sidecar
我们使用了 Java 原生的流量代理技术通过注入启动参数可以使得本地微服务流量以 socks 协议转发至通道服务 sidecar 上。关于具体参数细节可阅读 Java Networking and Proxies 来了解细节。
sidecar 将调用转发到云端微服务
其实 SSH 本身就可以用来进行数据转发充当正向代理和反向代理。SSH 协议从下到上分为传输层、认证层和连接层三层协议
传输层协议Transport Layer Protocol这层协议负责建立起安全的连接通道是整个 SSH 的安全性基石。用户认证协议User Authentication Protocol这层协议负责完成远程身份认证。连接协议Connection Protocol这层协议实现 SSH 通道的多路复用和信息交互可以通过它来实现远程命令执行和数据转发等多种功能。
我们基于 SSH 的连接协议来使得通道服务 sidecar 将调用转发到云端微服务虽然SSH底层原理有点复杂但上层使用是挺简单的主流的编程语言也基本都有现成的库来使用。
云端微服务调用转发到堡垒机
这里我们利用了微服务的机制将堡垒机的 IP 和特定端口作为本地微服务的地址信息注册到注册中心。这样云端微服务调用时就会通过注册中心发现堡垒机并发起服务请求再结合 SSH 的数据转发就能回到本地微服务。
众里寻他千百度
端云互联工具上线后受到了很多客户的欢迎但客户使用过程中遇到了新的问题
NIO 流量代理问题Java Networking and Proxies 里的流量代理参数只对 BIO 的流量生效NIO 框架并不支持。这个问题影响面非常大因为微服务应用基本都会直接或间接地使用 Java NIO 框架。具体简单的例子Netty 本身就是基于 Java Nio 的而很多流行的中间件框架都使用 Netty 作为传输框架。域名解析问题对于域名解析本地微服务应用在访问之前会发起域名解析而这些域名解析同样是不支持 Java 流量代理的。也就是说如果这个域名只能在云端完成解析那么整个调用就会失败。例如K8s 里的 service 域名只能在集群节点上完成 DNS 解析本地是无法解析的从而导致本地无法调用 K8s service。
对于这些问题业界通常的做法是采取容器来解决例如 Telepresence通过将应用跑在容器内再结合 iptables 来拦截并转发整个容器内的流量。这种方式是可行的我们也支持了这种方式整体架构如下所示 这个链路跟之前是差不多的除了本地引入了容器技术之外。在上图中我们通过 docker network connect可以使得应用容器和 sidecard 容器共享网络栈这样通道服务便可以通过 iptables 去拦截本地微服务进程的流量包括 NIO 和 DNS 流量并进行转发。
方案很美好但现实很骨感很多客户用不起来。究其原因那就是本地开发需要引入容器这个重量级的依赖。这里有两个问题一个是“重”另一个是“依赖”。“重”是因为本地开发机器的算力是非常小的。Chrome、IDE 和通信软件等应用往往已经占据了大部分的本地机器资源在这背景下本地再启动容器往往会导致死机。另外Windows 和 MacOS 等主流操作系统也并不自带 Docker 等容器软件开发者需要自己在本地自行安装由于网络带宽等原因整个安装过程也会遇到许多问题。
那除了使用容器还有别的办法来解决应用的流量代理问题吗还是有的不过局限性也非常大。例如 torsocks 这个工具就可以实现进程级别的 TCP 和 DNS 流量拦截并转发但问题是它并不支持 Windows 系统。MacOS 也存在问题。由于 torsocks 是基于 LD_PRELOAD/DYLD_INSERT_LIBRARIES 机制来改写系统调用来进行流量拦截的而 MacOS 系统本身有系统完整性保护会阻止特定系统调用被改写因此并不是所有的流量都能被拦截到。
难道就没有更好的方案了吗
那人却在灯火阑珊处
回顾一下我们所面临的问题Java 原生流量代理不支持 NIO 和 DNS 流量转发。这里有一个非常重要的信息--Java。业界或者开源社区的流量拦截方案普遍追求通用性从而引入了容器依赖顾此失彼。
既然追求通用性有诸多问题那么聚焦到 Java 语言是否有更优的解法答案是肯定的。Java 可以通过 Agent 字节码技术动态修改应用运行时的行为而上层代码无需任何变动。比如像 Pinpoint、SkyWalking 等链路跟踪工具它们都是通过注入一个字节码Agent来实现无侵入的链路埋点的。再比如诊断领域流行的 Arthas 工具它也是基于字节码技术来实现 Java 进程的调用跟踪和 Profiling。
于是我们开始探索基于字节码技术的解决方案。整个探索过程是艰难且有趣的。在微服务框架层面我们需要适配 SpringCloud、Dubbo、HSF 甚至是 gRPC 等主流框架在组件层面我们需要支持微服务、数据库、消息队列、任务调度、缓存等等组件在 JDK 版本上我们需要兼容从 JDK 1.7 到 JDK18 之间的版本...在这过程中我们不断进行迭代改进也不断收到客户的正面反馈让工具日趋完美。
在经过 1 年时间的打磨之后我们终于自研出基于字节码的 Java 流量代理技术架构如下所示 这个方案只需要引入一个代理字节码 Agent并没有引入外部依赖。这个代理 Agent 相比于容器来说轻量得多而且会在启动阶段被端云互联插件自动拉取并注入上层使用是无感知的。至此我们终于很好地解决了本地微服务应用的流量代理问题。
独上高楼望尽天涯路
在这几年里我们一直在低头赶路不断地发现问题并解决问题。与此同时云原生社区也在逐步演进。同样在 2018 年kubernetes 社区发表了一篇名为 Developing on Kubernetes 的文章上面对不同的开发模式有一个非常好的总结 remote 表示云端local 表示本地。cluster 为 K8s 集群dev 为开发环境。针对 dev 和 cluster 不同的位置整体可分为四种开发模式
pure off-line这种模式表示你的 K8s 集群和开发环境都在本地。K3s 、 Minikube和 EDAS Core这里先卖个关子下文再进行介绍都属于这种模式你可以在本地直接启动一个轻量级的开发集群。proxied这种模式表示 K8s 集群运行在云端开发环境在本地云端集群和本地开发环境通过代理进行互联。这个模式的典型代表为社区的 Telepresence 和 EDAS 端云互联。在多语言通用性上 Telepresence 略胜一筹而在 Java 上 EDAS 端云互联更加易用。live这种模式表示 K8s 集群运行在云端开发环境在本地本地代码通过 CICD 等方式来更新云端的应用。这个模式是最常见的模式也是普遍效率最低的模式。如果通过 CICD 部署意味着你每次代码修改都需要经过漫长的构建和部署才能生效到集群里面。如果在开发过程中需要不断修改代码来调试这个迭代部署过程是非常耗时的。remote这种模式表示 K8s 集群和开发环境都在云端。Cloud IDE 是典型的例子代码和运行环境都在云端本地通过浏览器或者轻量级的端应用来编辑代码。实际上来看这种方式仍未得到广大开发者认可本地 IDE 的体验优于 Cloud IDE 体验本地开发仍然是主流。
在 proxied 模式上我们已经把端云互联打磨的相当不错了但它不能解掉所有问题。这样的场景并不罕见本地开发调试都好好的但一部署上去就是有问题。这种问题的根源是本地运行的环境和云端集群里运行环境是不一致的这个不一致会产生种种问题。例如本地能正常运行一个需要 2c4g 的 Java 进程不代表云上集群也能正常分配一个 2c4g 的 Pod因为当前集群内可能是没有多余资源的。
这样的问题有很多不可一一枚举。这也促使我们进一步思考应该如何解决这些问题。在经过半年的调研、探索和研发我们研发出云原生工具箱Cloud Native Development Kit简称 CNKit由它来解决这些问题并提供云原生架构下的开发、调试和诊断能力。
云原生工具箱Cloud Native Development Kit
我们解决问题的思路是要解决环境不一致的问题只能回到环境中去。一个应用在云原生环境下启动虽然看上去很简单但实际上是要经历很多个步骤的。应用需要经过从 K8s 调度到 Pod 初始化再到服务拉起最终才能完成应用运行。在这个过程中你可能会遇到以下问题 对于这些问题我们进行归纳总结沉淀出一套解决方案通过 CNKit 来快速复制 Pod然后进行迭代开发、部署、调试和诊断。整体功能如下所示 通过与 EDAS 全流量流控集成CNKit 可使得只有符合特定规则的调试流量进入复制的 Pod而不影响其他正常流量。对于复制的 Pod你可使用 CNKit 开箱即用的部署、调试和诊断能力并且可以使用基于审计的命令终端。下面来具体说明复制、部署、调试和诊断能力。
复制
这个复制的 Pod 相当于我们自己的一个临时工作空间我们可以不断通过浏览器或者 IDE 来部署自己的应用包并进行调试和诊断。复制 Pod 当前支持如下配置 具体作用为
启动命令即 Pod 的启动命令。默认下使用原镜像的启动命令而如果需要进行迭代部署或者开启调试的话需要自定义启动命令。这是因为在生产环境中原镜像启动命令往往会使用应用进程来作为 1 号进程一旦应用退出或重启这个 Pod 就会随之释放。因此需要设置一个特殊的启动命令来防止 Pod 随应用退出而被释放。复制模式支持基于 Pod 复制或者从 Deployment 的 spec 进行创建。目标节点即 Pod 运行在那个集群节点上。默认通过 K8s 调度来运行 Pod但你也可以直接指定特定集群节点来运行此 Pod。Pod 日志配置将 Pod 日志打到标准输出或者重定向到文件。流量控制通过全链路流控可使得只有符合特定规则的请求进入该 Pod 节点。诊断选项支持应用启动时立即运行 tcpdump 来进行监测、一键打开 JVM 异常记录和去除 Liveness 探针。
这些选项都是基于 EDAS 长年累月的客户支持所总结出来的经验可能看上去并不酷炫但却是非常实用的。拿“去除 Liveness 探针”这个配置项来说明。如果应用启动阶段就出现异常这种情况下 Liveness 探针是会失败的K8s 会直接 Kill 掉这个 Pod 容器并重新拉起。我们会陷入 Liveness 失败Pod 容器被杀死然后容器重启导致现场丢失Liveness 又失败的无限循环当中。去除 Liveness 探针之后你就可以进去 Pod 容器中进行问题排查了。
这里还有一个非常有意思的配置项--全链路流控。全链路流控是 EDAS 上微服务治理的杀手锏可以使得整体微服务链路的流量指哪打哪。对于复制的 Pod我们可能会希望只有自己的请求才进入这个 Pod而不影响其他人的调用请求。这种情况只需要在界面上勾选加入特定流控分组即可使用上非常简单。
部署
还记得最初的问题吗在云原生架构下我们每次部署都需要经过 CICD、EDAS 部署和 K8s 调度来拉起应用这个过程是漫长而痛苦的。而且我们在排查问题时往往需要来临时安装特定工具每次拉起新的应用 Pod 意味着需要重新安装所需工具。
对于这个问题我们推荐采取“一次复制多次使用”策略。在上面提到我们可以通过复制 Pod 来创建出属于自己的“临时工作区”实质也是一个 Pod然后可以通过浏览器或者 IDE 来直接把应用包部署到临时工作区并且进行调试诊断。基于 CICD 和 CNKit 的开发流程是截然不同的如下所示 CICD 部署路径适合生产环境通过标准流程保证了线上业务的稳定性。但同时它又是流程冗长的在开发阶段优势不明显反而会降低开发效率。这种情况下 CNKit 部署流程是很好的互补你只需要复制 Pod然后便可以通过浏览器或者 IDE 来不断更新应用包调试代码。
调试
调试这里特指 remote debug是应用开发过程中相当重要的一环如果无法调试那么应用开发效率将会大大降低。在云原生架构下调试应用并不是那么简单但总是可以完成的。在这一方面CNKit 除了简化调试流程外还提供了流量控制能力
简化流程你只需要在页面上点击“开启调试”CNKit 便会重启 Pod 里的应用来开启调试端口。然后本地通过 IDE 来一键连接到 CNKit接着就可以开始断点调试了。流量控制通过集成 EDAS 全链路流控CNKit 可使得只有特定请求能进入复制 Pod触发断点调试逻辑。
通过这两点你可以非常方便地完成代码调试。下图是一个简单的说明样例假如你在开发一个商品中心上游为交易中心下游为库存中心使用 CNKit 进行调试的整体链路如下所示 标记为开发版本的商品中心即为复制出来的 Pod 节点云端环境中通过全链路流控来将特定流量转发到该 Pod 中开发者本地则通过 CNKit proxy 来连接到该 Pod 的调试端口。
实际上在一个多人并行开发的服务中每个人都可以拥有属于自己的开发版本节点只需要设定不同的流量控制规则即可这样可并行开发可互不干扰。
诊断
我们将问题诊断为 K8s 调度、应用启动、应用运行和应用下线四个阶段。在不同阶段采取的诊断手段并不相同 在 K8s 调度过程中我们主要关注其产生的相关事件发生调度异常时 K8s 会给出相关原因。下图为正常调度时的 K8s 事件 当出现调度异常例如资源不足导致调度失败的问题时K8s 会产生相应事件 而在应用启动阶段除了 K8s 事件我们还可以观察 Pod 日志这部分日志是应用产生的里面包含更详尽的信息。下图为 Pod 的标准输出日志样例 另外应用启动阶段会产生较多网络访问应用启动失败很多情况下都是由于网络请求异常引起的因此 CNKit 支持在启动前自动运行 Tcpdump 来记录网络请求。下图为应用启动时自动抓取的 Tcpdump 包CNKit 支持文本和 pcap 两种格式下图为文本格式的 Tcpdump 数据 最后在应用运行和下线阶段你仍然可以使用 K8s 事件、Pod 日志和 Tcpdump另外还可以一键使用 CNKit 集成的 Arthas 工具。通过在页面上一键运行 ArthasCNKit 会自动完成 Arthas 安装并运行整体交互如下所示 至此CNKit 的复制、部署、调试和诊断都一一分享完毕。但除了这些能力CNKit 还有一些隐藏彩蛋例如审计 Webshell 等等这些地方留给读者来慢慢探索此处不再赘述。
EDAS Core
除了端云互联和 CNKit我们还开放了 EDAS Core。如果按照上面 Developing on Kubernetes 划分的标准来看端云互联属于 proxied 模式CNKit 则为 live 模式而 EDAS Core 则为 pure off-line 模式。
EDAS 本身是收费的商业化产品它是一个应用托管和微服务管理的云原生 PaaS 平台提供应用开发、部署、监控、运维等全栈式解决方案同时支持 Spring Cloud 和 Apache Dubbo 等微服务运行环境。而 EDAS Core 则为免费的轻量级 EDAS 内核版本同样支持上述能力但剥离了商业化特性不提供服务 SLA 和实时的运维支持适合在开发阶段使用。
EDAS Core 最低只需要 4 核 8g 的机器资源我们完全可以在本地笔记本上来运行一个离线的 EDAS 平台并进行微服务开发。EDAS Core 整体架构如下所示 这里进行简单说明
EDAS Core包含了 EDAS 应用托管能力支持 Nacos 服务注册发现和 Minio 持久化存储可运行于 Kind、K3s、Docker-Desktop 和 K8s 集群之上只需 4c8g 的资源占用。开发者工具支持使用 Jenkins 插件进行持续部署、Terraform 进行基础设施维护、ACT 进行本地开发并兼容 EDAS 开放 API 和 SDK。安装介质支持通过 Helm、OSS 和 ADP 进行 EDAS Core 安装。K8s Cluster此 K8s 集群即为 EDAS Core 托管的集群上面运行微服务应用并自动注入服务治 OneAgent。服务集成在横向服务集成上EDAS Core 支持和 EDAS 商业化应用进行一键转换并集成了 ARMS 和 SkyWalking 等链路跟踪产品同时支持使用 ACR 进行镜像托管。
下面为 EDAS Core 的运行界面EDAS 老用户应该对这个界面比较熟悉了 当前 EDAS Core 处于内部邀测状态如果希望使用此能力欢迎在阿里云上向 EDAS 产品发起工单咨询。
结语
云原生架构和微服务开发这两个都是非常流行的技术领域但“云原生架构下的微服务开发”这个命题却甚少见国内厂商提及。EDAS 作为微服务托管领域的先行者很早就开始了云原生架构的支持并一直在关注新架构下的微服务开发问题。
从最早的端云互联模式开始到最近推出的云原生工具箱CNKit和 EDAS CoreEDAS 一直站在开发者角度来思考云原生技术演进所面临的新问题并不断提供解决这些问题的工具和产品。最后对于这几个工具产品进行简单的总结来结束本文 参考资料
EDAShttps://www.aliyun.com/product/edas云原生工具箱https://help.aliyun.com/document_detail/450983.htmlCLMhttps://github.com/cloudnativeapp/CLMtorsockshttps://github.com/dgoulet/torsocksdocker network connecthttps://docs.docker.com/engine/reference/commandline/network_connectThe Secure Shell (SSH) Connection Protocolhttps://www.rfc-editor.org/rfc/rfc4254Java Networking and Proxieshttps://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.htmlDeveloping on Kuberneteshttps://kubernetes.io/blog/2018/05/01/developing-on-kubernetes/Arthashttps://github.com/alibaba/arthas
原文链接
本文为阿里云原创内容未经允许不得转载。