2433 字
12 分钟
Kubernetes 1.14.1 集群部署实录(CentOS 7)

记录一次课程实验环境下的 Kubernetes 单 master + 单 node 集群搭建:kubeadm 初始化、flannel 网络、Dashboard、Nginx NodePort 发布,以及一路上踩过的 Docker 版本、镜像格式、DNS 和时间同步的坑。

部署时间:2026-10-22

环境规划#

实验指导书的原始规划是 master 192.168.100.60、node 192.168.100.61,实际环境与指导书不一致,本文按真实 IP 记录:

角色主机名IP说明
mastermaster192.168.100.233控制面、Dashboard
nodenode192.168.100.144工作节点
网关 / DNS-192.168.100.2VMware NAT

软件版本:

组件版本
操作系统CentOS 7 (kernel 3.10.0-1160)
Docker18.09.6
kubeadm / kubelet / kubectl1.14.1
Pod 网段10.16.0.0/16
网络插件flannel v0.11.0-amd64

提示:如果你的环境 IP 不同,按同样思路替换即可,关键是两台机器的 /etc/hosts、kubeadm 的 --apiserver-advertise-address 和 join 命令里的地址保持一致。

1. 基础环境配置(master、node 均执行)#

1.1 配置主机名解析#

两台机器的 /etc/hosts 保持一致:

Terminal window
vi /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.100.233 master
192.168.100.144 node

设置主机名:

Terminal window
# master
hostnamectl set-hostname master
# node
hostnamectl set-hostname node

验证:

Terminal window
getent hosts master
getent hosts node
ping -c 2 master

这里踩过一个坑:/etc/hosts 里把 node 拼成了 ndoe,同时没写 master 的条目,导致后面 chrony 一个时间源都没有。hosts 是整套集群的基础,先确认再往下走。

1.2 关闭防火墙、SELinux、swap#

Terminal window
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
swapoff -a
sed -i '/ swap / s/^/#/' /etc/fstab

1.3 内核参数#

Terminal window
cat >> /etc/sysctl.conf << EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
modprobe br_netfilter
sysctl -p

br_netfilter 是 net.bridge.* 这些参数存在的前提;不加载模块直接 sysctl -p 会报 No such file or directory。

1.4 开启 IPVS 相关模块#

Terminal window
vi /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
Terminal window
chmod 755 /etc/sysconfig/modules/ipvs.modules
bash /etc/sysconfig/modules/ipvs.modules
lsmod | grep -e ip_vs -e nf_conntrack_ipv4

1.5 时间同步(chrony)#

master:

Terminal window
yum -y install chrony
vi /etc/chrony.conf

删除默认的 4 行 server *.centos.pool.ntp.org,加入:

local stratum 10
server master iburst
allow all
Terminal window
systemctl start chronyd
systemctl enable chronyd
chronyc sources -v

node:

Terminal window
yum -y install chrony
vi /etc/chrony.conf

删除默认 4 行 server,加入:

server master iburst
Terminal window
systemctl start chronyd
systemctl enable chronyd
chronyc sources

出现 ^* master 即同步成功。若显示 0 个源,先查 getent hosts master 和 journalctl -u chronyd。

2. 准备 YUM 源#

课程实验是离线环境,源分两部分:

  • CentOS 7 ISO:基础系统包(本文环境用的是 CentOS-7-x86_64-Minimal-2009.iso,包比 DVD 少,缺什么再补)
  • K8S.tar.gz 解压出的 Kubernetes/ 目录:kubeadm/kubelet/kubectl、docker-ce 等 RPM

本实验 master 和 node 都使用本地 file:// 源,不使用 FTP。node 上原本没有 K8S 包,需要从 master 把 /opt/K8S 整个复制过去,保持路径一致。

2.1 上传安装介质#

先把两个文件通过 SFTP 或 VMware 共享文件夹传到 master 的 /root:

  • CentOS-7-x86_64-Minimal-2009.iso
  • K8S.tar.gz(课程提供的离线包)
Terminal window
ls -lh /root/CentOS-7-x86_64-Minimal-2009.iso /root/K8S.tar.gz

K8S.tar.gz 解压后主要有:

  • Kubernetes/:kubeadm/kubelet/kubectl、docker-ce 等 RPM
  • images/:各组件镜像 tar
  • yaml/:flannel、Dashboard 等清单
  • kubernetes_base.sh:批量导入镜像的脚本

2.2 master 准备源#

Terminal window
cd /root
# base 源:把 ISO 内容放到 /opt/centos
mkdir -p /opt/centos
mount /dev/cdrom /mnt
cp -r /mnt/* /opt/centos/
# 离线 RPM:解压 K8S 包
mkdir -p /opt/K8S
tar -zxf K8S.tar.gz -C /opt/K8S

配置 repo(master、node 完全相同):

Terminal window
cd /etc/yum.repos.d/
rm -f *
vi local.repo
[centos]
name=centos
baseurl=file:///opt/centos
gpgcheck=0
[K8S]
name=K8S
baseurl=file:///opt/K8S/Kubernetes
gpgcheck=0
Terminal window
yum clean all
yum makecache

2.3 node 同步源目录#

Terminal window
# master → node,保持 /opt/K8S 路径一致
scp -r /opt/K8S root@192.168.100.144:/opt/
# 基础源目录同样需要
scp -r /opt/centos root@192.168.100.144:/opt/

若 node 上已存在 /opt/K8S,先把旧目录移走,避免 scp 嵌套成 /opt/K8S/K8S。

然后在 node 上写一份和 master 完全相同的 local.repo:

Terminal window
cd /etc/yum.repos.d/
rm -f *
vi local.repo
[centos]
name=centos
baseurl=file:///opt/centos
gpgcheck=0
[K8S]
name=K8S
baseurl=file:///opt/K8S/Kubernetes
gpgcheck=0
Terminal window
yum clean all
yum makecache

不想把 ISO 内容复制到 node 时,才需要 master 开 FTP/HTTP 共享,让 node 的 [centos] 指向 ftp://192.168.100.233/centos;本实验两台机器都用本地源,最省事。

3. 安装 Docker 18.09.6#

Docker 的 RPM 已经包含在上一节的 [K8S] 离线源里,不需要额外添加 Docker 官方源:

Terminal window
yum -y install docker-ce

yum 会自动解析依赖,装上 docker-ce、docker-ce-cli、containerd.io 三个包。离线源里只有 18.09.6,所以不会装到新版本。

为什么不装最新版?kubelet 1.14 官方验证的是 Docker 18.09,而且 flannel 等 2018 年的老镜像是 Docker schema1 格式,Docker 26 默认拒绝使用,会直接导致节点 NotReady。若额外启用了 Docker 官方源,yum install docker-ce 就会装到 26.x,务必避免。

配置 daemon.json:

Terminal window
mkdir -p /etc/docker
vi /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}

Docker Hub 直连被 DNS 污染的环境,建议同时配置镜像加速器(按需保留):

{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://docker.m.daocloud.io"]
}
Terminal window
systemctl daemon-reload
systemctl start docker
systemctl enable docker
docker info | grep -E "Server Version|Cgroup"

应看到 Server Version: 18.09.6、Cgroup Driver: systemd。kubelet 和 Docker 的 cgroup 驱动必须一致。

4. 安装 kubeadm、kubelet、kubectl(1.14.1)#

master 和 node 都执行:

Terminal window
yum -y install kubelet-1.14.1 kubeadm-1.14.1 kubectl-1.14.1
systemctl enable kubelet
systemctl start kubelet

初始化完成前 kubelet 会反复重启,这是正常现象,不用管。

5. 加载离线镜像#

第 2 节已经把 K8S 包解压到 /opt/K8S,1.14.1 所需的镜像都在 /opt/K8S/images。master 上:

Terminal window
cd /opt/K8S
./kubernetes_base.sh

脚本会批量 docker load 镜像目录中的 tar 包。确认:

Terminal window
docker images | grep -E "kube-|etcd|flannel|coredns|pause"

6. kubeadm 初始化 master#

Terminal window
kubeadm init \
--kubernetes-version="v1.14.1" \
--image-repository=registry.aliyuncs.com/google_containers \
--apiserver-advertise-address=192.168.100.233 \
--pod-network-cidr=10.16.0.0/16

参数说明:

  • --apiserver-advertise-address:必须是 master 的真实 IP(不是指导书里的 .60)
  • --pod-network-cidr:必须与 flannel 的 Network 配置一致
  • --image-repository:与离线镜像的名称前缀对应

初始化成功后按提示配置 kubectl:

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

检查控制面:

Terminal window
kubectl get cs
kubectl get nodes

7. 部署 flannel 网络#

Terminal window
cd /opt/K8S/yaml
kubectl apply -f kube-flannel.yaml
kubectl get pods -n kube-system -o wide

master 上的 kube-flannel-ds-amd64-xxx Running 后,控制面节点会先变为 Ready。

8. node 加入集群#

8.1 在 node 上准备离线镜像#

第 2 节已经把 /opt/K8S 同步到了 node,镜像就在 /opt/K8S/images,直接运行加载脚本:

Terminal window
cd /opt/K8S
./kubernetes_base.sh
docker images | grep -E "kube-|etcd|flannel|coredns|pause"

若镜像目录或脚本不完整,至少确保 pause、kube-proxy、flannel 镜像存在,可用 docker save / docker load 从 master 补齐。

8.2 执行加入命令#

在 master 上生成 join 命令(token 默认 24 小时过期,过期可重新生成):

Terminal window
kubeadm token create --print-join-command

在 node 上执行打印出的命令,例如:

Terminal window
kubeadm join 192.168.100.233:6443 --token xxxxxx.xxxxxxxxxxxxxxxx \
--discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

成功标志:

This node has joined the cluster

8.3 踩坑:node 一直 NotReady,flannel 镜像 ImagePullBackOff#

现象:

kube-flannel-ds-amd64-xxxxx 0/1 Init:ImagePullBackOff

查事件:

Terminal window
kubectl describe pod -n kube-system kube-flannel-ds-amd64-xxxxx | tail -20

如果看到:

Failed to pull image "quay.io/coreos/flannel:v0.11.0-amd64":
[DEPRECATION NOTICE] Docker Image Format v1 and Docker Image manifest version 2,
schema 1 support is disabled by default ...

原因就找到了:这个 flannel 镜像是 Docker schema1 格式,node 上的 Docker 26 拒绝使用。解法:

  1. 把 node 的 Docker 降级到 18.09.6(与 master 一致);
  2. 在 node 上确保镜像存在;
  3. 删掉 flannel Pod 触发重建。

按本实验离线源正常安装的话,node 的 Docker 本来就会是 18.09.6,不会出现这个问题;这里是环境中混入了外来的 Docker 26。

降级 Docker(node):

Terminal window
systemctl stop kubelet
systemctl stop docker
yum remove -y docker-ce docker-ce-cli containerd.io docker-ce-rootless-extras \
docker-buildx-plugin docker-compose-plugin
# containerd 1.6 的元数据 1.2 读不了,挪走旧状态
mv /var/lib/containerd /var/lib/containerd.bak
yum install -y docker-ce-18.09.6 docker-ce-cli-18.09.6 containerd.io-1.2.6-3.3.el7

daemon.json 保持 cgroup systemd,然后启动 Docker 和 kubelet:

Terminal window
systemctl daemon-reload
systemctl start docker
systemctl enable docker
docker info | grep -E "Server Version|Cgroup"
systemctl start kubelet
systemctl status kubelet --no-pager

加载 flannel 镜像(node):

Terminal window
# 若 node 上没有镜像包,从 master 导出再传过去
# master:
docker save -o /root/flannel.tar quay.io/coreos/flannel:v0.11.0-amd64
scp /root/flannel.tar root@192.168.100.144:/root/
# node:
docker load -i /root/flannel.tar
docker images | grep flannel

触发重建:

Terminal window
kubectl delete pod -n kube-system kube-flannel-ds-amd64-xxxxx
kubectl get pods -n kube-system -o wide
kubectl get nodes

两个节点都 Ready 后:

NAME STATUS ROLES AGE VERSION
master Ready master ... v1.14.1
node Ready <none> ... v1.14.1

9. 部署 Dashboard#

Terminal window
cd /opt/K8S/yaml
kubectl create -f kubernetes-dashboard.yaml
kubectl create -f dashboard-adminuser.yaml

检查:

Terminal window
kubectl get pods -n kube-system -o wide
kubectl get svc -n kube-system

服务类型为 NodePort:

kubernetes-dashboard NodePort 10.102.208.171 <none> 443:30000/TCP

本次环境中 Dashboard Pod 调度到了 master,所以访问:

https://192.168.100.233:30000

不是 http://,也不要只认 node 的 IP(Pod 在哪个节点,用哪个节点 IP 最稳;NodePort 正常时任一节点 IP 都可以)。

浏览器提示证书不受信任,选择”高级 → 继续前往”。

获取登录 token:

Terminal window
kubectl -n kube-system get secret | grep admin
kubectl -n kube-system describe secret \
$(kubectl -n kube-system get secret | grep admin | awk '{print $1}')

复制 token: 后的字符串登录。

10. 部署 Nginx 示例应用#

node 上准备镜像(离线包或镜像加速器):

Terminal window
docker load -i /root/nginx_latest.tar
docker images | grep nginx
# 或走加速器
docker pull docker.m.daocloud.io/library/nginx:latest
docker tag docker.m.daocloud.io/library/nginx:latest nginx:latest

master 上创建 Deployment:

Terminal window
kubectl create deployment nginx --image=nginx
kubectl get pods -o wide
kubectl get deployment

--image=nginx 等价于 nginx:latest,默认拉取策略是 Always,kubelet 仍会尝试拉镜像。离线环境如果拉取失败,把策略改成 IfNotPresent:

Terminal window
kubectl patch deployment nginx -p \
'{"spec":{"template":{"spec":{"containers":[{"name":"nginx","image":"nginx","imagePullPolicy":"IfNotPresent"}]}}}}'

发布服务:

Terminal window
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get svc nginx

输出中的 80:3xxxx/TCP 即 NodePort:

NAME TYPE CLUSTER-IP PORT(S) AGE
nginx NodePort 10.100.233.224 80:31507/TCP 19s

浏览器访问:

http://192.168.100.144:31507

看到 “Welcome to nginx!” 即成功。

扩容:

Terminal window
kubectl scale deployment nginx --replicas=3
kubectl get pods -o wide

清理:

Terminal window
kubectl delete deployment nginx
kubectl delete svc nginx

11. 踩坑速查表#

问题原因解决
docker pull 超时,解析到奇怪 IPDocker Hub 域名被 DNS 污染配置 registry-mirrors,或用镜像站显式拉取后 docker tag
network 启动失败,连续 RTNETLINK answers: File exists残留的 br0 设备 / 重复的地址或网关配置清理残留网桥和重复 ifcfg,用 network 服务而非 nmcli
chronyc sources 显示 0 个源/etc/hosts 缺 master、主机名拼错修正 hosts,确保 getent hosts master 有返回
node NotReady,flannel Init:ImagePullBackOffflannel 镜像是 schema1,Docker 26 默认拒绝node Docker 降级到 18.09.6,加载镜像后重建 Pod
Dashboard 打不开用了 http:// 或访问了没有 Pod 的节点用 https://,优先访问 Dashboard Pod 所在节点的 IP
配了加速器仍走 Docker Hubdaemon.json 未加载或镜像源失效docker info 确认 Registry Mirrors,换可用源
node 加入报 token 无效token 默认 24 小时过期master 上 kubeadm token create --print-join-command
Nginx Pod 一直 ImagePullBackOffnginx:latest 默认 Always 拉取,离线拉不到加载镜像并改 imagePullPolicy: IfNotPresent

结语#

这套环境的核心难点不在 kubeadm 本身,而在老版本组件的兼容性和离线/受限网络:

  • 版本组合要对:kubelet 1.14.1 + Docker 18.09.6;
  • 老镜像格式要认:schema1 镜像在 Docker 26 上不可用;
  • 网络细节要通:hosts、chrony、flannel、NodePort 任一环出问题都会表现为集群异常。

集群跑起来之后,先给两台虚拟机打快照,再继续后面的 OpenShift 等实验,能省掉大量返工。

Kubernetes 1.14.1 集群部署实录(CentOS 7)
https://blog.ipox.cn/posts/zh-cn/k8s-1-14-1-centos7-deploy/
作者
槿鸢
发布于
2026-10-22
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取