使用 KubernetesClient 操作 kubernetes

使用 KubernetesClient 操作 kubernetes

Intro

我们的应用都是部署在 Kubernetes 上的,我们有一个服务内部有一层 MemoryCache,之前会依赖 Redis 的 Pub/Sub 来做缓存的更新,而 Redis 的 Pub/Sub 是一种不可靠的更新机制,容易发生消息丢失从而导致数据不一致的情况,之后用Stream代替了PUB/SUB。

之前我们有一次问题就是因为这个导致的,在 k8s 集群里有几个 Pod 的数据还是老数据,导致接口拿到的数据有时候是正确的有时候是错误的,这就很尴尬了,发现有问题,每次都去一个一个Pod 去检查就很烦,于是就想写一个脚本或者小工具来自动检查所有集群所有 Pod 的返回值,于是就有了这篇文章的探索。

实现原理

Kubernetes 集群通过 API Server 对外提供了 REST API 以方便通过 API 来操作 Kubernetes 集群

Components of Kubernetes
A diagram showing how the parts of a Kubernetes cluster relate to one another

kubectl 实际工作方式就是一个和 API Server 进行交互的命令行工具,所以我们完全可以自己根据 Kubernetes 提供的 API 来实现我们需要的功能,而 Kubernetes 官方也维护了一个 dotnet 的客户端  KubernetesClient,从而我们可以少写很多代码,直接使用这个 SDK 就可以比较方便的对 Kubernetes 进行操作了。

想一下,如果我们使用 kubectl 的话要如何检查一个集群所有的 pod 的返回结果呢?

首先我们可以通过 kubectl get pod 来获取一个 pod 列表,拿到 pod 列表之后就可以依次访问各个 pod 的 API 拿返回结果了,这里我想到的有两种方式,一种是在 pod 里执行 curl 命令,访问 API 拿到返回的数据,另一种方式是针对 pod 进行 port-forward,然后访问 localhost 就可以请求接口拿到返回数据了。

最后选择的是 port-forward 的方式,因为有的容器里可能并没有 curl,不够通用,所以放弃了在容器里 curl 的方式。

InspectSample

首先我们来看一下 KubernetesClient 基本的使用吧,来看一个简单的示例,遍历所有的 namespace,依次获取每个 namespace 下的 pod

首先我们需要构建一个 IKubernetes 实例以和 Kubenetes 进行通信,在此之前我们需要先构建 KubernetesClientConfiguration,基本使用如下:

// 使用默认的配置,默认的 kubernetes 配置文件,Windows 是 `%PROFILE%/.kube/config`,Linux 是 `%HOME%/.kube/config`
var config = KubernetesClientConfiguration.BuildDefaultConfig();
// 使用指定的配置文件
//var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(file);
IKubernetes kubernetes = new Kubernetes(config);

InspectSample:

var namespaces = _kubernetes.ListNamespace();
foreach (var ns in namespaces.Items)
{var namespaceName = ns.Metadata.Name;Console.WriteLine($"Namespace:{namespaceName}");var pods = _kubernetes.ListNamespacedPod(namespaceName);foreach (var pod in pods.Items){var podName = pod.Metadata.Name;Console.WriteLine($"  Pod: {podName}, Labels: {pod.Metadata.Labels.ToJson()}");var containers = pod.Spec.Containers;foreach (var container in containers){Console.WriteLine($"    Container: {container.Name}");}}
}

输出结果如下:

需要注意的是,如果用户没有权限访问所有的命名空间时,遍历命名空间的时候就会报错

CreatePodSample

上面是一个简单列出 pod 的使用,接着我们来看一个创建 Pod 的示例,我们执行 kubectl delete po/reservation 先把之前的 pod 删掉,然后再通过代码创建一个 pod,创建 pod 的代码如下:

const string namespaceName = "default";
const string podName = "reservation";
const string containerName = "reservation";
const string image = "weihanli/activityreservation:standalone";// // try delete pod if exits
// try
// {
//     await _kubernetes.DeleteNamespacedPodAsync(podName, namespaceName);
//     Console.WriteLine($"Pod:{podName} deleted");
// }
// catch
// {
//     //
// }
// await ListPods();var pod = new V1Pod
{Metadata = new V1ObjectMeta{Name = podName, NamespaceProperty = namespaceName,Labels = new Dictionary<string, string>(){{ "app", "reservation" }}},Spec = new V1PodSpec(new List<V1Container>(){new V1Container(containerName){Image = image,Ports = new List<V1ContainerPort> {new(80)}}}),
};
await _kubernetes.CreateNamespacedPodAsync(pod, namespaceName);await ListPods();async Task ListPods()
{var pods = await _kubernetes.ListNamespacedPodAsync(namespaceName);foreach (var item in pods.Items){Console.WriteLine($"{item.Metadata.Name}, {item.Metadata.Labels.ToJson()}");}
}

输出结果如下:

reservation, {"app":"reservation"}

Port-Forward Sample

最后来看一下我们的 Port-Forward 的示例,示例代码如下:

首先定义一个通用一点的 Port-Forward 的方法,根据官方给出的示例做了一些改动,更好的支持了 CancellationToken

// Port-forward, modified from https://github.com/kubernetes-client/csharp/blob/master/examples/portforward/PortForward.cs#L24
private static async Task PortForward(IKubernetes client, V1Pod pod, CancellationToken cancellationToken,int hostPort)
{Console.WriteLine($"Port-forward started for pod {pod.Metadata.Name}");// Note this is single-threaded, it won't handle concurrent requests well...var webSocket = await client.WebSocketNamespacedPodPortForwardAsync(pod.Metadata.Name, pod.Namespace(),new[] {80}, "v4.channel.k8s.io", cancellationToken: cancellationToken);var demux = new StreamDemuxer(webSocket, StreamType.PortForward);demux.Start();var stream = demux.GetStream((byte?) 0, (byte?) 0);var ipAddress = IPAddress.Loopback;var localEndPoint = new IPEndPoint(ipAddress, hostPort);var listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);listener.Bind(localEndPoint);listener.Listen(100);var handler = listener.Accept();cancellationToken.Register(() =>{try{handler.Close();listener.Close();handler.Dispose();listener.Dispose();demux.Dispose();webSocket.Dispose();}catch{//}Console.WriteLine("Port-forward closed");});cancellationToken.ThrowIfCancellationRequested();// Note this will only accept a single connectionvar accept = Task.Run(() =>{var bytes = new byte[4096];while (!cancellationToken.IsCancellationRequested){var bytesRec = handler.Receive(bytes);stream.Write(bytes, 0, bytesRec);if (bytesRec == 0 || Encoding.ASCII.GetString(bytes, 0, bytesRec).IndexOf("<EOF>", StringComparison.OrdinalIgnoreCase) > -1) break;}}, cancellationToken);var copy = Task.Run(() =>{var buff = new byte[4096];while (!cancellationToken.IsCancellationRequested){var read = stream.Read(buff, 0, 4096);handler.Send(buff, read, 0);}}, cancellationToken);await Task.WhenAny(accept, copy);
}

使用示例如下,使用上面创建的 pod 来演示 port-forward:

var pod = (await _kubernetes.ListNamespacedPodAsync("default")).Items.First(x => x.Name().Equals("reservation", StringComparison.Ordinal));using var cts = new CancellationTokenSource();
var portForwardTask = PortForward(_kubernetes, pod, cts.Token, 8000);try
{using var httpClient = new HttpClient {Timeout = TimeSpan.FromSeconds(10)};while (true){try{var response = await httpClient.GetAsync("http://localhost:8000/api/notice", cts.Token);Console.WriteLine(response.StatusCode);if (response.IsSuccessStatusCode){Console.WriteLine(await response.Content.ReadAsStringAsync(cts.Token));break;}}catch{//}Console.WriteLine("Waiting for port-forward ready...");await Task.Delay(1000, cts.Token);}
}
catch (Exception e)
{Console.WriteLine(e);
}
finally
{cts.Cancel();
}// wait for portForward exit
try
{await portForwardTask;
}
catch
{// ignore port-forward exit exception
}

输出结果如下:

More

通过上面的代码,我们已经可以实现访问 pod 里容器的接口了,只需要将找到 pod 的代码和 port-forward 的代码组合一下就可以达到我们的目标了,对于多个集群可以使用多个配置文件,遍历一下就可以了,如果是在一个配置文件中也可以先获取所有的 cluster,然后在构建 config 的时候指定一个 currentContext 就可以了

有了这个工具下次想检查每个 Pod 返回结果就只需要跑一下就可以比较方便的拿到所有 Pod 的返回结果了

更多 KubernetesClient 使用示例可以参考官方给出的示例:https://github.com/kubernetes-client/csharp/tree/master/examples

上面的代码也可以从我的 Github 上获取:https://github.com/WeihanLi/SamplesInPractice/tree/master/KubernetesClientSample

希望对你有所帮助~

References

  • https://github.com/kubernetes-client/csharp

  • https://kubernetes.io/docs/reference/using-api/client-libraries/

  • https://kubernetes.io/docs/reference/using-api/

  • https://github.com/WeihanLi/SamplesInPractice/tree/master/KubernetesClientSample

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/302197.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cent os重置mysql,linux mysql 能登陆不能修改用户(cent os 6.2)解决思路

linux mysql 能登陆不能修改用户(cent os 6.2)[root3mao /]# select user,host,password from mysql.userbash: syntax error near unexpected token from[root3mao /]# mysql -u rootWelcome to the MySQL monitor. Commands end with ; or /g.Your MySQL connection id is 4S…

本、硕、博到底有什么区别?清华教授的“兔子理论”让你快速弄懂

全世界只有3.14 % 的人关注了数据与算法之美前段时间&#xff0c;有人问到卢sir一个问题——“本、硕、博之间到底有什么区别&#xff1f;”曾经就有一位清华大学教授就讨论过这个问题&#xff0c;让我们来看看这位清华教授是如何看待本、硕、博区别的吧。作者 | 阎学通教授清华…

迁移SVN注意事项及操作方法

最近公司要迁移SVN到新服务器&#xff0c;虽说现在GIT貌似更胜一筹&#xff0c;但是相信用svn的公司还是不在少数&#xff0c;就花了点时间把自己迁移的过程整理了一下。 文档中也许还有不足之处&#xff0c;有问题的话&#xff0c;大家可以告诉我&#xff0c;我会在第一时间修…

重磅!微软发布新一代 Teams 开发工具 —— Teams Toolkit!不止VS Code extension!

今天凌晨&#xff08;北京时间 2021 年 5 月 26 日&#xff09;&#xff0c;在一年一度的 Build 大会上&#xff0c;微软正式发布了新一代的 Teams 开发工具 —— Teams Toolkit。截止到 2021 年 4 月份&#xff0c;Microsoft Teams 的日活用户已经达到了惊人的1.45亿&#xff…

UML实践----用例图、顺序图、状态图、类图、包图、协作图

http://www.uml.org.cn/oobject/200901203.asp UML实践----用例图、顺序图、状态图、类图、包图、协作图 2009-01-20 作者&#xff1a;Randy Miller 来源&#xff1a;网络 面向对象的问题的处理的关键是建模问题。建模可以把在复杂世界的许多重要的细节给抽象出。许多建模工具封…

“六级”题公布,觉得WebAPI简单的,勿进!

大型业务为什么需要深入WebAPI?众所周知&#xff0c;开发健壮的&#xff0c;稳定的&#xff0c;高度扩展性的业务程序&#xff0c;必须要有好的业务框架程序。就好比宝马X5和东风雪铁龙&#xff0c;如果大家体验过两车性能&#xff0c;都知道&#xff0c;宝马X5的性能甩东风雪…

hdu 2896 病毒侵袭

http://acm.hdu.edu.cn/showproblem.php?pid2896 AC自动机的简单题。。。忘记关debug了&#xff0c;wa了一次。。。囧&#xff01; View Code 1 #include <cstdio>2 #include <cstring>3 #include <algorithm>4 #include <set>5 #include <cstdli…

一件有趣的事:我用 Python 爬了爬自己的微信朋友

全世界只有3.14 % 的人关注了数据与算法之美最近几天干啥都不来劲&#xff0c;昨晚偶然了解到Python里的itchat包&#xff0c;它已经完成了wechat的个人账号API接口&#xff0c;使爬取个人微信信息更加方便。鉴于自己很早之前就想知道诸如自己微信好友性别比例都来自哪个城市之…

ML.NET Cookbook:(4)如何调试实验或预览管道?

大多数ML.NET数据操作都是延迟执行的&#xff1a;声明时&#xff0c;操作符不会立即处理数据&#xff0c;而是验证该操作是否可行。执行被推迟到实际请求输出数据为止。这意味着架构不匹配将在声明时抛出&#xff0c;但是直到执行时才抛出数据错误。延迟计算是数据库系统的一种…

数学本是非常有趣的,只是教科书呈现的方式太死板

数学是基础学科&#xff0c;是打开科学大门的钥匙。数学能力决定着一个人的科技创新能力&#xff0c;而科技创新能力决定着一个孩子未来的竞争力。数学也是一门不断累积的学问&#xff0c;学习数学也是一个渐进的过程&#xff0c;要是基础的概念不理解&#xff0c;基础学习得不…

oracle期间平均成本,小李飞刀系列之Oracle EBS期间平均成本(PAC)--生产成本计算(四)制造费用设置及成本计算...

在上两篇文章中介绍了资源的设置及其成本计算&#xff0c;本篇文章将介绍与资源关联非常紧密的制造费用的设置及成本计算。1. 制造费用设置图 1. 制造费用主设置界面制造费用主设置界面如图1所示&#xff0c;成本要素选择”制造费用”&#xff0c;并设置制造费用的名称、说明、…

通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格...

多运行时是一个非常新的概念。在 2020 年&#xff0c;Bilgin Ibryam 提出了 Multi-Runtime&#xff08;多运行时&#xff09;的理念&#xff0c;对基于 Sidecar 模式的各种产品形态进行了实践总结和理论升华。那到底什么是多运行时呢&#xff1f;首先还是得从分布式应用的四大类…

如何把文件压缩变成一张图片?

全世界只有3.14 % 的人关注了数据与算法之美先准备好三个文件。图片、压缩包、批处理文件。然后编辑bat文件。压缩命令代码是&#xff1a;copy /b 图片.jpg压缩包.rar 最后输出文件名.jpg例如&#xff1a;copy /b A.jpgtest.rar B.jpg 注意空格。保存之后执行bat批处理文件。执…

.NET程序崩溃了怎么抓 Dump ? 我总结了三种方案

一&#xff1a;背景 1. 讲故事最近几天接到了几个crash的求助&#xff0c;可能这几个朋友没玩过怎么去生成dump&#xff0c;只能手把手教&#xff0c;感觉也不是一个办法&#xff0c;所以有必要总结一下&#xff0c;后续再有朋友咨询的话&#xff0c;我就可以把这篇文章丢过去了…

敏捷软件开发之结对编程

2019独角兽企业重金招聘Python工程师标准>>> 说明 【作为推荐的最佳实践&#xff0c;结对编程早已为人们熟知&#xff0c;并且也是所有XP实践中争议最大的一个】 结对编程技术是一个非常简单和直观的概念&#xff1a;两位程序员肩并肩地坐在同一台电脑前合作完成同一…

Build 2021 :正式发布.NET 6 Preview4

微软在不断推进.NET 6的可用性&#xff0c;昨晚的Build 2021大会上发布了Preview4&#xff0c; 这是一个很大的版本更新&#xff0c;带来大量的功能&#xff0c;以及接近最终的产品交付质量&#xff0c;不过&#xff0c;这并不意味着可以在生产环境使用了&#xff0c;正式发布R…

程序员与代码的几种关系,每种都会被我们鄙视

全世界只有3.14 % 的人关注了数据与算法之美程序员很大部分时间都在和代码打交道&#xff0c;所以程序员和代码之间的关系&#xff0c;在很多常人看来&#xff0c;是无法理解的&#xff0c;下面我们就来聊聊。找到你仅仅是为了将你消灭掉在程序员的世界里面&#xff0c;一个词语…

.NET 6 Preview 4 已发布,ASP.NET Core 更新内容

原文&#xff1a;bit.ly/3wFqDy9作者&#xff1a;Daniel译者&#xff1a;王亮.NET 6 预览版 4 现已发布&#xff0c;其中包括对 ASP.NET Core 的许多新改进。下面是此次预览版中 ASP.NET Core 的更新内容&#xff1a;引入最小 API异步流HTTP 日志中间件新项目中使用 Kestrel 作…

linux 装nano命令,linux下安装 nano 如果没有这个命令的话~~可以看下

首先查看下这个目录里有没有Centos-Base.repo这个文件(附件里有这个)然后用Xmanager下的xftp 把本机上的这个文件复制到虚拟机中的/目录下[rootfox ~]#mv Centos-Base.repo /etc/yum.repos.d/[rootfox ~]# cd /etc/yum.repos.d/[rootfox yum.repos.d]# lsCentos-Base.repo Cen…

struts2对action的指定方法进行校验

2019独角兽企业重金招聘Python工程师标准>>> 在strust2中&#xff0c;我们可以实现对action的所有方法进行校验或者对action的指定方法进行校验。 一、对于输入校验struts2提供了两种实现方法&#xff1a; 1、采用手工编写代码实现。 &#xff08;1&#xff09;通过…