7 mins
My家里云, 异地k3s集群搭建
本文档记录了如何在跨地域 环境下使用 K3s 搭建轻量级 Kubernetes 集 群。通过 Tailscale 实现异地组网,结 合 NFS 提供共享存储,并通过命名 空间调度策略实现资源隔离。

🏗️ 部署k3sh2
节点规划表h3
节点 | 网络 | 身份 | 位置 | 备注 |
---|---|---|---|---|
k3s-bj-home-master | 192.168.1.10 | 控制节点, NFS服务器 | 北京 | |
k3s-sh-aliyun-work1 | 192.168.1.10 | work节点 | 上海 | |
k3s-usa-oracle-work2 | 192.168.1.10 | work节点 | 美国 | |
k3s-bj-home-work3 | 192.168.1.10 | work节点 | 北京 | |
k3s-bj-home-work4 | 192.168.1.10 | work节点 | 北京 |
✅ 建议:实际部署中请为每个节点分配不同的 IP 地址以避免冲突。
下载软件包h3
所有节点执行
mkdir -p /opt/k3s && cd /opt/k3s
curl https://get.k3s.io -SsL > install.shwget https://github.com/k3s-io/k3s/releases/download/v1.29.15%2Bk3s1/k3swget https://github.com/k3s-io/k3s/releases/download/v1.29.15%2Bk3s1/k3s-airgap-images-amd64.tar
mkdir -p /var/lib/rancher/k3s/agent/images/chmod +x k3schmod +x install.shcp -a k3s-airgap-images-* /var/lib/rancher/k3s/agent/images/cp -a k3s /usr/local/bin/
# 卸载脚本(可选)# /usr/local/bin/k3s-uninstall.sh# /usr/local/bin/k3s-agent-uninstall.sh
📌 说明:
- 使用
proxychains
是为了在代理环境下下载资源。- 安装完成后记得验证
/usr/local/bin/k3s
的权限是否正确。- 如果是离线环境,请确保提前准备好安装包。
异地组网h3
异地组网的方案很多,比如 ZeroTier、Tailscale、Netbird 等等。这里我们选择 Netbird,因为它简单易用且支持多种平台。
安装 Netbirdh4
# 安装文档 https://docs.netbird.io/how-to/getting-started#installationcurl -fsSL https://pkgs.netbird.io/install.sh | sh
📌 注意:如果你使用的是非 Ubuntu 系统,请参考官方文档进行适配安装。
启动并配置 Netbirdh4
netbird up --setup-key xxxxxxxxxxxxx# 正常完成, 会有一个wt0的网卡, 我们的异地k3s就用这个网卡通讯

📌 说明:
--auth-key
是你从 netbird 控制台获取的密钥。- 成功连接后会生成一个
wt0
网卡,用于节点间的通信。
MASTER节点安装h3
TAILSCALE_ETH=wt0TAILSCALE_IP=$(ip a | grep $TAILSCALE_ETH | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}"| head -n 1 )
INSTALL_K3S_DEBUG=true INSTALL_K3S_SKIP_DOWNLOAD=true INSTALL_K3S_EXEC="--disable traefik --node-ip $TAILSCALE_IP --flannel-iface $TAILSCALE_ETH --flannel-backend=vxlan" ./install.sh
📌 参数说明:
--disable traefik
:禁用默认 Ingress 控制器(后续手动部署)。--node-ip
:指定当前节点的 IP 地址。--flannel-iface
:指定 Flannel 使用的网络接口。--flannel-backend=vxlan
:使用 VXLAN 作为后端。
获取 node-tokenh4
cat /var/lib/rancher/k3s/server/node-tokenK106521xxxxxxxxxxxxxxxxxxxxxxxxxxxx::server:e47b4ef911d727671a79cdb6469682b1

✅ 建议:将 token 保存到安全的地方,用于 worker 节点加入集群。
WORK节点安装h3
TAILSCALE_ETH=wt0TAILSCALE_IP=$(ip a | grep $TAILSCALE_ETH | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}"| head -n 1 )
K3S_TOKEN="K10111631cd06c9e2b19cd3c6477cb74aa5fda54473bb19fbf7b1356e0ac78659f4::server:0319830013db1e32beced4c05aae8098"
INSTALL_K3S_SKIP_DOWNLOAD=true INSTALL_K3S_EXEC="--node-ip $TAILSCALE_IP --flannel-iface $TAILSCALE_ETH" K3S_URL=https://k3s-apiserver.internal.xyz:6443 K3S_TOKEN=$K3S_TOKEN ./install.sh
📌 参数说明:
K3S_URL
:指向 master 节点的 API Server 地址,我这里内部使用了k3s-apiserver.internal.xyz:6443
这是本地解析的一个域名K3S_TOKEN
:master 节点提供的 token。
修改工作节点标签(可选)h4
kubectl get node --selector='!node-role.kubernetes.io/master' | grep '<none>' | awk '{print "kubectl label node " $1 " node-role.kubernetes.io/worker= --overwrite" }' | bash
✅ 建议:该步骤可以自动为未标记的节点添加
worker
标签。
下载 Helmh3
wget https://get.helm.sh/helm-v3.18.2-linux-amd64.tar.gztar -xf helm-v3.18.2-linux-amd64.tar.gzmv linux-amd64/helm /usr/local/bin/chmod +x /usr/local/bin/helm
✅ 建议:Helm 是 Kubernetes 的包管理工具,推荐在生产环境中使用。
部署 Ingressh3
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginxhelm repo updatehelm search repo ingress-nginxhelm pull ingress-nginx/ingress-nginx --untar --version 4.12.3cd ingress-nginx/
# 可选:修改为国内镜像源# cp -a values.yaml values.yaml_bak# sed -i 's/registry: registry.k8s.io/registry: k8s.m.daocloud.io/g' values.yaml
helm upgrade --install ingress-nginx ./ --set controller.service.type=NodePort --namespace kube-system --create-namespace
✅ 建议:部署完成后请检查服务状态,确保 Ingress Controller 正常运行。
kubectl get pods -n kube-system
配置 HAProxy 作为四层代理h3
apt install haproxy -y
vim haproxy.cfgglobal log 127.0.0.1 local0 log 127.0.0.1 local1 notice tune.ssl.default-dh-param 2048
defaults log global mode http option dontlognull timeout connect 5000ms timeout client 600000ms timeout server 600000ms
backend ingress-http mode tcp balance roundrobin stick-table type ip size 200k expire 30m stick on src server ingress-http 127.0.0.1:31041 check
frontend ingress_http_80 mode tcp bind *:80 default_backend ingress-http
backend ingress-https mode tcp balance roundrobin stick-table type ip size 200k expire 30m stick on src server ingress-https 127.0.0.1:32475 check
frontend ingress_https_443 mode tcp bind *:443 default_backend ingress-https
systemctl enable haproxy --nowsystemctl restart haproxy
✅ 建议:根据实际负载情况调整超时时间和负载均衡策略。
部署 Dashboardh3
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/helm search repo kubernetes-dashboardhelm pull kubernetes-dashboard/kubernetes-dashboard --untar --version 7.13.0
# 调整一些配置cd kubernetes-dashboardsed -i 's/docker.io/docker.m.daocloud.io/g' values.yaml# dashboard自带了一个 Kong,也需要调整一下国内源cd charts/kongsed -i 's#repository: kong#repository: docker.m.daocloud.io/library/kong#g' values.yaml
helm upgrade --install kubernetes-dashboard ./ --namespace kube-dashboard --create-namespace

配置 Ingress 访问h4
# kubectl create secret tls domain-cn-tls --key /etc/ssl/domain.cn.key --cert /etc/ssl/domain.cn.pem -n kube-dashboard
kubectl apply -f - <<EOFapiVersion: networking.k8s.io/v1kind: Ingressmetadata: annotations: nginx.ingress.kubernetes.io/backend-protocol: HTTPS name: dashboard-ingress namespace: kube-dashboardspec: ingressClassName: nginx rules: - host: dh.domain.com http: paths: - backend: service: name: kubernetes-dashboard-kong-proxy port: number: 443 path: / pathType: Prefix tls: - hosts: - dh.domain.com secretName: domain-cn-tlsEOF
创建访问 Tokenh4
kubectl apply -f - <<EOFapiVersion: v1kind: ServiceAccountmetadata: name: admin-user namespace: kube-dashboard---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: admin-userroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-adminsubjects:- kind: ServiceAccount name: admin-user namespace: kube-dashboardEOF
# 生成有效期为 10 年的 Tokenkubectl create token admin-user -n kube-dashboard --duration 87600h
配置 NFS 网络存储h3
NFS Server 搭建h4
apt install nfs-kernel-server -y
vim /etc/exports/mnt/m2disk *(rw,sync,no_subtree_check,no_root_squash)
systemctl enable nfs-kernel-server --nowsystemctl restart nfs-kernel-server
所有节点安装 NFS 客户端h4
apt update && apt install -y nfs-common# sudo yum install -y nfs-utils
NFS Provisoner 配置h4
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/helm search repo nfs-subdir-external-provisionerhelm pull nfs-subdir-external-provisioner/nfs-subdir-external-provisioner --untar --version 4.0.18
# 调整一些配置cd nfs-subdir-external-provisionersed -i 's/registry.k8s.io/k8s.m.daocloud.io/g' values.yamlvim values.yaml
helm upgrade --install nfs-subdir-external-provisioner ./ --namespace kube-system --create-namespace
✅ 建议:确保 NFS 共享目录权限设置合理,避免权限问题导致挂载失败。
异地优化h3
使用命名空间划分资源区域h4
目标是:
- 需要运行在 home 环境下的服务,创建在
ser-home
命名空间下。 - 需要运行在 aliyun 环境下的服务,创建在
ser-aliyun
命名空间下。
开启 PodNodeSelector 准入控制器h5
# 划分资源的nskubectl create ns ser-usakubectl create ns ser-homekubectl create ns ser-aliyun
mkdir -p /etc/rancher/k3s/config.yaml.dcat > apiserver.yaml <<EOFkube-apiserver-arg: - "--enable-admission-plugins=PodNodeSelector"EOF
systemctl restart k3s
给节点打标签h5
kubectl label nodes k3s-bj-home-xxx location=homekubectl label nodes k3s-usa-oracle-xxx location=usakubectl label nodes k3s-sh-aliyun-xxx location=aliyun
配置命名空间注解h5
# 配置命名空间注解kubectl edit ns ser-aliyun
apiVersion: v1kind: Namespacemetadata: annotations: scheduler.alpha.kubernetes.io/node-selector: location=aliyun labels: kubernetes.io/metadata.name: ser-aliyun name: ser-aliyun
测试调度h5
# 测试调度kubectl -n ser-aliyun run test-pod-$RANDOM --image=m.daocloud.io/docker.io/library/nginx --restart=Neverkubectl -n ser-aliyun run test-pod$RANDOM --image=m.daocloud.io/docker.io/library/nginx --restart=Never
🔍 注意:如果你在 Deployment 上额外指定了
nodeSelector
和scheduler.alpha.kubernetes.io/node-selector
,后者的优先级更高。
补充h3
k3s 使用Dockerh4
# 网络插件mkdir /opt/cni/bin -pwget https://github.com/flannel-io/cni-plugin/releases/download/v1.7.1-flannel1/flannel-amd64mv flannel-amd64 /opt/cni/bin/flannel
curl -L https://github.com/containernetworking/plugins/releases/download/v1.7.1/cni-plugins-linux-amd64-v1.7.1.tgz | tar -C /opt/cni/bin -xz
mkdir -p /etc/cni/net.dcat > /etc/cni/net.d/10-flannel.conflist <<EOF{ "name": "cbr0", "cniVersion": "0.4.0", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, { "type": "portmap", "capabilities": { "portMappings": true } } ]}EOF
# cri-dockerdwget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.16/cri-dockerd-0.3.16.amd64.tgztar -xf cri-dockerd-0.3.16.amd64.tgzmv cri-dockerd/cri-dockerd /usr/local/bin/
wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.socketwget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.servicemv cri-docker.socket cri-docker.service /etc/systemd/system/
sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service
systemctl enable cri-docker.servicesystemctl enable --now cri-docker.socketsystemctl restart cri-docker.socket
# 安装命令INSTALL_K3S_DEBUG=true INSTALL_K3S_SKIP_DOWNLOAD=true INSTALL_K3S_EXEC="\--container-runtime-endpoint unix:///run/cri-dockerd.sock \--disable traefik \--node-ip $TAILSCALE_IP \--flannel-iface $TAILSCALE_ETH \--flannel-backend=vxlan" ./install.sh