Ubuntu中部署Kubernetes (K8s)集群
Kubernetes (K8s)是云原生生态的基石,是CNCF中第一个毕业的项目,是事实上的“云操作系统”标准;后续的分布式微服务都部署在K8s中。
演练K8s集群(CNI + IPVS模式),我们使用3个虚拟机(Ubuntu Server 18.04),需要SSD磁盘作为存储。K8s本身的微服务就不少,磁盘操作次数比普通的单应用服务的多。如果使用普通的机械磁盘,K8s集群的启动都困难。
节点类型 | 节点名称 | IP地址 | 最小内存 |
---|---|---|---|
主节点 | k8s-master | 192.168.80.90 | 3G |
工作点 | k8s-worker-1 | 192.168.80.91 | 2G |
工作点 | k8s-worker-2 | 192.168.80.92 | 2G |
1. 准备Docker
在每个节点上,安装好Docker,参考:Ubuntu 18.04中安装Docker
2. 安装 kubeadm
参考: https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
在每个节点上,关闭swap、开启ip_forward、安装IPVS和kubeadm:
sudo swapoff -a
sudo nano /etc/fstab
#/swap.img none swap sw 0 0
sudo nano /etc/sysctl.conf
net.ipv4.ip_forward=1
# ignore errors
sudo sysctl net.bridge.bridge-nf-call-iptables=1
sudo apt install apt-transport-https curl gnupg2 ipset ipvsadm -y
# take care GFW for google.com
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
sudo nano /etc/apt/sources.list.d/kubernetes.list
deb http://mirrors.ustc.edu.cn/kubernetes/apt kubernetes-xenial main
sudo apt-get update
sudo apt-get install kubeadm -y
# Lock K8s version
sudo apt-mark hold kubelet kubeadm kubectl
3. 部署Master节点
准备Master节点的配置文件init-config.yaml
(开启IPVS,配置CNI):
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
imageRepository: "kinsprite"
networking:
serviceSubnet: "10.96.0.0/12"
podSubnet: "10.244.0.0/16"
dnsDomain: "cluster.local"
kubernetesVersion: "v1.15.3"
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
featureGates:
SupportIPVSProxyMode: true
mode: "ipvs"
部署Master节点(包含Flannel CNI):
# 1. show the docker images
sudo kubeadm config images list
# 2. init cluster
sudo kubeadm init --ignore-preflight-errors=ImagePull --config=init-config.yaml
# 3. save the kube config
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# save the line: "kubeadm join 192.168.80.xx ......"
# 4. Flannel
sudo kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 5. Enabling shell autocompletion
# https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion
echo 'source <(kubectl completion bash)' >>~/.bashrc
sudo su -
kubectl completion bash > /etc/bash_completion.d/kubectl
exit
exit
# login again
到此,K8s集群的主节点部署完成,普通的POD不会部署到Master节点。
xxx@k8s-master:~$ kubectl get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-5c74cf5485-bt2gl 1/1 Running 4 44h 10.244.0.11 k8s-master <none> <none>
coredns-5c74cf5485-z7flg 1/1 Running 4 44h 10.244.0.10 k8s-master <none> <none>
etcd-k8s-master 1/1 Running 5 44h 192.168.80.90 k8s-master <none> <none>
...
4. 工作节点加入集群
在每个工作节点上,执行类似sudo kubeadm join 192.168.80.90:6443 --token xxxxx.yyyyyyyyyyy --discovery-token-ca-cert-hash sha256:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
的一条命令(来源于主节点sudo kubeadm init …命令的输出),待工作节点准备好。
查看节点状态
在主节点上执行kubectl get nodes
,可以看到节点的状态如下,表示所有节点准备好了:
xxx@k8s-master:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 3h4m v1.15.3
k8s-worker-1 Ready <none> 155m v1.15.3
k8s-worker-2 Ready <none> 153m v1.15.3
5. 察看集群状态
查看所有POD
xxx@k8s-master:~$ kubectl get pods -o wide --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system coredns-5c74cf5485-bt2gl 1/1 Running 1 3h12m 10.244.0.4 k8s-master <none> <none>
kube-system coredns-5c74cf5485-z7flg 1/1 Running 1 3h12m 10.244.0.5 k8s-master <none> <none>
kube-system etcd-k8s-master 1/1 Running 1 3h11m 192.168.80.90 k8s-master <none> <none>
kube-system kube-apiserver-k8s-master 1/1 Running 1 3h11m 192.168.80.90 k8s-master <none> <none>
kube-system kube-controller-manager-k8s-master 1/1 Running 1 3h11m 192.168.80.90 k8s-master <none> <none>
kube-system kube-flannel-ds-amd64-25v7l 1/1 Running 0 163m 192.168.80.91 k8s-worker-1 <none> <none>
kube-system kube-flannel-ds-amd64-7h788 1/1 Running 1 3h7m 192.168.80.90 k8s-master <none> <none>
kube-system kube-flannel-ds-amd64-tprwp 1/1 Running 2 161m 192.168.80.92 k8s-worker-2 <none> <none>
kube-system kube-proxy-gphl7 1/1 Running 1 3h12m 192.168.80.90 k8s-master <none> <none>
kube-system kube-proxy-gzjfp 1/1 Running 0 161m 192.168.80.92 k8s-worker-2 <none> <none>
kube-system kube-proxy-zvw56 1/1 Running 0 163m 192.168.80.91 k8s-worker-1 <none> <none>
kube-system kube-scheduler-k8s-master 1/1 Running 1 3h11m 192.168.80.90 k8s-master <none> <none>
可以看出所有的POD都准备好了(N/N表示准备好,M/N表示未准备好)。kube-flannel-ds与kube-proxy都是以DaemonSet的形式在每个节点上有一个POD,主要处理节点间通讯。其它几个的POD都是Master节点独有的。
查看所有Service
xxx@k8s-master:~$ kubectl get svc --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3h22m
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 3h22m
kubernetes
提供K8S API服务;kube-dns
提供K8S集群内部域名解析服务。
查看IPVS
xxx@k8s-master:~$ sudo ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 192.168.80.90:6443 Masq 1 3 0
TCP 10.96.0.10:53 rr
-> 10.244.0.4:53 Masq 1 0 0
-> 10.244.0.5:53 Masq 1 0 0
TCP 10.96.0.10:9153 rr
-> 10.244.0.4:9153 Masq 1 0 0
-> 10.244.0.5:9153 Masq 1 0 0
UDP 10.96.0.10:53 rr
-> 10.244.0.4:53 Masq 1 0 0
-> 10.244.0.5:53 Masq 1 0 0
在每个节点上执行sudo ipvsadm -ln
,输出的内容都是一样的。其中的调度方法,未指定时默认为rr
.
结合“查看所有Service”的结果,我们可以看到:集群内部访问Service时,均被转发到真实的POD IP或 Node IP上。
kubernetes
虚拟服务10.96.0.1:443
被转发到k8s-master
的外网192.168.80.90:6443
。kube-dns
虚拟服务10.96.0.10:xxx
被转发到coredns-5c74cf5485-bt2gl
、coredns-5c74cf5485-z7flg
两个POD上。
Flannel UDP或VXLAN模式
访问Service Cluster IP的跨节点网络流量路径为:【Client Pod -> IPVS
-> veth* -> cni0 -> flannel.1 -> flanneld或VXLAN -> k8s-worker-1 eth0】—-> 【k8s-worker-2 eth0 -> flanneld或VXLAN -> flannel.1 -> cni0 -> veth* -> Backend Pod】。
Client Pod与Backend Pod在同一节点时,网络流量路径为:【Client Pod -> IPVS
-> veth* -> cni0 -> veth* -> Backend Pod】。
只有UDP模式时,流量才进入flanneld进程用户空间;VXLAN模式时,flanneld只起到配置的作用。参考:https://msazure.club/flannel-networking-demystify/ 。
至此,我们完成一个空白K8S集群的搭建。
高可用集群节点要求:
- K8S主节点:>=3奇数节点;更高要求时,etcd分离到>=3的独立奇数节点。
- K8S工作节点:无状态节点,多多益善;有状态节点,一般每种Database每个分片都要求>=3的奇数节点。
要求奇数节点的原因:因为现在很多的选举算法在偶数节点的情况下,可能出现“脑裂”现象。在资源缺乏的情况下模拟高可用时,我们只需给同一服务提供多份POD————注意,有的Deployment限制在同一节点部署多份实例。
6. 部署K8s单例
在本地开发环境中,我们很多时候不需要一个集群,只需一个K8s部署微服务环境。此时,我们需要部署一个K8s单例。
已经试用过Snap中的MicroK8s,但是稳定性、自由度还是没有 kubeadm 安装的K8s高。参照上面的“3. 部署Master节点”,只需再执行下命一条命令即可:
# 6. Enable master to deploy PODs (ONLY FOR SINGLE INSTANCE DEVELOP ENV)
kubectl taint nodes --all node-role.kubernetes.io/master-
到此,K8S单例部署完成,Master节点也可以部署普通的POD。
xxx@k8s-single:~$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-77dbbd96bf-f4p8c 1/1 Running 12 51d
coredns-77dbbd96bf-swj64 1/1 Running 11 51d
etcd-k8s-single 1/1 Running 23 78d
kube-apiserver-k8s-single 1/1 Running 11 51d
kube-controller-manager-k8s-single 1/1 Running 11 51d
kube-flannel-ds-amd64-g5v78 1/1 Running 33 78d
kube-proxy-5ffvr 1/1 Running 11 51d
kube-scheduler-k8s-single 1/1 Running 11 51d
xxx@k8s-single:~$ kubectl get pods
NAME READY STATUS RESTARTS AGE
gin-test-v0.1.0-bb9fc6b5f-sx9xt 1/1 Running 14 60d
gitlab-hello-world-v0.1.0-7648d9f67-hbzxt 1/1 Running 4 37d