目前k8s发展太快,版本迭代和更新等,导致现在有很多冲突、不适用的解决方案,故搭建一套各个软件版本都较新的集群。
一台5600x+32G+有外网的电脑。
VMWARE虚拟机。
centos7最新的dvd版镜像。
以前做法:多个master服务器,然后使用keepalived监控master节点的可用性和故障转移,使用haproxy对master进行均衡负载。
新的解决方案:利用K8S原生的kube-vip实现master高可用。
建议使用kube-vip解决方案,这样,不存在VIP节点的问题,其中心思想也是vip架构,但是通过公平选举诞生的。
系统和软件版本选择
centos7.9.2009 3.10.x内核
kube-vip 0.3.8
Kubernetes 1.22.3
containerd(替代docker) 1.5.7
flannel (推荐可用calico替代)
主机和节点规划:
hostname ip
api.k8s.local 192.168.66.10
k8s-master01 192.168.66.11
k8s-master02 192.168.66.12
k8s-master03 192.168.66.13
k8s-node01 192.168.66.21
k8s-node02 192.168.66.22
k8s-node03 192.168.66.23
备注:
1.建议选择centos7,因为centos8无法安装npt和nptdate换成了wntp,8最新内核也取消了ntf-conn_ipvs的插件,8也只能支持到今年年底。
2.建议使用离线安装,不要用boot,重要不会自动获取IP,然后也不会等待软件源更新时间。采用最小安装。
3.vip的域名建议就采用默认的,一定要是那种域名形式的,否则无法解析和运行
以下步骤重复多台部署,感兴趣的可以用ansible批量部署,我这边没环境就没安排。
分别设置静态ip,然后用xshell批量部署了。
cd /etc/sysconfig/network-scripts
,找到里面的网卡名称,再vim进入,在里面添加静态网络信息。
将BOOTPROTO改成static,再添加IP,子网掩码,网关(我这里是66.1),dsn
centos7重启网卡:systemctl restart network
1.centos7 添加yum源
更新国内源。
yum install -y wget
进入yum.repos.d文件夹
cd /etc/yum.repos.d/
mv CentOS-Base.repo CentOS-Base.repo.backup
下载yum源
wget http://mirrors.163.com/.help/CentOS7-Base-163.repo
wget http://mirrors.aliyun.com/repo/Centos-7.repo
yum clean all 清除系统yum 缓存
yum makecache 生成yum缓存
2.设置系统主机名以及host文件修改
6台主机分别设置hostname:
hostnamectl set-hostname api.k8s.local
hostnamectl set-hostname k8s-master01
…
hostnamectl set-hostname k8s-node03
再修改host文件,让6台机器之间可以互相访问。
vi /etc/hosts
添加6条记录:(自带的千万别删,是添加)
192.168.66.10 api.k8s.local
192.168.66.11 k8s- master01
192.168.66.12 k8s- master02
192.168.66.13 k8s-master03
192.168.66.21 k8s-node01
192.168.66.22 k8s-node02
192.168.66.23 k8s-node03
3.升级内核版本(先升级)
centos7.x系统自带的3.10.x内核存在一些bug,导致运行的docker和k8s不稳定。所以升级一下,我这边get最新的是5.4,所以就用这个好了
#导入ELRepo仓库的公共密钥
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
#安装ELRepo仓库的yum源
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
上面命令如果报错,yum -y update可解决
查看可选的版本:
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
yum --enablerepo=elrepo-kernel install -y kernel-lt
#设置开机从新内核启动
grub2-set-default 0 #表示设置最新版本的为默认启动方式
reboot
4.安装依赖包
6台都需安装如下包:
yum install -y ntpdate ntp conntrack ipvsadm ipset jq iptables curl sysstat libseccomp wget vim net-tools git
解释:ntpdate ntp是同步时间用的组件。
conntrack ipvsadm ipset jq iptables 都是为了开启相应的网络组件
libseccomp:是运行containerd和docker的必要组件。这里有个坑,后面会讲到。
5.设置防火墙为iptable并设置为默认规则
停止防火墙并关闭其自启动:
systemctl stop firewalld && systemctl disable firewalld
安装iptables-services,启动它,并且设置开机自启,清空它的规则,保存默认规则
yum -y install iptables-services && systemctl start iptables && systemctl enable iptables && iptables -F && service iptables save
6.关闭seniuxs和虚拟内存
关闭swap分区(即虚拟内存)并且将其永久关闭。(虚拟内存在k8s里怕拖累系统运行速度)
swapoff -a && sed -i '/swap/s/^\(.*\)$/#\1/g' /etc/fstab
SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源,安全用。浪费资源和权限
setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
7.调整内核参数
cat > kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1 #开启网桥模式
net.bridge.bridge-nf-call-ip6tables=1 #开启网桥模式
net.ipv4.ip_forward=1 #net.ipv4.tcp_tw_recycle=0
vm.swappiness=0 #禁止使用swap空间,只有当系统OOM时才允许使用它
vm.overcommit_memory=1 #不检查物理内存是否够用
vm.panic_on_oom=0 #开启OOM
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1 #关闭ipv6的协议
net.netfilter.nf_conntrack_max=2310720
EOF
注:
net.bridge.bridge-nf-call-iptables=1 #开启网桥模式
net.bridge.bridge-nf-call-ip6tables=1 #开启网桥模式
net.ipv6.conf.all.disable_ipv6=1 #关闭ipv6的协议
以上为开启k8s必须的方案,其余仅为优化选项。
cp kubernetes.conf /etc/sysctl.d/kubernetes.conf #拷贝文件至sysctl.d目录下
sysctl -p /etc/sysctl.d/kubernetes.conf #手动刷新,并让其立即生效
报错1:显示没有 /proc/sys/net/bridge/bridge-nf-call-iptables
modprobe br_netfilter
报错2:显示没有 /proc/sys/net/ipv4/tcp_tw_recycle:
从4.10内核开始,官方修改了时间戳的生成机制,没有tcp_tw_recycle,只有tcp_tw_refuse,因此,需要删掉该行
报错3:显示没有 /proc/sys/net/netfilter/nf_conntrack:
3.0版本中是没有这个的,需要升级到4.0以后才会有这个文,或者如下指定
modprobe ip_netfilter
8.调整系统时区
时间要同步,否则k8s无法完成相应的操作
#设置系统时区为中国/上海
timedatectl set-timezone Asia/Shanghai
#将当前的UTC时间写入硬件时钟
timedatectl set-local-rtc 0
#重启依赖于系统时间的服务
systemctl restart rsyslog
systemctl restart crond
9.关闭不需要的服务
关闭邮箱服务,没啥用的服务。
systemctl stop postfix && systemctl disable postfix
报错没有load此服务:尝试systemctl disable postfix,若还是没有,那就是此版本中没有这个服务
10.设置rsyslogd和systemd journald
设置日志的保存方式
mkdir /var/log/journal #持久化保存日志的目录
mkdir /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF
[Journal]
#持久化保存到磁盘
Storage=persistent
#压缩历史日志
Compress=yes
SyncIntervalSec=5m
RateLimitInterval=30s
RateLimitBurst=1000
#最大占用空间10G
SystemMaxUse=10G
#单日志文件最大200M
SystemMaxFileSize=200M
#日志保存时间2周
MaxRetentionSec=2week
#不将日志转发到syslog
ForwardToSyslog=no
EOF
重启journald服务:
systemctl restart systemd-journald
推荐就是用journald来保存日志,后续也可通过此命令查找一些bug。
至此,初始化即完成了。以上步骤全部节点都需要操作。下面进行k8s的部署安装。
kubeam是官方推荐的安装方式,比较简洁快速,所以我们也用这个。下面进行相关的配置。
1.Kube-proxy开启ipvs的前置条件
常用的有iptables和ipvs 2种调度方式。ipvs实现了传输层负载均衡,也就是我们常说的4层LAN交换,会增加service调度pod的效率,需要进行配置,否则就会自动变回ipables的模式。
modprobe br_netfilter #加载netfilter模块
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 #modprobe -- nf_conntrack_ipv4
EOF
上述文件会引导一些相关依赖的加载
chmod 755 /etc/sysconfig/modules/ipvs.modules #赋予这些文件755权限
/etc/sysconfig/modules/ipvs.modules #启动这些模块
lsmod | grep -e ip_vs -e nf_contrack_ipv4 #查看这些模块是否被成功引导和加载
错误1:modprobe: FATAL: Module nf_conntrack_ipv4 not found in directory /lib/modules/…
原因分析:
linux kernel 4.19版本已经将nf_conntrack_ipv4 更新为 nf_conntrack, 而 kube-proxy 1.13 以下版本,强依赖 nf_conntrack_ipv4。
解决方式:
1、降级内核到 4.18
2、升级kube-proxy到 1.13+ (推荐,无需重启机器,影响小)
我们这里新版已经ok了所以就不用加载也没事。
2.安装containerd
需要在各个节点上全部安装此组件。由于需要调用runc,所以需要先安装runc。github有多个版本,cri版本,集成了相关依赖,故用这个安装。
wget https://github.com/containerd/containerd/releases/download/v1.5.7/cri-containerd-cni-1.5.7-linux-amd64.tar.gz
将压缩包解压到系统的各个目录中:
tar -C / -xzf cri-containerd-cni-1.5.7-linux-amd64.tar.gz
然后将/usr/local/bin和/usr/local/sbin追加到~/.bashrc文件的PATH环境变量中。
export PATH=$PATH:/usr/local/bin:/usr/local/sbin
执行下面的命令使其生效:
source ~/.bashrc
containerd的默认配置文件为/etc/containerd/config.toml,我们需要生成一个默认的配置:
mkdir -p /etc/containerd
containerd config default>/etc/containerd/config.toml
对于使用systemd作为init system的Linux发行版,使用systemd作为容器的cgroup driver可以确保节点在资源紧张情况下更稳定。推荐将containerd的cgroup driver配置为systemd(跟docker类似)
设置systemdCgroup为true
也可以根据需要修改mirrors地址
由于我们下载的安装包里面有一个/etc/systemd/system/containerd.service服务,所以重载并设置开机启动即可。
systemctl daemon-reload
systemctl enable containerd --now
配置完成后,可以用ctr version和crictr 查看安装的版本信息。
负载均衡安装设置(kube-vip)
kube-vip通过静态pod运行在控制节点(master)上。可以选择,ARP和BGP来设置。ARP模式,会选举leader,继承VIP的虚拟ip,而在BGP模式下,所有节点都会通知vip地址。
这里使用ARP模式。(BGP更优,最新版本推出的功能,避免ARP广播拥堵和拦截,不过BGP需要上层有3层交换机,以此来实现定向广播)
获取 kube-vip 的 docker 镜像,并在 /etc/kuberentes/manifests 中设置静态 pod 的 yaml 资源清单文件,这样 Kubernetes 就会自动在每个控制平面节点上部署 kube-vip 的 pod 了。
3.设置VIP地址(仅在master01上部署先)
mkdir -p /etc/kubernetes/manifests/
export VIP=192.168.66.10
export INTERFACE=ens33
ctr image pull ghcr.io/kube-vip/kube-vip:v0.3.8
ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip \
/kube-vip manifest pod \
--interface $INTERFACE \
--vip $VIP \
--controlplane \
--services \
--arp \
--leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml
注:
VIP地址根据规划而设置,需要更后面k8s initd配置文件的一致
INTERFACE:要用虚拟机里面的网卡名字,否则很尴尬,后面vip pod就起不来。
其他master先不要部署,否则join时候会提示k8s目录存在。
报错:ctr: failed to create shim: OCI runtime create failed: unable to retrieve OCI runtime error (open /run/containerd/io.containerd.runtime.v2.task/default/…/log.json: no such file or directory): runc did not terminate successfully
解决:containerd版本比较高,而libseccomp版本太低(最新是2.5.2,yum默认安装是2.3)
wget https://github.com/seccomp/libseccomp/releases/download/v2.5.2/libseccomp-2.5.2.tar.gz
tar -zxvf libseccomp-2.5.2.tar.gz
cd libseccomp-2.5.2
./configure --prefix=/usr --disable-static
make && make install
yum -y install libseccomp libseccomp-dev
编译过程中,可能提升缺少gcc和gperf组件,缺啥yum安装即可。
PS:怕其他节点也存在这个问题,建议都一次性升级,避免后续出现镜像或pod运行在各个节点上时出问题!!!!chrony也被删除了,若后续有问题,可以安装上
4.安装kubeadm相关组件(6台都需要安装)
让kubeadm去引导成为k8s,添加repo源,这里使用的是阿里源
cat <<EOF >/etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
然后安装
yum -y install kubeadm kubectl kubelet --disableexcludes=kubernetes
kubeadm version
–disableexcludes 禁掉除了kubernetes之外的别的仓库
kubelet是与容器接口进行交互,而k8s通过kubeadm安装以后都是以Pod方式存在,底层是以容器的方式运行。所以一定要开机自启,不然的话启动不了k8s集群。
这里默认的一下子变成1.22.3了,怕改动过大查看官方文档,发现还没,尴尬,生产环境中建议指定版本安装,避免因为版本不一致出现问题(很可能出现)
systemctl enable kubelet.service
5.集群初始化(仅在master01上运行即可,其余join):
生成一个默认的yaml配置文档,然后进行修改!
kubeadm config print init-defaults --component-configs KubeletConfiguration > kubeadm.yaml
vim kubeadm.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.66.11 #当前master的ip
bindPort: 6443
nodeRegistration:
criSocket: /run/containerd/containerd.sock #默认是docker,改为cocntainerd
imagePullPolicy: IfNotPresent
name: k8s-master01 #名字改成hostname一致
taints: # 给master添加污点,master节点不能调度应用
- effect: "NoSchedule"
key: "node-role.kubernetes.io/master"
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs # kube-proxy 模式指定为IPVS
---
apiServer:
extraArgs:
authorization-mode: Node,RBAC
timeoutForControlPlane: 4m0s
certSANs: # 添加其他master节点的相关信息
- api.k8s.local
- k8s-master01
- k8s-master02
- k8s-master03
- 192.168.66.11
- 192.168.66.12
- 192.168.66.13
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
controlPlaneEndpoint: api.k8s.local:6443 # 设置控制平面Endpoint地址
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16 # 指定 pod 子网,因为后续是用flannel插件,若是其他的这里也需要同步修改。
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
注:若版本相近,建议直接复制粘贴,否则很容易出错!!!!!!
修改完成后,拉取镜像,避免后续master节点创建和join时候很慢.
kubeadm config images pull --config kubeadm.yaml
#master01开始初始化
kubeadm init --upload-certs --config kubeadm.yaml
如果成功了,就会出现很多的行,然后会出现join的命令
#根据提示创建文件及目录
#目的为保存 kubectl 与 api server 交互时的缓存,交互过程为https协议
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
注:所有master创建或加入后都需要执行创建这些目录的过程。因为大家其实都是一样一样的!
6.其他master和node节点加入
在master01初始化集群后,会产生2条join的指令。
上面带有control-plane的是master加入命令,如下图
master其他节点加入成功后,
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
然后是node节点的加入。加入完成后,在任一maste节点都能看到相关信息。
kubectl get node可以看到,master都处于notReady状态。那是其他两个master还未成功启动kube-vip的静态pod并且缺少网络插件。
PS:正常配置完成后,都是notready状态。
7.先将另外2台maser也生成kube-vip文件。
export VIP=192.168.66.10
export INTERFACE=ens33
ctr image pull ghcr.io/kube-vip/kube-vip:v0.3.8
ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip \
/kube-vip manifest pod \
--interface $INTERFACE \
--vip $VIP \
--controlplane \
--services \
--arp \
--leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml
8.再来安装网络插件
目前主流有2种可以解决,flannel和calico(新版推荐使用这个,不过由于之前我们在默认文件里面是10.244.0.0的flannel网络。故此次先用这个)。相比于flannel,calico转发效率更高,且消耗极小的cpu资源。
安装flannel(任一master节点操作即可)
Flannel是centos专门为kubenetes设计的一个网络规划服务。Flannel的设计目的就是为集群中的所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得“同属一个内网”且”不重复的”IP地址,并让属于不同节点上的容器能够直接通过内网IP通信。
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f kube-flannel.yml
安装完成后,可以看到所有master和node节点都变成ready状态了。
再查看coredns,之前一直也是pending状态,现在也是running了。
至此,我们的高可用kube-vip集群就搭建完成了。
kube-vip的BGP模式,效率更优(无需全部ARP广播),calico在大型网络里面也效率更优,建议大型网络和集群用这2种插件。