k8s中的存储

configmap

功能

configMap用于保存配置数据,以键值对形式存储。

configMap 资源提供了向 Pod 注入配置数据的方法。

镜像和配置文件解耦,以便实现镜像的可移植性和可复用性。

etcd限制了文件大小不能超过1M

configmap的使用场景

填充环境变量的值

设置容器内的命令行参数

填充卷的配置文件

创建方式

字面值创建

 kubectl create cm lee-config --from-literal  fname=timing --from-literal lname=lee

通过文件创建

vim /etc/resolv.conf
# Generated by NetworkManager
nameserver 114.114.114.114

kubectl create cm lee2-config --from-file /etc/resolv.conf

通过目录创建

[root@k8s-master ~]# mkdir leeconfig
[root@k8s-master ~]# cp /etc/fstab /etc/rc.d/rc.local  leeconfig/
[root@k8s-master ~]# kubectl create cm lee3-config --from-file leeconfig/

通过yaml文件创建

kubectl create cm lee4-config --from-literal db_host=172.25.254.100 --from-literal db_port=3306 --dry-run=client -o yaml > lee-config.yaml

vim lee-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: lee4-config
data:
  db_host: 172.25.254.100
  db_port: "3306"

configmap的使用方式

通过环境变量的方式直接传递给pod

通过pod的 命令行运行方式

作为volume的方式挂载到pod内

使用configmap填充环境变量

将cm中的内容映射为指定变量

vim testpod1.yml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: testpod
  name: testpod
spec:
  containers:
  - image: busyboxplus:latest
    name: testpod
    command:
    - /bin/sh
    - -c
    - env
    env:
    - name: key1
      valueFrom:
        configMapKeyRef:
          name: lee4-config
          key: db_host
    - name: key2
      valueFrom:
        configMapKeyRef:
          name: lee4-config
          key: db_port
  restartPolicy: Never

把cm中的值直接映射为变量

vim testpod2.yml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: testpod
  name: testpod
spec:
  containers:
  - image: busyboxplus:latest
    name: testpod
    command:
    - /bin/sh
    - -c
    - env
    envFrom:
    - configMapRef:
        name: lee4-config
  restartPolicy: Never

在pod命令行中使用变量

vim testpod3.yml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: testpod
  name: testpod
spec:
  containers:
  - image: busyboxplus:latest
    name: testpod
    command:
    - /bin/sh
    - -c
    - echo ${db_host} ${db_port}		#变量调用需
    envFrom:
    - configMapRef:
        name: lee4-config
  restartPolicy: Never

通过数据卷使用configmap

 vim testpod4.yml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: testpod
  name: testpod
spec:
  containers:
  - image: busyboxplus:latest
    name: testpod
    command:
    - /bin/sh
    - -c
    - cat /config/db_host
    volumeMounts:					#调用卷策略
    - name: config-volume			#卷名称
      mountPath: /config
  volumes:							#声明卷的配置
  - name: config-volume				#卷名称
    configMap:
      name: lee4-config
  restartPolicy: Never

利用configMap填充pod的配置文件

建立配置文件模板

vim nginx.conf
server {
  listen 8000;
  server_name _;
  root /usr/share/nginx/html;
  index index.html;
}

利用模板生成cm

kubectl create cm nginx-conf --from-file nginx.conf

建立nginx控制器文件

kubectl create deployment nginx --image nginx:latest --replicas 1 --dry-run=client -o yaml > nginx.yml

设定nginx.yml中的卷

 vim nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/conf.d

      volumes:
        - name: config-volume
          configMap:
            name: nginx-conf

测试

 curl 10.244.2.38:8000

通过热更新cm修改配置

kubectl edit cm nginx-conf

apiVersion: v1
data:
  nginx.conf: |
    server {
      listen 8080;						#端口改为8080
      server_name _;
      root /usr/share/nginx/html;
      index index.html;
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2024-09-07T02:49:20Z"
  name: nginx-conf
  namespace: default
  resourceVersion: "153055"
  uid: 20bee584-2dab-4bd5-9bcb-78318404fa7a

secrets

secrets的功能

Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。

敏感信息放在 secret 中比放在 Pod 的定义或者容器镜像中来说更加安全和灵活

Pod 可以用两种方式使用 secret:

作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里。

当 kubelet 为 pod 拉取镜像时使用。

Secret的类型:

Service Account:Kubernetes 自动创建包含访问 API 凭据的 secret,并自动修改 pod 以使用此类型的 secret。

Opaque:使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱。

kubernetes.io/dockerconfigjson:用于存储docker registry的认证信息

secrets的创建

[root@k8s-master secrets]# echo -n timinglee > username.txt
[root@k8s-master secrets]# echo -n lee > password.txt

 kubectl create secret generic userlist --from-file username.txt --from-file password.txt

编写yaml文件

apiVersion: v1
kind: Secret
metadata:
  creationTimestamp: null
  name: userlist
type: Opaque
data:
  username: dGltaW5nbGVl
  password: bGVl

Secret的使用方法

Secret的使用方法

kubectl run  busyboxplus --image busyboxplus --dry-run=client -o yaml > pod1.yaml

apiVersion: v1
  labels:
    run: busyboxplus
  name: busyboxplus
spec:
  containers:
  - image: busyboxplus
    name: busyboxplus    
    volumeMounts:
    - name: secrets
      mountPath: /secret
      readOnly: true

  volumes:
  - name: secrets
    secret:
      secretName: userlist
将Secret设置为环境变量
vi pod3.yaml
存储docker registry的认证信息

建立私有仓库并上传镜像

建立用于docker认证的secret

volumes配置管理

容器中文件在磁盘上是临时存放的,这给容器中运行的特殊应用程序带来一些问题

当容器崩溃时,kubelet将重新启动容器,容器中的文件将会丢失,因为容器会以干净的状态重建。

当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件。

Kubernetes 卷具有明确的生命周期与使用它的 Pod 相同

卷比 Pod 中运行的任何容器的存活期都长,在容器重新启动时数据也会得到保留

当一个 Pod 不再存在时,卷也将不再存在。

Kubernetes 可以支持许多类型的卷,Pod 也能同时使用任意数量的卷。

卷不能挂载到其他卷,也不能与其他卷有硬链接。 Pod 中的每个容器必须独立地指定每个卷的挂载位置。

kubernets支持的卷的类型

官网:https://kubernetes.io/zh/docs/concepts/storage/volumes/

k8s支持的卷的类型如下:

awsElasticBlockStore 、azureDisk、azureFile、cephfs、cinder、configMap、csidownwardAPI、emptyDir、fc (fibre channel)、flexVolume、flocker、gcePersistentDisk、gitRepo (deprecated)、glusterfs、hostPath、iscsi、local、nfs、persistentVolumeClaim、projected、portworxVolume、quobyte、rbd、scaleIO、secret、storageos、vsphereVolume

emptyDir卷

功能:

当Pod指定到某个节点上时,首先创建的是一个emptyDir卷,并且只要 Pod 在该节点上运行,卷就一直存在。卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,但是这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会永久删除

emptyDir 的使用场景:

缓存空间,例如基于磁盘的归并排序。

耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。

在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。

示例

viyml文件

apiVersion: v1
kind: Pod
metadata:
  name: vol1
spec:
  containers:
  - image: busyboxplus:latest
    name: vm1
    command:
    - /bin/sh
    - -c
    - sleep 30000000
    volumeMounts:
    - mountPath: /cache
      name: cache-vol
  - image: nginx:latest
    name: vm2
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: cache-vol
  volumes:
  - name: cache-vol
    emptyDir:
      medium: Memory
      sizeLimit: 100Mi

hostpath卷

功能

hostPath 卷能将主机节点文件系统上的文件或目录挂载到您的 Pod 中,不会因为pod关闭而被删除

**hostPath 的一些用法**

  • 运行一个需要访问 Docker 引擎内部机制的容器,挂载 /var/lib/docker 路径。

  • 在容器中运行 cAdvisor(监控) 时,以 hostPath 方式挂载 /sys。

  • 允许 Pod 指定给定的 hostPath 在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在

hostPath的安全隐患

  • 具有相同配置(例如从 podTemplate 创建)的多个 Pod 会由于节点上文件的不同而在不同节点上有不同的行为。

  • 当 Kubernetes 按照计划添加资源感知的调度时,这类调度机制将无法考虑由 hostPath 使用的资源。

  • 基础主机上创建的文件或目录只能由 root 用户写入。您需要在 特权容器 中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入 hostPath 卷。

示例

[root@k8s-master ~]# vim pod2.yml

apiVersion: v1
kind: Pod
metadata:
  name: vol1
spec:
  containers:
  - image: nginx:latest
    name: vm1
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: cache-vol
  volumes:
  - name: cache-vol
    hostPath:
      path: /data
      type: DirectoryOrCreate		

当pod被删除后hostPath不会被清理

echo timinglee > /data/index.html

nfs卷

NFS 卷允许将一个现有的 NFS 服务器上的目录挂载到 Kubernetes 中的 Pod 中。这对于在多个 Pod 之间共享数据或持久化存储数据非常有用

例如,如果有多个容器需要访问相同的数据集,或者需要将容器中的数据持久保存到外部存储,NFS 卷可以提供一种方便的解决方案。

部署

部署一台nfs共享主机并在所有k8s节点中安装nfs-utils

部署nfs主机

[root@reg ~]# dnf install nfs-utils -y
[root@reg ~]# systemctl enable --now nfs-server.service

[root@reg ~]# vim /etc/exports
/nfsdata   *(rw,sync,no_root_squash)

[root@reg ~]# exportfs -rv
exporting *:/nfsdata

[root@reg ~]# showmount  -e
Export list for reg.timinglee.org:
/nfsdata *

在k8s中所有主机下载nfs-utils

[root@k8s-master & node1 & node2  ~]# dnf install nfs-utils -y

部署nfs卷

vim  pod3.yml

在nfs主机中

[root@reg ~]# echo timinglee > /nfsdata/index.html
[root@k8s-master volumes]# curl  10.244.2.50
timinglee

PersistentVolume持久卷

静态持久卷pv与静态持久卷声明pvc

PersistentVolume(持久卷,简称PV)

pv是集群内由管理员提供的网络存储的一部分。

  • PV也是集群中的一种资源。是一种volume插件,

  • 但是它的生命周期却是和使用它的Pod相互独立的。

  • PV这个API对象,捕获了诸如NFS、ISCSI、或其他云存储系统的实现细节

  • pv有两种提供方式:静态和动态

  • 静态PV:集群管理员创建多个PV,它们携带着真实存储的详细信息,它们存在于Kubernetes API中,并可用于存储使用

  • 动态PV:当管理员创建的静态PV都不匹配用户的PVC时,集群可能会尝试专门地供给volume给PVC。这种供给基于StorageClass

PersistentVolumeClaim(持久卷声明,简称PVC)

是用户的一种存储请求

它和Pod类似,Pod消耗Node资源,而PVC消耗PV资源

Pod能够请求特定的资源(如CPU和内存)。PVC能够请求指定的大小和访问的模式持久卷配置

PVC与PV的绑定是一对一的映射。没找到匹配的PV,那么PVC会无限期得处于unbound未绑定状态

volumes访问模式

ReadWriteOnce -- 该volume只能被单个节点以读写的方式映射

ReadOnlyMany -- 该volume可以被多个节点以只读方式映射

ReadWriteMany -- 该volume可以被多个节点以读写的方式映射

在命令行中,访问模式可以简写为:

RWO - ReadWriteOnce

ROX - ReadOnlyMany

RWX -- ReadWriteMany

volumes回收策略

Retain:保留,需要手动回收

Recycle:回收,自动删除卷中数据(在当前版本中已经废弃)

Delete:删除,相关联的存储资产,如AWS EBS,GCE PD,Azure Disk,or OpenStack Cinder卷都会被删除

注意:

只有NFS和HostPath支持回收利用

AWS EBS,GCE PD,Azure Disk,or OpenStack Cinder卷支持删除操作。

volumes状态说明

Available 卷是一个空闲资源,尚未绑定到任何申领

Bound 该卷已经绑定到某申领

Released 所绑定的申领已被删除,但是关联存储资源尚未被集群回收

Failed 卷的自动回收操作失败

静态pv示例

在nfs主机中创建实验目录

编写创建pv的yml文件,pv是集群资源,不在任何namespace中

vi pv.yml

建立pvc,pvc是pv使用的申请,需要保证和pod在一个namesapce中

vim pvc.yml

在其他namespace中无法应用

在pod中使用pvc

存储类storageclass

官网: https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

StorageClass说明

StorageClass提供了一种描述存储类(class)的方法,不同的class可能会映射到不同的服务质量等级和备份策略或其他策略等。

每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段, 这些字段会在StorageClass需要动态分配 PersistentVolume 时会使用到

属性

属性说明:https://kubernetes.io/zh/docs/concepts/storage/storage-classes/

Provisioner(存储分配器):用来决定使用哪个卷插件分配 PV,该字段必须指定。可以指定内部分配器,也可以指定外部分配器。外部分配器的代码地址为: kubernetes-incubator/external-storage,其中包括NFS和Ceph等。

Reclaim Policy(回收策略):通过reclaimPolicy字段指定创建的Persistent Volume的回收策略,回收策略包括:Delete 或者 Retain,没有指定默认为Delete。

存储分配器NFS Client Provisioner

源码地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

  • NFS Client Provisioner是一个automatic provisioner,使用NFS作为存储,自动创建PV和对应的PVC,本身不提供NFS存储,需要外部先有一套NFS存储服务。

  • PV以 {namespace}-{pvcName}-${pvName}的命名格式提供(在NFS服务器上)

部署NFS Client Provisioner

创建sa并授权

vim rbac.yml
apiVersion: v1
kind: Namespace
metadata:
  name: nfs-client-provisioner
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: nfs-client-provisioner
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: nfs-client-provisioner
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: nfs-client-provisioner
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io

查看rbac信息

部署应用

vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  namespace: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: sig-storage/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 172.25.254.254
            - name: NFS_PATH
              value: /nfsdata

创建存储类

vi class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "false"

创建pvc

vim pvc.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1G

测试pod

vim pod.yml
kind: Pod
apiVersion: v1
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: busybox
    command:
      - "/bin/sh"
    args:
      - "-c"
      - "touch /mnt/SUCCESS && exit 0 || exit 1"
    volumeMounts:
      - name: nfs-pvc
        mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim

设置默认存储类

指定多个pvc

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc2
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc3
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: 15Gi

设定默认存储类

kubectl edit sc nfs-client

{"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"nfs-client"},"parameters":{"archiveOnDelete":"false"},"provisioner":"k8s-sigs.io/nfs-subdir-external-provisioner"}

storageclass.kubernetes.io/is-default-class: "true"

statefulset控制器

功能特性

Statefulset是为了管理有状态服务的问提设计的- StatefulSet将应用状态抽象成了两种情况:

拓扑状态:应用实例必须按照某种顺序启动。新创建的Pod必须和原来Pod的网络标识一样

存储状态:应用的多个实例分别绑定了不同存储数据。

StatefulSet给所有的Pod进行了编号,编号规则是:(statefulset名称)-(序号),从0开始。

Pod被删除后重建,重建Pod的网络标识也不会改变,Pod的拓扑状态按照Pod的"名字+编号"的方式固定下来,并且为每个Pod提供了一个固定且唯一的访问入口,Pod对应的DNS记录。

StatefulSet的组成部分

Headless Service:用来定义pod网络标识,生成可解析的DNS记录

volumeClaimTemplates:创建pvc,指定pvc名称大小,自动创建pvc且pvc由存储类供应。

StatefulSet:管理pod的

构建方法

建立无头服务

apiVersion: v1
kind: Service
metadata:
 name: nginx-svc
 labels:
  app: nginx
spec:
 ports:
 - port: 80
   name: web
 clusterIP: None
 selector:
  app: nginx

建立statefulset

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx-svc"
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html

  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      storageClassName: nfs-client
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi

root@k8s-master statefulset]# kubectl get pods

NAME READY STATUS RESTARTS AGE

web-0 1/1 Running 0 3m26s

web-1 1/1 Running 0 3m22s

web-2 1/1 Running 0 3m18s

为每个pod建立index.html文件

[root@reg nfsdata]# echo web-0 > default-www-web-0-pvc/index.html
[root@reg nfsdata]# echo web-1 > default-www-web-1-pvc/index.html
[root@reg nfsdata]# echo web-2 > default-www-web-2-pvc/index.html

建立测试pod访问web-0~2

[root@k8s-master statefulset]# kubectl run -it testpod --image busyboxplus

/ # curl web-0.nginx-svc

web-0

/ # curl web-1.nginx-svc

web-1

/ # curl web-2.nginx-svc

web-2

statefulset的弹缩

首先,想要弹缩的StatefulSet. 需先清楚是否能弹缩该应用

用命令改变副本数

 $kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>

通过编辑配置改变副本数

$ kubectl edit statefulsets.apps <stateful-set-name>
statefulset有序回收
kubectl scale statefulset web --replicas 0

kubectl delete -f statefulset.yaml
 kubectl delete pvc --all
相关推荐
vvw&27 分钟前
如何在 Linux 服务器上部署 Pydio Cells 教程
linux·运维·服务器·自动化·debian·github·私有化部署
勇-子1 小时前
K8s docker-compose的入门
docker·eureka·kubernetes
枫叶红花1 小时前
【Linux系统编程】:信号(1)——前置知识,了解信号
linux·运维·服务器
7yewh2 小时前
嵌入式驱动RK3566 HDMI eDP MIPI 背光 屏幕选型与调试提升篇-eDP屏
linux·arm开发·驱动开发·嵌入式硬件·嵌入式linux·rk·edp
工业3D_大熊3 小时前
HOOPS Communicator功能剖析:3D Web模型树交互的实用指南!
linux·windows·macos·3d·docker·c#·.net
丶Darling.3 小时前
进程间通信博客总结目录
linux·网络编程·进程同步·系统编程·c/c++·阻塞和非阻塞
清水加冰3 小时前
【Linux进程】进程间的通信
linux·进程
YRr YRr4 小时前
详细指南:在Ubuntu 20.04上安装和配置Orbbec SDK及USB设备权限
linux·运维·ubuntu
yuanbenshidiaos4 小时前
linux----文件访问(c语言)
linux·服务器·算法
ghostwritten4 小时前
Linux 下的 GPT 和 MBR 分区表详解
linux·运维·gpt