陈计节-使用 .NET Core 开发 Kubernetes 基础组件(下篇)

在前两篇文章中,我们依次分享了本主题的第一部分内容:.NET Core 和 Kubernetes 简介,大家可以在《陈计节-使用 .NET Core 开发 Kubernetes 基础组件(上篇)》进行查看;以及第二部分内容:使用 .NET Core 与 Kubernetes 交互,大家可以在《陈计节-使用 .NET Core 开发 Kubernetes 基础组件(中篇)》进行查看。今天的文章是本主题的第三篇文章,也是最后一篇文章。

第三部分:使用 .NET Core 开发 Kubernetes 组件

我们来看一下如何去开发集群上的一些基础组件。其实我们很多场景都会用到这些基础组件。比如说作为公司的安全策略,可能公司哪一天突然会要求说现在不允许下载某个镜像仓库里面的镜像。这其实是很正常的,有时候你的集群部署在内网的,你不希望用你集群的同事一不小心就引用了外面公网上的一些镜像。你希望大家只能用内部的镜像。那我们如何去实现这样的一个需求呢?

第四个演示 Kncs.Webhook

我们集群中目前有 5 个 Pod 在正常运行,现在进入 Kncs.Webhook/manifests/test-pods 文件夹内,在终端执行 kubectl create -f ./validatee.yaml 命令,validatee.yaml 文件内容其实就是一个用于验证的 Pod。

在 validatee.yaml 文件中,它用的是外部镜像 abcd.com/centos:7 ,而这个域名的镜像正好是被公司的拦截策略命中的,所以上面执行创建命令时,报错意思为在创建资源对象的时候发生了一个拦截,提示为 Pod should not use this images。现在查看 Pod 数量的话就可以看到名为 webhook-tester-validating 的 Pod 没有被创建出来,集群现在依然还是 5 个 Pod。
这就是我们刚才讲的一个拦截项目,而这个项目其实在 Istio 软件中是很常见的,叫做自动注入 Sidecar 的一个能力。Istio 其实是一个叫做服务网格的产品,它的作用就是帮助我们在集群里面去管理各类的流量,可以实现流量灰度、熔断限流等功能。它的特点是允许我们在业务开发的过程当中,不需要去关注刚才我们讲的这些东西,而当你把程序部署到 Kubernetes 集群上的时候,它就通过自动注入的机制,帮我们把相关的容器注入进去。这种情况下容器就会接管我们的流量,帮助完成流量治理的功能。它的过程跟我们前面讲的内容很相关,前面讲的是拦截,这里讲的是自动注入。它其实是另外一种我们叫做 webhook 的东西。

我们看上图,用户创建的 Pod 里面就是一个名为 myapp 的容器,然后由 Istiod 做了处理之后,增加了一个名为 istio-proxy 的容器。这就叫做 webhook。
在前面的 Yaml 文件中可以看到我们只声明了一个容器,但是实际运行的 Pod 却有两个容器,实际上我们在这里就实现了自动注入。我们来做一个简单的演示。在 Kncs.Webhook/manifests/test-pods 文件夹内,有一个名为 injectee.yaml 的文件,这个文件默认也只有一个容器,现在来看一下我们如何向其中再注入一个容器。在终端执行 kubectl create -f ./injectee.yaml 命令。

看上图 Pod 已经创建好了。可以看到 webhook-tester-mutating Pod 里面确实运行两个容器,通过 describe 命令可以查看 Pod 的详细信息。

在 containers 里面,第一个容器为 centos 7 是处于 sleep 状态,第二个容器为 runtime 也是处于 sleep 状态。而第二个容器就是我们注入进去的。这就被称为自动注入能力。

上面两个演示都是 Kubernetes webhook 的功能,它其实是指用户在界面或是命令行工具写入的各类型的 Kubernetes 资源在写入到 DB 之前,Kubernetes 会调用外面的一些 webhook。比如你做 CI 的话,你希望一提交代码就能触发 CI 的自动运行,这个就是像 git 这种代码托管工具,它可以去调用 CI 的 URL。
在 Kubernetes 里面是一个类似的机制,它可以在写入到数据库之前先调用两种类型的 webhook:

1.第一种类型叫做 Mutating:表示由用户输入的资源可以做一些修改。

2.第二种类型叫做 Validating:表示在修改完之后,可以允许我们以编程的方式对结果来做一些验证。

我们上面的演示,拦截的功能用的就是第二种类型的 webhook,注入的功能就是用的第一种类型的 webhook。

webhook 这种请求实际上也是 JSON 的格式,我们可以用 .NET 程序去编写,整体流程分为三步:

1.获取 Webhook OpenAPI,用 nswag 将模型转换为 C# 类。模型链接在上面的图片中已经给出。

2.根据需求完成 Webhook 的开发。

3.最后将 Webhook 部署到集群中。

Kncs.Webhook 的代码逻辑是非常的简单,而且采用了 Minimal API 的方式去编写的。大家有兴趣的话可以自己去看相关的代码。

上图是其中一些值得单独拎出来说一说的代码片段:

1.在 Validating Webhook 里面会去检查你使用了哪些镜像,我们也用到了人见人爱的 LINQ 语法去完成检查。

2.在 Mutating Webhook 里面我们用到了匿名对象,有时候你在不经意当中就开始使用它了。

对于 Webhook,之前提到过第三个步骤是写完之后,你需要把它安装到集群里面去。具体是有一些步骤的:

1.需要把程序打包成一个容器镜像。

2.去编写相关的 Yaml 文件,包括 Deployment、Service。

3.自签证书:Kubernetes 作为一个运维平台是非常关注安全的,所以要求通讯过程一定是要加密的,我们要做一个自签的证书,然后在相关的 Webhook 配置中添加上证书,它会帮助我们完成相关的调用。

4.在集群中进行部署。

第五个演示 Kncs.CrdController

在今天课程的最后,我们带领大家做一个非常有意思的演示开开眼界。在前面的内容中我们都是使用的 Kubernetes 现成的功能,那我们有没有办法直接增加一个集群的功能呢?像我们日常创建Deployment、Service 等这些东西又是哪来的呢?所以实际上 Kubernetes 可以帮助我们去开发自定义的这种应用类型。

在上图中可以看到有一种 kind 叫做 CSharpApp,那我们能不能在集群里面直接让它运行 C# 代码呢?我们想实现一些具体的目标,比如说:

1.将 C# 代码部署为 Pod:支持直接修改代码,它自动就能运行。

2.能支持多个副本。

3.支持暴露服务端口:如果它是一个 web 应用的话,它还能够暴露出 Service,我能够直接通过本地去访问它。

4.代码变化后,重新部署:它还可以检测到我的代码的修改,然后帮我进行重新部署。

5.不接受编译错误的代码:如果有编译错误就提前拦截。

我们先清理掉之前创建的 Pod,然后来看一下刚才讲的 CSharpAPP,这是一个需要我们去关注的比较有趣的样例。进入 Kncs.CrdController/manifests/samples 目录下,在 console.yaml 文件中有一个叫做 hello-console 的 CSharpApp,它里面运行的是一个 Hello world。

目前集群中没有任何的 Pod,然后我们准备在集群中创建一些 Pod。我们在右边屏幕中执行 kubectl get pods -w 命令来监听应用的运行过程。在左边屏幕中执行 kubectl create -f ./console.yaml 命令。这个 console Pod 里面运行的是一个 Hello word。然后运行 Kncs.CrdController 程序。

Yaml 文件创建成功后,我们执行 kubectl get csharpapp 命令,可以看到输出了 hello-console,并且已经创建了 51 秒。然后执行 kubectl get csharpapp hello-console -o yaml 命令查看 Pod 详细信息。同时右边屏幕也输出了 Pod 的事件信息,表示用来运行 C# 代码的容器已经在创建之中了。

执行命令 kubectl get pods csa-hello-console-181119-rapp 可以查看创建进度。

查看 Pod 的详细信息,可以发现这个 Pod 里面还是挺复杂的:有一个 csharp-app-runner,然后它里面会将相关的 C# 代码给挂载进去。
现在 Pod 已经运行起来了,那我们来看一下它里面运行的结果是什么。当然我希望它运行的就是我的 CSharp APP 代码,这个代码会输出 Hello world from CSharp APP 。如何验证这一点呢?查看它的 Logs 就可以了。

执行命令 kubectl logs csa-hello-console-181119-rsa -c csa,在打印出来的日志中可以看到 Hello world from CSharp APP,打印的整个日志信息其实就是 .NET 自动 build 的过程。所以它会自动帮我们去完成编译,那么有没有可能我现在去给它做一些修改呢?

执行命令 kubectl edit csa hello-console,把 Hello world from CSharp APP 改为 Hello world from Jijie Chen’s CSharp APP。可以看到当我修改了程序之后,它又一次帮我们重新去运行了程序。而且把我们之前的 Pod 自动删掉了,这是不是很像 Deployment 的效果?

现在我们来看一下它在新的容器里面运行的效果是什么,从打印出来的日志中就可以看到,这时候我们的代码就已经被重新的编译和运行了。所以你可以看到,这基本上就实现了一个我们日常当中非常熟悉的 Deployment 的效果。

最后我们来看一个 Web 的效果。在命令行执行 kubectl create -f ./web.yaml 命令,在右侧屏幕可以看到删除 Pod 是需要一定时间的,它中间会逐步删除各种事件。web.yaml 文件有什么不一样的吗?web 我们知道它有一个关键的能力,就是让我们从外面要能访问到,所以配置了 type 为 LoadBalance 类型,把 80 端口暴露出来。那么如何访问 80 端口呢?

我们可以去获取 service,执行命令 kubectl get svc。看到创建了一个名为 hello-web 的 service,它的 EXTERNAL-IP 为 192.168.1.156,我们在浏览器里面来访问一下这个 IP:

可以看到页面显示 Hello world!,这表示已经访问成功了。

那么这就是它帮我们做了一个自动化的部署,同样的,类似的一个能力我们能不能去做一个 edit 呢?执行命令 kubectl edit csa hello-web。同样的,我们对 web 应用也做一个修改,把 Hello World 改为 Hello World from Jijie Chen。

可以想象,如果未来你公司的程序能够实现以这种方式去部署,那么我们可以任务这是一种自动化能力。等新 Pod 创建好了之后,我们去刷新页面,可以看到它现在已经帮我更新成了新版的页面。那么这整个过程中,我们所有的代码都是使用 C# 去完成的,这就是整个 Crd.Controller,我们使用 C# 去实现一个运行器,它可以完成应用的自动化部署。所以这就是 .NET Core 程序程序在 Kubernetes 上能够帮助我们实现各种类型的应用开发。

那我们今天呢,其实跟大家一起聊了很多。一开始我们聊了 .NET Core 和 Kubernetes 的一些介绍,以及我们聊了如何去使用进程的方式,用 ClientCs 去跟集群交互,模拟我们日常使用的一个场景。还有呢就是我们后面去关注的怎么样使用 ClientCs 去开发一些 Webhook、去开发 CrdController,然后以各种方式来定制集群的行为。
因为最后这个 CrdController 的代码是比较复杂的,它里面就留给大家一个家庭作业,去看一下它的运行的过程。如果你去看我的代码,你会发现我到目前还没有实现最后一个功能,就是去拒绝会编译错误的代码。那么这个功能大家有兴趣的话,我非常的鼓励你们去用之前讲的 webhook 的功能去把它完成。这样的话,基本上这个 CSharp APP 就可以成为一个小团队里面可以使用起来的自动化小工具了,可以说是比较有趣的一个东西吧。那我们今天的课程到这里就结束了,非常感谢大家的观看!

第四部分:答疑

第一个问题:怎么学习 Kubernetes?

我觉得这个问题显得比较宽泛了,那我也宽泛的回答一下:就是你最好要多练习。Linux 的特点就是如果你只看书或看视频,那你肯定是学不会的。所以如果你想学习的话,还是需要多加练习。在社区中有很多的交互式学习网站提供了练习素材。

第二个问题:有没有适合部署 Kubernetes 的精简系统呢?可以附加虚机管理的有吗?

这类我不是特别清楚,至少集群类的软件是肯定有的。而虚机管理的话,其实有很多虚机管理软件,你直接安装使用就可以了,这类软件也很多的。

第三个问题:怎么理解 Ingress?

新版本 Kubernetes 中增加了一个功能叫做 APIService。而在这之前呢,Ingress 其实是一种广泛使用的入口流量方法。因为 Kubernetes 它本身内置的 Service 有多种类型,比如 LoadBalance 类型,但这种类型更多还是需要依赖云厂商的实现或是你在本机进行一些配置才能够支持的。那么 Ingress 其实给我们提供了一种,一般来讲叫做七层流量 HTTP 或是 GRPC 这种接入的方法。而 LoadBalance 类型一般都是四层流量接入,而 Ingress 可以使得我们直接以七层的方式去使用。而它的底层可以去共享使用一个 LoadBalance Service,或是共享使用一个云平台的 CRB 这种设施。使得我们以单个的 CLB 共享 IP 的方式去用多个域名来接入到我们的网站。这样的话对于很多小体量的网站是非常好的。有一些 Ingress 也支持七层的转发规则。比如路径前缀,有一些还支持流量灰度的能力,这个都是比较有用的。以上就是 Ingress 相比于 LoadBalance Service来讲的话,它的一些特性。

第四个问题:Yaml 文件是通过接口去修改的吗?需要安装额外的组件来实现吗?

是的,我们今天演示了很多,既有通过 C# 去修改 Yaml,也有通过 C# 生成 Yaml 的,还有通过 C# 不生成 Yaml 直接去操作 API 的。所以今天演示的内容可以说是非常的丰富的。今天演示的代码不需要安装其它额外的组件,只需要 C# 代码加 NewGet 加 IDE 编辑器就可以了。不需要在本地安装 Kubectl,我今天演示的东西里面只需要代码。

第五个问题:Ingress 与 API Gateway 的区别?

其实它们两者有很多相似的地方:Ingress 是一个流量接入措施;API Gateway 除了流量接入之外,通常它还有更加丰富的、对流量的定制和控制能力。通常在它上面还会增加比如像登录或是 head 来做灰度,或是你对流量比例做一些控制。所以 API Gateway 相比于 Ingress 的流量接入能力之外,它还有对流量更细粒度的控制能力。

第六个问题:C# 语言开发 Kubernetes 生态产品和用纯 Go 开发相比有哪些优势呢?

C# 的优势就是它的开发效率比较高,尤其是对 .NET 社区而言,如果大家现有的很多业务已经是在用 C# 写的话,那这时候如果要与现有的业务进行交互的话,它的兼容性非常好,这就是它的独特优势。相对于 Go 语言而言,C# 在面向对象、性能、异步开发等这些方面,实际上都是有它的优势。由于 Kubernetes 生态更多是用 Go 语言开发的,所以使用 C# 也有一些需要注意的地方。如果你想用 C# 去写一些 Kubernetes 底层的东西,比如 CNI、CSI 等许多与操作系统做接口交互的,那么这时候 C# 能使用的周边工具会少一点,也会比较难利用 Go 语言生态已有的这些工具和内库。所以我们不能做一个非常武断的比较,说谁优谁劣的问题。我相信会有很多的厂商或者企业,在自己的这个场景里面会选择一个比较合适的东西来用。

如果是 C 语言的话,我也简单说一下。其实 C 语言相对于 C++ 或是 Go 语言来说,它是比较底层一点的开发语言了。如果你使用 C 语言,就会有很多东西可能需要自己做封装。因为 Kubernetes 它可以用 API 去调、用 SDK 去做,所以社区里面相关的工具都是有的,它其实跟 C# 就很像了,但是它的语法又可能反而还不如 C# 那么方便。
所以如果你只是要做相关的基础组件开发,而又不排斥 Go 语言的话。在 C 和 Go 语言之间选择的话,我比较推荐 Go;而如果是在 Go 和 C# 中间选择的话,就看大家业务的实际情况,然后去做出选择。

第七个问题:调用 Docker 生态是否有相关的 SDK 呢?

.NET 是可以直接调用 Docker API 的,社区中有一个名为 Docker .NET 的项目。Docker 是一个产品,它的 API 现在也已经抽象出来成为一个标准的东西了,所以也就是你与 Docker API 的一套标准打交道。你可以通过 .NET 程序运行一个容器,然后附加到它里面去查看一些进程和各种环境的情况吧,这个还是非常好玩的。

以上就是本主题的全部内容了。本主题前两篇文件的链接如下:
2. 《陈计节-使用 .NET Core 开发 Kubernetes 基础组件(中篇)》:使用 .NET Core 与 Kubernetes 交互。

给TA打赏
共{{data.count}}人
人已打赏
.Net Core

陈计节-使用 .NET Core 开发 Kubernetes 基础组件(中篇)

2022-6-6 10:31:44

.Net Core

交换 .NET Core 的在线旅程

2022-6-10 9:47:22

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
有新私信 私信列表
搜索