# 在Kubernetes上安装Alluxio

本文档展示了如何通过 [Operator](https://kubernetes.io/zh-cn/docs/concepts/extend-kubernetes/operator/)（Kubernetes 管理应用程序的扩展）在 Kubernetes 上安装 Alluxio。

## 准备工作

有关资源规划建议，请参阅[资源需求和兼容性](../prerequisites)。

假定 Kubernetes 集群可访问 Alluxio 和第三方组件所需的容器镜像。

有关如何从提供的 tarball 软件包中提取和上传 Alluxio 镜像的说明，以及在 Kubernetes 集群无法访问公共镜像存储库的情况下需要上传哪些第三方镜像，请参阅 [处理镜像](handling-images)。

**提取 Operator 的 Helm 图表**

将 Operator 的 Helm 图表 tarball 下载到可访问正在运行的 Kubernetes 集群并进行部署的位置。

```console
# 以下命令将会将文件解压缩到 alluxio-operator/ 目录
$ tar zxf alluxio-operator-3.2.1-helmchart.tgz
```

提取出的 `alluxio-operator` 目录包含用于部署 Operator 的 Helm 图表文件。

## 部署

### 部署 Alluxio operator

创建 `alluxio-operator/alluxio-operator.yaml` 文件指定镜像和版本，用于部署 operator。 以下示例展示了如何指定 `operator` 镜像和版本：

```yaml
global:
  image: <PRIVATE_REGISTRY>/alluxio-operator
  imageTag: 3.2.1
```

进入到 `alluxio-operator` 目录，执行以下命令部署 operator：

```console
$ cd alluxio-operator
# 最后一个参数表示是 helm chart 文件的路径，"." 表示当前目录
$ helm install operator -f alluxio-operator.yaml .
NAME: operator
LAST DEPLOYED: Wed May 15 17:32:34 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

# 确认 operator 是否正常运行
$ kubectl -n alluxio-operator get pod
NAME                                              READY   STATUS    RESTARTS   AGE
alluxio-cluster-controller-5647cc664d-lrx84       1/1     Running   0          14s
alluxio-collectinfo-controller-667b746fd6-hfzqk   1/1     Running   0          14s
alluxio-csi-controller-7bd66df6cf-7kh6k           2/2     Running   0          14s
alluxio-csi-nodeplugin-9cc9v                      2/2     Running   0          14s
alluxio-csi-nodeplugin-fgs5z                      2/2     Running   0          14s
alluxio-csi-nodeplugin-v22q6                      2/2     Running   0          14s
alluxio-ufs-controller-5f6d7c4d66-drjgm           1/1     Running   0          14s
```

> 部署 alluxio operator 需要从公共镜像仓库拉取依赖镜像， 如果您因为网络环境无法访问公共镜像仓库导致部署 `alluxio-operator` 失败， 请参考[配置 alluxio-operator 镜像](#配置-alluxio-operator-镜像)。

### 部署 Alluxio

创建 `alluxio-operator/alluxio-cluster.yaml` 文件以部署 Alluxio 集群。\
以下文件展示了最低配置，建议用于测试场景。

```yaml
apiVersion: k8s-operator.alluxio.com/v1
kind: AlluxioCluster
metadata:
  name: alluxio-cluster
  namespace: alx-ns
spec:
  image: <PRIVATE_REGISTRY>/alluxio-enterprise
  imageTag: AI-3.6-12.0.2
  properties:

  worker:
    count: 2
    pagestore:
      size: 100Gi
      reservedSize: 10Gi
```

上述提供的最低配置可帮助您快速部署 Alluxio 集群以进行测试和验证。

在预期会有重启的生产环境中，我们建议使用标签（labels）和选择器（selectors）部署 Alluxio 集群，并在PVCs上持久化信息。

选择一组 Kubernetes 节点来运行 Alluxio 集群，并为节点添加相应标签：

```console
kubectl label nodes <node-name> alluxio-role=coordinator
kubectl label nodes <node-name> alluxio-role=worker
```

以下配置是适用于生产场景的起始模板，其中添加了 `nodeSelector` 和 `metastore` 字段。

```yaml
apiVersion: k8s-operator.alluxio.com/v1
kind: AlluxioCluster
metadata:
  name: alluxio-cluster
  namespace: alx-ns
spec:
  image: <PRIVATE_REGISTRY>/alluxio-enterprise
  imageTag: AI-3.6-12.0.2
  properties:

  coordinator:
    nodeSelector:
      alluxio-role: coordinator
    metastore:
      type: persistentVolumeClaim
      storageClass: "gp2"
      size: 4Gi
    
  worker:
    nodeSelector:
      alluxio-role: worker
    count: 2
    pagestore:
      size: 100Gi
      reservedSize: 10Gi
```

切换到 `alluxio-operator` 目录并执行以下命令来部署 Alluxio 集群：

```console
$ cd alluxio-operator
$ kubectl create namespace alx-ns
$ kubectl create -f alluxio-cluster.yaml
alluxiocluster.k8s-operator.alluxio.com/alluxio-cluster created

# 集群此时开始启动
$ kubectl -n alx-ns get pod
NAME                                          READY   STATUS              RESTARTS   AGE
alluxio-cluster-coordinator-0                 0/1     Init:0/1            0          7s
alluxio-cluster-etcd-0                        0/1     ContainerCreating   0          7s
alluxio-cluster-etcd-1                        0/1     ContainerCreating   0          7s
alluxio-cluster-etcd-2                        0/1     ContainerCreating   0          7s
alluxio-cluster-grafana-847fd46f4b-84wgg      0/1     Running             0          7s
alluxio-cluster-prometheus-778547fd75-rh6r6   1/1     Running             0          7s
alluxio-cluster-worker-76c846bfb6-2jkmr       0/1     Init:0/2            0          7s
alluxio-cluster-worker-76c846bfb6-nqldm       0/1     Init:0/2            0          7s

# 检查集群的状态
$ kubectl -n alx-ns get alluxiocluster
NAME              CLUSTERPHASE   AGE
alluxio-cluster   Ready          2m18s

# 同时可以检查集群就绪后正在运行的 pod
$ kubectl -n alx-ns get pod
NAME                                          READY   STATUS    RESTARTS   AGE
alluxio-cluster-coordinator-0                 1/1     Running   0          2m3s
alluxio-cluster-etcd-0                        1/1     Running   0          2m3s
alluxio-cluster-etcd-1                        1/1     Running   0          2m3s
alluxio-cluster-etcd-2                        1/1     Running   0          2m3s
alluxio-cluster-grafana-7b9477d66-mmcc5       1/1     Running   0          2m3s
alluxio-cluster-prometheus-78dbb89994-xxr4c   1/1     Running   0          2m3s
alluxio-cluster-worker-85fd45db46-c7n9p       1/1     Running   0          2m3s
alluxio-cluster-worker-85fd45db46-sqv2c       1/1     Running   0          2m3s
```

在 Alluxio 3.x 中，Coordinator是无状态的控制组件，充当整个集群的接口，例如处理分布式负载等任务。

> 如果集群中的某些组件未能进入 `Running` 状态，您可以使用 `kubectl describe pod` 命令查看详细信息并定位问题。\
> 针对部署过程中遇到的具体问题，请参考常见问题解答[FAQ](#chang-jian-wen-ti)部分。

> Alluxio 集群还包含 etcd 和监控组件。\
> 如果无法从公共镜像仓库拉取镜像导致 etcd 或监控组件启动失败，请参考[配置 Alluxio 集群镜像](#pei-zhi-alluxio-ji-qun-jing-xiang)

### 将存储挂载到Alluxio

Alluxio 支持与多种底层存储系统集成，包括 [S3](#s3)、[HDFS](../../ufs/hdfs)、[OSS](#oss)、[COS](#cos) 和 [TOS](../../ufs/tos)。\\

通过使用 Operator，你可以通过创建`UnderFileSystem`资源来挂载底层存储。\
一个`UnderFileSystem`对应 Alluxio 的一个挂载点。\
关于 Alluxio 与底层存储的命名空间关系，请参考 [Alluxio 命名空间与底层文件系统命名空间](../../overview/namespace)文档。\\

创建 `alluxio-operator/ufs.yaml` 文件，用于指定 UFS 的配置。\
以下示例展示了如何将一个 S3 桶挂载到 Alluxio。

```yaml
apiVersion: k8s-operator.alluxio.com/v1
kind: UnderFileSystem
metadata:
  name: alluxio-s3
  namespace: alx-ns
spec:
  alluxioCluster: alluxio-cluster
  path: s3://<S3_BUCKET>/<S3_DIRECTORY>
  mountPath: /s3
  mountOptions:
    s3a.accessKeyId: <S3_ACCESS_KEY_ID>
    s3a.secretKey: <S3_SECRET_KEY>
    alluxio.underfs.s3.region: <S3_REGION>
```

关于挂载S3到Alluxio中，请在[Amazon AWS S3](../../ufs/s3)中寻找更多细节。

#### 执行挂载

首先，请确保 Alluxio 集群已启动运行，并处于 `Ready` 或 `WaitingForReady` 状态。

```console
# 检查集群的状态
$ kubectl -n alx-ns get alluxiocluster
NAME              CLUSTERPHASE   AGE
alluxio-cluster   Ready          2m18s
```

执行以下命令以创建 `UnderFileSystem` 资源，并将其挂载到 Alluxio 命名空间：

```console
$ cd alluxio-operator
$ kubectl create -f ufs.yaml
underfilesystem.k8s-operator.alluxio.com/alluxio-s3 created

# 验证挂载的状态
$ kubectl -n alx-ns get ufs
NAME         PHASE   AGE
alluxio-s3   Ready   46s

# 同时可以使用 Alluxio 的命令行来检查挂载结果
$ kubectl -n alx-ns exec -it alluxio-cluster-coordinator-0 -- alluxio mount list 2>/dev/null
Listing all mount points
s3://my-bucket/path/to/mount  on  /s3/ properties={s3a.secretKey=xxx, alluxio.underfs.s3.region=us-east-1, s3a.accessKeyId=xxx}
```

## 监控

部署 Alluxio 集群默认开启监控，通过 Grafana 可以直观地查看 Alluxio 各种指标， 请参考[监控和指标](../../monitoring-and-metrics#kubernetes-operator)中的 Kubernetes Operator 章节。

## 数据访问加速

上述步骤中，您部署了 Alluxio 集群，并将底层存储挂载到 Alluxio 中。训练任务通过 Alluxio 读取数据，可以提升训练速度和 GPU 利用率。 Alluxio 提供了3种数据访问方式：

* **基于FUSE 的 POSIX API**: 请参考[基于FUSE 的POSIX API](../../data-access/fuse-based-posix-api).
* **S3 API**: 请参考 [S3 API](../../data-access/s3-api).
* **FSSpec Python API**: 请参考 [FSSPEC Python API](../../data-access/fsspec).

## 常见问题

### etcd pod 一直处于 Pending 状态

比如三个 etcd pod 一直处于 Pending 状态，可以通过 `kubectl describe pod` 查看详细信息：

```
# 查看 pod 状态
kubectl -n alx-ns get pod

NAME                                          READY   STATUS     RESTARTS   AGE
alluxio-cluster-coordinator-0                 0/1     Init:1/2   0          73s
alluxio-cluster-etcd-0                        0/1     Pending    0          73s
alluxio-cluster-etcd-1                        0/1     Pending    0          73s
alluxio-cluster-etcd-2                        0/1     Pending    0          73s
alluxio-cluster-grafana-79db8c7dd9-lsq2l      1/1     Running    0          73s
alluxio-cluster-prometheus-7c6cbc4b4c-9nk25   1/1     Running    0          73s
alluxio-cluster-worker-8c79d5fd4-2c994        0/1     Init:1/2   0          73s
alluxio-cluster-worker-8c79d5fd4-jrchj        0/1     Init:1/2   0          73s

# 查看 etcd pod 的详细信息
kubectl -n alx-ns describe pod alluxio-cluster-etcd-0

Events:
  Type     Reason            Age    From               Message
  ----     ------            ----   ----               -------
  Warning  FailedScheduling  3m57s  default-scheduler  0/3 nodes are available: pod has unbound immediate PersistentVolumeClaims. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling., .

# 查看集群中的 pvc 状态
# 如果发现 etcd 的 pvc 一直处于 Pending 状态（alluxio-fuse 处于 Pending 状态是正常现象），可进一步查看情况
kubectl -n alx-ns get pvc

NAME                          STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS                  AGE
alluxio-cluster-fuse          Pending                                      alx-ns-alluxio-cluster-fuse   5m31s
data-alluxio-cluster-etcd-0   Pending                                                                    3h41m
data-alluxio-cluster-etcd-1   Pending                                                                    3h41m
data-alluxio-cluster-etcd-2   Pending                                                                    3h41m

# 查看 PVC 描述
kubectl -n alx-ns describe pvc data-alluxio-cluster-etcd-0

Events:
  Type    Reason         Age                      From                         Message
  ----    ------         ----                     ----                         -------
  Normal  FailedBinding  4m16s (x889 over 3h44m)  persistentvolume-controller  no persistent volumes available for this claim and no storage class is set
```

根据错误信息可知，etcd Pod 处于 Pending 状态的原因是未设置 storage class。可通过在 `alluxio-operator/alluxio-cluster.yaml` 文件中指定 etcd 的storage class 来解决。

```yaml
  etcd:
    persistence:
      storageClass: <STORAGE_CLASS>
      size: 
```

我们需要先删除 Alluxio 集群, 并且删除 etcd 的 pvc，然后重新创建 Alluxio 集群：

```console
# 删除 Alluxio 集群
$ kubectl delete -f alluxio-operator/alluxio-cluster.yaml

# 删除 etcd 的 pvc
$ kubectl -n alx-ns delete pvc data-alluxio-cluster-etcd-0
$ kubectl -n alx-ns delete pvc data-alluxio-cluster-etcd-1
$ kubectl -n alx-ns delete pvc data-alluxio-cluster-etcd-2

# 重新创建 Alluxio 集群
$ kubectl create -f alluxio-operator/alluxio-cluster.yaml
```

另外一种情况是 etcd pvc 指定了 storage class，但是 etcd pod 和 pvc 依然是 pending 状态。例如下面的 pvc 详细信息中所展示， etcd pvc 指定的 storage class 不支持动态制备，存储卷需要由集群管理员手动创建。

```console
# 查看 etcd pvc 的详细信息
kubectl -n alx-ns describe pvc data-alluxio-cluster-etcd-0

Events:
  Type    Reason                Age               From                         Message
  ----    ------                ----              ----                         -------
  Normal  WaitForFirstConsumer  25s               persistentvolume-controller  waiting for first consumer to be created before binding
  Normal  ExternalProvisioning  8s (x3 over 25s)  persistentvolume-controller  Waiting for a volume to be created either by the external provisioner 'none' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.
```

类似的 etcd pod 一直处于 Pending 状态的问题，可以通过上述方法进行排查。

### alluxio-cluster-fuse PVC 一直处于 Pending 状态

当我们创建集群之后，发现`alluxio-cluster-fuse` 一直处于 `Pending` 状态， 这是正常现象。当 alluxio-cluster-fuse 被业务 pod 使用时，pvc 会自动绑定 pv，pvc 的状态会变为 `Bound`。
