kubeadm1.22搭建高可用 k8s 架构
kubeadm1.22搭建高可用 k8s 架构
一、集群架构
1. k8s集群架构节点角色功能
1.1 节点角色
-
Master Node
-
k8s集群控制节点,接受集群外用户去集群操作请求,并对集群进行调度管理,;
-
Master Node
由API Server
、Scheduler [ˈskɛdʒʊlər]
、Cluster State Store
(ETCD数据库)和Controller Manger Server
所组成;
-
-
Worker Node
- 集群工作节点,运行用户业务应用容器;
Worker Node
包含kubelet
、kube proxy
和Container Runtime
;
1.2 Master节点组件介绍
master节点是集群管理中心,它的组件可以在集群内任意节点运行,
Master组件包括:
kube-scheduler
- 监视新创建没有分配到Node的Pod,为Pod选择一个
Node
- 监视新创建没有分配到Node的Pod,为Pod选择一个
kube-apiserver
- 用于暴露
kubernetes API
,任何的资源请求/调用操作都是通过kube-apiserver
提供的接口进行
- 用于暴露
ETCD
- 是
kubernetes
提供默认的分布式键值存储系统,保存所有集群数据,协助集群正常运转。使用时需要为etcd
数据提供备份计划
- 是
kube-controller-manager
- 运行管理控制器,它们是集群中处理常规任务的后台线程
- 控制器包括:
- 节点(Node)控制器
- 副本(Replication)控制器:负责维护系统中每个副本中的pod
- 端点(Endpoints)控制器:填充Endpoints对象(即连接service&pods)
- Service Account和Token控制器:为新的NameSpaces创建默认帐
户访问API Token
1.3 Node节点组件介绍
node节点用于运行以及维护Pod,提供kubernetes
运行时环境
Node组件包括:
kubelet
- 负责维护容器的生命周期(创建pod,销毁pod),同时也负责
Volume(CVI)
和网络(CNI)
的管理
- 负责维护容器的生命周期(创建pod,销毁pod),同时也负责
kube-proxy
- 负责写入规则至
IPTABLES
、IPVS
实现服务映射访问的 - 通过在主机上维护网络规则并执行连接转发来实现
service(Iptables/Ipvs)
- 随时与
API
通信,把Service
或Pod
改变提交给API
(不存储在Master本地,需要保存至共享存储上),保存至etcd
(可做高可用集群)中,负责service
实现,从内部pod
至service
和从外部node
到service
访问。
- 负责写入规则至
Container Runtime
containerd
CRI-O
Docker
- 负责镜像管理以及Pod和容器的真正运行
单master节点架构图
2. 高可用集群架构
官方提供了2种高可用的部署方式,一种是外部ETCD
的方式,即部署一个单独的ETCD
集群,另一种就是混合部署,ETCD
和apiserver
一起部署。我们采用第二种方式部署,一是部署简单,不需要在单独部署ETCD
,另一个因素就是节约服务器。
- 堆叠ETCD:每个master节点上运行一个
apiserver
和etcd
,etcd
只与本节点apiserver
通信。
- 外部ETCD:
etcd
集群运行在单独的主机上,每个etcd
都与apiserver
节点通信。
-
由外部负载均衡器提供一个vip,流量负载到keepalived master节点上。
-
当
keepalived
节点出现故障,vip
自动漂到其他可用节点。 -
haproxy
负责将流量负载到apiserver
节点。 -
三个
apiserver
会同时工作。注意k8s
中controller-manager
和scheduler
只会有一个工作,其余处于backup
状态。apiserver
主要是读写数据库,数据一致性的问题由数据库保证,此外apiserver
是k8s
中最繁忙的组件,多个同时工作也有利于减轻压力。而controller-manager
和scheduler
主要处理执行逻辑,多个大脑同时运作可能会引发混乱
二、准备方案
方案一:
HAProxy + Keepalived
这种组合既可以作为操作系统上的服务运行,也可以作为控制平面主机上的静态吊舱运行。对于这两种情况,服务配置是相同的。
- 使用
Kubeadm + HAProxy + Keepalived
部署高可用Kubernetes
集群,安装在主机上keepalive
的作用是虚拟IP
,让多个master
节点公用一个虚拟IP
,当主节点挂掉之后,虚拟IP
通过选举飘逸到剩下二个节点其中一个HAproxy
的作用在于实现apiserve
的负载均衡 权重配置,也可以用nginx
Kubeadm
的init
操作就会init
这个VIP
节点,当IP
节点可以多用时,自然实现了高可用
HAProxy
和Keepalived
也可以以静态Pod的形式运行服务
方案二:
- 使用
kube-vip
- 与传统的
keepalived
和haproxy
方法相比,kube-vip
在一个服务中实现了虚拟IP
和负载平衡的管理 kube-vip
将作为控制平面节点上的静态 pod 运行。
- 与传统的
三、主机准备环境
3.0 主机规划
准备六台机器以及一个vip
注意:master节点最少三台,因为我用2台master测试了负载高可用不可用。看了好多教程都用的2台master,他们只管搭建,不管测试。由于我刚开始用的是2台master,两台node,后面测试发现有问题,所以把其中一台node节点重新输出为master(条件允许的话也可以加mater主机)。在此申明以下,如果哪个小可爱想参考这篇部署高可用k8s的话,提前做好主机规划。我也是新手,大家一起学习~~
k8s-master1 192.168.19.152 kube-apiserver kube-controller-manager kube-scheduler etcd
k8s-master2 192.168.19.153 kube-apiserver kube-controller-manager kube-scheduler etcd
k8s-node01 192.168.19.151 kubelet kube-proxy docker etcd
k8s-node02 192.168.19.154 kubelet kube-proxy docker etcd
LB(Master) 192.168.19.155 haproxy/Nginx L4 VIP:192.168.19.155
角色 | ip | |
---|---|---|
k8s-master1 | 192.168.19.152 | |
k8s-master2 | 192.168.19.153 | |
k8s-worker1 | 192.168.19.151 | |
k8s-worker2 | 192.168.19.154 | |
k8s-vip | 192.168.19.155 | |
nfs、harbor | 192.168.19.153 |
3.1 准备基础rpm包配置PS1
# sudo yum -y install wget bash-completion git net-tools ntpdate vim epel-release
# vim /etc/bashrc
PS1="<\[\e[35m\]\u\[\e[m\]\[\e[31m\]@\[\e[m\]\[\e[32m\]\h\[\e[m\]\[\e[33m\] \W\[\e[m\]>\[\e[36m\]\\$\[\e[m\] "
# exec bash
3.2 配置ip地址
# cat /etc/sysconfig/network-scripts/ifcfg-eth0
TYPE="Ethernet"
BOOTPROTO="static"
NAME="eth0"
DEVICE="eth0"
ONBOOT="yes"
IPADDR="192.168.19.x"
PREFIX="24" 或 NETMASK=255.255.255.0
GATEWAY="192.168.19.2"
DNS1="119.29.29.29"
# systemctl restart network
3.3 所有节点主机名及绑定
<root@localhost ~># hostnamectl set-hostname k8s-master1
<root@localhost ~># hostnamectl set-hostname k8s-master2
<root@localhost ~># hostnamectl set-hostname k8s-worker1
<root@localhost ~># hostnamectl set-hostname k8s-worker2
<root@localhost ~># exec bash
<root@localhost ~># hostname
<root@k8s-xxx ~># cat /etc/hosts
192.168.19.152 k8s-master1
192.168.19.153 k8s-master2
192.168.19.151 k8s-worker1
192.168.19.154 k8s-worker2
<root@xxx ~># ping -c2 XXX
3.4 所有节点关闭selinux和firewalld
<root@k8s-xxx ~># systemctl stop firewalld
<root@k8s-xxx ~># systemctl disable firewalld
或
<root@k8s-xxx ~># systemctl disable firewalld --now && systemctl status firewalld
<root@k8s-xxx ~># iptables -nL 确保群为accept
<root@k8s-xxx ~># getenforce
<root@k8s-xxx ~># setenforce 0
<root@k8s-xxx ~># sed -ri 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
3.5 时间同步
<root@k8s-xxx ~># ntpdate ntp.aliyun.com
<root@k8s-xxx ~># ntpdatecn.ntp.org.cn
<root@k8s-xxx ~># crontab -e
<root@k8s-xxx ~># crontab -l
0 */2 * * * ntpdate ntp.aliyun.com
<root@k8s-xxx ~># tail -f /var/log/cron
<root@k8s-xxx ~># date
<root@k8s-xxx ~># hwclock -r 硬件时间
<root@k8s-xxx ~># hwclock --systohc (== hwclock -w 系统时间写入硬件时间)
3.6 升级内核版本
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
#查看最新版内核:
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
#安装最新版:
yum --enablerepo=elrepo-kernel install kernel-ml kernel-ml-devel –y
#查看当前可用内核版本:
awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg
#选择最新内核版本,0代表查看当前可用内核版本列表的左侧索引号
grub2-set-default 0
#生成grub文件
grub2-mkconfig -o /boot/grub2/grub.cfg
#重启linux
reboot
uname -r
删除非当前正在使用的内核
yum remove $(rpm -qa | grep kernel | grep -v $(uname -r))
3.7 所有节点关闭swap
<root@k8s-xxx ~># swapoff -a && sed -ri 's/.*swap.*/#&/' /etc/fstab
<root@k8s-xxx ~># swapoff -a && sed -i '/swap/ s/^\(.*\)$/#\1/g' /etc/fstab
3.8 验证mac地址uuid唯一性
<root@k8s-xxx ~># ip link
<root@k8s-xxx ~># cat /sys/class/net/ens33/address #mac地址
<root@k8s-xxx ~># cat /sys/class/dmi/id/product_uuid #uuid
3.9 添加网桥过滤
确保 br_netfilter
模块被加载。这一操作可以通过运行 lsmod | grep br_netfilter
来完成。若要显式加载该模块,可执行 sudo modprobe br_netfilter
。
为了让你的 Linux 节点上的 iptables
能够正确地查看桥接流量,你需要确保在你的 sysctl
配置中将 net.bridge.bridge-nf-call-iptables
设置为 1。例如:
<root@k8s-xxx ~># modprobe br_netfilter
永久
<root@k8s-xxx ~># cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
查看是否加载
<root@k8s-xxx ~># lsmod | grep br_netfilter
过滤桥接的IPv4/IPv6数据包,传递到iptables的链
<root@k8s-xxx ~># cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
从所有系统目录中读取值
<root@k8s-xxx ~># sysctl --system
加载网桥过滤配置文件
<root@k8s-xxx ~># sysctl -p /etc/sysctl.d/k8s.conf
3.10 停止邮件服务
<root@k8s-xxx ~># systemctl stop postfix && systemctl disable postfix
或
<root@k8s-xxx ~># systemctl disable postfix --now
3.11 考虑是否关闭NUMA
cp /etc/default/grub{,.bak}
vim /etc/default/grub
# 在 GRUB_CMDLINE_LINUX 一行添加 `numa=off` 参数,如下所示:
diff /etc/default/grub.bak /etc/default/grub
< GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rhgb quiet"
---
> GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rhgb quiet numa=off"
cp /boot/grub2/grub.cfg{,.bak}
grub2-mkconfig -o /boot/grub2/grub.cfg
3.12 kube-proxy
开启ipvs
的前置条件
IPVS:https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md
确保 IPVS
需要内核模块(注意: 对于 Linux 内核4.19及以后版本,使用 nf _ conntrack
而不是 nf _ conntrack _ ipv4
)
由于ipvs
已经加入到了内核的主干,所以为kube-proxy
开启ipvs
的前提需要加载以下的内核模块
当 kube-proxy
以 IPVS
代理模式启动时,它将验证 IPVS
内核模块是否可用。 如果未检测到 IPVS
内核模块,则 kube-proxy
将退回到以 iptables
代理模式运行。
安装ipset及ipvsadm
<root@k8s-xxx ~># rpm -qa ipvsadm
<root@k8s-xxx ~># yum -y install ipset ipvsadm
在所有节点执行如下脚本
添加需要加载的模块
#linux 4.18及以下内核版本使用:modprobe -- nf_conntrack_ipv4,
#linux 4.18以上使用 modprobe -- nf_conntrack
<root@k8s-xxx ~># cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
# modprobe -- nf_conntrack_ipv4
modprobe -- nf_ conntrack
EOF
授权、运行、检查是否加载
<root@k8s-xxx ~># chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4
modprobe: FATAL: Module nf_conntrack_ipv4 not found.
检查是否加载
<root@k8s-xxx ~># lsmod | grep -e ip_s -e f_conntrack_ipv4
或
<root@k8s-xxx ~># cut -f1 -d " " /proc/modules | grep -e ip_vs -e nf_conntrack_ipv4
3.12 安装容器运行时Docker
# yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
# yum install -y yum-utils
# yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# yum -y install docker-ce docker-ce-cli containerd.io
# docker version
例如: 3:20.10.6-3.el7 docker-ce-20.10.6
docker 版本排序
# yum list docker-ce --showduplicates | sort -r
# yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io -y
# yum install docker-ce-20.10.6 docker-ce-cli-c-20.10.6 containerd.io
3.13 使用 systemd
来管理容器的 cgroup
Cgroup
全称Control Group(控制组),是Linux系统内核提供的一个特性(Linux 2.6.24内核开始将Cgroup
加入)。
主要用于限制和隔离一组进程对系统资源的使用。可控制的资源主要包括CPU、内存、block I/O、网络带宽等等。
Systemd
也是对于Cgroup
接口的一个封装。systemd
以PID1
的形式在系统启动的时候运行,并提供了一套系统管理守护程序、库和实用程序,用来控制、管理Linux计算机操作系统资源。通过systemd-cgls
命令我们可以看到systemd
工作的进程PID
是1
。
更改设置,令容器运行时和 kubelet
使用 systemd
作为 cgroup
驱动,以此使系统更为稳定。 对于 Docker, 设置 native.cgroupdriver=systemd
选项。
mkdir /etc/docker
sudo mkdir /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl status docker
需要确保容器运行时和 kubelet 所使用的是相同的 cgroup 驱动,否则 kubelet 进程会失败。
3.14 修改docker-ce服务配置文件
配置加速器(可选)
配置镜像加速器
针对Docker客户端版本大于 1.10.0 的用户
您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://s2xmxgje.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
修改其目的是为了后续使用/etc/docker/daemon.json来进行更多配置。
修改内容如下
<root@k8s-xxx ~># cat /usr/lib/systemd/system/docker.service
[Unit]
...
[Service]
...
ExecStart=/usr/bin/dockerd #如果原文件此行后面
有-H选项,请删除-H(含)后面所有内容
...
[Install]
...
注意:有些版本不需要修改,请注意观察
<root@k8s-xxx ~># systemctl daemon-reload
systemctl restart docker
四、所有master节点部署keepalived
1. 了解keepalived工作原理
Keepalived
软件起初是专为LVS
负载均衡软件设计的,用来管理并监控LVS
集群系统中各个服务节点的状态,后来又加入了可以实现高可用的VRRP
功能。因此,Keepalived
除了能够管理LVS
软件外,还可以作为其他服务(例如:Nginx、Haproxy、MySQL等)的高可用解决方案软件
Keepalived
软件主要是通过VRRP协议
实现高可用功能的。通过主机之间的优先等级以及心跳检测来及时切换准备主机的工作状态,以提高集群的高可用性。VRRP
保证当主机的下一条路由器出现故障时,由另一台路由器来代替出现故障的路由器进行工作,从而保持网络通信的连续性和可靠性
虚拟 IP
的所有主机都需要在同一个 IP
子网中。且没被占用
keepalived
是以VRRP
(虚拟路由冗余协议)协议为基础, 包括一个master
和多个backup
。 master
劫持vip
对外提供服务。master
发送组播,backup
节点收不到vrrp
包时认为master
宕机,此时选出剩余优先级最高的节点作为新的master, 劫持vip
。
2. 安装配置keepalived
<root@k8s-master1 ~># yum -y install keepalived
<root@k8s-master2 ~># yum -y install keepalived
<root@k8s-master1 ~># rpm -qa keepalived
keepalived-1.3.5-19.el7.x86_64
<root@k8s-master1 ~># rpm -ql keepalived
文件或者目录 | 作用 |
---|---|
/etc/keepalived/keepalived.conf | 生效的配置文件 |
/etc/init.d/keepalived | 服务器管理脚本 |
/var/log/messages | 日志信息 |
/usr/lib/systemd/system/keepalived.service | 服务文件 |
/usr/sbin/keepalived | 二进制程序 |
Keepalived
配置由两个文件组成:服务配置文件和一个健康检查脚本,该脚本将定期调用,以验证持有虚拟 IP 的节点是否仍在运行。
cd /etc/keepalived
cp -a keepalived.conf{,.bak}
vim keepalived.conf
global_defs {
router_id LVS_DEVEL # 路由器标识,一般不用改,也可以写成每个主机自己的主机名
}
# 定期执行的脚本,它的退出码将被所有的VRRP instance记录,它以非0的权重监视
vrrp_script check_apiserver {
script "/etc/keepalived/check_apiserver.sh"
interval 3
weight -2
fall 10
rise 2
}
# 定义实例
vrrp_instance VI_1 {
# 指定keepalived节点的初始状态,可选值为MASTER|BACKUP
state ${STATE}
# RRP实例绑定的网卡接口,用户发送VRRP包
interface ${INTERFACE}
# 虚拟路由的ID,同一集群要一致,同一子网中的所有集群中应该是唯一的
# VRRP组名,两个节点的设置必须一样,以指明各个节点属于同一VRRP组
virtual_router_id ${ROUTER_ID}
# 定义优先级(1-254之间),按优先级来决定主备角色,优先级越大越优先
priority ${PRIORITY}
# 设置不抢占模式(默认是抢占模式)
nopreempt
# 主备通讯时间间隔,组播信息发送间隔,两个节点设置必须一样
advert_int 1
# 配置认证信息,两个节点必须一致
authentication {
# 认证方式
auth_type PASS
# 同一集群中的keepalived配置里的此处必须一致
auth_pass ${AUTH_PASS}
}
virtual_ipaddress {
# 配置要集群协商的VIP地址(可以是ip或172.16.3.200/24)
${APISERVER_VIP}
}
# track_script用于追踪脚本
track_script {
check_apiserver
}
}
上面的 keepalived
配置使用了一个健康检查脚本/etc/keepalived/check _ apiserver
。 负责确保保存虚拟IP
的节点上的 API
服务器是可用的。这个脚本可以是这样的:
#!/bin/sh
errorExit() {
echo "*** $*" 1>&2
exit 1
}
curl --silent --max-time 2 --insecure https://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://localhost:${APISERVER_DEST_PORT}/"
if ip addr | grep -q ${APISERVER_VIP}; then
curl --silent --max-time 2 --insecure https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/"
fi
-
${ APISERVER _ vip }
是在保存的集群主机之间协商的虚拟 IP 地址。 -
用于
Kubernetes
与API 服务器
对话的端口。
1、k8s-master1 配置
<root@k8s-master1 keepalived># cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
state MASTER # 主
interface ens33
virtual_router_id 51
priority 100 # 优先级
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.19.155 # vip
}
}
2、k8s-master2配置
<root@k8s-master2 keepalived># cat keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
state BACKUP # 备
interface ens33
virtual_router_id 51
priority 90 # 优先级比主低
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.19.155 # vip
}
}
3. 分别按照顺序启动主服务器和备服务器的keepalived
# systemctl start keepalived.service && systemctl enable keepalived.service
# systemctl enable keepalived.service --now
# systemctl status keepalived.service
# systemctl reload keepalived.service 修改了配置文件,重载配置
<root@k8s-master1 haproxy># ps aux |grep keepalived
root 54499 0.0 0.0 123020 2040 ? Ss 15:26 0:00 /usr/sbin/keepalived -D
root 54500 0.0 0.2 123020 5568 ? S 15:26 0:00 /usr/sbin/keepalived -D
root 54501 0.0 0.1 123020 3600 ? S 15:26 0:00 /usr/sbin/keepalived -D
3. 测试:k8s-master1挂了
Api-server
:现在没发测试等,安装好k8s再测试
# 停止服务或关闭网络
<root@k8s-master1 keepalived># systemctl stop keepalived.service
4. 几个注意
①脑裂:
通过抓包工具观察
# yum -y install tcpdump
# tcpdump -h
-n 不显示主机名称,以IP显示
-i 网卡接口
-w <数据包文件> 把数据包数据写入指定的文件。
-vv 更详细显示指令执行过程
# tcpdump vrrp -i ens33 -n
可以看到k8s-master1
和k8s-master2
同时向组播地址发生VRRP
包
由于防火墙开启导致的脑裂,防火墙没有允许vrrp
的组播
解决办法1:单播的方式
keepalived
在组播模式下所有的信息都会向224.0.0.18
的组播地址发送,产生众多的无用信息,并且会产生干扰和冲突,所以需要将其组播的模式改为单拨。这是一种安全的方法,避免局域网内有大量的keepalived
造成虚拟路由id
的冲突。
单播模式需要关闭vrrp_strict
,严格遵守vrrp
协议这个选项
单播需要在VIP实例配置段加入单播的源地址和目标地址
单播示例配置:注意此语法在keepalived1.2.11
版本以上支持
unicast_src_ip 192.168.1.21 ##(本地IP地址)
unicast_peer {
192.168.1.22 ##(对端IP地址)
}
# master1 配置
<root@k8s-master1 keepalived># cat keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
#vrrp_strict #如果有这个选项把它删除或注释
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.19.152 # 本地IP
unicast_peer {
192.168.19.153 # 对端IP
}
virtual_ipaddress {
192.168.19.155
}
}
# master2 配置
<root@k8s-master2 keepalived># cat keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
#vrrp_strict #如果有这个选项把它删除或注释
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.19.153 # 本地IP
unicast_peer {
192.168.19.152 # 对端IP
}
virtual_ipaddress {
192.168.19.155
}
}
单播,可以发现点对点
如果出现下面错误就是没#vrrp_strict
导致的
解决办法2:防火墙配置允许vrrp
的组播(或直接停止防火墙)
-
1、
keepalived
默认需要使用D类组播地址224.0.0.18
进行心跳通信 -
2、
keepalived
使用vrp
协议进行通信(协议号码为112)
# firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
# firewall-cmd --reload
②抢占模式和非抢占模式:
当master
发生异常,且后期恢复master
正常后,存在抢占
或非抢占
两种情况。
简单点说抢占模式就是,当master
宕机后,backup
接管服务。后续当master
恢复后,vip
再漂移到master
上,master
重新接管服务,多了一次多余的vip
切换
总结:抢占模式即MASTER从故障中恢复后,会将VIP从BACKUP节点中抢占过来。非抢占模式即MASTER恢复后不抢占BACKUP升级为MASTER后的VIP
设置非抢占模式
-
nopreempt
在主备服务器的配置文件,
vrrp_instance
段中 -
设置
state
工作模式都为为BACKUP
两个keepalived
节点都启动后,默认都是BACKUP
状态,双方在发送组播信息后,会根据优先级来选举一个MASTER
出来。由于两者都配置了nopreempt
,所以MASTER
从故障中恢复后,不会抢占vip
。这样会避免VIP
切换可能造成的服务延迟。
# k8s-master1 配置
<root@k8s-master1 keepalived># cat keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 100
advert_int 1
nopreempt # 非抢占模式
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.19.152
unicast_peer {
192.168.19.153
}
virtual_ipaddress {
192.168.19.155
}
}
# k8s-master2 配置
<root@k8s-master2 keepalived># cat keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
#vrrp_strict
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
nopreempt # 非抢占模式
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.19.153
unicast_peer {
192.168.19.152
}
virtual_ipaddress {
192.168.19.155
}
}
notify的用法:
notify_master
:当当前节点成为master时,通知脚本执行任务(一般用于启动某服务或发送邮件等,比如nginx,haproxy
等)
notify_backup
:当当前节点成为backup时,通知脚本执行任务(一一般用于启动某服务或发送邮件等,比如nginx,haproxy
等)
notify_fault
:当当前节点出现故障,执行的任务;
五、所有master节点部署haproxy
1. 安装haproxy
负载均衡方式将根据IP范围和端口转发用户通信量,流量将被转发到处理所有请求的后端所在的在端口上
<root@k8s-master1 keepalived># yum install haproxy -y
<root@k8s-master2 keepalived># yum install haproxy -y
<root@k8s-master1 haproxy># rpm -qa haproxy
haproxy-1.5.18-9.el7_9.1.x86_64
<root@k8s-master1 keepalived># rpm -qc haproxy
/etc/haproxy/haproxy.cfg
/etc/logrotate.d/haproxy
/etc/sysconfig/haproxy
<root@k8s-master1 haproxy># cp -a haproxy.cfg{,.bak}
2. 配置haproxy
修改haproxy
的配置文件,因为我们的haproxy
安装在2个master节点上面,haproxy
实现api-server
的负载均衡,所有不能用api-server
的端口,我们设置端口信息为16443,默认是api-server
是6443
# /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
# #全局配置文件
global
# #日志配置,所有的日志都记录本地,通过local2输出
log /dev/log local0
log /dev/log local1 notice
daemon
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
# 默认使用协议,可以为{http|tcp|health} http:是七层协议 tcp:是四层 health:只返回OK
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 1
timeout http-request 10s
timeout queue 20s
timeout connect 5s
timeout client 20s
timeout server 20s
timeout http-keep-alive 10s # #默认持久连接超时时间
timeout check 10s # #默认检查时间间隔
#---------------------------------------------------------------------
# apiserver frontend which proxys to the control plane nodes
#---------------------------------------------------------------------
# 前端服务器
# 代理到控制节点的apiserver前端
frontend apiserver
# ${APISERVER_DEST_PORT} 用于 Kubernetes 与 API 服务器对话的端口。
bind *:${APISERVER_DEST_PORT}
mode tcp
option tcplog
default_backend apiserver
#---------------------------------------------------------------------
# round robin balancing for apiserver
#---------------------------------------------------------------------
# 后端服务器
backend apiserver
option httpchk GET /healthz
http-check expect status 200
mode tcp
option ssl-hello-chk
balance roundrobin
# ${ apiserver_src _ port }是 API 服务器实例使用的端口
# ${ HOST1 _ id }是第一个负载平衡的 API 服务器主机的符号名称
# ${ HOST1 _ address }第一个负载平衡的 API 服务器主机的可解析地址(DNS 名称、 IP 地址)
# check 启动对后端server的健康状态检测
server ${HOST1_ID} ${HOST1_ADDRESS}:${APISERVER_SRC_PORT} check
# [...]
master1
和mast2
配置一样
<root@k8s-master1 haproxy># rsync -av ./haproxy.cfg root@k8s-master2:/etc/haproxy/
<root@k8s-master1 haproxy># cat haproxy.cfg
# /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
log /dev/log local0
log /dev/log local1 notice
daemon
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 1
timeout http-request 10s
timeout queue 20s
timeout connect 5s
timeout client 20s
timeout server 20s
timeout http-keep-alive 10s
timeout check 10s
#---------------------------------------------------------------------
# apiserver frontend which proxys to the control plane nodes
#---------------------------------------------------------------------
frontend apiserver
bind *:16443
mode tcp
option tcplog
default_backend apiserver
#---------------------------------------------------------------------
# round robin balancing for apiserver
#---------------------------------------------------------------------
backend apiserver
option httpchk GET /healthz
http-check expect status 200
mode tcp
option ssl-hello-chk
balance roundrobin
server k8s-master1 192.168.19.152:6443 check
server k8s-master2 192.168.19.153:6443 check
3. 启动并查看
# systemctl enable haproxy --now
<root@k8s-master1 haproxy># netstat -naltp|grep haproxy
tcp 0 0 0.0.0.0:16443 0.0.0.0:* LISTEN 68836/haproxy
<root@k8s-master1 haproxy># ps aux|grep haproxy
root 68834 0.0 0.1 44752 3112 ? Ss 16:37 0:00 /usr/sbin/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid
root 68835 0.0 0.1 46064 5308 ? S 16:37 0:00 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds
root 68836 0.0 0.0 46064 988 ? Ss 16:37 0:00 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds
六、安装kubeadm
所有节点安装kubelet
,kubeadm
,kubectl
,并 enable kubelet
服务(注意:不要start启动)
你需要在每台机器上安装以下的软件包:
kubeadm
:用来初始化集群的指令。kubelet
:在集群中的每个节点上用来启动 Pod 和容器等。kubectl
:用来与集群通信的命令行工具。
kubelet
,kubeadm
,kubectl
要版本一致
1. 安装最新版k8s
- 谷歌源(不推荐,慢)
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
# 将 SELinux 设置为 permissive 模式(相当于将其禁用)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable kubelet
# 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=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
# yum list | grep kubeadm
输入 y
# yum install -y --nogpgcheck kubelet kubeadm kubectl --disableexcludes=kubernetes
# rpm -qa kubeadm
kubeadm-1.22.4-0.x86_64
# rpm -qa kubelet
kubelet-1.22.4-0.x86_64
# rpm -qa kubectl
kubectl-1.22.4-0.x86_64
# systemctl enable kubelet && systemctl start kubelet
或
# systemctl enable kubelet
ps: 由于官网未开放同步方式, 可能会有索引gpg
检查失败的情况, 这时请用 yum install -y --nogpgcheck kubelet kubeadm kubectl
安装
新建 /etc/yum.repos.d/kubernetes.repo
,内容为:
[kubernetes]
name=kubernetes
baseurl=https://mirrors.tuna.tsinghua.edu.cn/kubernetes/yum/repos/kubernetes-el7-$basearch
enabled=1
# yum list | grep kubeadm
--disableexcludes=kubernetes #禁掉除了这个之外的别的仓库
# yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
# 安装指定版本的k8s
# yum install -y kubelet-<version> kubectl-<version> kubeadm-<version>
# yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
# systemctl enable --now kubelet
kubectl查看k8s版本信息
# kubectl version 查看安装的版本 # kubectl get nodes
-------------------------------------------------------------
name=Description#一个描述,随意。
baseurl=#设置资源库的地址,可以写阿里云也可以是自己的yum
ftp://
http://
file:///
enabled={1|0}#enabled=1开启本地更新模式
gpgcheck={1|0}# gpgcheck=1表示检查;可以不检查gpgcheck=0
gpgkey=#检查的key;如果上面不检查这一行可以不写。
2. 安装指定版本k8s
安装指定版本的kubeadm kubelet kubectl
# yum list | grep kubeadm
# 安装指定版本的k8s
# yum install -y kubelet-<version> kubectl-<version> kubeadm-<version> --disableexcludes=kubernetes
# yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
# systemctl enable kubelet
比如:
[root@XXX ~]# yum list kubeadm.x86_64 --showduplicates | sort -r
[root@XXX ~]# yum -y install --setopt=obsoletes=0 kubeadm-1.17.2-0 kubelet-1.17.2-0 kubectl-1.17.2-0
3. kubelet配置使用systemd驱动
警告:你需要确保容器运行时和kubelet
所使用的是相同的 cgroup
驱动,否则 kubelet
进程会失败。
kubeadm
支持在执行 kubeadm init
时,传递一个 KubeletConfiguration
结构体。 KubeletConfiguration
包含 cgroupDriver
字段,可用于控制 kubelet 的 cgroup 驱动。
说明: 在版本 1.22 中,如果用户没有在 KubeletConfiguration
中设置 cgroupDriver
字段, kubeadm init
会将它设置为默认值 systemd
。
<root@k8s-master ~># systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: activating (auto-restart) (Result: exit-code) since Wed 2021-11-10 12:33:39 CST; 1s ago
Docs: https://kubernetes.io/docs/
Process: 85021 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS (code=exited, status=1/FAILURE) #启动配置参数
Main PID: 85021 (code=exited, status=1/FAILURE)
主要配置kubelet,如果不配置可能会导致k8s集群无法启动。
为了实现docker使用的cgroupdriver与kubelet使用的cgroup的一致性,建议修改如下文件内容。
查看kubelet的cgroup驱动
[root@XXX ~]# DOCKER_CGROUP=$(docker info | grep Cgroup | awk '{print $3}')
[root@XXX ~]# echo $DOCKER_CGROUP
systemd
如果不是和docker使用的cgroupdriver 一致则通过下述方法修改
[root@XXX ~]# cat /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS=
[root@XXX ~]# vim /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"
[root@XXX ~]# systemctl daemon-reload
设置为开机自启动即可,千万不要start 开启,由于没有生成配置文件,集群初始化后自动启动
[root@XXX ~]# systemctl enable kubelet
五、使用 kubeadm 创建集群
使用 kubeadm 创建集群:https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
利用 kubeadm
创建高可用集群:https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/high-availability/
1. 准备所需的容器镜像
方法一:编写脚本,提前拉取需要的镜像
# 在master1和master2 下载镜像
<root@k8s-master1 ~># kubeadm config images list |tee image.list 写入文件并输出到屏幕
# 查看已列出镜像文件列表
<root@k8s-master1 ~># cat image.list
# 编写镜像下载脚本(通过阿里云下载相关镜像)
<root@k8s-master1 ~># cat image.pull
#!/bin/bash
images=(
kube-apiserver:v1.22.3
kube-proxy:v1.22.3
kube-controller-manager:v1.22.3
kube-scheduler:v1.22.3
etcd:3.5.0-0
pause:3.5
)
for imageName in ${images[@]} ; do
docker pull registry.aliyuncs.com/google_containers/$imageName
docker tag registry.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
docker rmi registry.aliyuncs.com/google_containers/$imageName
done
docker pull coredns/coredns:1.8.4
docker tag coredns/coredns:1.8.4 k8s.gcr.io/coredns/coredns:v1.8.4
docker rmi coredns/coredns:1.8.4
# 下载镜像
<root@k8s-master1 ~># sh image.pull
<root@k8s-master1 ~># docker images
工作节点导入:kube-proxy 和 pause 镜像
保存镜像为tar
<root@k8s-master1 ~># docker save -o kube-proxy.tar k8s.gcr.io/kube-proxy:v1.21.0
<root@k8s-master1 ~># docker save -o pause.tark8s.gcr.io/pause:3.4.1
<root@k8s-master1 ~># ls
kube-proxy.tar pause.tar
复制tar到worker节点
<root@k8s-master1 ~># scp kube-proxy.tar pause.tar worker1:/root
<root@k8s-master1 ~># scp kube-proxy.tar pause.tar worker2:/root
# 在worker1和worker2节点导入镜像
<root@k8s-masterx ~># ls
kube-proxy.tar pause.tar
<root@k8s-masterx ~># docker load -i kube-proxy.tar
<root@k8s-masterx ~># docker load -i pause.tar
<root@k8s-masterx ~># ls
kube-proxy.tar pause.tar
<root@k8s-masterx ~># docker load -i kube-proxy.tar
<root@k8s-masterx ~># docker load -i pause.tar
方法二:直接拉取初始化所需要的镜像(推荐)
不希望 kubeadm init
和 kubeadm join
下载存放在 k8s.gcr.io
上的默认的容器镜像
1.1 查看所需镜像
# 查看最新版本所需镜像
<root@k8s-xxx ~># kubeadm config images list | tee k8s-image.list
k8s.gcr.io/kube-apiserver:v1.22.4
k8s.gcr.io/kube-controller-manager:v1.22.4
k8s.gcr.io/kube-scheduler:v1.22.4
k8s.gcr.io/kube-proxy:v1.22.4
k8s.gcr.io/pause:3.5
k8s.gcr.io/etcd:3.5.0-0
k8s.gcr.io/coredns/coredns:v1.8.4
# 查看k8s指定版本对应的镜像版本
<root@k8s-xxx ~># kubeadm config images list --kubernetes-version=v1.21.0
1.2 安装阿里云镜像
使用阿里云镜像地址
- [地址1]
registry.aliyuncs.com/google_containers
- [地址2]
registry.cn-hangzhou.aliyuncs.com/google_containers
要等一会儿可以去抽支烟
<root@k8s-xxx ~># kubeadm config images pull \
--image-repository=registry.aliyuncs.com/google_containers
<root@k8s-xxx ~># docker images
方法三:命令初始化指定仓库地址
命令初始化的时候指定要拉取镜像的地址:--image-repository registry.aliyuncs.com/google_containe
2. 使用 kubeadm 配置集群中的每个 kubelet
kubelet:负责维护容器的生命周期(创建pod,销毁pod),同时也负责Volume(CVI)
和网络(CNI)
的管理
kubelet 是一个守护程序,在 Kubernetes 集群中的每个节点上运行。 当 Kubernetes 初始化或升级时,kubeadm CLI 工具由用户执行,而 kubelet 始终在后台运行。
由于kubelet是守护程序,因此需要通过某种初始化系统或服务管理器进行维护。
集群中涉及的所有 kubelet 的一些配置细节都必须相同, 而其他配置方面则需要基于每个 kubelet 进行设置,以适应给定机器的不同特性(例如操作系统、存储和网络)。 你可以手动地管理 kubelet 的配置,但是 kubeadm 现在提供一种 KubeletConfiguration
API 类型 用于集中管理 kubelet 的配置。
通过使用 kubeadm init
和 kubeadm join
命令为 kubelet 提供默认值。
查看kubelet
默认值
# kubeadm config print init-defaults --component-configs KubeletConfiguration
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: 1.2.3.4
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
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: 1.22.0
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
scheduler: {}
---
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging: {}
memorySwap: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
当调用 kubeadm init
时,kubelet 配置被编组到磁盘上的 /var/lib/kubelet/config.yaml
中, 并且上传到集群中的 ConfigMap。 ConfigMap 名为 kubelet-config-1.X
,其中 X
是你正在初始化的 kubernetes 版本的次版本。 在集群中所有 kubelet 的基准集群范围内配置,将 kubelet 配置文件写入 /etc/kubernetes/kubelet.conf
中。 此配置文件指向允许 kubelet 与 API 服务器通信的客户端证书。
3. kubelet 的 systemd 文件
kubeadm
中附带了有关系统如何运行 kubelet 的 systemd 配置文件
安装的配置文件被写入 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
并由系统使用
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
--kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# 这是 "kubeadm init" 和 "kubeadm join" 运行时生成的文件,动态地填充 KUBELET_KUBEADM_ARGS 变量
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# 这是一个文件,用户在不得已下可以将其用作替代 kubelet args。
# 用户最好使用 .NodeRegistration.KubeletExtraArgs 对象在配置文件中替代。
# KUBELET_EXTRA_ARGS 应该从此文件中获取。
EnvironmentFile=-/etc/default/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
该文件为 kubelet 指定由 kubeadm 管理的所有文件的默认位置。
- 用于 TLS 引导程序的 KubeConfig 文件为
/etc/kubernetes/bootstrap-kubelet.conf
, 但仅当/etc/kubernetes/kubelet.conf
不存在时才能使用。 - 具有唯一 kubelet 标识的 KubeConfig 文件为
/etc/kubernetes/kubelet.conf
。 - 包含 kubelet 的组件配置的文件为
/var/lib/kubelet/config.yaml
。 - 包含的动态环境的文件
KUBELET_KUBEADM_ARGS
是来源于/var/lib/kubelet/kubeadm-flags.env
。 - 包含用户指定标志替代的文件
KUBELET_EXTRA_ARGS
是来源于/etc/default/kubelet
(对于 DEB),或者/etc/sysconfig/kubelet
(对于 RPM)。KUBELET_EXTRA_ARGS
在标志链中排在最后,并且在设置冲突时具有最高优先级
Package name | Description |
---|---|
kubeadm |
给 kubelet 安装 /usr/bin/kubeadm CLI 工具和 kubelet 的 systemd 文件。 |
kubelet |
安装 kubelet 可执行文件到 /usr/bin 路径,安装 CNI 可执行文件到 /opt/cni/bin 路径。 |
kubectl |
安装 /usr/bin/kubectl 可执行文件。 |
cri-tools |
从 cri-tools git 仓库中安装 /usr/bin/crictl 可执行文件。 |
4. 集群初始化
1. k8s-Master1节点初始化
方法一:通过配置文件
生成默认初始化配置
<root@k8s-master1 ~># kubeadm config print init-defaults |tee kubeadm-init-config.yaml
#kubeadm config print init-defaults
#kubeadm config print join-defaults
修改默认初始化配置
https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta3/
修改之后的配置文件如下,注意以下几点advertiseAddress,name,imageRepository,kubernetesVersion,podSubnet,controlPlaneEndpoint,cgroupDriver
kubeadm 不支持将没有 --control-plane-endpoint
参数的单个控制平面集群转换为高可用性集群。
<root@k8s-master1 ~># vim kubeadm-init-config.yaml
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.19.152 # apiserver 所在主机IP即master地址
bindPort: 6443 # api server 端口
nodeRegistration:
criSocket: /var/run/dockershim.sock
imagePullPolicy: IfNotPresent
name: k8s-master1 # 改为master 节点的主机名(未设置默认为节点的主机名)
taints: null
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
#controlPlaneEndpoint: "master.k8s.io:16443" # 绑定的是VIP
# 192.168.19.155是VIP,16443是在haproxy 中配置端口
# 集群内就是通过前端 192.168.19.155:16443 来与后端负载 api-server ip:6443 通信的
controlPlaneEndpoint: "192.168.19.155:16443"
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
# 拉取镜像的地址 默认是k8s.gcr.io
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: 1.22.0 # k8s 的版本 会影响到下载镜像的版本(镜像可以提前下载)
networking:
dnsDomain: cluster.local
# pod网络(flanne插件,默认是100.244.0.0/16 calico 默认: 192.168.0.0/16)
# 如果不想使用默认的,等配置网络插件的时候再去修改
podSubnet: "172.16.0.0/16" # 添加pod 网络
serviceSubnet: 10.96.0.0/12 # service 网络
scheduler: {}
---
# # 配置 kubelet 的 cgroup 驱动
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
cgroupDriver: systemd
---
# 开启ipvs 模式(Kubernetes 1.14 版本开始默认使用 ipvs 代理)可不加
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
说明:1.11版本之后同时支持
iptables
与ipvs
,默认使用ipvs
,如果ipvs
模块没有加载时,会自动降级至iptables
- 在
Kubernetes 1.14
版本开始默认使用ipvs
代理- https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md
把下面这段加入kubeadm-config.yaml文件最后 --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 #注意版本 kind: KubeProxyConfiguration mode: ipvs
说明: 在版本 1.22 中,如果用户没有在
KubeletConfiguration
中设置cgroupDriver
字段,kubeadm init
会将它设置为默认值systemd
。kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 cgroupDriver: systemd
通过将参数 --upload-certs
添加到 kubeadm init
,主控制节点的证书 被加密并上传到 kubeadm-certs Secret
中。 请注意,此 Secret 将在 2 小时后自动过期。
# 试运行看有无错误
<root@k8s-master1 ~># kubeadm init --config kubeadm-init-config.yaml --dry-run
# --upload-certs 标志用来将在所有控制节点实例之间的共享证书上传到集群。
# 如果希望手动地通过控制平面节点或者使用自动化 工具复制证书则不加--upload-certs
# 当 --upload-certs 与 kubeadm init 一起使用时,主控制节点的证书 被加密并上传到 kubeadm-certs Secret 中。
<root@k8s-master1 ~># kubeadm init \
--config kubeadm-init-config.yaml \
--upload-certs | tee k8s-admin-init.log
# 如果初始化遇到问题,尝试使用下面的命令清理,再重新初始化
<root@k8s-master1 ~># kubeadm reset
<root@k8s-master1 ~># rm -rf $HOME/.kube/config
<root@k8s-master1 ~># rm -rf /etc/cni/net.d
<root@k8s-master1 ~># ipvsadm --clear
<root@k8s-master1 ~># ipvsadm -ln
重置过程不会清除CNI配置。为此,必须删除/etc/cni/net.d
重置过程不会重置或清理iptables规则或IPVS表。
如果要重置iptables,必须使用“iptables”命令手动重置。
如果您的群集设置为使用IPVS,则运行ipvsadm --clear 重置系统的IPVS表。
初始化成功后
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join 192.168.19.155:16443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:8ccf4d292eab06399b61d572c27f06879c9a8dfae9a2487d7b7562b5225cada4 \
--control-plane --certificate-key 140170149e5095b7eb96454e82153b7f2c966274965e646a330297d0c731264c
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.19.155:16443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:8ccf4d292eab06399b61d572c27f06879c9a8dfae9a2487d7b7562b5225cada4
警告:
kubeadm join
中token
有效期是24小时,保存证书的Secret 有效期2小时
kubeadm
对admin.conf
中的证书进行签名时,将其配置为Subject: O = system:masters, CN = kubernetes-admin
。system:masters
是一个例外的、超级用户组,可以绕过鉴权层(例如RBAC
)。 不要将admin.conf
文件与任何人共享,应该使用kubeadm kubeconfig user
命令为其他用户生成kubeconfig
文件,完成对他们的定制授权。
方式二:通过命令行
<root@k8s-master1 ~># kubeadm version
kubeadm init --help
--apiserver-advertise-address apiserver所公布的其正在监听的IP地址。apiserver 所在主机IP即master地址
-pod-network-cidr pod网络(flanne插件,默认是100.244.0.0/16 calico 默认: 192.168.0.0/16
)
--image-repository registry.aliyuncs.com/google_container(看情况:如要已经下载好了镜像可以不加)
<root@k8s-master1 ~># kubeadm init \
--control-plane-endpoint "192.168.19.155:16443" \
--image-repository registry.aliyuncs.com/google_containers \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=172.16.0.0/16 \
--upload-certs | tee kubeadm-init.log
# --upload-certs 标志用来将在所有控制节点实例之间的共享证书上传到集群。
# 如果希望手动地通过控制平面节点或者使用自动化 工具复制证书则不加--upload-certs
# --control-plane-endpoint 设置成负载均衡器的地址或 DNS 和端口
# --kubernetes-version 设置要使用的 Kubernetes 版本。 建议将 kubeadm、kebelet、kubectl 和 Kubernetes 的版本匹配。
kubeadm init \
--control-plane-endpoint "192.168.19.155:16443" \
--image-repository registry.aliyuncs.com/google_containers \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=172.16.0.0/16 \
--upload-certs | tee kubeadm-init.log
kubeadm init \
--control-plane-endpoint=192.168.100.16:8443 \ #记得对应修改你的虚拟IP和端口port
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.22.4 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=172.16.0.0/16 \
--upload-certs
#定义--pod-network-cidr和--service-cidr时候规划网段要记得和宿主机中已有的网段不能冲突
kubeadm init --apiserver-advertise-address=10.0.0.10 --control-plane-endpoint=10.0.0.100 --apiserver-bind-port=6443 --kubernetes-version=v1.20.5 --pod-network-cidr=10.100.0.0/16 --service-cidr=10.200.0.0/16 --service-dns-domain=zilong.local --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers --ignore-preflight-errors=swap
再次运行
kubeadm init
,你必须首先卸载集群。
令牌用于控制平面节点和加入节点之间的相互身份验证。 这里包含的令牌是密钥。确保它的安全, 因为拥有此令牌的任何人都可以将经过身份验证的节点添加到你的集群中。 可以使用 kubeadm token
命令列出,创建和删除这些令牌
<root@k8s-master1 ~># kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
abcdef.0123456789abcdef 23h 2021-12-01T11:03:41Z authentication,signing <none> system:bootstrappers:kubeadm:default-node-token
syon5h.cjn0ybfbojaoq79u 1h 2021-11-30T13:03:40Z <none> Proxy for managing TTL for the kubeadm-certs secret <none>
<root@k8s-master1 ~># kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Unhealthy Get "http://127.0.0.1:10251/healthz": dial tcp 127.0.0.1:10251: connect: connection refused
controller-manager Healthy ok
etcd-0 Healthy {"health":"true","reason":""}
# k8s-master1 状态是NotReady 是以为还没配置网络
<root@k8s-master1 ~># kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION
k8s-master1 NotReady control-plane,master 23m v1.22.4
2. 安装 Pod 网络附加组件
每个集群只能安装一个 Pod 网络。
安装 Pod 网络后,您可以通过在 kubectl get pods --all-namespaces
输出中检查 CoreDNS Pod 是否 Running
来确认其是否正常运行。 一旦 CoreDNS Pod
启用并运行,你就可以继续加入节点。
2.1 calico
参考官网:https://docs.projectcalico.org/getting-started/kubernetes/quickstart
1.安装Tigera Calico运算符和自定义资源定义。
<root@k8s-master1 ~># wget https://docs.projectcalico.org/manifests/tigera-operator.yaml --no-check-certificate
<root@k8s-master1 ~># kubectl create -f tigera-operator.yaml
2.通过创建必要的自定义资源来安装Calico。有关此清单中可用配置选项的详细信息,请参阅安装参考.
<root@k8s-master1 ~># wget https://docs.projectcalico.org/manifests/custom-resources.yaml --no-check-certificate
<root@k8s-master1 ~># kubectl create -f custom-resources.yaml
如果配置错可以删除再来
<root@k8s-master1 ~># kubectl delete -f https://docs.projectcalico.org/manifests/custom-resources.yaml
## 注意,如果你init配置的是 --pod-network-cidr=192.168.0.0/16,那就不用改,直接运行即可,否则你需要把文件先下来,改成你配置的,再创建
3.使用以下命令确认所有pod都在运行
<root@k8s-master1 ~># watch kubectl get pods -n calico-system
CoreDNS Pod 是否 Running
<root@k8s-master1 ~># kubectl get pods --all-namespaces -o wide
要确认所有的pod为running状态
<root@k8s-master1 ~># kubectl get pods -n kube-system
<root@k8s-master1 ~># kubectl get nodes -o wide
<root@k8s-master1 ~># kubectl describe nodes
每个集群只能安装一个 Pod 网络。
安装 Pod 网络后,您可以通过在
kubectl get pods --all-namespaces
输出中检查CoreDNS Pod
是否Running
来确认其是否正常运行。 一旦CoreDNS Pod
启用并运行,你就可以继续加入节点。
2.2 flannel
官网:https://github.com/flannel-io/flannel#flannel
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
3. 控制节点隔离
默认情况下,出于安全原因,你的集群不会在控制平面节点上调度 Pod。 如果你希望能够在控制平面节点上调度 Pod
<root@k8s-master1 ~># kubectl taint nodes --all node-role.kubernetes.io/master-
这将从任何拥有 node-role.kubernetes.io/master
taint 标记的节点中移除该标记, 包括控制平面节点,这意味着调度程序将能够在任何地方调度 Pods。
4. 加入节点
节点是你的工作负载(容器和 Pod 等)运行的地方。要将新节点添加到集群,请对每台计算机执行以下操作:
- SSH 到机器
- 成为 root (例如
sudo su -
) - 运行
kubeadm init
输出的命令。例如:
kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>
集群注册token的有效时间为24小时,如果集群创建完成后没有及时添加工作节点,那么我们需要重新生成token。kubeadm token list
可以查看令牌token 的过期时间
令牌用于控制平面节点和加入节点之间的相互身份验证
列出所有的引导令牌。
<root@k8s-master1 ~># kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
abcdef.0123 23h 2021-12-01T11:03:41Z authentication,signing <none> system:bootstrappers:kubeadm:default-node-token
syon5h.cjn0 1h 2021-11-30T13:03:40Z <none> Proxy for managing TTL for the kubeadm-certs secret <none>
# 删除令牌
kubeadm token delete
# 生成令牌
kubeadm token generate
5. 令牌token 过期解决办法
生成一个令牌token --token
# kubeadm token generate
生成一个密钥 Secret --certificate-key
# kubeadm certs certificate-key
默认情况下,令牌会在24小时后过期。如果要在当前令牌过期后将节点加入集群, 则可以通过在控制平面节点上运行以下命令来创建新令牌:
方法一
生成token
<root@k8s-master1 ~># kubeadm token generate
zw44us.65tarz882f7yw27p
根据生成的token,输出添加命令
# kubeadm token create <token> --print-join-command --ttl=0
<root@k8s-master1 ~># kubeadm token create zw44us.65tarz882f7yw27p --print-join-command --ttl=0
kubeadm join 192.168.0.105:6443 --token zw44us.65tarz882f7yw27p --discovery-token-ca-cert-hash sha256:b90746b53da98accc1245eafc4369036739e4f2451b213166805772252235439
查看生成的令牌
<root@k8s-master1 ~># kubeadm token list
方法二
kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>
# 生成token
--token
<root@k8s-master1 ~># kubeadm token list
<root@k8s-master1 ~># kubeadm token create
kiblue.uc8sixluj7xdw8du
# 生成token-ca-cert-hash
--discovery-token-ca-cert-hash
<root@k8s-master1 ~># openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'
b90746b53da98accc1245eafc4369036739e4f2451b213166805772252235439
# 把生成的token和 hash 替换
<root@k8s-master1 ~># kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>
<root@k8s-master1 ~># kubeadm join 192.168.0.105:6443 --token kiblue.uc8sixluj7xdw8du \
> --discovery-token-ca-cert-hash b90746b53da98accc1245eafc4369036739e4f2451b213166805772252235439
<root@k8s-master1 ~># kubeadm token list
6. 加入k8s-master2节点到集群
通过将参数 --upload-certs
添加到 kubeadm init
,你可以将控制平面证书临时上传到集群中的 Secret。 请注意,此 Secret 将在 2 小时后自动过期。
①证书没过期(2小时内)
--control-plane 通知 kubeadm join 创建一个新的控制平面。
--certificate-key ... 从集群中的 kubeadm-certs Secret 下载 控制平面证书并使用给定的密钥进行解密
<root@k8s-master2 ~># kubeadm join 192.168.19.155:16443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:8ccf4d292eab06399b61d572c27f06879c9a8dfae9a2487d7b7562b5225cada4 \
--control-plane
--certificate-key 140170149e5095b7eb96454e82153b7f2c966274965e646a330297d0c731264c
②如果证书过期(2小时之后)重新将控制平面证书上传到集群
通过将参数 --upload-certs
添加到 kubeadm init
,你可以将控制平面证书临时上传到集群中的 Secret。 请注意,此 Secret 将在 2 小时后自动过期。证书使用 32 字节密钥加密,可以使用 --certificate-key
指定。 通过将 --control-plane
和 --certificate-key
传递给 kubeadm join
, 可以在添加其他控制平面节点时使用相同的密钥下载证书。
以下阶段命令可用于证书到期后重新上传证书:
<root@k8s-master2 ~># kubeadm init phase upload-certs --upload-certs --certificate-key=SOME_VALUE --config=SOME_YAML_FILE
如果未将参数 --certificate-key
传递给 kubeadm init
和 kubeadm init phase upload-certs
, 则会自动生成一个新密钥。
以下命令可用于按需生成新密钥:
<root@k8s-master2 ~># kubeadm certs certificate-key
示例:
要重新上传证书并生成新的解密密钥,请在已加入集群节点的控制平面上使用以下命令:
# 重新上传证书并生成新的解密密钥
<root@k8s-master2 ~># sudo kubeadm init phase upload-certs --upload-certs
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
1973a75317d750e6fdbf3c4610feb76583533e5e0137bdfb5488e1bfcc4a4a3a
# 用上面生成的解密密钥certificate key 替换下面的--certificate-key
<root@k8s-master2 ~># kubeadm join 192.168.19.155:16443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:8ccf4d292eab06399b61d572c27f06879c9a8dfae9a2487d7b7562b5225cada4 \
--control-plane
--certificate-key 1973a75317d750e6fdbf3c4610feb76583533e5e0137bdfb5488e1bfcc4a4a3a
③手动分发证书到k8s-master2 适用于初始化的时候没加 --upload-certs
如果你选择不将 kubeadm init
与 --upload-certs
命令一起使用, 则意味着你将必须手动将证书从主控制平面节点复制到 将要加入的控制平面节点上。
使用 ssh
和 scp
:
第一步:应该在运行过 kubeadm init
命令的第一个 控制平面节点上运行以下脚本。 该脚本会将证书从第一个控制平面节点复制到另一个控制平面节点:
在以下示例中,用其他控制平面节点的 IP 地址替换 CONTROL_PLANE_IPS
。
USER=ubuntu # 可定制
CONTROL_PLANE_IPS="10.0.0.7 10.0.0.8"
for host in ${CONTROL_PLANE_IPS}; do
scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:
scp /etc/kubernetes/pki/ca.key "${USER}"@$host:
scp /etc/kubernetes/pki/sa.key "${USER}"@$host:
scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:
scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:
scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:
scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt
scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key
done
注意:
只需要复制上面列表中的证书。
kubeadm
将负责生成其余证书以及加入控制平面实例所需的 SAN。 如果你错误地复制了所有证书,由于缺少所需的 SAN,创建其他节点可能会失败。
第二步:在每个即将加入集群的控制平面节点上,你必须先运行以下脚本,然后 再运行 kubeadm join
。 该脚本会将先前复制的证书从主目录移动到 /etc/kubernetes/pki
:
USER=ubuntu # 可定制
mkdir -p /etc/kubernetes/pki/etcd
mv /home/${USER}/ca.crt /etc/kubernetes/pki/
mv /home/${USER}/ca.key /etc/kubernetes/pki/
mv /home/${USER}/sa.pub /etc/kubernetes/pki/
mv /home/${USER}/sa.key /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/
mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt
mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
7. 添加工作节点到集群
<root@k8s-worker1 ~># kubeadm join 192.168.19.155:16443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:8ccf4d292eab06399b61d572c27f06879c9a8dfae9a2487d7b7562b5225cada4 | tee k8s-worker1-init.log
<root@k8s-worker1 ~># kubeadm join 192.168.19.155:16443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:8ccf4d292eab06399b61d572c27f06879c9a8dfae9a2487d7b7562b5225cada4 | tee k8s-worker2-init.log
8. 验证集群
在控制节点上面验证:
# 查看节点状态
<root@k8s-master1 ~># kubectl describe node k8s-worker1
<root@k8s-master1 ~># kubectl get nodes -o wide
<root@k8s-master1 ~># kubectl get pods --all-namespaces -o wide
# 组件状态
<root@k8s-master1 ~># kubectl get cs
<root@k8s-master1 ~># kubectl get componentstatuses
# 查看集群健康状态
# 如果命令 kubectl cluster-info 返回了 url,但你还不能访问集群,那可以用以下命令来检查配置是否妥当
<root@k8s-master1 ~># kubectl cluster-info
<root@k8s-master1 ~># kubectl get serviceaccount
给节点打角色标签
<root@k8s-master1 ~># kubectl get nodes -o wide
# 增加节点标签 = 代表增加标签
<root@k8s-master1 ~># kubectl label nodes k8s-worker2 node-role.kubernetes.io/worker2=
<root@k8s-master1 ~># kubectl label nodes k8s-worker1 node-role.kubernetes.io/worker1=
<root@k8s-master1 ~># kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready control-plane,master 3h50m v1.22.4
k8s-master2 Ready control-plane,master 127m v1.22.4
k8s-worker1 Ready worker1 134m v1.22.4
k8s-worker2 Ready worker2 133m v1.22.4
# 删除节点标签
<root@k8s-master1 ~># kubectl label nodes k8s-worker2 node-role.kubernetes.io/worker2-
<root@k8s-master1 ~># kubectl label nodes k8s-worker1 node-role.kubernetes.io/worker1-
可能出现的问题
报错:Unhealthy
<root@k8s-master1 ~># kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Unhealthy Get "http://127.0.0.1:10251/healthz": dial tcp 127.0.0.1:10251: connect: connection refused
controller-manager Healthy ok
etcd-0 Healthy {"health":"true","reason":""}
解决办法:两个控制节点都要做
<root@k8s-master1 ~># kubectl version
<root@k8s-master1 ~># vim /etc/kubernetes/manifests/kube-controller-manager.yaml
<root@k8s-master1 ~># vim /etc/kubernetes/manifests/kube-scheduler.yaml
# 注释掉port=0这一行
所有节点重启kubelet
<root@k8s-master1 ~># systemctl restart kubelet.service
主节点再次执行kubectl get cs
<root@k8s-master1 ~># kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {"health":"true"}
9. 各个组件端口
![](https://gitee.com/wuheeee/images/raw/master/images/image-20211129223608735.png)
5. kubectl 命令补全
https://www.cnblogs.com/xlizi/p/13452518.html
kubelet
:在集群中的每个节点上用来启动 Pod 和容器等。kubectl
:用来与集群通信的命令行工具。
kubectl 的可选配置
启用 shell 自动补全功能
补全脚本依赖于工具 [bash-completion](
①安装 bash-completion
检查是否安装 bash-completion
# yum install bash-completion
##上述命令将创建文件 /usr/share/bash-completion/bash_completion,它是 bash-completion 的主脚本
# source /usr/share/bash-completion/bash_completion 或 exec bash
②启动 kubectl 自动补全功能
需要确保一点:kubectl 补全脚本已经导入(sourced)到 shell 会话中。 这里有两种验证方法:
- 在文件
~/.bashrc
中导入(source)补全脚本:
kubectl completion -h
echo 'source <(kubectl completion bash)' >> ~/.bashrc
source $HOME/.bash_profile 或 exec bash
- 将补全脚本添加到目录
/etc/bash_completion.d
中:
[root@XXX ~]# kubectl completion bash > /etc/bash_completion.d/kubectl
若要将kubectl自动补全添加到当前shell
# exec bash
[root@XXX ~]# source <(kubectl completion bash)
查看kubectl completion
[root@XXX ~]# kubectl completion -h
六、高可用集群的验证
由于本人开始选择的是两个master节点,不管怎么验证,想了所有出现的可能都失败。看官网猜测可能是mater节点太少。
1. 官网基础设施要求
对于这两种方法,你都需要以下基础设施:
- 配置满足
kubeadm
的最低要求 的三台机器作为控制面节点 - 配置满足
kubeadm
的最低要求的三台机器作为工作节点 - 在集群中,确保所有计算机之间存在全网络连接(公网或私网)
- 在所有机器上具有 sudo 权限
- 从某台设备通过 SSH 访问系统中所有节点的能力
- 所有机器上已经安装
kubeadm
和kubelet
,kubectl
是可选的。
仅对于外部 etcd 集群来说,你还需要:
- 给 etcd 成员使用的另外三台机器
2. 解决办法
新增一台master
节点,或把一个node
节点改为master
节点,由于新增master节点还有要资源,而且需要重新配置环境和镜像准备,关键是没难度。所有这儿我选择node
变master
,恢复快照不可能滴!
模拟:
在硬件升级、硬件维护的情况下,我们需要将某些Node进行隔离,脱离k8s
的调度范围。k8s
提供了一套机制,既可以将Node纳入调度范围,也可以将Node脱离调度范围。
第一步:拷贝admin.conf
为了使 kubectl
在其他计算机,将管理员 kubeconfig
文件从控制平面节点复制到工作
#方法一:
<root@k8s-worker2 ~># scp root@192.168.19.153:/etc/kubernetes/admin.conf .
<root@k8s-worker2 ~># ls
admin.conf anaconda-ks.cfg k8s-image.list kubeadm-config.yaml
<root@k8s-worker2 ~># kubectl --kubeconfig ./admin.conf get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready control-plane,master 19h v1.22.4
k8s-master2 Ready control-plane,master 17h v1.22.4
k8s-worker1 Ready worker1 17h v1.22.4
k8s-worker2 Ready worker2 17h v1.22.4
#方法二:
准备集群管理配置文件
<root@k8s-worker2 ~># mkdir .kube
<root@k8s-worker2 ~># scp master1:/root/.kube/config .kube/
使用命令验证
<root@k8s-worker2 ~># kubectl get nodes
<root@k8s-worker2 ~># kubectl cluster-info
说明:
上面的示例假定为 root 用户启用了SSH访问。如果不是这种情况, 你可以使用
scp
将 admin.conf 文件复制给其他允许访问的用户。
admin.conf
文件为用户提供了对集群的超级用户特权。 该文件应谨慎使用。对于普通用户,建议生成一个你为其授予特权的唯一证书。
第二步:清理node 节点
`让k8s-worker2 不可调度
<root@k8s-worker2 ~># kubectl --kubeconfig ./admin.conf cordon k8s-worker2
<root@k8s-worker2 ~># kubectl --kubeconfig ./admin.conf describe node k8s-worker2
<root@k8s-worker2 ~># kubectl --kubeconfig ./admin.conf get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready control-plane,master 19h v1.22.4
k8s-master2 Ready control-plane,master 17h v1.22.4
k8s-worker1 Ready worker1 17h v1.22.4
k8s-worker2 Ready,SchedulingDisabled worker2 17h v1.22.4
<root@k8s-worker2 ~># kubectl --kubeconfig ./admin.conf get pods -A
`把运行在worker2上面的负载pod 驱逐
<root@k8s-worker2 ~># kubectl taint nodes node1 key1=value1:NoExecute
<root@k8s-worker2 ~># kubectl drain <node name> --delete-emptydir-data --force --ignore-daemonsets
# 在删除节点之前,请重置 kubeadm 安装的状态:
<root@k8s-worker2 ~># kubeadm reset
<root@k8s-worker2 ~># rm -rf $HOME/.kube/config
<root@k8s-worker2 ~># rm -rf /etc/cni/net.d
# 重置过程不会重置或清除 iptables 规则或 IPVS 表
<root@k8s-worker2 ~># ipvsadm -ln
<root@k8s-worker2 ~># ipvsadm --clear
<root@k8s-worker2 ~># ipvsadm -C
<root@k8s-worker2 ~># iptables -nL
<root@k8s-worker2 ~># iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
# 删除节点
<root@k8s-worker2 ~># kubectl --kubeconfig ./admin.conf delete node k8s-worker2
<root@k8s-master1 ~># kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready control-plane,master 20h v1.22.4
k8s-master2 Ready control-plane,master 18h v1.22.4
k8s-worker1 Ready worker1 18h v1.22.4
# 重新开始,只需运行 kubeadm init 或 kubeadm join 并加上适当的参数
第三步:把worker2
变为master3
并加入集群
重新开始,只需运行 kubeadm init
或 kubeadm join
并加上适当的参数
# 修改主机名k8s-worker2变为k8s-master3
<root@k8s-worker2 ~># hostnamectl set-hostname k8s-master3
生成token
<root@k8s-master1 ~># kubeadm token generate
zw44us.65tarz882f7yw27p
根据生成的token,输出添加命令
# kubeadm token create <token> --print-join-command --ttl=0
<root@k8s-master1 ~># kubeadm token create zw44us.65tarz882f7yw27p --print-join-command --ttl=0
kubeadm join 192.168.0.105:6443 --token zw44us.65tarz882f7yw27p --discovery-token-ca-cert-hash sha256:b90746b53da98accc1245eafc4369036739e4f2451b213166805772252235439
查看生成的令牌
<root@k8s-master1 ~># kubeadm token list
-----------------------------------
`第一步:根据生成的token,输出添加命令
<root@k8s-master1 ~># kubeadm token create $(kubeadm token generate) --print-join-command --ttl=0
kubeadm join 192.168.19.155:16443 --token ban71s.8p09rc2l9yqe92y4 --discovery-token-ca-cert-hash sha256:8ccf4d292eab06399b61d572c27f06879c9a8dfae9a2487d7b7562b5225cada4
`第二步:要重新上传证书并生成新的解密密钥,请在已加入集群节点的控制平面上使用以下命令:
由于是添加master节点还需要生成master节点所需证书,通过Secret(也可以手动分发证书到k8s-master3)
如果是添加node节点上面第一步的命令就可以了
# 重新上传证书Secret
kubeadm init phase upload-certs --upload-certs --certificate-key=SOME_VALUE --config=SOME_YAML_FILE
# 生成:--certificate-key (--certificate-key=SOME_VALUE 可以省略)
<root@k8s-master1 ~># kubeadm certs certificate-key
a222218f73363bac3801ee7699ddf3e4f36b7e4c12a8696d0e377486a838fd26
<root@k8s-master1 ~># kubeadm init phase upload-certs \
--upload-certs \
--certificate-key=a222218f73363bac3801ee7699ddf3e4f36b7e4c12a8696d0e377486a838fd26
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
a222218f73363bac3801ee7699ddf3e4f36b7e4c12a8696d0e377486a838fd26
# 用上面生成的解密密钥certificate key 替换下面的--certificate-key
<root@k8s-worker2 ~># kubeadm join 192.168.19.155:16443 \
--token ban71s.8p09rc2l9yqe92y4 \
--discovery-token-ca-cert-hash sha256:8ccf4d292eab06399b61d572c27f06879c9a8dfae9a2487d7b7562b5225cada4 \
--control-plane \
--certificate-key a222218f73363bac3801ee7699ddf3e4f36b7e4c12a8696d0e377486a838fd26
To start administering your cluster from this node, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Run 'kubectl get nodes' to see this node join the cluster.
`第三步:任何master节点都可以验证
<root@k8s-master3 ~># kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready control-plane,master 20h v1.22.4
k8s-master2 Ready control-plane,master 18h v1.22.4
k8s-worker1 Ready worker1 18h v1.22.4
k8s-worker2 Ready control-plane,master 69s v1.22.4
`第四不:让这个节点恢复调度(因为重新加入的没必要做)
<root@k8s-master1 ~># kubectl cordon k8s-worker2
<root@k8s-worker2 ~># kubectl describe nodes k8s-worker2
`第四步:由于只有一个worker节点,设置允许让master3 上可以运行工作负载pod
<root@k8s-worker2 ~># kubectl taint nodes k8s-worker2 node-role.kubernetes.io/master-
node/k8s-worker2 untainted
<root@k8s-worker2 ~># kubectl describe nodes k8s-worker2
修改主机名k8s-worker2变为k8s-master3,日志这步在加入之前就应该做的
3. 验证集群的高可用
修改keepalived配置文件
三个主节点所需的脚本,有两个脚本用哪个都可以
# 检测haproxy 是否正常运行
<root@k8s-x ~># cat /etc/keepalived/check_haproxy.sh
#!/bin/bash
haproxy_status=`ps -C haproxy --no-header |wc -l`
if [ $haproxy_status -eq 0 ];then
systemctl start haproxy
sleep 3;
if [ `ps -C haproxy --no-header |wc -l` -eq 0 ];then
systemctl stop keepalived
fi
fi
# 检测apiserver 是否正常运行(其实也就是检测haproxy是否正常运行,因为它在访问16643端口,16443端口也就是haproxy的前端端口)
<root@k8s-x ~># cat /etc/keepalived/check_apiserver.sh
#!/bin/sh
errorExit() {
echo "*** $*" 1>&2
exit 1
}
curl --silent --max-time 2 --insecure https://localhost:16443/ -o /dev/null || errorExit "Error GET https://localhost:16443/"
if ip addr | grep -q 192.168.19.155; then
curl --silent --max-time 2 --insecure https://192.168.19.155:16443/ -o /dev/null || errorExit "Error GET https://192.168.19.155:16443/"
fi
<root@k8s-master1 ~># cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_script check_apiserver {
script "/etc/keepalived/check_apiserver.sh"
#script "/etc/keepalived/aa.sh"
interval 3 # #每个多长时间检测一次
# 当/etc/keepalived/check_apiserver.sh 执行脚本的执行结果为非0,并且weight为负数则优先级会减少
# 比如 有默认设置的100 减少为70,这时候master2权重90 和 master3权重80 都比这个高,所有master1上的VIP
# 会漂移到master2上,一定要把weight 根据实际设置合适的大小。
# 还有就是注意不抢占模式nopreempt 的使用
# 非抢占模式即MASTER恢复后不抢占BACKUP升级为MASTER后的VIP
weight -30
fall 2 # 执行失败多少次才认为失败(非0 状态)
rise 2 # 执行成功多少次才认为是成功
}
#vrrp_script check_haproxy {
# script "/etc/keepalived/aa.sh"
# interval 10
# weight -5
# fall 2
# rise 2
#}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.19.152
unicast_peer {
192.168.19.153
192.168.19.154
}
virtual_ipaddress {
192.168.19.155
}
track_script {
check_apiserver
#check_haproxy
}
notify_master "systemctl start haproxy" # 当成为master时就启动haproxy服务
# 当成为backup时就关闭haproxy服务,
notify_backup "systemctl stop haproxy" # 当成为backup时就关闭haproxy服务
}
<root@k8s-master2 ~># cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
#vrrp_strict
}
vrrp_script check_apiserver {
script "/etc/keepalived/check_apiserver.sh"
interval 3
weight -30
fall 10
rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.19.153
unicast_peer {
192.168.19.152
192.168.19.154
}
virtual_ipaddress {
192.168.19.155
}
track_script {
check_apiserver
}
}
<root@k8s-worker2 ~># cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_script check_apiserver {
script "/etc/keepalived/check_apiserver.sh"
interval 3
weight -30
fall 10
rise 2
}
vrrp_instance VI_1 {
state BACKUP #
interface ens33
virtual_router_id 51
priority 80 #
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.19.154
unicast_peer {
192.168.19.152
192.168.19.153
}
virtual_ipaddress {
192.168.19.155
}
track_script {
check_apiserver
}
}
修改haproxy配置文件
master节点配置都一样
# cat /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Example configuration for a possible web application. See the
# full configuration options online.
#
# http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
# to have these messages end up in /var/log/haproxy.log you will
# need to:
#
# 1) configure syslog to accept network log events. This is done
# by adding the '-r' option to the SYSLOGD_OPTIONS in
# /etc/sysconfig/syslog
#
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# /etc/sysconfig/syslog
#
# local2.* /var/log/haproxy.log
#
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
#frontend main *:88
frontend apiserver
stats uri /haproxy
bind *:16443
mode tcp
default_backend app
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend app
balance roundrobin
mode tcp
server k8s-master1 192.168.19.152:6443 check
server k8s-master2 192.168.19.153:6443 check
server k8s-worker2 192.168.19.154:6443 check
systemctl restart keepalived.service haproxy.service
systemctl enable keepalived.service haproxy.service
测试:
<root@k8s-worker2 ~># ip a s ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:83:33:9c brd ff:ff:ff:ff:ff:ff
inet 192.168.19.154/24 brd 192.168.19.255 scope global noprefixroute dynamic ens33
valid_lft 956sec preferred_lft 956sec
inet 192.168.19.155/32 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::6fd2:6c8a:c762:231c/64 scope link tentative noprefixroute dadfailed
valid_lft forever preferred_lft forever
inet6 fe80::3692:bf77:677c:fc68/64 scope link noprefixroute
valid_lft forever preferred_lft forever
<root@k8s-worker2 ~># tcpdump vrrp -i ens33 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
16:25:06.356636 IP 192.168.19.154 > 192.168.19.152: VRRPv2, Advertisement, vrid 51, prio 80, authtype simple, intvl 1s, length 20
16:25:06.356895 IP 192.168.19.154 > 192.168.19.153: VRRPv2, Advertisement, vrid 51, prio 80, authtype simple, intvl 1s, length 20
16:25:07.358654 IP 192.168.19.154 > 192.168.19.152: VRRPv2, Advertisement, vrid 51, prio 80, authtype simple, intvl 1s, length 20
16:25:07.358750 IP 192.168.19.154 > 192.168.19.153: VRRPv2, Advertisement, vrid 51, prio 80, authtype simple, intvl 1s, length 20
16:25:08.359413 IP 192.168.19.154 > 192.168.19.152: VRRPv2, Advertisement, vrid 51, prio 80, authtype simple, intvl 1s, length 20
16:25:08.359497 IP 192.168.19.154 > 192.168.19.153: VRRPv2, Advertisement, vrid 51, prio 80, authtype simple, intvl 1s, length 20
<root@k8s-worker2 manifests># kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7f6cbbb7b8-mrbpd 1/1 Running 1 (15h ago) 22h
coredns-7f6cbbb7b8-sc9mg 1/1 Running 1 (15h ago) 22h
etcd-k8s-master1 1/1 Running 29 (83m ago) 22h
etcd-k8s-master2 1/1 Running 21 (79m ago) 20h
etcd-k8s-worker2 1/1 Running 1 (83m ago) 115m
kube-apiserver-k8s-master1 1/1 Running 25 (82m ago) 22h
kube-apiserver-k8s-master2 1/1 Running 28 (77m ago) 20h
kube-apiserver-k8s-worker2 1/1 Running 0 20s
kube-controller-manager-k8s-master1 1/1 Running 25 (155m ago) 22h
kube-controller-manager-k8s-master2 1/1 Running 11 (84m ago) 20h
kube-controller-manager-k8s-worker2 1/1 Running 1 (2m14s ago) 115m
kube-proxy-4wslp 1/1 Running 1 (15h ago) 20h
kube-proxy-6mngd 1/1 Running 1 (15h ago) 22h
kube-proxy-c9b4h 1/1 Running 1 20h
kube-proxy-pnjzh 1/1 Running 0 115m
kube-scheduler-k8s-master1 1/1 Running 24 (155m ago) 18h
kube-scheduler-k8s-master2 1/1 Running 9 (84m ago) 18h
kube-scheduler-k8s-worker2 1/1 Running 1 (2m14s ago) 115m
模拟当k8s-worker2
节点挂了,分别在其他master
节点验证集群是否可以用
k8s-worker2
节点挂了,vip
会飘逸到权重高的节点,这儿会漂移到master1
节点,master2
和master3
验证集群还是可用的- 当
master2
节点挂了,那就是真挂了,集群不能使用的
结论master
节点高可用必须至少要三个节点。
4. kubectl proxy 让外部网络访问K8S service的ClusterIP
使用kubectl proxy命令就可以使API server监听在本地的8001端口上:
$ kubectl proxy --port=8009
Starting to serve on 127.0.0.1:8009
如果想通过其它主机访问就需要指定监听的地址:
$ kubectl proxy --address=0.0.0.0 --port=8009
Starting to serve on [::]:8009
此时通过curl访问会出现未认证的提示:
$ curl -X GET -L http://k8s-master:8009/
<h3>Unauthorized</h3>
设置API server接收所有主机的请求:
$ kubectl proxy --address='0.0.0.0' --accept-hosts='^*$' --port=8009
Starting to serve on [::]:8009
访问正常:
<root@k8s-worker2 ~># curl -X GET -L http://k8s-master1:8009/api
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "192.168.19.152:6443"
}
]
}
两个点
- 当
haproxy
挂了的话,要让keepalived
的自动VIP
切换 - 当
apiserver
挂了的话,要让keepalived
的自动VIP
切换
vrrp_script chk_haproxy {
script "/bin/bash -c 'if [[ $(netstat -nlp | grep 16443) ]]; then exit 0; else exit 1; fi'" # haproxy 检测
interval 2 # 每2秒执行一次检测
weight 11 # 权重变化
}
-----------------------------
vrrp_script check_haproxy {
script "killall -0 haproxy"
interval 3
weight -2
fall 10
rise 2
}
#!/bin/bash
# ps aux |grep -v grep|grep haproxy|wc -l
haproxy_status=`ps -C haproxy --no-header |wc -l`
if [ $haproxy_status -eq 0 ];then
/root/nginx/sbin/nginx
sleep 3;
if [ `ps -C haproxy --no-header |wc -l` -eq 0 ];then
killall keepalived
fi
fi
#!/bin/bash
haproxy_status=`ps -C haproxy --no-header |wc -l`
if [ $haproxy_status -eq 0 ];then
systemctl start haproxy
sleep 3;
if [ `ps -C haproxy --no-header |wc -l` -eq 0 ];then
systemctl stop keepalived
fi
fi
notify_master “systemctl start haproxy” # 当成为master时就启动http服务
notify_backup “systemctl stop haproxy” # 当成为backup时就关闭http服务
notify_fault “systemctl stop haproxy” # 当节点故障时候
##VRRP script(s)
#添加一个用于定期指定的脚本,它的退出码将被所有的VRRP instance记录,它以非0的权重监视
vrrp_script<SCRIPT_NAME> {
script <STRING>|<QUOTED-STRING> #执行脚本的路径
interval <INTEGER> #调用脚本两次之间的间隔,默认为1秒
timeout <INEGER> #第二次调用脚本后多长时间没有回应的超时时间
weight <INTEGER:-254..254> #根据该权重,动态调整调用该脚本选项的vrrp实例优先级,默认是2. 当脚本执行码为0,权重大于0时,vrrp实例优先级增加;当脚本执行码为非0,权重小于0时,vrrp实例优先级减小,其他情况优先级不变。
#当该值为0时,不改变实例的优先级
rise <INTEGER> ##设置脚本返回值连续为0的次数。加入该参数后,当脚本执行码连续为0的次数为rise次,且权重大于0时,vrrp实例优先级增加
fall <INTEGER> ##设置脚本返回值连续为0的次数。加入该参数后,当脚本执行码连续为非0的次数为rfall次,且权重小于0时,vrrp实例优先级增加
}
weight可正可负。为正时检测成功+weight,相当与节点检测失败时本身priority不变,但其他检测成功节点priority增加。为负时检测失败本身priority减少。
配置使用了一个健康检查脚本/etc/keepalived/check _ apiserver
。负责确保保存虚拟IP
的节点上的 API
服务器是可用的
#!/bin/sh
errorExit() {
echo "*** $*" 1>&2
exit 1
}
curl --silent --max-time 2 --insecure https://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://localhost:${APISERVER_DEST_PORT}/"
if ip addr | grep -q ${APISERVER_VIP}; then
curl --silent --max-time 2 --insecure https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/"
fi
七、k8s+kube-vip实现k8s高可用
八、总结
其实如果基础硬件资源足够的情况下,应该把负载调度器单独用一台或多台,不应该用master节点来负载调度