集群信息
1.节点规划
部署k8s集群的节点按照用途可以划分为如下2类角色:
-
master: 集群的master节点,集群的初始化节点,基础配置不低于2C2G
-
slave: 集群的slave节点,可以多台,基础配置不低于2C2G
本例为了演示slave节点的添加,会部署一台master+2台slave,节点规划如下:
主机名 | 节点ip | 角色 | 部署组件 |
---|---|---|---|
master | 192.168.10.100 | master | etcd, kube-apiserver, kube-controller-manager, kubeadm, kubectl,kubelet, kube-proxy, flannel |
node1 | 192.168.10.101 | slave | kubectl, kubelet, kube-proxy, flannel |
node2 | 192.168.10.102 | slave | kubectl, kubelet, kube-proxy, flannel |
2.组件版本
组件 | 版本 | 说明 |
---|---|---|
CentOS | CentOS Linux release 7.9.2009 (Core) | cat /etc/redhat-release 可以查到 |
Kernel | Linux 3.10.0-1160.71.1.el7.x86_64 | hostnamectl |grep -I Kernel 可以查到 |
etcd | 3.5.15-0 | 使用容器方式部署,默认数据挂载到本地路径 |
coredns | v1.10.1 | |
kubeadm | v1.28.15 | |
kubectl | v1.28.15 | |
kubelet | v1.28.15 | |
kube-proxy | v1.28.15 | |
flannel | v0.26.4 |
安装前准备工作
1.创建虚拟机
光盘最后再选,不然让你设置虚拟机密码,太麻烦。
虚拟机的位置不要放在C盘,系统很容易占满。
磁盘大小我这设置40G,固态盘有点小,如果硬盘大的话可以设置大点。一般选这单个文件,方便虚拟机迁移,和格式转换。
这先自定义一下硬件,也可以直接完成,之后再修改。看个人习惯。
我这内存才8G,虚拟机内存就给2G,处理器内核数量选2,因为我的电脑是单个CPU,所以数量选1,虚拟化勾上。顺便移除USB、声卡、打印机。
Cdrom选一下ISO系统文件,然后点关闭、完成。
2.安装系统
直接选 Install CentOS7,选第二个是检查光盘,时间比较长,不般用,有错误时会用一下。
选择时区:
选基础设施服务,不用选最小安装,很多命令都不全。连命令补全都没有。
分区的话,这里测试就先自动分区好了
网卡先设置点亮,再点Configre...设置IP
选择IPv4、再选Manual,手动设置IP,把DNS也设置一下,用阿里的223.5.5.5 ,保存退出,点完成(Done)
开始安装。
在安装过程中设置一下 root 用户的密码,和普通用户。要等5分钟左右才完成安装。
完成。点重启
3.克隆虚拟机
用SSH 连上虚拟机,把网卡配置文件处理一下。
cp /etc/sysconfig/network-scripts/ifcfg-ens32 /etc/sysconfig/network-scripts/ifcfg-ens32.bak
vim /etc/sysconfig/network-scripts/ifcfg-ens32
把标红的地方都删除了,退出保存。如下
执行命令 : poweroff 关机,开克隆:
拍下快照,方便回退。
第一台node完成,按照第一台的步骤再做一次,完成第二台,这样虚拟机就准备好了。
4.设置hosts解析
操作节点:所有节点(k8s-master,k8s-slave)均需执行
-
修改hostname hostname必须只能包含小写字母、数字、","、"-",且开头结尾必须是小写字母或数字
-
因为是克隆,所以要先从node1 或node2 开始,一台设置完再开另一台,防止IP冲突。
现在开启node2虚拟机,在node2上执行下面命令
# 在node2上执行下面命令
sed -i 's/10.100/10.102/g' /etc/sysconfig/network-scripts/ifcfg-ens32
hostnamectl set-hostname node2 && bash
开启node1虚拟机,在node1上执行下面命令
# 在node1上执行下面命令
sed -i 's/10.100/10.101/g' /etc/sysconfig/network-scripts/ifcfg-ens32
hostnamectl set-hostname node1 && bash
开启master虚拟机,在master上执行下面命令 ,这样三台虚拟机的IP和主机名都设置好了。
# 在master上执行下面命令
hostnamectl set-hostname master && bash
查看一下是否正确:
添加hosts解析
操作节点:所有的master和slave节点(master,node1,node2)都需要执行
cat >>/etc/hosts<<EOF
192.168.10.100 master
192.168.10.100 cluster-endpoint
192.168.10.101 node1
192.168.10.102 node2
EOF
# 测试
ping -c3 master
ping -c3 cluster-endpoint
ping -c3 node1
ping -c3 node2
5.调整系统配置
操作节点:所有的master和slave节点(master,node1,node2)都需要执行
设置yum源
rm -f /etc/yum.repos.d/CentOS-Base.repo
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum clean all && yum makecache
时间同步
# 启动chronyd服务,设置chronyd服务开机自启
systemctl start chronyd && systemctl enable chronyd
# chronyd服务启动稍等几秒钟,使用date命令验证时间
date
关闭swap
不同的容器运行时(如 Docker, containerd, CRI-O 等)对 swap 的处理方式不同。例如,某些容器运行时可能默认不支持或不完全支持 swap。在这种情况下,禁用 swap 可以避免潜在的问题。swap 的使用可能导致性能问题,为了最佳的性能和稳定性,在 Kubernetes 节点上禁用 swap。
#临时关闭
swapoff -a
# 防止开机自动挂载swap 分区
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
关闭selinux和防火墙
# 关闭selinux
sed -ri 's#(SELINUX=).*#\1disabled#' /etc/selinux/config
setenforce 0
# 关闭防火墙
systemctl disable firewalld && systemctl stop firewalld
# 安装ipset和ipvsadm
yum install ipset ipvsadm -y
# 添加需要加载的模块写入脚本文件(加载五个模块)
cat <<EOF > /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
# 为脚本添加执行权限
chmod +x /etc/sysconfig/modules/ipvs.modules
# 执行脚本文件
bash /etc/sysconfig/modules/ipvs.modules
修改内核参数
cat <<EOF> /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables =1
net.bridge.bridge-nf-call-iptables =1
net.ipv4.ip_forward=1
vm.max_map_count=262144
EOF
sysctl -p /etc/sysctl.d/k8s.conf
# 加载网桥过滤模块
modprobe br_netfilter
6.安装docker
操作节点:所有的master和slave节点(master,node1,node2)都需要执行
# 安装必要的一些系统工具
yum install -y yum-utils
# 添加软件源信息
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 查看所有的可用版本
yum list docker-ce --showduplicates | sort -r
# 安装Docker
yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
## 配置docker加速
mkdir -p /etc/docker
tee /etc/docker/daemon.json << EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://docker.m.daocloud.io",
"https://hub.urlsa.us.kg",
"https://docker.urlsa.us.kg"]
}
EOF
# 开启Docker服务
systemctl daemon-reload && systemctl restart docker && systemctl enable docker
# 测试
docker version
安装cri-dockerd
cri-dockerd的主要作用是作为Kubernetes与Docker之间的桥梁,使得Kubernetes能够通过CRI(Container Runtime Interface)标准接口调用Docker的功能。在Kubernetes v1.24及以后的版本中,Kubernetes移除了内置的dockershim,这意味着它不再直接支持Docker。为了继续使用Docker作为容器运行时,需要安装cri-dockerd来实现这一功能。
下载并安装cri-docker
# 看了一下,好像最后一个针对centos7的版本是 cri-dockerd-0.3.14-3.el7.x86_64.rpm
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.14/cri-dockerd-0.3.14-3.el7.x86_64.rpm
# 安装
yum -y install cri-dockerd-0.3.14-3.el7.x86_64.rpm
cri-docker.service 修改
在fd:// 后加入--pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 看好了,// 后面有个空格的 。
vi /usr/lib/systemd/system/cri-docker.service
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9
# 重新加载cri-docker
systemctl daemon-reload
systemctl enable cri-docker && systemctl start cri-docker
完成后重启所有虚拟机(也可以关机做快照,因为下面的集群设置容易出错,有快照方便回退),并检查设置,检查命令如下:
# 可以先查看selinux是否开启,Disabled是没有开。
getenforce
# 查看内存分配来检查seap是否已经禁用,0表示没有分配。
free -m | grep Swap
# 查看防火墙,Active: inactive (dead)表示没有开启。
systemctl status firewalld | grep Active
# 查看对应模块是否加载成功
lsmod | grep -e ip_vs -e nf_conntrack_ipv4
# 查看网桥过滤模块是否加载成功
lsmod | grep br_netfilter
部署kubernetes
1.安装 kubeadm, kubelet 和 kubectl
在Kubernetes集群中,kubeadm、kubectl 和 kubelet 是三个核心组件,它们在集群的初始化、管理和节点维护中扮演着不同的角色。
kubeadm 用于集群的初始化,创建和配置主节点和工作节点
kubectl 是用户与集群交互的接口,用于管理和查询集群资源。
kubelet 在每个节点上运行,确保节点上的 Pod 按照期望的状态运行。
操作节点:所有的master和slave节点(master,node1,node2)都需要执行
-
添加kubernetes.repo
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/repodata/repomd.xml.key
EOF
-
安装kubeadm、kubelet和kubectl
yum install -y --nogpgcheck kubelet kubeadm kubectl
## 查看kubeadm 版本
kubeadm version
-
配置kubelet的cgroup
# 配置kubelet的cgroup,编辑/etc/sysconfig/kubelet,执行下面命令会把原来这个文件所有内容替换
cat <<EOF | tee /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS="--fail-swap-on=true"
KUBELET_CGROUP_ARGS="--cgroup-driver=systemd"
KUBE_PROXY_MODE="ipvs"
EOF
# 设置kubelet开机自启
systemctl enable kubelet
# 这里仅设置了开机自启没有启动,是因为在kubernetes启动时会自动启动kubelet
# 修改一下 Cgroup
containerd config default > /etc/containerd/config.toml
sed -i -e 's/registry.k8s.io/registry.aliyuncs.com\/google_containers/g' /etc/containerd/config.toml
sed -i -e 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
cat /etc/containerd/config.toml |egrep "sandbox_image|SystemdCgroup|disabled_plugins"
systemctl restart containerd
搭建k8s集群
提前下载镜像
操作节点:只在master节点(master)执行
-
操作节点:只在master节点(master)执行
-
查看要下载的镜像
kubeadm config images list | sed 's/^.*\///g'
命令结果如下
-
下载镜像
master虚拟下载镜像, imaweb是镜像源,images全部镜像。
# master下载镜像 imaweb是镜像源,阿里云镜像源,也可以换别的,images全部镜像列表
imaweb=registry.cn-hangzhou.aliyuncs.com/google_containers
images=(
kube-apiserver:v1.28.15
kube-controller-manager:v1.28.15
kube-scheduler:v1.28.15
kube-proxy:v1.28.15
pause:3.9
etcd:3.5.15-0
coredns:v1.10.1
)
for imageName in ${images[@]} ; do
docker pull $imaweb/$imageName #从阿里云拉镜像
done
下载完成,查看镜像 docker images -a
初始化master节点
# --apiserver-advertise-address配置k8s apiserver地址,用于监听、响应其他节点请求。此处配置为master节点ip地址
# --service-cidr=10.96.0.0/12 配置k8s Service的IP范围
# --pod-network-cidr=10.244.0.0/16 配置k8s pod的IP范围
# --cri-socket 用cri-dockerd.sock, 不用默认的containerd.sock
kubeadm init \
--apiserver-advertise-address=192.168.10.100 \
--image-repository=registry.aliyuncs.com/google_containers \
--kubernetes-version v1.28.15 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16 \
--cri-socket=unix:///var/run/cri-dockerd.sock
当看到图下所示的显示时,说明集群初始化完成
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/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.10.100:6443 --token nlkc72.jv7si27k4etec0t0 \
--discovery-token-ca-cert-hash --discovery-token-ca-cert-hash sha256:bf564fa1832cf6a5666f4b776945746747843a9ea33d81fe8c4ad2be3937c5ee
master执行命令
将刚刚画面出现的代码复制粘贴到master上运行
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
node加入集群
将刚刚界面出现的代码复制粘贴到node1和node2上运行(记得结尾指定一下cri-socket),还有你不要直接复制我的,token和discovery-token-ca-cert-hash是系统生成的,每一次都有可能不一样,你要看自己部署成功后的提示。就是successfully!后面的话。
kubeadm join 192.168.10.100:6443 --token 3sj6sc.z8uhm59ejfna28dv \
--discovery-token-ca-cert-hash sha256:bf564fa1832cf6a5666f4b776945746747843a9ea33d81fe8c4ad2be3937c5ee \
--cri-socket=unix:///var/run/cri-dockerd.sock
查看集群节点信息
在master节点执行命令查看集群节点信息,但是当前STATUS都是NotReady的
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady control-plane 5m5s v1.28.15
node1 NotReady <none> 48s v1.28.15
node2 NotReady <none> 42s v1.28.15
安装网络插件
-
先拉取镜像
-
操作节点:所有的master和slave节点(master,node1,node2)都需要执行
# 先拉取镜像,此过程,国内速度比较慢
docker pull ghcr.io/flannel-io/flannel-cni-plugin:v1.6.2-flannel1
docker pull ghcr.io/flannel-io/flannel:v0.26.4
下载kube-flannel.yml 配置文件
*下面步骤仅在master节点操作!!!*
wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
kubectl apply -f kube-flannel.yml
如果下载不了kube-flannel.yml ,下面贴出原文
apiVersion: v1
kind: Namespace
metadata:
labels:
k8s-app: flannel
pod-security.kubernetes.io/enforce: privileged
name: kube-flannel
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: flannel
name: flannel
namespace: kube-flannel
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
k8s-app: flannel
name: flannel
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- nodes/status
verbs:
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
k8s-app: flannel
name: flannel
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flannel
subjects:
- kind: ServiceAccount
name: flannel
namespace: kube-flannel
---
apiVersion: v1
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"
}
}
kind: ConfigMap
metadata:
labels:
app: flannel
k8s-app: flannel
tier: node
name: kube-flannel-cfg
namespace: kube-flannel
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app: flannel
k8s-app: flannel
tier: node
name: kube-flannel-ds
namespace: kube-flannel
spec:
selector:
matchLabels:
app: flannel
k8s-app: flannel
template:
metadata:
labels:
app: flannel
k8s-app: flannel
tier: node
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
containers:
- args:
- --ip-masq
- --kube-subnet-mgr
command:
- /opt/bin/flanneld
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: EVENT_QUEUE_DEPTH
value: "5000"
image: ghcr.io/flannel-io/flannel:v0.26.4
name: kube-flannel
resources:
requests:
cpu: 100m
memory: 50Mi
securityContext:
capabilities:
add:
- NET_ADMIN
- NET_RAW
privileged: false
volumeMounts:
- mountPath: /run/flannel
name: run
- mountPath: /etc/kube-flannel/
name: flannel-cfg
- mountPath: /run/xtables.lock
name: xtables-lock
hostNetwork: true
initContainers:
- args:
- -f
- /flannel
- /opt/cni/bin/flannel
command:
- cp
image: ghcr.io/flannel-io/flannel-cni-plugin:v1.6.2-flannel1
name: install-cni-plugin
volumeMounts:
- mountPath: /opt/cni/bin
name: cni-plugin
- args:
- -f
- /etc/kube-flannel/cni-conf.json
- /etc/cni/net.d/10-flannel.conflist
command:
- cp
image: ghcr.io/flannel-io/flannel:v0.26.4
name: install-cni
volumeMounts:
- mountPath: /etc/cni/net.d
name: cni
- mountPath: /etc/kube-flannel/
name: flannel-cfg
priorityClassName: system-node-critical
serviceAccountName: flannel
tolerations:
- effect: NoSchedule
operator: Exists
volumes:
- hostPath:
path: /run/flannel
name: run
- hostPath:
path: /opt/cni/bin
name: cni-plugin
- hostPath:
path: /etc/cni/net.d
name: cni
- configMap:
name: kube-flannel-cfg
name: flannel-cfg
- hostPath:
path: /run/xtables.lock
type: FileOrCreate
name: xtables-lock
验证
插件部署好之后等待若干分钟,查看集群pod信息STATUS都是Running的
[root@master kubernetes]# kubectl get pod -o wide -A
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel kube-flannel-ds-f6khf 1/1 Running 0 19s 192.168.10.100 master <none> <none>
kube-flannel kube-flannel-ds-qcznr 1/1 Running 0 19s 192.168.10.102 node2 <none> <none>
kube-flannel kube-flannel-ds-xzzbw 1/1 Running 0 19s 192.168.10.101 node1 <none> <none>
kube-system coredns-66f779496c-d99gv 1/1 Running 0 69m 10.244.0.2 master <none> <none>
kube-system coredns-66f779496c-srkrb 1/1 Running 0 69m 10.244.0.3 master <none> <none>
kube-system etcd-master 1/1 Running 0 69m 192.168.10.100 master <none> <none>
kube-system kube-apiserver-master 1/1 Running 0 69m 192.168.10.100 master <none> <none>
kube-system kube-controller-manager-master 1/1 Running 0 69m 192.168.10.100 master <none> <none>
kube-system kube-proxy-57x8b 1/1 Running 0 29m 192.168.10.101 node1 <none> <none>
kube-system kube-proxy-jzbrk 1/1 Running 0 69m 192.168.10.100 master <none> <none>
kube-system kube-proxy-x9szr 1/1 Running 0 29m 192.168.10.102 node2 <none> <none>
kube-system kube-scheduler-master 1/1 Running 0 69m 192.168.10.100 master <none> <none>
不记得token、a证书sha256编码的hash值,可以查看
查看 token
命令:kubeadm token list
[root@master kubernetes]# kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION ES
5v11rg.el3tv0w19q30v72y 23h 2025-02-17T11:59:39Z authentication,signing <none> sn
nlkc72.jv7si27k4etec0t0 22h 2025-02-17T11:22:35Z authentication,signing The default bootstrap token generated by 'kubeadm init'. sn
生成新 token
命令:kubeadm token create
获取ca证书sha256编码的hash值,有时用的SSH客户端拉得太小也会显示不完整,可以用下面命令查看一下。
命令:openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
[root@master ~]# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
bf564fa1832cf6a5666f4b776945746747843a9ea33d81fe8c4ad2be3937c5ee
加入集群命令:把上面查到的代替 ... 即可。
kubeadm join master节点IP:6443 \
--token ... \
--discovery-token-ca-cert-hash sha256:...\
--cri-socket=unix:///var/run/cri-dockerd.sock
kubeadm join master节点IP:6443 \
--token nlkc72.jv7si27k4etec0t0 \
--discovery-token-ca-cert-hash sha256:bf564fa1832cf6a5666f4b776945746747843a9ea33d81fe8c4ad2be3937c5ee \
--cri-socket=unix:///var/run/cri-dockerd.sock