前言
搞了好多天(今天是20240819),中途遇到各种各样的问题,总算是可以用了
我这里用的vmware开了5台服务器做学习实践
K8S因为直接使用的 pkgs.k8s.io 仓库,所以直接拉取的最新release版(v1.31)
这里个人记录一下
友情提示:要使用 pkgs.k8s.io 仓库的话必须要科学上网哦
1. 环境准备
集群角色 | IP | 主机名 |
---|---|---|
控制节点 | 192.168.86.101 | weihengmaster1 |
控制节点 | 192.168.86.101 | weihengmaster1 |
控制节点 | 192.168.86.101 | weihengmaster1 |
控制节点 | 192.168.86.101 | weihengmaster1 |
控制节点 | 192.168.86.101 | weihengmaster1 |
Vip | 192.168.86.199 |
参考文档:https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#check-network-adapters
1.1 配置静态IP
注意:虚拟机克隆的,需要重新生成新的UUID和MachineID
重置MachineId:
rm -rf /etc/machine-id; systemd-machine-id-setup;reboot
#cat /etc/machine-id
重置UUID
nmcli con delete uuid acb2a913-945b-399d-815e-84a1a9d46485;nmcli con add type ethernet ifname ens160 con-name ens160;nmcli con up ens160
# 查看当前的网卡列表和 UUID:
# nmcli con show
# 删除要更改 UUID 的网络连接:
# nmcli con delete uuid <原 UUID>
# 重新生成 UUID:
# nmcli con add type ethernet ifname <接口名称> con-name <新名称>
# 重新启用网络连接:
# nmcli con up <新名称>
设置IP
nmcli con mod ens160 ipv4.addresses 192.168.86.101/24; nmcli con mod ens160 ipv4.gateway 192.168.2.1; nmcli con mod ens160 ipv4.method manual; nmcli con mod ens160 ipv4.dns "192.168.2.1"; nmcli con up ens160
1.2 修改主机名
hostnamectl set-hostname <newhostname>
1.3 配置免密
vim /etc/hosts
#添加主机配置
192.168.86.101 weihengmaster1
192.168.86.102 weihengmaster2
192.168.86.103 weihengmaster3
192.168.86.201 weihengnode1
192.168.86.202 weihengnode2
#每个服务节点执行如下命令即可添加上述配置
echo -e "192.168.86.101 weihengmaster1\n192.168.86.102 weihengmaster2\n192.168.86.103 weihengmaster3\n192.168.86.201 weihengnode1\n192.168.86.202 weihengnode2" | sudo tee -a /etc/hosts
#生成公私钥
ssh-keygen -f /root/.ssh/id_rsa -P ''
#把本地的ssh公钥文件安装到远程主机对应的账户
ssh-copy-id -i .ssh/id_rsa.pub weihengmaster1
ssh-copy-id -i .ssh/id_rsa.pub weihengmaster2
ssh-copy-id -i .ssh/id_rsa.pub weihengmaster3
ssh-copy-id -i .ssh/id_rsa.pub weihengnode1
ssh-copy-id -i .ssh/id_rsa.pub weihengnode2
#测试免密登录
[root@weihengmaster1 ~]# ssh weihengnode2
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Tue Jul 30 20:00:52 2024 from 192.168.2.101
[root@weihengnode2 ~]#
1.4 关闭防火墙
systemctl stop firewalld; systemctl disable firewalld
1.5 关闭SELinux
setenforce 0
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
# 参数解释
#
# setenforce 0
# 此命令用于设置 SELinux 的执行模式。0 表示关闭 SELinux。
#
# sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
# 该命令使用 sed 工具来编辑 /etc/selinux/config 文件。其中 '-i' 参数表示直接修改原文件,而不是输出到终端或另一个文件。's#SELINUX=enforcing#SELINUX=disabled#g' 是 sed 的替换命令,它将文件中所有的 "SELINUX=enforcing" 替换为 "SELINUX=disabled"。这里的 '#' 是分隔符,用于替代传统的 '/' 分隔符,以避免与路径中的 '/' 冲突。
#重启服务器,执行如下命令后显示 Disabled 则禁用成功
getenforce
1.6 关闭交换分区
#修改配置文件,永久关闭交换分区
sed -ri 's/.*swap.*/#&/' /etc/fstab
#修改内核参数
swapoff -a && sysctl -w vm.swappiness=0
#检查
cat /etc/fstab
1.7 配置ulimits
ulimit -SHn 65535
cat >> /etc/security/limits.conf <<EOF
* soft nofile 655360
* hard nofile 131072
* soft nproc 655350
* hard nproc 655350
* soft memlock unlimited
* hard memlock unlimited
EOF
# 参数解释
#
# soft nofile 655360
# soft表示软限制,nofile表示一个进程可打开的最大文件数,默认值为1024。这里的软限制设置为655360,即一个进程可打开的最大文件数为655360。
#
# hard nofile 131072
# hard表示硬限制,即系统设置的最大值。nofile表示一个进程可打开的最大文件数,默认值为4096。这里的硬限制设置为131072,即系统设置的最大文件数为131072。
#
# soft nproc 655350
# soft表示软限制,nproc表示一个用户可创建的最大进程数,默认值为30720。这里的软限制设置为655350,即一个用户可创建的最大进程数为655350。
#
# hard nproc 655350
# hard表示硬限制,即系统设置的最大值。nproc表示一个用户可创建的最大进程数,默认值为4096。这里的硬限制设置为655350,即系统设置的最大进程数为655350。
#
# soft memlock unlimited
# soft表示软限制,memlock表示一个进程可锁定在RAM中的最大内存,默认值为64 KB。这里的软限制设置为unlimited,即一个进程可锁定的最大内存为无限制。
#
# hard memlock unlimited
# hard表示硬限制,即系统设置的最大值。memlock表示一个进程可锁定在RAM中的最大内存,默认值为64 KB。这里的硬限制设置为unlimited,即系统设置的最大内存锁定为无限制。
1.8 安装iptables
所有主机安装
#安装iptables
yum install iptables-services -y
#禁用iptables
service iptables stop && systemctl disable iptables
#清空防火墙规则
iptables -F
1.9 安装基础软件包
在所有master和node节点执行
yum install -y yum-utils device-mapper-persistent-data lvm2 wget net-tools nfs-utils lrzsz gcc gcc-c++ make cmake libxml2-devel openssl-devel curl curl-devel unzip sudo libaio-devel wget vim ncurses-devel autoconf automake zlib-devel python-devel epel-release openssh-server socat ipvsadm conntrack telnet rsync
1.10 开启ipvs
不开启ipvs将会使用iptables进行数据包转发,但是效率低,所以官网推荐需要开通ipvs。
mkdir -p /etc/sysconfig/modules/
cat > /etc/sysconfig/modules/ipvs.modules << "EOF"
#!/bin/bash
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack"
for kernel_module in ${ipvs_modules}; do
/sbin/modinfo -F filename ${kernel_module} > /dev/null 2>&1
if [ 0 -eq 0 ]; then
/sbin/modprobe ${kernel_module}
fi
done
EOF
#ip_vs:IPVS 是 Linux 内核中的一个模块,用于实现负载均衡和高可用性。它通过在前端代理服务器上分发传入请求到后端实际服务器上,提供了高性能和可扩展的网络服务。
#ip_vs_rr:IPVS 的一种调度算法之一,使用轮询方式分发请求到后端服务器,每个请求按顺序依次分发。ip_vs_wrr:IPVS 的一种调度算法之一,使用加权轮询方式分发请求到后端服务器,每个请求按照指定的权重比例分发。
#nf_conntrack:这是一个内核模块,用于跟踪和管理网络连接,包括 TCP、UDP 和 ICMP 等协议。它是实现防火墙状态跟踪的基础。
#其他的大家可以自己网上查一下...
#授权并检查
chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep ip_vs
#拷贝到其他主机(所有master和worker)
scp /etc/sysconfig/modules/ipvs.modules weihengmaster2:/etc/sysconfig/modules/
1.11 安装docker-ce
在所有master和node节点执行
#设置云源 - docker官方(我用的这个)
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
#阿里yum源 - 国内用这个
#sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#刷新yum缓存
sudo yum makecache
#安装
yum install docker-ce docker-ce-cli containerd.io -y
#配置开机启动
systemctl start docker && systemctl enable docker.service
#查看状态
systemctl status docker
1.12 安装cri-dockerd
参考文档:https://mirantis.github.io/cri-dockerd/usage/install/
引用一段原文:
The easiest way to install cri-dockerd is to use one of the pre-built binaries or packages from the releases page. There are numerous supported platforms and using a pre-built package will install the binary and setup your system to run it as a service.
这就感觉有点坑爹,怎么就没有yum安装呢?那我们只能通过源码来安装了
容器运行时接口(Container Runtime Interface,CRI)
cri-dockerd 提供了一个接口,使得 Docker 能够符合 Kubernetes 的 CRI 标准,从而可以在 Kubernetes 中直接使用 Docker 作为容器运行时 ,通过 cri-dockerd,用户仍然可以使用 Docker 作为容器运行时,而无需修改现有的 Docker 工作流程。
我这边通过 releases page 手动下载并安装的cri-dockerd
在所有master和worker节点安装
目前(20240731)最新版本是0.3.15,我这里选了0.3.14(按照一般原则,不使用最新版本,以防踩坑)
#我切换下目录
#mkdir -p /data/work && cd /data/work
#下载cri-docker
#https://github.com/Mirantis/cri-dockerd/releases/
#wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.14/cri-dockerd-0.3.14.amd64.tgz
#解压cri-docker
tar xvf cri-dockerd-*.amd64.tgz
cp -r cri-dockerd/ /usr/bin/
chmod +x /usr/bin/cri-dockerd/cri-dockerd
#scp -r cri-dockerd/ root@weihengmaster2:/usr/bin/
写入启动的配置文件
# 写入启动配置文件
cat > /usr/lib/systemd/system/cri-docker.service <<EOF
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
Requires=cri-docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/cri-dockerd/cri-dockerd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
# [Unit]
# - Description:该参数用于描述该单元的功能,这里描述的是CRI与Docker应用容器引擎的接口。
# - Documentation:该参数指定了相关文档的网址,供用户参考。
# - After:该参数指定了此单元应该在哪些其他单元之后启动,确保在网络在线、防火墙和Docker服务启动之后再启动此单元。
# - Wants:该参数指定了此单元希望也启动的所有单元,此处是希望在网络在线之后启动。
# - Requires:该参数指定了此单元需要依赖的单元,此处是cri-docker.socket单元。
#
# [Service]
# - Type:该参数指定了服务的类型,这里是notify,表示当服务启动完成时向系统发送通知。
# - ExecStart:该参数指定了将要运行的命令和参数,此处是执行/usr/bin/cri-dockerd/cri-dockerd命令,并指定了网络插件为cni和Pod基础设施容器的镜像为registry.aliyuncs.com/google_containers/pause:3.7。
# - ExecReload:该参数指定在服务重载时运行的命令,此处是发送HUP信号给主进程。
# - TimeoutSec:该参数指定了服务启动的超时时间,此处为0,表示无限制。
# - RestartSec:该参数指定了自动重启服务的时间间隔,此处为2秒。
# - Restart:该参数指定了在服务发生错误时自动重启,此处是始终重启。
# - StartLimitBurst:该参数指定了在给定时间间隔内允许的启动失败次数,此处为3次。
# - StartLimitInterval:该参数指定启动失败的时间间隔,此处为60秒。
# - LimitNOFILE:该参数指定了允许打开文件的最大数量,此处为无限制。
# - LimitNPROC:该参数指定了允许同时运行的最大进程数,此处为无限制。
# - LimitCORE:该参数指定了允许生成的core文件的最大大小,此处为无限制。
# - TasksMax:该参数指定了此服务的最大任务数,此处为无限制。
# - Delegate:该参数指定了是否将控制权委托给指定服务,此处为是。
# - KillMode:该参数指定了在终止服务时如何处理进程,此处是通过终止进程来终止服务。
#
# [Install]
# - WantedBy:该参数指定了希望这个单元启动的多用户目标。在这里,这个单元希望在multi-user.target启动。
写入cri-docker的socket配置文件
cat > /usr/lib/systemd/system/cri-docker.socket <<EOF
[Unit]
Description=CRI Docker Socket for the API
PartOf=cri-docker.service
[Socket]
ListenStream=%t/cri-dockerd.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 该配置文件是用于systemd的单元配置文件(unit file),用于定义一个socket单元。
#
# [Unit]
# - Description:表示该单元的描述信息。
# - PartOf:表示该单元是cri-docker.service的一部分。
#
# [Socket]
# - ListenStream:指定了该socket要监听的地址和端口,这里使用了%t占位符,表示根据单元的类型来决定路径。%t/cri-dockerd.sock表示将监听Unix域套接字cri-dockerd.sock。Unix域套接字用于在同一台主机上的进程之间通信。
# - SocketMode:指定了socket文件的权限模式,此处为0660,即用户和用户组有读写权限,其他用户无权限。
# - SocketUser:指定了socket文件的所有者,此处为root用户。
# - SocketGroup:指定了socket文件的所属用户组,此处为docker用户组。
#
# [Install]
# - WantedBy:部分定义了该单元的安装配置信息。WantedBy=sockets.target表示当sockets.target单元启动时,自动启动该socket单元。sockets.target是一个系统服务,用于管理所有的socket单元。
启动cri-docker
systemctl daemon-reload
# 用于重新加载systemd管理的单位文件。当你新增或修改了某个单位文件(如.service文件、.socket文件等),需要运行该命令来刷新systemd对该文件的配置。
systemctl enable --now cri-docker.service
# 启用并立即启动cri-docker.service单元。cri-docker.service是cri-docker守护进程的systemd服务单元。
systemctl restart cri-docker.service
# 重启cri-docker.service单元,即重新启动cri-docker守护进程。
systemctl status docker.service
systemctl status cri-docker.service
# 显示docker.service单元的当前状态,包括运行状态、是否启用等信息。
2. 开始安装高可用集群
2.1 安装 kubeadm、kubelet 和 kubectl
参考文档:https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
你需要在每台机器上安装以下的软件包:
- kubeadm:用来初始化集群的指令。
- kubelet:在集群中的每个节点上用来启动 Pod 和容器等。
- kubectl:用来与集群通信的命令行工具。
2.1.1 添加 Kubernetes 的 yum 仓库
#这会覆盖 /etc/yum.repos.d/kubernetes.repo 中现存的所有配置
#如果要下载其他版本,在这里改对应的版本号就可以了
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.31/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.31/rpm/repodata/repomd.xml.key
EOF
#备一个阿里云的仓库,不过我是用的 pkgs.k8s.io
[kubernetes-aliyun]
name=Kubernetes from Aliyun
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
2.1.2 安装 kubelet kubeadm kubectl
#使用 yum 安装 kubectl
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable --now kubelet
#检查可用版本
#yum list --showduplicates kubelet kubeadm kubectl
#安装指定版本示例 - 我安装时没有指定版本号,安装的是 1.31.1
#sudo yum install -y kubelet-1.28.2 kubeadm-1.28.2 kubectl-1.28.2 --disableexcludes=kubernetes
#删除
#sudo yum remove -y kubelet kubeadm kubectl
#查看安装状态
kubectl cluster-info
#如果提示下面的内容,表示安装出现异常
The connection to the server <server-name:port> was refused - did you specify the right host or port?
#官方提示的解决办法:For example, if you are intending to run a Kubernetes cluster on your laptop (locally), you will need a tool like Minikube to be installed first and then re-run the commands stated above.
#按照提示安装minikube后问题得到解决
kubectl 命令自动补全插件、API版本转换插件等:
https://kubernetes.io/zh-cn/docs/tasks/tools/install-kubectl-linux/#verify-kubectl-configuration
2.1.3 配置cgroup driver
参考文档:https://kubernetes.io/docs/setup/production-environment/container-runtimes/#container-runtimes
K8S的容器运行时有 4种(推荐使用containerd):
- containerd
- CRI-O
- Docker Engine
- Mirantis Container
v1.22版本以后不需要在 KubeletConfiguration 中指定cgroupDriver,他默认就会是systemd
我这里仅做官方推荐的containerd的配置
参考:https://github.com/containerd/containerd/blob/main/docs/getting-started.md
这里有段原文,打印默认配置,感觉有点用:
The default configuration can be generated via containerd config default > /etc/containerd/config.toml
vim /etc/containerd/config.toml
#添加SystemdCgroup = true 的配置
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
#重启containerd
sudo systemctl restart containerd
2.1.4 docker镜像加速器配置
把这个 native.cgroupdriver 也顺带调整下
# 这个加到所有master和node节点
tee /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors":["https://rsbud4vc.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hub-mirror.c.163.com","http://qtid6917.mirror.aliyuncs.com", "https://rncxm540.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-opts": {
"max-size": "100m"
}
}
EOF
# 都重启一下吧
systemctl daemon-reload
systemctl restart docker
systemctl restart cri-docker
systemctl restart containerd
2.1.5 设置IPv4数据包转发
默认情况下,Linux 内核不允许 IPv4 数据包在接口之间路由。 大多数 Kubernetes 集群网络实现都会更改此设置(如果需要)
# 设置所需的 sysctl 参数,参数在重新启动后保持不变
# 这里顺带把 允许 iptables 进行桥接的参数配置加上,确保流量在 Kubernetes 网络插件中正确过滤和路由
cat <<EOF | sudo tee /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
# 应用 sysctl 参数而不重新启动
sudo sysctl --system
# 验证 ipv4转发 是否设置成功
sysctl net.ipv4.ip_forward
2.1.6 修改sandbox_image【可选】
sudo vi /etc/containerd/config.toml
#修改sandbox_image - 可选项操作
[plugins."io.containerd.grpc.v1.cri".containerd]
...
sandbox_image = "registry.k8s.io/pause:3.10"
...
#重启container
sudo systemctl restart containerd
#查看
#sudo crictl info | grep sandboxImage
2.2 通过keepalive+nginx实现 k8s apiserver 节点高可用
yum install nginx keepalived nginx-mod-stream -y
# 写入nginx配置文件
vim /etc/nginx/nginx.conf
# 添加负载均衡配置
stream {
log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';
access_log /var/log/nginx/k8s-access.log main;
upstream backend {
least_conn;
hash $remote_addr consistent;
server 192.168.86.101:6443 max_fails=3 fail_timeout=30s;
server 192.168.86.102:6443 max_fails=3 fail_timeout=30s;
server 192.168.86.103:6443 max_fails=3 fail_timeout=30s;
}
server {
listen 16443;
proxy_connect_timeout 1s;
proxy_pass backend;
}
}
# 这段配置是一个nginx的stream模块的配置,用于代理TCP和UDP流量。
#
# 首先,`worker_processes 1;`表示启动一个worker进程用于处理流量。
# 接下来,`events { worker_connections 1024; }`表示每个worker进程可以同时处理最多1024个连接。
# 在stream块里面,定义了一个名为`backend`的upstream,用于负载均衡和故障转移。
# `least_conn`表示使用最少连接算法进行负载均衡。
# `hash $remote_addr consistent`表示用客户端的IP地址进行哈希分配请求,保持相同IP的请求始终访问同一台服务器。
# `server`指令用于定义后端的服务器,每个服务器都有一个IP地址和端口号,以及一些可选的参数。
# `max_fails=3`表示当一个服务器连续失败3次时将其标记为不可用。
# `fail_timeout=30s`表示如果一个服务器被标记为不可用,nginx将在30秒后重新尝试。
# 在server块内部,定义了一个监听地址为127.0.0.1:8443的服务器。
# `proxy_connect_timeout 1s`表示与后端服务器建立连接的超时时间为1秒。
# `proxy_pass backend`表示将流量代理到名为backend的上游服务器组。
#
# 总结起来,这段配置将流量代理到一个包含3个后端服务器的上游服务器组中,使用最少连接算法进行负载均衡,并根据客户端的IP地址进行哈希分配请求。如果一个服务器连续失败3次,则将其标记为不可用,并在30秒后重新尝试。
# keepalive 配置
# cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
cat > /etc/keepalived/keepalived.conf << EOF
! Configuration File for keepalived
# 内容如下
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from weihengtest@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id NGINX_MASTER
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state MASTER
# 修改为实际网卡名
interface ens160
virtual_router_id 51 # VRRP 路由 ID 实例,每个实例是唯一的
priority 80 #优先级,备服务器设置 90、80
advert_int 1 #指定 VRRP 心跳包通告间隔时间,默认1秒
authentication {
auth_type PASS
auth_pass 1111
}
# 虚拟 IP
virtual_ipaddress {
192.168.86.199/24
}
track_script {
check_nginx
}
}
EOF
# vrrp_script :指定检查 nginx 工作状态脚本(根据 nginx 状态判断是否故障转移)
# virtual_ipaddress :虚拟IP(VIP)
# 配置检查脚本
cat > /etc/keepalived/check_nginx.sh << "EOF"
#!/bin/bash
count=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$")
if [ "$count" -eq 0 ];then
echo "systemctl stop keepalived"
systemctl stop keepalived
fi
EOF
# 授权
chmod +x /etc/keepalived/check_nginx.sh
# 启动服务
systemctl daemon-reload
systemctl start nginx && systemctl start keepalived && systemctl enable nginx keepalived
# 查看
systemctl status keepalived
systemctl restart nginx && systemctl start keepalived
测试vip 是否绑定成功
2.2.1 测试 keepalived
停掉master1服务器的nginx,IP漂移到了master2
重新启动master1 的nginx 和 keepalived,IP又重新回到了master1,master2上的192.168.86.199消失了
systemctl start nginx && systemctl start keepalived
2.3 使用 kubeadm 初始化k8s集群
参考文档:https://kubernetes.io/zh-cn/docs/reference/config-api/kubeadm-config.v1beta3/#kubeadm-k8s-io-v1beta3-ClusterConfiguration
在 weihengmaster1 上创建 kubeadm-config.yaml
vim kubeadm-config.yaml
# 内容如下
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
nodeRegistration:
criSocket: unix:///var/run/cri-dockerd.sock
taints: []
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.31.0
controlPlaneEndpoint: 192.168.86.199:16443
imageRepository: registry.k8s.io
pauseImage: registry.k8s.io/pause:3.10
#imageRepository: registry.aliyuncs.com/google_containers
apiServer:
certSANs:
- 192.168.86.101
- 192.168.86.102
- 192.168.86.103
- 192.168.86.199
networking:
podSubnet: 10.244.0.0/16
serviceSubnet: 10.10.0.0/16
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
#使用 kubeadm 初始化 k8s 集群
#配置文件中已经添加了podSubnet 初始化时不需要再指定CIDR --pod-network-cidr
kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=SystemVerification
# 初始化完毕后提示如下信息:
[root@weihengmaster1 yaml]# kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=SystemVerification
W0819 11:06:23.675801 65456 initconfiguration.go:332] error unmarshaling configuration schema.GroupVersionKind{Group:"kubeadm.k8s.io", Version:"v1beta4", Kind:"ClusterConfiguration"}: strict decoding error: unknown field "pauseImage"
[init] Using Kubernetes version: v1.31.0
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action beforehand using 'kubeadm config images pull'
W0819 11:06:23.877235 65456 checks.go:846] detected that the sandbox image "registry.aliyuncs.com/google_containers/pause:3.9" of the container runtime is inconsistent with that used by kubeadm.It is recommended to use "registry.k8s.io/pause:3.10" as the CRI sandbox image.
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local weihengmaster1] and IPs [10.10.0.1 192.168.86.101 192.168.86.199 192.168.86.102 192.168.86.103]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [localhost weihengmaster1] and IPs [192.168.86.101 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost weihengmaster1] and IPs [192.168.86.101 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
W0819 11:06:26.509456 65456 endpoint.go:57] [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address
[kubeconfig] Writing "admin.conf" kubeconfig file
W0819 11:06:26.659190 65456 endpoint.go:57] [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address
[kubeconfig] Writing "super-admin.conf" kubeconfig file
W0819 11:06:26.831919 65456 endpoint.go:57] [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address
[kubeconfig] Writing "kubelet.conf" kubeconfig file
W0819 11:06:27.072574 65456 endpoint.go:57] [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
W0819 11:06:27.154376 65456 endpoint.go:57] [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests"
[kubelet-check] Waiting for a healthy kubelet at http://127.0.0.1:10248/healthz. This can take up to 4m0s
[kubelet-check] The kubelet is healthy after 1.001501701s
[api-check] Waiting for a healthy API server. This can take up to 4m0s
[api-check] The API server is healthy after 31.076338846s
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node weihengmaster1 as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[bootstrap-token] Using token: ont7fm.zuejdf6esu3dndvf
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
W0819 11:07:01.130325 65456 endpoint.go:57] [endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address
[addons] Applied essential addon: kube-proxy
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 control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
kubeadm join 192.168.86.199:16443 --token ont7fm.zuejdf6esu3dndvf \
--discovery-token-ca-cert-hash sha256:c2db25caebdb3de354eeec4b3c80cf5f6baa13d9aad7d590a52bd32eb3d1ede3 \
--control-plane
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.86.199:16443 --token ont7fm.zuejdf6esu3dndvf \
--discovery-token-ca-cert-hash sha256:c2db25caebdb3de354eeec4b3c80cf5f6baa13d9aad7d590a52bd32eb3d1ede3
[root@weihengmaster1 yaml]#
# 下面命令是把 master 节点加入集群 ,需要保存下来,每个人的都不一样
kubeadm join 192.168.86.199:16443 --token ont7fm.zuejdf6esu3dndvf \
--discovery-token-ca-cert-hash sha256:c2db25caebdb3de354eeec4b3c80cf5f6baa13d9aad7d590a52bd32eb3d1ede3 \
--control-plane \
--cri-socket unix:///var/run/cri-dockerd.sock
# 下面命令是把 node 节点加入集群 ,需要保存下来
kubeadm join 192.168.86.199:16443 --token ont7fm.zuejdf6esu3dndvf \
--discovery-token-ca-cert-hash sha256:c2db25caebdb3de354eeec4b3c80cf5f6baa13d9aad7d590a52bd32eb3d1ede3
#配置kubectl的配置文件 config,相当于对kubectl 进行授权,这样kubectl命令可以使用这个证书对k8s集群进行管理
[root@weihengmaster1 yaml]# mkdir -p $HOME/.kube
[root@weihengmaster1 yaml]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@weihengmaster1 yaml]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
[root@weihengmaster1 yaml]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
weihengmaster1 NotReady control-plane 3m2s v1.31.0
[root@weihengmaster1 yaml]#
# 此时集群状态还是 NotReady 状态,因为没有安装网络插件
2.4 扩容k8s集群
2.4.1 添加 master 节点
#创建证书存放目录 - 所有master和worker都执行
cd /root && mkdir -p /etc/kubernetes/pki/etcd &&mkdir -p ~/.kube/
#将配置拷贝到master2、master3、node1、node2
scp -r /root/.kube weihengmaster3:/root/
#把 master1 节点的证书拷贝到 master2、master3 上
scp /etc/kubernetes/pki/ca.crt weihengmaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/ca.key weihengmaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.key weihengmaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.pub weihengmaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.crt weihengmaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.key weihengmaster2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/etcd/ca.crt weihengmaster2:/etc/kubernetes/pki/etcd/
scp /etc/kubernetes/pki/etcd/ca.key weihengmaster2:/etc/kubernetes/pki/etcd/
scp /etc/kubernetes/pki/ca.crt weihengmaster3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/ca.key weihengmaster3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.key weihengmaster3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.pub weihengmaster3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.crt weihengmaster3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.key weihengmaster3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/etcd/ca.crt weihengmaster3:/etc/kubernetes/pki/etcd/
scp /etc/kubernetes/pki/etcd/ca.key weihengmaster3:/etc/kubernetes/pki/etcd/
#证书拷贝之后在 master2、master3 上执行如下命令
#kubeadm token create --print-join-command
kubeadm join 192.168.86.199:16443 --token ont7fm.zuejdf6esu3dndvf \
--discovery-token-ca-cert-hash sha256:c2db25caebdb3de354eeec4b3c80cf5f6baa13d9aad7d590a52bd32eb3d1ede3 \
--control-plane \
--cri-socket unix:///var/run/cri-dockerd.sock
检查
2.4.2 添加node节点
kubeadm join 192.168.86.199:16443 --token ont7fm.zuejdf6esu3dndvf \
--discovery-token-ca-cert-hash sha256:c2db25caebdb3de354eeec4b3c80cf5f6baa13d9aad7d590a52bd32eb3d1ede3 \
--cri-socket unix:///var/run/cri-dockerd.sock
#把角色调整下
kubectl label node weihengnode1 node-role.kubernetes.io/worker=worker
上面状态都是 NotReady 状态,是因为还没有安装网络插件
2.5 安装 kubernetes 网络插件 - Calico
参考文章:https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart
#安装calico网络插件 - 这个yaml可以下载下来
[root@weihengmaster1 ~]# kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
#这个yaml可以下载下来
#kubectl apply -f calico.yaml
#kubectl delete -f <calico.yaml>
kubectl get pods -n kube-system
2.6 测试在集群上创建pod,网络是否正常
[root@weihengnode1 ~]# docker pull busybox
[root@weihengnode1 ~]# kubectl run busybox --image busybox --restart=Never --rm -it busybox -- sh
If you don't see a command prompt, try pressing enter.
/ # ping www.baidu.com
PING www.baidu.com (103.235.46.96): 56 data bytes
2.7 测试集群中部署 tomcat 服务
创建一个tomcat的pod,再创建一个service对象将端口暴露出去
kubectl apply -f tomcat.yaml
kubectl apply -f tomcat-service.yaml
测试 → 宿主机访问vmware的K8S集群 → 测试OK
OK,就到这里了