跨地域多节点K3s集群部署指南,涵盖离线安装、Netbird异地组网、系统优化、NFS存储配置及Docker运行时切换。

My家里云, 异地k3s集群搭建
8 mins
1667 words
Loading views

🏗️ 部署 k3sh1

节点规划表h2

节点网络身份位置备注
k3s-bj-home-master192.168.1.10控制节点,NFS 服务器北京
k3s-sh-aliyun-work1192.168.1.10Work 节点上海
k3s-usa-oracle-work2192.168.1.10Work 节点美国
k3s-bj-home-work3192.168.1.10Work 节点北京
k3s-bj-home-work4192.168.1.10Work 节点北京

建议:实际部署中请为每个节点分配不同的 IP 地址以避免冲突。


下载软件包h2

所有节点执行

Terminal window
mkdir -p /opt/k3s && cd /opt/k3s
curl https://get.k3s.io -SsL > install.sh
wget https://github.com/k3s-io/k3s/releases/download/v1.29.15%2Bk3s1/k3s
wget 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 k3s
chmod +x install.sh
cp -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 的权限是否正确。
  • 如果是离线环境,请提前准备好安装包。

异地组网h2

异地组网的方案很多,比如 ZeroTier、Tailscale、Netbird 等。这里选择 Netbird,因为它简单易用且支持多种平台。

安装 Netbirdh3

Terminal window
# 安装文档 https://docs.netbird.io/how-to/getting-started#installation
curl -fsSL https://pkgs.netbird.io/install.sh | sh

注意:如果你使用的是非 Ubuntu 系统,请参考官方文档进行适配安装。

启动并配置 Netbirdh3

Terminal window
netbird up --setup-key ******
# 正常完成后会生成一个 es0 网卡,我们的异地 k3s 就用这个网卡通信
b3eafe669209c33e9552951ab04c8486.png

说明

  • --setup-key 是从 Netbird 控制台获取的密钥。
  • 成功连接后会生成一个 es0 网卡,用于节点间的通信。

系统优化h2

参数优化h3

Terminal window
cat > /etc/sysctl.d/99-k3s.conf <<EOF
# 启用桥接流量处理
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
# 允许更多连接
net.core.somaxconn = 65535
net.ipv4.ip_forward = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
# 文件句柄数
fs.file-max = 1000000
fs.inotify.max_user_watches = 524288
# 避免 OOM killer 杀掉关键进程
vm.swappiness = 10
net.ipv4.tcp_keepalive_time = 30 # 降低保活时间,快速检测断连
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_retries2 = 5 # 减少重试次数,适应高延迟
net.ipv4.tcp_syn_retries = 3
net.core.somaxconn = 1024 # 增加连接队列
net.ipv4.ip_forward = 1 # 启用转发(ZeroTier 需要)
vm.overcommit_memory = 1 # 允许内存过分配
EOF
sysctl -p /etc/sysctl.d/99-k3s.conf
cat > /etc/security/limits.conf <<EOF
* soft nofile 65536
* hard nofile 65536
* soft nproc 65536
* hard nproc 65536
root soft nofile 65536
root hard nofile 65536
EOF

配置 IPVSh3

Terminal window
apt-get update && apt-get install -y ipset ipvsadm conntrack
cat > /etc/modules-load.d/ipvs.conf <<EOF
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
EOF
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack
lsmod | grep ip_vs

Master 节点安装h2

Terminal window
EASYTIER_ETH=es0
EASYTIER_IP=$(ip a | grep $EASYTIER_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=" \
server \
--flannel-iface=${EASYTIER_ETH} \
--node-external-ip=${EASYTIER_IP} \
--node-ip=${EASYTIER_IP} \
--bind-address=${EASYTIER_IP} \
--advertise-address=${EASYTIER_IP} \
--tls-san=${EASYTIER_IP} \
--data-dir=/var/lib/rancher/k3s \
--disable=traefik,servicelb \
--cluster-cidr=10.42.0.0/16 \
--service-cidr=10.43.0.0/16 \
--disable-network-policy \
--write-kubeconfig-mode=644 \
--kube-proxy-arg=proxy-mode=ipvs \
--kube-proxy-arg=ipvs-scheduler=rr \
" ./install.sh

获取 node-tokenh3

Terminal window
cat /var/lib/rancher/k3s/server/node-token
# 输出示例:K106521******::server:e47b4ef911d727671a79cdb6469682b1
image-20250614182931096

Work 节点安装h2

Terminal window
EASYTIER_ETH=es0
EASYTIER_IP=$(ip a | grep $EASYTIER_ETH | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}" | head -n 1)
K3S_TOKEN="******" # 替换为实际 token
INSTALL_K3S_SKIP_DOWNLOAD=true \
INSTALL_K3S_EXEC=" \
--node-external-ip=${EASYTIER_IP} \
--node-ip=${EASYTIER_IP} \
--flannel-iface=${EASYTIER_ETH} \
--kube-proxy-arg=proxy-mode=ipvs \
--kube-proxy-arg=ipvs-scheduler=rr \
" \
K3S_URL=https://k3s-apiserver.internal.0197011.xyz:6443 \
K3S_TOKEN=$K3S_TOKEN ./install.sh

参数说明

  • K3S_URL:指向 Master 节点的 API Server 地址,本例内部使用了 k3s-apiserver.internal.0197011.xyz:6443(本地解析的域名)。
  • K3S_TOKEN:Master 节点提供的 token(上文获取)。

修改工作节点标签(可选)h3

Terminal window
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 标签。


下载 Helmh2

Terminal window
wget https://get.helm.sh/helm-v3.18.2-linux-amd64.tar.gz
tar -xf helm-v3.18.2-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/
chmod +x /usr/local/bin/helm

建议:Helm 是 Kubernetes 的包管理工具,推荐在生产环境中使用。


部署 Ingressh2

Terminal window
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm search repo ingress-nginx
helm pull ingress-nginx/ingress-nginx --untar --version 4.12.3
cd 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 作为四层代理h2

Terminal window
apt install haproxy -y

编辑 /etc/haproxy/haproxy.cfg

Terminal window
global
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
Terminal window
systemctl enable haproxy --now
systemctl restart haproxy

建议:根据实际负载情况调整超时时间和负载均衡策略。


部署 Dashboardh2

Terminal window
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
helm search repo kubernetes-dashboard
helm pull kubernetes-dashboard/kubernetes-dashboard --untar --version 7.13.0
cd kubernetes-dashboard
sed -i 's/docker.io/docker.m.daocloud.io/g' values.yaml
# Dashboard 自带了一个 Kong,也需要调整国内源
cd charts/kong
sed -i 's#repository: kong#repository: docker.m.daocloud.io/library/kong#g' values.yaml
cd ../..
helm upgrade --install kubernetes-dashboard ./ \
--namespace kube-dashboard \
--create-namespace
image-20250614191156205

配置 Ingress 访问h3

Terminal window
# 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 - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
name: dashboard-ingress
namespace: kube-dashboard
spec:
ingressClassName: nginx
rules:
- host: dh.example.com
http:
paths:
- backend:
service:
name: kubernetes-dashboard-kong-proxy
port:
number: 443
path: /
pathType: Prefix
tls:
- hosts:
- dh.example.com
secretName: domain-cn-tls
EOF

创建访问 Tokenh3

Terminal window
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kube-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kube-dashboard
EOF
# 生成有效期为 10 年的 Token
kubectl create token admin-user -n kube-dashboard --duration 87600h

配置 NFS 网络存储h2

NFS Server 搭建h3

Terminal window
apt install nfs-kernel-server -y
vim /etc/exports
/mnt/storage *(rw,sync,no_subtree_check,no_root_squash)
systemctl enable nfs-kernel-server --now
systemctl restart nfs-kernel-server

所有节点安装 NFS 客户端h3

Terminal window
apt update && apt install -y nfs-common
# sudo yum install -y nfs-utils

NFS Provisioner 配置h3

Terminal window
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm search repo nfs-subdir-external-provisioner
helm pull nfs-subdir-external-provisioner/nfs-subdir-external-provisioner --untar --version 4.0.18
cd nfs-subdir-external-provisioner
sed -i 's/registry.k8s.io/k8s.m.daocloud.io/g' values.yaml
vim values.yaml # 按需调整配置
helm upgrade --install nfs-subdir-external-provisioner ./ \
--namespace kube-system \
--create-namespace

建议:确保 NFS 共享目录权限设置合理,避免权限问题导致挂载失败。


异地优化h2

使用命名空间划分资源区域h3

目标:

  1. 需要运行在 home 环境下的服务,创建在 ser-home 命名空间下。
  2. 需要运行在 aliyun 环境下的服务,创建在 ser-aliyun 命名空间下。
  3. 需要运行在 usa 环境下的服务,创建在 ser-usa 命名空间下。

开启 PodNodeSelector 准入控制器h4

Terminal window
kubectl create ns ser-usa
kubectl create ns ser-home
kubectl create ns ser-aliyun
mkdir -p /etc/rancher/k3s/config.yaml.d
cat > /etc/rancher/k3s/config.yaml.d/apiserver.yaml <<EOF
kube-apiserver-arg:
- "--enable-admission-plugins=PodNodeSelector"
EOF
systemctl restart k3s

给节点打标签h4

Terminal window
kubectl label nodes k3s-bj-home-xxx location=home
kubectl label nodes k3s-usa-oracle-xxx location=usa
kubectl label nodes k3s-sh-aliyun-xxx location=aliyun

配置命名空间注解h4

Terminal window
kubectl edit ns ser-aliyun

添加以下内容:

apiVersion: v1
kind: Namespace
metadata:
annotations:
scheduler.alpha.kubernetes.io/node-selector: location=aliyun
labels:
kubernetes.io/metadata.name: ser-aliyun
name: ser-aliyun

测试调度h4

Terminal window
kubectl -n ser-aliyun run test-pod-$RANDOM --image=m.daocloud.io/docker.io/library/nginx --restart=Never
kubectl -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 的优先级更高。


补充:k3s 使用 Docker 运行时h2

配置 CNI 插件h3

Terminal window
mkdir -p /opt/cni/bin
wget https://github.com/flannel-io/cni-plugin/releases/download/v1.7.1-flannel1/flannel-amd64
mv 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.d
cat > /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-dockerdh3

Terminal window
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.16/cri-dockerd-0.3.16.amd64.tgz
tar -xf cri-dockerd-0.3.16.amd64.tgz
mv cri-dockerd/cri-dockerd /usr/local/bin/
wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.socket
wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.service
mv 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.service
systemctl enable --now cri-docker.socket
systemctl restart cri-docker.socket

安装 k3s(使用 Docker)h3

Terminal window
EASYTIER_ETH=es0
EASYTIER_IP=$(ip a | grep $EASYTIER_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=" \
--container-runtime-endpoint unix:///run/cri-dockerd.sock \
--disable traefik \
--node-ip $EASYTIER_IP \
--flannel-iface $EASYTIER_ETH \
--flannel-backend=vxlan" ./install.sh

相关文档h2