liushanyu 发布的文章

K8s v1.23.17 + Calico(Tigera Operator)部署文档

适用环境:Ubuntu 20.04/22.04、国内网络、Docker 运行时、3 节点集群

环境信息

角色主机名IP配置
mastermaster192.168.0.342C4G
workerliu-node1192.168.0.352C4G
workerliu-node2192.168.0.362C4G

一、所有节点都要做(Master + Worker 共 3 台)

1.1 系统基础配置

# 关闭 swap
swapoff -a
sed -i '/swap/d' /etc/fstab

# 关闭防火墙(或放行 6443、10250-10255 等 K8s 端口)
ufw disable

# 加载内核模块
cat > /etc/modules-load.d/k8s.conf << 'EOF'
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter

# 内核参数
cat > /etc/sysctl.d/k8s.conf << 'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system

1.2 安装 Docker

# 卸载旧版本
apt-get remove -y docker docker-engine docker.io containerd runc 2>/dev/null

# 安装依赖
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release

# 添加 Docker 官方源
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io

# 配置镜像加速 + cgroupdriver
cat > /etc/docker/daemon.json << 'EOF'
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://dockerhub.timeweb.cloud",
    "https://docker.1ms.run"
  ],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}
EOF

systemctl daemon-reload
systemctl enable docker --now
systemctl restart docker

1.3 安装 kubeadm / kubelet / kubectl

# 添加阿里云 K8s 源
curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat > /etc/apt/sources.list.d/kubernetes.list << 'EOF'
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF

# 安装指定版本
apt-get update
apt-get install -y kubeadm=1.23.17-00 kubelet=1.23.17-00 kubectl=1.23.17-00

# 锁定版本,防止 apt upgrade 误升级
apt-mark hold kubeadm kubelet kubectl

# 启动 kubelet
systemctl enable kubelet

二、Master 节点初始化

以下操作仅在 master 上执行

2.1 拉取 K8s 镜像

kubeadm config images pull \
  --kubernetes-version=v1.23.17 \
  --image-repository=registry.aliyuncs.com/google_containers
国内必须用 registry.aliyuncs.com/google_containers,默认的 k8s.gcr.io 连不上。这一步可能要等 1-2 分钟,7 个镜像拉完会有 [config/images] Pulled 输出。

2.2 初始化集群

kubeadm init \
  --kubernetes-version=v1.23.17 \
  --image-repository=registry.aliyuncs.com/google_containers \
  --pod-network-cidr=10.244.0.0/16 \
  --service-cidr=10.96.0.0/12

成功后会输出类似这样的内容,kubeadm join 那一整行保存下来,worker 加入要用:

kubeadm join 192.168.0.34:6443 --token xxxxxx \
    --discovery-token-ca-cert-hash sha256:xxxxxx

2.3 配置 kubectl

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

2.4 安装 Calico 网络插件(Tigera Operator)

# 先确认你的物理网卡名
ip addr show | grep -E "^[0-9]+:" | awk -F': ' '{print $2}'
# 常见结果:ens34、ens33、eth0 等,记下来

# 安装 Operator
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/tigera-operator.yaml

# 创建 Calico 配置(把 interface 改成你实际的网卡名)
kubectl apply -f - << 'EOF'
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  calicoNetwork:
    ipPools:
    - blockSize: 24
      cidr: 10.244.0.0/16
      encapsulation: None
      natOutgoing: Enabled
    nodeAddressAutodetectionV4:
      interface: ens.*
EOF
关键interface: ens.* 要根据你的实际网卡名修改。比如网卡是 ens34 就写 ens.*,是 eth0 就写 eth.*。写错了 calico-node 会报 no valid host interfaces found

2.5 验证 Master 就绪

# 等 30-60 秒,Calico 会自动完成部署
kubectl get pods -n calico-system
kubectl get nodes

看到 master 状态 Ready,且 calico-node、calico-kube-controllers、calico-typha 都 Running 即可。


三、Worker 节点加入集群

以下操作在每个 worker 上执行

3.1 拉取 K8s 镜像

kubeadm config images pull \
  --kubernetes-version=v1.23.17 \
  --image-repository=registry.aliyuncs.com/google_containers

3.2 加入集群

把 master 初始化时输出的 kubeadm join 命令粘贴过来执行。如果丢了,在 master 上重新生成:

# 在 master 上执行
kubeadm token create --print-join-command

把输出复制到每个 worker 上执行:

kubeadm join 192.168.0.34:6443 --token xxxxxx \
    --discovery-token-ca-cert-hash sha256:xxxxxx

3.3 回到 Master 验证

kubectl get nodes

三个节点都 Ready 即部署完成。Calico 由 Operator 自动部署到 worker 上,不需要手动干预。


四、故障排查速查

4.1 镜像拉不下来

现象ImagePullBackOffErrImagePull

原因k8s.gcr.iodocker.io 在国内被墙。

解决

  • K8s 系镜像:加 --image-repository=registry.aliyuncs.com/google_containers
  • Docker Hub 镜像:确认 /etc/docker/daemon.json 里配了 registry-mirrors

4.2 Calico 节点 CrashLoopBackOff

现象calico-node 反复重启

排查

kubectl logs -n calico-system -l k8s-app=calico-node | tail -20

常见原因

报错关键字原因解决
no valid host interfaces found网卡名不匹配改 Installation 里的 interface 正则
Block has 0 free ipsIPAM 脏数据见下方 4.5 重置
connection is unauthorizedRBAC 权限不足重新 apply tigera-operator.yaml

4.3 节点 NotReady

通常是网络插件还没部署到该节点。Operator 会在大约 30-60 秒内自动完成,等一等即可。

kubectl get pods -n calico-system -o wide

确认该节点上已经有 calico-node 在运行。

4.4 忘记 join 命令

# 在 master 上重新生成
kubeadm token create --print-join-command

4.5 完全重置(重来)

# 在需要重置的节点上执行
kubeadm reset -f
rm -rf /etc/cni/net.d/*
rm -rf /var/lib/calico /var/lib/cni
iptables -F && iptables -t nat -F && iptables -t mangle -F
ip link delete cni0 2>/dev/null
ip link delete tunl0 2>/dev/null
systemctl restart docker

五、关键注意事项

  1. Pod CIDR(10.244.0.0/16)不能和公司内网网段重叠,否则路由冲突
  2. Service CIDR(10.96.0.0/12)不能和 Pod CIDR 重叠
  3. 国内环境永远用 registry.aliyuncs.com/google_containers 替代 k8s.gcr.io
  4. Calico 用 Tigera Operator 安装,不要手写 yaml — Operator 自动处理 RBAC、CNI 二进制、IPAM、证书
  5. Worker 节点不需要配 kubectl — 所有管理操作在 master 上执行
  6. 安装后锁定版本apt-mark hold kubeadm kubelet kubectl 防止误升级导致集群版本不一致

02 K8S 环境准备及基础优化

2.1 环境准备

主机名IP 地址操作系统硬件配置
master34192.168.0.34Ubuntu 22.04 LTS2C+,4G+,50G+
worker35192.168.0.35Ubuntu 22.04 LTS2C+,4G+,50G+
worker36192.168.0.36Ubuntu 22.04 LTS2C+,4G+,50G+
💡 部署 K8S 集群建议使用 root 用户操作。

2.2 Linux 基础优化

1)关闭 swap 分区

# 临时关闭,服务器重启后配置失效
swapoff -a && sysctl -w vm.swappiness=0

# 基于配置文件关闭,重启后依旧有效
sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab

2)确保各个节点 MAC 地址或 product_uuid 唯一

apt install net-tools

# 查看 MAC 地址(三节点必须互不相同)
root@master34:~# ifconfig ens33 | grep ether | awk '{print $2}'
00:0c:29:75:d7:32
root@worker35:~# ifconfig ens33 | grep ether | awk '{print $2}'
00:0c:29:4f:55:b8
root@worker36:~# ifconfig ens33 | grep ether | awk '{print $2}'
00:0c:29:ad:6c:49

# 查看 product_uuid(同样必须唯一)
root@master34:~# cat /sys/class/dmi/id/product_uuid
0c9a4d56-ca43-c602-d605-08769975d732
root@worker35:~# cat /sys/class/dmi/id/product_uuid
93d54d56-9cba-7fda-1a34-1fdc894f55b8
root@worker36:~# cat /sys/class/dmi/id/product_uuid
b1b24d56-9a26-b448-33f8-b1dc15ad6c49
📚 温馨提示:一般来讲,硬件设备会拥有唯一的地址,但有些虚拟机的地址可能会重复。Kubernetes 使用这些值来唯一确定集群中的节点,如果这些值在每个节点上不唯一,可能会导致安装失败。

3)检查网络节点是否互通

简而言之,就是检查 K8S 集群各节点是否互通,可以使用 ping 命令来测试:

ping baidu.com -c 10

4)允许 iptables 检查桥接流量

cat <<EOF | tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

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

sysctl --system

5)检查端口是否被占用

参考链接:K8S 官方文档 - 端口与协议

对照官方端口表,检查 master 节点和 worker 节点的各组件端口是否被占用。

6)Linux 内核优化

cat > /etc/sysctl.d/k8s.conf <<'EOF'
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv6.conf.all.disable_ipv6 = 1
fs.may_detach_mounts = 1
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.netfilter.nf_conntrack_max=2310720
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl =15
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 327680
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.ip_conntrack_max = 65536
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_timestamps = 0
net.core.somaxconn = 16384
EOF

# 加载所有系统级的内核参数配置文件,并立即生效
sysctl --system

2.3 安装 ipvsadm 以实现 kube-proxy 的负载均衡

1)安装 ipvsadm 等相关工具

apt -y install ipvsadm ipset sysstat conntrack

2)所有节点创建开机自动加载的模块配置文件

cat > /etc/modules-load.d/ipvs.conf << 'EOF'
ip_vs
ip_vs_lc
ip_vs_wlc
ip_vs_rr
ip_vs_wrr
ip_vs_lblc
ip_vs_lblcr
ip_vs_dh
ip_vs_sh
ip_vs_fo
ip_vs_nq
ip_vs_sed
ip_vs_ftp
ip_vs_sh
nf_conntrack
ip_tables
ip_set
xt_set
ipt_set
ipt_rpfilter
ipt_REJECT
ipip
EOF

2.4 安装 docker 环境

1)安装 docker

wget http://192.168.14.253/Resources/Docker/scripts/lsyedu-autoinstall-docker-docker-compose.tar.gz
tar xf lsyedu-autoinstall-docker-docker-compose.tar.gz
./install-docker.sh i

2)检查 cgroup 驱动是否是 systemd

root@master231:~# docker info | grep "Cgroup Driver:"
 Cgroup Driver: systemd
root@worker232:~# docker info | grep "Cgroup Driver:"
 Cgroup Driver: systemd
root@worker233:~# docker info | grep "Cgroup Driver:"
 Cgroup Driver: systemd

2.5 所有节点安装 kubeadm、kubelet、kubectl

1)软件包说明

软件包形象比喻作用
kubeadm盖房子(一次性)用来初始化 K8S 集群的工具
kubelet看房子(长期运行)底层用到了静态 Pod 技术启动 master 组件及 Pod 生命周期管理
kubectl管房子(发号施令)用来与 K8S 集群通信的命令行工具
⚠️ kubeadm 不能帮你安装或者管理 kubelet 或 kubectl,所以你需要确保它们与通过 kubeadm 安装的控制平面(master)的版本相匹配,否则存在版本偏差风险,可能导致预料之外的错误。控制平面与 kubelet 相差一个次要版本是支持的,但 kubelet 的版本不可以超过 API SERVER 的版本(例如 1.7.0 的 kubelet 可以兼容 1.8.0 的 API SERVER,反之则不可以)。

2)K8S 所有节点配置软件源

apt-get update && apt-get install -y apt-transport-https
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update

3)查看当前环境支持的 K8S 版本

root@master231:~# apt-cache madison kubeadm
   kubeadm |  1.28.2-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.28.1-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.28.0-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   ...
   kubeadm | 1.23.17-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm | 1.23.16-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   ...

4)所有节点安装 kubelet、kubeadm、kubectl

apt-get -y install kubelet=1.23.17-00 kubeadm=1.23.17-00 kubectl=1.23.17-00
📦 离线安装方式:软件包已打包好放在 nginx 站点目录,可跳过上面 2~4 步:
wget http://192.168.14.253/Resources/Kubernetes/K8S%20Cluster/kubeadm/softwares/lsyedu-kubeadm-kubectl-kubelet-1.23.17.tar.gz
tar xf lsyedu-kubeadm-kubectl-kubelet-1.23.17.tar.gz
dpkg -i *.deb

彩蛋:Ubuntu 打包软件

root@worker35:~# cd /var/cache/apt/archives
root@worker35:/var/cache/apt/archives# ls -1 *.deb | xargs tar zcf lsyedu-kubeadm-kubectl-kubelet-1.23.17.tar.gz
root@worker35:/var/cache/apt/archives# tar tf lsyedu-kubeadm-kubectl-kubelet-1.23.17.tar.gz
apt-transport-https_2.4.14_all.deb
conntrack_1%3a1.4.6-2build2_amd64.deb
cri-tools_1.26.0-00_amd64.deb
ebtables_2.0.11-4build2_amd64.deb
kubeadm_1.23.17-00_amd64.deb
kubectl_1.23.17-00_amd64.deb
kubelet_1.23.17-00_amd64.deb
kubernetes-cni_1.2.0-00_amd64.deb
socat_1.7.4.1-3ubuntu4_amd64.deb

5)检查各组件版本

参考链接:安装 kubectl

root@master34:~# kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.17", GitCommit:"953be8927218ec8067e1af2641e540238ffd7576", GitTreeState:"clean", BuildDate:"2023-02-22T13:33:14Z", GoVersion:"go1.19.6", Compiler:"gc", Platform:"linux/amd64"}

root@master34:~# kubectl version
Client Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.17", GitCommit:"953be8927218ec8067e1af2641e540238ffd7576", GitTreeState:"clean", BuildDate:"2023-02-22T13:34:27Z", GoVersion:"go1.19.6", Compiler:"gc", Platform:"linux/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?

root@master34:~# kubelet --version
Kubernetes v1.23.17
💡 此时 kubectl versionlocalhost:8080 refused正常现象:集群尚未初始化,kubectl 还没有可连接的 API Server,完成后续集群初始化后即恢复。worker232、worker233 验证输出与上面一致(均为 v1.23.17)。

2.6 时区优化及快照

1)检查时区

ln -svf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ll /etc/localtime

# 以 RFC 2822 格式显示当前时间和时区
date -R
Tue, 06 Jan 2026 10:40:14 +0800

2)验证 CPU 核心数

root@master34:~# lscpu | grep ^CPU\(s\)
CPU(s): 2
root@worker34:~# lscpu | grep ^CPU\(s\)
CPU(s): 2
root@worker34:~# lscpu | grep ^CPU\(s\)
CPU(s): 2

3)重启操作系统

reboot

4)验证加载的模块

lsmod | grep --color=auto -e ip_vs -e nf_conntrack
free -h

以 master34 为例(worker35、worker36 输出一致):

nf_conntrack_netlink    49152  0
nfnetlink              20480  5 nft_compat,nf_conntrack_netlink,nf_tables,ip_set
ip_vs_ftp              16384  0
nf_nat                 49152  3 nft_chain_nat,xt_MASQUERADE,ip_vs_ftp
ip_vs_sed              16384  0
ip_vs_nq               16384  0
ip_vs_fo               16384  0
ip_vs_sh               16384  0
ip_vs_dh               16384  0
ip_vs_lblcr            16384  0
ip_vs_lblc             16384  0
ip_vs_wrr              16384  0
ip_vs_rr               16384  0
ip_vs_wlc              16384  0
ip_vs_lc               16384  0
ip_vs                 176128  24 ip_vs_wlc,ip_vs_rr,ip_vs_dh,ip_vs_lblcr,ip_vs_sh,ip_vs_fo,ip_vs_nq,ip_vs_lblc,ip_vs_wrr,ip_vs_lc,ip_vs_sed,ip_vs_ftp
nf_conntrack          172032  5 xt_conntrack,nf_nat,nf_conntrack_netlink,xt_MASQUERADE,ip_vs
nf_defrag_ipv6         24576  2 nf_conntrack,ip_vs
nf_defrag_ipv4         16384  1 nf_conntrack
libcrc32c              16384  6 nf_conntrack,nf_nat,btrfs,nf_tables,raid456,ip_vs

root@master34:~# free -h
               total        used        free      shared  buff/cache   available
Mem:           3.8Gi       336Mi       3.0Gi       1.0Mi       420Mi       3.2Gi
Swap:             0B          0B          0B
📚 温馨提示:Linux kernel 4.19+ 版本已经将之前的 nf_conntrack_ipv4 模块更名为 nf_conntrack 模块哟~

5)关机拍快照

关机并拍摄快照,建议快照名称:k8s基础优化环境准备就绪

什么是k8s

参考官网链接:https://kubernetes.io/zh-cn/
kubernetes:用于自动部署、扩缩和管理容器化应用程序的开源系统

  • 它将组成应用程序的容器组合成逻辑单元,以便于管理和服务发现
    云上的k8s:华为云:CCE;阿里云:ACK;腾讯云:TKE;亚马逊云:EKS;Ucloud:Uk8s
    k8s生态:kubesphere,rancher,kuboard等

k8s架构

  • master|control plane相当于一个控制面板
    -- etcd:数据库,主要用于存储k8s集群数据,端口:2379
    -- api-server:k8s集群的控制访问入口,端口:6443
    -- scheduler:调度器,负责调度的相关工作
    -- controller manager:负责维护k8s集群的状态
  • slave |worker工作者
    -- kubelet:负责pod生命周期及worker节点状态监控并周期性的上报给api-server
    -- kube-proxy:负责代理pod请求,实现集群内部或集群外部的负载均衡和服务发现
  • CNI:容器网络接口------主要负责k8s集群worker节点的pod网络通信
    -- flannel、calico、canal、cilium

k8s常用资源介绍

  1. pods:一组容器的集合。所有容器默认共享网络名称空间,也可以基于存储卷的方式实现数据共享
  2. replicationcontroller:副本控制器。基于标签控制指定pod副本数量始终存活(官方已弃用)
  3. replicaset:副本集。基于标签控制指定pod副本数量始终存活,比rc更轻量级
  4. deployment:部署控制器。用于部署服务,支持声明式更新。底层控制pod副本数量是基于rs实现
  5. statefulset:状态控制器。用于部署有状态服务。可以为每个pod副本提供独立存储,网络表示
  6. daemonset:守护进程控制器。可以让每个工作节点有且只有一个pod运行
  7. jobs:一次性控制器。可以执行一次性任务
  8. cronjobs:周期性控制器。底层基于jobs控制器实现
  9. configmaps:配置管理。主要用来存储k8s应用的配置信息
  10. secrets:存储敏感数据。会将数据基于base64编码
  11. namespaces:名称空间。用来隔离k8s集群资源
  12. services:服务。用来代理pod请求,底层基于标签关联pod。相当于四层代理
  13. ingress:相当于七层代理,底层需要调用svc资源
  14. persistentvolume:存储卷。底层关联后端的存储系统
  15. storageclass:存储类。可以实现自动管理pv
  16. persistentvolumeclaim:存储卷声明,底层会自动关联相应的pv或sc
  17. horizontalpodautosale:水平pod伸缩。实现pod自动伸缩功能
  18. endpoint:关联后端的ip地址,一般和svc共同使用,比如映射内网ip地址
  19. serviceaccout:服务账号。一般是pod用来进行身份认证的
  20. role:命名空间内权限
  21. clusterrole:集群全局权限
  22. rolebinding:把role绑定给用户/sa
  23. clusterrolebinding:把clusterrole绑定给用户/sa
  24. networkpolicy:给pod添加防火墙
  25. endpointslice:endopoints升级版,大规模用
  26. limitrange:命名空间资源限制
  27. resourcequota:命名空间资源配额
  28. event:获取集群事件
  29. node:集群的节点
  30. componentstatus:用于查看k8s核心控制平面组件的健康状态

附加组件

  1. helm
  2. traefik
  3. coredns
  4. dashboard
  5. kuboard
  6. prometheus
  7. elasticstack
  8. rook ......

k8s网络类型

k8s中有三种网络类型:
-- 物理机网络:真实的机器ip
-- pod网络:给每个pod分配的虚拟ip
-- service网络:固定的ip

k8s集群部署方式

-- kubeadm
-- 二进制
-- 第三方组件
(1)kubesphere
(2)rancher
(3)kuboard
(4)kubeasz
(5)云产品: ACK、CCE、TKE、EKS、UK8S
(6)其他:minikube、kind