在Lightsail上使用Zerotier构建Kubernetes集群

AWS Lightsail是一个非常适合个人使用的云服务平台,提供了简单易用的界面和相对较低的价格。但是,它的基础服务不像EC2那么完善,我没有找到一个方便的AWS提供的跨区域组网方法。Zerotier则是一个虚拟局域网解决方案,可以让不同网络中的设备像在同一局域网中一样进行通信。结合这两者,我们可以轻松地在Lightsail上搭建一个Kubernetes集群。

1. 创建Lightsail实例

可以在AWS Lightsail每个区域上都创建一个2C2G的实例,包含在90天免费套餐中

2. 加入Zerotier网络

在每个实例上安装Zerotier,使用以下命令:

1
curl -s https://install.zerotier.com | sudo bash

然后加入Zerotier网络,使用以下命令:

1
sudo zerotier-cli join <your_network_id>

在Zerotier控制台中,授权你的实例加入网络。

使用ifconfig命令可以查看Zerotier创建的虚拟网卡和IP地址

1
2
3
4
5
6
7
8
9
10
ifconfig

ztksexlnsa: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 2800
inet 10.147.18.13 netmask 255.255.255.0 broadcast 10.147.18.255
inet6 fe80::acb6:3aff:fed5:96b6 prefixlen 64 scopeid 0x20<link>
ether ae:b6:3a:d5:96:b6 txqueuelen 1000 (Ethernet)
RX packets 9150 bytes 1161718 (1.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 9624 bytes 5133672 (4.8 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

尝试ping 另一台实例Zerotier IP地址

1
2
3
4
5
6
7
8
9
10
admin@worker:~$ ping 10.147.18.13
PING 10.147.18.13 (10.147.18.13) 56(84) bytes of data.
64 bytes from 10.147.18.13: icmp_seq=1 ttl=64 time=139 ms
64 bytes from 10.147.18.13: icmp_seq=2 ttl=64 time=139 ms
64 bytes from 10.147.18.13: icmp_seq=3 ttl=64 time=138 ms
64 bytes from 10.147.18.13: icmp_seq=4 ttl=64 time=140 ms
^C
--- 10.147.18.13 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 138.482/139.006/140.268/0.737 ms

可以看到能ping通,但是美国实例ping德国实例延迟比较高

3. 安装Kubernetes

为了方便,我使用kubeadm的1.23.3版本来安装Kubernetes集群,因为它可以兼容Docker。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sudo -i
curl https://get.docker.com | bash

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
EOF

sudo swapoff -a
sudo sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab

nano /etc/hostname # 修改为你的主机名(master或worker)
nano /etc/hosts # master 127.0.0.1

reboot

安装Kubernetes

1
2
3
4
5
6
7
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
sudo apt update
sudo apt install -y kubeadm=1.23.3-00 kubelet=1.23.3-00 kubectl=1.23.3-00
sudo apt-mark hold kubeadm kubelet kubectl

4. 初始化Kubernetes集群

在master节点上初始化Kubernetes集群

1
kubeadm init --pod-network-cidr=10.10.0.0/16 --apiserver-advertise-address=<your_master_ip> # 替换为你的Zerotier主节点IP

按照提示拷贝kubectl配置文件

在worker节点上加入Kubernetes集群

1
kubeadm join <your_master_ip>:6443 --token <your_token> --discovery-token-ca-cert-hash sha256:<your_hash>

查看节点状态

1
kubectl get nodes

发现节点状态为NotReady,原因是没有安装网络插件

5. 安装网络插件

安装Flannel网络插件

1
2
wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
nano kube-flannel.yml

有两个地方要修改:

  1. 修改net-conf.json Network为我们的pod-network-cidr,这里是10.10.0.0/16
  2. 选定args参数中Zerotier的网卡,如上文的ztksexlnsa
1
kubectl apply -f kube-flannel.yml

查看节点状态

1
kubectl get nodes -o wide

如果节点状态为Ready,说明网络插件安装成功

6. 修改Node连接IP

kubectl get nodes -o wide中查看节点的IP地址,发现并不是Zerotier的IP地址,而是AWS的NAT网卡地址,例如172.26.2.153

需要修改为Zerotier的IP地址,不然master和worker之间无法通信

1
sudo nano /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 

看到EnvironmentFile=-/etc/default/kubelet
那么就去修改这个文件

1
sudo nano /etc/default/kubelet

在文件中指定为你的Zerotier IP地址

1
KUBELET_EXTRA_ARGS="--node-ip=10.147.18.244"

然后重启kubelet

1
2
sudo systemctl daemon-reload
sudo systemctl restart kubelet

最好两台机器都重启一下,然后重新部署Flannel网络插件

1
2
kubectl delete -f kube-flannel.yml
kubectl apply -f kube-flannel.yml

7. 部署nginx测试连通性

可以选择这个yaml作为测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
apiVersion: v1
kind: ConfigMap
metadata:
name: ngx-conf
data:
default.conf: |
server {
listen 80;
location / {
default_type text/plain;
return 200 'srv : $server_addr:$server_port\nhost: $hostname\nuri : $request_method $host $request_uri\n';
}
}


---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ngx-dep
spec:
replicas: 2
selector:
matchLabels:
app: ngx-dep
template:
metadata:
labels:
app: ngx-dep
spec:
volumes:
- name: ngx-conf-vol
configMap:
name: ngx-conf
containers:
- image: nginx:alpine
name: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: ngx-conf-vol

---
apiVersion: v1
kind: Service
metadata:
name: ngx-svc
spec:
selector:
app: ngx-dep
ports:
- port: 80
targetPort: 80
protocol: TCP
1
kubectl apply -f nginx.yaml

然后查看pod和service的IP地址

1
2
kubectl get pods -o wide
kubectl get svc -o wide

如果在master和worker节点上都可以使用curl命令访问service或pod的IP地址,则说明集群网络配置正确了