• 容器编排学习(五)卷的概述与存储卷管理


    一  卷

    1  容器化带来的问题

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

    问题1:当容器崩溃或重启的时候,kubelet 会以干净的状态(镜像的状态)重启容器,容器内的历史数据会丢失

    问题2:当容器被删除时 (k8s 没有停止容器的概念,只有创建、删除),容器内的数据也会被一起清理

    问题3:多个容器中有共享文件或目录的需求

    2  卷是什么

    卷是一个抽象化的存储设备

    3  为什么使用卷

    卷可以解决容器崩溃或重启后历史数据丢失的问题

    卷可以解决容器或 Pod 被删除后数据持久保存的问题

    卷可以解决在多个容器内共享数据的问题

    Pod 可以同时使用任意数目的卷

    4  k8s支持的卷的类型

    持久卷:持久卷是集群中的存储资源,就像他的名字一样在里面存储的数据不会随着 Pod 的删除而丢失

    临时卷:有些应用程序需要额外的存储,但并不关心数据在重启后是否仍然可用。卷会遵从 Pod 的生命周期,与 Pod一起创建和删除

    投射卷:它允许您将多个现有卷源映射到同一个目录。通过将这些不同类型的卷源组合成一个统一的卷,可以更方便地管理和使用这些资源

    Pod资源文件

    1. [root@master ~]# vim web1.yaml
    2. ---
    3. kind: Pod
    4. apiVersion: v1
    5. metadata:
    6. name: web1
    7. spec:
    8. containers:
    9. - name: nginx
    10. image: myos:nginx

    二  持久卷

    1  hostPath卷

    • hostPath 卷的本质是使用本地设备,例如磁盘、分区、目录、Socket、CharDevice 和 BlockDevice 等等。hostPath卷的可用性取决于底层节点的可用性,如果节点变得不健康那么 hostPath 卷也将不可被访问。
    • hostPath 卷里面的数据不会随着 Pod的结束而消失
    • 注意事项:配置相同的 Pod,可能在不同的节点上表现不同因为不同节点上映射的文件内容不同

    使用 hostPath 卷保存日志

    1. [root@master ~]# vim web1.yaml
    2. ---
    3. kind: Pod
    4. apiVersion: v1
    5. metadata:
    6. name: web1
    7. spec:
    8. volumes: # 卷定义
    9. - name: logdata # 卷名称
    10. hostPath: # 资源类型
    11. path: /var/weblog # 宿主机路径
    12. type: DirectoryOrCreate # 目录不存在就创建
    13. containers:
    14. - name: nginx
    15. image: myos:nginx
    16. volumeMounts: # mount 卷
    17. - name: logdata # 卷名称
    18. mountPath: /usr/local/nginx/logs # 容器内路径

    type对应的类型

    验证 hostPath 卷

    1. [root@master ~]# kubectl apply -f web1.yaml
    2. pod/web1 created
    3. [root@master ~]# kubectl get pods -o wide
    4. NAME READY STATUS RESTARTS AGE IP NODE
    5. web1 1/1 Running 0 45m 10.244.2.16 node-0002
    6. [root@master ~]# curl http://10.244.2.16/
    7. Nginx is running !
    8. # 删除Pod ,日志数据也不会丢失
    9. [root@master ~]# kubectl delete pod web1
    10. pod "web1" deleted
    11. # 来到 node 上查看日志
    12. [root@node-0002 ~]# cat /var/weblog/access.log
    13. 10.244.0.0 - - [27/Jun/2022:02:00:12 +0000] "GET / HTTP/1.1" 200 19 "-" "curl/7.29.0"

    2  NFS卷

    NFS存储

    • k8s中允许将 nfs 存储以卷的方式挂载到你的 Pod 中
    • 在删除 Pod 时,nfs 存储卷会被卸载 (umount),而不是被删除。nfs 卷可以在不同节点的 Pod 之间共享数据。

    NFS卷的用途

    NFS最大的功能就是在不同节点的不同 Pd 中共享读写数据。本地NFS的客户端可以透明地读写位于远端NFS服务器上的文件,就像访问本地文件一样。

    名称IP地址配置
    nfs192.168.1.101CPU,1G内存

     配置NFS服务

    1. # 创建共享目录,并部署测试页面
    2. [root@nfs ~]# mkdir -p /var/webroot
    3. [root@nfs ~]# echo "nfs server" >/var/webroot/index.html
    4. # 部署 NFS 服务
    5. [root@nfs ~]# dnf install -y nfs-utils
    6. [root@nfs ~]# vim /etc/exports
    7. /var/webroot 192.168.1.0/24(rw,no_root_squash)
    8. [root@nfs ~]# systemctl enable --now nfs-server.service
    9. #----------------------------------------------------------#
    10. # 由于 Pod 是随机调度的,为了保证 NFS 存储卷可以正确加载,需要在所有 node 节点都安装 NFS软件工具包
    11. [root@node ~]# dnf install -y nfs-utils

    Pod调用NFS卷

    1. [root@master ~]# vim web1.yaml
    2. ---
    3. kind: Pod
    4. apiVersion: v1
    5. metadata:
    6. name: web1
    7. spec:
    8. volumes:
    9. - name: logdata
    10. hostPath:
    11. path: /var/weblog
    12. type: DirectoryOrCreate
    13. - name: website # 卷名称
    14. nfs: # NFS 资源类型
    15. server: 192.168.1.10 # NFS 服务器地址
    16. path: /var/webroot # NFS 共享目录
    17. containers:
    18. - name: nginx
    19. image: myos:nginx
    20. volumeMounts:
    21. - name: logdata
    22. mountPath: /usr/local/nginx/logs
    23. - name: website # 卷名称
    24. mountPath: /usr/local/nginx/html # 路径
    25. [root@master ~]# kubectl apply -f web1.yaml
    26. pod/web1 created
    27. [root@master ~]# kubectl get pods -o wide
    28. NAME READY STATUS RESTARTS AGE IP NODE
    29. web1 1/1 Running 0 12m 10.244.1.19 node-0001

    访问验证 nfs 卷

    1. [root@master ~]# curl http://10.244.1.19
    2. nfs server

    三  PV/PVC

    1  概述

    PV 的全称是 Persistent Volume,是持久卷

    PVC 的全称是 PersistentVolumeClaim,是持久卷声明

    2  用途

    存储的管理是一个与计算实例的管理完全不同的问题。管理员希望能提供一种通用的 API来完成Pod 对卷的部署管理与使用。PV/PVC就是为了满足这和需求而诞生的,PV/PVC的引入使集群具备了存储的逻辑抽象能力。

    3  k8s支持的存储卷

    • -cephfs - - CephFS volume
    • -csi--fc  - -  容器存储接口(CSI)
    • -fc - - Fibre Channel (FC) 存储
    • -hostPath - - HostPath 卷
    • -iscsi-iSCSI - - (SCSI over IP) 存储
    • -nfs - - 网络文件系统 (NFS)存储
    • -rbd -- Rados 块设备(RBD) 卷

    4  使用PV/PVC

    PV 是资源的提供者,根据集群的基础设施变化而变化,由K8s集群管理员配置

    PVC是资源的使用者,根据业务服务的需求变化来配置,用户无需知道PV的技术细节,只需要声明你需求什么样的资源即可

    PVC会根据用户声明的需求,自动找到 PV完成绑定

    5  PV资源文件

    • PV资源文件(hostPath)

    1. ---
    2. kind: PersistentVolume
    3. apiVersion: v1
    4. metadata:
    5. name: pv-local
    6. spec:
    7. volumeMode: Filesystem # 提供的资源类型 [Filesystem,Block]
    8. accessModes: # 存储卷能提供的访问模式
    9. - ReadWriteOnce # 卷支持的模式,支持多种
    10. - ReadOnlyMany # RWO,ROX,RWX,RWOP
    11. capacity: # 存储卷能提供的存储空间
    12. storage: 30Gi # 空间大小
    13. persistentVolumeReclaimPolicy: Retain # 数据回收方式
    14. hostPath: # hostPath配置
    15. path: /var/weblog
    16. type: DirectoryOrCreate
    • PV资源文件(NFS)

    1. ---
    2. kind: PersistentVolume
    3. apiVersion: v1
    4. metadata:
    5. name: pv-nfs
    6. spec:
    7. volumeMode: Filesystem # 提供 Fileststem 访问方式
    8. accessModes: # NFS 支持多种访问方式
    9. - ReadWriteOnce # RWO,ROX,RWX
    10. - ReadOnlyMany
    11. - ReadWriteMany
    12. capacity:
    13. storage: 20Gi # 提供的磁盘空间大小
    14. persistentVolumeReclaimPolicy: Retain # 数据手工回收
    15. mountOptions: # mount 的参数
    16. - nolock
    17. nfs: # NFS配置
    18. server: 192.168.1.10 # <NFS服务器IP地址>
    19. path: /var/webroot # <共享目录路径>
    • 创建 PV

    1. # 创建 PV
    2. [root@master ~]# kubectl apply -f pv.yaml
    3. persistentvolume/pv-local created
    4. persistentvolume/pv-nfs created
    5. # 查看PV状态
    6. [root@master ~]# kubectl get persistentvolume
    7. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS AGE
    8. pv-local 30Gi RWO Retain Available 2s
    9. pv-nfs 20Gi RWO,ROX,RWX Retain Available 2s
    • 持久卷
    1. [root@master ~]# vim pv.yaml
    2. ---
    3. kind: PersistentVolume
    4. apiVersion: v1
    5. metadata:
    6. name: pv-local
    7. spec:
    8. volumeMode: Filesystem
    9. accessModes:
    10. - ReadWriteOnce
    11. capacity:
    12. storage: 30Gi
    13. persistentVolumeReclaimPolicy: Retain
    14. hostPath:
    15. path: /var/weblog
    16. type: DirectoryOrCreate
    17. ---
    18. kind: PersistentVolume
    19. apiVersion: v1
    20. metadata:
    21. name: pv-nfs
    22. spec:
    23. volumeMode: Filesystem
    24. accessModes:
    25. - ReadWriteOnce
    26. - ReadOnlyMany
    27. - ReadWriteMany
    28. capacity:
    29. storage: 20Gi
    30. persistentVolumeReclaimPolicy: Retain
    31. mountOptions:
    32. - nolock
    33. nfs:
    34. server: 192.168.1.10
    35. path: /var/webroot
    36. [root@master ~]# kubectl apply -f pv.yaml
    37. persistentvolume/pv-local created
    38. persistentvolume/pv-nfs created
    39. [root@master ~]# kubectl get persistentvolume
    40. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS AGE
    41. pv-local 30Gi RWO Retain Available 2s
    42. pv-nfs 20Gi RWO,ROX,RWX Retain Available 2s

    6  PVC资源文件

    持久卷声明
    1. [root@master ~]# vim pvc.yaml
    2. ---
    3. kind: PersistentVolumeClaim
    4. apiVersion: v1
    5. metadata:
    6. name: pvc1
    7. spec: # 定义需求
    8. volumeMode: Filesystem # 需要使用 Filesystem 的存储卷
    9. accessModes:
    10. - ReadWriteOnce # 需要支持 RWO 的存储卷
    11. resources:
    12. requests:
    13. storage: 25Gi # 最小磁盘需求
    14. ---
    15. kind: PersistentVolumeClaim
    16. apiVersion: v1
    17. metadata:
    18. name: pvc2
    19. spec:
    20. volumeMode: Filesystem
    21. accessModes:
    22. - ReadWriteMany
    23. resources:
    24. requests:
    25. storage: 15Gi
    26. [root@master ~]# kubectl apply -f pvc.yaml
    27. persistentvolumeclaim/pvc1 created
    28. persistentvolumeclaim/pvc2 created
    29. [root@master ~]# kubectl get persistentvolumeclaims
    30. NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
    31. pvc1 Bound pv-local 30Gi RWO 8s
    32. pvc2 Bound pv-nfs 20Gi RWO,ROX,RWX 8s

    7  Pod调用PVC

    映射PVC为卷

    • 使用 PVC用户无需关心后端存储设备
    • 系统会自动查找匹配

    Pod 挂载 PVC

    1. [root@master ~]# vim web1.yaml
    2. ---
    3. kind: Pod
    4. apiVersion: v1
    5. metadata:
    6. name: web1
    7. spec:
    8. volumes: # 卷定义
    9. - name: logdata # 卷名称
    10. persistentVolumeClaim: # 通过PVC引用存储资源
    11. claimName: pvc1 # PVC名称
    12. - name: website # 卷名称
    13. persistentVolumeClaim: # 通过PVC引用存储资源
    14. claimName: pvc2 # PVC名称
    15. containers:
    16. - name: nginx
    17. image: myos:nginx
    18. volumeMounts:
    19. - name: logdata # PVC卷名称
    20. mountPath: /usr/local/nginx/logs # 挂载路径
    21. - name: website # PVC卷名称
    22. mountPath: /usr/local/nginx/html # 挂载路径

    服务验证

    创建 Pod 后访问查看

    1. [root@master ~]# kubectl delete pods web1
    2. pod "web1" deleted
    3. [root@master ~]# kubectl apply -f web1.yaml
    4. pod/web1 created
    5. [root@master ~]# kubectl get pods -o wide
    6. NAME READY STATUS RESTARTS AGE IP NODE
    7. web1 1/1 Running 0 45m 10.244.2.16 node-0002
    8. [root@master ~]# curl http://10.244.2.16
    9. nfs server

    四  存储卷管理

    1  临时卷

    configMap

    <1>  概述

    configMap 是一种临时卷

    configMap 卷提供了向 Pod 注入配置数据的方法,允许你将配置文件与镜像分离,使容器化的应用具有可移植性。

    configMap 在使用之前需要先创建它,configMap 不是用来保存大量数据的,在其中保存的数据不可超过 1 MiB。

    <2>  用途

    配置环境变量

    修改配置文件的参数,数据库的地址等

    <3>  修改系统时区 

    • 修改系统时区 01

    创建 configMap 语法格式

    kubectI  create configmap  名称  [选项/参数]

    1. # 使用命令创建 configMap
    2. [root@master ~]# kubectl create configmap tz --from-literal=TZ="Asia/Shanghai"
    3. configmap/tz created
    4. # 使用资源对象文件创建
    5. [root@master ~]# vim timezone.yaml
    6. ---
    7. kind: ConfigMap
    8. apiVersion: v1
    9. metadata:
    10. name: timezone
    11. data:
    12. TZ: Asia/Shanghai
    13. [root@master ~]# kubectl apply -f timezone.yaml
    14. configmap/timezone created
    15. [root@master ~]# kubectl get configmaps
    16. NAME DATA AGE
    17. kube-root-ca.crt 1 9d
    18. timezone 1 15s
    19. tz 1 50s
    • 修改系统时区 02
    1. [root@master ~]# vim web1.yaml
    2. ---
    3. kind: Pod
    4. apiVersion: v1
    5. metadata:
    6. name: web1
    7. spec:
    8. volumes:
    9. - name: logdata
    10. persistentVolumeClaim:
    11. claimName: pvc1
    12. - name: website
    13. persistentVolumeClaim:
    14. claimName: pvc2
    15. containers:
    16. - name: nginx
    17. image: myos:nginx
    18. envFrom: # 配置环境变量
    19. - configMapRef: # 调用资源对象
    20. name: timezone # 资源对象名称
    21. volumeMounts:
    22. - name: logdata
    23. mountPath: /usr/local/nginx/logs
    24. - name: website
    25. mountPath: /usr/local/nginx/html
    26. [root@master ~]# kubectl delete pods web1
    27. pod "web1" deleted
    28. [root@master ~]# kubectl apply -f web1.yaml
    29. pod/web1 created
    30. [root@master ~]# kubectl exec -it web1 -- date +%T
    31. 10:41:27
    <4>  nginx解析php

    在 Pod 中增加 php 容器,与 nginx 共享同一块网卡

    • 添加容器
    1. # 在 Pod 中增加 php 容器,与 nginx 共享同一块网卡
    2. [root@master ~]# vim web1.yaml
    3. ---
    4. kind: Pod
    5. apiVersion: v1
    6. metadata:
    7. name: web1
    8. spec:
    9. volumes:
    10. - name: logdata
    11. persistentVolumeClaim:
    12. claimName: pvc1
    13. - name: website
    14. persistentVolumeClaim:
    15. claimName: pvc2
    16. containers:
    17. - name: nginx
    18. image: myos:nginx
    19. envFrom:
    20. - configMapRef:
    21. name: timezone
    22. volumeMounts:
    23. - name: logdata
    24. mountPath: /usr/local/nginx/logs
    25. - name: website
    26. mountPath: /usr/local/nginx/html
    27. - name: php # 以下为新增加内容
    28. image: myos:php-fpm
    29. envFrom: # 不同容器需要单独配置时区
    30. - configMapRef:
    31. name: timezone
    32. volumeMounts:
    33. - name: website # 不同容器需要单独挂载NFS
    34. mountPath: /usr/local/nginx/html
    35. [root@master ~]# kubectl delete pod web1
    36. pod "web1" deleted
    37. [root@master ~]# kubectl apply -f web1.yaml
    38. pod/web1 created
    39. [root@master ~]# kubectl get pods
    40. NAME READY STATUS RESTARTS AGE
    41. web1 2/2 Running 0 5s
    42. [root@master ~]# kubectl exec -it web1 -c nginx -- ss -ltun
    43. Netid State Recv-Q Send-Q Local Address:Port ... ...
    44. tcp LISTEN 0 128 0.0.0.0:80 ... ...
    45. tcp LISTEN 0 128 127.0.0.1:9000 ... ...
    • 制作配置文件
    1. # 使用 nginx 配置文件创建 configMap
    2. [root@master ~]# kubectl cp -c nginx web1:/usr/local/nginx/conf/nginx.conf nginx.conf
    3. [root@master ~]# vim nginx.conf
    4. location ~ \.php$ {
    5. root html;
    6. fastcgi_pass 127.0.0.1:9000;
    7. fastcgi_index index.php;
    8. include fastcgi.conf;
    9. }
    10. # 使用命令创建 configMap
    11. [root@master ~]# kubectl create configmap nginx-php --from-file=nginx.conf
    12. configmap/nginx-php created
    • 映射配置文件
    1. [root@master ~]# vim web1.yaml
    2. ---
    3. kind: Pod
    4. apiVersion: v1
    5. metadata:
    6. name: web1
    7. spec:
    8. volumes:
    9. - name: logdata
    10. persistentVolumeClaim:
    11. claimName: pvc1
    12. - name: website
    13. persistentVolumeClaim:
    14. claimName: pvc2
    15. - name: nginx-php # 卷名称
    16. configMap: # 引用资源对象
    17. name: nginx-php # 资源对象名称
    18. containers:
    19. - name: nginx
    20. image: myos:nginx
    21. envFrom:
    22. - configMapRef:
    23. name: timezone
    24. volumeMounts:
    25. - name: nginx-php # 卷名称
    26. subPath: nginx.conf # 键值(文件名称)
    27. mountPath: /usr/local/nginx/conf/nginx.conf # 路径
    28. - name: logdata
    29. mountPath: /usr/local/nginx/logs
    30. - name: website
    31. mountPath: /usr/local/nginx/html
    32. - name: php
    33. image: myos:php-fpm
    34. envFrom:
    35. - configMapRef:
    36. name: timezone
    37. volumeMounts:
    38. - name: website
    39. mountPath: /usr/local/nginx/html
    • php解析验证
    1. # 拷贝测试页面 s4/public/info.php
    2. [root@ecs-proxy s4]# rsync -av public/info.php 192.168.1.10:/var/webroot/info.php
    3. #---------------------------------------------------------------------------------#
    4. [root@master ~]# kubectl delete pod web1
    5. pod "web1" deleted
    6. [root@master ~]# kubectl apply -f web1.yaml
    7. pod/web1 created
    8. [root@master ~]# kubectl get pods -o wide
    9. NAME READY STATUS RESTARTS AGE IP NODE
    10. web1 2/2 Running 0 18s 10.244.3.17 node-0003
    • 页面解析测试
    1. [root@master ~]# curl http://10.244.3.17/info.php
    2. <pre>
    3. Array
    4. (
    5. [REMOTE_ADDR] => 10.244.0.0
    6. [REQUEST_METHOD] => GET
    7. [HTTP_USER_AGENT] => curl/7.29.0
    8. [REQUEST_URI] => /info.php
    9. )
    10. php_host: web1
    11. 1229

    2  secret卷

    <1>  概述

    Secret 是一种临时卷

    Secret 类似于 ConfigMap 但专门用于保存机密数据

    在设置 Secret.data 字段时,所有键值都必须是经过base64编码的字符串

    <2>  用途

    配置一些需要加密的环境变量或文件(例如:https 证书)

    访问需要认证登录的私有镜像仓库(例如: harbor 私有仓库)

    <3>  语法格式

    kubect creat secret 子类型 名称 [选项/参数]

    <4>  子类型

    • 通用类型

    kubect creat secret generic 名称 [选项/参数]

    • 用于认证登录私有仓库的子类型

    kubect creat secret docker-registry 名称 [选项/参数]

    • 用于创建TLS证书的子类型

    kubectl create secret tls 名称 [选项/参数]

    <5> 登录私有仓库
    • 仓库 harbor:443/myimg/httpd:latest需要认证
    • 使用私有仓库中的镜像创建容器
    1. # 创建需要登录私有仓库的资源对象
    2. [root@master ~]# kubectl create secret docker-registry harbor-auth --docker-server=harbor:443 --docker-username="用户名" --docker-password="密码"
    3. secret/harbor-auth created
    4. [root@master ~]# kubectl get secrets harbor-auth -o yaml
    5. apiVersion: v1
    6. data:
    7. .dockerconfigjson: <经过加密的数据>
    8. kind: Secret
    9. metadata:
    10. name: harbor-auth
    11. namespace: default
    12. resourceVersion: "1558265"
    13. uid: 08f55ee7-2753-41fa-8aec-98a292115fa6
    14. type: kubernetes.io/dockerconfigjson
    <6>  登录认证私有仓库
    1. [root@master ~]# vim web2.yaml
    2. ---
    3. kind: Pod
    4. apiVersion: v1
    5. metadata:
    6. name: web2
    7. spec:
    8. imagePullSecrets: # 引用 secret 数据
    9. - name: harbor-auth # 资源对象名称
    10. containers:
    11. - name: apache
    12. image: harbor:443/myimg/httpd:latest # 使用私有仓库里的镜像
    13. [root@master ~]# kubectl apply -f web2.yaml
    14. pod/web2 created
    15. [root@master ~]# kubectl get pods
    16. NAME READY STATUS RESTARTS AGE
    17. web1 2/2 Running 0 33m
    18. web2 1/1 Running 0 18m

    3  emptyDir卷

    <1>  概述

    emptyDir 的本质是一个简单的空目录

    emptyDir 可以提供临时空间,同一个 Pod 中容器也可以用来共享数据。案例:缓存服务器、数据统计分析、排序等

    emptyDir 随 Pod 创建而创建,Pod 在该节点上运行期间一直存在。当 Pod 被从节点上删除时,临时卷中的数据也会被永久删除

    重启 Pod中的容器不会造成 emptyDir 数据的丢失

    <2>  临时空间

    1. [root@master ~]# vim web2.yaml
    2. ---
    3. kind: Pod
    4. apiVersion: v1
    5. metadata:
    6. name: web2
    7. spec:
    8. imagePullSecrets:
    9. - name: harbor-auth
    10. volumes: # 卷配置
    11. - name: cache # 卷名称
    12. emptyDir: {} # 资源类型
    13. containers:
    14. - name: apache
    15. image: harbor:443/myimg/httpd:latest
    16. volumeMounts: # 挂载卷
    17. - name: cache # 卷名称
    18. mountPath: /var/cache # 路径

    <3>  验证配置

    创建容器,验证配置

    1. [root@master ~]# kubectl delete pod web2
    2. pod "web2" deleted
    3. [root@master ~]# kubectl apply -f web2.yaml
    4. pod/web2 created
    5. [root@master ~]# kubectl exec -it web2 -- bash
    6. [root@web2 html]# mount -l |grep cache
    7. /dev/vda1 on /var/cache type xfs (rw,relatime,attr2)

  • 相关阅读:
    车联网安全入门——ICSim模拟器使用
    苹果手机ip地址怎么关闭
    计算机视觉传统图像处理库opencv的使用
    基于FPGA的频率计与串口通信(一)
    如何获得淘宝/天猫app商品详情原数据API数据
    2.5 OJ 网站的使用与作业全解
    layui杂项
    2021年上半年软件设计师上午真题及答案解析(六)
    发送短信验证码的倒计时一直停留在60秒,没有开始倒计时
    linux联网修改时间
  • 原文地址:https://blog.csdn.net/2301_79227925/article/details/132723947