前情概要
关于在虚拟机中centos系统搭建k8s集群,前前后后花了很多个白天黑夜才搞定,采用不同的搭建方式搭建集群次数至少10次以上,期间看了无数文章和视频,也踩过无数坑,很多视频、文章的安装教程都存在一些差别,有些时候可能因为k8s安装版本不同或者缺少某些必要的设置导致同一个命令返回的错误信息不一样,难点主要集中在安装flannel网络插件上以及集群节点状态为NotReady等问题,以flannel网络插件安装为例,其实有很多种安装办法,也都试过,但也遇到过各种各样的问题。还有就是一些配置,可能你在其它的教程中看到的会和本教程有不一致的情况,建议大家安装配置时按照本篇文章的操作步骤进行操作。
演示工具
VmWare17、MobaXterm
系统版本
CentOS7
集群节点
角色 | IP地址 |
---|---|
k8s-master | 192.168.12.136 |
k8s-slave1 | 192.168.12.137 |
k8s-slave2 | 192.168.12.138 |
单词说明
master:代表master节点操作
slave:代表slave节点操作
master+slave:代表master、slave节点都要操作
安装并配置Docker(master+slave)
- 安装docker
#安装yum-utils包
yum install yum-utils#添加阿里云 yum 仓库
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo#更新yum缓存到本地
yum makecache fast#安装docker ce 社区版本
yum -y install docker-ce#检查docker是否安装成功
docker version#启动docker
systemctl start docker#设置docker开机自启
systemctl enable docker#查看docker运行状态
systemctl status docker
- 设置daemon.json
#创建文件夹
mkdir -p /etc/docker#创建并编辑文件
tee /etc/docker/daemon.json <<-'EOF'
{"exec-opts":["native.cgroupdriver=systemd"],"registry-mirrors": ["https://docker.m.daocloud.io", "https://noohub.ru", "https://huecker.io","https://dockerhub.timeweb.cloud","https://0c105db5188026850f80c001def654a0.mirror.swr.myhuaweicloud.com","https://5tqw56kt.mirror.aliyuncs.com","https://docker.1panel.live","http://mirrors.ustc.edu.cn/","http://mirror.azure.cn/","https://hub.rat.dev/","https://docker.ckyl.me/","https://docker.chenby.cn","https://docker.hpcloud.cloud","https://docker.m.daocloud.io"]
}
EOF#重载服务配置文件并重启docker
systemctl daemon-reload && systemctl restart docker
说明
- 设置exec-opts的目的是因为kubelet默认cgoup驱动为systemd,而docker默认驱动为cgroupfs,但k8s官网要求docker和kubelet服务中的cgroup驱动必须一致,因此添加了 "exec-opts":["native.cgroupdriver=systemd"]配置,若不配置,后续kubeadm初始化的时候会报以下问题
:::info
The HTTP call equal to 'curl -sSL http://localhost:10248/healthz' failed with error: Get "http://localhost:10248/healthz“: dial tcp [::1]:10248: connect: connection refused
:::
- registry-mirros节点配置须注意,从2024年7月2日开始,阿里云镜像加速器配置功能做了调整,无法像以前一样直接复制镜像地址,复制的镜像地址都是无法访问的,上面命令中registry-mirrors对应数组的镜像节点地址是网上找了很久才找到可用的节点。
https://help.aliyun.com/zh/acr/product-overview/product-change-acr-mirror-accelerator-function-adjustment-announcement
设置独立的域名(master+slave)
- master节点执行以下命令
hostnamectl set-hostname k8s-master
- slave1节点执行以下命令
hostnamectl set-hostname k8s-slave1
- slave2节点执行以下命令
hostnamectl set-hostname k8s-slave2
设置完之后通过以下命令可以查看hostname
hostnamectl | grep "Static hostname"
添加主机名与IP对应的关系(master+slave)
集群机器分别执行以下命令,该命令用于修改hosts文件,添加添加主机名与IP对应的关系。
cat >> /etc/hosts << EOF
192.168.12.136 k8s-master
192.168.12.137 k8s-slave1
192.168.12.138 k8s-slave2
EOF
#可执行此命令用来检查配置是否写入文件中
cat /etc/hosts
同步时间(master+slave)
同步时间,设置中国时区(这一步必须做,否则后面安装flannel可能会有证书错误)
#安装ntpdate插件
yum install ntpdate -y
#同步时间
ntpdate cn.pool.ntp.org
输入date命令检查时间是否已同步
date
关闭并禁用防火墙(master+slave)
不禁用防火墙可能会导致后续执行kubeadm初始化命令报异常,但在实际工作场景中一般不会禁用防火墙,可以在生产环境中选择释放相应端口号即可。
#关闭防火墙
systemctl stop firewalld
#禁用防火墙
systemctl disable firewalld
关闭并禁用selinux(master+slave)
#临时关闭,将SELinux设置为permissive模式 0代表permissive模式;1代表enforcing模式;
setenforce 0#加上此行则代表永久关闭(需要重启机器)
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
关闭swap(master+slave)
有临时关闭和永久关闭两种选项,这里选择永久关闭。
#临时关闭
swapoff -a#永久关闭
swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
网桥设置(master+slave)
将桥接的IPv4流量传递到iptables的链
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 --system
安装k8s(master+slave)
- 设置阿里云镜像
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
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpghttp://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF#执行以下命令可以查看配置是否写入文件中
cat /etc/yum.repos.d/kubernetes.repo
- 安装k8s相关依赖包
#安装kubeadm、kubelet、kubectl
yum install -y kubectl-1.23.17 kubeadm-1.23.17 kubelet-1.23.17#启动kubelet
systemctl start kubelet#开机自启动kubelet
systemctl enable kubelet#查看kubelet运行日志(可以暂时不执行此命令)
journalctl -xefu kubelet
kubeadm初始化(master)
- 执行下面命令进行kubeadm初始化
注意:apiserver-advertise-address后面的IP地址要换成你的master节点的IP地址
kubeadm init \
--apiserver-advertise-address=192.168.12.136 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.23.17 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16参数解析
--apiserver-advertise-address : 指定apiserver的监听地址(内网地址/私有地址)
--image-repository : 镜像仓库地址
--kuberneters-version : 指定kuberneters版本,要与安装的版本保持一致
--service-cidr :外网能访问的IP地址
--pod-network-cidr : Pod网络IP地址,与后面部署的CNI网络组件yaml中保持一致
- 配置环境变量
普通用户:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
root用户:
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> /etc/profile
source /etc/profile
这里演示用的是root账户,因此执行root账户对应的命令。
注意:若不配置环境变量,执行命令时会报错,例如执行kubectl get node命令查看节点状态信息时会报以下错误
若配置了环境变量,执行kubectl get node命令会显示以下信息。
kubeadm加入到主节点(slave)
- 在每台slave机器中执行kubeadm join命令,该命令是mater节点初始化k8s时生成的。
kubeadm join 192.168.12.136:6443 --token af0b96.dc2rnj2tjb5fpec5 \--discovery-token-ca-cert-hash sha256:07351ab27b9df10f38d0f6ba588976679faf9ba1398192bf57340dd2f50eca70
注意:
- 这里的token值是临时token,有效期是24个小时,过期后将失效,需要在master节点执行以下命令重新创建token。
kubeadm token create --print-join-command
- 配置环境
echo "export KUBECONFIG=/etc/kubernetes/kubelet.conf" >> /etc/profile
source /etc/profile
- 查看集群节点状态信息
kubectl get node
状态都为NotReady,因为还未安装网络插件。
安装flannel网络(master)
flannel用于k8s节点之间容器网络通信的一个组件,可以为不同node节点分配不同的子网,实现容器间的跨机通信,从而实现整个kubents层级通信。
注意:网络插件并非只有flannel一种,还有很多,这里只以flannel作为演示。
- 输入如下命令
因为文件下载地址在国外,访问会很慢,因此需要做下配置,首先打开https://www.ipaddress.com/,在搜索框中查询raw.githubusercontent.com的真实IP。
#进入到hosts文件中
vi /etc/hosts#在hosts文件中添加如下配置并保存退出
185.199.108.133 raw.githubusercontent.com
- 下载网络插件到本地目录
cd /opt
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
虽然前面配置了域名,但也可能出现访问不了的情况,如下图所示,尝试多试几次。
文件完整内容如下所示,若因网络问题无法下载kube-flannel.yml文件到本地,则可以在本地创建文件,并复制粘贴以下内容到文件中。
---
kind: Namespace
apiVersion: v1
metadata:name: kube-flannellabels:k8s-app: flannelpod-security.kubernetes.io/enforce: privileged
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:labels:k8s-app: flannelname: flannel
rules:
- apiGroups:- ""resources:- podsverbs:- get
- apiGroups:- ""resources:- nodesverbs:- get- list- watch
- apiGroups:- ""resources:- nodes/statusverbs:- patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:labels:k8s-app: flannelname: flannel
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: flannel
subjects:
- kind: ServiceAccountname: flannelnamespace: kube-flannel
---
apiVersion: v1
kind: ServiceAccount
metadata:labels:k8s-app: flannelname: flannelnamespace: kube-flannel
---
kind: ConfigMap
apiVersion: v1
metadata:name: kube-flannel-cfgnamespace: kube-flannellabels:tier: nodek8s-app: flannelapp: flannel
data:cni-conf.json: |{"name": "cbr0","cniVersion": "0.3.1","plugins": [{"type": "flannel","delegate": {"hairpinMode": true,"isDefaultGateway": true}},{"type": "portmap","capabilities": {"portMappings": true}}]}net-conf.json: |{"Network": "10.244.0.0/16","EnableNFTables": false,"Backend": {"Type": "vxlan"}}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:name: kube-flannel-dsnamespace: kube-flannellabels:tier: nodeapp: flannelk8s-app: flannel
spec:selector:matchLabels:app: flanneltemplate:metadata:labels:tier: nodeapp: flannelspec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/osoperator: Invalues:- linuxhostNetwork: truepriorityClassName: system-node-criticaltolerations:- operator: Existseffect: NoScheduleserviceAccountName: flannelinitContainers:- name: install-cni-pluginimage: docker.io/flannel/flannel-cni-plugin:v1.6.0-flannel1command:- cpargs:- -f- /flannel- /opt/cni/bin/flannelvolumeMounts:- name: cni-pluginmountPath: /opt/cni/bin- name: install-cniimage: docker.io/flannel/flannel:v0.26.2command:- cpargs:- -f- /etc/kube-flannel/cni-conf.json- /etc/cni/net.d/10-flannel.conflistvolumeMounts:- name: cnimountPath: /etc/cni/net.d- name: flannel-cfgmountPath: /etc/kube-flannel/containers:- name: kube-flannelimage: docker.io/flannel/flannel:v0.26.2command:- /opt/bin/flanneldargs:- --ip-masq- --kube-subnet-mgrresources:requests:cpu: "100m"memory: "50Mi"securityContext:privileged: falsecapabilities:add: ["NET_ADMIN", "NET_RAW"]env:- name: POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.name- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespace- name: EVENT_QUEUE_DEPTHvalue: "5000"volumeMounts:- name: runmountPath: /run/flannel- name: flannel-cfgmountPath: /etc/kube-flannel/- name: xtables-lockmountPath: /run/xtables.lockvolumes:- name: runhostPath:path: /run/flannel- name: cni-pluginhostPath:path: /opt/cni/bin- name: cnihostPath:path: /etc/cni/net.d- name: flannel-cfgconfigMap:name: kube-flannel-cfg- name: xtables-lockhostPath:path: /run/xtables.locktype: FileOrCreate
- 上传
kubectl apply -f kube-flannel.yml
- 查看k8s集群节点信息,
注意:集群节点的状态必须都为Ready才算成功,如果存在某节点状态还是显示NotReady则多等几分钟重试。
kubectl get nodes
- 查看所有命名空间运行的Pod详细信息
kubectl get pod -A -o wide
若存在某些Pod的STATUS不为Running状态,则通过以下命令查找对应Pod的报错信息,其中NAME和NAMESPACE对应图中的列表项。
kubectl describe po NAME -n NAMESPACE