Kubernetes控制器—Deployment

我们已经知道ReplicaSet控制器是用来维护集群中运行的Pod数量的,但是往往在实际操作时候,我们反而不去直接使用RS,而是使用更上层的控制器,比如我们今天的主角Deployment。

Deployment 一个非常重要的功能就是实现了 Pod 的“水平扩展/收缩”,比如我们应用更新了,我们只需要更新我们的容器镜像,然后修改 Deployment 里面的 Pod 模板镜像,那么 Deployment 就会用滚动更新(Rolling Update)的方式来升级现在的 Pod,这个能力是非常重要的,因为对于线上的服务我们需要做到不中断服务,所以滚动更新就成了必须的一个功能。而 Deployment 这个能力的实现,依赖的就是 ReplicaSet 这个资源对象。

Deployment

Deployment 资源对象的格式和 ReplicaSet 几乎一致,如下资源对象就是一个常见的 Deployment 资源类型:(nginx-deploy.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-demo
namespace: dev
spec:
replicas: 3 # 期望的pod副本数量,默认值 1
selector: # 标签选择器,必须匹配Pod模板中的标签
matchExpressions: # Expressions匹配规则
- key: app
operator: In
values:
- nginx
- mysql
template: # Pod模板
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP

我们创建这个资源对象:

# kubectl apply -f deploy-demo.yaml
deployment.apps/deploy-demo created # kubectl get deploy -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
deploy-demo 3/3 1 3 3m13s # kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
deploy-demo-f8c77cd9d-5pb5g 1/1 Running 0 3m12s
deploy-demo-f8c77cd9d-n455r 1/1 Running 0 3m15s
deploy-demo-f8c77cd9d-zcwnx 1/1 Running 0 3m14s

到这里我们发现和之前的 RS 对象是否没有什么两样,都是根据spec.replicas来维持的副本数量,我们随意查看一个 Pod 的描述信息:

# kubectl describe pod deploy-demo-f8c77cd9d-5pb5g -n dev
Name: deploy-demo-f8c77cd9d-5pb5g
Namespace: dev
Priority: 0
Node: node1/192.168.209.147
Start Time: Mon, 20 Dec 2021 19:58:41 +0800
Labels: app=nginx
pod-template-hash=f8c77cd9d
Annotations: cni.projectcalico.org/podIP: 192.168.166.145/32
cni.projectcalico.org/podIPs: 192.168.166.145/32
Status: Running
IP: 192.168.166.145
IPs:
IP: 192.168.166.145
Controlled By: ReplicaSet/deploy-demo-f8c77cd9d
......

我们仔细查看其中有这样一个信息Controlled By: ReplicaSet/nginx-deploy-f8c77cd9d,什么意思?是不是表示当前我们这个 Pod 的控制器是一个 ReplicaSet 对象啊,我们不是创建的一个 Deployment 吗?为什么 Pod 会被 RS 所控制呢?那我们再去看下这个对应的 RS 对象的详细信息如何呢:

# kubectl describe rs deploy-demo-f8c77cd9d -n dev
Name: deploy-demo-f8c77cd9d
Namespace: dev
Selector: app in (mysql,nginx),pod-template-hash=f8c77cd9d
Labels: app=nginx
pod-template-hash=f8c77cd9d
Annotations: deployment.kubernetes.io/desired-replicas: 3
deployment.kubernetes.io/max-replicas: 4
deployment.kubernetes.io/revision: 4
deployment.kubernetes.io/revision-history: 2
Controlled By: Deployment/deploy-demo
......

其中有这样的一个信息:Controlled By: Deployment/nginx-deploy,明白了吧?意思就是我们的 Pod 依赖的控制器 RS 实际上被我们的 Deployment 控制着呢,我们可以用下图来说明 Pod、ReplicaSet、Deployment 三者之间的关系:

通过这张图,我们就很清楚的看到,一个定义了 replicas=3 的 Deployment,与它的 ReplicaSet,以及 Pod 的关系,实际上是一种“层层控制”的关系。 其中,ReplicaSet 负责通过“控制器模式”,保证系统中 Pod 的个数永远等于指定的个数(比 如,3 个)。这也正是 Deployment 只允许容器的restartPolicy=Always 的主要原因:只有在 容器能保证自己始终是 Running 状态的前提下,ReplicaSet 调整 Pod 的个数才有意义。 而在此基础上,Deployment 同样通过“控制器模式”,来操作 ReplicaSet 的个数和属性,进 而实现“水平扩展 / 收缩”和“滚动更新”这两个编排动作。

水平伸缩

“水平扩展 / 收缩”非常容易实现,Deployment Controller 只需要修改它所控制的 ReplicaSet 的 Pod 副本个数就可以了。

比如现在我们把 Pod 的副本调整到 4 个,那么 Deployment 所对应的 ReplicaSet 就会自动创建一个新的 Pod 出来,这样就水平扩展了,我们可以使用 kubectl scale 命令来完成这个操作 :

# kubectl scale deploy deploy-demo -n dev --replicas=4
deployment.apps/deploy-demo scaled # kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
deploy-demo-f8c77cd9d 4 4 4 23m

可以看到期望的 Pod 数量已经变成 4 了 ,同样我们查看RS的详细信息:

# kubectl describe rs deploy-demo-f8c77cd9d -n dev
Name: deploy-demo-f8c77cd9d
Namespace: dev
Selector: app in (mysql,nginx),pod-template-hash=f8c77cd9d
Labels: app=nginx
pod-template-hash=f8c77cd9d
...... 省略部分内容
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 24m replicaset-controller Created pod: deploy-demo-f8c77cd9d-n455r
Normal SuccessfulCreate 24m replicaset-controller Created pod: deploy-demo-f8c77cd9d-zcwnx
Normal SuccessfulCreate 24m replicaset-controller Created pod: deploy-demo-f8c77cd9d-5pb5g
Normal SuccessfulCreate 2m56s replicaset-controller Created pod: deploy-demo-f8c77cd9d-7tw7x

同样我们可以通过修改配置文件中的spec:replicas来实现。

滚动更新

如果只是水平伸缩这个功能,就完全没有必要设计Deployment这个资源对象了,这个功能resplicaSet就已经实现了。

现在我们来直接使用上面的 Deployment 资源对象:

# kubectl apply -f deploy-demo.yaml --record
deployment.apps/deploy-demo configured

注意,在这里额外加了一个–record 参数。它的作用,是记录下你每次操作所执行的命令, 以方便后面查看。

更新后,我们可以执行下面的 kubectl rollout status 命令来查看我们此次滚动更新的状态:

# kubectl rollout status deploy deploy-demo -n dev
Waiting for deployment "deploy-demo" rollout to finish: 2 out of 3 new replicas have been updated...
deployment "deploy-demo" successfully rolled out

此时我们可以尝试查看一下这个 Deployment 所控制的 ReplicaSet:

# kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
deploy-demo-f8c77cd9d 3 3 3 8s

如上所示,在用户提交了一个 Deployment 对象后,Deployment Controller 就会立即创建一 个 Pod 副本个数为 3 的 ReplicaSet。这个 ReplicaSet 的名字,则是由 Deployment 的名字和 一个随机字符串共同组成。 这个随机字符串叫作 pod-template-hash,在我们这个例子里就是:f8c77cd9d。 ReplicaSet 会把这个随机字符串加在它所控制的所有 Pod 的标签里,从而保证这些 Pod 不会与集群里的其他 Pod 混淆。

这个时候,如果我们修改了Deployment的pod模板,"滚动更新"就会被自动触发。我们使用kubectl edit指令编辑ETCD里API对象。

# Kubectl edit deployment/deploy-demo -n dev

......
spec:
containers:
- image: nginx:1.17.9 # 1.17.1 -> 1.17.9
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
protocol: TCP
......

kubectl edit 指令编辑完成后,保存退出,Kubernetes 就会立刻触发“滚动更新”的过程。

这时我们通过查看Deployment的Events,看到这个"滚动更新"的流程:

# kubectl describe deployment deploy-demo -n dev

......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 3m48s deployment-controller Scaled up replica set deploy-demo-f8c77cd9d to 3
Normal ScalingReplicaSet 21s deployment-controller Scaled up replica set deploy-demo-5df494d57d to 1
Normal ScalingReplicaSet 20s deployment-controller Scaled down replica set deploy-demo-f8c77cd9d to 2
Normal ScalingReplicaSet 20s deployment-controller Scaled up replica set deploy-demo-5df494d57d to 2
Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set deploy-demo-f8c77cd9d to 1
Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set deploy-demo-5df494d57d to 3
Normal ScalingReplicaSet 17s deployment-controller Scaled down replica set deploy-demo-f8c77cd9d to 0

可以看到,首先,当修改了 Deployment 里的 Pod 定义之后,Deployment Controller 会使用这个修改后的 Pod 模板,创建一个新的 ReplicaSet(hash=5df494d57d),这个新的 ReplicaSet 的初始 Pod 副本数是:0。 然后,在 Age=21 s 的位置,Deployment Controller 开始将这个新的 ReplicaSet 所控制的 Pod 副本数从 0 个变成 1 个,即:“水平扩展”出一个副本。

紧接着,在 Age=20 s 的位置,Deployment Controller 又将旧的 ReplicaSet(hash=f8c77cd9d)所控制的旧 Pod 副本数减少一个,即:“水平收缩”成两个副本。

如此交替进行,新 ReplicaSet 管理的 Pod 副本数,从 0 个变成 1 个,再变成 2 个,最后变成 3 个。而旧的 ReplicaSet 管理的 Pod 副本数则从 3 个变成 2 个,再变成 1 个,最后变成 0 个。这样,就完成了这一组 Pod 的版本升级过程。 像这样,将一个集群中正在运行的多个 Pod 版本,交替地逐一升级的过程,就是“滚动更 新”。 在这个“滚动更新”过程完成之后,你可以查看一下新、旧两个 ReplicaSet 的最终状态:

# kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
deploy-demo-5df494d57d 3 3 3 3m20s
deploy-demo-f8c77cd9d 0 0 0 6m47s

其中,旧 ReplicaSet(hash=f8c77cd9d)已经被“水平收缩”成了 0 个副本。

这种“滚动更新”的好处是显而易见的。 比如,在升级刚开始的时候,集群里只有 1 个新版本的 Pod。如果这时,新版本 Pod 有问题启 动不起来,那么“滚动更新”就会停止,从而允许开发和运维人员介入。

而在这个过程中,由于 应用本身还有两个旧版本的 Pod 在线,所以服务并不会受到太大的影响。 当然,这也就要求你一定要使用 Pod 的 Health Check 机制检查应用的运行状态,而不是简单 地依赖于容器的 Running 状态。要不然的话,虽然容器已经变成 Running 了,但服务很有可能尚未启动,“滚动更新”的效果也就达不到了。

而为了进一步保证服务的连续性,Deployment Controller 还会确保,在任何时间窗口内,只有指定比例的 Pod 处于离线状态。同时,它也会确保,在任何时间窗口内,只有指定比例的新 Pod 被创建出来。这两个比例的值都是可以配置的,默认都是 DESIRED 值的 25%。 所以,在上面这个 Deployment 的例子中,它有 3 个 Pod 副本,那么控制器在“滚动更 新”的过程中永远都会确保至少有 2 个 Pod 处于可用状态,至多只有 4 个 Pod 同时存在于集 群中。这个策略,是 Deployment 对象的一个字段,名叫 RollingUpdateStrategy,如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-demo
namespace: dev
spec:
replicas: 4 # 期望的pod副本数量,默认值 1
selector: # 标签选择器,必须匹配Pod模板中的标签
matchExpressions: # Expressions匹配规则
- key: app
operator: In
values:
- nginx
- mysql
minReadySeconds: 5 # 表示 Kubernetes在等待设置的时间后才进行升级,默认值0
strategy:
type: RollingUpdate # 指定更新策略: RollingUpdate和Recreate
rollingUpdate:
maxSurge: 50%
maxUnavailable: 50%
template: # Pod模板
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
  • minReadySeconds:表示 Kubernetes 在等待设置的时间后才进行升级,如果没有设置该值,Kubernetes 会假设该容器启动起来后就提供服务了,如果没有设置该值,在某些极端情况下可能会造成服务不正常运行,默认值就是0。
  • type=RollingUpdate:表示设置更新策略为滚动更新,可以设置为RecreateRollingUpdate两个值,默认值就是RollingUpdate,Recreate表示全部重新创建,在创建新pod之前,会杀死所有存活的pod。
  • maxSurge:表示升级过程中最多可以比原先设置多出的 Pod 数量,例如:maxSurage=1,replicas=5,就表示Kubernetes 会先启动一个新的 Pod,然后才删掉一个旧的 Pod,整个升级过程中最多会有5+1个 Pod。
  • maxUnavaible:表示升级过程中最多有多少个 Pod 处于无法提供服务的状态,当maxSurge不为0时,该值也不能为0,例如:maxUnavaible=1,则表示 Kubernetes 整个升级过程中最多会有1个 Pod 处于无法服务的状态。

同时maxSurgemaxUnavaible还可以使用百分比形式来表示,比如maxSurge=50%,指的是我们最多一次创建的新Pod数量时原来pod数量的二分之一。

结合以上讲述,现在我们可以扩展一下 Deployment、ReplicaSet 和 Pod 的关系图了。

如上所示,Deployment 的控制器,实际上控制的是 ReplicaSet 的数目,以及每个 ReplicaSet 的属性。而一个应用的版本,对应的正是一个 ReplicaSet;这个版本应用的 Pod 数量,则由 ReplicaSet 通过它自己的控制器(ReplicaSet Controller)来保证。 通过这样的多个 ReplicaSet 对象,Kubernetes 项目就实现了对多个“应用版本”的描述。

而明白了“应用版本和 ReplicaSet 一一对应”的设计思想之后,我们探究下Deployment对应用进行版本控制的具体原理。

我们使用kubectl set image指令,直接修改 deploy-demo 所使用的镜像。这个命令的好处就是,你可以不用像 kubectl edit 那样需要打开编辑器。

不过这一次,我把这个镜像名字修改成为了一个错误的名字,比如:nginx:1.91。这样,这个 Deployment 就会出现一个升级失败的版本。

# kubectl set image deployment/deploy-demo nginx=nginx:1.91 -n dev
deployment.apps/deploy-demo image updated

由于这个 nginx:1.91 镜像在 Docker Hub 中并不存在,所以这个 Deployment 的“滚动更 新”被触发后,会立刻报错并停止。 这时,我们来检查一下 ReplicaSet 的状态,如下所示:

# kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
deploy-demo-7465f86b8f 4 4 0 8s
deploy-demo-f8c77cd9d 2 2 2 46m

通过这个返回结果,我们可以看到,新版本的 ReplicaSet(hash=7465f86b8f)的“水平扩 展”已经停止。而且此时,它已经创建了四个 Pod,但是它们都没有进入 READY 状态。这当然 是因为这四个 Pod 都拉取不到有效的镜像。 与此同时,旧版本的 ReplicaSet(hash=f8c77cd9d)的“水平收缩”,也自动停止了。此 时,已经有两个旧 Pod 被删除,还剩下两个旧 Pod。 那么问题来了, 我们如何让这个 Deployment 的 4个 Pod,都回滚到以前的旧版本呢?

我们只需要执行一条 kubectl rollout undo 命令,就能把整个 Deployment 回滚到上一个版 本:

# kubectl rollout undo deployment/deploy-demo -n dev
deployment.apps/deploy-demo rolled back # kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
deploy-demo-7465f86b8f 0 0 0 4m51s
deploy-demo-f8c77cd9d 4 4 4 51m

很容易想到,在具体操作上,Deployment 的控制器,其实就是让这个旧 ReplicaSet(hash=f8c77cd9d )再次“扩展”成 4 个 Pod,而让新的 ReplicaSet(hash=7465f86b8f)重新“收缩”到 0 个 Pod。

更进一步地,如果我想回滚到更早之前的版本,要怎么办呢?

首先,我需要使用 kubectl rollout history 命令,查看每次 Deployment 变更对应的版本。而由于我们在创建这个 Deployment 的时候,指定了–record 参数,所以我们创建这些版本时执 行的 kubectl 命令,都会被记录下来。

# kubectl rollout history deployment/deploy-demo -n dev
deployments "deploy-demo"
REVISION CHANGE-CAUSE
1 kubectl create -f nginx-deployment.yaml --record
2 kubectl edit deployment/nginx-deployment
3 kubectl set image deployment/nginx-deployment nginx=nginx:1.91

当然,我们还可以通过这个 kubectl rollout history 指令,看到每个版本对应的 Deployment 的 API 对象的细节,具体命令如下所示:

# kubectl rollout history deployment/deploy-demo -n dev --revision=2

然后,我们就可以在 kubectl rollout undo 命令行最后,加上要回滚到的指定版本的版本号, 就可以回滚到指定版本了。这个指令的用法如下:

# kubectl rollout undo deployment/deploy-demo -n dev --to-revision=2

这样,Deployment Controller 还会按照“滚动更新”的方式,完成对 Deployment 的降级操 作。

不过,你可能已经想到了一个问题:我们对 Deployment 进行的每一次更新操作,都会生成一 个新的 ReplicaSet 对象,是不是有些多余,甚至浪费资源呢?

Kubernetes 项目还提供了一个指令,使得我们对 Deployment 的多次更新操作,最后只生成一个 ReplicaSet。 具体的做法是,在更新 Deployment 前,先执行一条 kubectl rollout pause 指令。

# kubectl rollout pause deployment/deploy-demo -n dev
deployment.apps/deploy-demo paused

这个 kubectl rollout pause 的作用,是让这个 Deployment 进入了一个“暂停”状态。 所以接下来,就可以随意使用 kubectl edit 或者 kubectl set image 指令,修改这个 Deployment 的内容了。

由于此时 Deployment 正处于“暂停”状态,所以我们对 Deployment 的所有修改,都不会触 发新的“滚动更新”,也不会创建新的 ReplicaSet。 而等到我们对 Deployment 修改操作都完成之后,只需要再执行一条 kubectl rollout resume 指令,就可以把这个 Deployment“恢复”回来,如下所示:

# kubectl rollout resume deploy/deploy-demo -n dev
deployment.apps/deploy-demo resumed

而在这个 kubectl rollout resume 指令执行之前,在 kubectl rollout pause 指令之后的这段时间里,我们对 Deployment 进行的所有修改,最后只会触发一次“滚动更新”。

当然,我们可以通过检查 ReplicaSet 状态的变化,来验证一下 kubectl rollout pause 和`` kubectl rollout resume` 指令的执行效果,如下所示:

# kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
deploy-demo-7465f86b8f 0 0 0 15m
deploy-demo-f8c77cd9d 3 3 3 15m

通过返回结果,我们可以看到,只有一个 hash=f8c77cd9d 的 ReplicaSet 被创建了出来。 不过,即使像上面这样小心翼翼地控制了 ReplicaSet 的生成数量,随着应用版本的不断增 加,Kubernetes 中还是会为同一个 Deployment 保存很多很多不同的 ReplicaSet。 那么,我们又该如何控制这些“历史”ReplicaSet 的数量呢?

很简单,Deployment 对象有一个字段,叫作 spec.revisionHistoryLimit,就是 Kubernetes 为 Deployment 保留的“历史版本”个数。所以,如果把它设置为 0,你就再也不能做回滚操作了。

Kubernetes控制器-Deployment的更多相关文章

  1. Kubernetes中Deployment部署故障排除

    Kubernetes中Deployment部署故障排除 字符型思维导图 排查pod状态(带标签):kubectl get pods,是否有等待处理的pod? 是?kubectl describe po ...

  2. Kubernetes 控制器

    在实际使用的时候并不会直接使用 Pod,而是会使用各种控制器来满足我们的需求,Kubernetes 中运行了一系列控制器来确保集群的当前状态与期望状态保持一致,它们就是 Kubernetes 的大脑. ...

  3. 【06】Kubernets:资源清单(控制器 - Deployment)

    写在前面的话 上一节主要简单的提了一下控制器都有哪些常用的,并且简单的功能是啥,最后一并提了 ReplicaSet 控制器. 但是 ReplicaSet 一般不需要我们直接配置,多以从本节开始,开始学 ...

  4. 【Kubernetes】Deployment控制器模型

    在Kubernetes中,Deployment是最基本的控制器对象 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deploym ...

  5. Kubernetes笔记(六):了解控制器 —— Deployment

    Pod(容器组)是 Kubernetes 中最小的调度单元,可以通过 yaml 定义文件直接创建一个 Pod.但 Pod 本身并不具备自我恢复(self-healing)功能.如果一个 Pod 所在的 ...

  6. Kubernetes之Deployment控制器

    Deployment 简介 deployment 是用来管理无状态应用的,面向的集群的管理,而不是面向的是一个不可变的个体,举例:有一群鸭子,要吃掉一个,只需要再放一个新的鸭仔就好了,不会影响什么,而 ...

  7. Kubernetes — 控制器

    Pod 这个看似复杂的 API 对象,实际上就是对容器的进一步抽象和封装而已. 说得更形象些,“容器”镜像虽然好用,但是容器这样一个“沙盒”的概念,对于描述应用来说, 还是太过简单了. 这就好比,集装 ...

  8. kubernetes 控制器详解【持续完善中】

    目录 资源创建详解 一:Pod及常用参数 1.简介 2.模板 3.删除pod 4.设置Pod主机名 5.镜像拉取策略(ImagePullPolicy) 二:RC 1.简介 2.模板 三:Deploym ...

  9. kubernetes的Deployment, DaemonSet, Job 和 CronJob事例

    k8s kubernetes给node节点添加标签和删除node节点标签 Deployment配置文件exampledeploymentv1.yaml apiVersion: apps/v1 kind ...

  10. Kubernetes之deployment

    Kubernetes实现了零停机的升级过程.升级操作可以通过使用ReplicationController或者ReplicaSet实现,但是Kubernetes提供了另一种基于ReplicaSet的资 ...

随机推荐

  1. Web前端入门第1问:英语是否很重要?有哪些前置条件?

    HELLO,这里是大熊学习前端开发的入门笔记. 本系列笔记基于 windows 系统. 在入门之前,是否有这样的疑问: 程序员的英语是否很牛?毕竟程序员的代码像天书一样,比如这样: 答案是否定的. 英 ...

  2. k8s NotReady cni config uninitialized

    前言 k8s node 节点 join master 后,状态报错:NOT READY 查看 kubelet 日志 journalctl -xeu kubelet 报错如下:Container run ...

  3. halcon 入门教程(一) 预处理图像 (图像平滑,图像增强,二值化,形态学分析)

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/18779326 本来今天想写一下halcon深度学习教程(三)目标检测的,不过今天有显卡的那台电 ...

  4. 文件转十六进制出现转义字符直接通过ASCII码逐字符展开的问题与修复

    近日工作中遇到某品牌电子签章系统生成的PDF文件若直接使用十六进制查看器打开,会出现转义字符被直接以ASCII编码转换为16进制字符串的问题,导致提取的文件无法匹配ASN.1格式,无法进一步对签章有效 ...

  5. ORACLE忘记用户名和密码、解锁、查询

    一.Oracle忘记用户名和密码 1.打开命令提示符,输入命令sqlplus ,进入oracle控制台 2.用户名输入 sqlplus/as sysdba,口令:空(回车即可) 3.连接成功后,输入& ...

  6. Pydantic Mixin:构建可组合的验证系统体系

    title: Pydantic Mixin:构建可组合的验证系统体系 date: 2025/3/22 updated: 2025/3/22 author: cmdragon excerpt: Pyda ...

  7. TimeSpan 的 Milliseconds 和 TotalMilliseconds 有啥区别?

    有小伙伴问到 TimeSpan的 Milliseconds和TotalMilliseconds有啥区别啊? 我用TimeSpan.FromSeconds(3600).Milliseconds就获取到是 ...

  8. Linux防火墙操作指令

    firewall-cmd --list-ports # 查看开放的端口号 firewall-cmd --zone=public --add-port=8888/tcp --permanent # 开放 ...

  9. MaxKB 开启模型联网搜索

    前言 模型联网搜索是当前大语言模型(LLM)领域的重要技术方向,其核心在于通过结合互联网实时数据与模型推理能力,突破预训练数据的时间限制,提供更精准.动态的回答. 核心应用场景 实时信息补充 例如查询 ...

  10. fiddler的composer设计器

    1.过程:点击composer,把要修改请求体的会话拖到composer空白处,composer出现请求方式,url,请求报文,请求体 2.在请求体中修改请求内容(比如删除号码),然后点击excute ...