> For the complete documentation index, see [llms.txt](https://documentation.alluxio.io/ee-ai-cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.alluxio.io/ee-ai-cn/start/installing-on-kubernetes/oci-oke.md).

# OCI OKE

本页介绍在已有的 Oracle Cloud Infrastructure Kubernetes Engine (OKE) 集群上部署 Alluxio 时，与 OCI 相关的差异。通用的 Operator 与集群安装流程见 [Kubernetes 安装](/ee-ai-cn/start/installing-on-kubernetes.md)。

## 概览

OKE 上部署 Alluxio 相较通用 Kubernetes 安装，有三处差异：

* **镜像仓库**。镜像推送到 OCI Container Registry (OCIR)。OCIR 使用 **Auth Token** 鉴权——与其他所有 OCI CLI 调用使用的 API Key 不同。
* **Worker 存储**。通用型 OCI 机型（例如 VM.Standard.E5.Flex）在系统和容器运行时之后，启动盘只剩 \~36 GiB 可用，所以 page store 使用 `emptyDir`（或默认的 `hostPath`），容量 cap 在 \~30 GiB。DenseIO 机型有本地 NVMe，可把 `hostPath` 指向 NVMe 挂载点，容量更大且 Pod 重启后缓存保留。多 Worker 部署**不能**用 `oci-bv` PVC——单个 RWO 卷无法被多个副本共享。
* **Load Balancer 注解**。OCI Service LB 默认是公网；需要 OCI 专用注解在 Kubernetes `Service` 上启用内部 LB。

OCI Object Storage 作为 UFS 的挂载在 [S3 兼容存储 → Oracle Cloud Infrastructure (OCI) object storage](/ee-ai-cn/ufs/s3-compatible.md#oracle-yun-ji-chu-she-shi-oci-dui-xiang-cun-chu) 中已有说明，本页不再重复。Alluxio EE 不支持 `oci://` scheme——OCI Object Storage 必须通过 S3 兼容端点挂载。

下文示例全部使用 `us-phoenix-1`（OCIR 别名 `phx.ocir.io`）。请根据您订阅的区域调整。

## 开始之前

下列检查是**附加于** [通用 Kubernetes 先决条件](/ee-ai-cn/start/installing-on-kubernetes.md#kai-shi-zhi-qian)之上的 OCI 专项。OKE 集群本身的开通不在本页范围内，请参考 [OKE 官方文档](https://docs.oracle.com/en-us/iaas/Content/ContEng/home.htm)。

* [ ] **OKE 集群可达：**

  ```shell
  kubectl cluster-info
  kubectl get nodes
  ```
* [ ] **`oci-bv` StorageClass 存在**（新版 OKE 集群默认已安装）：

  ```shell
  kubectl get storageclass oci-bv
  ```
* [ ] **CLI 工具已安装：**

  ```shell
  brew install oci-cli kubectl helm skopeo jq          # macOS；Linux 自行调整
  ```
* [ ] **OCI API Key 已配置：**

  ```shell
  oci setup config
  oci iam user get --user-id "$OCI_USER_OCID"          # 必须成功
  ```
* [ ] **OCIR Auth Token 已生成**（OCI Console → User → Auth Tokens——与 API Key 不是同一个凭证）
* [ ] **Alluxio 软件包已备齐：** Operator 镜像 `.tar`、Alluxio 镜像 `.tar`、Helm Chart `.tgz`、License

{% hint style="warning" %}
**解除 passphrase 保护的 API Key**。如果 `oci setup config` 给私钥加了 passphrase，CLI 每次调用都会交互式询问，无法用于自动化：

```shell
openssl rsa -in ~/.oci/oci_api_key.pem -out ~/.oci/oci_api_key.pem.dec
mv  ~/.oci/oci_api_key.pem.dec ~/.oci/oci_api_key.pem
chmod 600 ~/.oci/oci_api_key.pem
```

{% endhint %}

## 环境变量

```shell
export OCI_REGION=us-phoenix-1
export OCIR_HOST=phx.ocir.io                          # 区域别名；见 OCIR 文档
export OCI_TENANCY_OCID=ocid1.tenancy.oc1..xxxx
export OCI_USER_OCID=ocid1.user.oc1..xxxx
export OCI_OCIR_NAMESPACE=$(oci os ns get --region "$OCI_REGION" --query 'data' --raw-output)

export ALLUXIO_IMAGE_REPO="${OCIR_HOST}/${OCI_OCIR_NAMESPACE}/alluxio-ee"
export ALLUXIO_IMAGE_TAG=AI-3.9-16.0.0

export OCIR_AUTH_TOKEN='<auth-token-from-console>'
```

## 安装步骤

### 1. 推送 Alluxio 镜像到 OCIR

{% hint style="warning" %}
**OCIR 不接受 API Key 作为推送凭证**。必须使用 Auth Token。`~/.oci/config` 中的 API Key 用于其他所有 OCI CLI 调用，但不能用于 OCIR 镜像推送。
{% endhint %}

拼接 OCIR 登录信息并用 `skopeo` 推送（无需本地 Docker daemon）：

```shell
OCIR_USER=$(oci iam user get --user-id "$OCI_USER_OCID" --query 'data.name' --raw-output)
OCIR_LOGIN="${OCI_OCIR_NAMESPACE}/${OCIR_USER}"

echo "$OCIR_AUTH_TOKEN" | skopeo login "$OCIR_HOST" -u "$OCIR_LOGIN" --password-stdin

# Alluxio 镜像
skopeo copy \
  --dest-tls-verify=true \
  "docker-archive:alluxio-enterprise-AI-3.9-16.0.0-linux-amd64-docker.tar" \
  "docker://${ALLUXIO_IMAGE_REPO}:${ALLUXIO_IMAGE_TAG}"

# Operator 镜像
skopeo copy \
  --dest-tls-verify=true \
  "docker-archive:alluxio-operator-3.6.1-linux-amd64-docker.tar" \
  "docker://${OCIR_HOST}/${OCI_OCIR_NAMESPACE}/alluxio-operator:3.6.1"
```

{% hint style="info" %}
如果 OCI 账号启用了 Identity Domain（联邦身份），登录用户名为 `<namespace>/oracleidentitycloudservice/<user-email>`。
{% endhint %}

**✅ 成功：** 两个镜像出现在 OCI Console → Developer Services → Container Registry。

### 2. 创建 ImagePull Secret

每个从 OCIR 拉取镜像的 Pod 都需要一个 `docker-registry` Secret。在每个需要拉取镜像的命名空间下创建：

```shell
kubectl create namespace alx-ns
kubectl -n alx-ns create secret docker-registry ocir-pull \
  --docker-server="$OCIR_HOST" \
  --docker-username="$OCIR_LOGIN" \
  --docker-password="$OCIR_AUTH_TOKEN"

kubectl create namespace alluxio-operator
kubectl -n alluxio-operator create secret docker-registry ocir-pull \
  --docker-server="$OCIR_HOST" \
  --docker-username="$OCIR_LOGIN" \
  --docker-password="$OCIR_AUTH_TOKEN"
```

### 3. 使用 OCI 专用值部署 Alluxio

此后按通用的 [Kubernetes 安装](/ee-ai-cn/start/installing-on-kubernetes.md) 指南，**从 Step 1 — Prepare Helm Chart 开始**。上面的第 1 节替代了通用指南的 Step 0（把镜像推送到私有仓库）。

编写 `alluxio-operator.yaml` 和 `alluxio-cluster.yaml` 时请应用下面的 OCI 专用配置。

**Operator 配置（`alluxio-operator.yaml`）：**

```yaml
global:
  image: phx.ocir.io/<OCIR_NAMESPACE>/alluxio-operator
  imageTag: 3.6.1
  imagePullSecrets:
    - ocir-pull
```

**Cluster 镜像与 pull secret（`alluxio-cluster.yaml`）：**

```yaml
spec:
  image: phx.ocir.io/<OCIR_NAMESPACE>/alluxio-ee
  imageTag: AI-3.9-16.0.0
  imagePullSecrets:
    - ocir-pull
```

**Worker page store——先规划节点本地存储，再把 `hostPath` 指向它。**

Alluxio Worker 的缓存容量受限于每个 Worker Pod 可用的节点本地存储。OKE 上，在设置 `pagestore` 大小之前，先从以下方案中选**一种**进行节点存储规划：

* **DenseIO 机型**（BM.DenseIO.E5、VM.DenseIO2 等）自带高带宽本地 NVMe，是生产级 ML 工作负载的推荐机型。把 NVMe 挂载到节点的 `/mnt/alluxio/pagestore`，使用默认的 `hostPath` page store。
* **通用型机型 + 扩大启动盘**（VM.Standard.E5.Flex 在创建 Node Pool 时把 `bootVolumeSizeInGBs` 调大，例如 500–2000 GiB）。启动盘扩容后，`hostPath` 就有足够空间承载实际工作集。
* **通用型机型 + 每节点挂一块块存储卷**——用 Terraform、cloud-init 或 DaemonSet 为每个 Worker 节点额外挂一块 OCI Block Volume，格式化后挂载到 `/mnt/alluxio/pagestore`，再用 `hostPath`。每个节点独占自己的卷，不存在 RWO 共享问题。

然后把 page store 大小设成上面规划的容量：

```yaml
spec:
  worker:
    count: 3
    pagestore:
      # hostPath 是默认，对应节点的 /mnt/alluxio/pagestore。
      # size 请匹配上面规划的存储容量。
      size: 500Gi
      reservedSize: 50Gi
```

{% hint style="warning" %}
**不要使用 `pagestore.type: persistentVolumeClaim` + `oci-bv`**。`oci-bv` 是 `ReadWriteOnce` StorageClass；Alluxio Chart 会把所有 Worker 副本指向同一个 PVC，只有一个副本能 mount 成功，其余 `Pending`。请使用节点本地存储（`hostPath` 或 `emptyDir`）。
{% endhint %}

{% hint style="info" %}
**评估用简化方案。** OKE 默认的 E5.Flex 启动盘为 \~46 GiB（可用 \~36 GiB）。如果只是评估阶段，可接受小而短暂的缓存，可直接用 `pagestore.type: emptyDir` + `size: 30Gi`，无需额外存储规划。**不适合生产**——每次 Pod 重启缓存都从 UFS 重建。
{% endhint %}

**S3 Gateway 使用内部 Load Balancer**。OCI Service LB 默认为公网；把服务流量保持在 VCN 内部：

```yaml
spec:
  gateway:
    service:
      type: LoadBalancer
      annotations:
        oci.oraclecloud.com/load-balancer-type: "lb"
        service.beta.kubernetes.io/oci-load-balancer-internal: "true"
```

`helm upgrade --install` 完成后，OCI 大约 60–90 秒后完成 LB 开通。查看其内部 IP：

```shell
kubectl -n alx-ns get svc alluxio-cluster-s3gateway \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
```

### 4. 访问集群

步骤 3 创建的 Service LB 位于 VCN 内部。两种常见访问方式：

**方案 A —— 从管理员工作站 `kubectl port-forward`：**

```shell
kubectl -n alx-ns port-forward svc/alluxio-cluster-s3gateway 39999:39999
aws s3 --endpoint-url http://localhost:39999 ls s3://<bucket>/

kubectl -n alx-ns port-forward svc/alluxio-cluster-coordinator 19999:19999
# 访问 http://localhost:19999 打开 Alluxio Web UI
```

**方案 B —— 通过 VCN 内的 Bastion VM 建立 SSH 隧道：**

```shell
ssh -f -N -L 39999:<s3gw-internal-lb-ip>:39999 ubuntu@<bastion-ip>
ssh -f -N -L 3000:<grafana-internal-lb-ip>:80 ubuntu@<bastion-ip>
```

方案 A 无需额外 VM；方案 B 为团队提供可复用的 URL。

## 卸载

按通用的 [Kubernetes 安装 → 卸载](/ee-ai-cn/start/installing-on-kubernetes.md#xie-zai) 流程完成后，再清除 OCIR ImagePull Secret：

```shell
kubectl -n alx-ns delete secret ocir-pull
kubectl -n alluxio-operator delete secret ocir-pull
```

OCI 基础设施（VCN、OKE 集群、Node Pool）单独管理——清理请参考 [OKE 官方文档](https://docs.oracle.com/en-us/iaas/Content/ContEng/home.htm)。推到 OCIR 的 Alluxio 镜像可保留——下次部署可直接复用。

## 故障排查

#### 现象：OCIR `skopeo login` 或 push 返回 `unauthorized`

**可能原因：** 使用的是 API Key 口令而非 Auth Token。

**修复：** 在 OCI Console → User → Auth Tokens 生成 Auth Token，导出为 `OCIR_AUTH_TOKEN` 后重新 `skopeo login`。API Key 可用于 `oci` CLI 调用，但不能用于 OCIR 镜像推送。

#### 现象：OCIR 登录成功，但 `skopeo copy` 报 `denied: requested access to the resource is denied`

**可能原因：** 用户账号没有目标 compartment 的 `manage repos` 权限，或仓库路径错误。

**诊断：**

```shell
oci iam compartment list --compartment-id "$OCI_TENANCY_OCID" --query 'data[].name'
```

确认目标 compartment，然后检查该用户所在 group 的 IAM 策略是否包含 `Allow group <g> to manage repos in compartment <c>`。

**修复：** 授予该策略，或推送到您有权限的 compartment。OCIR 仓库名区分大小写。

#### 现象：OCIR 用户名被拒绝

**可能原因：** 联邦账号的登录格式错误，Identity Domain tenancy 需要额外一段路径。

**修复：** 非联邦用户使用 `<namespace>/<user-email>`。启用 Identity Domain（联邦）时使用 `<namespace>/oracleidentitycloudservice/<user-email>`。

#### 现象：Worker Pod `Pending`，PVC 也卡在 `Pending`

**可能原因：** 没有 `oci-bv` StorageClass，或 OKE 版本过旧未包含 OCI Block Volume CSI Driver。

**诊断：**

```shell
kubectl get storageclass
kubectl get pods -n kube-system -l app.kubernetes.io/name=oci-csi-node
```

**修复：** 为您的 OKE 集群安装或启用 OCI Block Volume CSI Add-on。详见 [OKE Block Volume CSI 文档](https://docs.oracle.com/en-us/iaas/Content/ContEng/Tasks/contengcreatingpvcondifferentstorageoptions.htm)。

#### 现象：Worker Pod CrashLoopBackOff，日志报 "quota exceeds total disk space"

**可能原因：** `pagestore.size` 超过了 Worker Pod 可用的节点本地存储。OKE 默认启动盘 \~46 GiB（可用 \~36 GiB），任何超过 \~36 GiB 的 `pagestore.size` 都会失败。

**修复：** 按 §3 规划更大的节点本地存储——扩大 Node Pool 的 `bootVolumeSizeInGBs`、挂接独立 Block Volume，或切换到 DenseIO 机型——再把 `pagestore.size` 设为该容量（`reservedSize` 留 10% 余量）。评估场景下可把 `pagestore.size` cap 在 30 GiB，使用默认启动盘。

#### 现象：只有一个 Worker 启动，其他 Worker 卡在 `Pending` 并报 `Multi-Attach error for volume`

**可能原因：** `pagestore.type: persistentVolumeClaim` 配合 `oci-bv` 这种 RWO StorageClass。Worker 副本共享同一个卷，OCI 只允许一个节点挂载。

**修复：** 改用 `pagestore.type: emptyDir`（见 §3）。OKE 上块存储设备一般没有 RWX 能力。

#### 现象：内置 etcd Pod 卡在 `ImagePullBackOff`

**可能原因：** Helm chart 自带的 etcd 镜像拉不到。最近的常见情况：`docker.io/bitnami/etcd` 镜像被下架，导致 Alluxio chart 默认路径不工作。

**诊断：**

```shell
kubectl -n alx-ns describe pod alluxio-cluster-etcd-0 | grep -A3 Events
```

查找 `manifest unknown` 或 `repository does not exist`。

**修复：** 改用外部 etcd 集群，禁用内置 etcd 并显式指定 endpoint——详见 [Kubernetes 安装 — B.3. 使用外部 ETCD](https://documentation.alluxio.io/ee-ai-cn/start/installing-on-kubernetes/pages/9bxv6yM8Fd3fkHo8BnW1#b.3.-shi-yong-wai-bu-etcd)。

#### 现象：UFS 写入 OCI Object Storage 返回 HTTP 501 "AWS chunked encoding not supported"

**可能原因：** OCI 的 S3 兼容 API 不支持 AWS SDK v2 的 chunked transfer encoding，而 Alluxio 默认使用 SDK v2。

**修复：** UFS 挂载时设置 `alluxio.underfs.s3.sdk.version=1`。完整的属性清单见 [S3 兼容存储 → Oracle Cloud Infrastructure (OCI) object storage](/ee-ai-cn/ufs/s3-compatible.md#oracle-yun-ji-chu-she-shi-oci-dui-xiang-cun-chu)。

#### 现象：S3 Gateway `Service` 的 `EXTERNAL-IP` 长时间 `<pending>`

**可能原因：** OKE 集群创建时没有指定 `service-lb-subnet`，或该子网 IP 耗尽。

**诊断：**

```shell
kubectl -n alx-ns describe svc alluxio-cluster-s3gateway | grep -A2 Events
```

查找与子网或 NSG 相关的 OCI LB 开通错误。

**修复：** 确保集群的 Service LB 子网有空闲 IP，并放通 Gateway 端口。如需更换 Service LB 子网，需重建 OKE 集群，指定 `--service-lb-subnet-ids`。

## 相关文档

* [Kubernetes 安装](/ee-ai-cn/start/installing-on-kubernetes.md) —— 通用的 Operator 和集群安装步骤
* [S3 兼容存储](/ee-ai-cn/ufs/s3-compatible.md#oracle-yun-ji-chu-she-shi-oci-dui-xiang-cun-chu) —— 通过 S3 兼容 API 挂载 OCI Object Storage
* [先决条件](/ee-ai-cn/start/prerequisites.md) —— 硬件、网络端口、资源规格和 etcd 要求
* [Worker 配置](/ee-ai-cn/administration/managing-worker.md) —— Page store 容量规划、JVM 调优和存储布局
