为何要裸机部署k8s?为什么不用minikube?其实本地裸机部署可以对k8s有更加深入的了解,而且k8s涉及的概念很多,如果没有实际操作基本上很难理解这些概念以及如何使用。
除此之外,minikube是主从单个节点部署在一台机器上,对于学习k8s不是特别有帮助。
裸机部署k8s
预备环境:
Parallel Desktop虚拟机 下载地址
macOS 12 M1
master主节点,slave1和slave2工作节点,实现一主二从
Ubuntu 20 Server for ARM 镜像 下载地址
每个节点至少2GB内存,2核CPU ,所以确保宿主主机内存 >= 16GB
master: 192.168.2.104
slave1: 192.168.2.109
slave2: 192.168.2.111
科学上网,自备梯子
另外说一句就是在我没有购买PD之前我是在VMware Fusion上搭建的,这应该和PD搭建是一样的。另外要注意的是,如果搭建了一个虚拟机后就 克隆 这个虚拟机,之后可能网络会有问题,所以还是建议手动一个一个搭建。
配置master和所有slave
ssh 密钥登陆
vim /etc/ssh/sshd_config PermitRootLogin yes RSAAuthentication yes PubkeyAuthentication yes
修改master IP地址和MAC地址
其实这里应该不需要修改的,至少我在PD上测试时不用(可能是我没有将虚拟机关闭的原因)
另外要注意 macaddress
需要和 PD/VMware上查看的一样
vim /etc/netplan/00-installer-config.yaml
network: ethernets: ens160: match: macaddress: 00 :50:56:29:1C:37 addresses: [192.168 .2 .104 /24 ] dhcp4: no gateway4: 192.168 .2 .2 nameservers: addresses: [114.114 .114 .114 ,8.8 .8 .8 ] version: 2 renderer: networkd
修改slave IP地址和Mac地址
对于PD来说,可修改也可不修改(除非你需要关闭虚拟机,不过一般都是暂停)
以下YAML文件中的Mac地址需要和PD/VMware虚拟机网络适配器中生成的Mac地址对应
vim /etc/netplan/00-installer-config.yaml
slave1
network: ethernets: ens160: match: macaddress: 00 :0C:29:7F:AF:F6 addresses: [192.168 .2 .109 /24 ] dhcp4: no gateway4: 192.168 .2 .2 nameservers: addresses: [114.114 .114 .114 ,8.8 .8 .8 ] version: 2 renderer: networkd
slave2
同上
network: ethernets: ens160: match: macaddress: 00 :50:56:37:E5:AA addresses: [192.168 .2 .111 /24 ] dhcp4: no gateway4: 192.168 .2 .2 nameservers: addresses: [114.114 .114 .114 ,8.8 .8 .8 ] version: 2 renderer: networkd
使配置生效!!!
设置主机名
# master hostnamectl set-hostname master# slave1 hostnamectl set-hostname slave1# slave2 hostnamectl set-hostname slave2
修改hosts
192.168.2.104 master 192.168.2.109 slave1 192.168.2.111 slave2
关闭swap
一定要关闭swap!!!
安装docker engine
sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpgecho \ "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io
安装kubeadm
sudo apt-get update sudo apt-get install -y ca-certificates curl software-properties-common apt-transport-https curl curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - tee /etc/apt/sources.list.d/kubernetes.list <<EOF deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF apt-get update apt-get install -y kubelet kubeadm kubectl systemctl enable kubelet systemctl start kubelet systemctl enable docker systemctl start docker
修改docker配置
这里可以使用阿里云的镜像源
cat <<EOF > daemon.json { "exec-opts": ["native.cgroupdriver=systemd"], "registry-mirrors": ["https://4xorsfia.mirror.aliyuncs.com"] } EOF mv daemon.json /etc/docker/ systemctl daemon-reload systemctl restart docker
用 kubeadm 初始化集群(仅master运行)
kubeadm init \ --apiserver-advertise-address=192.168.2.104 \ --image-repository registry.aliyuncs.com/google_containers \ --pod-network-cidr=10.244.0.0/16 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $(id -u):$(id -g) $HOME /.kube/config
把salve工作节点加入集群(仅slave运行)
分别在两台工作节点上执行:
kubeadm join 192.168.2.104:6443 --token ipk042.ctnrypl0wz3d9nle --discovery-token-ca-cert-hash sha256:0066e13bc73fe2c1c596fc53d6d5660030681b4fc74b4605e09cbfa523b466c7
安装网络插件flannel,否则 slave 是 NotReady 状态(master运行)
可能需要科学上网,或者在宿主主机下载后上传到master节点
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 wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml vim kube-flannel.yml"- --iface=enp0s5" (用实际网卡名替换,通过 ip a 查看) kubectl apply -f ./kube-flannel.yml ╭─root@master ~ ╰─ NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-6d8c4cb4d-c7hxb 1/1 Running 0 6m28s kube-system coredns-6d8c4cb4d-msp7c 1/1 Running 0 6m28s kube-system etcd-master 1/1 Running 5 6m42s kube-system kube-apiserver-master 1/1 Running 5 6m42s kube-system kube-controller-manager-master 1/1 Running 1 (6m7s ago) 6m42s kube-system kube-flannel-ds-ghjjl 1/1 Running 0 62s kube-system kube-flannel-ds-ppsd2 1/1 Running 0 59s kube-system kube-flannel-ds-r7wnb 1/1 Running 0 3m44s kube-system kube-proxy-5hchr 1/1 Running 0 62s kube-system kube-proxy-7z2bp 1/1 Running 0 59s kube-system kube-proxy-m5lfm 1/1 Running 0 6m28s kube-system kube-scheduler-master 1/1 Running 6 (6m9s ago) 6m42s
如果遇到了coredns
的崩溃,原因是coredns配置文件中的loop
参数导致,使用kubectl -n kube-system edit configmap coredns
: 删除即可,然后重启服务:(我使用PD搭建时没有这个问题,也可能是因为我之前VMware克隆了虚拟机导致的)
kubectl get pods -n kube-system -oname |grep coredns |xargs kubectl delete -n kube-system
测试test-k8s
至此基本上算是完成部署了,下面我们来编写一个yaml清单文件测试一下
app.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 apiVersion: apps/v1 kind: Deployment metadata: name: test-k8s spec: replicas: 5 selector: matchLabels: app: test-k8s template: metadata: labels: app: test-k8s spec: containers: - name: test-k8s image: registry.cn-hangzhou.aliyuncs.com/josexy/test-k8s:1.0.0
上面那个test-k8s测试镜像是我用go gin写的一个简单web服务,当访问主页时打印出当前环境的IP地址和主机名。
需要注意的是该镜像是基于 linux/arm64/v8 的,可能需要替换为其他的镜像或者自行构建
kubectl apply -f app.yaml
之后等待全部pods运行完成
╭─root@master ~/work/k8s ╰─ NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-k8s-777b86fcb4-8mq6k 1/1 Running 0 135m 10.244.2.48 slave2 <none> <none> test-k8s-777b86fcb4-9jvpv 1/1 Running 0 135m 10.244.1.59 slave1 <none> <none> test-k8s-777b86fcb4-h6j64 1/1 Running 0 135m 10.244.1.57 slave1 <none> <none> test-k8s-777b86fcb4-mm5wk 1/1 Running 0 135m 10.244.1.58 slave1 <none> <none> test-k8s-777b86fcb4-tg279 1/1 Running 0 135m 10.244.2.49 slave2 <none> <none>
可见创建的5个pods副本被k8s调度到了不同的节点上
现在通过curl访问 10.244.2.48
服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 > curl 10.244.2.48:10086 <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8" > <title>Test K8S</title> </head> <body> <p>Hello k8s</p> <p>HostName: test-k8s-777b86fcb4-8mq6k</p> <p>IP: 10.244.2.48</p> </body> </html>
可以看到访问的服务是正确的。
kubernetes 在pod内无法ping通servicename和ClusterIP的解决方法(所有节点)
原因:kube-proxy使用了iptable模式,修改为ipvs模式则可以在pod内ping通clusterIP或servicename ,需要使用 ipvs 替换iptables。
可以通过以下命令查看是否是ipvs模式
$ kubectl get cm kube-proxy -n kube-system -o yaml| grep mode mode: "ipvs"
开启kube-proxy ipvs模式的前提条件,由于ipvs已经加入到了内核的主干,所以为kube-proxy开启ipvs的前提需要加载以下的内核模块
ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack_ipv4 或者 nf_conntrack
加载模块shell脚本
cat > ipvsset.sh <<EOF #!/bin/bash modprobe -- ip_vs modprobe -- ip_vs_rr modprobe -- ip_vs_wrr modprobe -- ip_vs_sh modprobe -- nf_conntrack EOF chmod +x ipvsset.sh && sudo ./ipvsset.sh lsmod | grep -e ip_vs -e nf_conntrack
然后需要在 每一个节点上 安装ipset
,为了便于ipvs的代理查看,可以安装管理工具ipvsadm
apt install ipset ipvsadm
kube-proxy设置ipvs
kubectl edit cm kube-proxy -n kube-system
修改 ConfigMap 的 kube-system/kube-proxy
中的config.conf,mode: "ipvs"
之后重启各个节点上的kube-proxy pod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $ kubectl get pod -n kube-system | grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}' $ kubectl get pod -n kube-system -o wide| grep kube-proxy kube-proxy-cx4k4 1/1 Running 0 10m 192.168.2.104 master <none> <none> kube-proxy-nnc68 1/1 Running 0 10m 192.168.2.111 slave2 <none> <none> kube-proxy-qdg5h 1/1 Running 0 11m 192.168.2.109 slave1 <none> <none> $ kubectl logs kube-proxy-cx4k4 -n kube-system I0217 03:40:41.109206 1 node.go:163] Successfully retrieved node IP: 192.168.2.104 I0217 03:40:41.109237 1 server_others.go:138] "Detected node IP" address="192.168.2.104" I0217 03:40:41.120284 1 server_others.go:269] "Using ipvs Proxier" I0217 03:40:41.120297 1 server_others.go:271] "Creating dualStackProxier for ipvs" I0217 03:40:41.120313 1 server_others.go:491] "Detect-local-mode set to ClusterCIDR, but no IPv6 cluster CIDR defined, , defaulting to no-op detect-local for IPv6" I0217 03:40:41.121365 1 proxier.go:438] "IPVS scheduler not specified, use rr by default" I0217 03:40:41.121452 1 proxier.go:438] "IPVS scheduler not specified, use rr by default"
这样就可以在Pod内(docker)ping通ClusterIP或者servicename了:
比如:
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 ╭─root@master ~ ╰─ NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12h test-k8s ClusterIP 10.107.42.94 <none> 10086/TCP 38m ╭─root@master ~ ╰─ root@test-k8s-d4ddc8449-lkgg4:/code/go/src <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8" > <title>Test K8S</title> </head> <body> <p>Hello k8s</p> <p>HostName: test-k8s-d4ddc8449-lkgg4</p> <p>IP: 10.244.2.10</p> </body> </html>
Pod 报错解决
如果你运行 kubectl describe pod/pod-name
发现 Events 中有下面这个错误
networkPlugin cni failed to set up pod "test-k8s-68bb74d654-mc6b9_default" network: open /run/flannel/subnet.env: no such file or directory
在每个节点创建文件/run/flannel/subnet.env
写入以下内容即可解决
FLANNEL_NETWORK=10.244.0.0/16 FLANNEL_SUBNET=10.244.0.1/24 FLANNEL_MTU=1450 FLANNEL_IPMASQ=true
然后重新部署
kubectl rollout restart deployment test-k8s
查看节点(master运行)
╭─root@master ~ ╰─ NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME master Ready control-plane,master 6m1s v1.23.3 192.168.2.104 <none> Ubuntu 20.04.3 LTS 5.4.0-99-generic docker://20.10.12 slave1 Ready <none> 18s v1.23.3 192.168.2.109 <none> Ubuntu 20.04.3 LTS 5.4.0-99-generic docker://20.10.12 slave2 Ready <none> 15s v1.23.3 192.168.2.111 <none> Ubuntu 20.04.3 LTS 5.4.0-99-generic docker://20.10.12
主节点
╭─root@master ~ ╰─ REPOSITORY TAG IMAGE ID CREATED SIZE rancher/mirrored-flannelcni-flannel v0.16.3 2830f9802082 2 weeks ago 61.7MB registry.aliyuncs.com/google_containers/kube-apiserver v1.23.3 8e7422f73cf3 3 weeks ago 132MB registry.aliyuncs.com/google_containers/kube-proxy v1.23.3 d36a89daa194 3 weeks ago 109MB registry.aliyuncs.com/google_containers/kube-controller-manager v1.23.3 3e63a2140741 3 weeks ago 122MB registry.aliyuncs.com/google_containers/kube-scheduler v1.23.3 4bad79a8953b 3 weeks ago 53MB rancher/mirrored-flannelcni-flannel-cni-plugin v1.0.1 05932afd0a64 3 weeks ago 7.76MB registry.aliyuncs.com/google_containers/etcd 3.5.1-0 1040f7790951 3 months ago 132MB registry.aliyuncs.com/google_containers/coredns v1.8.6 edaa71f2aee8 4 months ago 46.8MB registry.aliyuncs.com/google_containers/pause 3.6 7d46a07936af 5 months ago 484kB
工作节点
╭─root@slave1 ~ ╰─ REPOSITORY TAG IMAGE ID CREATED SIZE rancher/mirrored-flannelcni-flannel v0.16.3 2830f9802082 2 weeks ago 61.7MB registry.aliyuncs.com/google_containers/kube-proxy v1.23.3 d36a89daa194 3 weeks ago 109MB rancher/mirrored-flannelcni-flannel-cni-plugin v1.0.1 05932afd0a64 3 weeks ago 7.76MB registry.aliyuncs.com/google_containers/pause 3.6 7d46a07936af 5 months ago 484kB
zsh 自动补全 kubectl
kubectl 通过命令 kubectl completion zsh
生成 Zsh 自动补全脚本。 在 shell 中导入(Sourcing)该自动补全脚本,将启动 kubectl 自动补全功能。
为了在所有的 shell 会话中实现此功能,请将下面内容加入到文件 ~/.zshrc
中。
source <(kubectl completion zsh)
部署和访问 Kubernetes 仪表板Dashboard(不完整)
在Master节点上运行以下命令安装dashboard插件(可能被墙)
这部分不是完整的,因此可以忽略
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
未完待续
虽然从最开始到现在算是成功在PD上部署了k8s集群环境,但是有一些功能是没有的。比如裸机环境下不支持 LoadBalancer 负载均衡器,需要而外安装 MetalLB(裸金属负载均衡器),这将在下一篇继续介绍。
参考