OpenKruise

OpenKruise 是 Kubernetes 的一个标准扩展,它可以配合原生 Kubernetes 使用,并为管理应用容器、sidecar、镜像分发等方面提供更加强大和高效的能力。

核心功能

  • 原地升级

    原地升级是一种可以避免删除、新建 Pod 的升级镜像能力。它比原生 Deployment/StatefulSet 的重建 Pod 升级更快、更高效,并且避免对 Pod 中其他不需要更新的容器造成干扰。

  • Sidecar 管理

    支持在一个单独的 CR 中定义 sidecar 容器,OpenKruise 能够帮你把这些 Sidecar 容器注入到所有符合条件的 Pod 中。这个过程和 Istio 的注入很相似,但是你可以管理任意你关心的 Sidecar。

  • 跨多可用区部署

    定义一个跨多个可用区的全局 workload,容器,OpenKruise 会帮你在每个可用区创建一个对应的下属 workload。你可以统一管理他们的副本数、版本、甚至针对不同可用区采用不同的发布策略。

CRD 列表

CloneSet
提供更加高效、确定可控的应用管理和部署能力,支持优雅原地升级、指定删除、发布顺序可配置、并行/灰度发布等丰富的策略,可以满足更多样化的应用场景。 Advanced StatefulSet
基于原生 StatefulSet 之上的增强版本,默认行为与原生完全一致,在此之外提供了原地升级、并行发布(最大不可用)、发布暂停等功能。 SidecarSet
对 sidecar 容器做统一管理,在满足 selector 条件的 Pod 中注入指定的 sidecar 容器。 UnitedDeployment
通过多个 subset workload 将应用部署到多个可用区。 BroadcastJob
配置一个 job,在集群中所有满足条件的 Node 上都跑一个 Pod 任务。 Advanced DaemonSet
基于原生 DaemonSet 之上的增强版本,默认行为与原生一致,在此之外提供了灰度分批、按 Node label 选择、暂停、热升级等发布策略。 AdvancedCronJob
一个扩展的 CronJob 控制器,目前 template 模板支持配置使用 Job 或 BroadcastJob。

以上在官方文档都有介绍,本文主要着重实战,先讲CloneSet,其他控制器后面会陆续更新。。。

部署Kruise到Kubernetes集群

这里使用helm来安装Kruise

1、现在kruise Chart

wget https://github.com/openkruise/kruise/releases/download/v0.7.0/kruise-chart.tgz
tar -zxf kruise-chart.tgz
cd kruise
[root@ kruise]# ls -l
total 16
-rw-r--r-- 1 root root 311 Dec 20 15:09 Chart.yaml
-rw-r--r-- 1 root root 4052 Dec 20 15:09 README.md
drwxr-xr-x 2 root root 4096 Dec 23 10:18 templates
-rw-r--r-- 1 root root 659 Dec 20 15:09 values.yaml

2、修改values.yaml,默认不用修改也行

3、执行部署

[root@qd01-stop-k8s-master001 kruise]# kubectl create ns kruise
namespace/kruise created
[root@qd01-stop-k8s-master001 kruise]# helm install kruise -n kruise -f values.yaml .
W1223 10:22:13.562088 1589994 warnings.go:67] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
。。。。。。。
NAME: kruise
LAST DEPLOYED: Wed Dec 23 10:22:12 2020
NAMESPACE: kruise
STATUS: deployed
REVISION: 1
TEST SUITE: None
这里会看到一堆的deprecated信息,因为新版的kubernetes对CRD的版本会淘汰,可以根据自己的集群版本修改CRD的API版本即可

4、检查kruise部署状态

[root@qd01-stop-k8s-master001 kruise]# helm ls -n kruise
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
kruise kruise 1 2020-12-23 10:22:12.963651877 +0800 CST deployed kruise-0.7.0 可以看到,集群中有的kruise crd类型
[root@qd01-stop-k8s-master001 kruise]# kubectl get crd|grep kruise
advancedcronjobs.apps.kruise.io 2020-12-23T02:22:13Z
broadcastjobs.apps.kruise.io 2020-12-23T02:22:13Z
clonesets.apps.kruise.io 2020-12-23T02:22:13Z
daemonsets.apps.kruise.io 2020-12-23T02:22:13Z
sidecarsets.apps.kruise.io 2020-12-23T02:22:13Z
statefulsets.apps.kruise.io 2020-12-23T02:22:13Z
uniteddeployments.apps.kruise.io 2020-12-23T02:22:13Z

下面我们开始来使用这些管理器

CloneSet

CloneSet 控制器提供了高效管理无状态应用的能力,它可以对标原生的 Deployment,但 CloneSet 提供了很多增强功能。

1、我们先创建一个简单的CloneSet,yaml如下

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
labels:
app: nginx-alpine
name: nginx-alpine
spec:
replicas: 5
selector:
matchLabels:
app: nginx-alpine
template:
metadata:
labels:
app: nginx-alpine
spec:
containers:
- name: nginx
image: nginx:alpine

2、部署

[root@qd01-stop-k8s-master001 demo]# kubectl apply -f  CloneSet.yaml
cloneset.apps.kruise.io/nginx-alpine created [root@qd01-stop-k8s-master001 demo]# kubectl get po |grep nginx
nginx-alpine-29g7n 1/1 Running 0 45s
nginx-alpine-bvgqm 1/1 Running 0 45s
nginx-alpine-q9tlw 1/1 Running 0 45s
nginx-alpine-s2t46 1/1 Running 0 44s
nginx-alpine-sslvf 1/1 Running 0 44s
从输出结果看,和原生的Deployment没有啥区别
#注意,这里如果get deployment是看不到nginx-alpine这个应用的,需要get cloneset才能看到
[root@qd01-stop-k8s-master001 demo]# kubectl get deployment
[root@qd01-stop-k8s-master001 demo]# kubectl get cloneset
NAME DESIRED UPDATED UPDATED_READY READY TOTAL AGE
nginx-alpine 5 5 5 5 5 2m16s

CloneSet 允许用户配置 PVC 模板 volumeClaimTemplates,用来给每个 Pod 生成独享的 PVC,这是 Deployment 所不支持的。 如果用户没有指定这个模板,CloneSet 会创建不带 PVC 的 Pod。

3、现在来创建一个带有 PVC 模板的例子

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
labels:
app: nginx-2
name: nginx-2
spec:
replicas: 5
selector:
matchLabels:
app: nginx-2
template:
metadata:
labels:
app: nginx-2
spec:
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: data-vol
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: rbd
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: rbd
resources:
requests:
storage: 2Gi

部署

[root@qd01-stop-k8s-master001 demo]# kubectl apply -f  CloneSet.yaml
cloneset.apps.kruise.io/nginx-2 created
[root@qd01-stop-k8s-master001 demo]# kubectl get pv|grep data-vol
pvc-0fde19f3-ea4b-47e0-81be-a8e43812e47b 2Gi RWO Delete Bound default/data-vol-nginx-2-t55h8 rbd 83s
pvc-72accf10-57a6-4418-a1bc-c64633b84434 2Gi RWO Delete Bound default/data-vol-nginx-2-t49mk rbd 82s
pvc-8fc8b9a5-afe8-446a-9190-08fcee0ec9f6 2Gi RWO Delete Bound default/data-vol-nginx-2-jw2zp rbd 84s
pvc-c9fba396-e357-43e8-9510-616f698da765 2Gi RWO Delete Bound default/data-vol-nginx-2-b5fdd rbd 84s
pvc-e5302eab-a9f2-4a71-a5a3-4cd43205e8a0 2Gi RWO Delete Bound default/data-vol-nginx-2-l54dz rbd 84s
[root@qd01-stop-k8s-master001 demo]# kubectl get po|grep nginx
nginx-2-b5fdd 1/1 Running 0 97s
nginx-2-jw2zp 1/1 Running 0 97s
nginx-2-l54dz 1/1 Running 0 97s
nginx-2-t49mk 1/1 Running 0 96s
nginx-2-t55h8 1/1 Running 0 96s

从部署结果可以看到,每个pod都创建了一个PVC,这个是原生的Deployment不能实现的。

注意:

每个被自动创建的 PVC 会有一个 ownerReference 指向 CloneSet,因此 CloneSet 被删除时,它创建的所有 Pod 和 PVC 都会被删除。
每个被 CloneSet 创建的 Pod 和 PVC,都会带一个 apps.kruise.io/cloneset-instance-id: xxx 的 label。关联的 Pod 和 PVC 会有相同的 instance-id,且它们的名字后缀都是这个 instance-id。
如果一个 Pod 被 CloneSet controller 缩容删除时,这个 Pod 关联的 PVC 都会被一起删掉。
如果一个 Pod 被外部直接调用删除或驱逐时,这个 Pod 关联的 PVC 还都存在;并且 CloneSet controller 发现数量不足重新扩容时,新扩出来的 Pod 会复用原 Pod 的 instance-id 并关联原来的 PVC。
当 Pod 被重建升级时,关联的 PVC 会跟随 Pod 一起被删除、新建。
当 Pod 被原地升级时,关联的 PVC 会持续使用。

4、指定 Pod 缩容

当一个 CloneSet 被缩容时,有时候用户需要指定一些 Pod 来删除。这对于 StatefulSet 或者 Deployment 来说是无法实现的,因为 StatefulSet 要根据序号来删除 Pod,而 Deployment/ReplicaSet 目前只能根据控制器里定义的排序来删除。

CloneSet 允许用户在缩小 replicas 数量的同时,指定想要删除的 Pod 名字。

现在我们来修改上面例子的部署文件,指定删除nginx-2-t55h8这个Pod

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
labels:
app: nginx-2
name: nginx-2
spec:
replicas: 4
scaleStrategy:
podsToDelete:
- nginx-2-t55h8

然后更新yaml文件

[root@qd01-stop-k8s-master001 demo]# kubectl apply -f CloneSet.yaml
cloneset.apps.kruise.io/nginx-2 configured [root@qd01-stop-k8s-master001 demo]# kubectl get po|grep nginx
nginx-2-b5fdd 1/1 Running 0 11m
nginx-2-jw2zp 1/1 Running 0 11m
nginx-2-l54dz 1/1 Running 0 11m
nginx-2-t49mk 1/1 Running 0 11m

现在看输入结果,已经没有nginx-2-t55h8这个Pod了

这个功能很实用,比如某台机器故障了,或者负载太高,你想删除指定的pod。

5、升级功能

CloneSet 提供了和 Advanced StatefulSet 相同的 3 个升级方式,默认为 ReCreate:

ReCreate: 控制器会删除旧 Pod 和它的 PVC,然后用新版本重新创建出来。
InPlaceIfPossible: 控制器会优先尝试原地升级 Pod,如果不行再采用重建升级。目前,只有修改 spec.template.metadata.* 和 spec.template.spec.containers[x].image 这些字段才可以走原地升级。
InPlaceOnly: 控制器只允许采用原地升级。因此,用户只能修改上一条中的限制字段,如果尝试修改其他字段会被 Kruise 拒绝。

现在我们来尝试原地升级Pod功能,把nginx镜像由nginx:alpine 升级为 nginx:latest

首先修改yaml文件,这里只粘贴出文件的修改的部分

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
...
spec:
replicas: 4
updateStrategy:
type: InPlaceIfPossible
inPlaceUpdateStrategy:
gracePeriodSeconds: 10
......
spec:
containers:
- name: nginx
image: nginx

执行升级

[root@qd01-stop-k8s-master001 demo]# kubectl apply -f CloneSet.yaml
cloneset.apps.kruise.io/nginx-2 configured
使用 kubectl describe查看升级过程
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 59m default-scheduler 0/22 nodes are available: 22 pod has unbound immediate PersistentVolumeClaims.
Warning FailedScheduling 59m default-scheduler 0/22 nodes are available: 22 pod has unbound immediate PersistentVolumeClaims.
Warning FailedScheduling 59m default-scheduler 0/22 nodes are available: 22 pod has unbound immediate PersistentVolumeClaims.
Normal Scheduled 59m default-scheduler Successfully assigned default/nginx-2-l54dz to qd01-stop-k8s-node007.ps.easou.com
Normal SuccessfulAttachVolume 59m attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-e5302eab-a9f2-4a71-a5a3-4cd43205e8a0"
Normal Pulling 58m kubelet Pulling image "nginx:alpine"
Normal Pulled 58m kubelet Successfully pulled image "nginx:alpine" in 6.230045975s
Normal Killing 55s kubelet Container nginx definition changed, will be restarted
Normal Pulling 55s kubelet Pulling image "nginx"
Normal Pulled 26s kubelet Successfully pulled image "nginx" in 29.136659264s
Normal Created 23s (x2 over 58m) kubelet Created container nginx
Normal Started 23s (x2 over 58m) kubelet Started container nginx

从输出可以看到,Container nginx definition changed, will be restarted,Pod并没有删除在重建,而是在原来的基础上直接更新了镜像文件,并重启了服务。

原地升级减少了删除重建环节,节省了升级时间和资源调度频率。。。

6、Partition 分批灰度

Partition 的语义是 保留旧版本 Pod 的数量或百分比,默认为 0。这里的 partition 不表示任何 order 序号。

在发布过程中设置了 partition:
如果是数字,控制器会将 (replicas - partition) 数量的 Pod 更新到最新版本。
如果是百分比,控制器会将 (replicas * (100% - partition)) 数量的 Pod 更新到最新版本。

现在我将上面的例子的 image 更新为 nginx:1.19.6-alpine 并且设置 partition=3

kind: CloneSet
metadata:
labels:
app: nginx-2
name: nginx-2
spec:
replicas: 5
updateStrategy:
type: InPlaceIfPossible
inPlaceUpdateStrategy:
gracePeriodSeconds: 10
partition: 3
selector:
matchLabels:
app: nginx-2
template:
metadata:
labels:
app: nginx-2
spec:
containers:
- name: nginx
image: nginx:1.19.6-alpine

查看结果

Status:
Available Replicas: 5
Collision Count: 0
Label Selector: app=nginx-2
Observed Generation: 6
Ready Replicas: 5
Replicas: 5
Update Revision: nginx-2-7b44cb9c8
Updated Ready Replicas: 2
Updated Replicas: 2
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulUpdatePodInPlace 45m cloneset-controller successfully update pod nginx-2-l54dz in-place(revision nginx-2-5879fd9f7)
Normal SuccessfulUpdatePodInPlace 44m cloneset-controller successfully update pod nginx-2-t49mk in-place(revision nginx-2-5879fd9f7)
Normal SuccessfulUpdatePodInPlace 43m cloneset-controller successfully update pod nginx-2-b5fdd in-place(revision nginx-2-5879fd9f7)
Normal SuccessfulUpdatePodInPlace 43m cloneset-controller successfully update pod nginx-2-jw2zp in-place(revision nginx-2-5879fd9f7)
Normal SuccessfulCreate 22m cloneset-controller succeed to create pod nginx-2-zpp8z
Normal SuccessfulUpdatePodInPlace 5m22s cloneset-controller successfully update pod nginx-2-zpp8z in-place(revision nginx-2-7b44cb9c8)
Normal SuccessfulUpdatePodInPlace 4m55s cloneset-controller successfully update pod nginx-2-jw2zp in-place(revision nginx-2-7b44cb9c8) [root@qd01-stop-k8s-master001 demo]# kubectl get pod -L controller-revision-hash
NAME READY STATUS RESTARTS AGE CONTROLLER-REVISION-HASH
nginx-2-b5fdd 1/1 Running 1 99m nginx-2-5879fd9f7
nginx-2-jw2zp 1/1 Running 2 99m nginx-2-7b44cb9c8
nginx-2-l54dz 1/1 Running 1 99m nginx-2-5879fd9f7
nginx-2-t49mk 1/1 Running 1 99m nginx-2-5879fd9f7
nginx-2-zpp8z 1/1 Running 1 19m nginx-2-7b44cb9c8

从输出信息我们可以看到,Update Revision已经更新为nginx-2-7b44cb9c8,而Pod中只有两个Pod升级了。

由于我们设置了 partition=3,控制器只升级了 2 个 Pod。

Partition 分批灰度功能完善了原生的Pod升级方式,使得升级能够进行更灵活,能够进行灰度上线。超赞。。。

7、最后再演示下发布暂停

用户可以通过设置 paused 为 true 暂停发布,不过控制器还是会做 replicas 数量管理:

  • 首先,我们将示例中image改为nginx:1.18.0 并设置副本数为10,修改后更新yaml,运行结果如下:
[root@qd01-stop-k8s-master001 demo]#  kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9: nginx:1.18.0,
nginx-2-b5fdd: nginx:1.18.0,
nginx-2-jw2zp: nginx:1.18.0,
nginx-2-l54dz: nginx:1.18.0,
nginx-2-nknrt: nginx:1.18.0,
nginx-2-rgmsc: nginx:1.18.0,
nginx-2-rpr5z: nginx:1.18.0,
nginx-2-t49mk: nginx:1.18.0,
nginx-2-v2bpx: nginx:1.18.0,
nginx-2-zpp8z: nginx:1.18.0,
  • 现在我们修改yaml文件,将image修改为nginx:alpine 执行更新,运行如下
[root@qd01-stop-k8s-master001 demo]#  kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9: nginx:1.18.0,
nginx-2-b5fdd: nginx:1.18.0,
nginx-2-jw2zp: nginx:1.18.0,
nginx-2-l54dz: nginx:1.18.0,
nginx-2-nknrt: nginx:alpine,
nginx-2-rgmsc: nginx:alpine,
nginx-2-rpr5z: nginx:alpine,
nginx-2-t49mk: nginx:1.18.0,
nginx-2-v2bpx: nginx:alpine,
nginx-2-zpp8z: nginx:1.18.0,
  • 现在看到,有4个pod的image已经更新为nginx:alpine 然后我们再次修改yaml文件,添加paused: true
spec:
replicas: 10
updateStrategy:
paused: true
type: InPlaceIfPossible
inPlaceUpdateStrategy:
gracePeriodSeconds: 10
  • 再次执行apply,更新yaml,再次查看更新进度,发现pod并没有继续更新了,已经暂停升级image了
[root@qd01-stop-k8s-master001 demo]#  kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9: nginx:1.18.0,
nginx-2-b5fdd: nginx:1.18.0,
nginx-2-jw2zp: nginx:1.18.0,
nginx-2-l54dz: nginx:1.18.0,
nginx-2-nknrt: nginx:alpine,
nginx-2-rgmsc: nginx:alpine,
nginx-2-rpr5z: nginx:alpine,
nginx-2-t49mk: nginx:1.18.0,
nginx-2-v2bpx: nginx:alpine,
nginx-2-zpp8z: nginx:1.18.0,
  • 最后把paused: true取消,再次apply yaml文件,升级会继续。。。
[root@qd01-stop-k8s-master001 demo]#  kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9: nginx:alpine,
nginx-2-b5fdd: nginx:alpine,
nginx-2-jw2zp: nginx:alpine,
nginx-2-l54dz: nginx:alpine,
nginx-2-nknrt: nginx:alpine,
nginx-2-rgmsc: nginx:alpine,
nginx-2-rpr5z: nginx:alpine,
nginx-2-t49mk: nginx:alpine,
nginx-2-v2bpx: nginx:alpine,
nginx-2-zpp8z: nginx:alpine,

以上就是整个发布暂停的演示,这个功能好处就是;我们在升级的过程中可以随时中断升级。

除此之外,CloneSet还有很多特性,例如:MaxUnavailable 最大不可用数量、MaxSurge 最大弹性数量、升级顺序、打散策略、生命周期钩子等,鉴于文章篇幅,这些特性不再演示了,有需要的可以查看官方文档。

Kubernetes应用管理器OpenKruise之CloneSet的更多相关文章

  1. Kubernetes学习之路(二十五)之Helm程序包管理器

    目录 1.Helm的概念和架构 2.部署Helm (1)下载helm (2)部署Tiller 3.helm的使用 4.chart 目录结构 5.chart模板 6.定制安装MySQL chart (1 ...

  2. Kubernetes应用管理

    除了容器资源管理和调度,Kubernetes另外一个核心价值是提供了针对不同类型应用管理的API接口集合,这些API集合把针对不同类型应用的管理能力分别到Kubernetes平台中.以Web业务(Lo ...

  3. ASP.NET Core on K8S深入学习(10)K8S包管理器Helm

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 一.关于Helm 1.1 为何需要Helm? 虽然K8S能够很好地组织和编排容 ...

  4. kubernetes-helm程序包管理器(二十)

    helm概述 Helm是Kubernetes的包管理器,Helm 让我们能够像 yum 管理 rpm 包那样安装.部署.升级和删除容器化应用. Helm的核心术语: Chart:一个helm程序包,是 ...

  5. 容器编排系统K8s之包管理器Helm基础使用

    前文我们了解了k8s上的hpa资源的使用,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14293237.html:今天我们来聊一下k8s包管理器helm的相 ...

  6. 第十四章 kubernetes 核心技术-调度器

    一.概述 一个容器平台的主要功能就是为容器分配运行时所需要的计算,存储和网络资源.容器调 度系统负责选择在最合适的主机上启动容器,并且将它们关联起来.它必须能够自动的处 理容器故障并且能够在更多的主机 ...

  7. Sublime Text 3中文乱码解决方法以及安装包管理器方法

    一般出现乱码是因为文本采用了GBK编码格式,Sublime Text默认不支持GBK编码. 安装包管理器 简单安装 使用Ctrl+`快捷键或者通过View->Show Console菜单打开命令 ...

  8. BZOJ 4196: [Noi2015]软件包管理器 [树链剖分 DFS序]

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1352  Solved: 780[Submit][Stat ...

  9. 定时管理器框架-Task.MainForm

    入住博客园4年多了,一直都是看别人的博客,学习别人的知识,为各个默默无私贡献自己技术总结的朋友们顶一个:这几天突然觉得是时候加入该队列中,贡献出自己微弱的力量,努力做到每个月有不同学习总结,知识学习的 ...

随机推荐

  1. 【CF620E】New Year Tree

    (题面来自luogu) 题意翻译 你有一棵以1为根的有根树,有n个点,每个节点初始有一个颜色c[i]. 有两种操作: 1 v c 将以v为根的子树中所有点颜色更改为c 2 v 查询以v为根的子树中的节 ...

  2. LeetCode周赛#208

    本周周赛的题面风格与以往不太一样,但不要被吓着,读懂题意跟着模拟,其实会发现并不会难到哪里去. 1599. 经营摩天轮的最大利润 #模拟 题目链接 题意 摩天轮\(4\)个座舱,每个座舱最多可容纳\( ...

  3. 测试:DOCX

    先拿到的是需求文档和接口文档以及测试用例模块,[以及之前写好的测试用例]再根据分配的任务进行编写用例 [智能看懂业务需求]现有功能点,在编写用例 [项目介绍]: 辽阳农商惠生活项目是作为一个农户和银行 ...

  4. Clickhouse 入门

    clickhouse 简介 ck是一个列式存储的数据库,其针对的场景是OLAP.OLAP的特点是: 数据不经常写,即便写也是批量写.不像OLTP是一条一条写 大多数是读请求 查询并发较少,不适合放置先 ...

  5. TkMybatis 是什么?

    一.TkMybatis Tkmybatis 是基于 Mybatis 框架开发的一个工具,通过调用它提供的方法实现对单表的数据操作,不需要写任何 sql 语句,这极大地提高了项目开发效率. 二.怎么用? ...

  6. 这次我让你彻底弄懂 RESTful

    微信搜 「yes的练级攻略」干货满满,不然来掐我,回复[123]一份20W字的算法刷题笔记等你来领.欢迎分享,转载请保留出处. 本文已收录至 https://github.com/yessimida/ ...

  7. JQuery浮动对象插件

    写了个插件,用来固定表的头部和尾部. /*! * smartFloat v1.0.1 * Copyright 2019- Richard * Licensed under MIT */ $.fn.ex ...

  8. day1(初始化项目结构)

    1.初始化项目结构  └─shiyanlou_project    │  .gitignore    │  README.en.md           # 英文    │  README.md    ...

  9. pom文件中<dependencies>和<dependencyManagement>的区别

    在父pom中,如果使用了<dependencies>标签,那么在该标签体中的所有jar包,即使子工程中没有写这些依赖,依旧会引用. 如果使用了<dependencyManagemen ...

  10. moviepy音视频剪辑VideoClip类fl_image方法及参数image_func的功能介绍

    ☞ ░ 前往老猿Python博文目录 ░ moviepy音视频剪辑模块的视频剪辑基类VideoClip的fl_image方法用于进行对剪辑帧数据进行变换. 调用语法:fl_image(self, im ...