大家好,我是米开朗基杨。

KubeSphere 3.3.0 (不出意外的话~)下周就要 GA 了,作为一名 KubeSphere 脑残粉,我迫不及待地先安装 RC 版[1]尝尝鲜,一顿操作猛如虎开启所有组件,装完之后发现有点尴尬:我用错了持久化存储。

我的 K8s 集群中有两个存储类(StorageClass),一个是 OpenEBS 提供的本地存储,另一个是 QingCloud CSI[2] 提供的分布式存储,而且默认的 StorageClass 是 OpenEBS 提供的 local-hostpath,所以 KubeSphere 的有状态组件默认便使用本地存储来保存数据。

失误失误,我本来是想用分布式存储作为默认存储的,但是我忘记将 csi-qingcloud 设置为默认的 StorageClass 了,反正不管怎样,就这么稀里糊涂地搞错了。虽然重装可以解决 99% 的问题,但作为一名成熟的 YAML 工程师,重装是不可能的,必须在不重装的情况下解决这个问题,才能体现出我的气质!

事实上不止我一个人遇到过这种情况,很多人都会稀里糊涂地装完一整套产品之后发现 StorageClass 用错了,这时候再想改回去恐怕就没那么容易了。这不巧了么这不是,本文就是来帮助大家解决这个问题的。

思路

我们先来思考一下换 StorageClass 需要做哪几件事情。首先需要将应用的副本数缩减为 0,然后创建一个新的 PVC,将旧 PV 的数据复制到新 PV,然后让应用使用新的 PV,并将副本扩展到原来的数量,最后再将旧 PV 删除。在这整个过程中还要防止删除 PVC 时 Kubernetes 将 PV 也删除了。

当然,有些 CSI 驱动或者存储后端可能会有更便利的数据迁移技巧,但是本文提供的是一种更加通用的方案,不管后端是什么存储都可以。

KubeSphere 3.3.0 开启所有组件之后使用的持久卷声明(PVC)如下:

本文就以 Elasticsearch 为例,演示如何将 Elasticsearch 的存储从本地存储替换为分布式存储。

备份 PVC 和 PV

首先第一步就是备份 PVC 和 PV,万一后面操作失败了,还有反悔的余地。

$ kubectl -n kubesphere-logging-system get pvc
NAME                                     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     AGE
data-elasticsearch-logging-data-0        Bound    pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9   20Gi       RWO            local-hostpath   28h
data-elasticsearch-logging-data-1        Bound    pvc-0851350a-270e-4d4d-af8d-081132c1775b   20Gi       RWO            local-hostpath   28h
data-elasticsearch-logging-discovery-0   Bound    pvc-8f32fc97-3d6e-471a-8121-655991d945a8   4Gi        RWO            local-hostpath   28h$ kubectl -n kubesphere-logging-system get pv pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9 -o yaml > pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9.yaml
$ kubectl -n kubesphere-logging-system get pv pvc-0851350a-270e-4d4d-af8d-081132c1775b -o yaml > pvc-0851350a-270e-4d4d-af8d-081132c1775b.yaml$ kubectl -n kubesphere-logging-system get pvc data-elasticsearch-logging-data-0 -o yaml > data-elasticsearch-logging-data-0.yaml
$ kubectl -n kubesphere-logging-system get pvc data-elasticsearch-logging-data-1 -o yaml > data-elasticsearch-logging-data-1.yaml

复制数据

不管 PV 的 accessModes 是 ReadWriteOnce[3] 还是 ReadWriteMany[4],在复制数据之前都要将应用的副本数量缩减为 0,因为 ReadWriteOne 模式同时只允许挂载一个 Pod,新 Pod 无法挂载,而 ReadWriteMany 模式如果不将副本数量缩减为 0,在复制数据时可能会有新的数据写入。所以无论如何,都要将副本数量缩为 0 。

$ kubectl -n kubesphere-logging-system get sts
NAME                              READY   AGE
elasticsearch-logging-data        2/2     28h
elasticsearch-logging-discovery   1/1     28h$ kubectl -n kubesphere-logging-system scale sts elasticsearch-logging-data --replicas=0$ kubectl -n kubesphere-logging-system get sts
NAME                              READY   AGE
elasticsearch-logging-data        0/0     28h
elasticsearch-logging-discovery   1/1     28h

创建一个新的 PVC 叫 new-data-elasticsearch-logging-data-0,容量和 data-elasticsearch-logging-data-0 一样,并将 storageClassName 指定为新的 StorageClass。

创建一个 Deployment,将新 PV 和旧 PV 都挂载进去,然后再将旧 PV 的数据拷贝到新 PV。

在『工作负载』界面点击『创建』,将下面的 YAML 粘贴进去即可。

apiVersion: apps/v1
kind: Deployment
metadata:namespace: kubesphere-logging-systemlabels:app: datacopyname: datacopy
spec:replicas: 1selector:matchLabels:app: datacopytemplate:metadata:labels:app: datacopyspec:containers:- name: datacopyimage: ubuntucommand:- 'sleep'args:- infinityvolumeMounts:- name: old-pvreadOnly: falsemountPath: /mnt/old- name: new-pvreadOnly: falsemountPath: /mnt/newvolumes:- name: old-pvpersistentVolumeClaim:claimName: data-elasticsearch-logging-data-0- name: new-pvpersistentVolumeClaim:claimName: new-data-elasticsearch-logging-data-0

这个 Deployment 将新 PV 和旧 PV 都挂载进去了,稍后我们会将旧 PV 的数据拷贝到新 PV。

Pod 启动成功后,点击容器的终端图标进入容器的终端。

在容器中先验证旧 PV 的挂载点是否包含应用数据,新 PV 的挂载点是否是空的,之后再执行命令 (cd /mnt/old; tar -cf - .) | (cd /mnt/new; tar -xpf -),以确保所有数据的所有权和权限被继承。

执行完成后,验证新 PV 的挂载点是否包含旧 PV 的数据,以及所有权和权限是否被正确继承。

到这里复制数据的任务就完成了,现在我们需要将 datacopy 的副本数量缩为 0。

迁移 PVC

迁移存储的理想状态是使用旧的 PVC,并将其指向新的 PV,这样工作负载的 YAML 配置清单就不需要做任何改变。但 PVC 和 PV 之间的绑定关系是不可更改的,要想让它们解绑,必须先删除旧的 PVC,再创建同名的 PVC,并将旧的 PV 与它绑定。

需要注意的是,默认情况下 PV 的回收策略是 Delete,一旦删除 PVC,与之绑定的 PV 和 PV 里的数据都会被删除。这是我们不希望看到的,所以我们需要修改回收策略,以便删除 PVC 时 PV 能够保留下来。

事实上可以通过 StorageClass 来设置全局的回收策略(reclaimPolicy)[5],如果不设置,默认就是 Delete。可以通过命令 kubectl describe pv <pv-name> 来查看 PV 的回收策略(reclaimPolicy):

$ kubectl describe pv pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9
Name:              pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9
Labels:            openebs.io/cas-type=local-hostpath
Annotations:       pv.kubernetes.io/provisioned-by: openebs.io/local
Finalizers:        [kubernetes.io/pv-protection]
StorageClass:      local-hostpath
Status:            Bound
Claim:             kubesphere-logging-system/data-elasticsearch-logging-data-0
Reclaim Policy:    Delete
...$ kubectl describe pv pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e
Name:              pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e
Labels:            <none>
Annotations:       pv.kubernetes.io/provisioned-by: disk.csi.qingcloud.com
Finalizers:        [kubernetes.io/pv-protection external-attacher/disk-csi-qingcloud-com]
StorageClass:      csi-qingcloud
Status:            Bound
Claim:             kubesphere-logging-system/new-data-elasticsearch-logging-data-0
Reclaim Policy:    Delete
...

我们可以通过 patch 命令将新旧 PV 的回收策略设置为 Retain

$ kubectl patch pv pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9 -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
persistentvolume/pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9 patched$ kubectl patch pv pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
persistentvolume/pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9 patched

⚠️注意:该命令对 PV 的稳定性和可用性没有任何影响,可以随时执行。

现在可以将新旧 PVC 全部删除,PV 不会受到任何影响。

$ kubectl -n kubesphere-logging-system delete pvc data-elasticsearch-logging-data-0 new-data-elasticsearch-logging-data-0
persistentvolumeclaim "data-elasticsearch-logging-data-0" deleted
persistentvolumeclaim "new-data-elasticsearch-logging-data-0" deleted

在创建最终的 PVC 之前,我们必须要确保新创建的 PVC 能够被绑定到新的 PV 上。通过以下命令可以看到新 PV 目前处于释放状态,不能被新 PVC 绑定:

$ kubectl describe pv pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e
Name:              pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e
Labels:            <none>
Annotations:       pv.kubernetes.io/provisioned-by: disk.csi.qingcloud.com
Finalizers:        [kubernetes.io/pv-protection external-attacher/disk-csi-qingcloud-com]
StorageClass:      csi-qingcloud
Status:            Released
Claim:             kubesphere-logging-system/new-data-elasticsearch-logging-data-0
Reclaim Policy:    Retain
Access Modes:      RWO
VolumeMode:        Filesystem
Capacity:          20Gi
...

这是因为 PV 在 spec.claimRef 中仍然引用了已经被删除的 PVC:

$ kubectl get pv pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e -o yaml
apiVersion: v1
kind: PersistentVolume
metadata:...name: pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e...
spec:accessModes:- ReadWriteOncecapacity:storage: 20GiclaimRef:apiVersion: v1kind: PersistentVolumeClaimname: new-data-elasticsearch-logging-data-0namespace: kubesphere-logging-systemresourceVersion: "657019"uid: f4e96f69-b3be-4afe-bb52-1e8e728ca55e...persistentVolumeReclaimPolicy: RetainstorageClassName: csi-qingcloudvolumeMode: Filesystem

为了解决这个问题,可以直接通过命令 kubectl edit pv <pv-name> 编辑 PV,将 claimRef 的内容全部删除。然后再查看 PV 已经处于可用状态(Available):

$ kubectl describe pv pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e
Name:              pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e
Labels:            <none>
Annotations:       pv.kubernetes.io/provisioned-by: disk.csi.qingcloud.com
Finalizers:        [kubernetes.io/pv-protection external-attacher/disk-csi-qingcloud-com]
StorageClass:      csi-qingcloud
Status:            Available
Claim:
Reclaim Policy:    Retain
Access Modes:      RWO
VolumeMode:        Filesystem
Capacity:          20Gi

最终我们需要创建与旧 PVC 同名的新 PVC,而且要尽可能保证与旧 PVC 的参数相同:

  • 新 PVC 的名字和旧 PVC 的名字相同;

  • spec.volumeName 指向新 PV;

  • 新 PVC 的 metadata.annotationsmetadata.labels 和旧 PVC 保存相同,因为这些值可能会影响到应用部署(比如 Helm chart 等)。

最终 PVC 内容如下:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:labels:app: elasticsearchcomponent: datarelease: elasticsearch-loggingrole: dataname: data-elasticsearch-logging-data-0namespace: kubesphere-logging-system
spec:storageClassName: csi-qingcloudaccessModes:- ReadWriteOnceresources:requests:storage: 20GivolumeMode: FilesystemvolumeName: pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e

在『存储卷声明』页面点击『创建』:

选择『编辑 YAML』,将上面的 YAML 内容复制粘贴进去,然后点击『创建』:

最终可以看到新的 PVC 和 PV 全部都是 Bound 状态:

$ kubectl -n kubesphere-logging-system get pvc data-elasticsearch-logging-data-0
NAME                                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS    AGE
data-elasticsearch-logging-data-0   Bound    pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e   20Gi       RWO            csi-qingcloud   64s$ kubectl get pv pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                                         STORAGECLASS    REASON   AGE
pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e   20Gi       RWO            Retain           Bound    kubesphere-logging-system/data-elasticsearch-logging-data-0   csi-qingcloud            11h

再来一遍

到目前为止,我们只迁移了 data-elasticsearch-logging-data-0 的数据,对于 data-elasticsearch-logging-data-1,按照上面的步骤再重复一遍就行了,记得将 datacopy 中的 PVC 改为 data-elasticsearch-logging-data-1new-data-elasticsearch-logging-data-0,其他地方的配置内容也要修改为新的。

恢复工作负载

现在所有的存储都迁移完成,PVC 名称保持不变,PV 使用的是新的存储。

$ kubectl get pv -A|grep elasticsearch-logging-data
pvc-0851350a-270e-4d4d-af8d-081132c1775b   20Gi       RWO            Retain           Released   kubesphere-logging-system/data-elasticsearch-logging-data-1        local-hostpath            40h
pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9   20Gi       RWO            Retain           Released   kubesphere-logging-system/data-elasticsearch-logging-data-0        local-hostpath            40h
pvc-d0acd2e7-ee1d-47cf-8506-69147fe25563   20Gi       RWO            Retain           Bound      kubesphere-logging-system/data-elasticsearch-logging-data-1        csi-qingcloud             9m53s
pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e   20Gi       RWO            Retain           Bound      kubesphere-logging-system/data-elasticsearch-logging-data-0        csi-qingcloud             11h$ kubectl -n kubesphere-logging-system get pvc|grep elasticsearch-logging-data
data-elasticsearch-logging-data-0        Bound    pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e   20Gi       RWO            csi-qingcloud    27m
data-elasticsearch-logging-data-1        Bound    pvc-d0acd2e7-ee1d-47cf-8506-69147fe25563   20Gi       RWO            csi-qingcloud    3m49s

将工作负载的副本恢复到之前的数量:

$ kubectl -n kubesphere-logging-system scale sts elasticsearch-logging-data --replicas=2
statefulset.apps/elasticsearch-logging-data scaled$ kubectl -n kubesphere-logging-system get pod -l app=elasticsearch,component=data
NAME                           READY   STATUS    RESTARTS   AGE
elasticsearch-logging-data-0   1/1     Running   0          4m12s
elasticsearch-logging-data-1   1/1     Running   0          3m42s

完美!

最后还有一点收尾工作,我们需要将所有新 PV 的回收策略重新设置为 Delete

$ kubectl patch pv pvc-d0acd2e7-ee1d-47cf-8506-69147fe25563 -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}'
persistentvolume/pvc-d0acd2e7-ee1d-47cf-8506-69147fe25563 patched$ kubectl patch pv pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}'
persistentvolume/pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e patched$ kubectl get pv -A|grep elasticsearch-logging-data
pvc-0851350a-270e-4d4d-af8d-081132c1775b   20Gi       RWO            Retain           Released   kubesphere-logging-system/data-elasticsearch-logging-data-1        local-hostpath            40h
pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9   20Gi       RWO            Retain           Released   kubesphere-logging-system/data-elasticsearch-logging-data-0        local-hostpath            40h
pvc-d0acd2e7-ee1d-47cf-8506-69147fe25563   20Gi       RWO            Delete           Bound      kubesphere-logging-system/data-elasticsearch-logging-data-1        csi-qingcloud             15m
pvc-f4e96f69-b3be-4afe-bb52-1e8e728ca55e   20Gi       RWO            Delete           Bound      kubesphere-logging-system/data-elasticsearch-logging-data-0        csi-qingcloud             11h

最后的最后,就可以将旧 PV 全部删除了:

$ kubectl delete pv pvc-0851350a-270e-4d4d-af8d-081132c1775b
persistentvolume "pvc-0851350a-270e-4d4d-af8d-081132c1775b" deleted$ kubectl delete pv pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9
persistentvolume "pvc-9aed3d1b-09a6-4fe3-8adc-9195a2bbb2b9" deleted

更简单的方案

上面的方案虽然完美解决了问题,但步骤比较繁琐,有没有更简洁的方法呢?

可以试试青云推出的云原生备份容灾 SaaS 服务[6],无需部署、维护本地备份基础架构,即可轻松完成多云异构环境下数据的自由迁移,从而实现多地、按需的数据保护与应用的高可用。而且价格比较亲民,对白嫖党友好,提供了 100GB 的免费存储,迁移几个 PV 完全够用了。

使用起来非常简单,先注册账户[7],然后导入 Kubernetes 集群。如果选择通过代理连接 Kubernetes 集群,需要执行红色方框内命令在 Kubernetes 集群中安装代理。

然后新建托管仓库。

接下来直接创建备份计划,选择直接复制

备份成功之后,将集群中的 PVC 和 PV 删除,并将工作负载的副本数缩减为 0。最后创建恢复计划,注意将源存储类型名称为 local-hostpath 的目标存储类型名称设置为你想迁移的存储,这样恢复后的 PV 使用的就是新的 StorageClass。

完了。

总结

本文介绍了如何将 Kubernetes 集群中现有 PV 的数据迁移到新的 PV,并创建同名的 PVC 来指向新的 PV,这样就完成了应用的数据迁移而不需要对应用的配置清单做任何更改。最后还介绍了如何通过云原生备份容灾 SaaS 服务来简化迁移过程。

引用链接

[1]

RC 版: https://github.com/kubesphere/kubesphere/releases/tag/v3.3.0-rc.2

[2]

QingCloud CSI: https://github.com/yunify/qingcloud-csi

[3]

ReadWriteOnce: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes

[4]

ReadWriteMany: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes

[5]

通过 StorageClass 来设置全局的回收策略(reclaimPolicy): https://kubernetes.io/docs/concepts/storage/storage-classes/#reclaim-policy

[6]

云原生备份容灾 SaaS 服务: https://kubesphere.cloud/self-service/disaster-recovery/

[7]

注册账户: https://kubesphere.cloud/sign-up/

你可能还喜欢

点击下方图片即可阅读

系统的过载(Overload)以及处理思路

2022-06-14

Kubernetes 容器和镜像 GC 原理解析

2022-06-13

构建我的第一个 22TB 容量的家庭存储服务器

2022-06-11

如何在 Mac 上愉快地使用 Docker

2022-06-10

云原生是一种信仰 

Kubernetes 中跨 StorageClass 迁移存储完全指南相关推荐

  1. Kubernetes 跨 StorageClass 迁移 Persistent Volumes 完全指南

    大家好,我是米开朗基杨. KubeSphere 3.3.0 (不出意外的话~)本周就要 GA 了,作为一名 KubeSphere 脑残粉,我迫不及待地先安装 RC 版尝尝鲜,一顿操作猛如虎开启所有组件 ...

  2. 使用Rook+Ceph在Kubernetes上作持久存储

    使用Rook+Ceph在Kubernetes上作持久存储 作者:Earl C. Ruby III 我想在新的Kubernetes集群上安装Prometheus和Grafana,但为了使这些软件包能够工 ...

  3. 使用Ceph集群作为Kubernetes的动态分配持久化存储

    2019独角兽企业重金招聘Python工程师标准>>> 使用Docker快速部署Ceph集群 , 然后使用这个Ceph集群作为Kubernetes的动态分配持久化存储. Kubern ...

  4. Kubernetes共享使用Ceph存储

    目录 简要概述 环境测试 结果验证 简要概述 Kubernetes pod 结合Ceph rbd块设备的使用,让Docker 数据存储在Ceph,重启Docker或k8s RC重新 调 度pod 不会 ...

  5. kubernetes部署nfs持久存储(静态和动态)

    kubernetes部署nfs持久存储(静态和动态) NFS简介 NFS是网络文件系统Network File System的缩写,NFS服务器可以让PC将网络中的NFS服务器共享的目录挂载到本地的文 ...

  6. K8S 快速入门(十六)实战篇:StorageClass(存储类)

    StorageClass 存储类 官方文档 上一节演示了 PVC的自动化实现方式:利用volumeClaimTemplates 这一节将讲解PV的自动化: 利用StorageClass实现,可以根据P ...

  7. 蚂蚁大规模 Kubernetes 集群无损升级实践指南【探索篇】

    文|王连平(花名:烨川 ) 蚂蚁集团高级开发工程师 负责蚂蚁 Kubernetes 集群容器交付 专注于集群交付能力.交付性能及交付 Trace 等相关领域 本文 12623 字 阅读 20 分钟 - ...

  8. Python 迁移学习实用指南 | iBooker·ApacheCN

    原文:Hands-On Transfer Learning with Python 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 不要担心自己的形象,只关心如何实现目标.--<原则& ...

  9. 运维实操——kubernetes(九)存储之Secret配置管理Service Account、Opaque、dockerconfigjson

    存储之Secret配置管理Service Account.Opaque.dockerconfigjson 1.什么是Secret? 2.Service Account 3.Opaque (1)从文件中 ...

最新文章

  1. 高性能WEB开发 - HTTP服务器篇
  2. 一些个人认为好看的电影
  3. [转贴]ASP优化之显示数据查询内容
  4. Silverlight 2.5D RPG游戏技巧与特效处理:(七)动画特写
  5. CF476D-Dreamoon and Sets【结论】
  6. GetConsoleTitle 函数--获取控制台窗口标题
  7. 10.看板方法---设置在制品限额
  8. 数据科学 IPython 笔记本 六、SciPy 统计推断
  9. 大学excel题库含答案_大学生计算机基础excel试题及答案
  10. 2018南邮全国计算机大赛,我院承办2018全国大学生物联网设计竞赛(TI杯)南京邮电大学选拔赛...
  11. outlook2010 pst文件过大解决办法
  12. 书评第003篇:《0day安全:软件漏洞分析技术(第2版)》
  13. 安卓从入门到进阶第一篇(环境搭建)
  14. 交规考试通过,庆祝一下
  15. 无人机集群任务规划方法研究综述论文解读
  16. 使用CSS绘制几何图形(圆形、三角形、扇形、菱形等
  17. 机器视觉入门资料大全,工业机器人“眼睛”
  18. java里面的环链怎么做_Java模式开发之责任链模式
  19. 计算机网络谢希仁课后习题
  20. 单样本和双样本的检验

热门文章

  1. 《那些年啊,那些事——一个程序员的奋斗史》——32
  2. 7-19 循环-分数矩阵 (50 分) 我们定义如下矩阵: 1/1 1/2 1/3 1/2 1/1 1/2 1/3 1/2 1/1 矩阵对角线上的元素始终是1/1
  3. 关于住房公积金支取问题的解答
  4. 道德经全文及译文 第二章
  5. 如何一句话让程序员高潮?
  6. c# 36进制,000-ZZZ
  7. Linux磁盘挂载及格式化文件系统格式为xfs
  8. python3**2的值_Python表达式3**2**3的值为_______________。
  9. 顶级婚礼6大流行元素:幸福也与众不同
  10. jupyter notebook启动出错