当前位置: 首页 > news >正文

Kubernetes 存储入门

目录

一、Volume 的概念

二、Volume的类型

三、通过emptyDir共享数据

四、使用HosPath挂载宿主机文件

五、挂载NFS至容器

六、PersistentVolume(PV,持久卷)

1、PV回收策略

2、PV访问策略

3、PV的配置方式

(1)静态配置

(2)动态配置

4、基于HostPath的PV

5、基于NFS的PV

七、PersistentVolumeClain(PVC,持久卷声明)

1、PVC的创建

(1)为hostpath类型的PV创建PVC

(2)为NFS类型的PV创建PVC

2、PVC的使用

(1)创建pod,绑定hostpath的PV

(2)创建pod,绑定NFS的PV


一、Volume 的概念

在 Kubernetes 中,由于应用部署具有高度的可扩展性和编排能力,数据存放在容器中无法保障安全,因此需要将有状态应用转变为无状态应用,把数据从应用中剥离出来,存放在如 NFS、Ceph 等云端存储中。而 Kubernetes 抽象出 Volume 概念来解决数据存储问题。

容器中的磁盘文件是短暂的,当容器崩溃重启后,运行时产生的数据会丢失;且一个 Pod 运行多个容器时可能需要共享文件,这些需求都可通过 Volume 解决。

Docker 也有卷的概念,但 Docker 卷只是磁盘上或另一个容器中的目录,生命周期不受管理,功能有限,比如每个容器只允许一个卷驱动程序,无法传递特殊参数给后端存储。

相比之下,Kubernetes 卷具有明确的生命周期,与使用它的 Pod 相同,因此其生命周期可以比 Pod 中任何容器的生命周期都长,能在容器重启或销毁后保留数据。Kubernetes 支持多种类型的卷,一个 Pod 可同时使用任意数量的卷。

从本质上讲,卷被挂载后,在容器中就是一个目录,可能包含数据,Pod 中的容器可对其进行增删改查操作,使用方式和裸机挂载几乎无区别。使用卷时,Pod 需通过 .spec.volumes 字段指定提供的卷,然后在容器中通过 .spec.containers.volumeMounts 字段指定卷的挂载目录。

二、Volume的类型

在传统架构中,企业内可能有自己的存储平台,比如NFS、Ceph、GlusterFS、Minio等。如果所在 的环境在公有云,也可以使用公有云提供的NAS、对象存储等。在Kubernetes中,Volume也支持配置 这些存储,用于挂载到Pod中实现数据的持久化。Kubernetes Volume支持的卷的类型有很多。

以下为常见的卷:

  • CephFS
  • GlusterFS
  • ISCSI
  • Cinder
  • NFS
  • RBD
  • HostPath

当然也支持一些Kubernetes独有的类型:

  • ConfigMap:用于存储配置文件
  • Secret:用于存储敏感数据
  • EmptyDir:用于一个Pod内多个容器的数据共享
  • PersistentVolumeClaim:对PersistentVolume的申请

三、通过emptyDir共享数据

emptyDir是一个特殊的Volume类型,与上述Volume不同的是,如果删除Pod,Emptyir卷中的数据也将被删除,所以一般emptyDir用于Pod中不同容器共享数据,比如一个Pod存在两个容器A和容器B,容器A需要使用容器B产生的数据,此时可以采用emptyDir共享数据,类似的使用如Filebeat 收集容器内程序产生的日志。

使用emptyDir卷时,直接指定emptyDir为{}即可

编写emptyDir的Deployment文件

vim nginx-empty.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginxname: nginxnamespace: default
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx01volumeMounts:- mountPath: /optname: share-volume- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx02command:- sh- -c- sleep 3600volumeMounts:- mountPath: /mntname: share-volumevolumes:- name: share-volumeemptyDir: {}#medium: Memory

备注:

volumeMounts:

  - mountPath: /mnt

  name: share-volume        #容器定义部分的卷挂载名称,此处的名称引用了volumes对应的名称

volumes:

  - name: share-volume        #共享存储卷的名称

此案例会将nginx01中/opt中的数据,共享给nginx02中的/mnt目录

此部署文件创建一个Deployment,采用spec.volume字段配置了一个名字为share-volume、类型 为emptyDir的volume,同时里面包含两个容器nginx01和nginx02,并将该volume挂载到了/opt和 /mnt目录下,此时/opt和/mnt目录的数据就实现了共享。

默认情况下,emptyDir支持节点上的任何介质,可以使SSD、磁盘或是网络存储,具体取决于自身 环境。可以将emptyDir.medium字段设置为Memory,让Kubernetes使用tmpfs(内存支持的文件系统),虽然tmpfs非常快,但是在节点重启时,数据同样会被清除,并且设置的大小会被记入Container的内存限制中。

部署该Deployment

kubectl create -f nginx-empty.yaml

查看部署结果

[root@k8s-master ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-8f8dcfd8c-sbzfh   2/2     Running   0          4s

登录Pod中的第一个容器

[root@k8s-master ~]# kubectl exec -ti nginx-8f8dcfd8c-sbzfh -c nginx01 -- bash
root@nginx-8f8dcfd8c-sbzfh:/# cd /opt/
root@nginx-8f8dcfd8c-sbzfh:/opt# ls
root@nginx-8f8dcfd8c-sbzfh:/opt# touch aaa
root@nginx-8f8dcfd8c-sbzfh:/opt# touch bbb
root@nginx-8f8dcfd8c-sbzfh:/opt# ls
aaa  bbb
root@nginx-8f8dcfd8c-sbzfh:/opt# exit
exit
[root@k8s-master ~]#

注:在该容器中的/opt下创建一个文件,并到第二个容器中查看,是否是共享的目录。

登录Pod中的第二个容器查看/mnt下的文件

[root@k8s-master ~]# kubectl exec -ti nginx-8f8dcfd8c-sbzfh -c nginx02 -- bash
root@nginx-8f8dcfd8c-sbzfh:/# cd /mnt/
root@nginx-8f8dcfd8c-sbzfh:/mnt# ls
aaa  bbb
root@nginx-8f8dcfd8c-sbzfh:/# date
Wed Jul  9 01:19:07 UTC 2025
root@nginx-8f8dcfd8c-sbzfh:/mnt# exit
exit
[root@k8s-master ~]# 

注:登录伤处后,此处可以使用date命令查看容器中的时间,会发现时间是不对的。是因为时区的问题,容器内使用的不是亚洲上海市区。导致时间不对。

删除此Pod

kubectl delete -f nginx-empty.yaml 

四、使用HosPath挂载宿主机文件

HostPath卷可以将节点上的文件或目录挂载到Pod上,用于实现Pod和宿主机之间的数据共享,常 用的示例有挂载宿主机的时区至Pod,或者将Pod的日志文件挂载到宿主机等。

编写Deployment文件,实现HostPath挂载

以下为使用HostPath卷的示例,实现将主机的/etc/localtime文件挂载到Pod的/etc/localtime

vim nginx-hostPath.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginxname: nginxnamespace: default
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginxvolumeMounts:- mountPath: /etc/localtimename: timezone-timevolumes:- name: timezone-timehostPath:path: /etc/localtimetype: File

注:关于时区的设置是通过配置/etc/localtime文件设置系统的时区,/etc/localtime用于配置系统时区(此文件是一个链接文件,链接自/usr/share/zoneinfo/Asia/Shanghai)。

创建此Pod

kubectl create -f nginx-hostPath.yaml 

查看创建结果

[root@k8s-master ~]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-59f95c99b5-k44sz   1/1     Running   0          5s

测试挂载情况

[root@k8s-master ~]# kubectl exec -ti nginx-59f95c99b5-k44sz -- bash
root@nginx-59f95c99b5-k44sz:/# date
Wed Jul  9 09:38:56 CST 2025
root@nginx-59f95c99b5-k44sz:/# ls -l /etc/localtime 
-rw-r--r--. 4 root root 561 Dec 11  2024 /etc/localtime
root@nginx-59f95c99b5-k44sz:/# exit
exit

在配置HostPath时,有一个type参数,用于表达不同的挂载类型,HostPath卷常用的类型有:

  • type为空字符串:默认选项,在挂载HostPath卷之前不会有任何检查
  • DirectoryOrCreate:如果给定的path不存在任何东西,那么将根据需要创建一个权限为 0755的空目录,和kubelet具有相同的组和权限
  • Directory:目录必须存在于给定的路径下
  • FileOrCreate:如果给定的路径不存在任何内容,则会根据需要创建一个空文件,权限设置为0644,和kubelet具有相同的组和所有权
  • File:文件,必须存在于给定的路径中
  • Socket:UNIX套接字,必须存在于给定的路径中
  • CharDevice:字符设备,必须存在于给定的路径中
  • BlockDevice:块设备,必须存在于给定的路径中

删除

kubectl delete -f nginx-hostPath.yaml

五、挂载NFS至容器

安装NFS(01/02/03)

在所有Kubernetes节点都要安装

dnf -y install nfs-utils

设置共享目录(在NFS服务器上)

01:NFS服务器

mkdir /opt/wwwroot
echo "test.com">/opt/wwwroot/index.htmlvim /etc/exports
/opt/wwwroot 192.168.10.0/24(rw,sync,no_root_squash)

开启nfs

systemctl start nfs
systemctl start rpcbind

编写Deployment文件,挂载NFS

vim nginx-nfsVolume.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginxname: nginxnamespace: default
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginxvolumeMounts:- mountPath: /usr/share/nginx/htmlname: nfs-volumevolumes:- name: nfs-volumenfs:server: 192.168.10.101path: /opt/wwwroot

部署此Pod

kubectl create -f nginx-nfsVolume.yaml

查看部署结果并登录容器查看挂载结果

[root@k8s-master ~]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7bf6df4679-l4vbl   1/1     Running   0          3s
[root@k8s-master ~]# kubectl exec -ti nginx-7bf6df4679-l4vbl -- bash
root@nginx-7bf6df4679-l4vbl:/# exit
exit
[root@k8s-master ~]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
nginx-7bf6df4679-l4vbl   1/1     Running   0          2m29s   10.244.85.199   k8s-node01   <none>           <none>
[root@k8s-master ~]# curl 10.244.85.199
test.com

六、PersistentVolume(PV,持久卷)

尽管 Volume 已经能够接入大部分存储后端,但在实际使用中仍存在诸多问题。例如,当数据卷不再被挂载使用时,其中的数据该如何处理;若想实现只读挂载或仅允许一个 Pod 挂载,Volume 可能难以满足这些复杂需求,且无法对存储的生命周期进行管理。此外,企业中使用 Kubernetes 的人员多样,并非都熟悉 Volume 或相关存储平台的配置参数,难以自行完成存储配置。

为此,Kubernetes 引入了 PersistentVolume(持久卷,简称 PV),它是由 Kubernetes 管理员设置的存储,其生命周期独立于使用它的 Pod,可能比挂载它的其他资源更长。PV 可以使用 NFS、GFS、CEPH 等常见的存储后端,并能提供访问模式、空间大小以及回收策略等更高级的配置。

1、PV回收策略

当用户使用完卷时,可以从API中删除PVC对象,从而允许回收资源。回收策略会告诉PV如何处理 改卷。目前回收策略可以设置为Retain、Recycle和Delete。静态PV默认的为Retain,动态PV默认为Delete。

  • Retain:保留,该策略允许手动回收资源,当删除PVC时,PV仍然存在,PV中的数据也存在。volume 被视为已释放,管理员可以手动回收卷。
  • Recycle:回收,如果volume插件支持,Recycle策略会对卷执行rm-rf清理该PV,卷中的数据 已经没了,但卷还在,使其可用于下一个新的PVC,但是本策略将会被弃用,目前只有NFS和HostPath 支持该策略。
  • Delete:删除,如果volume插件支持,删除PVC时会同时删除PV,PV中的数据自然也就没了。动 态卷默认为Delete,目前支持Delete的存储后端包括ANS EBS、GCE PD、Azure Disk、OpenStack Cinder等。

2、PV访问策略

在实际使用PV时,可能针对不同的应用会有不同的访问策略,比如某类Pod可以读写,某类Pod只 能读,或者需要配置是否可以被多个不同的Pod同时读写等,此时可以使用PV的访问策略进行简单控制, 目前支持的访问策略如下:

模式缩写说明

ReadWriteOnce

RWO仅能被单节点挂载为读写模式

ReadOnlyMany

ROX可被多个节点挂载为只读模式

ReadWriteMany

RWX可被多个节点挂载为读写模式

ReadWriteOncePod

RWOP仅能被单个 Pod 挂载为读写模式 (K8s 1.22+)

虽然PV在创建时可以指定不同的访问策略,但是也要后端的存储支持才行。比如一般情况下,大部 分块存储是不支持ReadWriteMany的。

在企业内,可能存储很多不同类型的存储,比如NFS、Ceph、GlusterFS等,针对不同类型的后端存储具有不同的配置方式,这也是对集群管理员的一种挑战,因为集群管理员需要对每种存储都要有所了解。

3、PV的配置方式

(1)静态配置

静态配置是手动创建PV并定义其属性,例如容量、访问模式、存储后端等。在这种情况下,Kubernetes 管理员负责管理和配置PV,然后应用程序可以使用这些PV。静态配置通常用于一些固定的存储后端,如 NFS。

(2)动态配置

动态配置允许Kubernetes集群根据PVC的需求自动创建PV,在这种情况下,管理员只需为存储后端配置StorageClass,然后应用程序就可以通过PVC请求存储。Kubernetes将自动创建与PVC匹配的 PV,并将其绑定到PVC上。这种方法使得存储管理更加灵活和可扩展,允许管理员在集群中动态添加、删除、和管理存储资源

4、基于HostPath的PV

可以创建一个基于HostPath的PV,和配置NFS的PV类似,只需要配置hostPath字段即可,其它配置基本一致。

在所有节点创建主机目录(01/02/03)

mkdir /mnt/data

编辑hostpath的yaml文件(01)

vim hostpath-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:name: mypv-hostpathlabels:type: local
spec:storageClassName: pv-hostpathcapacity:storage: 10GiaccessModes:- ReadWriteOncehostPath:path: "/mnt/data"

 注:

hostPath:宿主机的路径,使用hostPath类型需要固定Pod所在的节点,防止Pod漂移造成数据丢失。

storageClassName是一个用于标识StorageClass对象名称的标签。当你创建或配置PersistentVolumeClaim(PVC)时,可以指定storageClassName来告诉Kubernetes你希望使用哪个Storageclass来配置存储。

kubectl create -f hostpath-pv.yaml[root@k8s-master ~]# kubectl get pv
NAME            CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
mypv-hostpath   10Gi       RWO            Retain           Available           pv-hostpath             7s

5、基于NFS的PV

需要使用NFS,上文已经安装好NFS,不再安装

创建一个基于NFS的PV

注:PV目前没有NameSpace隔离,不需要指定命名空间,在任意命名空间下创建的PV均可以在其他 NameSpace使用

vim nfs-pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:name: mypv-nfs
spec:capacity:storage: 5GivolumeMode: FilesystemaccessModes:- ReadWriteOncepersistentVolumeReclaimPolicy: RecyclestorageClassName: pvc-nfsmountOptions:- hard- nfsvers=4.1nfs:path: /opt/wwwroot/server: 192.168.10.101

备注:

  • capacity:容量配置
  • volumeMode:卷的模式,目前支持Filesystem(文件系统)和Block(块),其中Block类型需 要后端存储支持,默认为文件系统。
  • accessModes:该PV的访问模式
  • storageclassName:PV的类,一个特定类型的PV只能绑定到特定类别的PVC。
  • persistentVolumeReclaimPolicy:回收策略
  • mountoption:非必要,新版本中已经弃用
  • nfs:NFS服务配置,包括以下两个选项

            path:NFS上的共享目录

            server:NFS的IP地址

创建PV:

kubectl create -f nfs-pv.yaml

查看PV创建结果:

[root@k8s-master ~]# kubectl get pv
NAME            CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
mypv-hostpath   10Gi       RWO            Retain           Available           pv-hostpath             3m58s
mypv-nfs        5Gi        RWO            Recycle          Available           pvc-nfs                 6s

七、PersistentVolumeClain(PVC,持久卷声明)

当kubernetes管理员提前创建好了PV,我们又应该如何使用它呢?

这里介绍kubernetes的另一个概念PersistentvolumeClaim(简称PVC)。PVC是其他技术人员在kubernetes上对存储的申请,他可以标明一个程序需要用到什么样的后端存储、多大的空间以及什么 访问模式进行挂载。这一点和Pod的Qos配置类似,Pod消耗节点资源,PVC消耗PV资源,Pod可以请 求特定级别的资源(CPU和内存),PVC可以请求特定的大小和访问模式的PV。例如申请一个大小为5G 且只能被一个Pod只读访问的存储。

在实际使用时,虽然用户通过PVC获取存储支持,但是用户可能需要具有不同性质的PV来解决不同 的问题,比如使用SSD硬盘来提高性能。所以集群管理员需要根据不同的存储后端来提供各种PV,而不 仅仅是大小和访问模式的区别,并且无须让用户了解这些卷的具体实现方式和存储类型,打扫了存储的解 耦,降低了存储使用的复杂度。

接下来我们来看看如何让PVC和前面创建的PV绑定。PVC和PV进行绑定的前提条件是一些参数必须 匹配,比如accessModes、storageClassName、volumeMode都需要相同,并且PVC的storage需要小 于等于PV的storage配置。

1、PVC的创建

(1)为hostpath类型的PV创建PVC

vim pvc-hostpath.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: mypvc-hostpath
spec:storageClassName: pv-hostpathaccessModes:- ReadWriteOnceresources:requests:storage: 3Gi

注:storageClassName:存储类名称需要和对应的PV中的名称一致,PV和PVC进行绑定并非是名字相同,而是StorageClassName相同且其他参数一致才可以进行绑定。

kubectl create -f pvc-hostpath.yaml[root@k8s-master ~]# kubectl get pvc
NAME             STATUS   VOLUME          CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc-hostpath   Bound    mypv-hostpath   10Gi       RWO            pv-hostpath    7s

(2)为NFS类型的PV创建PVC

vim pvc-nfs.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: mypvc-nfs
spec:storageClassName: pvc-nfsaccessModes:- ReadWriteOnceresources:requests:storage: 3Gi

注:storageClassName:存储类名称需要和对应的PV中的名称一致

kubectl create -f pvc-nfs.yaml [root@k8s-master ~]# kubectl get pvc
NAME             STATUS   VOLUME          CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc-hostpath   Bound    mypv-hostpath   10Gi       RWO            pv-hostpath    118s
mypvc-nfs        Bound    mypv-nfs        5Gi        RWO            pvc-nfs        5s

从上述两个简单的例子可以看出,PVC的定义和后端存储并没有关系。对于有存储需求的技 术人员,直接定义PVC即可绑定一块PV,之后就可以供Pod使用,而不用去关心具体的实现细节, 大大降低了存储的复杂度。接下来我们看一下PVC如何提供给Pod使用。

2、PVC的使用

上述创建了PV,并使用PVC与其绑定,现在还差一步就能让程序使用这块存储,那就是将PVC挂载 到Pod。和之前的挂载方式类似,PVC的挂载也是通过volumes字段进行配置的,只不过之前需要根据不 同的存储后端填写很多复杂的参数'而使用PVC进行挂载时,只填写PVC的名字即可,不需要再关心任何 的存储细节,这样即使不是Kubemetes管理员,不懂存储的其他技术人员想要使用存储,也可以非常简 单地进行配置和使用。比如我们将之前创建的hostPath类型的PVC挂载到Pod中,可以看到只需要配置 一个PersistentVolumeClaim类型的volumes,claimName配置为PVC的名称即可:

(1)创建pod,绑定hostpath的PV

vim pvc-pv-pod-hostpath.yaml 
kind: Pod
apiVersion: v1
metadata:name: hostpath-pv-pod
spec:volumes:- name: task-pv-storagepersistentVolumeClaim:claimName: mypvc-hostpathcontainers:- name: task-pv-containerimage: nginx:1.7.9ports:- containerPort: 80name: "http-server"volumeMounts:- mountPath: "/usr/share/nginx/html"name: task-pv-storage

注:claimName: mypvc-hostpath是基于hastpath创建的PVC的名字

kubectl create -f pvc-pv-pod-hostpath.yaml [root@k8s-master ~]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
hostpath-pv-pod          1/1     Running   0          9s    10.244.85.200   k8s-node01   <none>           <none>
nginx-7bf6df4679-l4vbl   1/1     Running   0          61m   10.244.85.199   k8s-node01   <none>           <none>

02:k8s-node01

[root@k8s-node01 ~]# mkdir /mnt/data
[root@k8s-node01 ~]# cd /mnt/data/
[root@k8s-node01 data]# echo "nihao.com">index.html

01

[root@k8s-master ~]# curl 10.244.85.200
nihao.com

(2)创建pod,绑定NFS的PV

vim pvc-pv-pod-nfs.yaml 
kind: Pod
apiVersion: v1
metadata:name: pvc-nfs
spec:volumes:- name: pvc-nfs01persistentVolumeClaim:claimName: mypvc-nfscontainers:- name: task-pv-containerimage: nginx:1.7.9ports:- containerPort: 80name: "http-server"volumeMounts:- mountPath: "/usr/share/nginx/html"name: pvc-nfs01

注:claimName: mypvc-nfs    是基于NFS创建的PVC的名字

kubectl create -f pvc-pv-pod-nfs.yaml[root@k8s-master ~]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
hostpath-pv-pod          1/1     Running   0          3m59s
nginx-7bf6df4679-l4vbl   1/1     Running   0          65m
pvc-nfs                  1/1     Running   0          6s
[root@k8s-master ~]# kubectl exec -ti pvc-nfs -- bash
root@pvc-nfs:/# ls /usr/share/nginx/html/
index.html
root@pvc-nfs:/# exit
exit
[root@k8s-master ~]# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
hostpath-pv-pod          1/1     Running   0          4m55s   10.244.85.200   k8s-node01   <none>           <none>
nginx-7bf6df4679-l4vbl   1/1     Running   0          66m     10.244.85.199   k8s-node01   <none>           <none>
pvc-nfs                  1/1     Running   0          62s     10.244.85.201   k8s-node01   <none>           <none>
[root@k8s-master ~]# curl 10.244.85.201
test.com
http://www.dtcms.com/a/271301.html

相关文章:

  • HTTP请求走私漏洞
  • 【Python】FastApi
  • P1009 [NOIP 1998 普及组] 阶乘之和
  • HashMap中get()、put()详解
  • 代码审计-shiro漏洞分析
  • Explain关键字
  • rt thread studio 和 KEIL对于使用rt thread 的中间件和组件,哪个更方便
  • Flask3.1打造极简CMS系统
  • VsCode 接入Continue 远程调用(持续扩展 + DeepSeek R1)— 免本地算力
  • ZECN致业:科创微光,照亮技术新征程
  • 200nl2sql
  • Linux建立本地软件仓库
  • 存储服务一NFS文件存储概述
  • 解锁HTML5页面生命周期API:前端开发的新视角
  • debug和release的区别,打印菱形,水仙花数,喝汽水问题,计算求和
  • 从互联网电脑迁移Dify到内网部署Dify方法记录
  • 语音识别核心模型的数学原理和公式
  • http get和http post的区别
  • 【软件工程】tob和toc含义理解
  • 【25软考网工】第十章 (3)网络冗余设计、广域网接入技术
  • Docker 高级管理 -- 容器通信技术与数据持久化
  • mysql 故障检测与处理
  • Linux 测开:日志分析 + 定位 Bug
  • Paimon 原子提交实现
  • 【Linux】Rocky Linux 安装 Docker 与 Docker-Compose
  • AI智能选股,DeepSeek智能分析股票测试
  • 搭建一款结合传统黄历功能的日历小程序
  • C++最小生成树算法详解
  • 人机协同的关键枢纽:软件工程3.0中对象模型与模型驱动的融合路径
  • Vue 3 中父子组件双向绑定的 4 种方式