K8s高可用集群部署----超详细(Detailed Deployment of k8s High Availability Cluster)

news2024/9/22 21:16:01

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老
导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。
常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等
数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等
懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

一.系统环境

本文主要基于Kubernetes1.23.1和Linux操作系统CentOS7.4。

服务器版本docker软件版本Kubernetes(k8s)集群版本CPU架构
CentOS Linux release 7.4.1708 (Core)Docker version 20.10.14v1.23.1x86_64

Kubernetes高可用集群总体架构图:

Kubernetes高可用集群架构图描述:

Kubernetes(k8s)配置文件是放在etcd集群里的,2个Kubernetes master节点都连接到etcd集群,就可以保证Kubernetes的master节点

数据同步,信息对等,我们刚开始是连接到Kubernetes的master1上的,master1出现故障之后,还需要手动切换连接到master2上,我

们可以使用haproxy做负载均衡器,我们连接到haproxy后,haproxy会把请求转发到后端realserver(master1和master2),master1故

障之后,haproxy检测到master1故障,会把请求转发给master2,如果害怕haproxy故障,可以使用Keepalive做haproxy的高可用,我

们连接Keepalive的VIP即可。

由于机器有限,我们本次Kubernetes高可用集群架构图如下:

Kubernetes高可用集群架构:k8sbalancemaster1作为master1节点,k8sbalancemaster2作为master2节点,k8sbalanceworker1作为worker节点,k8sbalanceetcd1作为etcd服务器,k8sbalanceetcd2作为etcd服务器,k8sbalancehaproxy1作为HAProxy服务器。

服务器操作系统版本CPU架构进程功能描述
k8sbalancehaproxy1/192.168.110.134CentOS Linux release 7.4.1708 (Core)x86_64haproxyHAProxy负载均衡器
k8sbalanceetcd1/192.168.110.135CentOS Linux release 7.4.1708 (Core)x86_64etcdetcd服务器
k8sbalanceetcd2/192.168.110.136CentOS Linux release 7.4.1708 (Core)x86_64etcdetcd服务器
k8sbalancemaster1/192.168.110.137CentOS Linux release 7.4.1708 (Core)x86_64docker,kube-apiserver,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calicok8s master1节点
k8sbalancemaster2/192.168.110.138CentOS Linux release 7.4.1708 (Core)x86_64docker,kube-apiserver,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calicok8s master2节点
k8sbalanceworker1/192.168.110.139CentOS Linux release 7.4.1708 (Core)x86_64docker,kubelet,kube-proxy,calicok8s worker节点

二.前言

Kubernetes是一个开源的容器编排平台,用于自动化地部署、扩展和管理容器化应用程序。在生产环境中,为了确保集群的高可用性,我们需要使用多个Master节点来实现冗余和故障切换。

三.Kubernetes(k8s)高可用简介

Kubernetes高可用集群由多个Master节点组成,每个Master节点都能够处理用户请求并执行相关操作。当任一Master节点发生故障时,其他节点可以接管其职责,从而保证整个集群的稳定运行。

本文将使用以下主要步骤来实现Kubernetes高可用集群:

  • 准备环境:安装所需的软件包和依赖项。
  • 配置负载均衡器:设置负载均衡器以实现流量的分发和故障切换。
  • 配置etcd集群:etcd集群存储k8s的配置文件和集群信息。
  • 初始化Master节点:选择一台Master节点,并进行初始化设置。
  • 添加额外的Master节点:将其他Master节点加入到集群中。
  • 添加worker节点:将worker节点加入到集群中。
  • 部署CNI网络插件calico:calico用于节点间的通信和配置网络策略。
  • 测试Kubernetes(k8s)的master节点数据同步。
  • 测试Kubernetes(k8s)集群的高可用。

四.配置机器基本环境

本次Kubernetes高可用集群共6台机器,我们先把6台机器都配置好基本环境,后面部署应用才会顺风顺水。

先配置各个节点的基本环境,6个节点都要同时设置,在此以k8sbalancehaproxy1节点作为示例。

首先设置主机名。

[root@localhost ~]# vim /etc/hostname

[root@localhost ~]# cat /etc/hostname
k8sbalancehaproxy1

查看默认的IP地址。

[root@localhost ~]# ifconfig
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.110.134  netmask 255.255.255.0  broadcast 192.168.110.255
        inet6 fe80::20c:29ff:fe09:7e88  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:09:7e:88  txqueuelen 1000  (Ethernet)
        RX packets 11476  bytes 4296221 (4.0 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 9366  bytes 6197543 (5.9 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1  (Local Loopback)
        RX packets 4020  bytes 239760 (234.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 4020  bytes 239760 (234.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

配置节点IP地址(可选),网卡配置详解。

[root@localhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens32

[root@localhost ~]# cat  /etc/sysconfig/network-scripts/ifcfg-ens32
TYPE=Ethernet
BOOTPROTO=static
NAME=ens32
DEVICE=ens32
ONBOOT=yes
DNS1=114.114.114.114
IPADDR=192.168.110.134
NETMASK=255.255.255.0
GATEWAY=192.168.110.2
ZONE=trusted

重启网络。

[root@localhost ~]# service network restart
Restarting network (via systemctl):                        [  确定  ]

[root@localhost ~]# systemctl restart NetworkManager

重启机器之后,主机名变为k8sbalancehaproxy1。

测试机器是否可以访问网络。

[root@k8sbalancehaproxy1 ~]# ping www.baidu.com
PING www.a.shifen.com (14.215.177.39) 56(84) bytes of data.
64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=1 ttl=128 time=34.1 ms
64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=2 ttl=128 time=34.2 ms
64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=3 ttl=128 time=41.9 ms
^C
--- www.a.shifen.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 34.123/36.765/41.958/3.672 ms

配置IP和主机名映射,其他节点的/etc/hosts文件内容也要一样。

[root@k8sbalancehaproxy1 ~]# vim /etc/hosts

[root@k8sbalancehaproxy1 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.110.134 k8sbalancehaproxy1
192.168.110.135 k8sbalanceetcd1
192.168.110.136 k8sbalanceetcd2
192.168.110.137 k8sbalancemaster1
192.168.110.138 k8sbalancemaster2
192.168.110.139 k8sbalanceworker1

可以ping通其他5个节点则成功。

[root@k8sbalancehaproxy1 ~]# ping k8sbalancehaproxy1
PING k8sbalancehaproxy1 (192.168.110.134) 56(84) bytes of data.
64 bytes from k8sbalancehaproxy1 (192.168.110.134): icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from k8sbalancehaproxy1 (192.168.110.134): icmp_seq=2 ttl=64 time=0.034 ms
64 bytes from k8sbalancehaproxy1 (192.168.110.134): icmp_seq=3 ttl=64 time=0.023 ms
^C
--- k8sbalancehaproxy1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.023/0.032/0.041/0.009 ms

[root@k8sbalancehaproxy1 ~]# ping k8sbalanceetcd1
PING k8sbalanceetcd1 (192.168.110.135) 56(84) bytes of data.
64 bytes from k8sbalanceetcd1 (192.168.110.135): icmp_seq=1 ttl=64 time=0.606 ms
64 bytes from k8sbalanceetcd1 (192.168.110.135): icmp_seq=2 ttl=64 time=0.438 ms
^C
--- k8sbalanceetcd1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.438/0.522/0.606/0.084 ms

[root@k8sbalancehaproxy1 ~]# ping k8sbalanceetcd2

[root@k8sbalancehaproxy1 ~]# ping k8sbalancemaster1

[root@k8sbalancehaproxy1 ~]# ping k8sbalancemaster2

[root@k8sbalancehaproxy1 ~]# ping k8sbalanceworker1

关闭屏保。

[root@k8sbalancehaproxy1 ~]# setterm -blank 0

下载新的yum源。

[root@k8sbalancehaproxy1 ~]# rm -rf /etc/yum.repos.d/* ;wget ftp://ftp.rhce.cc/k8s/* -P /etc/yum.repos.d/
--2022-04-09 17:48:37--  ftp://ftp.rhce.cc/k8s/*
           => “/etc/yum.repos.d/.listing”
正在解析主机 ftp.rhce.cc (ftp.rhce.cc)... 101.37.152.41
正在连接 ftp.rhce.cc (ftp.rhce.cc)|101.37.152.41|:21... 已连接。
正在以 anonymous 登录 ... 登录成功!
......

100%[=======================================================================================================================================================================>] 276         --.-K/s 用时 0s      

2022-04-09 17:48:40 (81.9 MB/s) - “/etc/yum.repos.d/k8s.repo” 已保存 [276]

新的repo文件如下。

[root@k8sbalancehaproxy1 ~]# ls /etc/yum.repos.d/
CentOS-Base.repo  docker-ce.repo  epel.repo  k8s.repo

关闭selinux,设置SELINUX=disabled。

[root@k8sbalancehaproxy1 ~]# vim /etc/selinux/config

[root@k8sbalancehaproxy1 ~]# cat /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of three two values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected. 
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted 

[root@k8sbalancehaproxy1 ~]# getenforce
Disabled

配置防火墙允许所有数据包通过。

[root@k8sbalancehaproxy1 ~]# firewall-cmd --set-default-zone=trusted
Warning: ZONE_ALREADY_SET: trusted
success

[root@k8sbalancehaproxy1 ~]# firewall-cmd --get-default-zone
trusted

Linux swapoff命令用于关闭系统交换分区(swap area),如果不关闭swap,就会在kubeadm初始化Kubernetes的时候报错:“[ERROR Swap]: running with swap on is not supported. Please disable swap”。

[root@k8sbalancehaproxy1 ~]# swapoff -a ;sed -i '/swap/d' /etc/fstab

[root@k8sbalancehaproxy1 ~]# cat /etc/fstab

#
# /etc/fstab
# Created by anaconda on Thu Oct 18 23:09:54 2018
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=9875fa5e-2eea-4fcc-a83e-5528c7d0f6a5 /                       xfs     defaults        0 0

五.部署haproxy负载均衡器

haproxy作为负载均衡器,现在部署haproxy。

安装haproxy。

[root@k8sbalancehaproxy1 ~]# yum -y install haproxy     
 
[root@k8sbalancehaproxy1 ~]# rpm -qa | grep haproxy
haproxy-1.5.18-9.el7_9.1.x86_64

修改haproxy配置文件/etc/haproxy/haproxy.cfg。

[root@k8sbalancehaproxy1 ~]# ls /etc/haproxy/
haproxy.cfg

[root@k8sbalancehaproxy1 ~]# vim /etc/haproxy/haproxy.cfg

[root@k8sbalancehaproxy1 ~]# tail -10 /etc/haproxy/haproxy.cfg

#k8s-masterlb这个名字可以随意起,*:6443表示监听6443端口,当有人通过haproxy访问6443端口
#把请求转发给后端的real server(k8s的master节点)   weight 1权重都是1
listen k8s-masterlb *:6443
    mode tcp
    #balance roundrobin表示轮询调度
    balance roundrobin
    #s1  s2 为k8s的两个master节点IP,weight都为1表示权重一样
    server s1 192.168.110.137:6443 weight 1
    server s2 192.168.110.138:6443 weight 1

设置haproxy开机自启动,现在启动haproxy。

[root@k8sbalancehaproxy1 ~]# systemctl enable haproxy --now

[root@k8sbalancehaproxy1 ~]# systemctl is-active haproxy
active

[root@k8sbalancehaproxy1 ~]# systemctl status haproxy
● haproxy.service - HAProxy Load Balancer
   Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; vendor preset: disabled)
   Active: active (running) since 六 2022-04-09 11:33:21 CST; 6h ago
 Main PID: 958 (haproxy-systemd)
   CGroup: /system.slice/haproxy.service
           ├─958 /usr/sbin/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid
           ├─963 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds
           └─964 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds

查看端口,已经开始监听6443端口了。

[root@k8sbalancehaproxy1 ~]# netstat -antup | grep 6443
tcp        0      0 0.0.0.0:6443            0.0.0.0:*               LISTEN      964/haproxy         

六.部署etcd集群

1.安装etcd。

[root@k8sbalanceetcd1 ~]# yum -y install etcd  

[root@k8sbalanceetcd1 ~]# rpm -qa | grep etcd
etcd-3.3.11-2.el7.centos.x86_64

2.修改etcd配置文件/etc/etcd/etcd.conf。

[root@k8sbalanceetcd1 ~]# ls /etc/etcd/
etcd.conf

[root@k8sbalanceetcd1 ~]# vim /etc/etcd/etcd.conf

[root@k8sbalanceetcd1 ~]# cat /etc/etcd/etcd.conf
#配置数据目录
ETCD_DATA_DIR="/var/lib/etcd/cluster.etcd"
ETCD_LISTEN_PEER_URLS="http://192.168.110.135:2380,http://localhost:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.110.135:2379,http://localhost:2379"
ETCD_NAME="etcd135"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.110.135:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.110.135:2379,http://localhost:2379"
##目前是两个节点,所以这里是两个节点的etcd
ETCD_INITIAL_CLUSTER="etcd135=http://192.168.110.135:2380,etcd136=http://192.168.110.136:2380"
##集群token
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
##新创建etcd集群的时候ETCD_INITIAL_CLUSTER_STATE="new",往已经存在的etcd集群添加etcd节点时:ETCD_INITIAL_CLUSTER_STATE="existing"
ETCD_INITIAL_CLUSTER_STATE="new"

3.设置etcd开机自启动并现在就启动。

[root@k8sbalanceetcd1 ~]# systemctl enable etcd --now   

[root@k8sbalanceetcd1 ~]# systemctl status etcd
● etcd.service - Etcd Server
   Loaded: loaded (/usr/lib/systemd/system/etcd.service; enabled; vendor preset: disabled)
   Active: active (running) since 六 2022-04-09 11:34:09 CST; 6h ago
 Main PID: 968 (etcd)
   CGroup: /system.slice/etcd.service
           └─968 /usr/bin/etcd --name=etcd135 --data-dir=/var/lib/etcd/cluster.etcd --listen-client-urls=http://192.168.110.135:2379,http://localhost:2379

4.另外一节点也安装etcd。

[root@k8sbalanceetcd2 ~]# yum -y install etcd   

5.修改etcd配置文件。

[root@k8sbalanceetcd2 ~]# vim /etc/etcd/etcd.conf

[root@k8sbalanceetcd2 ~]# ls /etc/etcd/
etcd.conf

[root@k8sbalanceetcd2 ~]# cat /etc/etcd/etcd.conf
#配置数据目录
ETCD_DATA_DIR="/var/lib/etcd/cluster.etcd"
ETCD_LISTEN_PEER_URLS="http://192.168.110.136:2380,http://localhost:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.110.136:2379,http://localhost:2379"
ETCD_NAME="etcd136"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.110.136:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.110.136:2379,http://localhost:2379"
##目前是两个节点,所以这里是两个节点的etcd
ETCD_INITIAL_CLUSTER="etcd135=http://192.168.110.135:2380,etcd136=http://192.168.110.136:2380"
##集群token
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
##新创建etcd集群的时候ETCD_INITIAL_CLUSTER_STATE="new",往已经存在的etcd集群添加etcd节点时:ETCD_INITIAL_CLUSTER_STATE="existing"
ETCD_INITIAL_CLUSTER_STATE="new"

6.设置etcd开机自启动,并现在就启动。

[root@k8sbalanceetcd2 ~]# systemctl enable etcd --now  

[root@k8sbalanceetcd2 ~]# systemctl status etcd  

7.两个etcd节点都启动之后,查看etcd集群成员。

[root@k8sbalanceetcd1 ~]# etcdctl member list
36adf18604130cea: name=etcd135 peerURLs=http://192.168.110.135:2380 clientURLs=http://192.168.110.135:2379,http://localhost:2379 isLeader=false
64d719893344455b: name=etcd136 peerURLs=http://192.168.110.136:2380 clientURLs=http://192.168.110.136:2379,http://localhost:2379 isLeader=true

8.查看集群健康状态。

[root@k8sbalanceetcd1 ~]# etcdctl cluster-health
member 36adf18604130cea is healthy: got healthy result from http://192.168.110.135:2379
member 64d719893344455b is healthy: got healthy result from http://192.168.110.136:2379
cluster is healthy

9.查看/下的数据。

[root@k8sbalanceetcd1 ~]# etcdctl ls /

自此,做共享数据的etcd集群配置好了。

七.部署Kubernetes(k8s) master HA

本次Kubernetes(k8s)集群,有2个master节点,1个worker节点。

7.1 配置docker

k8s是容器编排工具,需要容器,所以三个节点同时安装docker。

[root@k8sbalancemaster1 ~]# yum -y install docker-ce   

设置docker开机自启动并现在启动docker。

[root@k8sbalancemaster1 ~]# systemctl enable docker --now   

[root@k8sbalancemaster1 ~]# systemctl status docker    

查看docker版本。

[root@k8sbalancemaster1 ~]# docker --version
Docker version 20.10.14, build a224086

配置docker镜像加速器。

[root@k8sbalancemaster1 ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://frz7i079.mirror.aliyuncs.com"]
}

重启docker。

[root@k8sbalancemaster1 ~]# systemctl restart docker    

[root@k8sbalancemaster1 ~]# systemctl status docker    

设置iptables不对bridge的数据进行处理,启用IP路由转发功能。

[root@k8sbalancemaster1 ~]# cat <<EOF> /etc/sysctl.d/k8s.conf 
> net.bridge.bridge-nf-call-ip6tables = 1 
> net.bridge.bridge-nf-call-iptables = 1 
> net.ipv4.ip_forward = 1 
> EOF

使配置生效。

[root@k8sbalancemaster1 ~]# sysctl -p /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1

7.2 安装kubelet,kubeadm,kubectl

查看可用的kubeadm版本。

[root@k8sbalancemaster1 ~]# yum list --showduplicates kubeadm --disableexcludes=kubernetes | grep 1.23
kubeadm.x86_64                       1.23.1-0                        @kubernetes
kubeadm.x86_64                       1.23.0-0                        kubernetes 
kubeadm.x86_64                       1.23.1-0                        kubernetes 
kubeadm.x86_64                       1.23.2-0                        kubernetes 
kubeadm.x86_64                       1.23.3-0                        kubernetes 
kubeadm.x86_64                       1.23.4-0                        kubernetes 
kubeadm.x86_64                       1.23.5-0                        kubernetes 

此次k8s集群,我们安装k8s 1.23.1版本,三个节点都安装kubelet,kubeadm,kubectl,--disableexcludes=kubernetes 禁掉除了这个之外的别的仓库。

[root@k8sbalancemaster1 ~]# yum -y install kubelet-1.23.1-0 kubeadm-1.23.1-0 kubectl-1.23.1-0 --disableexcludes=kubernetes   

设置kubelet开机自启动并现在就启动。

[root@k8sbalancemaster1 ~]# systemctl enable kubelet --now    

注意:kubelet现在是启动不了的。

[root@k8sbalancemaster1 ~]# systemctl status kubelet   

docker的cgroup driver需要修改为systemd,默认docker的cgroup driver是cgroupfs,k8s 1.23.1版本,如果不加"exec-opts": ["native.cgroupdriver=systemd"]参数,进行kubeadm init初始化的时候会报错如下:failed to run Kubelet: misconfiguration: kubelet cgroup driver: "systemd" is differ 根据报错信息知道,是因为 k8s 和docker 的 cgroup driver 不一致导致的,k8s 的是 systemd ,而 docker 是cgroupfs。

[root@k8sbalancemaster1 ~]# cat /etc/docker/daemon.json 
{
"registry-mirrors": ["https://frz7i079.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"]
}

修改了/etc/docker/daemon.json之后,要重启docker进行生效。

[root@k8sbalancemaster1 ~]#  systemctl restart docker   

可以查看docker的 Cgroup Driver。

[root@k8sbalancemaster1 ~]# docker info | grep Cgroup
 Cgroup Driver: systemd
 Cgroup Version: 1

7.3 kubeadm初始化

在k8sbalancemaster1节点进行kubeadm init初始化,kubeadm初始化命令:kubeadm init --image-repository registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.1 --pod-network-cidr=10.244.0.0/16,本次我们使用的是外部的etcd集群,而不是以容器运行的etcd,所以不能使用以上命令初始化k8s集群,kubeadm init --help 可以查看k8s集群初始化的各种命令。本次我们使用kubeadm config文件进行k8s初始化。

kubeadm config文件可以去存在的k8s集群上生成,没有的话直接按照模板改就行。

[root@k8scloude1 ~]# kubeadm config view

Command "view" is deprecated, This command is deprecated and will be removed in a future release, please use 'kubectl get cm -o yaml -n kube-system kubeadm-config' to get the kubeadm config directly.

apiServer:

  extraArgs:

    authorization-mode: Node,RBAC

  timeoutForControlPlane: 4m0s

apiVersion: kubeadm.k8s.io/v1beta2

certificatesDir: /etc/kubernetes/pki

clusterName: kubernetes

controllerManager: {}

dns:

  type: CoreDNS

etcd:

  local:

    dataDir: /var/lib/etcd

imageRepository: registry.aliyuncs.com/google_containers

kind: ClusterConfiguration

kubernetesVersion: v1.21.9

networking:

  dnsDomain: cluster.local

  podSubnet: 10.244.0.0/16

  serviceSubnet: 10.96.0.0/12

scheduler: {}

生成kubeadm config文件。

[root@k8scloude1 ~]# kubeadm config view >kubeadm_config.yaml   

把kubeadm config文件传到k8sbalancemaster1机器。

[root@k8scloude1 ~]# scp kubeadm_config.yaml 192.168.110.137:~/    

修改kubeadm config文件:

  • controlPlaneEndpoint: "192.168.110.134:6443"指向haproxy的6443端口
  • http://192.168.110.135:2379 http://192.168.110.136:2379指向外部的etcd集群,数据是写入etcd集群的leader节点
  • kubernetesVersion: v1.23.1 指定k8s的版本
  • podSubnet: 10.244.0.0/16 指定pod网段地址
  • serviceSubnet: 10.96.0.0/12 指定服务网段地址
[root@k8sbalancemaster1 ~]# vim kubeadm_config.yaml

[root@k8sbalancemaster1 ~]# cat kubeadm_config.yaml
apiServer:
  extraArgs:
    authorization-mode: Node,RBAC
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
controlPlaneEndpoint: "192.168.110.134:6443"
clusterName: kubernetes
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  external:
    endpoints:
    - "http://192.168.110.135:2379"
    - "http://192.168.110.136:2379"
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: v1.23.1
networking:
  dnsDomain: cluster.local
  podSubnet: 10.244.0.0/16
  serviceSubnet: 10.96.0.0/12
scheduler: {}

进行kubeadm初始化时,注意内存不应该少于1700M,不然会报错如下: #[ERROR Mem]: the system RAM (1346 MB) is less than the minimum 1700 MB 内存不应该小于1700 MB。

kubeadm初始化。

[root@k8sbalancemaster1 ~]# kubeadm init --config=kubeadm_config.yaml  

进行kubeadm初始化的时候会去下载相应镜像,可以使用 docker images查看镜像下载情况。

[root@k8sbalancemaster1 ~]# docker images    

kubeadm初始化成功之后,按照提示拷贝kubeconfig文件并授权。

[root@k8sbalancemaster1 ~]# mkdir -p $HOME/.kube   

[root@k8sbalancemaster1 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config   

[root@k8sbalancemaster1 ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config   

7.4 添加master/worker节点到k8s集群

如果一个k8s集群有多个master,则以控制面的方式加入k8s集群,命令为:kubeadm join 192.168.110.134:6443 --token 3pc2kl.36wdzgtwutm9fll0 --discovery-token-ca-cert-hash sha256:0b311caadf2439b261849f50edadda3926c42f15b6f8cf6489f0dfec6393cf0b --control-plane

worker节点加入k8s集群则使用命令:kubeadm join 192.168.110.134:6443 --token 3pc2kl.36wdzgtwutm9fll0 --discovery-token-ca-cert-hash sha256:0b311caadf2439b261849f50edadda3926c42f15b6f8cf6489f0dfec6393cf0b

下面把k8sbalanceworker1加入集群。

[root@k8sbalanceworker1 ~]# kubeadm join 192.168.110.134:6443 --token 3pc2kl.36wdzgtwutm9fll0 --discovery-token-ca-cert-hash sha256:0b311caadf2439b261849f50edadda3926c42f15b6f8cf6489f0dfec6393cf0b   

k8sbalanceworker1加入集群之后,可以看到k8sbalanceworker1加入了集群,但是STATUS为NotReady,等我们安装了calico网络插件之后,STATUS会变为Ready的。

[root@k8sbalancemaster1 ~]# kubectl get node
NAME                STATUS   ROLES                  AGE    VERSION
k8sbalancemaster1   NotReady    control-plane,master   3d9h   v1.23.1
k8sbalanceworker1   NotReady    <none>                 3d9h   v1.23.1

把k8sbalancemaster2以控制面的方式加入k8s集群,作为第二个k8s master节点,执行如下命令会报错,原因是没有各种证书。

如果我们把k8sbalancemaster1下/etc/kubernetes/pki的所有证书都拷贝过来,k8sbalancemaster2加入集群的时候还是会报错。

[root@k8sbalancemaster2 ~]# kubeadm join 192.168.110.134:6443 --token 3pc2kl.36wdzgtwutm9fll0 --discovery-token-ca-cert-hash sha256:0b311caadf2439b261849f50edadda3926c42f15b6f8cf6489f0dfec6393cf0b --control-plane

kubeadm reset清空设置。

[root@k8sbalancemaster2 ~]# kubeadm reset  

把k8sbalancemaster1目录/etc/kubernetes/pki/下的ca.crt , ca.key ,sa.key ,sa.pub ,front-proxy-ca.key ,front-proxy-ca.crt 文件拷贝到k8sbalancemaster2目录/etc/kubernetes/pki下,再次把k8sbalancemaster2以控制面的方式加入k8s集群,这次k8sbalancemaster2就加入k8s集群成功了。

[root@k8sbalancemaster2 ~]# kubeadm join 192.168.110.134:6443 --token 3pc2kl.36wdzgtwutm9fll0 --discovery-token-ca-cert-hash sha256:0b311caadf2439b261849f50edadda3926c42f15b6f8cf6489f0dfec6393cf0b --control-plane   

按照提示拷贝kubeconfig文件并授权。

[root@k8sbalancemaster2 ~]# mkdir -p $HOME/.kube  

[root@k8sbalancemaster2 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config   

[root@k8sbalancemaster2 ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config   

k8sbalancemaster2加入集群之后,可以发现此时三个节点的状态都是NotReady的,是因为没有CNI网络插件,为了节点间的通信,需要安装cni网络插件,需要去官网下载calico.yaml文件。

[root@k8sbalancemaster1 ~]# kubectl get node
NAME                STATUS   ROLES                  AGE     VERSION
k8sbalancemaster1   NotReady    control-plane,master   3d10h   v1.23.1
k8sbalancemaster2   NotReady    control-plane,master   3d9h    v1.23.1
k8sbalanceworker1   NotReady    <none>                 3d10h   v1.23.1

7.5 部署CNI网络插件calico

虽然现在k8s集群已经有2个master节点,1个worker节点,但是此时三个节点的状态都是NotReady的,原因是没有CNI网络插件,为了节点间的通信,需要安装cni网络插件,常用的cni网络插件有calico和flannel,两者区别为:flannel不支持复杂的网络策略,calico支持网络策略,因为今后还要配置k8s网络策略networkpolicy,所以本文选用的cni网络插件为calico!

创建放calico文件的目录。

[root@k8sbalancemaster1 ~]# mkdir cni  

[root@k8sbalancemaster1 ~]# cd cni/

下载calico部署文件。

[root@k8sbalancemaster1 cni]# curl https://docs.projectcalico.org/manifests/calico.yaml -O      

[root@k8sbalancemaster1 cni]# ls
calico.yaml

查看需要下载的calico镜像,这四个镜像需要在所有节点都下载。

[root@k8sbalancemaster1 cni]# grep image calico.yaml
          image: docker.io/calico/cni:v3.22.1
          image: docker.io/calico/cni:v3.22.1
          image: docker.io/calico/pod2daemon-flexvol:v3.22.1
          image: docker.io/calico/node:v3.22.1
          image: docker.io/calico/kube-controllers:v3.22.1

拉取镜像。

[root@k8sbalancemaster1 cni]# docker pull docker.io/calico/cni:v3.22.1  
[root@k8sbalancemaster1 cni]# docker pull docker.io/calico/node:v3.22.1  
[root@k8sbalancemaster1 cni]# docker pull docker.io/calico/kube-controllers:v3.22.1  
[root@k8sbalancemaster1 cni]# docker pull docker.io/calico/pod2daemon-flexvol:v3.22.1  

[root@k8sbalancemaster1 cni]# docker images | grep calico
calico/kube-controllers                                           v3.22.1   c0c6672a66a5   5 weeks ago    132MB
calico/cni                                                        v3.22.1   2a8ef6985a3e   5 weeks ago    236MB
calico/pod2daemon-flexvol                                         v3.22.1   17300d20daf9   5 weeks ago    19.7MB
calico/node                                                       v3.22.1   7a71aca7b60f   5 weeks ago    198MB

#下载calico镜像
[root@k8sbalancemaster2 ~]# docker pull docker.io/calico/cni:v3.22.1  
[root@k8sbalancemaster2 ~]# docker pull docker.io/calico/node:v3.22.1   
[root@k8sbalancemaster2 ~]# docker pull docker.io/calico/kube-controllers:v3.22.1  
[root@k8sbalancemaster2 ~]# docker pull docker.io/calico/pod2daemon-flexvol:v3.22.1  

[root@k8sbalancemaster2 ~]# docker images | grep calico
calico/kube-controllers                                           v3.22.1   c0c6672a66a5   5 weeks ago    132MB
calico/cni                                                        v3.22.1   2a8ef6985a3e   5 weeks ago    236MB
calico/pod2daemon-flexvol                                         v3.22.1   17300d20daf9   5 weeks ago    19.7MB
calico/node                                                       v3.22.1   7a71aca7b60f   5 weeks ago    198MB

#下载calico镜像
[root@k8sbalanceworker1 ~]# docker pull docker.io/calico/cni:v3.22.1   
[root@k8sbalanceworker1 ~]# docker pull docker.io/calico/node:v3.22.1  
[root@k8sbalanceworker1 ~]# docker pull docker.io/calico/kube-controllers:v3.22.1  
[root@k8sbalanceworker1 ~]# docker pull docker.io/calico/pod2daemon-flexvol:v3.22.1   

[root@k8sbalanceworker1 ~]# docker images | grep calico
calico/kube-controllers                              v3.22.1   c0c6672a66a5   5 weeks ago    132MB
calico/cni                                           v3.22.1   2a8ef6985a3e   5 weeks ago    236MB
calico/pod2daemon-flexvol                            v3.22.1   17300d20daf9   5 weeks ago    19.7MB
calico/node                                          v3.22.1   7a71aca7b60f   5 weeks ago    198MB

安装calico。

[root@k8sbalancemaster1 cni]# kubectl apply -f calico.yaml   

查看ds。

[root@k8sbalancemaster1 cni]# kubectl get ds
No resources found in default namespace.

[root@k8sbalancemaster1 cni]# kubectl get ds -A
NAMESPACE     NAME          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   calico-node   3         3         3       3            3           kubernetes.io/os=linux   3d9h
kube-system   kube-proxy    3         3         3       3            3           kubernetes.io/os=linux   3d10h

7.6 配置kubectl命令tab键自动补全

查看kubectl自动补全命令。

[root@k8sbalancemaster1 cni]# kubectl --help | grep bash
  completion    Output shell completion code for the specified shell (bash, zsh or fish)

添加source <(kubectl completion bash)到/etc/profile,并使配置生效。

[root@k8sbalancemaster1 cni]# vim /etc/profile   

[root@k8sbalancemaster1 cni]# grep completion /etc/profile
source <(kubectl completion bash)

[root@k8sbalancemaster1 cni]# source /etc/profile

此时即可kubectl命令tab键自动补全,可以看到所有k8s节点都是Ready状态。

[root@k8sbalancemaster1 cni]# kubectl get node
NAME                STATUS   ROLES                  AGE     VERSION
k8sbalancemaster1   Ready    control-plane,master   3d12h   v1.23.1
k8sbalancemaster2   Ready    control-plane,master   3d11h   v1.23.1
k8sbalanceworker1   Ready    <none>                 3d12h   v1.23.1

八.测试k8s的两个master节点数据是否能同步

查看namespace。

[root@k8sbalancemaster1 cni]# kubectl get ns
NAME              STATUS   AGE
default           Active   3d12h
kube-node-lease   Active   3d12h
kube-public       Active   3d12h
kube-system       Active   3d12h

创建masterha命名空间。

[root@k8sbalancemaster1 cni]# kubectl create ns masterha
namespace/masterha created

在master1节点创建命名空间masterha,在master2上也可以看到该命名空间。

[root@k8sbalancemaster2 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   3d12h
kube-node-lease   Active   3d12h
kube-public       Active   3d12h
kube-system       Active   3d12h
masterha          Active   17s

在master2创建命名空间master2。

[root@k8sbalancemaster2 ~]# kubectl create ns master2
namespace/master2 created

在master2节点创建命名空间master2,在master1上也可以看到该命名空间。

[root@k8sbalancemaster1 cni]# kubectl get ns
NAME              STATUS   AGE
default           Active   3d12h
kube-node-lease   Active   3d12h
kube-public       Active   3d12h
kube-system       Active   3d12h
master2           Active   20s
masterha          Active   51s

下面测试k8s的两个master,其中一个master宕机,k8s集群是否能正常工作。

把k8sbalancemaster1节点关机。

[root@k8sbalancemaster1 cni]# init 0

把k8sbalancemaster1节点关机之后,k8sbalancemaster2也可以正常查看节点状态。

[root@k8sbalancemaster2 ~]# kubectl get node
Unable to connect to the server: net/http: TLS handshake timeout

[root@k8sbalancemaster2 ~]# kubectl get node
NAME                STATUS     ROLES                  AGE     VERSION
k8sbalancemaster1   NotReady   control-plane,master   3d12h   v1.23.1
k8sbalancemaster2   Ready      control-plane,master   3d11h   v1.23.1
k8sbalanceworker1   Ready      <none>                 3d12h   v1.23.1

k8sbalancemaster2也可以创建命名空间和查看命名空间。

[root@k8sbalancemaster2 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   3d12h
kube-node-lease   Active   3d12h
kube-public       Active   3d12h
kube-system       Active   3d12h
master2           Active   4m16s
masterha          Active   4m47s

[root@k8sbalancemaster2 ~]# kubectl create ns yoyo
namespace/yoyo created

[root@k8sbalancemaster2 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   3d12h
kube-node-lease   Active   3d12h
kube-public       Active   3d12h
kube-system       Active   3d12h
master2           Active   5m58s
masterha          Active   6m29s
yoyo              Active   3s

现在启动k8sbalancemaster1。

可以发现,k8s的一个master节点关闭之后,只要另外一个master还在运行,集群就还可以正常运行,并且k8sbalancemaster1关闭期间,在k8sbalancemaster2创建的数据,等k8sbalancemaster1恢复之后会自动同步数据。

[root@k8sbalancemaster1 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   3d12h
kube-node-lease   Active   3d12h
kube-public       Active   3d12h
kube-system       Active   3d12h
master2           Active   8m23s
masterha          Active   8m54s
yoyo              Active   2m28s

现在整个集群都是正常的了。

[root@k8sbalancemaster1 ~]# kubectl get node
NAME                STATUS   ROLES                  AGE     VERSION
k8sbalancemaster1   Ready    control-plane,master   3d12h   v1.23.1
k8sbalancemaster2   Ready    control-plane,master   3d11h   v1.23.1
k8sbalanceworker1   Ready    <none>                 3d12h   v1.23.1

九.使用客户端访问k8s集群

接下来使用客户端访问k8s集群,把etcd2机器作为k8s的客户端。

在k8sbalancemaster1查看kubectl文件位置。

[root@k8sbalancemaster1 ~]# which kubectl
/usr/bin/kubectl

把kubectl文件拷贝到客户端,或者客户端直接下载kubectl文件也可以。

[root@k8sbalancemaster1 ~]# scp /usr/bin/kubectl 192.168.110.131:~/    

从k8s集群拷贝一个kubectl文件或者下载一个kubectl文件。

[root@etcd2 ~]# mv kubectl /usr/bin/  

[root@etcd2 ~]# which kubectl
/usr/bin/kubectl

现在客户端是访问不了k8s集群的。

[root@etcd2 ~]# kubectl get node
The connection to the server localhost:8080 was refused - did you specify the right host or port?

客户端访问k8s集群可以使用kubeconfig文件的方式,也可以通过token的方式。

本次使用kubeconfig文件访问k8s集群,先在k8sbalancemaster1节点创建一个kubeconfig文件。

创建存放kubeconfig文件的目录。

[root@k8sbalancemaster1 ~]# mkdir ca  

[root@k8sbalancemaster1 ~]# cd ca

[root@k8sbalancemaster1 ca]# pwd
/root/ca

下面开始申请证书,创建私钥,名字可以自己命名为haproxy.key,因为我们是通过haproxy负载均衡,把请求转发给两个k8s的master节点的,所以我们创建haproxy用户。

[root@k8sbalancemaster1 ca]# openssl genrsa -out haproxy.key 2048  

利用刚生成的私钥haproxy.key 生成证书请求文件 haproxy.csr,CN 的值为haproxy,就是我们授权的用户。

[root@k8sbalancemaster1 ca]# openssl req -new -key haproxy.key -out haproxy.csr -subj "/CN=haproxy/O=cloude2022"   

对证书请求文件haproxy.csr进行 base64 编码。

[root@k8sbalancemaster1 ca]# cat haproxy.csr | base64 | tr -d "\n"   

编写申请证书请求文件的 yaml 文件,注意:对于k8s V1.21.1版本,我们使用的api版本为:apiVersion: certificates.k8s.io/v1beta1 ,并且注释掉signerName: kubernetes.io/legacy-aa,但是对于k8s v1.23.1版本,api版本为apiVersion: certificates.k8s.io/v1,并且需要signerName,经过测试,signerName: kubernetes.io/kube-apiserver-client能正确生成证书请求文件,另外两种signerName都有问题,注意这里 apiVersion 要带 beta1,否则 signerName 那行就不能注释掉,但这样的话后面的 操作就不能获取到证书。这里 request 里的是 base64 编码之后的证书请求文件。

[root@k8sbalancemaster1 ca]# vim csr.yaml

[root@k8sbalancemaster1 ca]# cat csr.yaml
#apiVersion: certificates.k8s.io/v1beta1
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: haproxy
spec:
  groups:
  - system:authenticated
  #signerName: kubernetes.io/legacy-aa 
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2JEQ0NBVlFDQVFBd0p6RVFNQTRHQTFVRUF3d0hhR0Z3Y205NGVURVRNQkVHQTFVRUNnd0tZMnh2ZFdSbApNakF5TWpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTNMbXkyRnN3azZweFRWCmZ5SmhnUEVLSnZvcHN4bnVERGF5UStFSlFaWlk0SjA5cXlndXVvaXRxTTZ5YTRUcEV1Uy9wWldEajJOTjYwOTIKWmhCcUxTMzhsMGlQWE5lbzRLRlVQUEVQc2ZKeEgrclNGOUg1bE44VjlQSnJHZ1pDdFJITC8rUlNTc1N2ZkJMZgpmdThZL0N3czUvNXdMVXkyL1gySW5GWGUyTVlTNjZmWHBOY1VaUmxnUEVkZTJoK1BHemwrWEwrYzN3c080aEduCjlXYmRhS2R4YVJvaW9zc1VaRFlxcnQwOGFsdjNHdDJSYkRFUDhTLzExMWFTbEQ0blZKTHhZdUM5VXdib3RTdTMKeXN5RzVHUmZmMmpMMlBJaENoMFd0ZUl1clRQY2JTSSt2bklPb29XdjBQeDdzRzlnMFpVWW54RFpHdzU4Q3JhTApieUZlVHdNQ0F3RUFBYUFBTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFDSXJpelJXVzB2K1FadlZ4NG5VR2pnCjFGaXdaOWg3YW1sdzdQUDUrcFRFNG40MGh3Y1B4Z3k3cDhoaG9VY2VsRWtxM0ZLMm5tTjFtaGdVbFJrWHdVQS8KWWtNd3BXWTE1TE82Zmtod1YrODQ0MVRkN01mTWFPR25SNHAzV1NId3dtQWJyb0dVVm54NFZWcEpFYi9SQTZ4TQpLc3FjTDJpbG5IK2xPZkNEODhnSndwWGxjQ3BxbnEvRTFUUmt0WUZuKzZPSWZzRGsvVWRxN0tPRFBvakN5ZFlZClNsL2lFS094TlQwam1MSWRpZ0RGSXNRa2RxUXRGZnNCMjF5K1krNVJDeGZabGVkRTRIb0VHNnJSZTNtR01peDMKMm1pNG9TTm00MzhacEUrNjliOCtFN3pzbUNZcHNMWnBzSEhUdzlLVzBENUFOY3dWSGVTbk9rZWV4djRoK0hWbQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K
  #signerName: kubernetes.io/kubelet-serving
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - client auth

申请证书。

[root@k8sbalancemaster1 ca]# kubectl apply -f csr.yaml   

查看已经发出证书申请的请求。

[root@k8sbalancemaster1 ca]# kubectl get csr -o wide   

批准证书。

[root@k8sbalancemaster1 ca]# kubectl certificate approve haproxy   

查看审批通过的证书。

[root@k8sbalancemaster1 ca]# kubectl get csr -o wide

[root@k8sbalancemaster1 ca]# kubectl get csr haproxy -o yaml

只查看certificate字段。

[root@k8sbalancemaster1 ca]# kubectl get csr/haproxy -o jsonpath='{.status.certificate}'

对certificate解码并导出证书文件。

[root@k8sbalancemaster1 ca]# kubectl get csr/haproxy -o jsonpath='{.status.certificate}' | base64 -d > haproxy.crt    

[root@k8sbalancemaster1 ca]# cat haproxy.crt
-----BEGIN CERTIFICATE-----
MIIDDTCCAfWgAwIBAgIRAMtBJdW9NhxGrZeQ6kxQ7powDQYJKoZIhvcNAQELBQAw
FTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0yMjA0MDgwOTE5NTFaFw0yMzA0MDgw
OTE5NTFaMCcxEzARBgNVBAoTCmNsb3VkZTIwMjIxEDAOBgNVBAMTB2hhcHJveHkw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNy5sthbMJOqcU1X8iYYDx
Cib6KbMZ7gw2skPhCUGWWOCdPasoLrqIrajOsmuE6RLkv6WVg49jTetPdmYQai0t
/JdIj1zXqOChVDzxD7HycR/q0hfR+ZTfFfTyaxoGQrURy//kUkrEr3wS337vGPws
LOf+cC1Mtv19iJxV3tjGEuun16TXFGUZYDxHXtofjxs5fly/nN8LDuIRp/Vm3Win
cWkaIqLLFGQ2Kq7dPGpb9xrdkWwxD/Ev9ddWkpQ+J1SS8WLgvVMG6LUrt8rMhuRk
X39oy9jyIQodFrXiLq0z3G0iPr5yDqKFr9D8e7BvYNGVGJ8Q2RsOfAq2i28hXk8D
AgMBAAGjRjBEMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYD
VR0jBBgwFoAUk+IKVztCgmAPMQOPURy9OqPMy9owDQYJKoZIhvcNAQELBQADggEB
ACwohGXvBvQ4Yrx+Vdt7Q5IUInqa2XHHZ5XWlyqFVctR4IJ/PJz/B7DnWIFiwSJQ
GZDtBvM63+u23zED8EMveggTkB23P6y8/Wqznt8zsGGARYLp73oCqWIQcWpnrrnA
whGYOK6x6iRpHrHWrrfn+wIr/vQIG2glj7FxRJpAmISLtqdLihRIQ2vITRdRqYXn
wnJIKCtVyK5T78pnZRJEC4pQsfcX+xNH/sA8HVY04YnhzqtyDyuuA0IxMmBV34bL
34AWyiYzo7QvVKC7LkMVpIfZ2V7755RLm6oPTgPD5P6/uCRpI3pRlg83mRuRH0W7
dV0DcIQ/63k8cR/ovU9Qbrc=
-----END CERTIFICATE-----

拷贝 CA 证书到当前目录。

[root@k8sbalancemaster1 ca]# cp /etc/kubernetes/pki/ca.crt .    

kubeconfig文件包含3个字段:cluster,user,context上下文(可以把cluster和user关联在一起)。

kubeconfig文件里,clusters 字段指定 kubernetes 集群的信息,users 指定用户,contexts 用于 指定上下文包括用户默认所在的命名空间等信息。

设置集群字段:

  • --kubeconfig指定生成的kubeconfig文件名,
  • set-cluster指定集群名,
  • --server指定连接到哪个k8s上,--server设置连接到哪一个k8s master节点上,我们可以连接master1或者master2,haproxy是我们的负载均衡器,我们连接haproxy的6443端口,haproxy会把请求转发给后端的两个master节点,所以我们--server=https://192.168.110.134:6443连接的是haproxy端口。
  • --certificate-authority 指定CA证书,
  • --embed-certs=true 的意思是把CA证书内 容写入到此 kubeconfig >文件里。
[root@k8sbalancemaster1 ca]# kubectl config --kubeconfig=haproxykubeconfig set-cluster clusterhaproxy --server=https://192.168.110.134:6443 --certificate-authority=ca.crt --embed-certs=true    

设置用户字段。

[root@k8sbalancemaster1 ca]# kubectl config --kubeconfig=haproxykubeconfig set-credentials haproxy --client-certificate=haproxy.crt --client-key=haproxy.key --embed-certs=true   

设置上下文字段。

[root@k8sbalancemaster1 ca]# kubectl config --kubeconfig=haproxykubeconfig set-context contexthaproxy --cluster=clusterhaproxy --namespace=default --user=haproxy  

修改haproxykubeconfig文件,把当前上下文修改为current-context: "contexthaproxy"。

[root@k8sbalancemaster1 ca]# vim haproxykubeconfig

[root@k8sbalancemaster1 ca]# cat haproxykubeconfig
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1EUXdOekUzTWprd05Wb1hEVE15TURRd05ERTNNamt3TlZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTktJCkFUTk8wd2ZFR2ZVR1UxcG1URUtFMy9Jbk9GRkdkSXQ4S1BON2Q3a0RvbFlvbmN2TjRIYWttRmJ0T2FmY2lUakoKNnNFRG81VExXbFd4elZ6MThuWVJoYW45TWplUXNROGk3cHIxTnp4S3ZpbXNMSE9VTEt6VzhjL1JlbmJnRDNoTQpVU2JwbUo4UGhBMXhGZEpIOEJaclh4QTVQRFo4cjQ4TGZReVREZFFQSmh5OE9qN1JsOXkwS3BlbUlHOXhBanNBCkliQWlITFZIZXRaMmRRSStJYnZRbDB5L1dybVc0WFFNeWJ0VXFYUTFWT3F5a2VGeUdyelR3aFhVYTVJanQ1cnYKVFNOV3RDM21FQXJ2Nmk5VDlOY3VKcXdiVWgxZUJsT0Vkc0hYdm4yOCtVRzJFeFdTV3AxY0dYbDd0bkhkT1kwZAp4OFQ1NEVrQXlJM0lLR3l3Sy9NQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZKUGlDbGM3UW9KZ0R6RURqMUVjdlRxanpNdmFNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSHV0em82WEFkSjBUbU8zRFFxRgp6bkVHOGNuQW5IbjRWZVZ6dWNrcVV0aEV5d3J6ekF0U0dhazlZM2tlVjlkSXhGN1pwUHc4bHN3T3FPbGJOQldTCjMxaHhja3hac3V6MTBOZmduTnlLa3UwV2pyVmxuOU5EZjhEcWRuR0psRXVHQ25ZTCtiMFJzcE9tdFNJQXZZVlAKckdleTAwK3U4NmsyMVE3dUlqK1oyWkhJUDJiUysxNGQrUTJSeVFuYnVkV1JERm4zK0twL2p1ZGJqRHVvRXZKNgpxVkl6ZU9kY0VYQ2ZEanVrdkY4VXlBVUQrTm9BSTNqbWdSbVZMMDRTUGRReUpPcnRUZ1hmYW9xYTBxVVI1Z1V3CjEvUmtMc295Q21UMVhMY3FnYllQSU1VcWpWanRidDFSTXpsQ3lUUkJWRU1UYlJYa1NVcklLUlZwaEU2ZTRXc1AKaFJjPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
    server: https://192.168.110.134:6443
  name: clusterhaproxy
contexts:
- context:
    cluster: clusterhaproxy
    namespace: default
    user: haproxy
  name: contexthaproxy
current-context: "contexthaproxy"
kind: Config
preferences: {}
users:
- name: haproxy
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lSQU10QkpkVzlOaHhHclplUTZreFE3cG93RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TWpBME1EZ3dPVEU1TlRGYUZ3MHlNekEwTURndwpPVEU1TlRGYU1DY3hFekFSQmdOVkJBb1RDbU5zYjNWa1pUSXdNakl4RURBT0JnTlZCQU1UQjJoaGNISnZlSGt3CmdnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUROeTVzdGhiTUpPcWNVMVg4aVlZRHgKQ2liNktiTVo3Z3cyc2tQaENVR1dXT0NkUGFzb0xycUlyYWpPc211RTZSTGt2NldWZzQ5alRldFBkbVlRYWkwdAovSmRJajF6WHFPQ2hWRHp4RDdIeWNSL3EwaGZSK1pUZkZmVHlheG9HUXJVUnkvL2tVa3JFcjN3UzMzN3ZHUHdzCkxPZitjQzFNdHYxOWlKeFYzdGpHRXV1bjE2VFhGR1VaWUR4SFh0b2ZqeHM1Zmx5L25OOExEdUlScC9WbTNXaW4KY1drYUlxTExGR1EyS3E3ZFBHcGI5eHJka1d3eEQvRXY5ZGRXa3BRK0oxU1M4V0xndlZNRzZMVXJ0OHJNaHVSawpYMzlveTlqeUlRb2RGclhpTHEwejNHMGlQcjV5RHFLRnI5RDhlN0J2WU5HVkdKOFEyUnNPZkFxMmkyOGhYazhECkFnTUJBQUdqUmpCRU1CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TUNNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WUQKVlIwakJCZ3dGb0FVaytJS1Z6dENnbUFQTVFPUFVSeTlPcVBNeTlvd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBQ3dvaEdYdkJ2UTRZcngrVmR0N1E1SVVJbnFhMlhISFo1WFdseXFGVmN0UjRJSi9QSnovQjdEbldJRml3U0pRCkdaRHRCdk02Myt1MjN6RUQ4RU12ZWdnVGtCMjNQNnk4L1dxem50OHpzR0dBUllMcDczb0NxV0lRY1dwbnJybkEKd2hHWU9LNng2aVJwSHJIV3JyZm4rd0lyL3ZRSUcyZ2xqN0Z4UkpwQW1JU0x0cWRMaWhSSVEydklUUmRScVlYbgp3bkpJS0N0VnlLNVQ3OHBuWlJKRUM0cFFzZmNYK3hOSC9zQThIVlkwNFluaHpxdHlEeXV1QTBJeE1tQlYzNGJMCjM0QVd5aVl6bzdRdlZLQzdMa01WcElmWjJWNzc1NVJMbTZvUFRnUEQ1UDYvdUNScEkzcFJsZzgzbVJ1UkgwVzcKZFYwRGNJUS82M2s4Y1Ivb3ZVOVFicmM9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBemN1YkxZV3pDVHFuRk5WL0ltR0E4UW9tK2ltekdlNE1OckpENFFsQmxsamduVDJyCktDNjZpSzJvenJKcmhPa1M1TCtsbFlPUFkwM3JUM1ptRUdvdExmeVhTSTljMTZqZ29WUTg4USt4OG5FZjZ0SVgKMGZtVTN4WDA4bXNhQmtLMUVjdi81RkpLeEs5OEV0OSs3eGo4TEN6bi9uQXRUTGI5ZllpY1ZkN1l4aExycDllawoxeFJsR1dBOFIxN2FINDhiT1g1Y3Y1emZDdzdpRWFmMVp0MW9wM0ZwR2lLaXl4UmtOaXF1M1R4cVcvY2EzWkZzCk1RL3hML1hYVnBLVVBpZFVrdkZpNEwxVEJ1aTFLN2ZLeklia1pGOS9hTXZZOGlFS0hSYTE0aTZ0TTl4dElqNisKY2c2aWhhL1EvSHV3YjJEUmxSaWZFTmtiRG53S3RvdHZJVjVQQXdJREFRQUJBb0lCQVFDWDdldlhGTENUYkxDegpDZGI5Qzl6RWxza2x3S2xQeUZWT0FCZHF5SW1hTkcxR3lLTldYQUVzTElER2NDUStrRTk1Zng4QW5ZcTdObWcxClZ1U00wOFlkQURDenlkc3gvNlF1bG1FVFdwSDF1Wnhsb01zaklrM00wSW53ZWk5UlZlZ1ZoblNaSEVQRXB3VkQKYmFwcFhCbTNoME9TclVCVU5YZzVPQ1NxcElXRzNGYm04dGZZcGlMV2d6a08zRU1mYWlxZHZSaVBlbTM2WjNIYwpjdWx5RXpCMjZXdXZadzFKRjgwdVBaVE5PcVJ2VnpmZWlzdFhPa0xhdEpXM3ZJbFFUaGE5eG9LL3orZmduazVmCittanFzWUluNU5HVDJmNXNPcEV5U1BQRDZOaGxFc3RzU2g3QTFZendTVGZKNm8xUkR1aFR5cXk2U1pON0NkWEYKbmR3K2tGRFJBb0dCQVBuOWFQcWRDdEVVMGlPZ1FkL1FGQVoyaEkxMXVGQWdNU2ZEUUMrMVBnSGV0SWZMeGZqYQpOZFMyVXdnRW5mazRrNTdwQUdYOHZCVTlLTmZuZXdXQjBUZHY3UkdDUmhOUkdEVWdybVppZmIvS3duU0xSMmxQCmlvSWlWTmpjdy8vdE4vRlljSVFzNXAreG9SVlpwNTZiQlNOd1lhQ2UybXR5T0wydUxtZ2F5Nzc1QW9HQkFOSysKTWltQjFTZ1RXL25RMDU4eG95cWFsY0RQSWpxbGtPKzRlNXFaQ0Evclc3SHVMblZMSlZxdGp4TER4bDE4dEZlRworK2ZHYkRLbmMvWkRRNjROL0pxUmxDTmR5UHQ3MnNmbEd4ZHhuWm9UbUUzdE4rU3pLT3NPY2RuU0hib0FZdGJmCjJISE05ak9pYTdmMm15bVlEelNxa3lERTJpUTMwSkJvUndHdDdYRGJBb0dCQUxDeXlLZ1RwcGlnZ2VRQ20yMUsKVTAwNktua2VremUzZVdja29GTFlaY3JHa281Rm4xcEZTclZlWmhRTngyZG44UmZxazRpQytxSjhoMGtNYWkwNwpWQmsrT0xBZWg4K1JpMjNKK3R1TmxGcWpRNDFEQVNmVHZCQTltZ0ZyRWZMc3hwVUZzUW9ML3JzenY2c3Fvc3I5CndjVUo0MGUzNEtUL3FGR1NNMlVNUTZWcEFvR0JBS2dwV28raWFUdWtUd1ZGckVmZ2JPbkhGbTRYR3FJZmtVcW8KTkFGRjBaZ2FYejNZNkR0eUxpbHdTclZYZ1FjQ1JrbDlqYThCdHo2b1BqRW90VzNDL1drOWR5N05YRjNJRStqawpHVDBZelFDd1dCeitpRlkyM0JUTW51Nkg2bTZNZGxJdHBtSVFnZmpyeHZheGtsaWJYSzdTMmJvUk9sd2lLWXZCCm1iOXVVUVIzQW9HQWRUNFRwdWxJWjVSTGxYYWJEc2h6NStBa21SR0gwL2tzNmF2WjdHbGRYL2lMb3R0NUJ2disKN3VsUEVPY2VYZnRuUjFrOWtvVVoyeGJTRVBzTmFqQ3BWaktnYkNPQy9VY2E5MmVhM3B3aFFRTk85RnZoQVhReApwck1yc2RLTEZGN3dwcHViT0FadXhId2NlaDk0YlkzRGJoNGl4eGthbzNQQjJwbU0zdG96dFVRPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=

此时haproxy用户的kubeconfig文件haproxykubeconfig就创建好了,客户端使用该文件就可以通过认证了。

[root@k8sbalancemaster1 ca]# ls
ca.crt  csr.yaml  haproxy.crt  haproxy.csr  haproxy.key  haproxykubeconfig

把kubeconfig文件拷贝到客户端etcd2。

[root@k8sbalancemaster1 ca]# scp haproxykubeconfig 192.168.110.131:~/   

etcd2机器收到kubeconfig文件了。

[root@etcd2 ~]# ll -h haproxykubeconfig
-rw------- 1 root root 5.5K 4月   8 17:49 haproxykubeconfig

查看节点状态,可以看到haproxy用户认证通过了,只是没有权限,我们对用户haproxy进行授权即可访问k8s资源了。

[root@etcd2 ~]# kubectl get node --kubeconfig=haproxykubeconfig
Error from server (Forbidden): nodes is forbidden: User "haproxy" cannot list resource "nodes" in API group "" at the cluster scope

我们对用户haproxy进行授权。

对haproxy用户授予cluster-admin的权限。

[root@k8sbalancemaster1 ca]# kubectl create clusterrolebinding haproxy --clusterrole=cluster-admin --user=haproxy  
clusterrolebinding.rbac.authorization.k8s.io/haproxy created

cluster-admin角色权限很大的,使用时请注意安全。

[root@k8sbalancemaster1 ca]# kubectl get clusterrolebinding | grep haproxy
haproxy                                                ClusterRole/cluster-admin                                                          9s

对用户haproxy进行授权之后,客户端etcd2可以查看k8s集群节点状态了。

[root@etcd2 ~]# kubectl get node --kubeconfig=haproxykubeconfig
NAME                STATUS   ROLES                  AGE     VERSION
k8sbalancemaster1   Ready    control-plane,master   3d13h   v1.23.1
k8sbalancemaster2   Ready    control-plane,master   3d12h   v1.23.1
k8sbalanceworker1   Ready    <none>                 3d13h   v1.23.1

也可以使用环境变量的方式。

[root@etcd2 ~]# export KUBECONFIG=haproxykubeconfig

[root@etcd2 ~]# kubectl get node
NAME                STATUS   ROLES                  AGE     VERSION
k8sbalancemaster1   Ready    control-plane,master   3d13h   v1.23.1
k8sbalancemaster2   Ready    control-plane,master   3d12h   v1.23.1
k8sbalanceworker1   Ready    <none>                 3d13h   v1.23.1

查看命名空间。

[root@etcd2 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   3d13h
kube-node-lease   Active   3d13h
kube-public       Active   3d13h
kube-system       Active   3d13h
master2           Active   53m
masterha          Active   53m
yoyo              Active   47m

十.测试Kubernetes(k8s)集群高可用

haproxykubeconfig文件中,server: https://192.168.110.134:6443表示连接的是haproxy端口,haproxy是我们的负载均衡器,当客户端连接haproxy: https://192.168.110.134:6443的时候,haproxy会把客户端请求转发给后端的两个master节点,当我们其中一个k8s的master节点宕机,也不影响Kubernetes(k8s)集群功能,这就是高可用。

现在把k8sbalancemaster2关机。

[root@k8sbalancemaster2 ~]# init 0

k8sbalancemaster2关机之后,在客户端etcd2查看命名空间。

[root@etcd2 ~]# kubectl get ns
Unable to connect to the server: net/http: TLS handshake timeout

[root@etcd2 ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   3d13h
kube-node-lease   Active   3d13h
kube-public       Active   3d13h
kube-system       Active   3d13h
master2           Active   55m
masterha          Active   56m
yoyo              Active   49m

查看节点状态。

[root@etcd2 ~]# kubectl get node
NAME                STATUS     ROLES                  AGE     VERSION
k8sbalancemaster1   Ready      control-plane,master   3d13h   v1.23.1
k8sbalancemaster2   NotReady   control-plane,master   3d12h   v1.23.1
k8sbalanceworker1   Ready      <none>                 3d13h   v1.23.1

可以发现就算k8sbalancemaster2节点宕机,客户端依旧可以正常访问k8s集群,并且不需要手动切换连接到另外一个正常的k8s master节点。

启动k8sbalancemaster2之后,所有节点都是Ready状态。

[root@etcd2 ~]# kubectl get node
NAME                STATUS   ROLES                  AGE     VERSION
k8sbalancemaster1   Ready    control-plane,master   3d13h   v1.23.1
k8sbalancemaster2   Ready    control-plane,master   3d12h   v1.23.1
k8sbalanceworker1   Ready    <none>                 3d13h   v1.23.1

十一.总结

本章介绍了在 CentOS 7.4 上安装部署 Kubernetes(k8s) 高可用集群的步骤。从安装 Docker 和 Kubernetes 相关工具,部署负载均衡器haproxy,部署etcd集群,初始化主节点,配置网络插件,添加其他主节点和工作节点,部署高可用控制平面,到最后验证集群状态,每个步骤都详细说明了操作方法。

通过搭建高可用的 Kubernetes 集群,可以确保应用程序的稳定性和可靠性。

我们希望本章对你理解如何在 CentOS 7.4 上安装部署 Kubernetes(k8s) 高可用集群有所帮助。如果你有任何问题或需要进一步的指导,请随时向我们提问。

致力于一条龙式的为您解决问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2105833.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sM4040B科学级显微制冷相机特性

sM4040B科学级显微制冷相机特性 sM4040B搭载了 GSENSE4040BSI 3.2 英寸图像传感器&#xff0c;针对传感器固有的热噪声&#xff0c;专门设计了高效制冷模块&#xff0c;使得相机传感器的工作温度比环境温度低达 35-40 度。针对制冷相机常见的低温结雾现象设计了防结雾机制&…

【图灵完备 Turing Complete】游戏经验攻略分享 Part.3 存储器

这一章&#xff0c;前面不难&#xff0c;后面难。 教你别这么连线连出问题。 看结果说话&#xff0c;延迟两个时刻输出。 先不管要求&#xff0c;输出一个稳定的信号&#xff0c;看看之前给了延迟元件正好延迟一刻&#xff0c;然后作为输入和那个稳定的信号做一个逻辑运算改变…

逻辑导论前传

人类的逻辑运算建立在已有的数据库上&#xff0c; 我们无法处理逻辑问题&#xff0c;是因为宇宙的意志不允许我们得出正确答案&#xff0c;每个人都是一个答案&#xff0c;当你认知到了所有人&#xff0c;你也就得到了所有正确答案&#xff0c;这时候宇宙智慧采取正确答案的逻辑…

绿色无广告,纯净体验——2024年优质免费视频剪辑软件

如果你习惯一个视频网站的时候&#xff0c;工作上遇到问题也会第一时间在视频网站上进行搜索解决方案。就比如我同事就很喜欢在短视频网站上搜索Office软件的一些操作步骤。如果你也想分享这类视频&#xff0c;那么我们一起探讨下有哪些适合抖音剪辑的视频剪辑工具。 1.福昕视…

Linux下安装Docker-ce ,配置nginx容器

引言 直接在windows系统中使用nginx服务&#xff0c;面临着如下问题&#xff1a; 1.性能瓶颈 高并发处理能力有限&#xff0c;资源利用率不高。 2.兼容性和稳定性问题 Nginx最初是为Linux等Unix-like系统设计的&#xff0c;虽然在Windows上也有版本&#xff0c;但可能不是…

【Redis】Redis 持久化机制详解:RDB、AOF 和混合持久化的工作原理及优劣分析

目录 持久化RDB触发机制流程说明RDB ⽂件的处理RDB 的优缺点 AOF使⽤ AOF命令写⼊⽂件同步重写机制启动时数据恢复 混合持久化小结 持久化 回顾 MySQL 的事务的特性&#xff1a; 原子性一致性持久性&#xff08;持久化&#xff09;隔离性 持久化&#xff1a;把数据存储在硬盘上…

RabbitMQ 02 操作,配置信息,用户权限

01.介绍启动&#xff0c;关闭 02.环境 2.1 MQ是用Erlang语言写的 2.2 一个RabbitMQ 节点 一个 Erlang节点一个Erlang 程序 &#xff08;RabbitMQ程序&#xff09; 2.3 Erlang节点&#xff1a; 这个是Erlang节点集群状态下&#xff1a; 2.4 启动节点 2.5 查看日志信息 …

leetcode97. 交错字符串,二维动态规划

leetcode97. 交错字符串 给定三个字符串 s1、s2、s3&#xff0c;请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下&#xff0c;其中每个字符串都会被分割成若干 非空 子字符串&#xff1a; s s1 s2 … sn t t1 t2 … tm |n…

Jedis 操作 Redis 数据结构全攻略

Jedis 操作 Redis 数据结构全攻略 一 . 认识 RESP二 . 前置操作2.1 创建项目2.2 关于开放 Redis 端口的问题2.2.1 端口转发?2.2.2 端口配置 2.3 连接到 Redis 服务器 三 . 通用命令3.1 set 和 get3.2 exists 和 del3.3 keys3.4 expire、ttl、type 三 . string 相关命令3.1 mse…

一文说清什么是数据仓库

01 数据仓库的概念 数据仓库的概念可以追溯到20世纪80年代&#xff0c;当时IBM的研究人员开发出了“商业数据仓库”。本质上&#xff0c;数据仓库试图提供一种从操作型系统到决策支持环境的数据流架构模型。 目前对数据仓库&#xff08;Data Warehouse&#xff09;的标准定义&a…

高级组件封装技巧--tree的封装

el-tree是一个经常用到的组件&#xff0c;但是它不支持v-model,使用起来很麻烦&#xff0c;这篇教程封装了el-tree,使得它使用起来很简单&#xff0c;并且支持搜索&#xff0c;支持叶子节点横向排列&#xff0c;这样就算数据多了&#xff0c;也会显的很紧凑,同时它支持提交half…

springboot+mybatis+vue2分页功能开发

前端框架代码 <div class"block"><span class"demonstration">完整功能</span><el-paginationsize-change"handleSizeChange"current-change"handleCurrentChange":current-page"currentPage4":page-s…

MLM:多模态大型语言模型的简介、微调方法、发展历史及其代表性模型、案例应用之详细攻略

MLM&#xff1a;多模态大型语言模型的简介、微调方法、发展历史及其代表性模型、案例应用之详细攻略 目录 相关文章 AI之MLM&#xff1a;《MM-LLMs: Recent Advances in MultiModal Large Language Models多模态大语言模型的最新进展》翻译与解读 MLM之CLIP&#xff1a;CLIP…

Draw.io for Mac/Win:免费且强大的流程图绘制工具

在数字化时代&#xff0c;流程图已成为表达复杂过程和逻辑关系的重要工具。Draw.io&#xff08;现也称为diagrams.net&#xff09;&#xff0c;作为一款免费且功能强大的流程图绘制工具&#xff0c;无论是对于Mac还是Windows用户&#xff0c;都是不可多得的选择。 一、跨平台兼…

计算机毕业设计 半成品配菜平台 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

智能电网中巡检机器人的信息安全技术应用

随着电力行业的数字化和智能化发展&#xff0c;智能巡检机器人作为电力系统自动化运维的重要工具&#xff0c;能够在无人干预的情况下&#xff0c;对电网设备进行实时监测和故障诊断。这种高效、可靠的巡检方式在智能电网建设中发挥了重要作用。然而&#xff0c;随着机器人在电…

yolo 3d车辆目标检测(教程+代码)

关于3D目标检测及其与YOLO3D相关性的概览&#xff1a; 3D目标检测&#xff1a;开启视觉感知的新维度 随着计算机视觉技术的发展&#xff0c;目标检测算法已经成为人工智能领域的重要组成部分。从自动驾驶汽车到无人机导航&#xff0c;再到增强现实&#xff08;AR&#xff09;应…

Java项目:137 springboot基于springboot的智能家居系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本基于Springboot的智能家居系统提供管理员、用户两种角色的服务。 总的功能个人中心、基础数据管理、家具管理、任务管理和用户管理。本系统…

计算机工具软件安装攻略:Visual Studio Code下载、安装和使用

Visual Studio Code下载、安装和使用 1 Visual Studio Code简介 Visual Studio Code通常简称为VS Code&#xff0c;是一款由微软开发的免费、开源的轻量级代码编辑器。它在开发者社区中非常受欢迎&#xff0c;具有强大的功能和扩展性&#xff0c;适用于多种编程语言和开发场景…

git如何设置嵌套仓库(设置子树或子模块),并解决直接将一个仓库拖拽到另一个仓库中导致的问题

git 将一个仓库拷贝到另一个仓库的文件夹下。默认git并不会处理&#xff0c;上传上去之后&#xff0c;只会创建一个文件夹&#xff0c;但是这个文件夹点不开。 在 git add . 的时候&#xff0c;会报出警告&#xff1a; 警告&#xff1a;正在添加嵌入式 git 仓库&#xff1a;cl…