本文与大家分享新手如何配置 JuiceFS 作为 Kubernetes 的数据持久化介质。Kubernetes 涉及的概念较多,我会尽量以简洁易懂的语言解释文章的内容。但请注意,这篇文章还是需要你对 Kubernetes 集群的创建和管理以及 JuiceFS 的基本架构和使用有一定了解。
Kubernetes 数据持久化不仅关乎数据的安全性和可靠性,还直接关系到应用程序的可用性和性能。在设计和部署容器化应用时,关注数据持久化将有助于确保系统的稳定性和弹性,特别是预期的业务规模和类型有以下特点时:
- 需要存储大量数据;
- 数据量大增大减,波动大;
- 需要在应用之间共享数据,甚至与 Kubernetes 集群外部共享数据。
为什么要用 JuiceFS 为 Kubernetes 提供数据持久化
我们知道,Kubernetes 是容器编排平台,它负责管理应用程序的容器化部署、伸缩和运行。而容器是短暂且无状态的,当容器实例终止时,容器内的文件系统和数据也会丢失。当我们的应用需要持久的存储数据时,就需要创建并挂载持久卷(Persistent Volume)存储数据,以确保数据在容器重新启动时仍然可用。
Kubernetes 支持使用多种存储介质创建持久卷(PV),包括传统的本地磁盘、文件共享、以及各种受支持的云存储。
传统的本地存储解决方案往往面临单点故障、扩展性差、难以管理等一系列问题。而各类云平台针对 Kubernetes 数据持久化提供的存储解决方案几乎都是与平台牢牢捆绑在一起的,当你想与外部共享或将数据迁移到其他平台时会有一定的难度。
而 JuiceFS 这种适合多云环境部署的云文件系统没有上述限制,可以很好地满足 Kubernetes 数据持久化的常见需求。
首先,JuiceFS 可以使用任何对象存储作为底层数据存储,以及任何支持的数据库作为元数据存储引擎。你可以在任何云的任何设备上挂载访问、共享和迁移。
其次,JuiceFS 有多种访问方式。你可以通过 FUSE 挂载、S3 Gateway、WebDAV、Docker Plugin、CSI Driver、HDFS API 等多种方式进行读写访问。
再次,JuiceFS 支持在上千台设备同时挂载、共享访问。任何安装了 JuiceFS 客户的系统,不论裸机、虚拟机、还是容器化应用,不论位于何处,只要能够访问到对象存储和数据库,就可以共享挂载读写。
另外,JuiceFS 有优异的性能表现。数据分块技术充分提高底层对象存储的读写效率;独立存储的元数据可以让百亿 PB 级文件规模仍能够高效检索;多重缓存机制可以实现接近本地磁盘的性能。
JuiceFS 的功能特色不止于此,但篇幅有限,这里不作进一步展开,各位有兴趣可以到官网查看更详细的资料。
对于本文而言,更重要的是用于 Kubernetes 集群数据持久化的 JuiceFS CSI Driver 究竟该如何安装?是否容易安装?是否便于管理和维护?以及应用如何使用持久化存储?下面就让我们一起来探索这些问题的答案。
01 JuiceFS CSI Driver 的三种工作模式
JuiceFS 的 CSI Driver 有以下三种工作模式:Mount Pod、Sidecar 和 进程挂载。既然提供了不同的模式,就说明它们必然有各自面向的场景和要解决的问题。
模式一:Mount Pod 模式
JuiceFS CSI Driver 默认采用 Mount Pod(容器挂载)模式,即让 JuiceFS 客户端运行在独立的 Pod 中,并由 CSI Node Service 来管理 Mount Pod 的生命周期。
该模式的好处是当多个 Pods 共享同一个 PV 时,不必额外创建新的 Mount Pod,只需引用现有的 Mount Pod,当它不再被引用时会被自动删除。另外,这种模式下,客户端与 CSI 驱动是彼此独立的,因此在升级 CSI Driver 时不会影响到客户端。
模式二:Sidecar 模式
由于 CSI Node Service 是 DaemonSet 组件,一些云平台提供的 Serverless Kubernetes 不支持部署 DaemonSet,这种情况下就可以采用 Sidecar 模式,将 JuiceFS 客户端运行在 Sidecar 容器中。
Sidecar 模式下部署的 CSI 驱动只有 CSI Controller 组件,它会注册一个 Webhook 来监听容器变动,当有 Pod 需要使用 JuiceFS PVC 时,它会将带有 JuiceFS 客户端的容器注入应用所在的 Pod 并挂载到应用容器以供使用。
Sidecar 模式有几个情况需要关注:首先,它依赖 FUSE,因此需要允许以特权模式(Privileged)运行容器;其次,Sidecar 容器是有状态的,一旦发生意外重启需要重建整个 Pod 才能恢复。
模式三:进程挂载模式
在进程挂载模式下,JuiceFS 客户端不再运行在独立的 Pod 中,而是运行在 CSI Node Service 容器中,所有需要挂载的 JuiceFS PV 都会在 CSI Node Service 容器中以进程模式挂载。
由于所有 JuiceFS 文件系统都要在 CSI Node Service 容器中挂载,因此这个容器也需要更大的资源声明,通常资源请求至少 1 CPU 和 1GiB 内存,资源约束至少 2 CPU 和 5GiB 内存。
02 安装和管理 JuiceFS CSI Driver 该用 Kubectl 还是 Helm?
了解了 JuiceFS CSI Driver 的三种工作模式,我们可以这样判断,在没有特殊需要的情况下,首选默认的 Mount Pod 模式就对了。
在开始尝试安装 JuiceFS CSI Driver 时,我们碰到的第二个问题是 Kubectl 和 Helm 这两种安装工具,该用哪个?
事实上,不论使用 Kubectl 还是 Helm,最终获得的安装结果都是一致的。二者的主要区别在于,Helm 可以用一个统一的 values.yaml 配置文件来管理 CSI Driver 所有组件的配置,便于后期维护。而使用 Kubectl 安装 CSI Driver,后续的维护都需要单独进行手动处理,无疑会增大维护的复杂度和出错的概率。
从实践上来看,Helm 是一个针对 Kubernetes 的包管理器,在安装、升级和维护等方面都更直观,所以 Helm 是更推荐的方式,具体安装方法请参考 Helm 官方文档,确保你的 Helm 版本不低于 3.1.0 即可。
使用 Helm 安装 JuiceFS CSI Driver
依次执行以下三条命令:
# 添加 JuiceFS 仓库
helm repo add juicefs https://juicedata.github.io/charts/
# 更新仓库
helm repo update
# 安装 CSI Driver
helm install juicefs-csi-driver juicefs/juicefs-csi-driver -n kube-system
命令执行完毕,还需要等待相应的服务和容器部署妥当,使用 Kubectl 检查 Pods 部署情况:
kubectl get pods -n kube-system -l app.kubernetes.io/name=juicefs-csi-driver
如下图所示,当 CSI Driver 相关组件都部署完毕,就可以开始着手配置使用了。
03 用 Kubernetes Secret 保管密钥等敏感信息
一个典型的 JuiceFS 文件系统由对象存储和数据库构成,客户端需要通过对象存储的 Access Key / Secret Key 以及数据库的 URL、用户名和密码才能访问和操控文件系统。很显然,以明文方式在 Kubenetes 集群中使用这些敏感信息是有一定安全隐患的,所以我们要用 Kubernetes Secret 这种专门为集群保存和传递密钥的工具。
Kubernetes 的 Secret 对象用于将密钥、密码和 API 令牌等敏感数据存储在 etcd 中,通过卷挂载或环境变量的方式传递给 Pod。
Kubernetes 中一切皆配置,Secret 也不例外。我们应该将一个 JuiceFS 文件系统的密钥信息写在同一个 Secret 配置文件中。如果有多个文件系统,则创建多个 Secret 配置文件。在之后创建 PV 的时候,只需要引用相应文件系统的 Secret 即可。
下面是 JuiceFS 社区版的一个 Kubernetes Secret 配置文件示例,我将它命名为 myjfs-secret,它对应的是名为 myjfs 的文件系统,将各项的值替换成你实际的信息即可。
apiVersion: v1
kind: Secret
metadata:
name: myjfs-secret
type: Opaque
stringData:
name: myjfs
metaurl: redis://:xxx@192.168.8.8/1
storage: s3
bucket: https://myjfs.xxx.com
access-key: <ACCESS_KEY>
secret-key: <SECRET_KEY>
# 设置 Mount Pod 时区,默认为 UTC。
# envs: "{TZ: Asia/Shanghai}"
# 如需在 Mount Pod 中创建文件系统,也可以将更多 juicefs format 参 数填入 format-options。
# format-options: trash-days=1,block-size=4096
```
将上述 Secret 配置信息整理好写入到一个名为 myjfs-secret.yaml 的文件,然后传入集群。
```shell
kubectl apply -f myjfs-secret.yaml
注意:JuiceFS 社区版、云服务和企业版之间的配置项有一定差异,本文配置均以社区版为例,其他版本请参考相关文档。
04 PV 静态配置和动态配置
安装好了 JuiceFS CSI Driver,接下来需要考虑的是如何在 JuiceFS 上创建持久卷(Persistent Volume,PV),这里涉及到 Kubernetes 中 PV 的两种使用方式,让我们来分别简要地介绍一下。
静态配置(Static Provisioning)
这是一种一切都预先手动创建的方式,首先创建 PV,然后创建一个 PVC 来绑定这个 PV,最后在应用 Pod 中引用 PVC 进行使用。
静态配置的使用流程大致为:
- 创建 PV
- 创建 PVC 并绑定 PV
- 创建应用并引用 PVC
可以查看官方文档提供的示例。
静态配置方式通常适合已经在 JuiceFS 文件系统中存储了大量数据,需要在 Pods 中访问这些数据的情况。
由于创建和使用 PV 的整个过程都需要手动操作,对于有大量应用需要创建和使用 PV 的情况显然是不适合的。
静态配置下默认挂载 JuiceFS 文件系统的根目录,如果需要隔离不同 PV 之间的数据,应该配置挂载子目录。
动态配置(Dynamic Provisioning)
这种方式无需预先创建 PV,而是将创建 PV 的规则定义在 StorageClass 中,当有应用通过 PVC 请求 PV 时,CSI Driver 会根据 StorageClass 自动创建所需的 PV。
静态配置的使用流程大致为:
- 创建 StorageClass
- 通过 PVC 请求自动创建 PV 资源
- 创建应用并引用 PVC
动态配置方式可以根据应用的需要动态创建 PV,在一定程度上简化了运维工作,这对于长期性或规模性使用都会很有帮助。下面为大家提供一组动态配置示例:
为每个 JuiceFS 文件系统创建 StorageClass
与 Secret 一样,你应该为每个 JuiceFS 文件系统创建单独的 StorageClass 配置文件。为了便于管理,一个 StorageClass 配置文件建议对应一个 Secret 文件。
比如下面的 StorageClass 配置被命名为 myjfs-sc
,它对应的 Secret 为 myjfs-secret
。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: myjfs-sc
provisioner: csi.juicefs.com
reclaimPolicy: Retain
parameters:
csi.storage.k8s.io/provisioner-secret-name: myjfs-secret
csi.storage.k8s.io/provisioner-secret-namespace: default
csi.storage.k8s.io/node-publish-secret-name: myjfs-secret
csi.storage.k8s.io/node-publish-secret-namespace: default
```
其中,reclaimPolicy 这一项需要根据实际需要来设置:
- Retain:代表当 PVC 被删除时,相应的 PV 会保留下来,不会被删除,对应的文件系统中的数据也不会被删除;
- Delete:代表当 PVC 被删除时,相应的 PV 将一起被删除,同时对应的文件系统中的数据会被一同删除。
可以把上述配置写在一个名为 `myjfs-sc.yaml` 的文件上传到 Kubernetes 集群:
```shell
kubectl apply -f myjfs-sc.yaml
部署应用
这里为了直观地感受到挂载了 PV 的效果,可以部署一个 Apahce httpd 服务器应用。将下面的配置写入一个名为 my-apache.yaml
的配置文件:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-apache-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
storageClassName: myjfs-sc
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-apache
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: my-apache
template:
metadata:
labels:
app: my-apache
spec:
containers:
- name: apache
image: httpd:latest
volumeMounts:
- name: data
mountPath: /usr/local/apache2/htdocs
volumes:
- name: data
persistentVolumeClaim:
claimName: my-apache-pvc
---
apiVersion: v1
kind: Service
metadata:
name: my-apache
namespace: default
spec:
selector:
app: my-apache
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
这个配置文件中声明了三个资源:
- 首先,是一个 PVC,它声明使用名为 myjfs-sc 的 StorageClass 去创建容量为 10Gi 的 PV;
- 然后,是一个 Deployment 部署 httpd 应用,它引用了上面声明的 PVC;
- 最后,是一个 Service,它采用 LoadBalancer 模式对外提供访问。
将这个配置上传到集群:
kubectl apply -f my-apache.yaml
等待资源部署完毕,就可以使用 Service 服务映射的端口去访问这个 Apache Web 服务器了。
由于 PV 中还没有数据,所以页面展现的文件列表内容是空的。现在让我们做一个有意义的尝试,在本地任何一台计算机上通过 JuiceFS 客户端挂载这个文件系统,写入一些文件到 PV 对应的目录,然后在回来看看 Apache Web 服务器这边的反应。
从外部共享访问 JuiceFS
开始之前需要确保你本地已经安装了 JuiceFS 客户端,如果还没有请访问下载页面安装 JuiceFS 社区版客户端。
使用以下命令将文件系统挂载到本地任意空目录:
juicefs mount redis://:xxx@192.168.8.8/1 $HOME/mnt
如图所示,在本地挂载 JuiceFS 文件系统后,可以在挂载点中看到以 pvc- + PV id
为组合的文件夹名。如下图,通过 kubectl get pvc
可以查到挂载点中目录与 pv 的对应关系。
接下来我们通过本地挂载点向文件夹中写入一个名为 abc.txt 的文件:
touch abc.txt
回到浏览器,刷新页面即可看到页面中列出了这个文件。
这表明我们成功地应用挂上了 PV 持久卷,同时也验证了 JuiceFS 文件系统可以方便地在集群内外共享使用。
05 使用 JuiceFS CSI Dashboard
在安装 JuiceFS CSI Driver 时,将同时安装 CSI Dashboard,这是一个基于网页的 CSI 控制台。通过 CSI Dashboard,您可以了解哪些应用 Pod 绑定了哪个 PV,创建了哪些 StorageClass,以及它下面有哪些 PV。此外,您还可以查看各项资源的配置情况,使问题排查更加简单直观。
然后就可以在浏览器中使用 http://localhost:8088 访问 CSI Dashboard。
最后
至此,在 Kubernetes 中使 JuiceFS 持久化数据的基本知识你就都已经掌握了。但由于 Kubernetes 集群的管理几乎都需要在命令行操作,如果你还不是很熟练,建议你尝试安装使用 Kubernetes Dashboard,它的 WebUI 可以让你更直观的管理集群中的各种资源。
有了图形化的 Dashboard,在安装 CSI Driver 以及后续为应用创建 PV 发生故障也更容易进行排查。比如,笔者在写这篇文章时,部署的测试集群每个节点只分配了 1GB 内存,结果在安装 CSI Driver 以后 juicefs-csi-controller
控制器始终无法启动,通过 Dashboard 上提供的报错信息才知道原来是内存不足所致,将节点内存升级到 2GB 以后,CSI Driver 的所有资源才得以成功部署启动。
如果你希望进一步了解更多 JuiceFS 在 Kubernetes 中使用的进阶内容,请查阅 JuiceFS 官方的 CSI 文档。