k8sk8s镜像CentOS 7 单机部署 Kubernetes v1.28.2 完整避坑指南
建材王哥
CentOS 7 单机部署 Kubernetes v1.28.2 完整避坑指南
前言
本文详细记录了在 CentOS 7.9 系统上,使用 Kubeadm 部署 Kubernetes v1.28.2 单机集群的全过程。
部署环境:
- 操作系统:CentOS 7.9
- Kubernetes 版本:v1.28.2
- 容器运行时:Containerd
- 网络插件:Flannel v0.22.0
- 服务器配置:建议 2核4G 以上
第一阶段:系统环境准备
在安装 Kubernetes 之前,必须对 Linux 系统进行一系列内核和网络配置,否则后续初始化会频繁报错。
1. 关闭 Swap 分区
原理:Kubernetes 为了保证性能和稳定性,要求关闭 Swap。如果开启了 Swap,Kubelet 将无法启动。
1 2 3 4 5
| swapoff -a
sed -i '/swap/d' /etc/fstab
|
2. 关闭 SELinux 和防火墙
原理:SELinux 和防火墙的安全策略可能会拦截 K8s 组件之间的网络通信(如 API Server 和 Kubelet 之间),导致集群异常。初学者建议先关闭,熟练后再配置策略。
1 2 3 4 5 6 7 8 9
| setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config
systemctl stop firewalld systemctl disable firewalld
|
3. 配置内核参数
原理:K8s 的网络插件(如 Flannel)需要网桥过滤器支持,且需要开启 IPv4 转发,否则容器无法跨节点通信。
1 2 3 4 5 6 7 8 9 10 11 12
| modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF
sysctl --system
|
第二阶段:安装 Containerd(容器运行时)
K8s 1.24 版本之后不再直接支持 Docker,而是使用 Containerd 作为容器运行时。
1. 安装 Containerd
避坑点:CentOS 默认 yum 源的 Containerd 版本过旧,不支持 K8s 1.28 所需的 CRI v1 接口,必须安装较新版本。
1 2 3 4 5 6 7 8
| yum install -y yum-utils
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y containerd.io
|
2. 配置 Containerd
避坑点:Containerd 默认配置不支持 K8s 的 SystemdCgroup 驱动,必须修改配置,否则 Kubelet 会报 Cgroup 不匹配错误。同时配置国内镜像源加速镜像下载。
1 2 3 4 5 6 7 8 9 10 11
| containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
sed -i 's#sandbox_image = "registry.k8s.io/pause.*"#sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"#g' /etc/containerd/config.toml
systemctl enable --now containerd
|
3. 配置代理(关键步骤)
遇到的问题:国内网络环境无法直接访问 Docker Hub 和 GitHub,导致 Flannel 等镜像下载失败。
解决方案:为主机配置代理,并让 Containerd 使用该代理。
前提:假设你的代理客户端(如 V2RayN)已开启“允许来自局域网的连接”,且监听端口为 10808。请将 172.20.10.4 替换为你实际的主机 IP。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| mkdir -p /etc/systemd/system/containerd.service.d
cat > /etc/systemd/system/containerd.service.d/http_proxy.conf << EOF [Service] Environment="HTTP_PROXY=http://172.20.10.4:10808" Environment="HTTPS_PROXY=http://172.20.10.4:10808" Environment="NO_PROXY=127.0.0.1,localhost,192.168.88.130" EOF
systemctl daemon-reload systemctl restart containerd
|
第三阶段:安装 Kubeadm, Kubelet, Kubectl
1. 配置 K8s 阿里云源
原理:K8s 官方源在国外,速度极慢甚至无法访问,使用阿里云镜像源加速下载。
1 2 3 4 5 6 7 8
| cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled=1 gpgcheck=0 repo_gpgcheck=0 EOF
|
2. 安装指定版本组件
1 2 3 4 5 6
|
yum install -y kubeadm-1.28.2 kubelet-1.28.2 kubectl-1.28.2
systemctl enable --now kubelet
|
第四阶段:初始化 Kubernetes 集群
1. 执行初始化命令
避坑点:
--apiserver-advertise-address 必须填写当前虚拟机的真实内网 IP,不能填错,否则 etcd 无法启动。
--image-repository 指定阿里云镜像源,解决拉取核心组件超时问题。
1 2 3 4 5 6 7 8
| kubeadm init \ --apiserver-advertise-address=192.168.88.130 \ --image-repository registry.aliyuncs.com/google_containers \ --kubernetes-version v1.28.2 \ --service-cidr=10.96.0.0/12 \ --pod-network-cidr=10.244.0.0/16 \ --ignore-preflight-errors=NumCPU
|
2. 配置 Kubectl 权限
原理:Kubectl 需要读取 admin.conf 证书才能操作集群。
1 2 3 4 5 6 7 8
| mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
|
3. 允许 Master 节点运行 Pod(单机必做)
原理:默认 Master 节点带有“污点”,禁止调度业务 Pod。单机部署需要移除污点。
1 2
| kubectl taint nodes --all node-role.kubernetes.io/control-plane-
|
第五阶段:安装网络插件(Flannel)
这一步是网络问题的重灾区。Flannel 镜像仓库地址已迁移,且国内直接拉取困难。
1. 准备 Flannel 部署文件
创建 kube-flannel.yml 文件,内容如下(已包含国内镜像源配置):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
| 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 kind: ConfigMap metadata: name: kube-flannel-cfg namespace: kube-flannel labels: tier: node k8s-app: flannel app: flannel data: cni-conf.json: | { "name": "cbr0", "cniVersion": "1.0.0", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, { "type": "portmap", "capabilities": { "portMappings": true } } ] } net-conf.json: | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan" } } --- apiVersion: apps/v1 kind: DaemonSet metadata: name: kube-flannel-ds namespace: kube-flannel labels: tier: node app: flannel k8s-app: flannel spec: selector: matchLabels: app: flannel k8s-app: flannel template: metadata: labels: tier: node app: flannel k8s-app: flannel spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/os operator: In values: - linux hostNetwork: true priorityClassName: system-node-critical tolerations: - operator: Exists effect: NoSchedule serviceAccountName: flannel initContainers: - name: install-cni-plugin image: docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.2.0 command: - cp args: - -f - /flannel - /opt/cni/bin/flannel volumeMounts: - name: cni-plugin mountPath: /opt/cni/bin - name: install-cni image: docker.io/rancher/mirrored-flannelcni-flannel:v0.22.0 command: - cp args: - -f - /etc/kube-flannel/cni-conf.json - /etc/cni/net.d/10-flannel.conflist volumeMounts: - name: cni mountPath: /etc/cni/net.d - name: flannel-cfg mountPath: /etc/kube-flannel/ containers: - name: kube-flannel image: docker.io/rancher/mirrored-flannelcni-flannel:v0.22.0 command: - /opt/bin/flanneld args: - --ip-masq - --kube-subnet-mgr resources: requests: cpu: "100m" memory: "50Mi" securityContext: privileged: false capabilities: add: ["NET_ADMIN", "NET_RAW"] env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: EVENT_QUEUE_DEPTH value: "5000" volumeMounts: - name: run mountPath: /run/flannel - name: flannel-cfg mountPath: /etc/kube-flannel/ - name: xtables-lock mountPath: /run/xtables.lock volumes: - name: run hostPath: path: /run/flannel - name: cni-plugin hostPath: path: /opt/cni/bin - name: cni hostPath: path: /etc/cni/net.d - name: flannel-cfg configMap: name: kube-flannel-cfg - name: xtables-lock hostPath: path: /run/xtables.lock type: FileOrCreate
|
2. 解决 Flannel 镜像拉取问题(核心难点)
遇到的问题:配置文件中请求的镜像名 rancher/mirrored-flannelcni-flannel 在 Docker Hub 上已更名,直接拉取会报 Not Found。
解决方案:
- 拉取新名字的镜像。
- 使用
ctr 命令给镜像打上旧名字的标签。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| crictl pull docker.io/flannel/flannel:v0.22.0
crictl pull docker.io/flannel/flannel-cni-plugin:v1.2.0
ctr -n k8s.io images tag \ docker.io/flannel/flannel:v0.22.0 \ docker.io/rancher/mirrored-flannelcni-flannel:v0.22.0
ctr -n k8s.io images tag \ docker.io/flannel/flannel-cni-plugin:v1.2.0 \ docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.2.0
|
注:crictl 是 K8s 专用镜像工具,ctr -n k8s.io 是 Containerd 的原生工具,K8s 的镜像存储在 k8s.io 命名空间下,所以打标签时必须指定 -n k8s.io。
3. 部署 Flannel
1 2
| kubectl apply -f kube-flannel.yml
|
第六阶段:最终验证
等待约 1-2 分钟,让 Pod 启动。
1 2 3 4 5 6 7
| kubectl get nodes
kubectl get pods -A
|
常见问题与解决方案总结
| 现象/报错 |
原因 |
解决方案 |
Port 6443 is in use |
上次初始化残留进程占用端口 |
执行 kubeadm reset -f 并重启 kubelet/containerd。 |
connection refused |
API Server 未启动或配置文件 IP 错误 |
检查 admin.conf 中的 IP 是否为本机 IP;检查 containerd 状态。 |
ImagePullBackOff |
镜像拉取失败(网络或镜像名错误) |
配置代理或使用阿里云源;注意 Flannel 镜像是否需要打标签改名。 |
CrashLoopBackOff (etcd) |
IP 地址配置错误 |
kubeadm init 时必须确保 --apiserver-advertise-address 是本机真实 IP。 |
CRI v1 runtime API is not implemented |
Containerd 版本过旧或 CRI 插件未开启 |
安装新版 Containerd,确保 SystemdCgroup = true。 |
NotReady |
网络插件未安装 |
安装 Flannel 或 Calico。 |
结语
通过本文,你不仅成功部署了一个单机 K8s 集群,还深入了解了 Linux 内核参数、容器运行时、网络代理以及 K8s 镜像管理的细节。希望这篇避坑指南能帮助你在 K8s 的学习之路上少走弯路!