• K8S的控制器Deployment,ReplicaSet,StatefulSet,CronJob,最小单位pod


    K8S的控制器

    Deployment:无状态控制器,主要可以创建无状态的服务,比如说nginx,Apache等这些不用创建主从、主主等状态的pod,还支持滚动升级,回滚等高级功能,默认创建pod的控制器。表现形式一般就是yml文件的kind: Deployment

    ReplicaSet:ReplicaSet 是通过一组字段来定义的,包括一个用来识别可获得的 Pod 的集合的选择算符、一个用来标明应该维护的副本个数的数值、一个用来指定应该创建新 Pod 以满足副本个数条件时要使用的 Pod 模板等等。 每个 ReplicaSet 都通过根据需要创建和删除 Pod 以使得副本个数达到期望值, 进而实现其存在价值。当 ReplicaSet 需要创建新的 Pod 时,会使用所提供的 Pod 模板。

    StatefulSet:有状态控制器,主要是为了创建有状态的服务,比如说mysql,redis等这些需要验证主从关系、复制关系等有状态的pod。表现形式一般就是yml文件的kind: StatefulSet

    DeamonSet:在全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。主要用于收集每个节点的日志信息。

    Job:Job 会创建一个或者多个 Pod,并将继续重试 Pod 的执行,直到指定数量的 Pod 成功终止。 随着 Pod 成功结束,Job 跟踪记录成功完成的 Pod 个数。 当数量达到指定的成功个数阈值时,任务(即 Job)结束。 删除 Job 的操作会清除所创建的全部 Pod。 挂起 Job 的操作会删除 Job 的所有活跃 Pod,直到 Job 被再次恢复执行。

    CronJob:一个 CronJob 对象就像 crontab (cron table) 文件中的一行。 它用 Cron 格式进行编写, 并周期性地在给定的调度时间执行 Job。

    搭建K8S文档:yum安装K8S
    ansible搭建K8S集群:ansible搭建K8S
    准备至少3个机器搭建好K8S集群测试调度

    节点名称IP
    nfs-server192.168.116.130
    k8s-master192.168.116.131
    k8s-node1192.168.116.132
    k8s-node2192.168.116.133

    1、Deploymen控制器(常用pod控制器)

    官网:deployment

    Deployment主要作用:

    • 创建 Deployment 以将 ReplicaSet 上线。ReplicaSet 在后台创建 Pod。 检查 ReplicaSet
      的上线状态,查看其是否成功。
    • 通过更新 Deployment 的 PodTemplateSpec,声明 Pod 的新状态 。 新的 ReplicaSet
      会被创建,Deployment 以受控速率将 Pod 从旧 ReplicaSet 迁移到新 ReplicaSet。 每个新的
      ReplicaSet 都会更新 Deployment 的修订版本。
    • 如果 Deployment 的当前状态不稳定,回滚到较早的 Deployment 版本。 每次回滚都会更新 Deployment
      的修订版本。
    • 扩大 Deployment 规模以承担更多负载。
    • 暂停 Deployment 以应用对 PodTemplateSpec 所作的多项修改, 然后恢复其执行以启动新的上线版本。
    • 使用 Deployment 状态来判定上线过程是否出现停滞。
    • 清理较旧的不再需要的 ReplicaSet 。

    Deploymen创建pod

    vi nginx.yml
    
    apiVersion: apps/v1
    kind: Deployment          #指定控制器的类型
    metadata:
      labels:
        app: nginx
      name: nginx-deployment  #指定控制器的名称
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.23.2
    
    kubectl apply -f Deploymen.yml  创建pod
    kubectl get pod -n default   查看pod
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    2、ReplicaSet控制器(实现pod数量控制)

    官网文档:ReplicaSet

    ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。 然而,Deployment 是一个更高级的概念,它管理 ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。 因此,我们建议使用 Deployment 而不是直接使用 ReplicaSet, 除非你需要自定义更新业务流程或根本不需要更新。这实际上意味着,你可能永远不需要操作 ReplicaSet 对象:而是使用 Deployment,并在 spec 部分定义你的应用。

    vi ReplicaSet.yml
    
    apiVersion: apps/v1
    kind: ReplicaSet     #指定控制器的类型
    metadata:
      name: frontend     #指定控制器的名称
      labels:
        app: guestbook
        tier: frontend
    spec:
      #实际作用就是下面这个控制pod的数量
      replicas: 3
      selector:
        matchLabels:
          tier: frontend
      template:
        metadata:
          labels:
            tier: frontend
        spec:
          containers:
          - name: nginx
            image: nginx:1.23.2
    
    kubectl apply -f ReplicaSet.yml
    kubectl get pod -n default 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    3、StatefulSet控制器(有状态服务控制器)

    官网文档:StatefulSet
    StatefulSet 是用来管理有状态应用的工作负载 API 对象。
    StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。和 Deployment 类似, StatefulSet 管理基于相同容器规约的一组 Pod。但和 Deployment 不同的是, StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID。这些 Pod 是基于相同的规约来创建的, 但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。

    StatefulSet 对于需要满足以下一个或多个需求的应用程序很有价值:

    • 稳定的、唯一的网络标识符。
    • 稳定的、持久的存储。
    • 有序的、优雅的部署和扩缩。
    • 有序的、自动的滚动更新。

    在上面描述中,“稳定的”意味着 Pod 调度或重调度的整个过程是有持久性的。 如果应用程序不需要任何稳定的标识符或有序的部署、删除或扩缩, 则应该使用由一组无状态的副本控制器提供的工作负载来部署应用程序,比如 Deployment 或者 ReplicaSet 可能更适用于你的无状态应用部署需要。

    StatefulSet搭建redis有状态pod
    选一台设备当做NFS服务,创建目录挂载

    yum install -y nfs-utils   安装NFS
    
    创建2个目录
    mkdir /data/redis0 -p
    mkdir /data/redis1 -p
    
    vi /etc/exports  配置挂载
    
    /data/redis0 *(rw,no_root_squash)
    /data/redis1 *(rw,no_root_squash)
    
    
    systemctl restart nfs-server
    systemctl enable nfs-server
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.1 master创建pv存储池

    pv介绍文档:k8s-存储池
    master创建pv

    yum install -y nfs-utils   安装NFS插件,master和node都要安装
    showmount -e 192.168.116.130  确保每台设备都有限制挂载目录
    
    
    mkdir redis   创建文件夹保存yml文件
    cd redis
    vi redis-pv.yml       创建pv
    
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: redis-pv-0
      namespace: default
    spec:
      capacity:
        storage: 10Gi
      accessModes:
        - ReadWriteOnce
      nfs:
        server: 192.168.116.130
        path: /data/redis0
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: redis-pv-1
      namespace: default
    spec:
      capacity:
        storage: 10Gi
      accessModes:
        - ReadWriteOnce
      nfs:
        server: 192.168.116.130
        path: /data/redis1
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    在这里插入图片描述

    3.2 master创建configmap保存配置文件

    vi redis-configmap.yml
    
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: redis-configmap #定义configmap名字
      namespace: default   #pod和configmap要在同一个名称空间中
      labels:
        app: redis-configmap
    data:
      redis.conf: |
        bind 0.0.0.0
        protected-mode yes
        port 6379
        tcp-backlog 511
        timeout 0
        tcp-keepalive 300
        daemonize no
        supervised no
        pidfile /var/run/redis.pid
        loglevel notice
        logfile "/data/redis.log"
        databases 16
        always-show-logo yes
        save 900 1
        save 300 10
        save 60 10000
        stop-writes-on-bgsave-error no
        rdbcompression yes
        rdbchecksum yes
        dbfilename dump.rdb
        dir /data
        slave-serve-stale-data yes
        slave-read-only yes
        repl-diskless-sync no
        repl-diskless-sync-delay 5
        repl-disable-tcp-nodelay no
        slave-priority 100
        lazyfree-lazy-eviction no
        lazyfree-lazy-expire no
        lazyfree-lazy-server-del no
        slave-lazy-flush no
        appendonly yes
        appendfilename "appendonly.aof"
        appendfsync everysec
        no-appendfsync-on-rewrite no
        auto-aof-rewrite-percentage 100
        auto-aof-rewrite-min-size 64mb
        aof-load-truncated yes
        aof-use-rdb-preamble no
        lua-time-limit 5000
        slowlog-log-slower-than 10000
        slowlog-max-len 128
        latency-monitor-threshold 0
        notify-keyspace-events ""
        hash-max-ziplist-entries 512
        hash-max-ziplist-value 64
        list-max-ziplist-size -2
        list-compress-depth 0
        set-max-intset-entries 512
        zset-max-ziplist-entries 128
        zset-max-ziplist-value 64
        hll-sparse-max-bytes 3000
        activerehashing yes
        client-output-buffer-limit normal 0 0 0
        client-output-buffer-limit slave 256mb 64mb 60
        client-output-buffer-limit pubsub 32mb 8mb 60
        hz 10
        aof-rewrite-incremental-fsync yes
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    3.3 master创建secret保存redis密码

    echo -n "admin" |base64   密码转换为base64
    
    vi redis-secret.yml
    
    apiVersion: v1
    kind: Secret
    metadata:
      name: redis-secret
    type: Opaque
    data:
      pass: YWRtaW4K   #定义键值对
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.4 master创建service

    vi redis-service.yml
    
    apiVersion: v1       #创建Headless Service
    kind: Service
    metadata:
      name: redis-svc
      labels:
        app: redis-svc
    spec:
      selector:
        app: redis    #绑定pod的spec.selector.matchLabels.app: redis
      ports:
      - name: redis-service  #绑定pod的ports
        port: 6379
      clusterIP: None
    ---
    apiVersion: v1   #创建对外端口
    kind: Service
    metadata:
      name: redis-access-svc
      labels:
        app: redis-access-svc
    spec:
      type: NodePort
      selector:
        app: redis
      ports:
      - name: redis-nodeport
        port: 6379
        targetPort: 6379
        nodePort: 30079   #注意K8S开放的端口范围
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    3.5 master通过StatefulSet创建pod

    vi redis-StatefulSet.yml
    
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: redis
    spec:
      selector:
        matchLabels:
          app: redis
      serviceName: "redis-svc"  #绑定Headless Service名字
      replicas: 2               #创建2个,制作主从
      template:
        metadata:
          labels:
            app: redis
        spec:
          containers:
          - name: redis
            image: redis:4.0.6
            env:
              - name: redispass  #实际镜像使用就是这个变量名字
                valueFrom:
                  secretKeyRef:
                    name: redis-secret  #绑定上面创建的secret名字
                    key: pass           #绑定key
            resources:
              limits:
                cpu: 500m
                memory: 1Gi
              requests:
                cpu: 500m
                memory: 1Gi
            ports:
            - containerPort: 6379
              protocol: TCP
              name: redis-service    #对应创建的service名称
            - containerPort: 6379
              protocol: TCP
              name: redis-nodeport
            command:
            - bash
            - "-c"
            - |
              set -ex
              [[ `hostname` =~ -([0-9]+)$ ]]
              ordinal=${BASH_REMATCH[1]}
              #通过hostname制作主从文件
              if [[ $ordinal -eq 0 ]]; then
                mkdir /data/etc -p
                cp /etc/redis/redis.conf /data/etc/redis.conf
                echo "requirepass ${redispass}" >>/data/etc/redis.conf
                redis-server /data/etc/redis.conf
              else
                mkdir /data/etc -p
                cp /etc/redis/redis.conf /data/etc/redis.conf
                echo "masterauth ${redispass}" >>/data/etc/redis.conf
                echo "slaveof redis-0.redis-svc 6379" >>/data/etc/redis.conf
                redis-server /data/etc/redis.conf
              fi
            volumeMounts:
            - name: conf
              mountPath: "/etc/redis"
            - name: data
              mountPath: /data
          volumes:
          - name: conf               #对应上面的volumeMounts的conf
            configMap:
              name: redis-configmap  #指定名字,绑定上面创建的configmap
      volumeClaimTemplates:          #动态选择pv存储池
      - metadata:
          name: data                 #对应上面volumeMounts的data
        spec:
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 10Gi
              
    kubectl apply -f .   将当前目录下的yml文件创建
    kubectl get pvc -A   查看pvc和pv绑定
    kubectl get svc -A   查看service
    kubectl get pod -A   查看pod
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    在这里插入图片描述

    3.6 测试redis主从

    连接主redis

    kubectl exec -it redis-0 /bin/bash 连接主pod
    
    redis-cli -a admin   连接redis
    set a1 aa            设置键值对
    info                 查看主从状态
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    在这里插入图片描述
    连接从redis

    kubectl exec -it redis-1 /bin/bash   连接从pod
    redis-cli -a admin
    get a1                            可以看到a1的值可以获取到,证明主从成功
    info                              查看主从状态
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    在这里插入图片描述

    在NFS服务器连接redis

    ll /data/redis0/    查看redis文件
    ll /data/redis1/
    
    • 1
    • 2

    在这里插入图片描述

    4、DaemonSet控制器(主要用于每个节点创建守护pod进程)

    官网文档:DaemonSet

    DaemonSet 的一些典型用法:

    • 在每个节点上运行集群守护进程
    • 在每个节点上运行日志收集守护进程
    • 在每个节点上运行监控守护进程

    一种简单的用法是为每种类型的守护进程在所有的节点上都启动一个 DaemonSet。 一个稍微复杂的用法是为同一种守护进程部署多个 DaemonSet;每个具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求。

    通过elk搭建日志监控集群文档:真机搭建elk

    通过DaemonSet创建pod

    vi DaemonSet.yml     用DaemonSet创建pod时,k8s的每个节点都会创建一个pod
    
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: filebeat
      namespace: default
      labels:
        k8s-app: filebeat
    spec:
      selector:
        matchLabels:
          name: filebeat
      template:
        metadata:
          labels:
            name: filebeat
        spec:
          containers:
          - name: filebeat
            image: docker.elastic.co/beats/filebeat:8.4.3
    
    kubectl apply -f DaemonSet.yml 
    kubectl get pod -n default -o wide
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    5、Job控制器(一次性任务控制器)

    官网文档:Job

    Job 会创建一个或者多个 Pod,并将继续重试 Pod 的执行,直到指定数量的 Pod 成功终止。 随着 Pod 成功结束,Job 跟踪记录成功完成的 Pod 个数。 当数量达到指定的成功个数阈值时,任务(即 Job)结束。 删除 Job 的操作会清除所创建的全部 Pod。 挂起 Job 的操作会删除 Job 的所有活跃 Pod,直到 Job 被再次恢复执行。

    用job控制器创建一个任务

    vi job.yml
    
    apiVersion: batch/v1
    kind: Job
    metadata:
      name: pi
    spec:
      template:
        spec:
          containers:
          - name: pi
            image: perl:5.34.0
            command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
          restartPolicy: Never
      backoffLimit: 4
    
    创建任务,计算 π 到小数点后 2000 位
    kubectl apply -f job.yml 
    kubectl logs -f pi-kt7fn     在日志可以看到计算完成的信息
    kubectl get pod -n default   当STATUS为Completed时,证明任务完成,可以查看完结果删除
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    6、CronJob控制器(定时任务控制器)

    官网文档:CronJob

    CronJob 用于执行周期性的动作,例如备份、报告生成等。 这些任务中的每一个都应该配置为周期性重复的(例如:每天/每周/每月一次); 你可以定义任务开始执行的时间间隔。

    注意:

    • 所有 CronJob 的 schedule: 时间都是基于 kube-controller-manager. 的时区。
    • 如果你的控制平面在 Pod 或是裸容器中运行了 kube-controller-manager, 那么为该容器所设置的时区将会决定
      Cron Job 的控制器所使用的时区。
    • Kubernetes 项目官方并不支持设置如 CRON_TZ 或者 TZ 等变量。 CRON_TZ 或者 TZ 是用于解析和计算下一个
      Job 创建时间所使用的内部库中一个实现细节。 不建议在生产集群中使用它。

    CronJob控制器实际就是创建当任务触发时,通过job控制器生成一个pod进行操作,默认会保留最近3个pod。
    用CronJob控制器创建pod

    vi CronJob.yml
    
    #apiVersion: batch/v1   当k8s版本为1.21时,用这个api
    apiVersion: batch/v1beta1 #当k8s版本小于1.21时,用这个api
    kind: CronJob
    metadata:
      name: hello
    spec:
      schedule: "* * * * *"
      jobTemplate:
        spec:
          template:
            spec:
              containers:
              - name: hello
                image: busybox:1.28
                imagePullPolicy: IfNotPresent
                command:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
              restartPolicy: OnFailure
    
    kubectl apply -f CronJob.yml             创建定时任务pod
    kubectl get pod -n default 
    kubectl logs -f hello-1667197860-j8ntj -n default  查看第一个一次性任务的pod的日志时间
    
    通过status为Completed状态时,可以看到job任务完成了
    
    kubectl get pod -n default 
    kubectl logs -f hello-1667197920-fjfwc         查看第二个一次性任务的pod的日志时间
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    7、k8s最小单位pod(单实例pod)

    官网文档:pod

    Deployment,ReplicaSet,StatefulSet,job,CronJob这些控制器实际就是通过各种条件控制pod的各种状态、形式、结构进行变化。
    通常你不需要直接创建 Pod,甚至单实例 Pod。 相反,你会使用诸如 Deployment 或 Job 这类工作负载资源来创建 Pod。 如果 Pod 需要跟踪状态,可以考虑 StatefulSet 资源。

    Kubernetes 集群中的 Pod 主要有两种用法:

    • 运行单个容器的 Pod。“每个 Pod 一个容器” 模型是最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod
      看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
    • 运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。
      这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的
      “边车”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。

    创建单个pod

    vi pod.yml
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.23.2
    
    kubectl apply -f pod.yml
    kubectl get pod -n default 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

  • 相关阅读:
    什么灯适合学生在暑假使用?照度国AA级的舒适护眼灯
    MVCC:多版本并发控制案例分析(一)
    数据库tps的思考
    AWS无服务器 应用程序开发—第十四章 实战1
    VBA_MF系列技术资料1-192
    基于PHP的视频社交管理系统
    Salesforce ServiceCloud考证学习(2)
    文献阅读-图文匹配的相似性推理和过滤
    真的不会写,求告知🥹
    MySQL系列-索引
  • 原文地址:https://blog.csdn.net/DLWH_HWLD/article/details/125851879