前言 使用kubeadm搭建一套kubernetes集群很简单,但是一个单节点的master并不能满足我们在生产环境的需求。因此必须得解决单点的问题后才能考虑在生产环境大面积推广应用。
实践目标
至少2个以上的master节点可以同时管理集群; 集群的所有功能正常可用; 支持后续扩展; 环境准备 参考master单节点安装,此处不再具体描述。系统参数 修改系统内核参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 setenforce 0 sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config systemctl stop firewalld && systemctl disable firewalld swapoff -a sed -i 's/.*swap.*/#&/' /etc/fstab cat >> /etc/sysctl.conf <<eof net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 vm.swappiness=0 eof sysctl -p lsmod | grep ip
docker相关 安装docker。
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 cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 EOF yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum makecache fast yum -y install docker-ce systemctl enable docker systemctl start docker docker --version
安装相关组件 安装kubeadm必须组件
1 2 3 4 5 yum install -y kubelet kubeadm kubectl yum install -y kubelet-1.23.4 kubeadm-1.23.4 kubectl-1.23.4 --disableexcludes=kubernetes
配置NGINX代理 kube-apiserver高可用可以直接起多个节点,很多使用keepalive,haproxy来进行高可用配置,但是在大部分的公有云上无法使用vip。公有云上可以使用公有云提供的LoadBalance,这里我们使用nginx来代替. nginx stream 四层协议的转发、代理或者负载均衡.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 yum -y install nginx nginx-mod-stream stream { log_format main '$remote_addr [$time_local]' '$protocol $status $bytes_sent $bytes_received' '$session_time' ; server { listen 16443; proxy_pass kubeapi; access_log /var/log/nginx/access.log main; } upstream kubeapi { server 192.168.1.109:6443; server 192.168.1.217:6443; } }
部署集群 获取默认配置文件 导出
1 kubeadm config print init-defaults > kubeadm-config.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 apiVersion: kubeadm.k8s.io/v1beta3 bootstrapTokens: - groups : - system:bootstrappers:kubeadm:default-node-token token: abcdef.0123456789abcdef ttl: 24h0m0s usages: - signing - authentication kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.109 bindPort: 6443 nodeRegistration: criSocket: /var/run/dockershim.sock imagePullPolicy: IfNotPresent name: node taints: null --- apiServer: timeoutForControlPlane: 4m0s apiVersion: kubeadm.k8s.io/v1beta3 certificatesDir: /etc/kubernetes/pki clusterName: kubernetes controlPlaneEndpoint: 192.168.1.109:16443 controllerManager: {} dns: {} etcd: local : dataDir: /var/lib/etcd imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers kind: ClusterConfiguration kubernetesVersion: 1.23.4 networking: dnsDomain: cluster.local serviceSubnet: 10.96.0.0/12 podSubnet: 10.244.0.0/16 scheduler: {} --- apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration cgroupDriver: cgroupfs --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: ipvs
配置说明:
controlPlaneEndpoint:为集群apiserver监听端口16443 imageRepository:由于国内无法访问google镜像仓库k8s.gcr.io,这里指定为私有仓库地址 registry.cn-hangzhou.aliyuncs.com/google_containers podSubnet:指定的IP地址段与后续部署的网络插件相匹配 执行初始化 1 2 kubeadm init --config=kubeadm-config.yaml --upload-certs | tee kubeadm-init.log
该命令指定了初始化时需要使用的配置文件,其中添加–upload-certs参数可以在后续执行加入节点时自动分发证书文件。 低版本注意使用–experimental-upload-certs。
kubeadm init主要执行了以下操作:
[init]:指定版本进行初始化操作 [preflight] :初始化前的检查和下载所需要的Docker镜像文件 [kubelet-start]:生成kubelet的配置文件”/var/lib/kubelet/config.yaml”,没有这个文件kubelet无法启动,所以初始化之前的kubelet实际上启动失败。 [certificates]:生成Kubernetes使用的证书,存放在/etc/kubernetes/pki目录中。 [kubeconfig] :生成 KubeConfig 文件,存放在/etc/kubernetes目录中,组件之间通信需要使用对应文件。 [control-plane]:使用/etc/kubernetes/manifest目录下的YAML文件,安装 Master 组件。 [etcd]:使用/etc/kubernetes/manifest/etcd.yaml安装Etcd服务。 [wait-control-plane]:等待control-plan部署的Master组件启动。 [apiclient]:检查Master组件服务状态。 [uploadconfig]:更新配置 [kubelet]:使用configMap配置kubelet。 [patchnode]:更新CNI信息到Node上,通过注释的方式记录。 [mark-control-plane]:为当前节点打标签,打了角色Master,和不可调度标签,这样默认就不会使用Master节点来运行Pod。 [bootstrap-token]:生成token记录下来,后边使用kubeadm join往集群中添加节点时会用到 [addons]:安装附加组件CoreDNS和kube-proxy 无论是初始化失败或者集群已经完全搭建成功,你都可以直接执行kubeadm reset命令清理集群或节点,然后重新执行kubeadm init或kubeadm join相关操作即可。 注意清理.kube
目录
配置网络插件 calico
1 2 kubectl apply -f https://docs.projectcalico.org/v3.21/manifests/calico.yaml
其他节点加入集群 master join
1 2 3 4 kubeadm join 192.168.1.109:16443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:b9852b8ec72c5f26988763325e9da155de6136a3c3a62f48749bb4b6e09c37c0 \ --control-plane
执行后会自动生成相关文件和目录
1 2 3 4 5 6 7 8 [root@k8s-node-217 kubernetes] total 28 -rw------- 1 root root 5638 Feb 22 17:07 admin.conf -rw------- 1 root root 5673 Feb 22 17:07 controller-manager.conf -rw------- 1 root root 1955 Feb 22 17:07 kubelet.conf drwx------ 2 root root 96 Feb 22 17:07 manifests drwxr-xr-x 2 root root 288 Feb 22 17:07 pki -rw------- 1 root root 5621 Feb 22 17:07 scheduler.conf
如果在某些特殊情况下需要手动上传的话,注意传输以下文件即可: admin.conf pki/ca.* pki/front-proxy* pki/sa*
worker 新node
1 2 kubeadm join 192.168.1.109:16443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:b9852b8ec72c5f26988763325e9da155de6136a3c3a62f48749bb4b6e09c37c0
无论在master节点或node节点,要能够执行kubectl命令必须进行以下配置
1 2 3 mkdir -p $HOME /.kubesudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $(id -u):$(id -g) $HOME /.kube/config
检查集群 两台master节点展示信息一致。
1 2 3 4 5 6 7 8 9 10 11 12 [root@uat-109 ~] NAME STATUS ROLES AGE VERSION k8s-node-217 Ready control-plane,master 8m2s v1.23.4 master Ready control-plane,master 30h v1.23.4 test-216-tips Ready <none> 27h v1.23.4 [root@k8s-node-217 ~] NAME STATUS ROLES AGE VERSION k8s-node-217 Ready control-plane,master 8m9s v1.23.4 master Ready control-plane,master 30h v1.23.4 test-216-tips Ready <none> 27h v1.23.4
其他 删除节点 在master节点上执行:kubectl drain node-xxx --delete-local-data --force --ignore-daemonsets
当节点变成不可调度状态时候 SchedulingDisabled,执行kubectl delete node node-xxx
ipvs
参考:https://www.jianshu.com/p/89f126b241db
IPVS简介:
尽管 Kubernetes 在版本v1.6中已经支持5000个节点,但使用 iptables 的 kube-proxy 实 际上是将集群扩展到5000个节点的瓶颈。 在5000节点集群中使用 NodePort 服务,如 果有2000个服务并且每个服务有10个 pod,这将在每个工作节点上至少产生20000个 iptable 记录,这可能使内核非常繁忙。
ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层LAN交换,作为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs 可以将基于TCP和UDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。
我们知道kube-proxy支持 iptables 和 ipvs 两种模式, 在kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中 就添加支持了,从 v1.2版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于netfilter的。ipvs 会使用 iptables 进行包过滤、SNAT、masquared。 具体来说,ipvs 将使用ipset来存储需要DROP或masquared的流量的源或目标地址, 以确保 iptables 规则的数量是恒定的,这样我们就不需要关心我们有多少服务了。
启动ipvs的要求:
k8s版本 >= v1.11 使用ipvs需要安装相应的工具来处理”yum install ipset ipvsadm -y“ 确保 ipvs已经加载内核模块, ip_vs、ip_vs_rr、ip_vs_wrr、ip_vs_sh、 nf_conntrack_ipv4。如果这些内核模块不加载,当kube-proxy启动后,会退回到iptables模式。
先前基于iptables规则表的DNAT->SNAT方式来处理外部客户端到k8s集群pod内的流量 和集群内部流量(cluster-ip到pod ip),无需在宿主机上管理cluster-ip都由iptables来进行 管理。
使用IPVS后是需要对vs(虚拟服务也就是vip)进行管理,由于IPVS的DNAT钩子挂在 INPUT链上,因此必须要让内核识别 VIP(cluster-ip) 是本机的 IP。k8s 通过设置将 service cluster ip 绑定到虚拟网卡kube-ipvs0,其中下面的10.96.x.x都是VIP,也就 是cluster-ip。
kube-proxy 开启 ipvs
1 yum install ipset ipvsadm -y
修改ConfigMap的kube-system/kube-proxy中的config.conf,mode: “ipvs”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@master k8s] ... ipvs: excludeCIDRs: null minSyncPeriod: 0s scheduler: "" strictARP: false syncPeriod: 30s kind: KubeProxyConfiguration metricsBindAddress: 127.0.0.1:10249 mode: "ipvs" nodePortAddresses: null oomScoreAdj: -999 portRange: "" resourceContainer: /kube-proxy ... configmap/kube-proxy edited
对于Kubernetes来说,可以直接将这三个Pod删除之后,会自动重建。
1 2 3 4 [root@master k8s] kube-proxy-fn68r 1/1 Running 0 75s kube-proxy-hrjls 1/1 Running 0 78s kube-proxy-ltbqk 1/1 Running 0 77s
批量删除 kube-proxy
1 kubectl get pod -n kube-system | grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'
由于你已经通过ConfigMap修改了kube-proxy的配置,所以后期增加的Node节点,会直接使用ipvs模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 [root@master ~] I0222 09:25:27.699369 1 node.go:163] Successfully retrieved node IP: 192.168.1.109 I0222 09:25:27.699464 1 server_others.go:138] "Detected node IP" address="192.168.1.109" I0222 09:25:27.774905 1 server_others.go:269] "Using ipvs Proxier" I0222 09:25:27.774932 1 server_others.go:271] "Creating dualStackProxier for ipvs" I0222 09:25:27.775016 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" E0222 09:25:27.775284 1 proxier.go:379] "Can't set sysctl, kernel version doesn't satisfy minimum version requirements" sysctl="net/ipv4/vs/conn_reuse_mode" minimumKernelVersion="4.1" I0222 09:25:27.775454 1 proxier.go:438] "IPVS scheduler not specified, use rr by default" E0222 09:25:27.775637 1 proxier.go:379] "Can't set sysctl, kernel version doesn't satisfy minimum version requirements" sysctl="net/ipv4/vs/conn_reuse_mode" minimumKernelVersion="4.1" I0222 09:25:27.775756 1 proxier.go:438] "IPVS scheduler not specified, use rr by default" I0222 09:25:27.775850 1 ipset.go:113] "Ipset name truncated" ipSetName="KUBE-6-LOAD-BALANCER-SOURCE-CIDR" truncatedName="KUBE-6-LOAD-BALANCER-SOURCE-CID" I0222 09:25:27.775890 1 ipset.go:113] "Ipset name truncated" ipSetName="KUBE-6-NODE-PORT-LOCAL-SCTP-HASH" truncatedName="KUBE-6-NODE-PORT-LOCAL-SCTP-HAS" I0222 09:25:27.776321 1 server.go:656] "Version info" version="v1.23.4" I0222 09:25:27.783258 1 conntrack.go:52] "Setting nf_conntrack_max" nf_conntrack_max=131072 I0222 09:25:27.783815 1 config.go:317] "Starting service config controller" I0222 09:25:27.783883 1 shared_informer.go:240] Waiting for caches to sync for service config I0222 09:25:27.783942 1 config.go:226] "Starting endpoint slice config controller" I0222 09:25:27.783963 1 shared_informer.go:240] Waiting for caches to sync for endpoint slice config I0222 09:25:27.884501 1 shared_informer.go:247] Caches are synced for endpoint slice config I0222 09:25:27.884570 1 shared_informer.go:247] Caches are synced for service config
日志中打印出了Using ipvs Proxier,说明ipvs模式已经开启。
使用ipvsadm测试,可以查看之前创建的Service已经使用LVS创建了集群。
1 2 3 4 5 6 7 8 9 10 [root@master ~] IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP master:https rr -> master:sun-sr-https Masq 1 0 13 -> master1:sun-sr-https Masq 1 0 14 TCP master:domain rr TCP master:9153 rr UDP master:domain rr