码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 【重识云原生】第六章容器6.3.3节——Kube-Scheduler使用篇


      《重识云原生系列》专题索引:

    1. 第一章——不谋全局不足以谋一域
    2. 第二章计算第1节——计算虚拟化技术总述
    3. 第二章计算第2节——主流虚拟化技术之VMare ESXi
    4. 第二章计算第3节——主流虚拟化技术之Xen
    5. 第二章计算第4节——主流虚拟化技术之KVM
    6. 第二章计算第5节——商用云主机方案
    7. 第二章计算第6节——裸金属方案
    8. 第三章云存储第1节——分布式云存储总述
    9. 第三章云存储第2节——SPDK方案综述
    10. 第三章云存储第3节——Ceph统一存储方案
    11. 第三章云存储第4节——OpenStack Swift 对象存储方案
    12. 第三章云存储第5节——商用分布式云存储方案
    13. 第四章云网络第一节——云网络技术发展简述
    14. 第四章云网络4.2节——相关基础知识准备
    15. 第四章云网络4.3节——重要网络协议
    16. 第四章云网络4.3.1节——路由技术简述
    17. 第四章云网络4.3.2节——VLAN技术
    18. 第四章云网络4.3.3节——RIP协议
    19. 第四章云网络4.3.4节——OSPF协议
    20. 第四章云网络4.3.5节——EIGRP协议
    21. 第四章云网络4.3.6节——IS-IS协议
    22. 第四章云网络4.3.7节——BGP协议
    23. 第四章云网络4.3.7.2节——BGP协议概述
    24. 第四章云网络4.3.7.3节——BGP协议实现原理
    25. 第四章云网络4.3.7.4节——高级特性
    26. 第四章云网络4.3.7.5节——实操
    27. 第四章云网络4.3.7.6节——MP-BGP协议
    28. 第四章云网络4.3.8节——策略路由
    29. 第四章云网络4.3.9节——Graceful Restart(平滑重启)技术
    30. 第四章云网络4.3.10节——VXLAN技术
    31. 第四章云网络4.3.10.2节——VXLAN Overlay网络方案设计
    32. 第四章云网络4.3.10.3节——VXLAN隧道机制
    33. 第四章云网络4.3.10.4节——VXLAN报文转发过程
    34. 第四章云网络4.3.10.5节——VXlan组网架构
    35. 第四章云网络4.3.10.6节——VXLAN应用部署方案
    36. 第四章云网络4.4节——Spine-Leaf网络架构
    37. 第四章云网络4.5节——大二层网络
    38. 第四章云网络4.6节——Underlay 和 Overlay概念
    39. 第四章云网络4.7.1节——网络虚拟化与卸载加速技术的演进简述
    40. 第四章云网络4.7.2节——virtio网络半虚拟化简介
    41. 第四章云网络4.7.3节——Vhost-net方案
    42. 第四章云网络4.7.4节vhost-user方案——virtio的DPDK卸载方案
    43. 第四章云网络4.7.5节vDPA方案——virtio的半硬件虚拟化实现
    44. 第四章云网络4.7.6节——virtio-blk存储虚拟化方案
    45. 第四章云网络4.7.8节——SR-IOV方案
    46. 第四章云网络4.7.9节——NFV
    47. 第四章云网络4.8.1节——SDN总述
    48. 第四章云网络4.8.2.1节——OpenFlow概述
    49. 第四章云网络4.8.2.2节——OpenFlow协议详解
    50. 第四章云网络4.8.2.3节——OpenFlow运行机制
    51. 第四章云网络4.8.3.1节——Open vSwitch简介
    52. 第四章云网络4.8.3.2节——Open vSwitch工作原理详解
    53. 第四章云网络4.8.4节——OpenStack与SDN的集成
    54. 第四章云网络4.8.5节——OpenDayLight
    55. 第四章云网络4.8.6节——Dragonflow
    56.  第四章云网络4.9.1节——网络卸载加速技术综述

    57. 第四章云网络4.9.2节——传统网络卸载技术

    58. 第四章云网络4.9.3.1节——DPDK技术综述

    59. 第四章云网络4.9.3.2节——DPDK原理详解

    60. 第四章云网络4.9.4.1节——智能网卡SmartNIC方案综述

    61. 第四章云网络4.9.4.2节——智能网卡实现

    62. 第六章容器6.1.1节——容器综述

    63. 第六章容器6.1.2节——容器安装部署

    64. 第六章容器6.1.3节——Docker常用命令

    65. 第六章容器6.1.4节——Docker核心技术LXC

    66. 第六章容器6.1.5节——Docker核心技术Namespace

    67. 第六章容器6.1.6节—— Docker核心技术Chroot

    68. 第六章容器6.1.7.1节——Docker核心技术cgroups综述

    69. 第六章容器6.1.7.2节——cgroups原理剖析

    70. 第六章容器6.1.7.3节——cgroups数据结构剖析

    71. 第六章容器6.1.7.4节——cgroups使用

    72. 第六章容器6.1.8节——Docker核心技术UnionFS

    73. 第六章容器6.1.9节——Docker镜像技术剖析

    74. 第六章容器6.1.10节——DockerFile解析

    75. 第六章容器6.1.11节——docker-compose容器编排

    76. 第六章容器6.1.12节——Docker网络模型设计

    77. 第六章容器6.2.1节——Kubernetes概述

    78. 第六章容器6.2.2节——K8S架构剖析

    79. 第六章容器6.3.1节——K8S核心组件总述

    80. 第六章容器6.3.2节——API Server组件

    81. 第六章容器6.3.3节——Kube-Scheduler使用篇

    82. 第六章容器6.3.4节——etcd组件

    83. 第六章容器6.3.5节——Controller Manager概述

    84. 第六章容器6.3.6节——kubelet组件

    85. 第六章容器6.3.7节——命令行工具kubectl

    86. 第六章容器6.3.8节——kube-proxy

    87. 第六章容器6.4.1节——K8S资源对象总览

    88. 第六章容器6.4.2.1节——pod详解

    89. 第六章容器6.4.2.2节——Pod使用(上)

    90. 第六章容器6.4.2.3节——Pod使用(下)

    91. 第六章容器6.4.3节——ReplicationController

    92. 第六章容器6.4.4节——ReplicaSet组件

    93. 第六章容器基础6.4.5.1节——Deployment概述

    94. 第六章容器基础6.4.5.2节——Deployment配置详细说明

    95. 第六章容器基础6.4.5.3节——Deployment实现原理解析

    96. 第六章容器基础6.4.6节——Daemonset

    97. 第六章容器基础6.4.7节——Job

    98. 第六章容器基础6.4.8节——CronJob

    1 scheduler

    1.1 scheduler简介

            scheduler是任务调度器,在K8S中实现组件名为kube-scheduler,负责任务调度、选择合适的节点来执行任务。Scheduler 负责决定将 Pod 放在哪个 Node 上运行。Scheduler 在调度时会充分考虑 Cluster 的拓扑结构,当前各个节点的负载,以及应用对高可用、性能、数据亲和性的需求。它监听 kube-apiserver,查询还未分配 Node 的 Pod,然后根据调度策略为这些 Pod 分配节点(更新 Pod 的 NodeName 字段)。

            scheduler通过 kubernetes 的监测(Watch)机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。 scheduler会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。 scheduler会依据下文的调度原则来做出调度选择。

            实际上调度完成之后,scheduler只需更新 Pod 的NodeName字段即可。

    1.2 Scheduler调度策略

    1.2.1 调度器需要充分考虑诸多的因素:

    调度器需要充分考虑诸多的因素:

    • 公平调度
    • 资源高效利用
    • QoS
    • affinity 和 anti-affinity
    • 数据本地化(data locality)
    • 内部负载干扰(inter-workload interference)
    • deadlines

    1.2.2 指定node节点调度

            有三种方式可以指定 Pod 只运行在指定的 Node 节点上:

    1. nodeSelector:只调度到匹配指定 label 的 Node 上
    2. nodeAffinity:功能更丰富的 Node 选择器,比如支持集合操作
    3. podAffinity:调度到满足条件的 Pod 所在的 Node 上

    1.2.3 taints和tolerations

            Taints 和 tolerations 用于保证 Pod 不被调度到不合适的 Node 上,其中 Taint 应用于 Node 上,而 toleration 则应用于 Pod 上。目前支持的 taint 类型:

    1. NoSchedule:新的 Pod 不调度到该 Node 上,不影响正在运行的 Pod
    2. PreferNoSchedule:soft 版的 NoSchedule,尽量不调度到该 Node 上
    3. NoExecute:新的 Pod 不调度到该 Node 上,并且删除(evict)已在运行的 Pod。Pod 可以增加一个时间(tolerationSeconds)

            然而,当 Pod 的 Tolerations 匹配 Node 的所有 Taints 的时候可以调度到该 Node 上;当 Pod 是已经运行的时候,也不会被删除(evicted)。另外对于 NoExecute,如果 Pod 增加了一个 tolerationSeconds,则会在该时间之后才删除 Pod。

    1.2.4 优先级调度

            从 v1.8 开始,kube-scheduler 支持定义 Pod 的优先级,从而保证高优先级的 Pod 优先调度。并从 v1.11 开始默认开启。

            注:在 v1.8-v1.10 版本中的开启方法为apiserver 配置 --feature-gates=PodPriority=true 和 --runtime-config=scheduling.k8s.io/v1alpha1=truekube-scheduler 配置 --feature-gates=PodPriority=true

            在指定 Pod 的优先级之前需要先定义一个 PriorityClass(非 namespace 资源),如

    1. apiVersion: v1
    2. kind: PriorityClass
    3. metadata:
    4. name: high-priority
    5. value: 1000000
    6. globalDefault: false
    7. description: "This priority class should be used for XYZ service pods only."

    其中

    • value 为 32 位整数的优先级,该值越大,优先级越高
    • globalDefault 用于未配置 PriorityClassName 的 Pod,整个集群中应该只有一个 PriorityClass 将其设置为 true

            然后,在 PodSpec 中通过 PriorityClassName 设置 Pod 的优先级:

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: nginx
    5. labels:
    6. env: test
    7. spec:
    8. containers:
    9. - name: nginx
    10. image: nginx
    11. imagePullPolicy: IfNotPresent
    12. priorityClassName: high-priority

    1.2.5 多调度器

            如果默认的调度器不满足要求,还可以部署自定义的调度器。并且,在整个集群中还可以同时运行多个调度器实例,通过 podSpec.schedulerName 来选择使用哪一个调度器(默认使用内置的调度器)。

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: nginx
    5. labels:
    6. app: nginx
    7. spec:
    8. # 选择使用自定义调度器 my-scheduler
    9. schedulerName: my-scheduler
    10. containers:
    11. - name: nginx
    12. image: nginx:1.10

    1.2.6 调度器扩展

            kube-scheduler 还支持使用 --policy-config-file 指定一个调度策略文件来自定义调度策略,比如:

    1. {
    2. "kind" : "Policy",
    3. "apiVersion" : "v1",
    4. "predicates" : [
    5. {"name" : "PodFitsHostPorts"},
    6. {"name" : "PodFitsResources"},
    7. {"name" : "NoDiskConflict"},
    8. {"name" : "MatchNodeSelector"},
    9. {"name" : "HostName"}
    10. ],
    11. "priorities" : [
    12. {"name" : "LeastRequestedPriority", "weight" : 1},
    13. {"name" : "BalancedResourceAllocation", "weight" : 1},
    14. {"name" : "ServiceSpreadingPriority", "weight" : 1},
    15. {"name" : "EqualPriority", "weight" : 1}
    16. ],
    17. "extenders":[
    18. {
    19. "urlPrefix": "http://127.0.0.1:12346/scheduler",
    20. "apiVersion": "v1beta1",
    21. "filterVerb": "filter",
    22. "prioritizeVerb": "prioritize",
    23. "weight": 5,
    24. "enableHttps": false,
    25. "nodeCacheCapable": false
    26. }
    27. ]
    28. }

    1.2.7 其他影响调度的因素

    • 如果 Node Condition 处于 MemoryPressure,则所有 BestEffort 的新 Pod(未指定 resources limits 和 requests)不会调度到该 Node 上
    • 如果 Node Condition 处于 DiskPressure,则所有新 Pod 都不会调度到该 Node 上
    • 为了保证 Critical Pods 的正常运行,当它们处于异常状态时会自动重新调度。Critical Pods 是指
      • annotation 包括 scheduler.alpha.kubernetes.io/critical-pod=''
      • tolerations 包括 [{"key":"CriticalAddonsOnly", "operator":"Exists"}]
      • priorityClass 为 system-cluster-critical 或者 system-node-critical

    1.3 启动 kube-scheduler 示例

    kube-scheduler --address=127.0.0.1 --leader-elect=true --kubeconfig=/etc/kubernetes/scheduler.conf

    2 scheduler工作原理

    2.1 scheduler工作流程

            scheduler工作流程基本上如下:

    • scheduler维护待调度的podQueue并监听APIServer。
    • 创建Pod时,我们首先通过APIServer将Pod元数据写入etcd。
    • scheduler通过Informer监听Pod状态。添加新的Pod时,会将Pod添加到podQueue。
    • 主程序不断从podQueue中提取Pods并按照一定的算法将节点分配给Pods。
    • 节点上的kubelet也侦听ApiServer。如果发现有新的Pod已调度到该节点,则将通过CRI调用高级容器运行时来运行容器。
    • 如果scheduler无法调度Pod,则如果启用了优先级和抢占功能,则首先进行抢占尝试,删除节点上具有低优先级的Pod,然后将要调度的Pod调度到该节点。如果未启用抢占或抢占尝试失败,则相关信息将记录在日志中,并且Pod将添加到podQueue的末尾。

    2.2 Pod调度选择原理

            具体scheduler 给一个 pod 做调度选择包含两个步骤:

    1. 过滤(预选)阶段,过滤阶段会将所有满足 Pod 调度需求的 Node 选出来。 例如,PodFitsResources 过滤函数会检查候选 Node 的可用资源能否满足 Pod 的资源请求。 在过滤之后,得出一个 Node 列表,里面包含了所有可调度节点;通常情况下, 这个 Node 列表包含不止一个 Node。如果这个列表是空的,代表这个 Pod 不可调度。
    2. 打分(优选)阶段,在打分阶段,scheduler会为 Pod 从所有可调度节点中选取一个最合适的 Node。 根据当前启用的打分规则,scheduler会给每一个可调度节点进行打分。
    3. 最后,scheduler 会将 Pod 调度到得分最高的 Node 上。 如果存在多个得分最高的 Node,scheduler 会从中随机选取一个。

    2.2.1 预选策略(Predicates)

    • PodFitsHostPorts:检查Pod容器所需的HostPort是否已被节点上其它容器或服务占用。若是已被占用,则禁止Pod调度到该节点。
    • PodFitsHost:检查Pod指定的NodeName是否匹配当前节点。
    • PodFitsResources:检查节点是否有足够空闲资源(例如CPU和内存)来知足Pod的要求。
    • PodMatchNodeSelector:检查Pod的节点选择器(nodeSelector)是否与节点(Node)的标签匹配
    • NoVolumeZoneConflict:对于给定的某块区域,判断若是在此区域的节点上部署Pod是否存在卷冲突。
    • NoDiskConflict:根据节点请求的卷和已经挂载的卷,评估Pod是否适合该节点。
    • MaxCSIVolumeCount:决定应该附加多少CSI卷,以及该卷是否超过配置的限制。
    • CheckNodeMemoryPressure:若是节点报告内存压力,而且没有配置异常,那么将不会往那里调度Pod。
    • CheckNodePIDPressure:若是节点报告进程id稀缺,而且没有配置异常,那么将不会往那里调度Pod。
    • CheckNodeDiskPressure:若是节点报告存储压力(文件系统已满或接近满),而且没有配置异常,那么将不会往那里调度Pod。
    • CheckNodeCondition:节点能够报告它们有一个彻底完整的文件系统,然而网络不可用,或者kubelet没有准备好运行Pods。若是为节点设置了这样的条件,而且没有配置异常,那么将不会往那里调度Pod。
    • PodToleratesNodeTaints:检查Pod的容忍度是否能容忍节点的污点。
    • CheckVolumeBinding:评估Pod是否适合它所请求的容量。这适用于约束和非约束PVC。

            若是在predicates(预选)过程当中没有合适的节点,那么Pod会一直在pending状态,不断重试调度,直到有节点知足条件。

            通过这个步骤,若是有多个节点知足条件,就继续priorities过程,最后按照优先级大小对节点排序。

    2.2.2 优选策略(Priorities,即打分策略)

    • SelectorSpreadPriority:对于属于同一服务、有状态集或副本集(Service,StatefulSet or ReplicaSet)的Pods,会将Pods尽可能分散到不一样主机上。
    • InterPodAffinityPriority:策略有podAffinity和podAntiAffinity两种配置方式。简单来讲,就说根据Node上运行的Pod的Label来进行调度匹配的规则,匹配的表达式有:In, NotIn, Exists, DoesNotExist,经过该策略,能够更灵活地对Pod进行调度。
    • LeastRequestedPriority:偏向使用较少请求资源的节点。换句话说,放置在节点上的Pod越多,这些Pod使用的资源越多,此策略给出的排名就越低。
    • MostRequestedPriority:偏向具备最多请求资源的节点。这个策略将把计划的Pods放到整个工做负载集所需的最小节点上运行。
    • RequestedToCapacityRatioPriority:使用默认的资源评分函数模型建立基于ResourceAllocationPriority的requestedToCapacity。
    • BalancedResourceAllocation:偏向具备平衡资源使用的节点。
    • NodePreferAvoidPodsPriority:根据节点注释scheduler.alpha.kubernet .io/preferAvoidPods为节点划分优先级。可使用它来示意两个不一样的Pod不该在同一Node上运行。
    • NodeAffinityPriority:根据preferredduringschedulingignoredingexecution中所示的节点关联调度偏好来对节点排序。
    • TaintTolerationPriority:根据节点上没法忍受的污点数量,为全部节点准备优先级列表。此策略将考虑该列表调整节点的排名。
    • ImageLocalityPriority:偏向已经拥有本地缓存Pod容器镜像的节点。
    • ServiceSpreadingPriority:对于给定的服务,此策略旨在确保Service的Pods运行在不一样的节点上。总的结果是,Service对单个节点故障变得更有弹性。
    • EqualPriority:赋予全部节点相同的权值1。
    • EvenPodsSpreadPriority:实现择优 pod的拓扑扩展约束

            代码入口路径在release-1.9及之前的代码入口在plugin/cmd/kube-scheduler,从release-1.10起,kube-scheduler的核心代码迁移到pkg/scheduler目录下面,入口也迁移到cmd/kube-scheduler

    2.3 如何扩展scheduler?

            在真实的生产环境中,Kube-scheduler 可能不能满足我们的需求,我们需要扩展其功能。一般来说有以下4种扩展方式:

    • clone 官方 kube-schedule,然后对其进行代码级更改,这种方式有一定的局限性,比如你使用的是托管k8s集群,我们压根无法替换默认的调度器。此外,kubernetes 社区更新迭代比较快,每年会发4个正式版本,我们需要不断地merge上游的代码。
    • 实现一个新的调度器,配置 pod.spec.schedulerName 来选择使用哪一个调度器。由于两个调度器并行运行,非常有可能出现资源冲突的问题。
    • Scheduler extender。侵入性比较小,可以独立于原生 Scheduler 运行,并且无需修改原生 Scheduler 的代码,只需要在运行原生 Scheduler 的时候加一个配置即可。但是该方式也有一些劣势,比如scheduler extender 和默认调度器之间有一些通信成本,扩展点有限,scheduler extender 和默认调度器无法共享cache。
    • Scheduler Framework 。Scheduler Framework 是 Kubernetes Scheduler 的一种可插入架构,可以简化调度器的自定义。 它向现有的调度器增加了一组新的“插件” API。插件被编译到scheduler程序中。 这些 API 允许大多数调度功能以插件的形式实现,同时使调度“核心”保持简单且可维护。

            发展至今,Scheduler Framework 是最佳的扩展方案。

    2.3.1 Scheduler Framework

            Scheduler Framework定义了一些扩展点。调度器插件注册后在一个或多个扩展点处被调用。 这些插件中的一些可以改变调度决策,而另一些仅用于提供信息。

    2.3.1.1 工作流程

            每次调度一个 Pod 的尝试都分为两个阶段,即 调度周期 和 绑定周期。

            调度周期为 Pod 选择一个节点,绑定周期将该决策应用于集群。 调度周期和绑定周期一起被称为“调度上下文”。

            调度周期是串行运行的,而绑定周期可能是同时运行的。

    2.3.1.2 扩展点

            如上图所示,我们简单介绍一下支持的扩展点:

    • QueueSort: 对队列中的 Pod 进行排序
    • PreFilter: 预处理 Pod 的相关信息,或者检查集群或 Pod 必须满足的某些条件。 如果 PreFilter 插件返回错误,则调度周期将终止。
    • Filter: 过滤出不能运行该 Pod 的节点。对于每个节点, 调度器将按照其配置顺序调用这些过滤插件。如果任何过滤插件将节点标记为不可行, 则不会为该节点调用剩下的过滤插件。节点可以被同时进行评估。
    • PostFilter: 在筛选阶段后调用,但仅在该 Pod 没有可行的节点时调用。 插件按其配置的顺序调用。如果任何后过滤器插件标记节点为“可调度”, 则其余的插件不会调用。典型的后筛选实现是抢占,试图通过抢占其他 Pod 的资源使该 Pod 可以调度。
    • PreScore: 运行评分任务以生成可评分插件的共享状态
    • Score: 通过调用每个评分插件对过滤的节点进行排名
    • NormalizeScore: 结合分数并计算节点的最终排名
    • Reserve: 在绑定周期之前选择保留的节点
    • Permit: 批准或拒绝调度周期的结果
    • PreBind: 用于执行 Pod 绑定前所需的任何工作。例如,一个预绑定插件可能需要提供网络卷并且在允许 Pod 运行在该节点之前 将其挂载到目标节点上。
    • Bind: 用于将 Pod 绑定到节点上。直到所有的 PreBind 插件都完成,Bind 插件才会被调用。
    • PostBind: 这是个信息性的扩展点。 绑定后插件在 Pod 成功绑定后被调用。这是绑定周期的结尾,可用于清理相关的资源。

    2.3.1.3 Plugin API

            插件 API 分为两个步骤。首先,插件必须完成注册并配置,然后才能使用扩展点接口。 扩展点接口具有以下形式。

    1. type Plugin interface {
    2. Name() string
    3. }
    4. type QueueSortPlugin interface {
    5. Plugin Less(*v1.pod, *v1.pod) bool
    6. }
    7. type PreFilterPlugin interface {
    8. Plugin
    9. PreFilter(context.Context, *framework.CycleState, *v1.pod) error
    10. }

            你可以在调度器配置中启用或禁用插件。 如果你在使用 Kubernetes v1.18 或更高版本,大部分调度插件都在使用中且默认启用。

    参考链接

    一文看懂 kube-scheduler - 知乎

    k8s基础介绍(详细)_南柯一梦,笑谈浮生的博客-CSDN博客_k8s基础

    kube-scheduler · Kubernetes指南

    kube-scheduler概念与工作流程 - Cylon - 博客园

    深度好文:我花了10个小时,写出了这篇K8S架构解析

    Kubernetes K8S之调度器kube-scheduler详解 - 踏歌行666 - 博客园

    Kubernetes调度器-Kube Scheduler – 邹坤个人博客

  • 相关阅读:
    【建议背诵】软考高项考试案例简答题汇总~(5)
    jvm中提前进入老年代
    Apache文件管理自学笔记——映射文件夹和基于单ip多域名配置apache虚拟机
    对拍系列 v1.0
    【电子通识】PE和SQE是什么职位
    Docker学习——容器
    Hadoop3:MapReduce源码解读之Map阶段的数据输入过程整体概览(0)
    spring security OAuth2 实战
    Warmup小记
    攻防世界-web-Training-WWW-Robots
  • 原文地址:https://blog.csdn.net/junbaozi/article/details/126878490
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号