目录
2.10 配置免密登录(在 k8s-master1 上操作 )
三、安装 Docker 和容器运行时 containerd(所有节点)
4.5.6 同步 etcd 配置到集群其它 master 节点
4.5.7 启动 etcd 集群(三个 master 节点都需要操作)
5.5.2 生成 apiserver 证书及 token 文件
5.6.7 同步 kubectl 配置文件到集群其它 master 节点
5.7 部署 kube-controller-manager
5.7.1 创建 kube-controller-manager 证书请求文件
5.7.2 创建 kube-controller-manager 证书文件
5.7.3 创建 kube-controller-manager 的 kube-controller-manager.kubeconfig
5.7.4 创建 kube-controller-manager 配置文件
5.8.1 创建 kube-scheduler 证书请求文件
5.8.3 创建 kube-scheduler 的 kubeconfig
6.1 部署 kubelet(在 k8s-master1 上操作)
6.1.1 创建 kubelet-bootstrap.kubeconfig
6.3.2 修改 calico.yaml 里的 pod 网段
七、安装 keepalived+nginx 实现 k8s apiserver 高可用
7.2 安装 nginx 与 keeplived(所有 master 节点)
7.3 nginx 配置(三个 master 节点的 nginx 配置一样)
7.4 配置 KeepAlived(所有 Master 节点)
7.6 启动 nginx 和 keepalived(所有 master 节点)
本篇文章所用到的资料文件下载地址:https://download.csdn.net/download/weixin_46560589/87450425
一、集群环境准备
- 操作系统:CentOS 7.6
- 最低配置: 2Gib 内存 / 2vCPU / 30G 硬盘
- 虚拟机网络:NAT 模式
- podSubnet( pod 网段):10.0.0.0/16
- serviceSubnet(service 网段):10.255.0.0/16
- k8s 版本:1.25.x
K8s 集群角色 | IP | 主机名 | 安装的组件 |
控制节点(master) | 192.168.78.150 | k8s-master1 | kube-apiserver、kube-controller-manager、kube-scheduler、etcd、kubelet、kube-proxy、docker、KeepAlive、nginx |
控制节点(master) | 192.168.78.151 | k8s-master2 | kube-apiserver、kube-controller-manager、kube-scheduler、etcd、kubelet、kube-proxy、docker、KeepAlive、nginx |
控制节点(master) | 192.168.78.152 | k8s-master3 | kube-apiserver、kube-controller-manager、kube-scheduler、etcd、kubelet、kube-proxy、docker、KeepAlive、nginx |
工作节点(node) | 192.168.78.153 | k8s-node1 | kubelet、kube-proxy、docker、calico、coredns |
工作节点(node) | 192.168.78.154 | k8s-node2 | kubelet、kube-proxy、docker、calico、coredns |
虚拟 IP(VIP) | 192.168.78.155 | 备注:在 master 节点生成,不需要另外新开一台主机 |
注意:VIP(虚拟 IP)不要和公司内⽹ IP 重复,⾸先去 ping ⼀下,不通才可⽤。VIP 需要和主机在同⼀个局域⽹内!
1.1 kubeadm 和二进制安装 k8s 适用场景分析
kubeadm 是官方提供的开源工具,是一个开源项目,用于快速搭建 kubernetes 集群,目前是比较方便和推荐使用的。kubeadm init 以及 kubeadm join 这两个命令可以快速创建 kubernetes 集群。Kubeadm 初始化 k8s,所有的组件都是以 pod 形式运行的,具备故障自恢复能力。
kubeadm 是工具,可以快速搭建集群,也就是相当于用程序脚本帮我们装好了集群,属于自动部署,简化部署操作,证书、组件资源清单文件都是自动创建的,自动部署屏蔽了很多细节,使得对各个模块感知很少,如果对 k8s 架构组件理解不深的话,遇到问题比较难排查。
kubeadm 适合需要经常部署 k8s,或者对自动化要求比较高的场景下使用。
二进制:在官网下载相关组件的二进制包,如果手动安装,对 kubernetes 理解也会更全面。
Kubeadm 和二进制都适合生产环境,在生产环境运行都很稳定,具体如何选择,可以根据实际项目进行评估。
kubeadm 安装 k8s:【Kubernetes 企业项目实战】01、使用 kubeadm 安装 K8s-v1.23 高可用集群_Stars.Sky的博客-CSDN博客
1.2 多 master 节点高可用架构图
二、基础环境配置(以下操作所有节点都得执⾏)
2.1 初步的环境初始化
可以查看我的这篇文章所有步骤都执行一遍:CentOS 7 初始化系统_centos7初始化_Stars.Sky的博客-CSDN博客
2.2 关闭交换分区 swap 提升性能
- # 临时关闭
- swapoff -a
- # 永久关闭:注释 swap 挂载,给 swap 这行开头加一下 "#" 注释
- sed -ri 's/.*swap.*/#&/' /etc/fstab
- # 查看效果
- free -m
为什么要关闭 swap 交换分区?
Swap 交换分区,如果机器内存不够,会使用 swap 分区,但是 swap 分区的性能较低,k8s 设计的时候为了能提升性能,默认是不允许使用交换分区的。Kubeadm 初始化的时候会检测 swap 是否关闭,如果没关闭,那就初始化失败。如果不想要关闭交换分区,安装k8s 的时候可以指定 --ignore-preflight-errors=Swap 来解决。
2.3 修改机器内核参数
- # 加载 br_netfilter 模块
- cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
- overlay
- br_netfilter
- EOF
- sudo modprobe overlay
- sudo modprobe br_netfilter
- # 验证模块是否加载成功:
- lsmod | grep br_netfilter
- # 修改内核参数
- echo "modprobe br_netfilter" >> /etc/profile
- cat > /etc/sysctl.d/k8s.conf <<EOF
- net.bridge.bridge-nf-call-ip6tables = 1
- net.bridge.bridge-nf-call-iptables = 1
- net.ipv4.ip_forward = 1
- EOF
- # 使刚才修改的内核参数生效
- sysctl -p /etc/sysctl.d/k8s.conf
- # 设置开机自启
- systemctl enable --now systemd-modules-load.service
问题 1 :sysctl 是做什么的?
在运行时配置内核参数 -p 从指定的文件加载系统参数,如不指定即从 /etc/sysctl.conf 中加载。
问题 2 :为什么要执行 modprobe br_netfilter ?
修改 /etc/sysctl.d/k8s.conf 文件,增加如下三行参数:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1sysctl -p /etc/sysctl.d/k8s.conf 出现报错:
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or directory
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory解决方法:
modprobe br_netfilter
问题 3 :为什么开启 net.bridge.bridge-nf-call-iptables 内核参数?
在 centos 下安装 docker,执行 docker info 出现如下警告:
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
解决办法:
vim /etc/sysctl.d/k8s.confnet.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
问题 4 :为什么要开启 net.ipv4.ip_forward = 1 参数?
kubeadm 初始化 k8s 如果报错:就表示没有开启 ip_forward,需要开启。
net.ipv4.ip_forward 是数据包转发:
出于安全考虑,Linux 系统默认是禁止数据包转发的。所谓转发即当主机拥有多于一块的网卡时,其中一块收到数据包,根据数据包的目的 ip 地址将数据包发往本机另一块网卡,该网卡根据路由表继续发送数据包。这通常是路由器所要实现的功能。
要让 Linux 系统具有路由转发功能,需要配置一个 Linux 的内核参数net.ipv4.ip_forward。这个参数指定了 Linux 系统当前对路由转发功能的支持情况;其值为 0时表示禁止进行 IP 转发;如果是 1,则说明 IP 转发功能已经打开。
2.4 配置阿里云的 repo 源
配置国内安装 docker 和 containerd 的阿里云的 repo 源:
- yum install yum-utils -y
- yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
2.5 配置安装 k8s 组件需要的阿里云的 repo 源
- cat > /etc/yum.repos.d/kubernetes.repo <<EOF
- [kubernetes]
- name=Kubernetes
- baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
- enabled=1
- gpgcheck=0
- EOF
2.6 主机系统优化
- # limit 优化
- ulimit -SHn 65535
- cat <<EOF >> /etc/security/limits.conf
- * soft nofile 655360
- * hard nofile 131072
- * soft nproc 655350
- * hard nproc 655350
- * soft memlock unlimited
- * hard memlock unlimited
- EOF
2.7 开启 ipvs
不开启 ipvs 将会使用 iptables 进行数据包转发,效率低,所以官网推荐需要开通 ipvs:
- # 编写 ipvs 脚本
- vim /etc/sysconfig/modules/ipvs.modules
- #!/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
- # 执行脚本
- chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep ip_vs
问题 1 :ipvs 是什么?
ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的 4 层 LAN交换,作为 Linux 内核的一部分。ipvs 运行在主机上,在真实服务器集群前充当负载均衡器。ipvs 可以将基于 TCP 和 UDP 的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。
问题 2 :ipvs 和 iptable 对比分析
kube-proxy 支持 iptables 和 ipvs 两种模式, 在 kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于netfilter 的,但是 ipvs 采用的是 hash 表,因此当 service 数量达到一定规模时,hash 查表的速度优势就会显现出来,从而提高 service 的服务性能。那么 ipvs 模式和 iptables 模式之间有哪些差异呢?
ipvs 为大型集群提供了更好的可扩展性和性能
ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
ipvs 支持服务器健康检查和连接重试等功能
2.8 清除邮件提示消息
- # 清除 "您在 /var/spool/mail/root 中有新邮件"信息
- echo "unset MAILCHECK" >> /etc/profile
- source /etc/profile
- # 清空邮箱数据站空间
- cat /dev/null > /var/spool/mail/root
2.9 升级 Linux 内核
安装 kubernetes 1.24及以上版本,Linux Kernel 需要在 5.x 以上的版本才可满足需求。
2.9.1 安装 5.x 内核
- #1. 查看内核版本
- [root@k8s-master1 ~]# uname -r
- 3.10.0-957.el7.x86_64
- #2. 查看操作系统版本
- [root@k8s-master1 ~]# cat /etc/redhat-release
- CentOS Linux release 7.6.1810 (Core)
- #3. 更新软件源,导入 ElRepo 仓库公钥
- rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
- # ElRepo 是一个分发企业版 Linux 内核的社区仓库,在系统中导入 ElRepo 仓库的公钥,后续将从这个仓库中获取升级内核相关的资源。
- #4. 安装 ELRepo
- yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm -y
- #5. 查看可用的稳定版镜像,kernel-ml 为长期稳定版本,lt 为长期维护版本
- yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
- #6. 安装最新版内核
- yum --enablerepo=elrepo-kernel install kernel-ml
- # 此次安装最新长期支持版内核(推荐)
- yum --enablerepo=elrepo-kernel install -y kernel-lt
- #7. 查看当前系统已安装内核
- [root@k8s-master1 ~]# awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg
- 0 : CentOS Linux (5.4.231-1.el7.elrepo.x86_64) 7 (Core)
- 1 : CentOS Linux (3.10.0-957.el7.x86_64) 7 (Core)
- 2 : CentOS Linux (0-rescue-89c97f8441be4a6588d371b35bbb6a48) 7 (Core)
2.9.2 切换新内核启动
修改 /etc/default/grub 文件,设置 GRUB_DEFAULT 的值为 2.3.2 中输出的最新版内核对应的序号。CentOS Linux (5.4.231-1.el7.elrepo.x86_64) 7 (Core) 前边的序号是 0,所以设置GRUB_DEFAULT = 0 。
- vim /etc/default/grub
- GRUB_TIMEOUT=5
- GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
- GRUB_DEFAULT=0 # 只修改此次
- GRUB_DISABLE_SUBMENU=true
- GRUB_TERMINAL_OUTPUT="console"
- GRUB_CMDLINE_LINUX="rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
- GRUB_DISABLE_RECOVERY="true"
- # 重新配置内核参数
- grub2-mkconfig -o /boot/grub2/grub.cfg
- # 重启系统
- reboot
- # 再次查看系统内核是否为最新版本
- [root@k8s-master1 ~]# uname -r
- 5.4.231-1.el7.elrepo.x86_64
2.10 配置免密登录(在 k8s-master1 上操作 )
Master1 节点免密钥登录其他节点,安装过程中⽣成配置⽂件和证书均在 Master1 上操作,集群管理也在 Master01上操作。密钥配置如下:
- # ⼀直回⻋就⾏
- ssh-keygen -t rsa
- # 等待一会,然后输入 yes,再输入各主机的密码即可
- for i in k8s-master1 k8s-master2 k8s-master3 k8s-node1 k8s-node2;do ssh-copy-id -i .ssh/id_rsa.pub $i;done
三、安装 Docker 和容器运行时 containerd(所有节点)
docker 的安装可以看我这篇文章更详细:【云原生 | Docker 基础篇】02、CentOS 7 安装 Docker 详细图文教程_Stars.Sky的博客-CSDN博客_centos7安装docker
3.1 安装 docker-ce
- yum -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin
- # 设置 Docker 开机自启并启动
- systemctl enable docker.service --now
- #1. 接下来生成 containerd 的配置文件:
- mkdir -p /etc/containerd
- containerd config default > /etc/containerd/config.toml
- # 修改配置文件:
- vim /etc/containerd/config.toml
- 把 SystemdCgroup = false 修改成 SystemdCgroup = true
- 把 sandbox_image = "k8s.gcr.io/pause:3.6" 修改成 sandbox_image="registry.aliyuncs.com/google_containers/pause:3.7"
- # 配置 containerd 开机启动,并启动 containerd
- systemctl enable containerd --now
- #2. 使用 crictl 对 Kubernetes 节点进行调试
- cat > /etc/crictl.yaml <<EOF
- runtime-endpoint: unix:///run/containerd/containerd.sock
- image-endpoint: unix:///run/containerd/containerd.sock
- timeout: 10
- debug: false
- EOF
- systemctl restart containerd
- #3. 配置 containerd 镜像加速器
- vim /etc/containerd/config.toml
- # 找到 config_path = "",修改成如下目录:
- config_path = "/etc/containerd/certs.d"
- # 保存退出 wq
- mkdir /etc/containerd/certs.d/docker.io/ -p
- vim /etc/containerd/certs.d/docker.io/hosts.toml
- # 写入如下内容:
- [host."https://vh3bm52y.mirror.aliyuncs.com",host."https://registry.docker-cn.com"]
- capabilities = ["pull"]
- # 重启containerd:
- systemctl restart containerd
3.2 配置 docker 镜像加速器和驱动
docker 镜像加速器可以看我这篇文章更详细:【云原生 | Docker 基础篇】03、Docker 阿里云镜像加速器_Stars.Sky的博客-CSDN博客_docker 镜像加速
- # 修改 docker 文件驱动为 systemd,默认为 cgroupfs,kubelet 默认使用 systemd,两者必须一致才可
- mkdir -p /etc/docker
- vim /etc/docker/daemon.json
- {
- "registry-mirrors":["https://hlfcd01t.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hub-mirror.c.163.com"],
- "exec-opts": ["native.cgroupdriver=systemd"]
- }
- # 重新加载配置文件并重启 docker
- systemctl daemon-reload && systemctl restart docker
四、搭建 etcd 集群(在 master1 上操作)
etcd 是一个高可用的键值数据库,存储 k8s 的资源状态信息和网络信息的,etcd 中的数据变更是通过 api server 进行的。
4.1 配置 etcd 工作目录
- # 创建 etcd 配置文件、证书文件、数据存放目录(三个 master 节点上都创建以下目录)
- mkdir -p /etc/etcd
- mkdir -p /etc/etcd/ssl
- mkdir -p /var/lib/etcd/default.etcd
4.2 安装签发证书工具 cfssl
cfssl GitHub下载官网:Releases · cloudflare/cfssl · GitHub
cfssl 是使用 go 编写,由 CloudFlare 开源的一款 PKI/TLS 工具。主要程序有:
- cfssl 是 CFSSL 的命令行工具;
- cfssljson 用来从 cfssl 程序获取 JSON 输出,并将证书、密钥、CSR 和 bundle 写入文件中。
- [root@k8s-master1 ~]# mkdir -p /data/work
- [root@k8s-master1 ~]# cd /data/work/
- # 如果在虚机上下载不了,就复制链接到浏览器上下载再上传
- [root@k8s-master1 work]# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
- [root@k8s-master1 work]# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
- [root@k8s-master1 work]# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
- [root@k8s-master1 work]# ls
- cfssl-certinfo_linux-amd64 cfssljson_linux-amd64 cfssl_linux-amd64
- # 添加可执行权限
- [root@k8s-master1 work]# chmod +x cfssl*
- [root@k8s-master1 work]# mv cfssl_linux-amd64 /usr/local/bin/cfssl
- [root@k8s-master1 work]# mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
- [root@k8s-master1 work]# mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo
- # 验证
- [root@k8s-master1 work]# cfssl version
- Version: 1.2.0
- Revision: dev
- Runtime: go1.6
4.3 配置 CA 证书
4.3.1 创建 ca 证书请求文件
- [root@k8s-master1 work]# vim ca-csr.json
- {
- "CN": "kubernetes",
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "ST": "Hubei",
- "L": "Wuhan",
- "O": "k8s",
- "OU": "system"
- }
- ],
- "ca": {
- "expiry": "87600h"
- }
- }
- # 创建 ca 证书
- [root@k8s-master1 work]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
注:
-
CN:Common Name(公用名称),kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name);浏览器使用该字段验证网站是否合法;对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端证书则为证书申请者的姓名。
-
O:Organization(单位名称),kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group);对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端单位证书则为证书申请者所在单位名称。
-
L 字段:所在城市。
-
S 字段:所在省份。
-
C 字段:只能是国家字母缩写,如中国:CN
4.3.2 配置 ca 证书策略
- [root@k8s-master1 work]# vim ca-config.json
- {
- "signing": {
- "default": {
- "expiry": "87600h"
- },
- "profiles": {
- "kubernetes": {
- "usages": [
- "signing",
- "key encipherment",
- "server auth",
- "client auth"
- ],
- "expiry": "87600h"
- }
- }
- }
- }
- server auth 表示 client 可以对使用该 ca 对 server 提供的证书进行验证。
- client auth 表示 server 可以使用该 ca 对 client 提供的证书进行验证。
4.4 创建 etcd 证书
配置 etcd 证书请求,hosts 的 ip 改为自己 etcd 所在 master 节点的 IP 和虚拟 IP:
- # 配置 etcd 请求文件
- [root@k8s-master1 work]# vim etcd-csr.json
- {
- "CN": "etcd",
- "hosts": [
- "127.0.0.1",
- "192.168.78.150",
- "192.168.78.151",
- "192.168.78.152",
- "192.168.78.155"
- ],
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [{
- "C": "CN",
- "ST": "Hubei",
- "L": "Wuhan",
- "O": "k8s",
- "OU": "system"
- }]
- }
- # 上述文件 hosts 字段中 IP 为所有 etcd 节点的集群内部通信IP,可以预留几个 ip,方便日后做扩容用
- # 生成 etcd 证书
- [root@k8s-master1 work]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes etcd-csr.json | cfssljson -bare etcd
- [root@k8s-master1 work]# ls
- ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem etcd.csr etcd-csr.json etcd-key.pem etcd.pem
4.5 部署 etcd 集群
4.5.1 下载 etcd 软件包
[root@k8s-master1 work]# wget https://github.com/etcd-io/etcd/releases/download/v3.5.2/etcd-v3.5.2-linux-amd64.tar.gz
4.5.2 安装 etcd 软件
- [root@k8s-master1 work]# tar -zxvf etcd-v3.5.2-linux-amd64.tar.gz
- [root@k8s-master1 work]# cp -p etcd-v3.5.2-linux-amd64/etcd* /usr/local/bin/
4.5.3 分发 etcd 软件
- [root@k8s-master1 work]# scp etcd-v3.5.2-linux-amd64/etcd* k8s-master2:/usr/local/bin/
- [root@k8s-master1 work]# scp etcd-v3.5.2-linux-amd64/etcd* k8s-master3:/usr/local/bin/
4.5.4 创建配置文件
- [root@k8s-master1 work]# cat > /etc/etcd/etcd.conf <<"EOF"
- #[Member]
- ETCD_NAME="etcd1"
- ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
- ETCD_LISTEN_PEER_URLS="https://192.168.78.150:2380"
- ETCD_LISTEN_CLIENT_URLS="https://192.168.78.150:2379,http://127.0.0.1:2379"
- #[Clustering]
- ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.78.150:2380"
- ETCD_ADVERTISE_CLIENT_URLS="https://192.168.78.150:2379"
- ETCD_INITIAL_CLUSTER="etcd1=https://192.168.78.150:2380,etcd2=https://192.168.78.151:2380,etcd3=https://192.168.78.152:2380"
- ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
- ETCD_INITIAL_CLUSTER_STATE="new"
- EOF
说明:
-
ETCD_NAME:节点名称,集群中唯一
-
ETCD_DATA_DIR:数据目录
-
ETCD_LISTEN_PEER_URLS:集群通信监听地址
-
ETCD_LISTEN_CLIENT_URLS:客户端访问监听地址
-
ETCD_INITIAL_ADVERTISE_PEER_URLS:集群通告地址
-
ETCD_ADVERTISE_CLIENT_URLS:客户端通告地址
-
ETCD_INITIAL_CLUSTER:集群节点地址
-
ETCD_INITIAL_CLUSTER_TOKEN:集群 Token
-
ETCD_INITIAL_CLUSTER_STATE:加入集群的当前状态,new 是新集群,existing 表示加入已有集群(扩容时用)
4.5.5 创建服务配置文件
- #5. 创建服务配置文件
- [root@k8s-master1 work]# cat > /usr/lib/systemd/system/etcd.service <<"EOF"
- [Unit]
- Description=Etcd Server
- After=network.target
- After=network-online.target
- Wants=network-online.target
- [Service]
- Type=notify
- EnvironmentFile=-/etc/etcd/etcd.conf
- WorkingDirectory=/var/lib/etcd/
- ExecStart=/usr/local/bin/etcd \
- --cert-file=/etc/etcd/ssl/etcd.pem \
- --key-file=/etc/etcd/ssl/etcd-key.pem \
- --trusted-ca-file=/etc/etcd/ssl/ca.pem \
- --peer-cert-file=/etc/etcd/ssl/etcd.pem \
- --peer-key-file=/etc/etcd/ssl/etcd-key.pem \
- --peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \
- --peer-client-cert-auth \
- --client-cert-auth
- Restart=on-failure
- RestartSec=5
- LimitNOFILE=65536
- [Install]
- WantedBy=multi-user.target
- EOF
- [root@k8s-master1 work]# cp ca*.pem /etc/etcd/ssl/
- [root@k8s-master1 work]# cp etcd*.pem /etc/etcd/ssl/
- [root@k8s-master1 work]# ls /etc/etcd/ssl/
- ca-key.pem ca.pem etcd-key.pem etcd.pem
4.5.6 同步 etcd 配置到集群其它 master 节点
- # 传送服务配置文件后,需要手动修改 etcd 节点名称及 IP 地址
- [root@k8s-master1 work]# for i in k8s-master2 k8s-master3;do scp /etc/etcd/etcd.conf $i:/etc/etcd/; done;
- # 传送证书文件
- [root@k8s-master1 work]# for i in k8s-master2 k8s-master3; do scp /etc/etcd/ssl/* $i:/etc/etcd/ssl; done
- # 传送服务启动配置文件
- [root@k8s-master1 work]# for i in k8s-master2 k8s-master3;do scp /usr/lib/systemd/system/etcd.service $i:/usr/lib/systemd/system/; done
k8s-master2 etcd.conf(修改 etcd 节点名称和 ip 即可):
- [root@k8s-master2 ~]# vim /etc/etcd/etcd.conf
- #[Member]
- ETCD_NAME="etcd2"
- ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
- ETCD_LISTEN_PEER_URLS="https://192.168.78.151:2380"
- ETCD_LISTEN_CLIENT_URLS="https://192.168.78.151:2379,http://127.0.0.1:2379"
- #[Clustering]
- ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.78.151:2380"
- ETCD_ADVERTISE_CLIENT_URLS="https://192.168.78.151:2379"
- ETCD_INITIAL_CLUSTER="etcd1=https://192.168.78.150:2380,etcd2=https://192.168.78.151:2380,etcd3=https://192.168.78.152:2380"
- ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
- ETCD_INITIAL_CLUSTER_STATE="new"
k8s-master3 etcd.conf(修改 etcd 节点名称和 ip 即可):
- [root@k8s-master3 ~]# vim /etc/etcd/etcd.conf
- #[Member]
- ETCD_NAME="etcd3"
- ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
- ETCD_LISTEN_PEER_URLS="https://192.168.78.152:2380"
- ETCD_LISTEN_CLIENT_URLS="https://192.168.78.152:2379,http://127.0.0.1:2379"
- #[Clustering]
- ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.78.152:2380"
- ETCD_ADVERTISE_CLIENT_URLS="https://192.168.78.152:2379"
- ETCD_INITIAL_CLUSTER="etcd1=https://192.168.78.150:2380,etcd2=https://192.168.78.151:2380,etcd3=https://192.168.78.152:2380"
- ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
- ETCD_INITIAL_CLUSTER_STATE="new"
4.5.7 启动 etcd 集群(三个 master 节点都需要操作)
启动 etcd 服务的时候,先启动的 master1 的 etcd 服务,会一直卡住在启动的状态,然后接着再启动 master2 的 etcd,这样 master1 这个节点 etcd 才会正常起来(最好是三个节点同时一起执行):
- systemctl daemon-reload
- systemctl enable --now etcd.service
- systemctl status etcd
4.5.8 验证集群状态
[root@k8s-master1 work]# ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.78.150:2379,https://192.168.78.151:2379,https://192.168.78.152:2379 endpoint health
- # 检查 ETCD 数据库性能
- ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.78.150:2379,https://192.168.78.151:2379,https://192.168.78.152:2379 check perf
ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.78.150:2379,https://192.168.78.151:2379,https://192.168.78.152:2379 member list
ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.78.150:2379,https://192.168.78.151:2379,https://192.168.78.152:2379 endpoint status
五、Kubernetes 组件部署
5.1 Kubernetes 软件包下载
k8s 各版本软件包下载官网:kubernetes/CHANGELOG at master · kubernetes/kubernetes · GitHub
找到需要安装的 k8s 版本(本次安装 k8s-v1.25 版本):
点击 Server Binaries:
点击 adm64 版本下载即可:
- # 在线下载安装包
- [root@k8s-master1 ~]# wget https://storage.googleapis.com/kubernetes-release/release/v1.25.6/kubernetes-server-linux-amd64.tar.gz
5.2 Kubernetes 软件包安装
- [root@k8s-master1 ~]# tar -zxvf kubernetes-server-linux-amd64.tar.gz
- [root@k8s-master1 ~]# cd kubernetes/server/bin/
- [root@k8s-master1 bin]# cp kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/
5.3 Kubernetes 软件分发
- [root@k8s-master1 bin]# scp kube-apiserver kube-controller-manager kube-scheduler kubectl k8s-master2:/usr/local/bin/
- [root@k8s-master1 bin]# scp kube-apiserver kube-controller-manager kube-scheduler kubectl k8s-master3:/usr/local/bin/
- [root@k8s-master1 bin]# scp kubelet kube-proxy k8s-master1:/usr/local/bin
- [root@k8s-master1 bin]# scp kubelet kube-proxy k8s-master2:/usr/local/bin
- [root@k8s-master1 bin]# scp kubelet kube-proxy k8s-master3:/usr/local/bin
- [root@k8s-master1 bin]# scp kubelet kube-proxy k8s-node1:/usr/local/bin
- [root@k8s-master1 bin]# scp kubelet kube-proxy k8s-node2:/usr/local/bin
5.4 在集群节点上创建目录(所有节点)
- mkdir -p /etc/kubernetes/
- mkdir -p /etc/kubernetes/ssl
- mkdir -p /var/log/kubernetes
5.5 部署 api-server
apiserver:提供 k8s api,是整个系统的对外接口,提供资源操作的唯一入口,供客户端和其它组件调用,提供了 k8s 各类资源对象(pod、deployment、Service 等)的增删改查,是整个系统的数据总线和数据中心,并提供认证、授权、访问控制、API 注册和发现等机制,并将操作对象持久化到 etcd 中。相当于“营业厅”。
5.5.1 创建 apiserver 证书请求文件
- [root@k8s-master1 work]# pwd
- /data/work
- [root@k8s-master1 work]# cat > kube-apiserver-csr.json << "EOF"
- {
- "CN": "kubernetes",
- "hosts": [
- "127.0.0.1",
- "192.168.78.150",
- "192.168.78.151",
- "192.168.78.152",
- "192.168.78.153",
- "192.168.78.154",
- "192.168.78.155",
- "192.168.78.156",
- "192.168.78.157",
- "10.255.0.1",
- "kubernetes",
- "kubernetes.default",
- "kubernetes.default.svc",
- "kubernetes.default.svc.cluster",
- "kubernetes.default.svc.cluster.local"
- ],
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "ST": "Hubei",
- "L": "Wuhan",
- "O": "k8s",
- "OU": "system"
- }
- ]
- }
- EOF
说明:
如果 hosts 字段不为空则需要指定授权使用该证书的 IP(含 VIP) 或域名列表。由于该证书被 kubernetes master 集群使用,需要将节点的 IP 都填上,为了方便后期扩容可以多写几个预留的 IP。同时还需要填写 service 网络的首个 IP(一般是 kube-apiserver 指定的 service-cluster-ip-range 网段的第一个 IP,如 10.255.0.1)。
5.5.2 生成 apiserver 证书及 token 文件
- # 创建 token.csv 文件
- [root@k8s-master1 work]# cat > token.csv << EOF
- $(head -c 16 /dev/urandom | od -An -t x | tr -d ' '),kubelet-bootstrap,10001,"system:kubelet-bootstrap"
- EOF
- [root@k8s-master1 work]# cat token.csv
- 78c75da77de755539a346161f05894b8,kubelet-bootstrap,10001,"system:kubelet-bootstrap"
- # 生成证书
- [root@k8s-master1 work]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-apiserver-csr.json | cfssljson -bare kube-apiserver
说明:
-
启动 TLS Bootstrapping 机制
Master apiserver 启用 TLS 认证后,每个节点的 kubelet 组件都要使用由 apiserver 使用的 CA 签发的有效证书才能与 apiserver 通讯,当 Node 节点很多时,这种客户端证书颁发需要大量工作,同样也会增加集群扩展复杂度。
为了简化流程,Kubernetes引入了TLS bootstraping 机制来自动颁发客户端证书,kubelet 会以一个低权限用户自动向 apiserver 申请证书,kubelet 的证书由 apiserver 动态签署。所以强烈建议在 Node 上使用这种方式,目前主要用于 kubelet,kube-proxy 还是由我们统一颁发一个证书。
Bootstrap 是很多系统中都存在的程序,比如 Linux 的 bootstrap,bootstrap 一般都是作为预先配置在开启或者系统启动的时候加载,这可以用来生成一个指定环境。Kubernetes 的 kubelet 在启动时同样可以加载一个这样的配置文件,这个文件的内容类似如下形式:
- apiVersion: v1
- clusters: null
- contexts:
- - context:
- cluster: kubernetes
- user: kubelet-bootstrap
- name: default
- current-context: default
- kind: Config
- preferences: {}
- users:
- - name: kubelet-bootstrap
- user: {}
1.TLS 作用
TLS 的作用就是对通讯加密,防止中间人窃听;同时如果证书不信任的话根本就无法与 apiserver 建立连接,更不用提有没有权限向 apiserver 请求指定内容。
2. RBAC 作用
当 TLS 解决了通讯问题后,那么权限问题就应由 RBAC 解决(可以使用其他权限模型,如 ABAC);RBAC 中规定了一个用户或者用户组(subject)具有请求哪些 api 的权限;在配合 TLS 加密的时候,实际上 apiserver 读取客户端证书的 CN 字段作为用户名,读取 O 字段作为用户组。
以上说明:第一,想要与 apiserver 通讯就必须采用由 apiserver CA 签发的证书,这样才能形成信任关系,建立 TLS 连接;第二,可以通过证书的 CN、O 字段来提供 RBAC 所需的用户与用户组。
-
kubelet 首次启动流程
TLS bootstrapping 功能是让 kubelet 组件去 apiserver 申请证书,然后用于连接 apiserver;那么第一次启动时没有证书如何连接 apiserver ?
在 apiserver 配置中指定了一个 token.csv 文件,该文件中是一个预设的用户配置;同时该用户的 Token 和由 apiserver 的 CA 签发的用户被写入了 kubelet 所使用的 bootstrap.kubeconfig 配置文件中;这样在首次请求时,kubelet 使用 bootstrap.kubeconfig 中被 apiserver CA 签发证书时信任的用户来与 apiserver 建立 TLS 通讯,使用 bootstrap.kubeconfig 中的用户 Token 来向apiserver 声明自己的 RBAC 授权身份。
token.csv 格式:
- # 格式:token,用户名,UID,用户组
- 3940fd7fbb391d1b4d861ad17a1f0613,kubelet-bootstrap,10001,"system:kubelet-bootstrap"
首次启动时,可能与遇到 kubelet 报 401 无权访问 apiserver 的错误;这是因为在默认情况下,kubelet 通过 bootstrap.kubeconfig 中的预设用户 Token 声明了自己的身份,然后创建 CSR 请求;但是不要忘记这个用户在我们不处理的情况下他没任何权限的,包括创建 CSR 请求;所以需要创建一个 ClusterRoleBinding,将预设用户 kubelet-bootstrap 与内置的 ClusterRole system:node-bootstrapper 绑定到一起,使其能够发起 CSR 请求。稍后安装 kubelet的时候演示。
5.5.3 创建 apiserver 服务配置文件
kube-apiserver 配置文件官方文档:kube-apiserver | Kubernetes
- [root@k8s-master1 work]# cat > /etc/kubernetes/kube-apiserver.conf << "EOF"
- KUBE_APISERVER_OPTS="--enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
- --anonymous-auth=false \
- --bind-address=192.168.78.150 \
- --secure-port=6443 \
- --advertise-address=192.168.78.150 \
- --authorization-mode=Node,RBAC \
- --runtime-config=api/all=true \
- --enable-bootstrap-token-auth \
- --service-cluster-ip-range=10.255.0.0/16 \
- --token-auth-file=/etc/kubernetes/token.csv \
- --service-node-port-range=30000-32767 \
- --tls-cert-file=/etc/kubernetes/ssl/kube-apiserver.pem \
- --tls-private-key-file=/etc/kubernetes/ssl/kube-apiserver-key.pem \
- --client-ca-file=/etc/kubernetes/ssl/ca.pem \
- --kubelet-client-certificate=/etc/kubernetes/ssl/kube-apiserver.pem \
- --kubelet-client-key=/etc/kubernetes/ssl/kube-apiserver-key.pem \
- --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \
- --service-account-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \
- --service-account-issuer=api \
- --etcd-cafile=/etc/etcd/ssl/ca.pem \
- --etcd-certfile=/etc/etcd/ssl/etcd.pem \
- --etcd-keyfile=/etc/etcd/ssl/etcd-key.pem \
- --etcd-servers=https://192.168.78.150:2379,https://192.168.78.151:2379,https://192.168.78.152:2379 \
- --allow-privileged=true \
- --apiserver-count=3 \
- --audit-log-maxage=30 \
- --audit-log-maxbackup=3 \
- --audit-log-maxsize=100 \
- --audit-log-path=/var/log/kube-apiserver-audit.log \
- --event-ttl=1h \
- --alsologtostderr=true \
- --logtostderr=false \
- --log-dir=/var/log/kubernetes \
- --v=4"
- EOF
说明:
-
--logtostderr:启用日志
-
--v:日志等级
-
--log-dir:日志目录
-
--etcd-servers:etcd 集群地址
-
--bind-address:监听地址
-
--secure-port:https 安全端口
-
--advertise-address:集群通告地址
-
--allow-privileged:启用授权
-
--service-cluster-ip-range:Service 虚拟 IP 地址段
-
--enable-admission-plugins:准入控制模块
-
--authorization-mode:认证授权,启用 RBAC 授权和节点自管理
-
--enable-bootstrap-token-auth:启用 TLS bootstrap 机制
-
--token-auth-file:bootstrap token 文件
-
--service-node-port-range:Service nodeport 类型默认分配端口范围
-
--kubelet-client-xxx:apiserver 访问 kubelet 客户端证书
-
--tls-xxx-file:apiserver https 证书
-
--etcd-xxxfile:连接 Etcd 集群证书
-
-audit-log-xxx:审计日志
5.5.4 创建 apiserver 服务管理配置文件
- [root@k8s-master1 work]# cat > /usr/lib/systemd/system/kube-apiserver.service << "EOF"
- [Unit]
- Description=Kubernetes API Server
- Documentation=https://github.com/kubernetes/kubernetes
- After=etcd.service
- Wants=etcd.service
- [Service]
- EnvironmentFile=-/etc/kubernetes/kube-apiserver.conf
- ExecStart=/usr/local/bin/kube-apiserver $KUBE_APISERVER_OPTS
- Restart=on-failure
- RestartSec=5
- Type=notify
- LimitNOFILE=65536
- [Install]
- WantedBy=multi-user.target
- EOF
5.5.5 同步文件到集群 master 节点
- [root@k8s-master1 work]# cp ca*.pem /etc/kubernetes/ssl/
- [root@k8s-master1 work]# cp kube-apiserver*.pem /etc/kubernetes/ssl/
- [root@k8s-master1 work]# cp token.csv /etc/kubernetes/
- [root@k8s-master1 work]# scp /etc/kubernetes/token.csv k8s-master2:/etc/kubernetes
- [root@k8s-master1 work]# scp /etc/kubernetes/token.csv k8s-master3:/etc/kubernetes
- [root@k8s-master1 work]# scp /etc/kubernetes/ssl/kube-apiserver*.pem k8s-master2:/etc/kubernetes/ssl
- [root@k8s-master1 work]# scp /etc/kubernetes/ssl/kube-apiserver*.pem k8s-master3:/etc/kubernetes/ssl
- [root@k8s-master1 work]# scp /etc/kubernetes/ssl/ca*.pem k8s-master2:/etc/kubernetes/ssl
- [root@k8s-master1 work]# scp /etc/kubernetes/ssl/ca*.pem k8s-master3:/etc/kubernetes/ssl
- [root@k8s-master1 work]# scp /etc/kubernetes/kube-apiserver.conf k8s-master2:/etc/kubernetes/
- [root@k8s-master1 work]# scp /etc/kubernetes/kube-apiserver.conf k8s-master3:/etc/kubernetes/
- [root@k8s-master1 work]# scp /usr/lib/systemd/system/kube-apiserver.service k8s-master2:/usr/lib/systemd/system/
- [root@k8s-master1 work]# scp /usr/lib/systemd/system/kube-apiserver.service k8s-master3:/usr/lib/systemd/system/
注意: master2 和 master3 的配置文件 kube-apiserver.conf 中的 IP 地址需要修改为实际的本机 IP。
- [root@k8s-master2 ~]# vim /etc/kubernetes/kube-apiserver.conf
- KUBE_APISERVER_OPTS="--enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
- --anonymous-auth=false \
- --bind-address=192.168.78.151 \ # 修改此处
- --secure-port=6443 \
- --advertise-address=192.168.78.151 \ # 修改此处
- --authorization-mode=Node,RBAC \
- --runtime-config=api/all=true \
- --enable-bootstrap-token-auth \
- --service-cluster-ip-range=10.255.0.0/16 \
- --token-auth-file=/etc/kubernetes/token.csv \
- --service-node-port-range=30000-32767 \
- --tls-cert-file=/etc/kubernetes/ssl/kube-apiserver.pem \
- --tls-private-key-file=/etc/kubernetes/ssl/kube-apiserver-key.pem \
- --client-ca-file=/etc/kubernetes/ssl/ca.pem \
- --kubelet-client-certificate=/etc/kubernetes/ssl/kube-apiserver.pem \
- --kubelet-client-key=/etc/kubernetes/ssl/kube-apiserver-key.pem \
- --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \
- --service-account-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \
- --service-account-issuer=api \
- --etcd-cafile=/etc/etcd/ssl/ca.pem \
- --etcd-certfile=/etc/etcd/ssl/etcd.pem \
- --etcd-keyfile=/etc/etcd/ssl/etcd-key.pem \
- --etcd-servers=https://192.168.78.150:2379,https://192.168.78.151:2379,https://192.168.78.152:2379 \
- --allow-privileged=true \
- --apiserver-count=3 \
- --audit-log-maxage=30 \
- --audit-log-maxbackup=3 \
- --audit-log-maxsize=100 \
- --audit-log-path=/var/log/kube-apiserver-audit.log \
- --event-ttl=1h \
- --alsologtostderr=true \
- --logtostderr=false \
- --log-dir=/var/log/kubernetes \
- --v=4"
- [root@k8s-master3 ~]# vim /etc/kubernetes/kube-apiserver.conf
- KUBE_APISERVER_OPTS="--enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
- --anonymous-auth=false \
- --bind-address=192.168.78.152 \ # 修改此处
- --secure-port=6443 \
- --advertise-address=192.168.78.152 \ # 修改此处
- --authorization-mode=Node,RBAC \
- --runtime-config=api/all=true \
- --enable-bootstrap-token-auth \
- --service-cluster-ip-range=10.255.0.0/16 \
- --token-auth-file=/etc/kubernetes/token.csv \
- --service-node-port-range=30000-32767 \
- --tls-cert-file=/etc/kubernetes/ssl/kube-apiserver.pem \
- --tls-private-key-file=/etc/kubernetes/ssl/kube-apiserver-key.pem \
- --client-ca-file=/etc/kubernetes/ssl/ca.pem \
- --kubelet-client-certificate=/etc/kubernetes/ssl/kube-apiserver.pem \
- --kubelet-client-key=/etc/kubernetes/ssl/kube-apiserver-key.pem \
- --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \
- --service-account-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \
- --service-account-issuer=api \
- --etcd-cafile=/etc/etcd/ssl/ca.pem \
- --etcd-certfile=/etc/etcd/ssl/etcd.pem \
- --etcd-keyfile=/etc/etcd/ssl/etcd-key.pem \
- --etcd-servers=https://192.168.78.150:2379,https://192.168.78.151:2379,https://192.168.78.152:2379 \
- --allow-privileged=true \
- --apiserver-count=3 \
- --audit-log-maxage=30 \
- --audit-log-maxbackup=3 \
- --audit-log-maxsize=100 \
- --audit-log-path=/var/log/kube-apiserver-audit.log \
- --event-ttl=1h \
- --alsologtostderr=true \
- --logtostderr=false \
- --log-dir=/var/log/kubernetes \
- --v=4"
5.5.6 启动 apiserver 服务
- systemctl daemon-reload
- systemctl enable --now kube-apiserver
- systemctl status kube-apiserver
- # 测试
- [root@k8s-master1 work]# curl --insecure https://192.168.78.150:6443/
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "Unauthorized",
- "reason": "Unauthorized",
- "code": 401
- }
- [root@k8s-master1 work]# curl --insecure https://192.168.78.151:6443/
- [root@k8s-master1 work]# curl --insecure https://192.168.78.152:6443/
上面看到 401,这个是正常的的状态,只是还没认证。
5.6 部署 kubectl
Kubectl 是客户端工具,操作 k8s 资源的,如增删改查等。Kubectl 操作资源的时候,怎么知道连接到哪个集群呢?这时需要一个文件 /etc/kubernetes/admin.conf,kubectl 会根据这个文件的配置,去访问 k8s 资源。/etc/kubernetes/admin.con 文件记录了访问的 k8s 集群和用到的证书。
5.6.1 创建 kubectl 证书请求文件
- [root@k8s-master1 work]# cat > admin-csr.json << "EOF"
- {
- "CN": "admin",
- "hosts": [],
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "ST": "Hubei",
- "L": "Wuhan",
- "O": "system:masters",
- "OU": "system"
- }
- ]
- }
- EOF
说明:后续 kube-apiserver 使用 RBAC 对客户端(如 kubelet、kube-proxy、Pod)请求进行授权;kube-apiserver 预定义了一些 RBAC 使用的 RoleBindings,如 cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,该 Role 授予了调用 kube-apiserver 的所有 API 的权限;O 指定该证书的 Group 为 system:masters,kubelet 使用该证书访问 kube-apiserver 时 ,由于证书被 CA 签名,所以认证通过,同时由于证书用户组为经过预授权的 system:masters,所以被授予访问所有 API 的权限。
注: 这个 admin 证书,是将来生成管理员用的 kube config 配置文件用的,现在我们一般建议使用 RBAC 来对 kubernetes 进行角色权限控制, kubernetes 将证书中的 CN 字段 作为 User, O 字段作为 Group; "O": "system:masters", 必须是 system:masters,否则后面 kubectl create clusterrolebinding 报错。
证书 O 配置为 system:masters 在集群内部 cluster-admin 的 clusterrolebinding 将 system:masters 组和 cluster-admin clusterrole 绑定在一起。
5.6.2 生成证书文件
[root@k8s-master1 work]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
5.6.3 复制文件到指定目录
[root@k8s-master1 work]# cp admin*.pem /etc/kubernetes/ssl/
5.6.4 生成 kubeconfig 配置文件
kubeconfig 为 kubectl 的配置文件,包含访问 apiserver 的所有信息,如 apiserver 地址、CA 证书和自身使用的证书(这里如果报错找不到 kubeconfig 路径,请手动复制到相应路径下,没有则忽略)。
- # 设置集群参数
- [root@k8s-master1 work]# kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.78.150:6443 --kubeconfig=kube.config
- # 设置客户端认证参数
- [root@k8s-master1 work]# kubectl config set-credentials admin --client-certificate=admin.pem --client-key=admin-key.pem --embed-certs=true --kubeconfig=kube.config
- # 设置上下文参数
- [root@k8s-master1 work]# kubectl config set-context kubernetes --cluster=kubernetes --user=admin --kubeconfig=kube.config
- # 设置当前上下文
- [root@k8s-master1 work]# kubectl config use-context kubernetes --kubeconfig=kube.config
5.6.5 准备 kubectl 配置文件并进行角色绑定
- [root@k8s-master1 work]# mkdir ~/.kube
- [root@k8s-master1 work]# cp kube.config ~/.kube/config
- # 授权 kubernetes 证书访问 kubelet api 权限
- [root@k8s-master1 work]# kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes --kubeconfig=/root/.kube/config
5.6.6 查看集群状态
- # 查看集群信息
- [root@k8s-master1 ~]# kubectl cluster-info
- Kubernetes control plane is running at https://192.168.78.150:6443
- To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
- # 查看集群组件状态
- [root@k8s-master1 ~]# kubectl get componentstatuses
- Warning: v1 ComponentStatus is deprecated in v1.19+
- NAME STATUS MESSAGE ERROR
- scheduler Unhealthy Get "https://127.0.0.1:10259/healthz": dial tcp 127.0.0.1:10259: connect: connection refused
- controller-manager Unhealthy Get "https://127.0.0.1:10257/healthz": dial tcp 127.0.0.1:10257: connect: connection refused
- etcd-0 Healthy {"health":"true","reason":""}
- etcd-1 Healthy {"health":"true","reason":""}
- etcd-2 Healthy {"health":"true","reason":""}
- # 查看命名空间中资源对象
- [root@k8s-master1 ~]# kubectl get all --all-namespaces
- NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- default service/kubernetes ClusterIP 10.255.0.1 <none> 443/TCP 16h
5.6.7 同步 kubectl 配置文件到集群其它 master 节点
- [root@k8s-master2 ~]# mkdir /root/.kube
- [root@k8s-master3 ~]# mkdir /root/.kube
- [root@k8s-master1 ~]# scp /root/.kube/config k8s-master2:/root/.kube/
- [root@k8s-master1 ~]# scp /root/.kube/config k8s-master3:/root/.kube/
5.6.8 配置 kubectl 命令补全(可选)
Kubectl 自动补全官方文档:kubectl 备忘单 | Kubernetes
- # 注意:在三个 master 节点上执行
- # 在 bash 中设置当前 shell 的自动补全,要先安装 bash-completion 包
- yum install -y bash-completion
- source /usr/share/bash-completion/bash_completion
- # 在你的 bash shell 中永久地添加自动补全
- source <(kubectl completion bash)
- echo "source <(kubectl completion bash)" >> ~/.bashrc
5.7 部署 kube-controller-manager
controller-manager:作为集群内部的管理控制中心,负责集群内的 Node、Pod 副本、服务端点(Endpoint)、命名室间(Namespace)、服务账号(ServiceAccount)、资源定额(ResourceQuota) 的管理,当某个 Node 意外宕机时,Controller Manager 会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。与 apiserver 交互,实时监控和维护 k8s 集群的控制器的健康情况,对有故障的进行处理和恢复,相当于“大总管”。
5.7.1 创建 kube-controller-manager 证书请求文件
- [root@k8s-master1 work]# pwd
- /data/work
- [root@k8s-master1 work]# cat > kube-controller-manager-csr.json << "EOF"
- {
- "CN": "system:kube-controller-manager",
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "hosts": [
- "127.0.0.1",
- "192.168.78.150",
- "192.168.78.151",
- "192.168.78.152",
- "192.168.78.155"
- ],
- "names": [
- {
- "C": "CN",
- "ST": "HuBei",
- "L": "Wuhan",
- "O": "system:kube-controller-manager",
- "OU": "system"
- }
- ]
- }
- EOF
说明:
-
hosts 列表包含所有 kube-controller-manager 节点 IP;
-
CN 为 system:kube-controller-manager;
-
O 为 system:kube-controller-manager,kubernetes 内置的 ClusterRoleBindings system:kube-controller-manager 赋予 kube-controller-manager 工作所需的权限。
5.7.2 创建 kube-controller-manager 证书文件
[root@k8s-master1 work]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
5.7.3 创建 kube-controller-manager 的 kube-controller-manager.kubeconfig
- # 设置集群参数
- [root@k8s-master1 work]# kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.78.150:6443 --kubeconfig=kube-controller-manager.kubeconfig
- # 设置客户端认证参数
- [root@k8s-master1 work]# kubectl config set-credentials system:kube-controller-manager --client-certificate=kube-controller-manager.pem --client-key=kube-controller-manager-key.pem --embed-certs=true --kubeconfig=kube-controller-manager.kubeconfig
- # 设置上下文参数
- [root@k8s-master1 work]# kubectl config set-context system:kube-controller-manager --cluster=kubernetes --user=system:kube-controller-manager --kubeconfig=kube-controller-manager.kubeconfig
- # 设置当前上下文
- [root@k8s-master1 work]# kubectl config use-context system:kube-controller-manager --kubeconfig=kube-controller-manager.kubeconfig
5.7.4 创建 kube-controller-manager 配置文件
kube-controller-manager 配置文件官方文档:kube-controller-manager | Kubernetes
- [root@k8s-master1 work]# cat > kube-controller-manager.conf << "EOF"
- KUBE_CONTROLLER_MANAGER_OPTS=" \
- --secure-port=10257 \
- --bind-address=127.0.0.1 \
- --kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \
- --service-cluster-ip-range=10.255.0.0/16 \
- --cluster-name=kubernetes \
- --cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem \
- --cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \
- --allocate-node-cidrs=true \
- --cluster-cidr=10.0.0.0/16 \
- --root-ca-file=/etc/kubernetes/ssl/ca.pem \
- --service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem \
- --leader-elect=true \
- --feature-gates=RotateKubeletServerCertificate=true \
- --controllers=*,bootstrapsigner,tokencleaner \
- --horizontal-pod-autoscaler-sync-period=10s \
- --tls-cert-file=/etc/kubernetes/ssl/kube-controller-manager.pem \
- --tls-private-key-file=/etc/kubernetes/ssl/kube-controller-manager-key.pem \
- --use-service-account-credentials=true \
- --alsologtostderr=true \
- --logtostderr=false \
- --log-dir=/var/log/kubernetes \
- --v=2"
- EOF
- –secure-port=10257、–bind-address=127.0.0.1: 在本地网络接口监听 10257 端口的 https /metrics 请求;
- –kubeconfig:指定 kubeconfig 文件路径,kube-controller-manager 使用它连接和验证 kube-apiserver;
- –authentication-kubeconfig 和 --authorization-kubeconfig:kube-controller-manager 使用它连接 apiserver,对 client 的请求进行认证和授权。kube-controller-manager 不再使用 --tls-ca-file 对请求 https metrics 的 Client 证书进行校验。如果没有配置这两个 kubeconfig 参数,则 client 连接 kube-controller-manager https 端口的请求会被拒绝(提示权限不足)。
- –cluster-signing-*-file:签名 TLS Bootstrap 创建的证书;
- –experimental-cluster-signing-duration:指定 TLS Bootstrap 证书的有效期;
- –root-ca-file:放置到容器 ServiceAccount 中的 CA 证书,用来对 kube-apiserver 的证书进行校验;
- –service-account-private-key-file:签名 ServiceAccount 中 Token 的私钥文件,必须和 kube-apiserver 的 --service-account-key-file 指定的公钥文件配对使用;
- –service-cluster-ip-range :指定 Service Cluster IP 网段,必须和 kube-apiserver 中的同名参数一致;
- –leader-elect=true:集群运行模式,启用选举功能;被选为 leader 的节点负责处理工作,其它节点为阻塞状态;
- –controllers=*,bootstrapsigner,tokencleaner:启用的控制器列表,tokencleaner 用于自动清理过期的 Bootstrap token;
- –horizontal-pod-autoscaler-*:custom metrics 相关参数,支持 autoscaling/v2alpha1;
- –tls-cert-file、–tls-private-key-file:使用 https 输出 metrics 时使用的 Server 证书和秘钥;
- –use-service-account-credentials=true: kube-controller-manager 中各 controller 使用 serviceaccount 访问 kube-apiserver。
5.7.5 创建服务启动文件
- [root@k8s-master1 work]# cat > /usr/lib/systemd/system/kube-controller-manager.service << "EOF"
- [Unit]
- Description=Kubernetes Controller Manager
- Documentation=https://github.com/kubernetes/kubernetes
- [Service]
- EnvironmentFile=-/etc/kubernetes/kube-controller-manager.conf
- ExecStart=/usr/local/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_OPTS
- Restart=on-failure
- RestartSec=5
- [Install]
- WantedBy=multi-user.target
- EOF
5.7.6 同步文件到集群 master 节点
- [root@k8s-master1 work]# cp kube-controller-manager*.pem /etc/kubernetes/ssl/
- [root@k8s-master1 work]# cp kube-controller-manager.kubeconfig /etc/kubernetes/
- [root@k8s-master1 work]# cp kube-controller-manager.conf /etc/kubernetes/
- [root@k8s-master1 work]# scp kube-controller-manager*.pem k8s-master2:/etc/kubernetes/ssl/
- [root@k8s-master1 work]# scp kube-controller-manager*.pem k8s-master3:/etc/kubernetes/ssl/
- [root@k8s-master1 work]# scp kube-controller-manager.kubeconfig kube-controller-manager.conf k8s-master2:/etc/kubernetes/
- [root@k8s-master1 work]# scp kube-controller-manager.kubeconfig kube-controller-manager.conf k8s-master3:/etc/kubernetes/
- [root@k8s-master1 work]# scp /usr/lib/systemd/system/kube-controller-manager.service k8s-master2:/usr/lib/systemd/system/
- [root@k8s-master1 work]# scp /usr/lib/systemd/system/kube-controller-manager.service k8s-master3:/usr/lib/systemd/system/
5.7.7 启动服务(在三个 master 执行)
- systemctl daemon-reload
- systemctl enable --now kube-controller-manager
- systemctl status kube-controller-manager
- [root@k8s-master1 work]# kubectl get componentstatuses
- Warning: v1 ComponentStatus is deprecated in v1.19+
- NAME STATUS MESSAGE ERROR
- scheduler Unhealthy Get "https://127.0.0.1:10259/healthz": dial tcp 127.0.0.1:10259: connect: connection refused
- etcd-0 Healthy {"health":"true","reason":""}
- etcd-2 Healthy {"health":"true","reason":""}
- controller-manager Healthy ok
- etcd-1 Healthy {"health":"true","reason":""}
5.8 部署 kube-scheduler
scheduler:负责 k8s 集群中 pod 调度 , scheduler 通过与 apiserver 交互监听到创建 Pod 副本的信息后,它会检索所有符合该 Pod 要求的工作节点列表,开始执行 Pod 调度逻辑。调度成功后将 Pod 绑定到目标节点上,相当于“调度室”。
5.8.1 创建 kube-scheduler 证书请求文件
- [root@k8s-master1 work]# cat > kube-scheduler-csr.json << "EOF"
- {
- "CN": "system:kube-scheduler",
- "hosts": [
- "127.0.0.1",
- "192.168.78.150",
- "192.168.78.151",
- "192.168.78.152",
- "192.168.78.155"
- ],
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "ST": "Hubei",
- "L": "Wuhan",
- "O": "system:kube-scheduler",
- "OU": "system"
- }
- ]
- }
- EOF
注:
-
hosts 列表包含所有 kube-scheduler 节点 IP 和 VIP;
-
CN 为 system:kube-scheduler;
-
O 为 system:kube-scheduler,kubernetes 内置的 ClusterRoleBindings system:kube-scheduler 将赋予 kube-scheduler 工作所需的权限。
5.8.2 生成 kube-scheduler 证书
[root@k8s-master1 work]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler
5.8.3 创建 kube-scheduler 的 kubeconfig
- # 设置集群参数
- [root@k8s-master1 work]# kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.78.150:6443 --kubeconfig=kube-scheduler.kubeconfig
- # 设置客户端认证参数
- [root@k8s-master1 work]# kubectl config set-credentials system:kube-scheduler --client-certificate=kube-scheduler.pem --client-key=kube-scheduler-key.pem --embed-certs=true --kubeconfig=kube-scheduler.kubeconfig
- # 设置上下文参数
- [root@k8s-master1 work]# kubectl config set-context system:kube-scheduler --cluster=kubernetes --user=system:kube-scheduler --kubeconfig=kube-scheduler.kubeconfig
- # 设置当前上下文
- [root@k8s-master1 work]# kubectl config use-context system:kube-scheduler --kubeconfig=kube-scheduler.kubeconfig
5.8.4 创建服务配置文件
kube-scheduler 配置文件官方文档:kube-scheduler | Kubernetes
- [root@k8s-master1 work]# cat > kube-scheduler.conf << "EOF"
- KUBE_SCHEDULER_OPTS=" \
- --kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \
- --leader-elect=true \
- --alsologtostderr=true \
- --logtostderr=false \
- --log-dir=/var/log/kubernetes \
- --v=2"
- EOF
5.8.5 创建服务启动配置文件
- [root@k8s-master1 work]# cat > /usr/lib/systemd/system/kube-scheduler.service << "EOF"
- [Unit]
- Description=Kubernetes Scheduler
- Documentation=https://github.com/kubernetes/kubernetes
- [Service]
- EnvironmentFile=-/etc/kubernetes/kube-scheduler.conf
- ExecStart=/usr/local/bin/kube-scheduler $KUBE_SCHEDULER_OPTS
- Restart=on-failure
- RestartSec=5
- [Install]
- WantedBy=multi-user.target
- EOF
5.8.6 同步文件至集群 master 节点
- [root@k8s-master1 work]# cp kube-scheduler*.pem /etc/kubernetes/ssl/
- [root@k8s-master1 work]# cp kube-scheduler.kubeconfig /etc/kubernetes/
- [root@k8s-master1 work]# cp kube-scheduler.conf /etc/kubernetes/
- [root@k8s-master1 work]# scp kube-scheduler*.pem k8s-master2:/etc/kubernetes/ssl/
- [root@k8s-master1 work]# scp kube-scheduler*.pem k8s-master3:/etc/kubernetes/ssl/
- [root@k8s-master1 work]# scp kube-scheduler.kubeconfig kube-scheduler.conf k8s-master2:/etc/kubernetes/
- [root@k8s-master1 work]# scp kube-scheduler.kubeconfig kube-scheduler.conf k8s-master3:/etc/kubernetes/
- [root@k8s-master1 work]# scp /usr/lib/systemd/system/kube-scheduler.service k8s-master2:/usr/lib/systemd/system/
- [root@k8s-master1 work]# scp /usr/lib/systemd/system/kube-scheduler.service k8s-master3:/usr/lib/systemd/system/
5.8.7 启动服务
- systemctl daemon-reload
- systemctl enable --now kube-scheduler
- systemctl status kube-scheduler
- [root@k8s-master1 work]# kubectl get componentstatuses
- Warning: v1 ComponentStatus is deprecated in v1.19+
- NAME STATUS MESSAGE ERROR
- scheduler Healthy ok
- controller-manager Healthy ok
- etcd-0 Healthy {"health":"true","reason":""}
- etcd-2 Healthy {"health":"true","reason":""}
- etcd-1 Healthy {"health":"true","reason":""}
六、工作节点(worker node)部署
6.1 部署 kubelet(在 k8s-master1 上操作)
kubelet:每个 Node 节点上的 kubelet 定期就会调用 API Server 的 REST 接口报告自身状态,API Server 接收这些信息后,将节点状态信息更新到 etcd 中。kubelet 也通过 API Server 监听 Pod 信息,从而对 Node 机器上的 POD 进行管理,如创建、删除、更新 Pod。
6.1.1 创建 kubelet-bootstrap.kubeconfig
- [root@k8s-master1 work]# BOOTSTRAP_TOKEN=$(awk -F "," '{print $1}' /etc/kubernetes/token.csv)
- [root@k8s-master1 work]# kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.78.150:6443 --kubeconfig=kubelet-bootstrap.kubeconfig
- [root@k8s-master1 work]# kubectl config set-credentials kubelet-bootstrap --token=${BOOTSTRAP_TOKEN} --kubeconfig=kubelet-bootstrap.kubeconfig
- [root@k8s-master1 work]# kubectl config set-context default --cluster=kubernetes --user=kubelet-bootstrap --kubeconfig=kubelet-bootstrap.kubeconfig
- [root@k8s-master1 work]# kubectl config use-context default --kubeconfig=kubelet-bootstrap.kubeconfig
- # 添加权限
- [root@k8s-master1 work]# kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap
6.2.2 创建 kubelet 配置文件
- # "cgroupDriver": "systemd" 要和 docker 的驱动一致。address 替换为自己 master1 的 IP 地址。
- [root@k8s-master1 work]# cat > kubelet.json << "EOF"
- {
- "kind": "KubeletConfiguration",
- "apiVersion": "kubelet.config.k8s.io/v1beta1",
- "authentication": {
- "x509": {
- "clientCAFile": "/etc/kubernetes/ssl/ca.pem"
- },
- "webhook": {
- "enabled": true,
- "cacheTTL": "2m0s"
- },
- "anonymous": {
- "enabled": false
- }
- },
- "authorization": {
- "mode": "Webhook",
- "webhook": {
- "cacheAuthorizedTTL": "5m0s",
- "cacheUnauthorizedTTL": "30s"
- }
- },
- "address": "192.168.78.150",
- "port": 10250,
- "readOnlyPort": 10255,
- "cgroupDriver": "systemd",
- "hairpinMode": "promiscuous-bridge",
- "serializeImagePulls": false,
- "clusterDomain": "cluster.local.",
- "clusterDNS": ["10.255.0.2"]
- }
- EOF
6.1.3 创建 kubelet 服务启动管理文件
kubelet 配置官方文档:kubelet | Kubernetes
- [root@k8s-master1 work]# cat > /usr/lib/systemd/system/kubelet.service << "EOF"
- [Unit]
- Description=Kubernetes Kubelet
- Documentation=https://github.com/kubernetes/kubernetes
- After=docker.service
- Requires=docker.service
- [Service]
- WorkingDirectory=/var/lib/kubelet
- ExecStart=/usr/local/bin/kubelet \
- --bootstrap-kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig \
- --cert-dir=/etc/kubernetes/ssl \
- --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \
- --config=/etc/kubernetes/kubelet.json \
- --container-runtime-endpoint=unix:///run/containerd/containerd.sock \
- --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.2 \
- --alsologtostderr=true \
- --logtostderr=false \
- --log-dir=/var/log/kubernetes \
- --v=2
- Restart=on-failure
- RestartSec=5
- [Install]
- WantedBy=multi-user.target
- EOF
注:
-
–network-plugin:启用 CNI
-
–kubeconfig:用于连接 apiserver
-
–bootstrap-kubeconfig:首次启动向 apiserver 申请证书
-
–config:配置参数文件
-
–cert-dir:kubelet 证书生成目录
-
–pod-infra-container-image:管理 Pod 网络容器的镜像地址
6.1.4 同步文件到集群节点
如果不想 master 节点也安装 kubelet 组件,可以只给 node 节点传送文件,只在 node 节点安装也可。
- [root@k8s-master1 work]# cp kubelet-bootstrap.kubeconfig kubelet.json /etc/kubernetes/
- [root@k8s-master1 work]# for i in k8s-master2 k8s-master3 k8s-node1 k8s-node2;do scp /etc/kubernetes/kubelet-bootstrap.kubeconfig /etc/kubernetes/kubelet.json $i:/etc/kubernetes/;done
- [root@k8s-master1 work]# for i in k8s-master2 k8s-master3 k8s-node1 k8s-node2;do scp ca.pem $i:/etc/kubernetes/ssl/;done
- [root@k8s-master1 work]# for i in k8s-master2 k8s-master3 k8s-node1 k8s-node2;do scp /usr/lib/systemd/system/kubelet.service $i:/usr/lib/systemd/system/;done
注意:传送后到各个节点后的 kubelet.json 中 address 需要自己去手动修改为当前主机 IP 地址。
6.1.5 创建目录及启动服务(所有节点执行)
- mkdir -p /var/lib/kubelet
- systemctl daemon-reload
- systemctl enable --now kubelet
- systemctl status kubelet
6.1.6 验证集群状态
可以看到一个各节点发送了 CSR 请求,如果状态是 Pending,则需要 Approve 一下 bootstrap 请求:
- [root@k8s-master1 work]# kubectl get csr
- NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
- node-csr-ELAsquFkboi3FVWEvtjHcYPhZkroHFZvtw0HSfmQcU8 22s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap <none> Pending
- node-csr-IHAdsHaotk8Z3_tW7rYvSmeKGdXqbPB0m98YdwfBs9Y 22s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap <none> Pending
- node-csr-RH7808N9oudntus38bSsUuhw5xxInRlSyzBtLPQzlf8 22s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap <none> Pending
- node-csr-X9GbXTxND15dH5bH1Fe-Qq9XMdl084qlHo8YpNeW5fw 22s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap <none> Pending
- node-csr-Z0KsK-FCseOEi1UfrCIkzC-HtxBijchx0tnS4eIpq8g 22s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap <none> Pending
- # approve 方法:
- [root@k8s-master1 work]# kubectl certificate approve node-csr-ELAsquFkboi3FVWEvtjHcYPhZkroHFZvtw0HSfmQcU8
- [root@k8s-master1 work]# kubectl certificate approve node-csr-IHAdsHaotk8Z3_tW7rYvSmeKGdXqbPB0m98YdwfBs9Y
- [root@k8s-master1 work]# kubectl certificate approve node-csr-RH7808N9oudntus38bSsUuhw5xxInRlSyzBtLPQzlf8
- [root@k8s-master1 work]# kubectl certificate approve node-csr-X9GbXTxND15dH5bH1Fe-Qq9XMdl084qlHo8YpNeW5fw
- [root@k8s-master1 work]# kubectl certificate approve node-csr-Z0KsK-FCseOEi1UfrCIkzC-HtxBijchx0tnS4eIpq8g
- # 再次查看状态是否变为 Approved,Issued
- [root@k8s-master1 work]# kubectl get csr
- [root@k8s-master1 work]# kubectl get nodes
- NAME STATUS ROLES AGE VERSION
- k8s-master1 NotReady <none> 94s v1.25.6
- k8s-master2 NotReady <none> 72s v1.25.6
- k8s-master3 NotReady <none> 84s v1.25.6
- k8s-node1 NotReady <none> 2m4s v1.25.6
- k8s-node2 NotReady <none> 61s v1.25.6
注意:STATUS 是 NotReady 表示还没有安装网络插件。
6.2 部署 kube-proxy
kube-proxy:提供网络代理和负载均衡,是实现 service 的通信与负载均衡机制的重要组件,kube-proxy 负责为 Pod 创建代理服务,从 apiserver 获取所有 service 信息,并根据 service 信息创建代理服务,实现 service 到 Pod 的请求路由和转发,从而实现 K8s 层级的虚拟转发网络,将到 service 的请求转发到后端的 pod 上。
6.2.1 创建 kube-proxy 证书请求文件
- [root@k8s-master1 work]# cat > kube-proxy-csr.json << "EOF"
- {
- "CN": "system:kube-proxy",
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "ST": "Hubei",
- "L": "Wuhan",
- "O": "k8s",
- "OU": "system"
- }
- ]
- }
- EOF
6.2.2 生成证书
[root@k8s-master1 work]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
6.2.3 创建 kubeconfig 文件
- [root@k8s-master1 work]# kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.78.150:6443 --kubeconfig=kube-proxy.kubeconfig
- [root@k8s-master1 work]# kubectl config set-credentials kube-proxy --client-certificate=kube-proxy.pem --client-key=kube-proxy-key.pem --embed-certs=true --kubeconfig=kube-proxy.kubeconfig
- [root@k8s-master1 work]# kubectl config set-context default --cluster=kubernetes --user=kube-proxy --kubeconfig=kube-proxy.kubeconfig
- [root@k8s-master1 work]# kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
6.2.4 创建服务配置文件
- [root@k8s-master1 work]# cat > kube-proxy.yaml << "EOF"
- apiVersion: kubeproxy.config.k8s.io/v1alpha1
- bindAddress: 192.168.78.150
- clientConnection:
- kubeconfig: /etc/kubernetes/kube-proxy.kubeconfig
- clusterCIDR: 192.168.78.0/24
- healthzBindAddress: 192.168.78.150:10256
- kind: KubeProxyConfiguration
- metricsBindAddress: 192.168.78.150:10249
- mode: "ipvs"
- EOF
6.2.5 创建服务启动管理文件
- [root@k8s-master1 work]# cat > /usr/lib/systemd/system/kube-proxy.service << "EOF"
- [Unit]
- Description=Kubernetes Kube-Proxy Server
- Documentation=https://github.com/kubernetes/kubernetes
- After=network.target
- [Service]
- WorkingDirectory=/var/lib/kube-proxy
- ExecStart=/usr/local/bin/kube-proxy \
- --config=/etc/kubernetes/kube-proxy.yaml \
- --alsologtostderr=true \
- --logtostderr=false \
- --log-dir=/var/log/kubernetes \
- --v=2
- Restart=on-failure
- RestartSec=5
- LimitNOFILE=65536
- [Install]
- WantedBy=multi-user.target
- EOF
6.2.6 同步文件到集群节点
如果不想 master 节点也安装 kube-proxy 组件,可以只给 node 节点传送文件,只在 node 节点安装也可。
- [root@k8s-master1 work]# cp kube-proxy*.pem /etc/kubernetes/ssl/
- [root@k8s-master1 work]# cp kube-proxy.kubeconfig kube-proxy.yaml /etc/kubernetes/
- [root@k8s-master1 work]# for i in k8s-master2 k8s-master3 k8s-node1 k8s-node2;do scp kube-proxy.kubeconfig kube-proxy.yaml $i:/etc/kubernetes/;done
- [root@k8s-master1 work]# for i in k8s-master2 k8s-master3 k8s-node1 k8s-node2;do scp /usr/lib/systemd/system/kube-proxy.service $i:/usr/lib/systemd/system/;done
注意:传送后需要手动修改 kube-proxy.yaml 中三个 Address IP 地址为当前主机 IP.
6.2.7 服务启动(所有节点)
- mkdir -p /var/lib/kube-proxy
- systemctl daemon-reload
- systemctl enable --now kube-proxy
- systemctl status kube-proxy
6.3 网络组件部署 Calico
Calico 各版本官方文档:System requirements | Calico Documentation
可以通过这里来查看 Calico 所支持的 k8s 版本:
6.3.1 下载 calico.yaml
- [root@k8s-master1 ~]# curl https://raw.githubusercontent.com/projectcalico/calico/v3.24.5/manifests/calico.yaml -O
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
- 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0curl: (7) Failed connect to raw.githubusercontent.com:443; 拒绝连接
我自己的虚机下载不了,所以换了方法:
复制这个连接:https://raw.githubusercontent.com/projectcalico/calico/v3.24.5/manifests/calico.yaml 到浏览器下载,再上传到 master1 即可:
6.3.2 修改 calico.yaml 里的 pod 网段
在命令模式下输入 /192 就可以快速定位到需要修改的地址了,不然慢慢找太麻烦了,文件很长;然后把注释取消掉,把 value 修改成我们的 pod ip 地址即可:
- [root@k8s-master1 ~]# vim calico.yaml
- ······
- # no effect. This should fall within `--cluster-cidr`.
- - name: CALICO_IPV4POOL_CIDR
- value: "10.0.0.0/16"
- # Disable file logging so `kubectl logs` works.
- - name: CALICO_DISABLE_FILE_LOGGING
- value: "true"
- ······
注意:改的时候请看清缩进关系,即这里的对齐关系。
6.3.3 提前下载好所需的镜像(可省略,直接执行下一步)
ctr 是 containerd 自带的工具,有命名空间的概念,若是 k8s 相关的镜像,都默认在 k8s.io 这个命名空间,所以导入镜像时需要指定命令空间为 k8s.io:
- [root@k8s-master1 ~]# grep image calico.yaml
- image: docker.io/calico/cni:v3.24.5
- imagePullPolicy: IfNotPresent
- image: docker.io/calico/cni:v3.24.5
- imagePullPolicy: IfNotPresent
- image: docker.io/calico/node:v3.24.5
- imagePullPolicy: IfNotPresent
- image: docker.io/calico/node:v3.24.5
- imagePullPolicy: IfNotPresent
- image: docker.io/calico/kube-controllers:v3.24.5
- imagePullPolicy: IfNotPresent
- # 在所有节点(包括 master)上把这些镜像下载下来:
- for i in docker.io/calico/cni:v3.24.5 docker.io/calico/node:v3.24.5 docker.io/calico/kube-controllers:v3.24.5 ; do ctr -n=k8s.io images pull $i ; done
6.3.4 安装 calico 网络
[root@k8s-master1 ~]# kubectl apply -f calico.yaml
6.3.5 验证结果
- [root@k8s-master1 work]# kubectl get pods -A
- NAMESPACE NAME READY STATUS RESTARTS AGE
- kube-system calico-kube-controllers-798cc86c47-s8hb2 1/1 Running 0 98s
- kube-system calico-node-7n6hg 1/1 Running 0 98s
- kube-system calico-node-7r6tt 1/1 Running 0 98s
- kube-system calico-node-9sx5w 1/1 Running 0 98s
- kube-system calico-node-fbbjq 1/1 Running 0 98s
- kube-system calico-node-frf6p 1/1 Running 0 98s
- [root@k8s-master1 work]# kubectl get nodes
- NAME STATUS ROLES AGE VERSION
- k8s-master1 Ready <none> 53m v1.25.6
- k8s-master2 Ready <none> 53m v1.25.6
- k8s-master3 Ready <none> 53m v1.25.6
- k8s-node1 Ready <none> 54m v1.25.6
- k8s-node2 Ready <none> 52m v1.25.6
6.4 部署 CoreDNS
6.4.1 下载 coredns.yaml
coredns.yaml 下载官网:kubernetes/cluster/addons/dns/coredns at master · kubernetes/kubernetes · GitHub
- # wget 不下来的手动去复制吧(我就是复制的),wget 下载的文件格式不对
- [root@k8s-master1 work]# wget https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/coredns/coredns.yaml.base
- # 或者复制内容
- [root@k8s-master1 work]# vim coredns.yaml
6.4.2 修改 coredns.yaml
拿到 yaml 文件需要修改几处配置:
- #1. 修改 k8s 集群后缀名称 __DNS__DOMAIN__ 为 cluster.local
- #77 kubernetes __DNS__DOMAIN__ in-addr.arpa ip6.arpa {
- # 修改后:kubernetes cluster.local in-addr.arpa ip6.arpa {
- #2. 修改 coredns 谷歌地址为 dockerhub 地址,容易下载
- #142 image: registry.k8s.io/coredns/coredns:v1.10.0
- # 修改后:image: coredns/coredns:1.10.0
- #3. 修改 pod 启动内存限制大小,300Mi 即可(这步可省略不做,我修改了~)
- #146 memory: __DNS__MEMORY__LIMIT__
- # 修改后:memory: 300Mi
- #4. 修改 coredns 的 svcIP 地址,一般为 svc 网段的第二位(一开始我们规划好的 10.255.0.0),10.255.0.2,第一位为 apiserver 的 svc
- #212 clusterIP: __DNS__SERVER__
- # 修改后:clusterIP: 10.255.0.2
- #5. 修改 coredns 副本数,默认是 1,且默认没有 replicas 字段(这步可省略不做)
- 102 spec:
- 103 # replicas: not specified here:
- 104 # 1. In order to make Addon Manager do not reconcile this replicas parameter.
- 105 # 2. Default is 1.
- 106 # 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
- replicas: 3
- 107 strategy:
完整 coredns.yaml 配置文件如下:
- [root@k8s-master1 work]# cat coredns.yaml
- # __MACHINE_GENERATED_WARNING__
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: coredns
- namespace: kube-system
- labels:
- kubernetes.io/cluster-service: "true"
- addonmanager.kubernetes.io/mode: Reconcile
- ---
- apiVersion: rbac.authorization.k8s.io/v1
- kind: ClusterRole
- metadata:
- labels:
- kubernetes.io/bootstrapping: rbac-defaults
- addonmanager.kubernetes.io/mode: Reconcile
- name: system:coredns
- rules:
- - apiGroups:
- - ""
- resources:
- - endpoints
- - services
- - pods
- - namespaces
- verbs:
- - list
- - watch
- - apiGroups:
- - ""
- resources:
- - nodes
- verbs:
- - get
- - apiGroups:
- - discovery.k8s.io
- resources:
- - endpointslices
- verbs:
- - list
- - watch
- ---
- apiVersion: rbac.authorization.k8s.io/v1
- kind: ClusterRoleBinding
- metadata:
- annotations:
- rbac.authorization.kubernetes.io/autoupdate: "true"
- labels:
- kubernetes.io/bootstrapping: rbac-defaults
- addonmanager.kubernetes.io/mode: EnsureExists
- name: system:coredns
- roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: system:coredns
- subjects:
- - kind: ServiceAccount
- name: coredns
- namespace: kube-system
- ---
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: coredns
- namespace: kube-system
- labels:
- addonmanager.kubernetes.io/mode: EnsureExists
- data:
- Corefile: |
- .:53 {
- errors
- health {
- lameduck 5s
- }
- ready
- kubernetes cluster.local in-addr.arpa ip6.arpa {
- pods insecure
- fallthrough in-addr.arpa ip6.arpa
- ttl 30
- }
- prometheus :9153
- forward . /etc/resolv.conf {
- max_concurrent 1000
- }
- cache 30
- loop
- reload
- loadbalance
- }
- ---
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: coredns
- namespace: kube-system
- labels:
- k8s-app: kube-dns
- kubernetes.io/cluster-service: "true"
- addonmanager.kubernetes.io/mode: Reconcile
- kubernetes.io/name: "CoreDNS"
- spec:
- # replicas: not specified here:
- # 1. In order to make Addon Manager do not reconcile this replicas parameter.
- # 2. Default is 1.
- # 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
- strategy:
- type: RollingUpdate
- rollingUpdate:
- maxUnavailable: 1
- selector:
- matchLabels:
- k8s-app: kube-dns
- template:
- metadata:
- labels:
- k8s-app: kube-dns
- spec:
- securityContext:
- seccompProfile:
- type: RuntimeDefault
- priorityClassName: system-cluster-critical
- serviceAccountName: coredns
- affinity:
- podAntiAffinity:
- preferredDuringSchedulingIgnoredDuringExecution:
- - weight: 100
- podAffinityTerm:
- labelSelector:
- matchExpressions:
- - key: k8s-app
- operator: In
- values: ["kube-dns"]
- topologyKey: kubernetes.io/hostname
- tolerations:
- - key: "CriticalAddonsOnly"
- operator: "Exists"
- nodeSelector:
- kubernetes.io/os: linux
- containers:
- - name: coredns
- image: coredns/coredns:1.10.0
- imagePullPolicy: IfNotPresent
- resources:
- limits:
- memory: 300Mi
- requests:
- cpu: 100m
- memory: 70Mi
- args: [ "-conf", "/etc/coredns/Corefile" ]
- volumeMounts:
- - name: config-volume
- mountPath: /etc/coredns
- readOnly: true
- ports:
- - containerPort: 53
- name: dns
- protocol: UDP
- - containerPort: 53
- name: dns-tcp
- protocol: TCP
- - containerPort: 9153
- name: metrics
- protocol: TCP
- livenessProbe:
- httpGet:
- path: /health
- port: 8080
- scheme: HTTP
- initialDelaySeconds: 60
- timeoutSeconds: 5
- successThreshold: 1
- failureThreshold: 5
- readinessProbe:
- httpGet:
- path: /ready
- port: 8181
- scheme: HTTP
- securityContext:
- allowPrivilegeEscalation: false
- capabilities:
- add:
- - NET_BIND_SERVICE
- drop:
- - all
- readOnlyRootFilesystem: true
- dnsPolicy: Default
- volumes:
- - name: config-volume
- configMap:
- name: coredns
- items:
- - key: Corefile
- path: Corefile
- ---
- apiVersion: v1
- kind: Service
- metadata:
- name: kube-dns
- namespace: kube-system
- annotations:
- prometheus.io/port: "9153"
- prometheus.io/scrape: "true"
- labels:
- k8s-app: kube-dns
- kubernetes.io/cluster-service: "true"
- addonmanager.kubernetes.io/mode: Reconcile
- kubernetes.io/name: "CoreDNS"
- spec:
- selector:
- k8s-app: kube-dns
- clusterIP: 10.255.0.2
- ports:
- - name: dns
- port: 53
- protocol: UDP
- - name: dns-tcp
- port: 53
- protocol: TCP
- - name: metrics
- port: 9153
- protocol: TCP
6.4.3 安装 coredns
- [root@k8s-master1 work]# kubectl apply -f coredns.yaml
- [root@k8s-master1 work]# kubectl get pods -A
- NAMESPACE NAME READY STATUS RESTARTS AGE
- kube-system calico-kube-controllers-798cc86c47-s8hb2 1/1 Running 0 54m
- kube-system calico-node-7n6hg 1/1 Running 0 54m
- kube-system calico-node-7r6tt 1/1 Running 0 54m
- kube-system calico-node-9sx5w 1/1 Running 0 54m
- kube-system calico-node-fbbjq 1/1 Running 0 54m
- kube-system calico-node-frf6p 1/1 Running 0 54m
- kube-system coredns-65bc566d6f-f6qvh 1/1 Running 0 53s
- # 节点⻆⾊名字更改
- [root@k8s-master1 work]# kubectl label nodes k8s-master1 node-role.kubernetes.io/master=master
- [root@k8s-master1 work]# kubectl label nodes k8s-node1 node-role.kubernetes.io/work=work
- node/k8s-node1 labeled
- [root@k8s-master1 work]# kubectl label nodes k8s-node2 node-role.kubernetes.io/work=work
- node/k8s-node2 labeled
- [root@k8s-master1 work]# kubectl get nodes
- NAME STATUS ROLES AGE VERSION
- k8s-master1 Ready master 17h v1.25.6
- k8s-master2 Ready <none> 17h v1.25.6
- k8s-master3 Ready <none> 17h v1.25.6
- k8s-node1 Ready work 17h v1.25.6
- k8s-node2 Ready work 17h v1.25.6
6.4.5 测试 coredns 域名解析功能
- [root@k8s-master1 work]# cat<<EOF | kubectl apply -f -
- apiVersion: v1
- kind: Pod
- metadata:
- name: busybox
- namespace: default
- spec:
- containers:
- - name: busybox
- image: busybox:1.28
- command:
- - sleep
- - "3600"
- imagePullPolicy: IfNotPresent
- restartPolicy: Always
- EOF
- # ⾸先查看 pod 是否安装成功
- [root@k8s-master1 work]# kubectl get pods
- NAME READY STATUS RESTARTS AGE
- busybox 1/1 Running 0 57s
- # 通过下面可以看到能访问网络
- [root@k8s-master1 work]# kubectl exec busybox -it -- sh
- / # ping www.baidu.com
- PING www.baidu.com (182.61.200.6): 56 data bytes
- 64 bytes from 182.61.200.6: seq=0 ttl=127 time=84.916 ms
- 64 bytes from 182.61.200.6: seq=1 ttl=127 time=35.237 ms
- 64 bytes from 182.61.200.6: seq=2 ttl=127 time=43.888 ms
- 64 bytes from 182.61.200.6: seq=3 ttl=127 time=69.534 ms
- 64 bytes from 182.61.200.6: seq=4 ttl=127 time=33.419 ms
- ^C
- --- www.baidu.com ping statistics ---
- 5 packets transmitted, 5 packets received, 0% packet loss
- round-trip min/avg/max = 33.419/53.398/84.916 ms
- # 10.255.0.2 就是我们 coreDNS 的 clusterIP,说明 coreDNS 配置好了。解析内部 Service 的名称,是通过 coreDNS 去解析的:
- / # nslookup kubernetes.default.svc.cluster.local
- Server: 10.255.0.2
- Address 1: 10.255.0.2 kube-dns.kube-system.svc.cluster.local
- Name: kubernetes.default.svc.cluster.local
- Address 1: 10.255.0.1 kubernetes.default.svc.cluster.local
注意:busybox 要用指定的 1.28 版本,不能用最新版本,最新版本,nslookup 会解析不到 dns 和 ip.
七、安装 keepalived+nginx 实现 k8s apiserver 高可用
7.1 keepalived+nginx 高可用介绍
7.1.1 什么是高可用?
高可用 HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。如果一个系统能够一直提供服务,那么这个可用性则是百分之百,但是天有不测风云。所以我们只能尽可能的去减少服务的故障。
7.1.2 解决的问题?
在生产环境上很多时候是以 Nginx 做反向代理对外提供服务,但是一天 Nginx 难免遇见故障,如:服务器宕机。当 Nginx 宕机那么所有对外提供的接口都将导致无法访问。
虽然我们无法保证服务器百分之百可用,但是也得想办法避免这种悲剧,今天我们使用keepalived 来实现 Nginx 的高可用。
7.1.3 双机热备方案
这种方案是国内企业中最为普遍的一种高可用方案,双机热备其实就是指一台服务器在提供服务,另一台为某服务的备用状态,当一台服务器不可用另外一台就会顶替上去。
7.1.4 keepalived 是什么?
Keepalived 软件起初是专为 LVS 负载均衡软件设计的,用来管理并监控 LVS 集群系统中各个服务节点的状态,后来又加入了可以实现高可用的 VRRP (Virtual Router Redundancy Protocol ,虚拟路由器冗余协议)功能。因此,Keepalived 除了能够管理 LVS 软件外,还可以作为其他服务(例如:Nginx、Haproxy、MySQL等)的高可用解决方案软件。
7.1.5 故障转移机制
Keepalived 高可用服务之间的故障切换转移,是通过 VRRP 来实现的。在 Keepalived 服务正常工作时,主 Master 节点会不断地向备节点发送(多播的方式)心跳消息,用以告诉备 Backup 节点自己还活着,当主 Master 节点发生故障时,就无法发送心跳消息,备节点也就因此无法继续检测到来自主 Master 节点的心跳了,于是调用自身的接管程序,接管主 Master 节点的 IP 资源及服务。而当主 Master 节点恢复时,备 Backup 节点又会释放主节点故障时自身接管的 IP资源及服务,恢复到原来的备用角色。
7.2 安装 nginx 与 keeplived(所有 master 节点)
yum install -y nginx keepalived nginx-all-modules.noarch
7.3 nginx 配置(三个 master 节点的 nginx 配置一样)
- cat /etc/nginx/nginx.conf
- user nginx;
- worker_processes auto;
- error_log /var/log/nginx/error.log;
- pid /run/nginx.pid;
- include /usr/share/nginx/modules/*.conf;
- events {
- worker_connections 1024;
- }
- # 四层负载均衡,为三台 Master apiserver 组件提供负载均衡
- stream {
- log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';
- access_log /var/log/nginx/k8s-access.log main;
- upstream k8s-apiserver {
- server 192.168.78.150:6443;
- server 192.168.78.151:6443;
- server 192.168.78.152:6443;
- }
- server {
- listen 16443; # 由于 nginx 与 master 节点复用,这个监听端口不能是 6443,否则会冲突
- proxy_pass k8s-apiserver;
- }
- }
- http {
- log_format main '$remote_addr - $remote_user [$time_local] "$request" '
- '$status $body_bytes_sent "$http_referer" '
- '"$http_user_agent" "$http_x_forwarded_for"';
- access_log /var/log/nginx/access.log main;
- sendfile on;
- tcp_nopush on;
- tcp_nodelay on;
- keepalive_timeout 65;
- types_hash_max_size 4096;
- include /etc/nginx/mime.types;
- default_type application/octet-stream;
- include /etc/nginx/conf.d/*.conf;
- server {
- listen 80;
- listen [::]:80;
- server_name _;
- root /usr/share/nginx/html;
- include /etc/nginx/default.d/*.conf;
- error_page 404 /404.html;
- location = /404.html {
- }
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- }
- }
- }
7.4 配置 KeepAlived(所有 Master 节点)
主从配置不一致,需要注意。
7.4.1 Master1
- [root@k8s-master1 work]# vim /etc/keepalived/keepalived.conf
- global_defs {
- notification_email {
- [email protected]
- [email protected]
- [email protected]
- }
- notification_email_from [email protected]
- smtp_server 127.0.0.1
- smtp_connect_timeout 30
- router_id NGINX_MASTER
- }
- vrrp_script check_nginx {
- script "/etc/keepalived/check_nginx.sh" # 心跳执行的脚本,检测 nginx 是否启动
- interval 2 #(检测脚本执行的间隔,单位是秒)
- weight 2 # 权重
- }
- # vrrp 实例定义部分
- vrrp_instance VI_1 {
- state MASTER # 指定 keepalived 的角色,MASTER 为主,BACKUP 为备
- interface ens32 # 当前进行vrrp通讯的网络接口卡(当前centos的网卡) 用ifconfig查看你具体的网卡
- virtual_router_id 51 # VRRP 路由 ID 实例,每个实例是唯一的,主从要一致
- priority 100 # 优先级,优先级,数值越大,获取处理请求的优先级越高。备服务器设置 90
- advert_int 1 # 指定 VRRP 心跳包通告间隔时间,默认 1 秒
- # 授权访问
- authentication {
- auth_type PASS # 设置验证类型和密码,MASTER 和 BACKUP 必须使用相同的密码才能正常通信
- auth_pass 1111
- }
- # 虚拟 IP
- virtual_ipaddress {
- 192.168.78.155/24 # 定义虚拟 ip(VIP),可多设,每行一个
- }
- track_script {
- check_nginx #(调用检测脚本)
- }
- }
7.4.2 Master2
- [root@k8s-master2 ~]# vim /etc/keepalived/keepalived.conf
- global_defs {
- notification_email {
- [email protected]
- [email protected]
- [email protected]
- }
- notification_email_from [email protected]
- smtp_server 127.0.0.1
- smtp_connect_timeout 30
- router_id NGINX_MASTER
- }
- vrrp_script check_nginx {
- script "/etc/keepalived/check_nginx.sh" # 心跳执行的脚本,检测 nginx 是否启动
- interval 2 #(检测脚本执行的间隔,单位是秒)
- weight 2 # 权重
- }
- # vrrp 实例定义部分
- vrrp_instance VI_1 {
- state BACKUP # 指定 keepalived 的角色,MASTER 为主,BACKUP 为备
- interface ens32 # 当前进行vrrp通讯的网络接口卡(当前centos的网卡) 用ifconfig查看你具体的网卡
- virtual_router_id 51 # VRRP 路由 ID 实例,每个实例是唯一的,主从要一致
- priority 90 # 优先级,优先级,数值越大,获取处理请求的优先级越高。备服务器设置 90
- advert_int 1 # 指定 VRRP 心跳包通告间隔时间,默认 1 秒
- # 授权访问
- authentication {
- auth_type PASS # 设置验证类型和密码,MASTER 和 BACKUP 必须使用相同的密码才能正常通信
- auth_pass 1111
- }
- # 虚拟 IP
- virtual_ipaddress {
- 192.168.78.155/24 # 定义虚拟 ip(VIP),可多设,每行一个
- }
- track_script {
- check_nginx #(调用检测脚本)
- }
- }
7.4.3 Master3
- [root@k8s-master3 ~]# vim /etc/keepalived/keepalived.conf
- global_defs {
- notification_email {
- [email protected]
- [email protected]
- [email protected]
- }
- notification_email_from [email protected]
- smtp_server 127.0.0.1
- smtp_connect_timeout 30
- router_id NGINX_MASTER
- }
- vrrp_script check_nginx {
- script "/etc/keepalived/check_nginx.sh" # 心跳执行的脚本,检测 nginx 是否启动
- interval 2 #(检测脚本执行的间隔,单位是秒)
- weight 2 # 权重
- }
- # vrrp 实例定义部分
- vrrp_instance VI_1 {
- state BACKUP # 指定 keepalived 的角色,MASTER 为主,BACKUP 为备
- interface ens32 # 当前进行vrrp通讯的网络接口卡(当前centos的网卡) 用ifconfig查看你具体的网卡
- virtual_router_id 51 # VRRP 路由 ID 实例,每个实例是唯一的,主从要一致
- priority 90 # 优先级,优先级,数值越大,获取处理请求的优先级越高。备服务器设置 90
- advert_int 1 # 指定 VRRP 心跳包通告间隔时间,默认 1 秒
- # 授权访问
- authentication {
- auth_type PASS # 设置验证类型和密码,MASTER 和 BACKUP 必须使用相同的密码才能正常通信
- auth_pass 1111
- }
- # 虚拟 IP
- virtual_ipaddress {
- 192.168.78.155/24 # 定义虚拟 ip(VIP),可多设,每行一个
- }
- track_script {
- check_nginx #(调用检测脚本)
- }
- }
7.5 健康检查脚本(三个 master 执行)
- vim /etc/keepalived/check_nginx.sh
- #!/bin/bash
- #1、判断 Nginx 是否存活
- counter=`ps -C nginx --no-header | wc -l`
- if [ $counter -eq 0 ]; then
- #2、如果不存活则尝试启动 Nginx
- systemctl start nginx
- sleep 2
- #3、等待 2 秒后再次获取一次 Nginx 状态
- counter=`ps -C nginx --no-header | wc -l`
- #4、再次进行判断,如 Nginx 还不存活则停止 Keepalived,让地址进行漂移
- if [ $counter -eq 0 ]; then
- systemctl stop keepalived
- fi
- fi
- # 授权
- chmod +x /etc/keepalived/check_nginx.sh
7.6 启动 nginx 和 keepalived(所有 master 节点)
- systemctl daemon-reload
- systemctl enable --now nginx
- systemctl enable --now keepalived
7.7 查看 vip 是否绑定成功
- # 看到有 VIP 绑定到 ens32 ⽹卡上了
- [root@k8s-master1 work]# ip a | grep ens32
- 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
- inet 192.168.78.150/24 brd 192.168.78.255 scope global noprefixroute ens32
- inet 192.168.78.155/24 scope global secondary ens32
7.8 测试 keepalived
先停掉 master1 上的 keepalived,然后 vip 会随机漂移到 master2 或 master3 上,因为它两的权重相同:
- [root@k8s-master1 work]# systemctl stop keepalived.service
- [root@k8s-master1 work]# ip a | grep ens32
- 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
- inet 192.168.78.150/24 brd 192.168.78.255 scope global noprefixroute ens32
- [root@k8s-master2 ~]# ip a | grep ens32
- 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
- inet 192.168.78.151/24 brd 192.168.78.255 scope global noprefixroute ens32
- # vip 在 master 3 上:
- [root@k8s-master3 ~]# ip addr | grep ens32
- 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
- inet 192.168.78.152/24 brd 192.168.78.255 scope global noprefixroute ens32
- inet 192.168.78.155/24 scope global secondary ens32
- # 重新启动 keepalive,vip 回来了
- [root@k8s-master1 work]# systemctl start keepalived.service
- [root@k8s-master1 work]# ip a | grep ens32
- 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
- inet 192.168.78.150/24 brd 192.168.78.255 scope global noprefixroute ens32
- inet 192.168.78.155/24 scope global secondary ens32
目前所有的 Worker Node 组件连接都还是 master1 Node,如果不改为连接 VIP 走负载均衡器,那么 Master 还是单点故障。
因此接下来就是要改所有 Worker Node(kubectl get node 命令查看到的节点)组件配置文件,由原来 192.168.78.150 修改为 192.168.78.155(VIP)。
在 node1 和 node2 执行:
- [root@k8s-node1 ~]# ls /etc/kubernetes/
- kubelet-bootstrap.kubeconfig kubelet.json kubelet.kubeconfig kube-proxy.kubeconfig kube-proxy.yaml ssl
- sed -i 's#192.168.78.150:6443#192.168.78.155:16443#' /etc/kubernetes/kubelet-bootstrap.kubeconfig
- sed -i 's#192.168.78.150:6443#192.168.78.155:16443#' /etc/kubernetes/kubelet.json
- sed -i 's#192.168.78.150:6443#192.168.78.155:16443#' /etc/kubernetes/kubelet.kubeconfig
- sed -i 's#192.168.78.150:6443#192.168.78.155:16443#' /etc/kubernetes/kube-proxy.kubeconfig
- sed -i 's#192.168.78.150:6443#192.168.78.155:16443#' /etc/kubernetes/kube-proxy.yaml
- # 重启服务即可
- systemctl restart kubelet kube-proxy
这样 k8s-v1.25 高可用集群就安装好了!!!
标签:master1,K8s,kubernetes,--,手把手,master,k8s,root,kube From: https://www.cnblogs.com/data159/p/17244258.html上一篇文章:【云原生 | Kubernetes 实战】01、K8s-v1.25集群搭建和部署基于网页的 K8s 用户界面 Dashboard_containerd镜像加速_Stars.Sky的博客-CSDN博客
下一篇文章:2023 K8s 认证工程师 CKA 考题分析和题库练习(上)_Stars.Sky的博客-CSDN博客_k8s认证考试