边缘集群部署 - 云端部署 CubeStudio 与 CloudCore

云端 K8s/NFS 已就绪后,在云端部署 CubeStudio 控制面并装 KubeEdge CloudCore 时读这篇(云-边主线 Phase C/D)

02-部署安装 / 部署方式 / 边缘集群
cube-studiostart.shconfig.pyCONTAINER_CLInerdctlhubsecretccristio-ingressgatewayexternalIPsCloudCorekeadm initdynamicControllerrequireAuthorizationvgpu-hami

边缘集群部署 - 云端部署 CubeStudio 与 CloudCore

本篇对应云-边主线的 Phase C(云端部署 CubeStudio)Phase D(云端 CloudCore / KubeEdge)。承接 03-云端环境准备-K8s与NFS

来源:docs/部署/kubeedge部署边缘集群cube-studio.md 第 4~5 节。


四、Phase C:云端部署 cube-studio

C.1 代码上传

# 本地(Mac)打包 install/kubernetes(含 kustomize/cube 等)
tar -czf /tmp/cube-k8s.tar.gz -C install kubernetes
scp /tmp/cube-k8s.tar.gz root@47.114.127.214:/root/

# 云端解压
mkdir -p /root/cube-studio && cd /root/cube-studio
tar -xzf /root/cube-k8s.tar.gz

C.2 改 config.py & start.sh

cd /root/cube-studio/kubernetes

# config.py:CubeStudio 调用容器 CLI,统一成 nerdctl
sed -i 's|^CONTAINER_CLI=.docker.|CONTAINER_CLI="nerdctl"|' cube/overlays/config/config.py

# kubeconfig 给 CubeStudio 用
cp /etc/kubernetes/admin.conf config
mkdir -p kubeconfig && cp /etc/kubernetes/admin.conf kubeconfig/dev-kubeconfig

CONTAINER_CLI 默认值是 docker(见 myapp/config.py:1110,注释写明可选 docker / nerdctl)。本场景没装 docker、用 containerd+nerdctl,所以改成 nerdctl

三处 patch(否则 start.sh 会卡住或报语法错):

  1. 跳过 kubectl 重下载(已装 v1.28):把 start.sh 第 15/17 行的 wget -O kubectl ... 注释掉。必须同时在 if/fi 里加一行 true,否则空 if 体会报 syntax error near unexpected token 'fi'
    if [ "$ARCH" = "x86_64" ]; then
    # #   wget -O kubectl ...
    # # elif [ "$ARCH" = "aarch64" ]; then
    # #   wget -O kubectl ...
      true   # ← 必须加,否则 bash 语法错
    fi
    

    已核实:install/kubernetes/start.sh:15,17 确为 wget -O kubectl https://cube-studio.oss-cn-hangzhou.aliyuncs.com/install/kubectl-amd64-1.28(与 arm64 版)。

  2. node 标签查找改 fallback:原脚本 node=$(kubectl get node -o wide | grep $1 ...),传入的是公网 IP,grep 匹配不到内网 IP 的节点。改为:
    node=$(kubectl get node -o name | head -n 1 | sed 's|node/||')
    
  3. 跳过 docker 镜像预拉init_node.shsh pull_images_mini.shdocker pull(没装 docker),改成:
    # sh pull_images_mini.sh
    echo SKIP pull_images_mini  # 用 containerd 懒拉
    

C.3 跑 start.sh

cd /root/cube-studio/kubernetes
nohup bash start.sh 47.114.127.214 > /root/start.log 2>&1 &
tail -f /root/start.log

C.4 修 ccr 私有镜像鉴权

create_ns_secret.shxxx/xxx 占位凭证创建 hubsecretccr.ccs.tencentyun.com 私有镜像会 401 拉失败。

已核实:install/kubernetes/create_ns_secret.sh:7 确为 kubectl create secret docker-registry hubsecret --docker-server=ccr.ccs.tencentyun.com --docker-username=xxx --docker-password=xxx,需替换成真实凭证。

获取正确凭证后(若旧环境上已有 /root/.docker/config.json,可解 base64 取 username:password),批量重建各命名空间的 hubsecret

for ns in infra kubeflow istio-system pipeline automl jupyter service monitoring logging kube-system aihub default; do
  kubectl -n $ns delete secret hubsecret 2>/dev/null
  kubectl -n $ns create secret docker-registry hubsecret \
    --docker-server=ccr.ccs.tencentyun.com \
    --docker-username=<你的账号> \
    --docker-password=<你的密码>
done

# 触发失败 pod 重拉
kubectl get pods -A --no-headers | awk '$4 ~ /ImagePullBackOff|ErrImagePull/ {print $1, $2}' | \
  while read ns pod; do kubectl delete pod -n $ns $pod --grace-period=0 --force; done

C.5 修 istio-ingressgateway Service

CubeStudio 的 install YAML(install/kubernetes/istio/install-1.15.0.yaml)里只有 istio-ingressgateway 的 Deployment 没有 Service,需手动建 ClusterIP + externalIPs:

cat > /tmp/ingress-svc.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: istio-ingressgateway
  namespace: istio-system
  labels:
    app: istio-ingressgateway
    istio: ingressgateway
spec:
  type: ClusterIP
  externalIPs:
  - 172.30.159.159
  - 47.114.127.214
  selector:
    app: istio-ingressgateway
    istio: ingressgateway
  ports:
  - {name: http,  port: 80,   targetPort: 8080}
  - {name: http2, port: 8080, targetPort: 8080}
  - {name: https, port: 443,  targetPort: 8443}
EOF
kubectl apply -f /tmp/ingress-svc.yaml

# 首次 istiod 没 CA 前 ingressgateway 挂着,重启一次让 envoy 拉全配置
kubectl rollout restart deployment -n istio-system istiod istio-ingressgateway

C.6 清理无 GPU 场景下会卡住的资源

kubectl delete deployment vgpu-hami-scheduler -n kube-system
kubectl delete daemonset vgpu-hami-device-plugin -n kube-system
kubectl delete job vgpu-hami-admission-create vgpu-hami-admission-patch -n kube-system

C.7 验收

curl -sI http://47.114.127.214/          # 301 → /frontend/
curl -sI http://47.114.127.214/frontend/ # 200

默认账号 admin / admin,首次登录后立即改密码。


五、Phase D:云端 CloudCore(KubeEdge v1.23.0)

D.1 装 keadm

KEADM_VER=1.23.0
wget -q https://gh-proxy.com/https://github.com/kubeedge/kubeedge/releases/download/v${KEADM_VER}/keadm-v${KEADM_VER}-linux-amd64.tar.gz -O /tmp/keadm.tar.gz
mkdir -p /tmp/keadm-extract
tar -xzf /tmp/keadm.tar.gz -C /tmp/keadm-extract
cp $(find /tmp/keadm-extract -name keadm -type f | head -1) /usr/local/bin/keadm
keadm version

注意:v1.23.0 的 release tarball 解压后内层目录名其实是 keadm-v1.20.0-linux-amd64/(KubeEdge 上游打包失误),keadm version 也会显示 v1.20.0。这不影响实际部署的 cloudcore 镜像版本——keadm init --kubeedge-version=v1.23.0 才决定用哪个镜像。

D.2 init

keadm init \
  --advertise-address=47.114.127.214 \
  --set iptablesManager.mode="external" \
  --kubeedge-version=v1.23.0

D.3 打开 dynamicController

cloudcore configmap 的 data 是一个 yaml 字符串(不是顶层结构),不能直接 sed 整个 cm yaml。要先把字符串导出、改完再 apply 回去:

# 导出 cloudcore.yaml 字段到临时文件
kubectl get cm -n kubeedge cloudcore -o jsonpath='{.data.cloudcore\.yaml}' > /tmp/cc.yaml

# 改 dynamicController.enable: false → true
sed -i '/dynamicController:/{n;s|enable: false|enable: true|;}' /tmp/cc.yaml

# 写回 configmap
kubectl create cm cloudcore -n kubeedge --from-file=cloudcore.yaml=/tmp/cc.yaml \
  --dry-run=client -o yaml | kubectl apply -f -

# Deployment 默认 RollingUpdate,但 cloudcore 用 hostNetwork 需端口独占,改 Recreate
kubectl patch deployment cloudcore -n kubeedge -p '{"spec":{"strategy":{"type":"Recreate","rollingUpdate":null}}}'
kubectl rollout restart deployment cloudcore -n kubeedge

注意featureGates.requireAuthorization 默认 false。启用会引入大量 RBAC / serviceaccountaccesses reconcile 逻辑,调试复杂,建议保持 false

D.4 RBAC(仅启用 requireAuthorization 时需要)

启用 requireAuthorization 才需要补 ClusterRole。仓库提供了现成的 install/kubernetes/kubeedge/20-cloud-rbac.yaml(ClusterRole 名 cloudcore-extra,带 rbac/aggregate-to-cloudcore: "true" 标签,会自动聚合到默认 cloudcore 角色,覆盖 devices.kubeedge.io / apps.kubeedge.io / policy.kubeedge.io 等 CRD 权限):

kubectl apply -f install/kubernetes/kubeedge/20-cloud-rbac.yaml
kubectl rollout restart deployment cloudcore -n kubeedge

老环境若报 failed to list *v1beta1.DeviceStatus forbidden(缺 devices.kubeedge.io 权限),也应用这个文件补齐,见 07-踩坑速查

D.5 拿 token

keadm gettoken
# 输出形如:xxxxx.eyJhbGciOi...   (边缘 keadm join 时用)

下一步:边缘节点接入与 CubeStudio 项目组配置,见 05-边缘节点接入与项目组配置

最后更新 2026-07-04完整文档以官方仓库为准:GitHub Wiki