Ubuntu通过kubeadm安装k8s集群
环境准备:
| 系统 | ubuntu |
| 版本号 | 24.04 |
| docker版本 | 28.0.4 |
| kubernetes版本 | v1.32 |
| k8s-master01 | 192.168.49.20(至少2G内存,2核cpu) |
| k8s-master02 | 192.168.49.21(至少2G内存,2核cpu) |
| k8s-master03 | 192.168.49.22(至少2G内存,2核cpu) |
| k8s-node01 | 192.168.49.23(至少2G内存) |
| k8s-node02 | 192.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


