边缘集群部署 - 云端环境准备(K8s + NFS)
本篇对应一次从零到可用的跨公网"云-边"部署的前两个阶段:Phase A 云端 K8s 集群 + Phase B 云端 NFS 服务端。公网云主机作为云端(K8s 控制面 + cube-studio + CloudCore + NFS 服务端)。
来源:
docs/部署/kubeedge部署边缘集群cube-studio.md第 0~3 节。覆盖云厂商安全组、Ubuntu 24.04 适配、containerd 2.x 镜像 mirror、NFS 跨公网挂载。
零、交付前必读:要替换的变量
文档里所有命令用的都是作者当时环境的示例值。正式部署前请把下列占位符换成你自己的:
| 占位符 | 示例(作者的) | 说明 | 怎么查 |
|---|---|---|---|
<云端公网IP> |
47.114.127.214 |
云端主机公网 IP,边缘节点必须能访问 | 云厂商控制台 / curl ifconfig.me |
<云端内网IP> |
172.30.159.159 |
云端 eth0 的 IP,可能 == 公网 IP(无 NAT 的云)或私网 IP(阿里云 ECS) | ip -4 addr show eth0 |
<云端内网CIDR> |
172.30.0.0/16 |
云端 VPC 内网 CIDR,用于 NFS exports | 云厂商 VPC 配置 |
<边缘节点名> |
edge-pc |
kubectl 里的 node 名称 | 自己取,建议只有小写字母/数字/- |
<边缘内网IP> |
192.168.3.22 |
边缘节点在局域网的 IP | 边缘机 ip -4 addr show |
<边缘内网CIDR> |
192.168.3.0/24 |
边缘所在局域网 CIDR | 边缘路由器配置 |
<ccr账号> / <ccr密码> |
825485697 / <你的密码> |
ccr.ccs.tencentyun.com 私有仓库凭证(CubeStudio 商业版镜像在那里) |
供应商提供 |
关于边缘出口公网 IP:本文不需要这个值。早期版本曾用边缘出口 IP 来做 NFS export 白名单和安全组放行,但家宽/4G 出口 IP 会变,每次变都要改云端 export + 安全组并强制重挂,经常凌晨断服。现在统一改成
*/0.0.0.0/0(详见 Phase B 末尾"安全权衡")。
其它要自己确定的
- 云厂商:示例是阿里云。任意厂商都行,唯一要求:云主机有固定公网 IP,能开放
22/80/443/6443/10000-10004/2049端口。 - K8s 版本:本文用
v1.28.15。K8s 1.25–1.29 都 OK,KubeEdge 必须对应升到 ≥ v1.22(K8s 1.28+ 上 v1.20 有 bug)。 - CubeStudio 商业版镜像凭证:只有社区版镜像的话,04 里的
hubsecret部分可跳过。
一、环境(示例)
角色
| 角色 | 位置 | 规格 | OS |
|---|---|---|---|
云端 cube |
公网 47.114.127.214 / 内网 172.30.159.159 |
≥ 8 vCPU / 16 GiB | Ubuntu 22.04+ |
边缘 edge-pc |
NAT 内网 192.168.3.22 / 出口公网 IP 不固定 |
≥ 4 C / 8 GiB | Ubuntu 20.04+ |
版本栈
- K8s:v1.28.15(kubeadm 自装,
registry.aliyuncs.com镜像源) - 容器运行时:containerd 2.2.1(云)/ 1.7.3(边)
- CNI:flannel v0.25.6
- KubeEdge:最终用 v1.23.0(也试过 v1.20.0 / v1.22.1)
云厂商安全组 / 云主机防火墙(入方向,提前在控制台配置)
| 端口 | 协议 | 源 | 用途 |
|---|---|---|---|
| 22 | TCP | 管理员 IP | SSH |
| 80、443 | TCP | 0.0.0.0/0 | cube-studio Web |
| 6443 | TCP | 0.0.0.0/0 | kube-apiserver(边缘 kube-proxy 要走公网连云端 apiserver) |
| 10000-10004 | TCP | 0.0.0.0/0 | CloudCore(websocket / https / stream / tunnel) |
| 2049、111、20048 | TCP/UDP | 0.0.0.0/0 |
NFS(详见下方"安全权衡") |
| 30000-32767 | TCP | 按需 | K8s NodePort(可选) |
NFS 公网放行的安全权衡:NFSv4 +
sec=sys没有真正的客户端鉴权,源 IP 是唯一防线。把 2049 对0.0.0.0/0开等于让全网都能尝试挂载/data/nfs。本场景边缘出口 IP 经常变、/data/nfs里只有 CubeStudio 的 pipeline workspace(无核心数据资产),团队接受这个风险。如果 NFS 上有敏感数据,请改用 WireGuard:给边缘分一个固定虚拟 IP,NFS export 写虚拟 IP,安全组只对 51820/udp 开放。
二、Phase A:云端 K8s 集群(containerd + kubeadm)
A.1 系统基线
apt-get update -qq
swapoff -a
sed -i.bak '/ swap / s/^/#/' /etc/fstab
cat > /etc/modules-load.d/k8s.conf <<EOF
overlay
br_netfilter
EOF
modprobe overlay && modprobe br_netfilter
cat > /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
timedatectl set-timezone Asia/Shanghai
mkdir -p /data/nfs /data/k8s # /data/k8s 后续会被替换为软链
A.2 安装 containerd 2.x
Ubuntu 24.04 apt 源即为 containerd 2.x:
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq containerd
mkdir -p /etc/containerd # apt 不自动创建
containerd config default > /etc/containerd/config.toml
关键配置(containerd 2.x 与 1.x 语法不同):
# 1. SystemdCgroup 改 true
sed -i 's|SystemdCgroup = false|SystemdCgroup = true|' /etc/containerd/config.toml
# 2. sandbox 镜像换阿里云(2.x 字段名是 sandbox,不是 sandbox_image)
sed -i "s|sandbox = 'registry.k8s.io/pause:3.10.1'|sandbox = 'registry.aliyuncs.com/google_containers/pause:3.9'|" /etc/containerd/config.toml
# 3. 开启 config_path(用于 certs.d 镜像 mirror)
# 位置: [plugins.'io.containerd.cri.v1.images'.registry] config_path = '/etc/containerd/certs.d'
# kubeadm generate 默认已有,确认即可
关键点:containerd 2.x 的 Transfer Service 需要单独配 config_path(与 CRI registry 的 config_path 并列),否则 kubelet/crictl pull 仍会绕过 mirror 直连原始 registry:
[plugins.'io.containerd.transfer.v1.local']
config_path = '/etc/containerd/certs.d'
同时设置(强制走 CRI plugin 拉镜像):
use_local_image_pull = true
A.3 registry mirror
mkdir -p /etc/containerd/certs.d/docker.io
cat > /etc/containerd/certs.d/docker.io/hosts.toml <<EOF
server = "https://registry-1.docker.io"
[host."https://docker.m.daocloud.io"]
capabilities = ["pull", "resolve"]
EOF
# registry.k8s.io → 阿里云
mkdir -p /etc/containerd/certs.d/registry.k8s.io
cat > /etc/containerd/certs.d/registry.k8s.io/hosts.toml <<EOF
server = "https://registry.k8s.io"
[host."https://registry.aliyuncs.com/google_containers"]
capabilities = ["pull", "resolve"]
override_path = true
EOF
systemctl restart containerd
A.4 nerdctl + crictl
GitHub 直连在国内会超时,用 gh-proxy.com。两个都要装:CubeStudio 用 nerdctl 拉镜像,kubeadm preflight 校验 crictl 必须存在。
NERDCTL_VER=1.7.6
wget -q https://gh-proxy.com/https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VER}/nerdctl-${NERDCTL_VER}-linux-amd64.tar.gz -O /tmp/nerdctl.tar.gz
tar -xzf /tmp/nerdctl.tar.gz -C /usr/local/bin nerdctl
CRICTL_VER=v1.28.0
wget -q https://gh-proxy.com/https://github.com/kubernetes-sigs/cri-tools/releases/download/${CRICTL_VER}/crictl-${CRICTL_VER}-linux-amd64.tar.gz -O /tmp/crictl.tar.gz
tar -xzf /tmp/crictl.tar.gz -C /usr/local/bin
cat > /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
EOF
A.5 kubeadm / kubelet / kubectl v1.28
apt-get install -y -qq apt-transport-https ca-certificates curl gpg conntrack socat
mkdir -p /etc/apt/keyrings
curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/deb/Release.key | \
gpg --dearmor --yes -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/deb/ /" > /etc/apt/sources.list.d/kubernetes.list
apt-get update -qq
apt-get install -y -qq kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl
A.6 kubeadm init
⭐ 四大坑之 4:
--apiserver-cert-extra-sans必须含公网 IP,否则后面改 kube-proxy server 为公网 IP 时证书不匹配照样握手失败。
kubeadm config images pull \
--image-repository=registry.aliyuncs.com/google_containers \
--kubernetes-version=v1.28.15
kubeadm init \
--apiserver-advertise-address=172.30.159.159 \
--apiserver-cert-extra-sans=47.114.127.214,172.30.159.159 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12 \
--kubernetes-version=v1.28.15 \
--image-repository=registry.aliyuncs.com/google_containers \
--cri-socket=unix:///run/containerd/containerd.sock
mkdir -p /root/.kube
cp /etc/kubernetes/admin.conf /root/.kube/config
export KUBECONFIG=/etc/kubernetes/admin.conf
A.7 CNI plugins + flannel + 单节点去污 + 节点标签
先装 CNI plugins(Ubuntu 24.04 apt 的 containerd 不带 loopback/bridge 等基础插件;不装会一直 failed to find plugin "loopback"):
mkdir -p /opt/cni/bin
wget -q https://gh-proxy.com/https://github.com/containernetworking/plugins/releases/download/v1.4.0/cni-plugins-linux-amd64-v1.4.0.tgz -O /tmp/cni.tgz
tar -xzf /tmp/cni.tgz -C /opt/cni/bin
# flannel manifest(github 直连会 timeout,走代理)
wget -q https://gh-proxy.com/https://raw.githubusercontent.com/flannel-io/flannel/v0.25.6/Documentation/kube-flannel.yml -O /tmp/kube-flannel.yml
sed -i 's|docker.io/flannel/|docker.m.daocloud.io/flannel/|g' /tmp/kube-flannel.yml
kubectl apply -f /tmp/kube-flannel.yml
# 单节点集群移除 control-plane taint
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
# 云端训练节点标签(CubeStudio 按 label 调度 pipeline)
kubectl label node cube \
train=true cpu=true org=public notebook=true service=true \
node-role.kubernetes.io/master=true gpu=false --overwrite
验收:kubectl get nodes → Ready;kubectl get pods -A 全 Running。
三、Phase B:云端 NFS 服务端
apt-get install -y -qq nfs-kernel-server
mkdir -p /data/nfs/k8s
chmod -R 777 /data/nfs
# 让 CubeStudio 默认的 hostPath /data/k8s/... 自动落到 NFS 导出区
rm -rf /data/k8s
ln -sf /data/nfs/k8s /data/k8s
/etc/exports(对所有 IP 放行,原因见上方"安全权衡"——边缘出口 IP 不固定,按 IP 白名单运维成本太高):
注意:必须用
*而不是0.0.0.0/0。Ubuntu 24.04 NFS server 解析0.0.0.0/0后所有非本地 IP 一律mount.nfs: access denied by server(即使exportfs -v显示规则已加载)。换成*立即可挂。这是 nfs-utils 的 CIDR 匹配 bug,不是配置写错。
cat > /etc/exports <<EOF
/data/nfs *(rw,no_root_squash,async,no_subtree_check,insecure)
/data/nfs 172.30.0.0/16(rw,no_root_squash,async,no_subtree_check,insecure)
/data/nfs 10.244.0.0/16(rw,no_root_squash,async,no_subtree_check,insecure)
/data/nfs 127.0.0.1(rw,no_root_squash,async,no_subtree_check,insecure)
EOF
exportfs -ar
systemctl enable --now nfs-kernel-server
showmount -e 127.0.0.1 # 应显示上述 4 行
配合云厂商安全组也要对
0.0.0.0/0放行2049/tcp、111/tcp+udp、20048/tcp(见 Phase A 安全组表格)。两边都改完才算生效。边缘侧的挂载方式见 05-边缘节点接入与项目组配置。
下一步:在云端部署 CubeStudio 与 CloudCore,见 04-云端CubeStudio与CloudCore。