使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版)

2025-05-27 0 86

使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版)

前面我们课程中的集群是单 master 的集群,对于生产环境风险太大了,非常有必要做一个高可用的集群,这里的高可用主要是针对控制面板来说的,比如 kube-apiserver、etcd、kube-controller-manager、kube-scheduler 这几个组件,其中 kube-controller-manager 于 kube-scheduler 组件是 Kubernetes 集群自己去实现的高可用,当有多个组件存在的时候,会自动选择一个作为 Leader 提供服务,所以不需要我们手动去实现高可用,apiserver 和 etcd 就需要手动去搭建高可用的集群的。高可用的架构有很多,比如典型的 haproxy + keepalived 架构,或者使用 nginx 来做代理实现。

环境准备

4个节点,都是 Centos 7.6 系统,内核版本:3.10.0-1062.4.1.el7.x86_64,在每个节点上添加 hosts 信息:

  1. ➜~cat/etc/hosts
  2. 192.168.31.10api.k8s.local#vip
  3. 192.168.31.31master1
  4. 192.168.31.32master2
  5. 192.168.31.33master3
  6. 192.168.31.100node1

其中 192.168.31.10 为 vip,使用域名 api.k8s.local 进行映射。

使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版)

  • 节点的 hostname 必须使用标准的 DNS 命名,另外千万不用什么默认的 localhost 的 hostname,会导致各种错误出现的。在 Kubernetes 项目里,机器的名字以及一切存储在 Etcd 中的 API 对象,都必须使用标准的 DNS 命名(RFC 1123)。可以使用命令 hostnamectl set-hostname node1 来修改 hostname。

禁用防火墙:

  1. ➜~systemctlstopfirewalld
  2. ➜~systemctldisablefirewalld

禁用 SELINUX:

  1. ➜~setenforce0
  2. ➜~cat/etc/selinux/config
  3. SELINUX=disabled

由于开启内核 ipv4 转发需要加载 br_netfilter 模块,所以加载下该模块:

  1. ➜~modprobebr_netfilter

创建/etc/sysctl.d/k8s.conf文件,添加如下内容:

  1. net.bridge.bridge-nf-call-ip6tables=1
  2. net.bridge.bridge-nf-call-iptables=1
  3. net.ipv4.ip_forward=1

执行如下命令使修改生效:

  1. ➜~sysctl-p/etc/sysctl.d/k8s.conf

安装 ipvs:

  1. ➜~cat>/etc/sysconfig/modules/ipvs.modules<<EOF
  2. #!/bin/bash
  3. modprobe–ip_vs
  4. modprobe–ip_vs_rr
  5. modprobe–ip_vs_wrr
  6. modprobe–ip_vs_sh
  7. modprobe–nf_conntrack_ipv4
  8. EOF
  9. ➜~chmod755/etc/sysconfig/modules/ipvs.modules&&bash/etc/sysconfig/modules/ipvs.modules&&lsmod|grep-eip_vs-enf_conntrack_ipv4

上面脚本创建了的/etc/sysconfig/modules/ipvs.modules文件,保证在节点重启后能自动加载所需模块。使用lsmod | grep -e ip_vs -e nf_conntrack_ipv4命令查看是否已经正确加载所需的内核模块。

接下来还需要确保各个节点上已经安装了 ipset 软件包:

  1. ➜~yuminstallipset

为了便于查看 ipvs 的代理规则,最好安装一下管理工具 ipvsadm:

  1. ➜~yuminstallipvsadm

同步服务器时间

  1. ➜~yuminstallchrony-y
  2. ➜~systemctlenablechronyd
  3. ➜~systemctlstartchronyd
  4. ➜~chronycsources
  5. 210Numberofsources=4
  6. MSName/IPaddressStratumPollReachLastRxLastsample
  7. ===============================================================================
  8. ^+sv1.ggsrv.de261732-823us[-1128us]+/-98ms
  9. ^-montreal.ca.logiplex.net261732-17ms[-17ms]+/-179ms
  10. ^-ntp6.flashdance.cx261732-32ms[-32ms]+/-161ms
  11. ^*119.28.183.184263332+661us[+357us]+/-38ms
  12. ➜~date
  13. TueAug3114:36:14CST2021

关闭 swap 分区:

  1. ➜~swapoff-a

修改/etc/fstab文件,注释掉 SWAP 的自动挂载,使用free -m确认 swap 已经关闭。swappiness 参数调整,修改/etc/sysctl.d/k8s.conf添加下面一行:

  1. vm.swappiness=0

执行 sysctl -p /etc/sysctl.d/k8s.conf 使修改生效。

安装 Containerd

我们已经了解过容器运行时 containerd 的一些基本使用,接下来在各个节点上安装 Containerd。

由于 containerd 需要调用 runc,所以我们也需要先安装 runc,不过 containerd 提供了一个包含相关依赖的压缩包 cri-containerd-cni-${VERSION}.${OS}-${ARCH}.tar.gz,可以直接使用这个包来进行安装。首先从 release 页面下载最新版本的压缩包,当前为 1.5.5 版本:

  1. ➜~wgethttps://github.com/containerd/containerd/releases/download/v1.5.5/cri-containerd-cni-1.5.5-linux-amd64.tar.gz
  2. #如果有限制,也可以替换成下面的URL加速下载
  3. #wgethttps://download.fastgit.org/containerd/containerd/releases/download/v1.5.5/cri-containerd-cni-1.5.5-linux-amd64.tar.gz

直接将压缩包解压到系统的各个目录中:

  1. ➜~tar-C/-xzfcri-containerd-cni-1.5.5-linux-amd64.tar.gz

然后要将 /usr/local/bin 和 /usr/local/sbin 追加到 ~/.bashrc 文件的 PATH 环境变量中:

  1. exportPATH=$PATH:/usr/local/bin:/usr/local/sbin

然后执行下面的命令使其立即生效:

  1. ➜~source~/.bashrc

containerd 的默认配置文件为 /etc/containerd/config.toml,我们可以通过如下所示的命令生成一个默认的配置:

  1. ➜~mkdir-p/etc/containerd
  2. ➜~containerdconfigdefault>/etc/containerd/config.toml

对于使用 systemd 作为 init system 的 Linux 的发行版,使用 systemd 作为容器的 cgroup driver 可以确保节点在资源紧张的情况更加稳定,所以推荐将 containerd 的 cgroup driver 配置为 systemd。

修改前面生成的配置文件 /etc/containerd/config.toml,在 plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options 配置块下面将 SystemdCgroup 设置为 true:

  1. [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  2. [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  3. SystemdCgroup=true
  4. ….

然后再为镜像仓库配置一个加速器,需要在 cri 配置块下面的 registry 配置块下面进行配置 registry.mirrors:

  1. [plugins."io.containerd.grpc.v1.cri"]
  2. #sandbox_image="k8s.gcr.io/pause:3.5"
  3. sandbox_image="registry.aliyuncs.com/k8sxio/pause:3.5"
  4. [plugins."io.containerd.grpc.v1.cri".registry]
  5. [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
  6. [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
  7. endpoint=["https://bqr1dr1n.mirror.aliyuncs.com"]
  8. [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
  9. endpoint=["https://registry.aliyuncs.com/k8sxio"]

由于上面我们下载的 containerd 压缩包中包含一个 etc/systemd/system/containerd.service 的文件,这样我们就可以通过 systemd 来配置 containerd 作为守护进程运行了,现在我们就可以启动 containerd 了,直接执行下面的命令即可:

  1. ➜~systemctldaemon-reload
  2. ➜~systemctlenablecontainerd–now

启动完成后就可以使用 containerd 的本地 CLI 工具 ctr 和 crictl 了,比如查看版本:

  1. ➜~ctrversion
  2. Client:
  3. Version:v1.5.5
  4. Revision:72cec4be58a9eb6b2910f5d10f1c01ca47d231c0
  5. Goversion:go1.16.6
  6. Server:
  7. Version:v1.5.5
  8. Revision:72cec4be58a9eb6b2910f5d10f1c01ca47d231c0
  9. UUID:cd2894ad-fd71-4ef7-a09f-5795c7eb4c3b
  10. ➜~crictlversion
  11. Version:0.1.0
  12. RuntimeName:containerd
  13. RuntimeVersion:v1.5.5
  14. RuntimeApiVersion:v1alpha2

负载均衡器

为 apiserver 提供负载均衡器有很多方法,比如传统的 haproxy+keepalived,或者使用 nginx 代理也可以,这里我们使用一个比较新颖的工具 kube-vip

kube-vip(https://kube-vip.io/) 可以在你的控制平面节点上提供一个 Kubernetes 原生的 HA 负载均衡,我们不需要再在外部设置 HAProxy 和 Keepalived 来实现集群的高可用了。

在以前我们在私有环境下创建 Kubernetes 集群时,我们需要准备一个硬件/软件的负载均衡器来创建多控制面集群,更多的情况下我们会选择使用 HAProxy + Keepalived 来实现这个功能。一般情况下我们创建2个负载均衡器的虚拟机,然后分配一个 VIP,然后使用 VIP 为负载均衡器提供服务,通过 VIP 将流量重定向到后端的某个 Kubernetes 控制器平面节点上。

使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版)

haproxy+keepalived

如果我们使用 kube-vip 的话会怎样呢?

使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版)

kube-vip

kube-vip 可以通过静态 pod 运行在控制平面节点上,这些 pod 通过 ARP 会话来识别每个节点上的其他主机,我们可以选择 BGP 或 ARP 来设置负载平衡器,这与 Metal LB 比较类似。在 ARP 模式下,会选出一个领导者,这个节点将继承虚拟 IP 并成为集群内负载均衡的 Leader,而在 BGP 模式下,所有节点都会通知 VIP 地址。

集群中的 Leader 将分配 vip,并将其绑定到配置中声明的选定接口上。当 Leader 改变时,它将首先撤销 vip,或者在失败的情况下,vip 将直接由下一个当选的 Leader 分配。当 vip 从一个主机移动到另一个主机时,任何使用 vip 的主机将保留以前的 vip <-> MAC 地址映射,直到 ARP 过期(通常是30秒)并检索到一个新的 vip <-> MAC 映射,这可以通过使用无偿的 ARP 广播来优化。

kube-vip 可以被配置为广播一个无偿的 arp(可选),通常会立即通知所有本地主机 vip <-> MAC 地址映射已经改变。

使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版)

要使用 kube-vip 来实现集群的高可用,首先在 master1 节点上生成基本的 Kubernetes 静态 Pod 资源清单文件:

  1. ➜~mkdir-p/etc/kubernetes/manifests/
  2. #配置vip地址
  3. ➜~exportVIP=192.168.31.10
  4. #设置网卡名称
  5. ➜~exportINTERFACE=ens33
  6. ➜~ctrimagepulldocker.io/plndr/kube-vip:v0.3.8
  7. #使用下面的容器输出静态Pod资源清单
  8. ➜~ctrrun–rm–net-hostdocker.io/plndr/kube-vip:v0.3.8vip\\
  9. /kube-vipmanifestpod\\
  10. –interface$INTERFACE\\
  11. –vip$VIP\\
  12. –controlplane\\
  13. –services\\
  14. –arp\\
  15. –leaderElection|tee/etc/kubernetes/manifests/kube-vip.yaml
  16. apiVersion:v1
  17. kind:Pod
  18. metadata:
  19. creationTimestamp:null
  20. name:kube-vip
  21. namespace:kube-system
  22. spec:
  23. containers:
  24. -args:
  25. -manager
  26. env:
  27. name:vip_arp
  28. value:"true"
  29. name:vip_interface
  30. value:ens33
  31. name:port
  32. value:"6443"
  33. name:vip_cidr
  34. value:"32"
  35. name:cp_enable
  36. value:"true"
  37. name:cp_namespace
  38. value:kube-system
  39. name:vip_ddns
  40. value:"false"
  41. name:svc_enable
  42. value:"true"
  43. name:vip_leaderelection
  44. value:"true"
  45. name:vip_leaseduration
  46. value:"5"
  47. name:vip_renewdeadline
  48. value:"3"
  49. name:vip_retryperiod
  50. value:"1"
  51. name:vip_address
  52. value:192.168.31.10
  53. image:ghcr.io/kube-vip/kube-vip:v0.3.8
  54. imagePullPolicy:Always
  55. name:kube-vip
  56. resources:{}
  57. securityContext:
  58. capabilities:
  59. add:
  60. -NET_ADMIN
  61. -NET_RAW
  62. -SYS_TIME
  63. volumeMounts:
  64. -mountPath:/etc/kubernetes/admin.conf
  65. name:kubeconfig
  66. hostNetwork:true
  67. volumes:
  68. -hostPath:
  69. path:/etc/kubernetes/admin.conf
  70. name:kubeconfig
  71. status:{}

这里我们将 vip 设置为 192.168.31.10,首先会将 master1 节点选举为 Leader,然后接下来我们使用该 vip 来初始化控制器平台。

初始化控制平面

上面的相关环境配置也完成了,现在我们就可以来安装 Kubeadm 了,我们这里是通过指定 yum 源的方式来进行安装的:

  1. ➜~cat<<EOF>/etc/yum.repos.d/kubernetes.repo
  2. [kubernetes]
  3. name=Kubernetes
  4. baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
  5. enabled=1
  6. gpgcheck=1
  7. repo_gpgcheck=1
  8. gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
  9. https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
  10. EOF

当然了,上面的 yum 源是需要科学上网的,如果不能科学上网的话,我们可以使用阿里云的源进行安装:

  1. ➜~cat<<EOF>/etc/yum.repos.d/kubernetes.repo
  2. [kubernetes]
  3. name=Kubernetes
  4. baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
  5. enabled=1
  6. gpgcheck=0
  7. repo_gpgcheck=0
  8. gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
  9. http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
  10. EOF

然后安装 kubeadm、kubelet、kubectl:

  1. #–disableexcludes禁掉除了kubernetes之外的别的仓库
  2. ➜~yummakecachefast
  3. ➜~yuminstall-ykubelet-1.22.1kubeadm-1.22.1kubectl-1.22.1–disableexcludes=kubernetes
  4. ➜~kubeadmversion
  5. kubeadmversion:&version.Info{Major:"1",Minor:"22",GitVersion:"v1.22.1",GitCommit:"632ed300f2c34f6d6d15ca4cef3d3c7073412212",GitTreeState:"clean",BuildDate:"2021-08-19T15:44:22Z",GoVersion:"go1.16.7",Compiler:"gc",Platform:"linux/amd64"}

可以看到我们这里安装的是 v1.22.1 版本,然后将 master 节点的 kubelet 设置成开机启动:

  1. ➜~systemctlenable–nowkubelet

到这里为止上面所有的操作都需要在所有节点执行配置。

当我们执行 kubelet –help 命令的时候可以看到原来大部分命令行参数都被 DEPRECATED了,这是因为官方推荐我们使用 –config 来指定配置文件,在配置文件中指定原来这些参数的配置,可以通过官方文档 Set Kubelet parameters via a config file 了解更多相关信息,这样 Kubernetes 就可以支持动态 Kubelet 配置(Dynamic Kubelet Configuration)了,参考 Reconfigure a Node’s Kubelet in a Live Cluster。

然后我们可以通过下面的命令在 master1 节点上输出集群初始化默认使用的配置:

  1. ➜~kubeadmconfigprintinit-defaults–component-configsKubeletConfiguration>kubeadm.yaml

然后根据我们自己的需求修改配置,比如修改 imageRepository 指定集群初始化时拉取 Kubernetes 所需镜像的地址,kube-proxy 的模式为 ipvs,另外需要注意的是我们这里是准备安装 flannel 网络插件的,需要将 networking.podSubnet 设置为10.244.0.0/16:

  1. #kubeadm.yaml
  2. apiVersion:kubeadm.k8s.io/v1beta3
  3. bootstrapTokens:
  4. -groups:
  5. -system:bootstrappers:kubeadm:default-node-token
  6. token:abcdef.0123456789abcdef
  7. ttl:24h0m0s
  8. usages:
  9. -signing
  10. -authentication
  11. kind:InitConfiguration
  12. localAPIEndpoint:
  13. advertiseAddress:192.168.31.31#指定当前节点内网IP
  14. bindPort:6443
  15. nodeRegistration:
  16. criSocket:/run/containerd/containerd.sock#使用containerd的Unixsocket地址
  17. imagePullPolicy:IfNotPresent
  18. name:master1
  19. taints:#给master添加污点,master节点不能调度应用
  20. -effect:"NoSchedule"
  21. key:"node-role.kubernetes.io/master"
  22. apiVersion:kubeproxy.config.k8s.io/v1alpha1
  23. kind:KubeProxyConfiguration
  24. mode:ipvs#kube-proxy模式
  25. apiVersion:kubeadm.k8s.io/v1beta3
  26. certificatesDir:/etc/kubernetes/pki
  27. clusterName:kubernetes
  28. controllerManager:{}
  29. dns:{}
  30. etcd:
  31. local:
  32. dataDir:/var/lib/etcd
  33. imageRepository:registry.aliyuncs.com/k8sxio
  34. kind:ClusterConfiguration
  35. kubernetesVersion:1.22.1
  36. controlPlaneEndpoint:api.k8s.local:6443#设置控制平面Endpoint地址
  37. apiServer:
  38. extraArgs:
  39. authorization-mode:Node,RBAC
  40. timeoutForControlPlane:4m0s
  41. certSANs:#添加其他master节点的相关信息
  42. -api.k8s.local
  43. -master1
  44. -master2
  45. -master3
  46. -192.168.31.30
  47. -192.168.31.31
  48. -192.168.31.32
  49. networking:
  50. dnsDomain:cluster.local
  51. serviceSubnet:10.96.0.0/12
  52. podSubnet:10.244.0.0/16#指定pod子网
  53. scheduler:{}
  54. apiVersion:kubelet.config.k8s.io/v1beta1
  55. authentication:
  56. anonymous:
  57. enabled:false
  58. webhook:
  59. cacheTTL:0s
  60. enabled:true
  61. x509:
  62. clientCAFile:/etc/kubernetes/pki/ca.crt
  63. authorization:
  64. mode:Webhook
  65. webhook:
  66. cacheAuthorizedTTL:0s
  67. cacheUnauthorizedTTL:0s
  68. clusterDNS:
  69. -10.96.0.10
  70. clusterDomain:cluster.local
  71. cpuManagerReconcilePeriod:0s
  72. evictionPressureTransitionPeriod:0s
  73. fileCheckFrequency:0s
  74. healthzBindAddress:127.0.0.1
  75. healthzPort:10248
  76. httpCheckFrequency:0s
  77. imageMinimumGCAge:0s
  78. kind:KubeletConfiguration
  79. cgroupDriver:systemd#配置cgroupdriver
  80. logging:{}
  81. memorySwap:{}
  82. nodeStatusReportFrequency:0s
  83. nodeStatusUpdateFrequency:0s
  84. rotateCertificates:true
  85. runtimeRequestTimeout:0s
  86. shutdownGracePeriod:0s
  87. shutdownGracePeriodCriticalPods:0s
  88. staticPodPath:/etc/kubernetes/manifests
  89. streamingConnectionIdleTimeout:0s
  90. syncFrequency:0s
  91. volumeStatsAggPeriod:0s
  • 对于上面的资源清单的文档比较杂,要想完整了解上面的资源对象对应的属性,可以查看对应的 godoc 文档,地址: https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3。

这里需要注意的是我们在 ClusterConfiguration 块的配置中新增了控制平面的地址以及将 api.k8s.local 这个域名加入到了证书签名中,该域名将映射到 vip:

  1. controlPlaneEndpoint:api.k8s.local:6443#设置控制平面Endpoint地址
  2. apiServer:
  3. extraArgs:
  4. authorization-mode:Node,RBAC
  5. timeoutForControlPlane:4m0s
  6. certSANs:#添加其他master节点的相关信息
  7. -api.k8s.local
  8. -master1
  9. -master2
  10. -master3
  11. -192.168.31.30
  12. -192.168.31.31
  13. -192.168.31.32

在开始初始化集群之前可以使用 kubeadm config images pull –config kubeadm.yaml 预先在各个服务器节点上拉取所k8s需要的容器镜像。

配置文件准备好过后,可以使用如下命令先将相关镜像 pull 下面:

  1. ➜~kubeadmconfigimagespull–configkubeadm.yaml
  2. [config/images]Pulledregistry.aliyuncs.com/k8sxio/kube-apiserver:v1.22.1
  3. [config/images]Pulledregistry.aliyuncs.com/k8sxio/kube-controller-manager:v1.22.1
  4. [config/images]Pulledregistry.aliyuncs.com/k8sxio/kube-scheduler:v1.22.1
  5. [config/images]Pulledregistry.aliyuncs.com/k8sxio/kube-proxy:v1.22.1
  6. [config/images]Pulledregistry.aliyuncs.com/k8sxio/pause:3.5
  7. [config/images]Pulledregistry.aliyuncs.com/k8sxio/etcd:3.5.0-0
  8. failedtopullimage"registry.aliyuncs.com/k8sxio/coredns:v1.8.4":output:time="2021-08-31T15:09:13+08:00"level=fatalmsg="pullingimage:rpcerror:code=NotFounddesc=failedtopullandunpackimage\\"registry.aliyuncs.com/k8sxio/coredns:v1.8.4\\":failedtoresolvereference\\"registry.aliyuncs.com/k8sxio/coredns:v1.8.4\\":registry.aliyuncs.com/k8sxio/coredns:v1.8.4:notfound"
  9. ,error:exitstatus1
  10. Toseethestacktraceofthiserrorexecutewith–v=5orhigher

上面在拉取 coredns 镜像的时候出错了,没有找到这个镜像,我们可以手动 pull 该镜像,然后重新 tag 下镜像地址即可:

  1. ➜~ctr-nk8s.ioipulldocker.io/coredns/coredns:1.8.4
  2. ➜~ctr-nk8s.ioitagdocker.io/coredns/coredns:1.8.4registry.aliyuncs.com/k8sxio/coredns:v1.8.4

然后就可以使用上面的配置文件在 master1 节点上进行初始化:

  1. ➜~kubeadminit–upload-certs–configkubeadm.yaml
  2. [init]UsingKubernetesversion:v1.22.1
  3. [preflight]Runningpre-flightchecks
  4. [preflight]PullingimagesrequiredforsettingupaKubernetescluster
  5. ……
  6. YourKubernetescontrol-planehasinitializedsuccessfully!
  7. Tostartusingyourcluster,youneedtorunthefollowingasaregularuser:
  8. mkdir-p$HOME/.kube
  9. sudocp-i/etc/kubernetes/admin.conf$HOME/.kube/config
  10. sudochown$(id-u):$(id-g)$HOME/.kube/config
  11. Alternatively,ifyouaretherootuser,youcanrun:
  12. exportKUBECONFIG=/etc/kubernetes/admin.conf
  13. Youshouldnowdeployapodnetworktothecluster.
  14. Run"kubectlapply-f[podnetwork].yaml"withoneoftheoptionslistedat:
  15. https://kubernetes.io/docs/concepts/cluster-administration/addons/
  16. Youcannowjoinanynumberofthecontrol-planenoderunningthefollowingcommandoneachasroot:
  17. kubeadmjoinapi.k8s.local:6443–tokenabcdef.0123456789abcdef\\
  18. –discovery-token-ca-cert-hashsha256:435fbc28490d1f897337923c19ec27bcf3639e9fe84e8448177777d23cae4176\\
  19. –control-plane–certificate-key7892cd62c5ab60b28b462af32c7e49aa73d5fd4f723352f3af6546a74e465abc
  20. Pleasenotethatthecertificate-keygivesaccesstoclustersensitivedata,keepitsecret!
  21. Asasafeguard,uploaded-certswillbedeletedintwohours;Ifnecessary,youcanuse
  22. "kubeadminitphaseupload-certs–upload-certs"toreloadcertsafterward.
  23. Thenyoucanjoinanynumberofworkernodesbyrunningthefollowingoneachasroot:
  24. kubeadmjoinapi.k8s.local:6443–tokenabcdef.0123456789abcdef\\
  25. –discovery-token-ca-cert-hashsha256:435fbc28490d1f897337923c19ec27bcf3639e9fe84e8448177777d23cae4176

这里初始化的 –upload-certs 标志用来将在所有控制平面实例之间的共享证书上传到集群。然后根据安装提示拷贝 kubeconfig 文件:

  1. ➜~mkdir-p$HOME/.kube
  2. ➜~sudocp-i/etc/kubernetes/admin.conf$HOME/.kube/config
  3. ➜~sudochown$(id-u):$(id-g)$HOME/.kube/config

接着我们可以根据上面的提示添加其他的控制平面节点。

添加控制平面

对于每个其他控制平面节点,执行先前在第一个节点 master1 上的 kubeadm init 输出提供的 join 命令来添加控制平面节点:

  1. ➜~kubeadmjoinapi.k8s.local:6443–tokenabcdef.0123456789abcdef–discovery-token-ca-cert-hashsha256:435fbc28490d1f897337923c19ec27bcf3639e9fe84e8448177777d23cae4176–control-plane–certificate-key7892cd62c5ab60b28b462af32c7e49aa73d5fd4f723352f3af6546a74e465abc
  2. [preflight]Runningpre-flightchecks
  3. [preflight]Readingconfigurationfromthecluster…
  4. [preflight]FYI:Youcanlookatthisconfigfilewith'kubectl-nkube-systemgetcmkubeadm-config-oyaml'
  5. [preflight]Runningpre-flightchecksbeforeinitializingthenewcontrolplaneinstance
  6. ……
  7. Thisnodehasjoinedtheclusterandanewcontrolplaneinstancewascreated:
  8. *Certificatesigningrequestwassenttoapiserverandapprovalwasreceived.
  9. *TheKubeletwasinformedofthenewsecureconnectiondetails.
  10. *Controlplane(master)labelandtaintwereappliedtothenewnode.
  11. *TheKubernetescontrolplaneinstancesscaledup.
  12. *Anewetcdmemberwasaddedtothelocal/stackedetcdcluster.
  13. Tostartadministeringyourclusterfromthisnode,youneedtorunthefollowingasaregularuser:
  14. mkdir-p$HOME/.kube
  15. sudocp-i/etc/kubernetes/admin.conf$HOME/.kube/config
  16. sudochown$(id-u):$(id-g)$HOME/.kube/config
  17. Run'kubectlgetnodes'toseethisnodejointhecluster.

需要注意需要在另外两个节点 master2 和 master3 都执行上面的 join 命令,上面的命令中的 –control-plane 就是通知 kubeadm join 创建一个新的控制平面,–certificate-key 会从集群中的 kubeadm-certs Secret 下载控制平面证书并使用给定的密钥进行解密。

当这两个节点被添加到集群后,我们接下来也需要在节点上运行 kube-vip,将当前节点作为 kube-vip 的成员,同样执行下面的命令即可:

  1. #配置vip地址
  2. ➜~exportVIP=192.168.31.10
  3. #设置网卡名称
  4. ➜~exportINTERFACE=ens33
  5. ➜~ctrimagepulldocker.io/plndr/kube-vip:v0.3.8
  6. #使用下面的容器输出静态Pod资源清单
  7. ➜~ctrrun–rm–net-hostdocker.io/plndr/kube-vip:v0.3.8vip\\
  8. /kube-vipmanifestpod\\
  9. –interface$INTERFACE\\
  10. –vip$VIP\\
  11. –controlplane\\
  12. –services\\
  13. –arp\\
  14. –leaderElection|tee/etc/kubernetes/manifests/kube-vip.yaml

kube-vip 的静态 Pod 清单创建完成后,正常将能够看到 kube-vip 的 Pod 会按预期启动并运行:

  1. ➜~kubectlgetpods-A|grepvip
  2. kube-systemkube-vip-master11/1Running17m42s
  3. kube-systemkube-vip-master21/1Running04m24s
  4. kube-systemkube-vip-master31/1Running014s

这个时候控制平面节点就都准备好了:

  1. ➜~kubectlgetnodes
  2. NAMESTATUSROLESAGEVERSION
  3. master1Readycontrol-plane,master9m18sv1.22.1
  4. master2Readycontrol-plane,master7m11sv1.22.1
  5. master3Readycontrol-plane,master5m9sv1.22.1

添加工作节点

接下来我们可以将 node1 工作节点加入到集群中,同样使用在 master1 上初始化后的提示 join 命令,记得将 master1 节点上面的 $HOME/.kube/config 文件拷贝到 node 节点对应的文件中,安装 kubeadm、kubelet、kubectl(可选),然后执行上面初始化完成后提示的 join 命令即可:

  1. ➜~kubeadmjoinapi.k8s.local:6443–tokenabcdef.0123456789abcdef\\
  2. >–discovery-token-ca-cert-hashsha256:435fbc28490d1f897337923c19ec27bcf3639e9fe84e8448177777d23cae4176
  3. [preflight]Runningpre-flightchecks
  4. [preflight]Readingconfigurationfromthecluster…
  5. [preflight]FYI:Youcanlookatthisconfigfilewith'kubectl-nkube-systemgetcmkubeadm-config-oyaml'
  6. [kubelet-start]Writingkubeletconfigurationtofile"/var/lib/kubelet/config.yaml"
  7. [kubelet-start]Writingkubeletenvironmentfilewithflagstofile"/var/lib/kubelet/kubeadm-flags.env"
  8. [kubelet-start]Startingthekubelet
  9. [kubelet-start]WaitingforthekubelettoperformtheTLSBootstrap…
  10. Thisnodehasjoinedthecluster:
  11. *Certificatesigningrequestwassenttoapiserverandaresponsewasreceived.
  12. *TheKubeletwasinformedofthenewsecureconnectiondetails.
  13. Run'kubectlgetnodes'onthecontrol-planetoseethisnodejointhecluster.
  • 如果忘记了上面的 join 命令可以使用命令 kubeadm token create –print-join-command 重新获取。

执行成功后运行 get nodes 命令:

  1. ➜~kubectlgetnodes
  2. NAMESTATUSROLESAGEVERSION
  3. master1Readycontrol-plane,master9m18sv1.22.1
  4. master2Readycontrol-plane,master7m11sv1.22.1
  5. master3Readycontrol-plane,master5m9sv1.22.1
  6. node1NotReady<none>24sv1.22.1

可以看到是 NotReady 状态,这是因为还没有安装网络插件,接下来安装网络插件,可以在文档 https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/ 中选择我们自己的网络插件,这里我们安装 flannel:

  1. ➜~wgethttps://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
  2. #如果有节点是多网卡,则需要在资源清单文件中指定内网网卡
  3. #搜索到名为kube-flannel-ds的DaemonSet,在kube-flannel容器下面
  4. ➜~vikube-flannel.yml
  5. ……
  6. containers:
  7. name:kube-flannel
  8. image:quay.io/coreos/flannel:v0.14.0
  9. command:
  10. -/opt/bin/flanneld
  11. args:
  12. –ip-masq
  13. –kube-subnet-mgr
  14. –iface=eth0#如果是多网卡的话,指定内网网卡的名称
  15. ……
  16. ➜~kubectlapply-fkube-flannel.yml#安装flannel网络插件

隔一会儿查看 Pod 运行状态:

  1. ➜~kubectlgetpods-nkube-system
  2. NAMEREADYSTATUSRESTARTSAGE
  3. coredns-7568f67dbd-lvcd51/1Running030m
  4. coredns-7568f67dbd-shfrk1/1Running030m
  5. etcd-master11/1Running045m
  6. etcd-master21/1Running045m
  7. etcd-master31/1Running1(46mago)54m
  8. kube-apiserver-master11/1Running4(45mago)58m
  9. kube-apiserver-master21/1Running2(45mago)56m
  10. kube-apiserver-master31/1Running1(46mago)54m
  11. kube-controller-manager-master11/1Running15(48mago)58m
  12. kube-controller-manager-master21/1Running1(47mago)56m
  13. kube-controller-manager-master31/1Running054m
  14. kube-flannel-ds-4js7f1/1Running038m
  15. kube-flannel-ds-hch261/1Running038m
  16. kube-flannel-ds-l6xzv1/1Running038m
  17. kube-flannel-ds-qpzqq1/1Running038m
  18. kube-proxy-fpxp81/1Running054m
  19. kube-proxy-qdsfq1/1Running056m
  20. kube-proxy-ww9b21/1Running058m
  21. kube-proxy-zcw981/1Running050m
  22. kube-scheduler-master11/1Running15(48mago)58m
  23. kube-scheduler-master21/1Running056m
  24. kube-scheduler-master31/1Running1(47mago)54m
  25. kube-vip-master11/1Running2(48mago)58m
  26. kube-vip-master21/1Running1(47mago)55m
  27. kube-vip-master31/1Running051m
  • 当我们部署完网络插件后执行 ifconfig 命令,正常会看到新增的cni0与flannel1这两个虚拟设备,但是如果没有看到cni0这个设备也不用太担心,我们可以观察/var/lib/cni目录是否存在,如果不存在并不是说部署有问题,而是该节点上暂时还没有应用运行,我们只需要在该节点上运行一个 Pod 就可以看到该目录会被创建,并且cni0设备也会被创建出来。

网络插件运行成功了,node 状态也正常了:

  1. ➜~kubectlgetnodes
  2. NAMESTATUSROLESAGEVERSION
  3. master1Readycontrol-plane,master9m18sv1.22.1
  4. master2Readycontrol-plane,master7m11sv1.22.1
  5. master3Readycontrol-plane,master5m9sv1.22.1
  6. node1Ready<none>24sv1.22.1

测试高可用

上面我们搭建了3个 master 节点的高可用 Kubernetes 集群,接下来我们来测试下高可用是否生效。

首先查看其中任一个 kube-vip 的 Pod 日志:

  1. ➜~kubectllogs-fkube-vip-master1-nkube-system
  2. time="2021-09-07T08:53:24Z"level=infomsg="serverstarted"
  3. time="2021-09-07T08:53:24Z"level=infomsg="StartingKube-vipManagerwiththeARPengine"
  4. time="2021-09-07T08:53:24Z"level=infomsg="Namespace[kube-system],Hybridmode[true]"
  5. time="2021-09-07T08:53:24Z"level=infomsg="Beginningclustermembership,namespace[kube-system],lockname[plndr-svcs-lock],id[master1]"
  6. I090708:53:24.2056691leaderelection.go:243]attemptingtoacquireleaderleasekube-system/plndr-svcs-lock…
  7. time="2021-09-07T08:53:24Z"level=infomsg="Beginningclustermembership,namespace[kube-system],lockname[plndr-cp-lock],id[master1]"
  8. I090708:53:24.2061621leaderelection.go:243]attemptingtoacquireleaderleasekube-system/plndr-cp-lock…
  9. ……
  10. time="2021-09-07T08:55:55Z"level=infomsg="Node[master3]isassumingleadershipofthecluster"
  11. time="2021-09-07T08:55:55Z"level=infomsg="newleaderelected:master3"

可以看到 master3 现在是我们的 Leader,接下来我们将 master3 节点关掉,然后观察另外的 kube-vip 的日志变化:

  1. ➜~kubectllogs-fkube-vip-master2-nkube-system
  2. ……
  3. time="2021-09-07T08:55:55Z"level=infomsg="Node[master3]isassumingleadershipofthecluster"
  4. time="2021-09-07T08:55:55Z"level=infomsg="newleaderelected:master3"
  5. time="2021-09-07T10:28:58Z"level=infomsg="Node[master1]isassumingleadershipofthecluster"
  6. ……

可以看到 master1 节点获取了 kube-vip 的 Leader,也就是这个时候 vip 是绑定到 master1 节点的,而且这个时候集群仍然可以正常访问的。

Dashboard

v1.22.1 版本的集群需要安装最新的 2.0+ 版本的 Dashboard:

  1. #推荐使用下面这种方式
  2. ➜~wgethttps://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml
  3. ➜~virecommended.yaml
  4. #修改Service为NodePort类型
  5. ……
  6. kind:Service
  7. apiVersion:v1
  8. metadata:
  9. labels:
  10. k8s-app:kubernetes-dashboard
  11. name:kubernetes-dashboard
  12. namespace:kubernetes-dashboard
  13. spec:
  14. ports:
  15. -port:443
  16. targetPort:8443
  17. selector:
  18. k8s-app:kubernetes-dashboard
  19. type:NodePort#加上type=NodePort变成NodePort类型的服务
  20. ……

直接创建:

  1. ➜~kubectlapply-frecommended.yaml

新版本的 Dashboard 会被默认安装在 kubernetes-dashboard 这个命名空间下面:

  1. ➜~kubectlgetpods-nkubernetes-dashboard-owide
  2. NAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATES
  3. dashboard-metrics-scraper-856586f554-pllvt1/1Running024m10.88.0.7master<none><none>
  4. kubernetes-dashboard-76597d7df5-829981/1Running021m10.88.0.2node2<none><none>

我们仔细看可以发现上面的 Pod 分配的 IP 段是 10.88.xx.xx,包括前面自动安装的 CoreDNS 也是如此,我们前面不是配置的 podSubnet 为 10.244.0.0/16 吗?我们先去查看下 CNI 的配置文件:

  1. ➜~ls-la/etc/cni/net.d/
  2. total8
  3. drwxr-xr-x21001docker67Aug3116:45.
  4. drwxr-xr-x.31001docker19Jul3001:13..
  5. -rw-r–r–11001docker604Jul3001:1310-containerd-net.conflist
  6. -rw-r–r–1rootroot292Aug3116:4510-flannel.conflist

可以看到里面包含两个配置,一个是 10-containerd-net.conflist,另外一个是我们上面创建的 Flannel 网络插件生成的配置,我们的需求肯定是想使用 Flannel 的这个配置,我们可以查看下 containerd 这个自带的 cni 插件配置:

  1. ➜~cat/etc/cni/net.d/10-containerd-net.conflist
  2. {
  3. "cniVersion":"0.4.0",
  4. "name":"containerd-net",
  5. "plugins":[
  6. {
  7. "type":"bridge",
  8. "bridge":"cni0",
  9. "isGateway":true,
  10. "ipMasq":true,
  11. "promiscMode":true,
  12. "ipam":{
  13. "type":"host-local",
  14. "ranges":[
  15. [{
  16. "subnet":"10.88.0.0/16"
  17. }],
  18. [{
  19. "subnet":"2001:4860:4860::/64"
  20. }]
  21. ],
  22. "routes":[
  23. {"dst":"0.0.0.0/0"},
  24. {"dst":"::/0"}
  25. ]
  26. }
  27. },
  28. {
  29. "type":"portmap",
  30. "capabilities":{"portMappings":true}
  31. }
  32. ]
  33. }

可以看到上面的 IP 段恰好就是 10.88.0.0/16,但是这个 cni 插件类型是 bridge 网络,网桥的名称为 cni0:

  1. ➜~ipa
  2. 6:cni0:<BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP>mtu1500qdiscnoqueuestateUPgroupdefaultqlen1000
  3. link/ether9a:e7:eb:40:e8:66brdff:ff:ff:ff:ff:ff
  4. inet10.88.0.1/16brd10.88.255.255scopeglobalcni0
  5. valid_lftforeverpreferred_lftforever
  6. inet62001:4860:4860::1/64scopeglobal
  7. valid_lftforeverpreferred_lftforever
  8. inet6fe80::98e7:ebff:fe40:e866/64scopelink
  9. valid_lftforeverpreferred_lftforever

但是使用 bridge 网络的容器无法跨多个宿主机进行通信,跨主机通信需要借助其他的 cni 插件,比如上面我们安装的 Flannel,或者 Calico 等等,由于我们这里有两个 cni 配置,所以我们需要将 10-containerd-net.conflist 这个配置删除,因为如果这个目录中有多个 cni 配置文件,kubelet 将会使用按文件名的字典顺序排列的第一个作为配置文件,所以前面默认选择使用的是 containerd-net 这个插件。

  1. ➜~mv/etc/cni/net.d/10-containerd-net.conflist/etc/cni/net.d/10-containerd-net.conflist.bak
  2. ➜~ifconfigcni0down&&iplinkdeletecni0
  3. ➜~systemctldaemon-reload
  4. ➜~systemctlrestartcontainerdkubelet

然后记得重建 coredns 和 dashboard 的 Pod,重建后 Pod 的 IP 地址就正常了:

  1. ➜~kubectlgetpods-nkubernetes-dashboard-owide
  2. NAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATES
  3. dashboard-metrics-scraper-856586f554-tp8m51/1Running042s10.244.1.6node2<none><none>
  4. kubernetes-dashboard-76597d7df5-9rmbx1/1Running066s10.244.1.5node2<none><none>
  5. ➜~kubectlgetpods-nkube-system-owide-lk8s-app=kube-dns
  6. NAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATES
  7. coredns-7568f67dbd-n7bfx1/1Running05m40s10.244.1.2node2<none><none>
  8. coredns-7568f67dbd-plrv81/1Running03m47s10.244.1.4node2<none><none>

查看 Dashboard 的 NodePort 端口:

  1. ➜~kubectlgetsvc-nkubernetes-dashboard
  2. NAMETYPECLUSTER-IPEXTERNAL-IPPORT(S)AGE
  3. dashboard-metrics-scraperClusterIP10.99.37.172<none>8000/TCP25m
  4. kubernetes-dashboardNodePort10.103.102.27<none>443:31050/TCP25m

然后可以通过上面的 31050 端口去访问 Dashboard,要记住使用 https,Chrome 不生效可以使用Firefox 测试,如果没有 Firefox 下面打不开页面,可以点击下页面中的信任证书即可:

使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版)

信任证书

信任后就可以访问到 Dashboard 的登录页面了:

使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版)

Dashboard 登录页面

然后创建一个具有全局所有权限的用户来登录 Dashboard:

  1. #admin.yaml
  2. kind:ClusterRoleBinding
  3. apiVersion:rbac.authorization.k8s.io/v1
  4. metadata:
  5. name:admin
  6. roleRef:
  7. kind:ClusterRole
  8. name:cluster-admin
  9. apiGroup:rbac.authorization.k8s.io
  10. subjects:
  11. -kind:ServiceAccount
  12. name:admin
  13. namespace:kubernetes-dashboard
  14. apiVersion:v1
  15. kind:ServiceAccount
  16. metadata:
  17. name:admin
  18. namespace:kubernetes-dashboard

直接创建:

  1. ➜~kubectlapply-fadmin.yaml
  2. ➜~kubectlgetsecret-nkubernetes-dashboard|grepadmin-token
  3. admin-token-lwmmxkubernetes.io/service-account-token31d
  4. ➜~kubectlgetsecretadmin-token-lwmmx-ojsonpath={.data.token}-nkubernetes-dashboard|base64-d
  5. #会生成一串很长的base64后的字符串

然后用上面的 base64 解码后的字符串作为 token 登录 Dashboard 即可,新版本还新增了一个暗黑模式:

使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版)

k8s dashboard

最终我们就完成了使用 kubeadm 搭建 v1.22.1 版本的高可用 kubernetes 集群,使用 coredns、ipvs、flannel、containerd、kube-vip 这些组件。

清理

如果你的集群安装过程中遇到了其他问题,我们可以使用下面的命令来进行重置:

  1. ➜~kubeadmreset
  2. ➜~ifconfigcni0down&&iplinkdeletecni0
  3. ➜~ifconfigflannel.1down&&iplinkdeleteflannel.1
  4. ➜~rm-rf/var/lib/cni/

原文链接:https://mp.weixin.qq.com/s/ypIObV4ARzo-DOY81EDc_Q

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 行业资讯 使用 Kube-vip 搭建高可用的 Kubernetes 集群(完整版) https://www.kuaiidc.com/63372.html

相关文章

发表评论
暂无评论