码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 【重识云原生】第四章容器基础6.4.10.5节——Statefulset原理剖析


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

    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 StatefulSet工作原理剖析

    1.1 工作原理简述

            首先,StatefulSet 的控制器直接管理的是 Pod。这是因为,StatefulSet 里的不同 Pod 实例,不再像 ReplicaSet 中那样都是完全一样的,而是有了细微区别的。比如,每个 Pod 的 hostname、名字等都是不同的、携带了编号的。而 StatefulSet 区分这些实例的方式,就是通过在 Pod 的名字里加上事先约定好的编号。

            其次,Kubernetes 通过 Headless Service,为这些有编号的 Pod,在 DNS 服务器中生成带有同样编号的 DNS 记录。只要 StatefulSet 能够保证这些 Pod 名字里的编号不变,那么 Service 里类似于 web-0.nginx.default.svc.cluster.local 这样的 DNS 记录也就不会变,而这条记录解析出来的 Pod 的 IP 地址,则会随着后端 Pod 的删除和再创建而自动更新。这当然是 Service 机制本身的能力,不需要 StatefulSet 操心。

            最后,StatefulSet 还为每一个 Pod 分配并创建一个同样编号的 PVC。这样,Kubernetes 就可以通过 Persistent Volume 机制为这个 PVC 绑定上对应的 PV,从而保证了每一个 Pod 都拥有一个独立的 Volume。在这种情况下,即使 Pod 被删除,它所对应的 PVC 和 PV 依然会保留下来。所以当这个 Pod 被重新创建出来之后,Kubernetes 会为它找到同样编号的 PVC,挂载这个 PVC 对应的 Volume,从而获取到以前保存在 Volume 里的数据。

            从上面内容可以看出,管理有状态应用 Pod 的关键是提供稳定不变的 Pod 标识和稳定不变的存储。

    1.2 拓扑状态实现

    1.2.1 稳定不变的拓扑状态

            StatefulSet 中Pod标识和 Pod是绑定的,不管 Pod 被调度到哪个节点上,每个 Pod 将被分配一个整数序号,从 0 到 N-1,该序号在 StatefulSet 上是唯一的。

            每个 Pod 根据 StatefulSet 的名称和 Pod 的序号派生出它的主机名。组合主机名的格式为 (StatefulSet名称)(序号);例如StatefulSet 名称为 web,replicas 为 3,那么将会创建三个名称分别为 web-0、web-1、web-2 的 Pod。一旦每个 Pod 创建成功,就会得到一个匹配的 DNS 名称,格式为:. ..svc.cluster.local,其中 service-name 由 StatefulSet 的 serviceName 域来设定;并且这些 Pod 的创建,是严格按照编号顺序进行的。比如,在 web-0 进入到 Running 状态、并且 Conditions 成为 Ready 之前,web-1 会一直处于 Pending 状态。

            当我们把这几个 Pod 删除之后,Kubernetes 会按照原先编号的顺序,创建出新的 Pod。并且,Kubernetes 依然为它们分配了与原来相同的“网络身份”;

            通过这种严格的对应规则,StatefulSet 就保证了 Pod 网络标识的稳定性;

    1.2.2 运用Headless Service实现Pod网络标识稳定不变

            通过 Headless Service 的方式,StatefulSet 为每个 Pod 创建了一个固定并且稳定的 DNS 记录,来作为它的访问入口。

    1.2.2.1 Service简介

            Service 类型一般有如下的三种:

    • VIP(Virtual IP,即:虚拟 IP)

            Service提供一个 VIP,我们访问这个IP地址时,它会把请求转发到该 Service 所代理的某一个 Pod 上。

    • DNS (Normal Service)

            这种情况下,访问“my-svc.my-namespace.svc.cluster.local”解析到的,正是 my-svc 这个 Service 的 VIP,后面的流程就跟 VIP 方式一致。

    • DNS (Headless Service)

            这种情况下,访问“my-svc.my-namespace.svc.cluster.local”解析到的,直接就是 my-svc 代理的某一个 Pod 的 IP 地址。所以,Headless Service 不需要分配一个 VIP,而是可以直接以 DNS 记录的方式解析出被代理 Pod 的 IP 地址。

    1.2.2.2 Headless Service

    1.2.2.2.1 案例

            参考如下的demo-service.yaml案例:

    1. apiVersion: v1
    2. kind: Service
    3. metadata:
    4. name: demo-service
    5. labels:
    6. app: nginx
    7. spec:
    8. ports:
    9. - port: 80
    10. name: web
    11. clusterIP: None
    12. selector:
    13. app: demo-nginx

            创建成功后可以查看到如下的内容:

     demo-service

    1.2.2.2.2 clusterIP

            关于于上面的这行配置clusterIP: None。

            clusterIP 是服务的IP地址,通常由主服务器随机分配还具有如下特点:

    • 如果地址是手动指定的,并且未被其他人使用,则该地址将分配给服务;否则,服务创建将失败
    • 无法通过更新更改此字段。
    • 有效值为“ None”,空字符串(“”)或有效IP地址。
    • 当不需要代理时,可以为无头服务指定“无”。
    • 仅适用于ClusterIP,NodePort和LoadBalancer类型。
    • 如果type为ExternalName,则忽略。

            Headless Service 是一个标准 Service 的 YAML 文件。只不过,它的 clusterIP 字段的值是:None。这个 Service 被创建后并不会被分配一个 VIP,而是会以 DNS 记录的方式暴露出它所代理的 Pod。

    1.2.2.2.3 DNS 记录

            当按照这样的方式创建了一个 Headless Service 之后,它所代理的所有 Pod 的 IP 地址,都会被绑定一个这样格式的 DNS 记录,如下所示:

    ...svc.cluster.local

            这个 DNS 记录,正是 Kubernetes 项目为 Pod 分配的唯一的“可解析身份”(Resolvable Identity)。有了这个“可解析身份”,只需要知道了一个 Pod 的名字,以及它对应的 Service 的名字,就可以非常确定地通过这条 DNS 记录访问到 Pod 的 IP 地址。

    1.2.2.3 StatefulSet实现Pod的拓扑状态

           Stateful状态集在创建和扩展的时候有特殊的限制,如果一个有状态集期望的Pod数量是N,那么有StatefulSet会从0开始依次创建这些Pod在第一个Pod正常运行之前是不会创建第二个Pod。在删除Pod的时候,则是从第N个Pod开始反向依次删除。

           StatefulSet的核心功能就是通过某种方式记录这些状态,然后在Pod被重新创建时能够为新Pod恢复这些状态。

           只要知道一个Pod的名字以及它对应的Service的名字,就可以通过这条DNS记录访问到Pod的IP地址(pod的名称.service名称) -> Pod的IP。

           定义Stateful的对象中有一个serviceName字段来告诉Stateful控制器使用具体的service来解析它所管理的Pod的IP地址。

           Pod的名称由StatfulSet对象的名称+Pod创建时所在的索引组成 StatefulSet使用这个DNS记录解析规则来维持Pod的拓扑状态。

           StatefulSet给它所管理的所有Pod的名字进行了编号,编号规则是: - .而且这些编号都是从0开始累加与StatefulSet的每个Pod实例一一对应、绝不重复。

           这些Pod的创建也是严格按照编号顺序进行的,比如,在web-0进入到Running 状态、并且细分状态(Conditions)成为Ready之前,web-1会一直处于Pending状态。

           把这两个Pod删除之后Kubernetes会按照原先编号的顺序,创建出了两个新的 Pod,并且Kubernetes依然为它们分配了与原来相同的“网络身份”:web-0.nginx和 web-1.nginx。

           通过永远不改变Pod名称的方式StatefulSet保证了Pod网络标识的稳定性。不管Pod是被删除重启还是被调度到其他节点上都不会改变Pod的名称。

           StatefulSet管理的pod使用的镜像是一样的,但是每个pod的命令和初始化流程可以完全不一样来实现主从Pod的拓扑部署。

          尽管web-0.nginx这条DNS记录本身不会变但它解析到的Pod的IP地址并不是固定的。这就意味着,对于“有状态应用”实例的访问必须使用DNS记录或者hostname的方式而绝不应该直接访问这些Pod的IP地址。

    1.3 “稳定不变的存储”的实现

    1.3.1 稳定不变的存储概述

    • 每个 Pod 都会绑定一个固定编号的 PVC,这些 PVC 的名字都是 -;
    • 名叫 web-0 的 Pod,会声明使用名叫 www-web-0 的 PVC;
    • PV/PVC 通过动态卷的方式存储于远程存储服务器;
    • 当一个 Pod 被删除后,对应的 PVC 和 PV 并不会被删除,数据依然存在于远程服务器,Pod 被重建后,StatefulSet 会重新查找对应名称的 PVC 来进行绑定;

    1.3.2 StatefulSet实现Pod的存储状态

          通过PVC机制来实现存储状态管理。

          在StatefulSet对象中除了定义PodTemplate还会定义一个volumeClaimTemplates凡是被这个StatefulSet管理的Pod都会声明一个对应的PVC,这个PVC的定义就来自于 volumeClaimTemplates这个模板字段。

            这个PVC的名字,会被分配一个与这个Pod完全一致的编号。

             把一个Pod比如web-0删除之后,这个Pod对应的PVC和PV并不会被删除,而这个Volume 里已经写入的数据,也依然会保存在远程存储服务里。

            StatefulSet在重新创建web-0这个pod的时候.它声明使用的PVC的名字还是叫作:www-web-0 这个PVC的定义,还是来自于PVC模板(volumeClaimTemplates)这是StatefulSet创建 Pod的标准流程。

            Kubernetes为它查找名叫www-web-0的PVC时,就会直接找到旧Pod遗留下来的同名的 PVC进而找到跟这个PVC绑定在一起的PV.这样新的Pod就可以挂载到旧Pod对应的那个Volume并且获取到保存在Volume里的数据.通过这种方式Kubernetes的StatefulSet就实现了对应用存储状态的管理。

            StatefulSet其实就是一种特殊的Deployment,而其独特之处在于,它的每个Pod都被编号了.而且,这个编号会体现在Pod的名字和hostname等标识信息上,这不仅代表了Pod的创建顺序,也是Pod的重要网络标识(即:在整个集群里唯一的、可被的访问身份).有了这个编号后StatefulSet就使用Kubernetes里的两个标准功能:Headless Service 和 PV/PVC,实现了对 Pod 的拓扑状态和存储状态的维护。

    1.4 核心逻辑实现

            StatefulSet的实现机制整体流程相对简明,接下来按照Pod管理、状态计算、状态管理、更新策略这几部分来依次讲解。

    1.4.1 Pod的release与adopt

            statefulSet中的pod的名字都是按照一定规律来进行设置的, 名字本身也有含义, k8s在进行statefulset更新的时候,首先会过滤属于当前statefulset的pod,并做如下操作:

    • K8s中控制器与Pod的关联主要通过两个部分:controllerRef和label, statefulset在进行Pod过滤的时候,如果发现对应的pod的controllerRef都是当前的statefulset但是其label或者名字并不匹配,则就会尝试release对应的Pod
    • 反之如果发现对应Pod的label和名字都匹配,但是controllerRef并不是当前的statefulSet就会更新对应的controllerRef为当前的statefulset, 这个操作被称为adopt。

             通过该流程可以确保当前statefulset关联的Pod要么与当前的对象关联,要么我就释放你,这样可以维护Pod的一致性,即时有人修改了对应的Pod则也会调整成最终一致性。

    1.4.2 副本分类

             在经过第一步的Pod状态的修正之后,statefulset会遍历所有属于自己的Pod,同时将Pod分为两个大类:有效副本和无效副本(condemned),前面提到过Pod的名字也是有序的即有N个副本的Pod则名字依次是{0...N-1}, 这里区分有效和无效也是依据对应的索引顺序,如果超过当前的副本即为无效副本

    1.4.3 单调更新

            单调更新主要是指的当对应的Pod管理策略不是并行管理的时候,只要当前Replicas(有效副本)中任一一个Pod发生创建、终止、未就绪的时候,都会等待对应的Pod就绪,即你要想更新一个statefulset的Pod的时候,对应的Pod必须已经RunningAndReady

    1. func allowsBurst(set *apps.StatefulSet) bool {
    2. return set.Spec.PodManagementPolicy == apps.ParallelPodManagement
    3. }

    1.4.4 基于计数器的滚动更新

             滚动更新的实现相对隐晦一点,其主要是通过控制副本计数来实现,首先倒序检查对应的Pod的版本是否是最新版本,如果发现不是,则直接删除对应的Pod,同时将currentReplica计数减一,这样在检查对应的Pod的时候,就会发现对应的Pod的不存在,就需要为对应的Pod生成新的Pod信息,此时就会使用最新的副本去更新。

    1. func newVersionedStatefulSetPod(currentSet, updateSet *apps.StatefulSet, currentRevision, updateRevision string, ordinal int) *v1.Pod {
    2. // 如果发现当前的Pod的索引小于当的副本计数,则表明当前Pod还没更新到,但实际上可能因为别的原因
    3. // 需要重新生成Pod模板,此时仍然使用旧的副本配置
    4. if currentSet.Spec.UpdateStrategy.Type == apps.RollingUpdateStatefulSetStrategyType &&
    5. (currentSet.Spec.UpdateStrategy.RollingUpdate == nil && ordinal < int(currentSet.Status.CurrentReplicas)) ||
    6. (currentSet.Spec.UpdateStrategy.RollingUpdate != nil && ordinal < int(*currentSet.Spec.UpdateStrategy.RollingUpdate.Partition)) {
    7. pod := newStatefulSetPod(currentSet, ordinal)
    8. setPodRevision(pod, currentRevision)
    9. return pod
    10. }
    11. // 使用新的配置生成新的Pod配置
    12. pod := newStatefulSetPod(updateSet, ordinal)
    13. setPodRevision(pod, updateRevision)
    14. return pod
    15. }

    1.4.5 无效副本的清理

            无效副本的清理应该主要是发生在对应的statefulset缩容的时候,如果发现对应的副本已经被遗弃,就会直接删除,此处默认也需要遵循单调性原则,即每次都只更新一个副本

    1.4.6 基于删除的单调性更新

    1. if getPodRevision(replicas[target]) != updateRevision.Name && !isTerminating(replicas[target]) {
    2. klog.V(2).Infof("StatefulSet %s/%s terminating Pod %s for update", set.Namespace, set.Name, replicas[target].Name)
    3. err := ssc.podControl.DeleteStatefulPod(set, replicas[target])
    4. status.CurrentReplicas--
    5. return &status, err
    6. }

            Pod的版本检测位于对应一致性同步的最后,当代码走到当前位置,则证明当前的statefulSet在满足单调性的情况下,有效副本里面的所有Pod都是RunningAndReady状态了,此时就开始倒序进行版本检查,如果发现版本不一致,就根据当前的partition的数量来决定允许并行更新的数量,在这里删除后,就会触发对应的事件,从而触发下一个调度事件,触发下一轮一致性检查。

    1.4.7 OnDelete策略

    1. if set.Spec.UpdateStrategy.Type == apps.OnDeleteStatefulSetStrategyType {
    2. return &status, nil
    3. }

            StatefulSet的更新策略除了RollingUpdate还有一种即OnDelete即必须人工删除对应的 Pod来触发一致性检查,所以针对那些如果想只更新指定索引的statefulset可以尝试该策略,每次只删除对应的索引,这样只有指定的索引会更新为最新的版本。

    1.4.8 状态存储

            状态存储其实就是我们常说的PVC,在Pod创建和更新的时候,如果发现对应的PVC的不存在则就会根据statefulset里面的配置创建对应的PVC,并更新对应Pod的配置。

    1.5 有状态应用总结

            从核心实现分析中可以看出来,有状态应用的实现,实际上核心是基于一致性状态、单调更新、持久化存储的组合,通过一致性状态、单调性更新,保证期望副本的数量的Pod处于RunningAndReady的状态并且保证有序性,同时通过持久化存储来进行数据的保存。

             有序的重要性,在分布式系统中比较常见的两个设计就是分区和副本,其中副本主要是为了保证可用性,而分区主要是进行数据的平均分布,二者通常都是根据当前集群中的节点来进行分配的,如果我们节点短暂的离线升级,数据保存在对应的PVC中,在恢复后可以很快的进行节点的信息的恢复并重新加入集群,所以后面如果开发这种类似的分布式应用的时候,可以将底层的恢复和管理交给k8s,数据保存在PVC中,则应用更多的只需要关注系统的集群管理和数据分布问题即,这也是云原生带来的改变。

    参考链接

    Statefulset详细解析 - 不懂123 - 博客园

    k8s中statefulset资源类型的深入理解

    十,StatefulSet简介及简单使用 - 戴红领巾的少年 - 博客园

    k8s之StatefulSet详解_最美dee时光的博客-CSDN博客_statefulset

    Kubernetes学习笔记 —— 7. StatefulSet - 知乎

    容器化部署实战(五)|控制器 StatefulSet 的原理

    K8s StatefulSet

    kubernetes——StatefulSet详解

    Kubernetes 深入理解StatefulSet(一):拓扑状态_富士康质检员张全蛋的博客-CSDN博客

    图解kubernetes控制器StatefulSet核心实现原理_8小时的博客-CSDN博客

    详解 Kubernetes StatefulSet 实现原理_cbmljs的博客-CSDN博客_kubectl statefulset

    Kubernetes:StatefulSet剖析

    Kubernetes Deployments vs StatefulSets - Stack Overflow

    StatefulSet: Run and Scale Stateful Applications Easily in Kubernetes | Kubernetes

    Running ZooKeeper, A Distributed System Coordinator | Kubernetes

    StatefulSets | Kubernetes

    StatefulSet · Kubernetes Engine

  • 相关阅读:
    html简单案例
    312页18万字数字化校园总体建设方案
    Spring解析之finishBeanFactoryInitialization即初始化单例bean
    9.4 RetLibc实战之利用VirtualAlloc
    idea2021.2.3安装炫酷插件activate-power-mode失败解决方案
    33. 对 BFC 的理解, 如何创建 BFC?
    CorelDraw插件开发-文字功能-文本分裂-语言-横排重组-窗口函数-Cdr插件开发(一)
    【嵌入式UI框架:LVGL】使用恩智浦GUI设计工具,像Qt一样开发MCU界面
    【Git】在 Raspberry PI 上部署 Gogs
    理解思想:Python多线程和并发编程
  • 原文地址:https://blog.csdn.net/junbaozi/article/details/127577543
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | 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号