上一篇两年前的文章 记 容器编排工具 k3s + Rancher 环境的搭建 记录了 外置 mysql 数据库的 k3s 集群 以及方便的集群管理工具 Rancher 的安装与配置过程。
而如果家中有自建 NAS 、树莓派服务器等 Homelab 设施,以及在各个云服务商均部署有云服务器的这种更为常见的场景,为了设法充分利用这些资源,我在这之后又探索了 使用嵌入式 Etcd 的多 Server 节点高可用部署 和 通过 Tailscale NAT 穿透 建立跨云内网实现跨云 k3s 集群。
WireGuard 与 Tailscale
介绍 Tailscale 这个强大的组网工具之前先来简要介绍一下 WireGuard。
WireGuard 是一个用于替代 OpenVPN、L2TP/IPsec 这类传统 VPN 的高性能、现代化且安全的 VPN 协议(官网是这么描述的),它与这些传统 VPN 的主要区别有:
- WireGuard 在保证核心功能 “加密隧道” 实现的同时切割掉了许多不必要的功能,因此它相当的简洁(代码只有几千行),还有着非常简单的配置步骤
- WireGuard 可以运行在内核态,避免了与用户态之间来回切换,因此速度非常快,且可以支持很高的带宽
- WireGuard 没有 Server/Client 之分,连线的两端地位是对等的,因此非常适合用来进行各种拓扑组网
知乎 上有一篇文章详细介绍了 WireGuard 是如何对传统 VPN 进行精简化的;后面我也会看看源码学习学习,毕竟我对能简洁优雅地实现核心功能的东西相当感兴趣。
Tailscale 是一个基于 Wireguard 实现的 mesh 网络构建器。它大致是通过一个集中式 control plane 记录与分发不同节点之间的 wireguard 连接配置,以及一些灵活的打洞黑科技来实现的。
对于大多数用户来说,Tailscale 的主要功能即通过搭建 vpn,将处于不同网络的设备连接在同一个网络下。
k3s 高可用 + 嵌入式 Etcd 集群
节点 A 操作:
curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_START=true sh -s server --cluster-init
ExecStart=/usr/local/bin/k3s \
server \
'--cluster-init' \
'--tls-san=bwhk3c.verge.toay.io' \
'--kube-apiserver-arg' \
'service-node-port-range=1-65535' \
'--advertise-address' \
'100.110.1.10' \
'--node-ip' \
'100.110.1.10' \
'--node-external-ip' \
'154.223.21.101' \
root@lnhks2:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
lnhks2.verge.toay Ready control-plane,etcd,master 17s v1.28.5+k3s1
cat /var/lib/rancher/k3s/server/token
节点 B 操作:
curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_START=true K3S_TOKEN="K100f0e009f7a9270407795b9de387ac358bd35663d7ee69a967426aaa3548722ed::server:9419304cf3481d654a933db2f24461ba" sh -s server --server https://lnhks2.verge.toay:6443
ExecStart=/usr/local/bin/k3s \
server \
'--server' \
'https://lnhks2.verge.toay:6443' \
'--advertise-address' \
'100.110.1.20' \
'--node-ip' \
'100.110.1.20' \
'--node-external-ip' \
'34.92.159.61' \
root@gchka3:/home/twikor# kubectl get nodes
NAME STATUS ROLES AGE VERSION
gchka3.verge.toay Ready control-plane,etcd,master 8s v1.28.5+k3s1
lnhks2.verge.toay Ready control-plane,etcd,master 6m17s v1.28.5+k3s1
root@lnhks2:~# kubectl label node/gchka3.verge.toay node-role.kubernetes.io/worker=true
node/gchka3.verge.toay labeled
root@lnhks2:~# kubectl label node/lnhks2.verge.toay node-role.kubernetes.io/worker=true
node/lnhks2.verge.toay labeled
root@lnhks2:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
gchka3.verge.toay Ready control-plane,etcd,master,worker 2m10s v1.28.5+k3s1
lnhks2.verge.toay Ready control-plane,etcd,master,worker 8m19s v1.28.5+k3s1
若遇到非常奇怪的pod内dns不能正常解析的错误,尝试修改cattle-cluster-agent的dnsPolicy
,这也是我在网上翻遍了github issues才找到的解决方法。。。
修改前:
~ sudo kubectl get pod -n cattle-system
NAME READY STATUS RESTARTS AGE
cattle-cluster-agent-569cc46d9c-66pdb 1/1 Running 0 83s
cattle-cluster-agent-569cc46d9c-pkljj 0/1 Error 2 (40s ago) 81s
rancher-webhook-5b5665c649-rsx9s 1/1 Running 0 4h30m
INFO: Using resolv.conf: search cattle-system.svc.cluster.local svc.cluster.local cluster.local corgi-ladon.ts.net toaylabs.org.github.beta.tailscale.net verge.toay nameserver 10.43.0.10 options ndots:5
ERROR: https://deploy.cordon.toay.io/ping is not accessible (Could not resolve host: deploy.cordon.toay.io)
修改:
~ sudo kubectl edit deployment cattle-cluster-agent -n cattle-system
Warning: spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key: beta.kubernetes.io/os is deprecated since v1.14; use "kubernetes.io/os" instead
deployment.apps/cattle-cluster-agent edited
同样地:
kubectl edit deployment fleet-agent -n cattle-fleet-system
修改后:
~ sudo kubectl get pod -n cattle-system
NAME READY STATUS RESTARTS AGE
cattle-cluster-agent-57ccdb69b4-9q7bl 1/1 Running 0 13s
cattle-cluster-agent-57ccdb69b4-p882r 1/1 Running 0 15s
rancher-webhook-5b5665c649-rsx9s 1/1 Running 0 4h35m
节点 C 操作:
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.28.5+k3s1 K3S_TOKEN=K100f0e009f7a9270407795b9de387ac358bd35663d7ee69a967426aaa3548722ed::server:9419304cf3481d654a933db2f24461ba K3S_URL=https://bwhk3c.verge.toay:6443 sh -s - --docker --node-ip 100.120.10.1
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
bwhk3c.verge.toay Ready control-plane,etcd,master 9m46s v1.28.5+k3s1 100.110.10.1 45.78.28.214 Ubuntu 22.04.3 LTS 5.15.0-25-generic containerd://1.7.11-k3s2
gchka3.verge.toay Ready control-plane,etcd,master 9s v1.28.5+k3s1 100.111.10.1 34.92.159.61 Ubuntu 22.04.3 LTS 6.2.0-1019-gcp docker://24.0.5
svc4ubt.verge.toay Ready control-plane,etcd,master 7m12s v1.28.5+k3s1 100.120.10.20 <none> Ubuntu 22.04.4 LTS 5.15.0-94-generic docker://24.0.5
Proxmox 配置 Tailscale 域名证书
#!/bin/bash
NAME="$(tailscale status --json | jq '.Self.DNSName | .[:-1]' -r)"
tailscale cert "${NAME}"
pvenode cert set "${NAME}.crt" "${NAME}.key" --force --restart
root@insulator:~# NAME="$(tailscale status --json | jq '.Self.DNSName | .[:-1]' -r)"
root@insulator:~# NAME
-bash: NAME: command not found
root@insulator:~# echo $NAME
insulator-verge-toay.corgi-ladon.ts.net
root@insulator:~# tailscale cert "${NAME}"
pvenode cert set "${NAME}.crt" "${NAME}.key" --force --restart
Wrote public cert to insulator-verge-toay.corgi-ladon.ts.net.crt
Wrote private key to insulator-verge-toay.corgi-ladon.ts.net.key
Setting custom certificate files
Restarting pveproxy
┌─────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────┐
│ filename │ pveproxy-ssl.pem │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ fingerprint │ 1A:C1:B6:AA:74:28:AE:31:54:E9:CA:5B:5B:A3:58:1B:78:8D:25:E3:66:5E:39:65:E5:3C:15:67:8D:00:89:71 │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ subject │ /CN=insulator-verge-toay.corgi-ladon.ts.net │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ issuer │ /C=US/O=Let's Encrypt/CN=R3 │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ notbefore │ 2024-02-18 22:50:04 │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ notafter │ 2024-05-18 22:50:03 │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ public-key-type │ id-ecPublicKey │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ public-key-bits │ 256 │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ san │ - insulator-verge-toay.corgi-ladon.ts.net │
└─────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────┘
Bonus
Tailscale 实现了一些非常好用的便捷功能
Taildrop
从 Linux 端发送:
tailscale file cp <src-file-loc> <dst-device>:
然后从 Linux 端接收:
tailscale file get <dst-dir>
使用 exitnode
sudo tailscale up --exit-node=<exit-node-ip> --exit-node-allow-lan-access=true