Skip to main content

在 Kubernetes 中使用 JuiceFS

相比于相比普通云盘(如 AWS EBS、阿里云弹性云盘等),JuiceFS 支持更多适合云环境使用的特性:

  • 作为分布式共享存储,JuiceFS 支持同时挂载到多个 Pod 并发读写
  • 文件系统挂载不受可用区限制,可以在云上与本地同时挂载
  • JuiceFS 元数据服务默认跨两个可用区部署,相当于同城双活,不受公有云单可用区故障影响
  • 几乎无限的存储空间(取决于所使用的的对象存储),无需进行扩容操作

在 Kubernetes 中有各种不同方式来使用 JuiceFS,请针对不同使用场景来选择:

  • hostPath,适用于所有 Kubernetes 版本。
  • CSI,适用于 Kubernetes v1.13 及以上版本。
  • FlexVolume,适用于 Kubernetes v1.2 及以上版本,官方已经不推荐,建议使用 CSI。

hostPath 存储卷​

如果你仅仅需要在 Kubernetes 容器中简单使用 JuiceFS,没有其他任何复杂要求(比如隔离性、权限控制),那么完全可以以 hostPath 卷 的方式使用 JuiceFS,搭建起来也十分简单:

  1. 在 Kubernetes 节点上统一安装、挂载 JuiceFS,如果节点众多,考虑自动化部署。

  2. 在 pod 定义中使用 hostPath 卷,直接将宿主机上的 JuiceFS 子目录挂载到容器中:

    apiVersion: v1
    kind: Pod
    metadata:
    name: juicefs-app
    spec:
    containers:
    - ...
    volumeMounts:
    - name: jfs-data
    mountPath: /opt/app-data
    volumes:
    - name: jfs-data
    hostPath:
    # 假设挂载点为 /jfs
    path: "/jfs/myapp/"
    type: Directory

相比以 CSI 驱动的方式来使用 JuiceFS,hostPath 更为简单直接,出问题也更易排查,但也要注意:

  • 为求管理方便,一般所有容器都在使用同一个宿主机挂载点,缺乏隔离可能导致数据安全问题,未来也无法在不同应用中单独调整 JuiceFS 挂载参数。请谨慎评估。

  • 所有节点都需要提前挂载 JuiceFS,因此集群加入新节点,需要在初始化流程里进行安装和挂载,否则新节点没有 JuiceFS 挂载点,容器将无法创建。

  • 宿主机上的 JuiceFS 挂载进程所占用的系统资源(如 CPU、内存等)不受 Kubernetes 控制,有可能占用较多宿主机资源。可以考虑用 system-reserved 来适当调整 Kubernetes 的系统资源预留值,为 JuiceFS 挂载进程预留更多资源。

  • 如果宿主机上的 JuiceFS 挂载进程意外退出,将会导致应用 pod 无法正常访问挂载点,此时需要重新挂载 JuiceFS 文件系统并重建应用 pod。作为对比,JuiceFS CSI 驱动提供「挂载点自动恢复」功能来解决这个问题。

  • JuiceFS 挂载点的生命周期与宿主机绑定,如需重新挂载文件系统,可以借助 JuiceFS 客户端的平滑重启功能来确保重新挂载以后不会影响应用 pod 访问挂载点。详见「客户端升级与平滑重启」。

  • 如果你使用 Docker 作为 Kubernetes 容器运行环境,最好令 JuiceFS 先于 Docker 启动,否则在节点重启的时候,偶尔可能出现容器启动时,JuiceFS 尚未挂载好的情况,此时便会因该依赖问题启动失败。以 systemd 为例,可以用下方 unit file 来配置启动顺序:

    /etc/systemd/system/docker.service.d/override.conf
    [Unit]
    # 请使用下方命令确定 JuiceFS 挂载服务的名称(例如 jfs.mount):
    # systemctl list-units | grep "\.mount"
    After=network-online.target firewalld.service containerd.service jfs.mount

CSI 存储卷​

如果对灵活性、可观测性有要求,推荐以 CSI 存储卷的方式来使用 JuiceFS,这也是 Kubernetes 下的标准用法。JuiceFS CSI 有着自己的文档体系,请参考 JuiceFS CSI 驱动文档。

FlexVolume 存储卷​

注意

FlexVolume 已经不再被 Kubernetes 官方推荐,如有可能,请选择 CSI 存储卷方式。

设置 FlexVolume 首先需要安装 JuiceFS 客户端 juicefs,这同时也是 FlexVolume 的驱动,支持 init, mount and unmount 操作。

将 juicefs 放到所有主机的 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/juicedata~juicefs/juicefs 位置,并且将它改成可执行的(需要 Python>=2.7)。

wget https://juicefs.com/static/juicefs
chmod +x juicefs
cp juicefs /usr/libexec/kubernetes/kubelet-plugins/volume/exec/juicedata~juicefs/juicefs

在配置文件中使用明文密钥​

你可以像下面这样定义一个 Flex 卷并使用 juicedata/juicefs 作为驱动:

volumes:
- name: test
flexVolume:
driver: "juicedata/juicefs"
options:
name: "myjfs"
token: "TOKEN"
accesskey: "ACCESSKEY"
secretkey: "SECRETKEY"

你还可以把其他挂载参数加入到 options 里,比如 cacheSize 和 cacheDir 完整的参数列表请参考 juicefs mount -h。

每个 Pod 会使用一个独立的挂载点,跟 Pod 有相同的生命周期。

Kubernetes 密钥管理​

或许你不想把密钥的明文放到 Pod 配置文件中,使用 Kubernetes 的密钥管理可以做到。

apiVersion: v1
kind: Secret
metadata:
name: myjfs
type: juicedata/juicefs
data:
token: BASE64(TOKEN)
accesskey: BASE64(ACCESSKEY)
secretkey: BASE64(SECRETKEY)

用下面的方法可以生成秘密的 base64 编码:

echo -n TOKEN | base64

然后你可以在 Pod 配置文件中使用它:

volumes:
- name: test
flexVolume:
driver: "juicedata/juicefs"
secretRef:
name: “myjfs”
options:
name: "myjfs"

使用 JuiceFS 的配置文件​

不管是使用明文还是 Kubernetes 密钥,Flex 卷都会把它们通过命令行参数的方式传递给驱动,比如:

/usr/libexec/kubernetes/kubelet-plugins/volume/exec/juicedata~juicefs/juicefs mount /var/lib/kubelet/pods/aa8ef19f-ba1f-11e7-ab55-0800279245af/volumes/juicedata~juicefs/test '{"kubernetes.io/fsType":"","kubernetes.io/pod.name":"test","kubernetes.io/pod.namespace":"default","kubernetes.io/pod.uid":"aa8ef19f-ba1f-11e7-ab55-0800279245af","kubernetes.io/pvOrVolumeName":"test","kubernetes.io/readwrite":"rw","kubernetes.io/secret/accesskey":"","kubernetes.io/secret/secretkey":"","kubernetes.io/secret/token":"TOKEN","kubernetes.io/serviceAccount.name":"default","name":"NAME"}'

这样看起来也不是很安全,其他人通过 ps 等方法可以看到密钥明文或者编码后的,通过 JuiceFS 的配置文件(/root/.juicefs/myjfs.conf)我们可以把这些从命令行中隐藏起来,它是一个有如下内容的 JSON 文件:

{"token": "TOKEN", "accesskey": "ACCESSKEY", "secretkey": "SECRETKEY"}

一旦你把这个配置文件部署到所有主机的 /root/.juicefs/myjfs.conf,就不需要在 Pod 配置文件中使用明文或者密码了,如下:

volumes:
- name: test
flexVolume:
driver: "juicedata/juicefs"
options:
name: "NAME"