Ubuntu通过kubeadm安装k8s集群

环境准备:

系统ubuntu
版本号24.04
docker版本28.0.4
kubernetes版本v1.32
k8s-master01192.168.49.20(至少2G内存,2核cpu)
k8s-master02192.168.49.21(至少2G内存,2核cpu)
k8s-master03192.168.49.22(至少2G内存,2核cpu)
k8s-node01192.168.49.23(至少2G内存)
k8s-node02192.168.49.24(至少2G内存)

一、初始化

1、配置host文件,每台机器的/etc/hosts文件中写入:

192.168.49.20 k8s-master01
192.168.49.21 k8s-master02
192.168.49.22 k8s-master03
192.168.49.23 k8s-node01
192.168.49.24 k8s-node02

2、配置时间同步, 每台机器都要执行,如下:

timedatectl set-timezone Asia/Shanghai   #先设置时区为上海
apt install ntpsec-ntpdate               #安装ntpdate
ntpdate ntp.aliyun.com                   #同步阿里云时间
crontab -e                               #加入定时任务

3、配置内核转发和网桥过滤,,每台机器执行如下:

cat << EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

加载如下两个模块(如果先安装的docker,在安装后这两个模块就是默认加载了):

modprobe overlay          #lsmod | grep overlay可查看
modprobe br_netfilter     #lsmod | grep br_netfilter 可查看

4、安装ipvs,每台机器都要安装

cat << EOF | tee /etc/modules-load.d/ipvs.conf
ip_vs
ip_vs_rr
ip_VS_wrr
ip_vs_sh
nf_conntrack
EOF

加载模块

modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack

查看是否加载成功,如图:

5、关闭swap分区(如果不配置关闭就要配置kubelet容忍swap):

swapoff -a        #临时禁用
vim /etc/fastb    #注释掉,永久禁用

6、安装docker 和cri-dockerd,这里省略,k8s1.32对应的pause为3.10,因此cri-dockerd要用3.10版本

7、安装etcd,k8s1.32要求etcd要3.5.15以上,可以参考链接安装etcd

二、安装 kubeadm、kubelet 和 kubectl

  • kubeadm:用来初始化集群的指令
  • kubelet:在集群中的每个节点上用来启动 Pod 和容器等
  • kubectl:用来与集群通信的命令行工具

注:如果是离线机器安装,就需要找到有网的机器,然后执行下面的步骤将安装包下载回来

1、首先安装需要的工具包

apt-get install -y apt-transport-https ca-certificates curl gpg 

2、下载公共签名密钥(1.32版本)

# /etc/apt/keyrings目录没有就要创建
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

3、添加仓库源:

echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
apt update     #更新源头

4、查看当前可用的软件版本,如图:

apt-cache madison kubelet | kubeadm | kubectl

5、有网机器直接执行命令安装

apt-get install -y kubelet kubeadm kubectl  #默认安装最新版本
或者指定版本
apt-get install -y kubelet=1.32.3-1.1 kubeadm=1.32.3-1.1 kubectl=1.32.3-1.1 #指定版本

机器没有网可将1-4步骤放在有网机器执行,然后执行命令将包下载回来,如下:

#/root/k8s路径为自己创建的
apt-get install -y --download-only -o dir::cache::archives=/root/k8s kubeadm=1.32.3-1.1

放到内网机器后,执行命令安装,如下:

dpkg -i *.deb
apt-mark hold kubelet kubeadm kubectl  #锁定版本,防止自动更新
组件master节点work节点
kubeadm需要必须(加入集群)
kubectl需要非必须
kubelet需要必须

6、配置kubelet,配置cgroup管理,所有节点都要执行,如下:

vim /etc/default/kubelet #1.30版本后的路径,之前在/etc/sysconf/kubelet

添加如下配置:

KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"

配置开机自启动,此时不用启动,现在启动也会报错,kubeadm init后会自动带起来

systemctl enable kubelet

7、安装nginx+keepalived,保证api-server高可用

三、初始化集群

初始化集群的操作需要在master上操作

1、规划集群网段

规划pod/service网段,这两个网段和宿主机网段不能重复

  • 宿主机网段:192.168.49.0/24
  • service网段:10.96.0.0/12
  • pod网段:10.244.0.0/16

2、执行kubeadm init初始化集群,可通过命令获取默认的初始化配置文件,如下:

kubeadm config print init-defaults > kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.49.20
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///var/run/cri-dockerd.sock
  imagePullPolicy: IfNotPresent
  imagePullSerial: true
  name: k8s-master1
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/master
timeouts:
  controlPlaneComponentHealthCheck: 4m0s
  discovery: 5m0s
  etcdAPICall: 2m0s
  kubeletHealthCheck: 4m0s
  kubernetesAPICall: 1m0s
  tlsBootstrap: 5m0s
  upgradeManifests: 5m0s
---
apiServer: {}
apiVersion: kubeadm.k8s.io/v1beta4
caCertificateValidityPeriod: 87600h0m0s
certificateValidityPeriod: 8760h0m0s
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: "192.168.49.19:16443"
controllerManager: {}       #保持控制器管理器,生产环境保持默认值就行,不用动
dns: {}
encryptionAlgorithm: RSA-2048
etcd:
  external:
    endpoints:
    - https://192.168.49.20:2379
    - https://192.168.49.21:2379
    - https://192.168.49.22:2379
    caFile: /data/etcd/ssl/etcd-ca.pem
    certFile: /data/etcd/ssl/server.pem
    keyFile: /data/etcd/ssl/server-key.pem
imageRepository: registry.aliyuncs.com/google_containers 
kind: ClusterConfiguration
kubernetesVersion: 1.32.3
networking:
  dnsDomain: cluster.local
  podSubnet: 10.244.0.0/16
  serviceSubnet: 10.96.0.0/12
proxy: {}
scheduler: {}

---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs

注意:每个节点要安装cri-dockerd

执行如下命令初始化集群,如下:

kubeadm init --config kubeadm-config.yaml

3、在其他master节点创建一下目录:

mkdir -p /etc/kubernetes/pki/

4、复制文件到其他两个master节点,如下:

scp -r /etc/kubernetes/pki/ca.* root@k8s-master02:/etc/kubernetes/pki/
scp -r /etc/kubernetes/pki/sa.* root@k8s-master02:/etc/kubernetes/pki/
scp -r /etc/kubernetes/pki/front-proxy-ca.* root@k8s-master02:/etc/kubernetes/pki
scp -r /etc/kubernetes/admin.conf root@k8s-master02:/etc/kubernetes/

5、其他master节点和node节点加入集群执行以下命令 :

kubeadm join .........

6、所有master执行如下命令:

#root用户执行以下命令:
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile

#非root用户可以执行以下命令:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

此时的所有节点还是NotReady状态,安装calico后即可变为Ready

如果一个忘记加入命令,可在master节点获取加入命令:

#有--control-plane参数就是Master节点加入命令,没有就是worker节点加入命令
kubeadm token create --print-join-command

加入失败或者需要重新加入:

# 1. 驱逐 master02
kubectl drain k8s-master02 --delete-emptydir-data --force --ignore-daemonsets

# 2. 从集群删除节点
kubectl delete node k8s-master02
# 重置
kubeadm reset -f

# 强制删除所有残留文件(解决你之前的证书报错)
rm -rf /etc/kubernetes
rm -rf /var/lib/kubelet
rm -rf /var/lib/etcd
rm -rf ~/.kube
rm -rf /etc/cni/net.d

# 清空网络规则
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X

# 重启服务(cri-dockerd)
systemctl daemon-reload
systemctl restart cri-dockerd
systemctl restart kubelet

四、安装calico(3.30.0版本),离线安装,在线会导致镜像拉取失败,如下:

1、先下载tigera-operator,首先执行如下命令:

wget https://raw.githubusercontent.com/projectcalico/calico/v3.30.0/manifests/tigera-operator.yaml

2、查看tigera-operator需要的镜像,将镜像下载回来,如下:

cat tigera-operator.yaml | grep image:

3、然后执行命令创建tigera-operator,如下:

kubectl create -f tigera-operator.yaml

4、将custom-resources.yaml下载回来,修改cidr地址为上面定义的pod地址,如下:

wget  https://raw.githubusercontent.com/projectcalico/calico/v3.30.0/manifests/custom-resources.yaml

最后执行命令创建calico,如下:

kubectl create -f custom-resources.yaml

创建后会自动创建calico-system命名空间并且运行calico相关容器,默认情况下容器都是通过docker.io地址拉取,国内无法拉取,可先通过外网机器拉回来保存到本地仓库,然后拉取到k8s节点上,再修改为对应的镜像名字即可,最后查看calico运行情况,如图:

calico安装成功后,coredns也会正常运行,如图:

五、如果某个节点加入后出现问题,要剔除这个节点,然后再重新加入,可执行如下步骤:

1、先标记节点为不可调度:

kubectl cordon <node-name>

2、驱除节点上的所有Pod,如下:

kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
  • –ignore-daemonsets:忽略 DaemonSet 管理的 Pod
  • –delete-emptydir-data:删除 emptyDir 数据

3、确认节点状态,执行kubectl get nodes,此时应该显示为:

NotReady,SchedulingDisabled

4、删除节点,如下:

kubectl delete node <node-name>

5、在要剔除的节点上重置kubeadm,如下:

kubeadm reset

6、清理网络配置,如下:

# 清理 CNI 配置
rm -rf /etc/cni/net.d
# 清理 iptables 规则
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
# 清理 IPVS 规则
ipvsadm --clear

7、重新加入集群,在Master节点生成加入命令,如下:

kubeadm token create --print-join-command

8、执行命令加入集群,如下:

kubeadm join ....

9、验证节点状态,并恢复调度,如下:

kubectl get nodes
kubectl uncordon node-name

六、部署metallb和traefik

metallb是 Kubernetes 的网络负载均衡解决方案,专门用于裸机集群或云厂商不提供负载均衡服务的环境

metallb主要功能:

  • 为k8s service提供外部访问,为LoadBalancer类型的Service分配一个外部IP,外部客户端就可以通过这个 IP 访问你的服务,就像访问云负载均衡器一样
  • 支持L2或者BGP模式:L2 模式(Layer 2):在局域网内通过 ARP 广播分配 IP,适合小型集群或内部网络,BGP 模式(Border Gateway Protocol):在大规模或企业级网络中,通过路由器动态广播 IP,更可靠、可扩展

traefik主要功能:

  • Traefik 是一个现代、动态、自动化的反向代理和负载均衡器,专为微服务和 Kubernetes 环境设计,能够自动发现服务、管理证书,并提供强大的中间件和可视化监控功能

实际的资源请求原理是:

用户 → VIP → (DNAT: VIP → Traefik ClusterIP) → Traefik Pod → 业务 Service (ClusterIP) → 业务 Pod

部署metallb:

helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb -n metallb-system --create-namespace

涉及镜像:

  • quay.io/metallb/speaker:v0.15.3
  • quay.io/frrouting/frr:10.4.1
  • quay.io/metallb/controller:v0.15.3

部署traefik:

helm repo add traefik https://traefik.github.io/charts
helm install traefik traefik/traefik -n traefik --create-namespace \
--set service.type=LoadBalancer  # 让 MetalLB 分配 VIP

涉及镜像:

  • docker.io/traefik:v3.7.1

通过metallbe给集群分配IP池:

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default
  namespace: metallb-system
spec:
  addresses:
  - 192.168.51.72-192.168.51.75 # 你的内网VIP段

---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system

IP池子中的IP主要是为多个 LoadBalancer 类型的 Service 提供独立的外部 IP,比如:每当你在 Kubernetes 中创建一个 Service 类型为 LoadBalancer,MetalLB 会从地址池中选择一个 未被使用的 IP 分配给该 Service,如果你的地址池里有多个 IP,就可以给多个 Service 分配不同的外部 IP,而不会冲突。如果某个 IP 出现冲突或者节点故障,MetalLB 可以把 Service 的外部 IP 切换到池中其他可用 IP,对于高可用或未来扩展的集群,预留多个 IP 是一种好习惯,当然,地址池可以是 单 IP(/32)

查看traefik的service,可以看到vip 已经分配了(192.168.51.72),如图:

查看VIP在哪个节点:

方法一:每个节点都会运行metallb-speaker开头的pod,负责广播,告诉其他节点,VIP目前在哪个机器上,端口是7472,如果查看当前VIP漂移到哪个机器可以,可以使用如下命令:

curl -s http://节点IP:7472/metrics | grep -i metallb_speaker_announced

方法二:通过arping命令

arping -c 2 192.168.51.72 #下图中的mac地址就是VIP所在机器的MAC地址

通过metallb+traefik实现完整的网络测试可参考metallb+traefik 网络请求测试

traefik的工作流程是:

  • 创建IngressRoute后,将域名规则写入到etcd中
  • 用户请求–>VIP–>traefik pod 监测kubernetes api 获取规则加载到内容中
  • 根据规则调用自定义的service服务
  • service 匹配后最终的pod

完整的用户请求流程:

域名-->VIP-->traefix pod 根据域名匹配IngressRoute中规则-->IngressRoute中定义的规则对应的Service--> Service匹配的最终Pod

标签