软件技术学习笔记

个人博客,记录软件技术与程序员的点点滴滴。

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上。

  1. kubernetes虚拟服务10.96.0.1:443被转发到k8s-master的外网192.168.80.90:6443
  2. kube-dns虚拟服务10.96.0.10:xxx被转发到coredns-5c74cf5485-bt2glcoredns-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集群的搭建。

高可用集群节点要求:

  1. K8S主节点:>=3奇数节点;更高要求时,etcd分离到>=3的独立奇数节点。
  2. 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