1 参考文档
2 环境准备
2.1 物理环境
主机 | IP | 配置 | OS |
---|---|---|---|
master/node1 | 192.168.67.139 | 2core 2GB | Centos7.9 |
node2 | 192.168.67.140 | 2core 2GB | Centos7.9 |
node3 | 192.168.67.141 | 2core 2GB | Centos7.9 |
node4 | 192.168.67.142 | 2core 2GB | Centos7.9 |
2.2 软件环境
软件 | 版本 |
---|---|
docker | v20.10.12 |
kubeadmin | v1.23.3 |
kubelet | v1.23.3 |
kubectl | v1.23.3 |
2.3 镜像
镜像 | 版本 |
---|---|
conformance | v1.23.3 |
kube-apiserver | v1.23.3 |
kube-controller-manager | v1.23.3 |
kube-proxy | v1.23.3 |
kube-scheduler | v1.23.3 |
flannel | v1.0.1 |
3 步骤
3.1 准备工作
3.1.1 确保各节点MAC和product_uuid的唯一性
- 你可以使用命令
ip link
或ifconfig -a
来获取网络接口的 MAC 地址 - 可以使用
sudo cat /sys/class/dmi/id/product_uuid
命令对 product_uuid 校验
一般来讲,硬件设备会拥有唯一的地址,但是有些虚拟机的地址可能会重复。
3.1.2 运行iptables检查桥接流量
确保 br_netfilter
模块被加载。这一操作可以通过运行 lsmod | grep br_netfilter
来完成。若要显式加载该模块,可执行 sudo modprobe br_netfilter
。
为了让你的 Linux 节点上的 iptables 能够正确地查看桥接流量,你需要确保在你的 sysctl
配置中将 net.bridge.bridge-nf-call-iptables
设置为 1。例如:
1 | cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf |
3.1.3 关闭防火墙
1 | systemctl stop firewalld |
如果各个主机启用了防火墙,需要开放Kubernetes各个组件所需要的端口。如下图所示,详细信息请看官网。
3.1.4 永久关闭swap
vim /etc/fstab
如果不修改,kubelet启动报错:
3.1.5 关闭selinux
1 | 将 SELinux 设置为 permissive 或 disabled模式(相当于将其禁用) |
3.2 安装docker
卸载旧版本
1 | yum remove docker \ |
源安装
执行以下命令安装依赖包:
1 | $ sudo yum install -y yum-utils |
鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。
执行下面的命令添加 yum
软件源:
1 | $ sudo yum-config-manager \ |
安装docker-ce
1 | $ sudo yum install docker-ce docker-ce-cli containerd.io |
开机自启
1 | 启动 Docker |
3.3 安装 kubeadm、kubelet 和 kubectl
你需要在每台机器上安装以下的软件包:
kubeadm
:用来初始化集群的指令。kubelet
:在集群中的每个节点上用来启动 Pod 和容器等。kubectl
:用来与集群通信的命令行工具。
1 | cat <<EOF > /etc/yum.repos.d/kubernetes.repo |
3.4 配置cgroup驱动程序
需保证容器服务和kubelet的cgroup驱动一致,否则kubelet启动报错:
由于 kubeadm 把 kubelet 视为一个系统服务来管理,所以对基于 kubeadm 的安装, 我们推荐使用 systemd
驱动,不推荐 cgroupfs
驱动。
3.4.1 Cgroup 驱动程序说明
警告:
你需要确保容器(docker)和 kubelet 所使用的是相同的 cgroup 驱动,否则 kubelet 进程会失败。
相关细节可参见kubelet配置 cgroup 驱动。容器配置cgroup驱动
3.4.2 查看kubelet和docker的驱动程序
- kubelet
1 | [root@node1 ~]# cat /var/lib/kubelet/kubeadm-flags.env |
- docker
1 | [root@node1 ~]# docker info |grep Cgroup |
3.4.4 Docker配置cgroup驱动
1 | sudo mkdir /etc/docker |
3.4.5 kubelet配置cgroup驱动(可选)
kubelet不配置默认即使用systemd
1 | # 将kubelet和docker 的驱动程序改成一致。 |
3.5 kubeadm创建集群
3.5.1 kubeadm config
kubeadm已经进入GA阶段,其控制面初始化和加入节点步骤都支持大量的可定制内容,因此kubeadm还提供了配置文件功能用于复杂定制。同时,kubeadm将配置文件以ConfigMap的形式保存到集群之中,便于后续的查询和升级工作。kubeadm config子命令提供了对这一组功能的支持:
◎ kubeadm config upload from-file:由配置文件上传到集群中生成ConfigMap。
◎ kubeadm config upload from-flags:由配置参数生成ConfigMap。
◎ kubeadm config view:查看当前集群中的配置值。
◎ kubeadm config print init-defaults:输出kubeadm init默认参数文件的内容。
◎ kubeadm config print join-defaults:输出kubeadm join默认参数文件的内容。
◎ kubeadm config migrate:在新旧版本之间进行配置转换。
◎ kubeadm config images list:列出所需的镜像列表。
◎ kubeadm config images pull:拉取镜像到本地。例如,执行kubeadm config print init-defaults,可以取得默认的初始化参数文件:
1 | kubeadm config print init-defaults > init.default.yaml |
3.5.2 导出kubeadm集群默认配置文件
1 | kubeadm config print init-defaults > init.default.yaml |
3.5.3 修改默认配置文件
修改如下内容:
- 主节点IP——advertiseAddress
- 国内阿里镜像地址imageRepository——registry.cn-hangzhou.aliyuncs.com/k8s-images-kx(通过阿里镜像仓库拉取的国外镜像)
- pod网段配置——不同网络插件网段不一样详细见官网(配置网络插件subnet地址段)
将上面的内容保存为init-config.yaml备用。
纠正:
podSubent
的值设置为flannel的默认网段,FLANNEL_NETWORK
的默认值(可通过flannel.yaml文件查看);podSubent=10.244.0.0/16
原因:
后面配置NFS存储类的时候,pod无法正常访问kube-apiserver。
参考:
k8s 1.20.x版本NFS动态存储配置 - 巽逸 - 博客园 (cnblogs.com)
(71条消息) Kubeadm 部署 使用flannel无法连接service/kubernetes_weixin_40455124的博客-CSDN博客
3.5.4 下载kubernetes相关镜像
使用config images list 子命令查询所需的镜像,例如
1 | [root@node1 home]# kubeadm config images list --config=init.default.yaml |
使用config images pull 子命令下载所需的镜像,例如(国内无法下载,只做演示)
预拉取镜像
通过阿里云镜像仓库构建下载镜像,具体方法不做细说。
镜像使用方式有2种:
- 修改镜像名为国外镜像名,例如
k8s.gcr.io/kube-apiserver:v1.23.0
k8s.gcr.io/kube-controller-manager:v1.23.0
k8s.gcr.io/kube-scheduler:v1.23.0
k8s.gcr.io/kube-proxy:v1.23.0
k8s.gcr.io/pause:3.6
k8s.gcr.io/etcd:3.5.1-0
k8s.gcr.io/coredns/coredns:v1.8.6
- 修改初始化配置文件,修改国外仓库为阿里云仓库
imageRepository: registry.cn-hangzhou.aliyuncs.com/k8s-images-kx
kind: ClusterConfiguration
kubernetesVersion: 1.23.3
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
1 | [root@node1 home]# kubeadm config images pull --config=init.default.yaml |
3.5.5 初始化集群
1 | [root@node1 home]# kubeadm init --config=init.default.yaml |
初始化失败,可以如下命令重置
1 | [root@node1 home]# kubeadm reset |
显示如下安装成功
普通用户使用集群需如下配置
1 | mkdir -p $HOME/.kube |
3.5.6 查询集群状态
1 | kubectl get node |
notready原因是没有安装pod网络。
3.5.7 安装pod网络(二选一)
各pod组件的链接均可以通过如下地址找到,及相关使用教程。
网络说明
Kubernetes的网络通信问题:
1. 容器间通信: 即同一个Pod内多个容器间通信,通常使用loopback来实现。
2. Pod间通信: K8s要求,Pod和Pod之间通信必须使用Pod-IP 直接访问另一个Pod-IP
3. Pod与Service通信: 即PodIP去访问ClusterIP,当然,clusterIP实际上是IPVS 或 iptables规则的虚拟IP,是没有TCP/IP协议栈支持的。但不影响Pod访问它.
4. Service与集群外部Client的通信,即K8s中Pod提供的服务必须能被互联网上的用户所访问到。
需要注意的是,k8s集群初始化时的service网段,pod网段,网络插件的网段,以及真实服务器的网段,都不能相同,如果相同就会出各种各样奇怪的问题,而且这些问题在集群做好之后是不方便改的,改会导致更多的问题,所以,就在搭建前将其规划好。
CNI(容器网络接口):
这是K8s中提供的一种通用网络标准规范,因为k8s本身不提供网络解决方案。
目前比较知名的网络解决方案有:
flannel
calico
canel
kube-router
…….
等等,目前比较常用的时flannel和calico,flannel的功能比较简单,不具备复杂网络的配置能力,calico是比较出色的网络管理插件,单具备复杂网络配置能力的同时,往往意味着本身的配置比较复杂,所以相对而言,比较小而简单的集群使用flannel,考虑到日后扩容,未来网络可能需要加入更多设备,配置更多策略,则使用calico更好
所有的网络解决方案,它们的共通性:
1. 虚拟网桥
2. 多路复用:MacVLAN
3. 硬件交换:SR-IOV(单根-I/O虚拟网络):它是一种物理网卡的硬件虚拟化技术,它通过输出VF(虚拟功能)来将网卡虚拟为多个虚拟子接口,每个VF绑定给一个VM后,该VM就可以直接操纵该物理网卡。
kubelet来调CNI插件时,会到 /etc/cni/net.d/目录下去找插件的配置文件,并读取它,来加载该插件,并让该网络插件来为Pod提供网络服务。
flannel网络插件要怎么部署?
1. flannel部署到那个节点上?
因为kubelet是用来管理Pod的,而Pod运行需要网络,因此凡是部署kubelet的节点,都需要部署flannel来提供网络,因为kubelet正是通过调用flannel来实现为Pod配置网络的(如:添加网络,配置网络,激活网络等)。
3.5.7.1 flannel
在所有节点都pull下载flannel镜像,节点加入集群时自动创建flannel容器。
1 | kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml |
3.5.7.2 calico
在所有节点都pull下载calico镜像
1 | kubectl apply -f https://projectcalico.docs.tigera.io/manifests/canal.yaml |
3.5.7.3 查看集群状态
coredns正常运行,节点状态ready.
3.5.8 添加Node节点
1 | # token和hash 下面会介绍如何获取 |
输出如下内容
1 | [root@node3 ~]# kubeadm join --token abcdef.01234ad56789abcdef 192.168.76.139:6443 --discovery-token-ca-cert-hash sha256:500813d6c8feca1d82468821993be623d3d7ccdfa33d202f3c7fe3c6b39da086c7d |
查询token
1 | kubeadm token list |
输出类似于以下内容:
1 | 5didvk.d09sbcov8ph2amjw |
查询 –discovery-token-ca-cert-hash
1 | openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \ |
输出类似于以下内容:
1 | 8cb2de97839780a412b93877f8507ad6c94f73add17d5d7058e91741c9d5ec78 |
3.5.8 测试
首先验证kube-apiserver, kube-controller-manager, kube-scheduler, pod network 是否正常:
1 | # 部署一个 Nginx Deployment,包含两个Pod |
再验证一下kube-proxy
是否正常:
1 | # 以 NodePort 方式对外提供服务 https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/ |
最后验证一下dns, pod network是否正常:
1 | # 运行Busybox并进入交互模式 |
4 补充
4.1 允许master节点部署pod
这是因为k8s集群默认不让在master节点创建pod,也就是说Master Node不参与工作负载。
当前的master节点被打上了node-role.kubernetes.io/master:NoSchedule
的污点:
1 | [root@k8s-master k8s]# kubectl describe nodes node1 |grep -E '(Roles|Taints)' |
允许master部署pod
1 | [root@k8s-master nginx]# kubectl taint nodes node1 node-role.kubernetes.io/master- |
禁止master部署pod
1 | [root@k8s-master]# kubectl taint nodes node1 node-role.kubernetes.io/master=true:NoSchedule |
4.2 卸载集群
想要撤销kubeadm执行的操作,首先要排除节点,并确保该节点为空, 然后再将其关闭。
在Master节点上运行:
1 | kubectl drain <node name> --delete-local-data --force --ignore-daemonsets |
然后在需要移除的节点上,重置kubeadm的安装状态:
1 | sudo kubeadm reset |
1 | # 卸载集群后,建议手动删除CNI网络的地址段配置文件,避免重装集群造成影像。 |
如果你想重新配置集群,使用新的参数重新运行kubeadm init
或者kubeadm join
即可。
5 问题总结
5.1 创建deployment后,配置NodePort,无法通过任意节点访问
问题描述:
创建nginx的depolyment,并配置nodeport端口配置,只能通过pod所在的节点IP和暴漏端口访问,无法通过其他节点“IP:端口”访问;集群内pod之间不能通过pod IP互相访问;kube-dns解析异常等问题。
查看节点kube-proxy服务日志显示如下错误
问题原因:节点没有开启路由转发功能。
解决办法:添加net.ipv4.ip_forward = 1
到/etc/sysctl.conf或/etc/sysctl.d/k8s.conf,执行sysctl -p
命令生效。