使用 OCI Connector 以无密方式部署工作负载

在 Kubernetes 集群中,从私有镜像仓库拉取镜像通常需要将仓库凭证分发到各个命名空间,这增加了凭证泄露的风险。

OCI Connector 提供了一种无密解决方案,通过充当仓库的代理,使用户无需在每个命名空间中存储长期密码或机器人令牌即可访问私有仓库,从而最大限度地保障凭证安全。

本指南演示如何使用 OCI Connector 部署需要从私有 OCI 仓库拉取镜像的工作负载。OCI Connector 作为 Kubernetes 集群与 OCI 仓库之间的反向代理,负责身份验证和镜像拉取。

功能概述

使用 OCI Connector 部署工作负载时,请注意以下要点:

  • 要在 Kubernetes 运行时通过 OCI Connector 代理拉取镜像,必须配置 ConnectorOCI 以 NodePort 或 Ingress 方式暴露服务。详细设置请参考安装指南
  • 工作负载中指定的镜像地址会被自动重写为指向 OCI Connector 代理。由于代理使用 HTTP,需配置运行时允许不安全的仓库。
  • OCI Connector 作为 OCI 仓库的反向代理,代表工作负载处理认证和镜像拉取。
  • OCI Connector 代理通过服务账户令牌对客户端进行认证,确保只有授权的工作负载能访问指定的连接器。

前提条件

  • 集群中已安装并运行 ConnectorsCore: 确保 ConnectorsCore 已部署。
  • ConnectorOCI 已安装并对外暴露(NodePort 或 Ingress): 部署 ConnectorOCI 并对外暴露,详情见安装指南
  • 拥有私有 OCI 仓库访问权限: 需具备有效凭证和访问权限。
  • 已配置 kubectl: 确保已安装并配置 kubectl 以访问集群。

借助 OCI Connector,您可以在 Kubernetes 集群中安全地从私有仓库拉取镜像,无需在客户端存储凭证。此方案确保敏感凭证集中管理,且不会暴露给单个工作负载或用户。

OCI Connector 通过安全的集中服务代理身份验证和镜像请求,实现 Pod 的无凭证镜像拉取。

概览

流程包含以下关键步骤:

  1. 创建定义 OCI 仓库连接的 Connector 资源。
  2. 设置认证 Secret。
  3. 创建用于内部认证的 ServiceAccount 令牌。
  4. 配置镜像拉取 Secret。
  5. 部署带有相应注解的工作负载。

操作步骤

第 1 步:创建 Connector

首先,创建演示用命名空间:

kubectl create namespace oci-connector-demo

接着,创建定义 OCI 仓库连接的 Connector 资源,该资源负责管理认证和代理操作。

kubectl apply -n oci-connector-demo -f - <<'EOF'
apiVersion: connectors.alauda.io/v1alpha1
kind: Connector
metadata:
  name: harbor
spec:
  address: https://harbor.example.com # 替换为您的 OCI 仓库地址
  auth:
    name: tokenAuth
    secretRef:
      name: harbor-secret
  connectorClassName: oci
---
apiVersion: v1
stringData: # 替换为实际认证信息
  password: robotsecret
  username: robot$demo
kind: Secret
metadata:
  name: harbor-secret
type: cpaas.io/distribution-registry-token
EOF

建议: 如果您的 OCI 仓库支持,建议使用 robot account 访问仓库,而非 admin 账号。

说明:

  • Connector 资源定义连接参数,包括仓库地址和认证方式
  • Secret 资源安全存储仓库凭证
  • connectorClassName: oci 指定该连接器类型为 OCI
  • 使用 tokenAuth 认证方式进行令牌认证

此时,我们已在命名空间 oci-connector-demo 中创建了一个连接器,且连接器状态为 Ready

$ kubectl get connector.connectors -n oci-connector-demo
NAME     CLASS   ADDRESS                      READY   REASON   AGE
harbor   oci     https://harbor.example.com   True             30s

第 2 步:创建 ServiceAccount 令牌

为命名空间中的默认 ServiceAccount 生成令牌:

$ kubectl create token default -n oci-connector-demo
eyJhbGciOiJSUzI1NiIsImtpZCI6xxxximJ0VNVV_GblYvYy3dg...

该令牌用于通过连接器代理拉取镜像。任何有权限访问连接器的 ServiceAccount 都可用作 Pod 的拉取 Secret。 有关 Connector 资源权限的更多信息,请参见Connector 范围权限

说明:

  • 该令牌用于认证连接器代理的请求
  • 令牌作用域限定在特定命名空间(oci-connector-demo
  • 请妥善保存该令牌,后续步骤将使用

注意: ServiceAccount 令牌有过期时间(默认 1 小时)。可使用 --duration 参数延长有效期。详情见 Kubernetes 文档

第 3 步:创建镜像拉取 Secret

使用 ServiceAccount 令牌创建仓库 Secret:

kubectl create secret docker-registry oci-connector-secret \
  --docker-server="192.168.x.x:31567" \
  --docker-username="u" \
  --docker-password="eyJhbGciOiJSUzI1NiIsImtpZCI6xxxximJ0VNVV_GblYvYy3dg" \
  --docker-email=xxx@xxxx \
  --namespace=oci-connector-demo

说明:

docker-server 指向集群中连接器代理服务地址,可通过连接器状态获取:

$ kubectl get connectors.connector harbor -n oci-connector-demo -o jsonpath='{.status.proxy.httpAddress.url}'
http://192.168.x.x:31567/namespaces/oci-connector-demo/connectors/harbor
  • docker-username 设置为 "u"(占位用户名)
  • docker-password 使用上一步生成的 ServiceAccount 令牌
  • docker-email 可填写任意有效邮箱(用于 CNCF Distribution Registry 兼容)

第 4 步:为 ServiceAccount 添加镜像拉取 Secret

将镜像拉取 Secret 绑定到 ServiceAccount,使使用该 ServiceAccount 的 Pod 自动使用该 Secret 拉取镜像。

kubectl patch serviceaccount default -n oci-connector-demo -p "{\"imagePullSecrets\": [{\"name\": \"oci-connector-secret\"}]}"

说明:

  • 此命令将 oci-connector-secret 添加到默认 ServiceAccount 的 imagePullSecrets 列表
  • 使用该 ServiceAccount 的 Pod 会自动使用此 Secret 拉取镜像
  • 无需在每个 Pod 定义中单独指定 Secret

确保任何使用该 ServiceAccount 的 Pod 都能自动使用此 Secret 进行镜像拉取。

第 5 步:部署工作负载

创建带有必要注解以使用 OCI Connector 的工作负载(此处以 Pod 为例)。

kubectl apply -n oci-connector-demo -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: oci-connector-pod
  annotations:
    connectors.cpaas.io/connector: oci-connector-demo/harbor
  labels:
    connectors.cpaas.io/proxy-inject: "true"
spec:
  containers:
    - name: oci-connector-container
      image: harbor.example.com/oci-connector-demo:v1
  serviceAccountName: default
EOF
  • connectors.cpaas.io/connector 注解指定使用的连接器(格式为 namespace/connector-name)。
  • connectors.cpaas.io/proxy-inject: "true" 标签启用该 Pod 的代理注入。
  • image 字段填写您的原始镜像地址。
  • serviceAccountName: default 确保 Pod 使用带有镜像拉取 Secret 的 ServiceAccount。

第 6 步:验证 Pod 状态

Pod 创建后,可查看 Pod 中镜像地址已被重写为连接器代理地址。

$ kubectl get pod oci-connector-pod -n oci-connector-demo -o jsonpath='{.spec.containers[0].image}'
# 示例输出:
# 192.168.x.x:31567/namespaces/oci-connector-demo/connectors/harbor/oci-connector-demo:v1

然后,检查 Pod 是否运行正常,并通过连接器代理成功拉取镜像:

kubectl get pod oci-connector-pod -n oci-connector-demo

预期输出:

NAME                  READY   STATUS    RESTARTS   AGE
oci-connector-pod     1/1     Running   0          2m

故障排查

常见问题

  1. Pod 卡在 ImagePullBackOff:

    • 确认连接器配置正确且运行正常。
    • 验证 ServiceAccount 令牌有效且未过期。
    • 确认镜像拉取 Secret 已正确绑定到 ServiceAccount。
  2. 认证失败:

    • 检查 harbor-secret 中的仓库凭证是否正确。
    • 确保连接器地址可访问。
    • 验证仓库参数是否与实际仓库匹配。
  3. 代理注入无效:

    • 确认存在 connectors.cpaas.io/proxy-inject: "true" 标签。
    • 检查连接器注解格式是否正确。
    • 确认连接器存在于指定命名空间。

验证命令

# 查看连接器状态
kubectl get connector.connectors harbor -n oci-connector-demo

# 验证 Secret 是否存在
kubectl get secret oci-connector-secret -n oci-connector-demo

# 查看 ServiceAccount 配置
kubectl get serviceaccount default -n oci-connector-demo -o yaml

# 查看 Pod 事件以排查问题
kubectl describe pod oci-connector-pod -n oci-connector-demo

总结

至此,您已完成使用 OCI Connector 以无密方式部署工作负载的全过程。该方案通过集中管理凭证,消除向单个工作负载分发敏感信息的需求,从而提升安全性。