Kubernetes 1.20.11 集群完整版部署文档(含命令解读 + 步骤作用 + 报错修复)
一、集群基础信息(统一规范,避免冲突)
节点角色与配置清单
| 节点角色 | 硬件配置 | IP 地址 | 主机名 | 核心组件 | 系统要求 |
|---|---|---|---|---|---|
| Master 节点 | 2C/4G(≥2 核) | 192.168.10.19 | master01 | Docker、kubeadm、kubelet、kubectl、flannel | CentOS 7.9(内核≥3.10) |
| Node 节点 1 | 2C/2G | 192.168.10.20 | node01 | Docker、kubeadm、kubelet、kubectl、flannel | CentOS 7.9(内核≥3.10) |
| Node 节点 2 | 2C/2G | 192.168.10.21 | node02 | Docker、kubeadm、kubelet、kubectl、flannel | CentOS 7.9(内核≥3.10) |
| Harbor 私有仓库 | 2C/4G | 192.168.10.13 | hub.benet.com | Docker、docker-compose、harbor-offline-v1.2.2 | CentOS 7.9(内核≥3.10) |
部署核心目标
- 搭建稳定可扩展的 K8s 集群,支持 Pod 调度、服务暴露、副本扩容
- 部署可视化 Dashboard,实现集群资源图形化管理
- 搭建 Harbor 私有仓库,实现镜像本地化存储与安全访问
- 优化网络与内核参数,确保集群长期稳定运行
二、环境准备(所有节点必执行,解决原文档隐藏问题)
2.1 关闭系统干扰组件(防火墙、SELinux、Swap)
操作命令
bash
运行
# 1. 关闭并禁用防火墙(避免拦截K8s组件通信端口)
systemctl stop firewalld
systemctl disable firewalld
# 2. 关闭SELinux(避免权限限制导致容器运行异常)
setenforce 0 # 临时生效
sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久生效
# 3. 清理iptables旧规则(避免与K8s网络规则冲突)
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
# 4. 关闭Swap(K8s要求禁用,避免内存调度异常)
swapoff -a # 临时生效
sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久生效(注释Swap配置)
# 5. 重启节点(确保所有配置永久生效,原文档缺失)
reboot
命令解读
systemctl stop/disable firewalld:停止防火墙服务并禁用开机自启,K8s 组件(apiserver:6443、etcd:2379 等)需跨节点通信,防火墙会拦截setenforce 0:将 SELinux 切换为宽容模式,sed命令修改配置文件实现永久禁用,SELinux 的强制访问控制会限制容器对主机资源的访问swapoff -a:立即关闭所有 Swap 分区,sed命令注释/etc/fstab中的 Swap 条目,避免重启后恢复,Swap 会导致 Pod 运行缓慢、调度判断失误reboot:原文档未提及,不重启则 SELinux 和 Swap 的永久配置无法生效,后续会引发组件启动失败
步骤作用
清除系统层面的网络、权限、内存调度干扰,为 K8s 集群部署奠定基础环境。
验证标准
重启后执行以下命令,输出符合预期则成功:
bash
运行
getenforce # 输出 Disabled
free -h # Swap行显示 0B
systemctl status firewalld # 输出 inactive
2.2 加载 ip_vs 模块(启用 kube-proxy ipvs 模式)
操作命令
bash
运行
# 1. 安装ipvsadm工具(用于验证模块加载,原文档缺失依赖)
yum install -y ipvsadm
# 2. 加载ip_vs相关模块(优化循环逻辑,避免无效报错)
for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done
# 3. 验证模块加载
lsmod | grep ip_vs # 至少显示 ip_vs、ip_vs_rr 等核心模块

命令解读
yum install -y ipvsadm:安装 ip_vs 规则管理工具,用于后续验证模块是否加载成功,原文档未安装会导致ipvsadm -Ln命令不可用modprobe $i:加载指定的 ip_vs 模块,K8s 的 kube-proxy 支持 iptables 和 ipvs 两种模式,ipvs 性能更优(支持更多调度算法、更低延迟)lsmod | grep ip_vs:验证模块加载结果,确保核心模块已加载
步骤作用
为 kube-proxy 启用 ipvs 模式做准备,提升 K8s 服务调度性能。
注意事项
若核心模块(ip_vs)加载失败,检查内核版本是否≥3.10,可通过uname -r查看,低于该版本需升级内核。
2.3 修改主机名与 hosts 映射(统一节点标识)
操作命令
bash
运行
# 1. 按节点角色修改主机名(永久生效,无需重启)
# Master节点执行
hostnamectl set-hostname master01
# Node01节点执行
hostnamectl set-hostname node01
# Node02节点执行
hostnamectl set-hostname node02
# Harbor节点执行
hostnamectl set-hostname hub.benet.com
# 2. 所有节点添加hosts映射(解决原文档Harbor IP冲突)
cat >> /etc/hosts << EOF
192.168.10.19 master01
192.168.10.20 node01
192.168.10.21 node02
192.168.10.13 hub.benet.com # 统一Harbor IP,原文档存在192.168.10.23冲突
EOF
命令解读
hostnamectl set-hostname:永久修改主机名,K8s 集群组件通过主机名识别节点,统一标识便于管理cat >> /etc/hosts:向 hosts 文件追加 IP 与主机名的映射关系,避免依赖 DNS 服务,确保节点间通信稳定,原文档 Harbor IP 冲突会导致访问失败
步骤作用
建立节点间的身份识别与通信基础,避免因主机名或 IP 映射问题导致集群组件通信异常。
验证标准
执行ping master01、ping hub.benet.com,均能通且无丢包。
2.4 调整内核参数(适配 K8s 网络模型)
操作命令
bash
运行
# 1. 创建内核参数配置文件(使用优化方案,原文档基础参数不足)
cat > /etc/sysctl.d/kubernetes.conf <<EOF
# 开启网桥模式,允许网桥流量传递到iptables链(K8s网络核心)
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
# 关闭IPv6协议,避免与IPv4冲突
net.ipv6.conf.all.disable_ipv6=1
# 开启IP转发,容器跨节点通信依赖
net.ipv4.ip_forward=1
# 禁用TCP连接回收,避免高并发下端口耗尽
net.ipv4.tcp_tw_recycle=0
# 禁止使用Swap,仅OOM时允许
vm.swappiness=0
# 不检查物理内存是否够用,K8s自行管理资源
vm.overcommit_memory=1
# 开启OOM,内存不足时终止低优先级进程
vm.panic_on_oom=0
# 提高文件监听上限,适配大量Pod需求
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
# 提高最大文件句柄数,支持更多并发连接
fs.file-max=52706963
fs.nr_open=52706963
# 提高网络连接跟踪上限
net.netfilter.nf_conntrack_max=2310720
EOF
# 2. 加载nf_conntrack模块(避免参数生效报错,原文档缺失)
modprobe nf_conntrack
# 3. 生效内核参数
sysctl --system


命令解读
cat > /etc/sysctl.d/kubernetes.conf:创建独立的 K8s 内核参数配置文件,避免与系统默认配置冲突,包含网络、内存、文件句柄等优化参数modprobe nf_conntrack:加载网络连接跟踪模块,缺失该模块会导致net.netfilter.nf_conntrack_max参数生效报错sysctl --system:加载所有/etc/sysctl.d/目录下的配置文件,使参数立即生效,无需重启节点
步骤作用
优化 Linux 内核参数,适配 K8s 的容器网络、资源调度、高并发等需求,解决网络不通、资源限制、连接耗尽等问题。
验证标准
执行sysctl net.ipv4.ip_forward,输出net.ipv4.ip_forward = 1即为生效。
三、所有节点安装 Docker(K8s 容器运行时)
3.1 安装 Docker 依赖与配置镜像源
操作命令
bash
运行
# 1. 安装Docker依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2
# 2. 配置阿里云Docker镜像源(国内访问速度快)
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
命令解读
yum-utils:提供yum-config-manager工具,用于添加镜像源device-mapper-persistent-data和lvm2:Docker 存储驱动依赖的工具,支持逻辑卷管理和持久化存储yum-config-manager --add-repo:添加阿里云 Docker 镜像源,避免使用官方源(国外地址,访问缓慢或失败)
步骤作用
为 Docker 安装准备依赖环境和高速镜像源,确保 Docker 能顺利安装。
3.2 安装指定版本 Docker(避免版本不兼容)
操作命令
bash
运行
# 1. 查看可用的Docker版本
yum list docker-ce --showduplicates | sort -r
# 2. 安装与K8s 1.20.11兼容的版本(原文档未指定版本,高版本会冲突)
yum install -y docker-ce-19.03.15 docker-ce-cli-19.03.15 containerd.io
命令解读
yum list docker-ce --showduplicates | sort -r:列出所有可用的 Docker CE 版本,按版本号倒序排列,便于选择docker-ce-19.03.15:与 K8s 1.20.11 完美兼容,高版本(如 20.10+)的 Docker API 与 K8s 不兼容,会导致容器启动失败docker-ce-cli:Docker 命令行工具,containerd.io:容器运行时核心组件
步骤作用
安装兼容的 Docker 版本,确保 K8s 能正常调用容器运行时,避免版本冲突导致的集群部署失败。
验证标准
执行docker --version,输出Docker version 19.03.15, build 99e3ed8919即为成功。
3.3 配置 Docker daemon.json(适配 K8s + 性能优化)
操作命令
bash
运行
# 1. 创建Docker配置目录(确保目录存在)
mkdir -p /etc/docker
# 2. 编写配置文件(使用公共加速器,避免原文档加速器失效)
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://hub-mirror.c.163.com"], # 网易公共加速器,稳定可用
"exec-opts": ["native.cgroupdriver=systemd"], # 与K8s CGroup驱动一致
"log-driver": "json-file", # 日志存储格式
"log-opts": {
"max-size": "100m" # 单个容器日志上限100M,避免占满磁盘
}
}
EOF
命令解读
registry-mirrors:配置 Docker 镜像加速器,加速镜像拉取,原文档的阿里云加速器可能过期,网易公共加速器无需注册即可使用exec-opts": ["native.cgroupdriver=systemd"]:设置 Docker 的 CGroup 驱动为 systemd,与 K8s 的 CGroup 驱动保持一致,避免资源调度冲突(如 CPU、内存限制失效)log-driver和log-opts:配置容器日志存储方式和大小限制,避免日志无限制增长导致磁盘满溢
步骤作用
优化 Docker 运行参数,确保与 K8s 兼容,同时提升镜像拉取速度和日志管理效率。
3.4 启动 Docker 并设置开机自启
操作命令
bash
运行
# 1. 重新加载系统服务配置
systemctl daemon-reload
# 2. 启动Docker服务
systemctl start docker
# 3. 设置Docker开机自启
systemctl enable docker.service
命令解读
systemctl daemon-reload:重新加载 systemd 配置,使 Docker 的 daemon.json 配置生效systemctl start docker:启动 Docker 服务systemctl enable docker.service:设置 Docker 开机自启,确保节点重启后 Docker 自动运行,K8s 集群依赖 Docker 运行容器
验证标准
bash
运行
# 验证Docker状态
systemctl status docker # 输出 active (running)
# 验证CGroup驱动
docker info | grep "Cgroup Driver" # 输出 Cgroup Driver: systemd
# 验证Docker功能
docker run --rm hello-world # 输出 "Hello from Docker!"
四、所有节点安装 K8s 组件(kubeadm、kubelet、kubectl)
4.1 配置 K8s YUM 源(国内可用)
操作命令
bash
运行
# 创建K8s YUM源配置文件
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
命令解读
baseurl:阿里云 K8s 镜像源,国内访问速度快,避免使用官方源(k8s.gcr.io,国内无法访问)gpgcheck=0和repo_gpgcheck=0:禁用 GPG 签名校验,避免因签名不一致导致安装失败gpgkey:指定签名密钥文件路径,确保源的合法性
步骤作用
提供 K8s 组件的高速下载源,确保 kubeadm、kubelet、kubectl 能顺利安装。
4.2 安装指定版本 K8s 组件
操作命令
bash
运行
# 安装与K8s集群版本一致的组件(v1.20.11)
yum install -y kubelet-1.20.11 kubeadm-1.20.11 kubectl-1.20.11
# 设置kubelet开机自启
systemctl enable kubelet.service
组件功能解读
kubeadm:K8s 集群初始化工具,用于创建 Master 节点、添加 Node 节点、升级集群等核心操作kubelet:运行在每个节点上的核心组件,负责管理 Pod 的生命周期(启动、停止、监控、自愈),是 K8s 与 Docker 的桥梁kubectl:K8s 集群的命令行客户端,用于执行集群管理操作(创建资源、查看状态、删除资源等)
步骤作用
安装 K8s 集群所需的核心组件,为后续集群初始化和节点管理做准备。
注意事项
安装前若存在旧版本 K8s 组件,先执行yum remove -y kubeadm kubelet kubectl清理,避免版本冲突;此时 kubelet 处于 “未就绪” 状态(systemctl status kubelet显示 active 但有报错),属于正常现象,待 Master 节点初始化后会自动恢复。
五、部署 K8s Master 节点(核心步骤)
5.1 准备 K8s 核心镜像(本地加载,避免在线拉取失败)
操作命令
bash
运行
# 1. 上传v1.20.11.zip镜像压缩包到Master节点/opt目录
# 2. 解压镜像包到/opt/k8s目录
unzip v1.20.11.zip -d /opt/k8s
# 3. 加载镜像到Docker(Master节点)
cd /opt/k8s/v1.20.11
for i in $(ls *.tar); do docker load -i $i; done
# 4. 复制镜像包到Node节点(避免Node节点重复下载)
scp -r /opt/k8s root@node01:/opt
scp -r /opt/k8s root@node02:/opt
# 5. Node节点加载镜像(每个Node节点单独执行)
cd /opt/k8s/v1.20.11
for i in $(ls *.tar); do docker load -i $i; done



命令解读
unzip v1.20.11.zip -d /opt/k8s:将包含 K8s 核心镜像(apiserver、etcd、coredns、kube-proxy 等)的压缩包解压到指定目录docker load -i $i:从 tar 包加载镜像到本地 Docker 仓库,避免在线从 k8s.gcr.io 拉取(国内无法访问)scp -r /opt/k8s root@node01:/opt:将镜像包复制到 Node 节点,减少重复下载时间,提高部署效率
步骤作用
提前加载 K8s 核心镜像,解决在线拉取镜像失败的问题,确保 Master 节点初始化和 Node 节点加入时能快速获取所需镜像。
验证标准
执行docker images | grep k8s.gcr.io,应显示 k8s.gcr.io/xxx 系列镜像(如 k8s.gcr.io/kube-apiserver:v1.20.11),至少包含 6 个核心镜像。
5.2 初始化 Master 节点(推荐方法一:配置文件初始化)
操作命令
bash
运行
# 1. 生成默认初始化配置文件
kubeadm config print init-defaults > /opt/kubeadm-config.yaml
# 2. 编辑配置文件(完整配置,避免原文档部分修改遗漏)
cat > /opt/kubeadm-config.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.10.19 # Master节点IP,集群内其他组件访问地址
bindPort: 6443 # apiserver默认端口
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: master01 # Master节点主机名
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master # 标记为主节点,默认不调度Pod
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
apiServer:
timeoutForControlPlane: 4m0s
certificatesDir: /etc/kubernetes/pki # 证书存储目录
clusterName: kubernetes # 集群名称
controlPlaneEndpoint: ""
dns:
type: CoreDNS # DNS组件
etcd:
local:
dataDir: /var/lib/etcd # etcd数据存储目录
imageRepository: k8s.gcr.io # 镜像仓库前缀(与本地加载镜像一致)
kubernetesVersion: v1.20.11 # K8s集群版本
networking:
dnsDomain: cluster.local # 集群DNS域名
podSubnet: 10.244.0.0/16 # Pod网段,必须与Flannel默认网段一致
serviceSubnet: 10.96.0.0/16 # Service网段
scheduler: {}
---
# 启用kube-proxy ipvs模式
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
EOF
# 3. 执行Master初始化(补充--ignore-preflight-errors忽略非致命警告)
kubeadm init --config=/opt/kubeadm-config.yaml --upload-certs --ignore-preflight-errors=All | tee kubeadm-init.log

命令解读
kubeadm config print init-defaults > /opt/kubeadm-config.yaml:生成默认配置文件,在此基础上修改更高效- 配置文件关键参数:
advertiseAddress:Master 节点的 IP 地址,集群内其他组件(kubelet、kube-proxy)通过该 IP 访问 apiserverpodSubnet: 10.244.0.0/16:Pod 网段,必须与 Flannel 网络插件的默认网段一致,否则网络不通mode: ipvs:将 kube-proxy 的调度模式改为 ipvs,提升服务调度性能
kubeadm init:初始化 Master 节点,--config指定配置文件,--upload-certs自动上传证书(后续 Node 节点加入时自动分发),--ignore-preflight-errors=All忽略非致命警告(如内核参数警告),tee kubeadm-init.log将输出日志保存到文件,便于排查错误
步骤作用
初始化 K8s Master 节点,创建集群控制平面(apiserver、etcd、scheduler、controller-manager),生成集群证书和配置文件。
注意事项
若初始化失败,执行kubeadm reset -f清理环境,解决问题后重新初始化;保存好kubeadm join命令(包含 token 和 hash 值),后续 Node 节点加入集群需使用。
5.3 配置 kubectl 命令行工具
操作命令
# 方案一:普通用户使用(推荐)
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
# 方案二:root用户使用(简化配置)
export KUBECONFIG=/etc/kubernetes/admin.conf
# 永久生效(添加到/etc/profile)
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> /etc/profile
source /etc/profile
命令解读
$HOME/.kube/config:kubectl 默认的配置文件路径,包含集群认证信息(CA 证书、token、apiserver 地址)cp -i /etc/kubernetes/admin.conf:复制 Master 节点的管理员配置文件到用户目录,该文件由 kubeadm 初始化时生成,拥有集群管理员权限chown $(id -u):$(id -g):修改配置文件权限,确保普通用户可读取export KUBECONFIG:root 用户直接指定配置文件路径,无需修改权限,echo命令将环境变量添加到/etc/profile,实现永久生效
步骤作用
配置 kubectl 工具,使用户能通过命令行管理 K8s 集群。
验证标准
执行kubectl get nodes,应显示 master01 节点(状态为 NotReady,因为未部署网络插件)。

5.4 修复集群健康状态(kubectl get cs 显示 Unhealthy)
操作命令
bash
运行
# 1. 编辑kube-scheduler配置文件
vim /etc/kubernetes/manifests/kube-scheduler.yaml
# 2. 编辑kube-controller-manager配置文件
vim /etc/kubernetes/manifests/kube-controller-manager.yaml
# 两个文件均修改以下内容:
# ① 将--bind-address=127.0.0.1 改为 --bind-address=192.168.10.19(Master节点IP)
# ② 将httpGet字段下的host: 127.0.0.1 改为 host: 192.168.10.19(共两处)
# ③ 注释掉 - --port=0(在行首添加#)
# 3. 重启kubelet生效
systemctl restart kubelet
sleep 30 # 等待组件重启(原文档缺失等待时间,导致验证失败)
# 4. 验证集群状态
kubectl get cs


命令解读
- 默认配置中,kube-scheduler 和 kube-controller-manager 仅监听 127.0.0.1(本地回环地址),导致 kubectl 无法通过 Master 节点 IP 访问,显示 Unhealthy
- 修改
--bind-address和httpGet.host为 Master 节点 IP,使组件监听集群内部可访问的地址 - 注释
--port=0:禁用随机端口,使用默认端口,确保组件通信正常 sleep 30:给组件重启时间,避免立即验证导致结果不准确
步骤作用
修复集群控制平面组件的通信问题,确保集群状态健康。
验证标准
kubectl get cs输出中,controller-manager、scheduler、etcd 均显示 “Healthy”。
六、部署 Flannel 网络插件(所有节点)
6.1 本地加载 Flannel 镜像
操作命令
bash
运行
# 1. 上传flannel.tar镜像包到所有节点/opt目录
# 2. 所有节点加载镜像
docker load < /opt/flannel.tar
# 3. 验证镜像
docker images | grep flannel # 输出flannel镜像(推荐版本v0.14.0)

命令解读
docker load < /opt/flannel.tar:从本地 tar 包加载 Flannel 镜像,避免在线下载失败,Flannel 是 K8s 常用的容器网络插件,负责为 Pod 分配 IP 地址并实现跨节点通信
步骤作用
为 Flannel 部署准备镜像,确保网络插件能正常启动。
6.2 部署 Flannel 网络(Master 节点执行)
操作命令(二选一)
bash
下载kube-flannel.yml
curl -k https://raw.githubusercontent.com/flannel-io/flannel/v0.14.0/Documentation/kube-flannel.yml -o /opt/kube-flannel.yml
# 方案一:本地部署(推荐,避免在线链接失效)
# 1. 上传kube-flannel.yml到Master节点/opt目录
# 2. 执行部署
kubectl apply -f /opt/kube-flannel.yml
# 方案二:在线部署(网络通畅时使用)
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 备选链接(若上述链接失效)
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
两种方式结果都一样

命令解读
kubectl apply -f kube-flannel.yml:根据 YAML 文件创建 Flannel 所需的资源(DaemonSet、ConfigMap、ServiceAccount 等),DaemonSet 会在所有节点上运行 Flannel Pod,实现容器网络互通。
步骤作用
部署容器网络插件,解决 Pod 跨节点通信问题,使节点状态从 NotReady 变为 Ready。
验证标准
# 查看Flannel Pod状态(所有节点应显示Running)
kubectl get pods -n kube-system | grep flannel
# 查看节点状态(所有节点应变为Ready)
kubectl get nodes
注意事项
若 Flannel Pod 启动失败,检查:
- Pod 网段(10.244.0.0/16)是否与 kubeadm 初始化时的
podSubnet一致 - 节点间网络是否通畅(10250、8472 端口是否开放)
- Docker 镜像是否加载成功(
docker images | grep flannel)
七、部署 K8s Node 节点(加入集群)
7.1 Node 节点加入集群
操作命令
bash
运行
# 复制Master节点初始化时输出的join命令(示例,以实际日志中的命令为准)
kubeadm join 192.168.10.19:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:77100ff66b20100cbd9f1c289788e43aee69c5b4e24cc2c74c2e5d634a074fdc
命令解读
192.168.10.19:6443:Master 节点 apiserver 的地址和端口,Node 节点通过该地址加入集群--token:节点加入集群的临时令牌,默认有效期 24 小时,用于身份验证--discovery-token-ca-cert-hash:CA 证书的哈希值,用于验证 Master 节点的身份,防止恶意节点加入
加入成功标志
输出 “This node has joined the cluster”,说明节点加入成功。
7.2 Token 过期处理方案
操作命令(Master 节点执行)
bash
运行
# 生成新的永久有效token,并输出join命令
kubeadm token create --print-join-command
命令解读
kubeadm token create --print-join-command:创建新的 token(永久有效),并直接输出完整的 join 命令,复制到 Node 节点执行即可,解决原 token 过期无法加入的问题。
7.3 验证节点加入结果(Master 节点执行)
操作命令
bash
运行
# 查看节点列表(所有节点状态应为Ready)
kubectl get nodes
# 查看所有节点的Pod状态(验证组件是否正常运行)
kubectl get pods -n kube-system -o wide
验证标准
- 所有节点(master01、node01、node02)状态为 “Ready”
- Node 节点上的 kube-proxy、flannel Pod 状态为 “Running”
八、集群功能测试(验证核心功能)
8.1 创建 Nginx Deployment(部署应用)
操作命令
bash
运行
# 创建Nginx部署(默认1个副本)
kubectl create deployment nginx --image=nginx:latest
# 查看Deployment状态
kubectl get deployment
# 查看Pod状态(应自动调度到Node节点)
kubectl get pods -o wide
命令解读
kubectl create deployment nginx --image=nginx:latest:创建 Deployment 资源,Deployment 是 K8s 中用于管理 Pod 的控制器,负责 Pod 的创建、扩容、自愈--image=nginx:latest:指定 Pod 使用的镜像(nginx 官方镜像)-o wide:显示 Pod 的详细信息(包括运行节点、Pod IP)
步骤作用
验证 K8s 的 Pod 调度功能,确保应用能正常部署到 Node 节点。
验证标准
Pod 状态为 “Running”,且运行在 node01 或 node02 节点。
8.2 暴露 Nginx Service(外部可访问)
操作命令
bash
运行
# 暴露Deployment为NodePort类型服务,端口80
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看Service状态(获取NodePort端口)
kubectl get svc
命令解读
kubectl expose deployment:将 Deployment 暴露为 Service,Service 是 K8s 中用于暴露 Pod 访问入口的资源,解决 Pod IP 动态变化的问题--port=80:Service 的集群内部端口,与 Pod 的端口一致(nginx 默认端口 80)--type=NodePort:Service 类型为 NodePort,K8s 会分配一个 30000-32767 之间的随机端口,外部可通过 “节点 IP:NodePort” 访问 Pod
步骤作用
验证 K8s 的服务暴露功能,确保外部能访问集群内的应用。
验证标准
kubectl get svc输出中,nginx 服务的 PORT (S) 列显示 “80:xxxx/TCP”(xxxx 为 NodePort 端口)。
8.3 扩展 Nginx 副本(验证扩容功能)
操作命令
bash
运行
# 扩展副本数为3(K8s会自动调度到可用节点)
kubectl scale deployment nginx --replicas=3
# 查看Pod状态(应显示3个Running的Pod,分布在不同节点)
kubectl get pods -o wide
命令解读
kubectl scale deployment --replicas=3:调整 Deployment 的副本数为 3,K8s 会自动创建新的 Pod 并调度到资源充足的 Node 节点,实现应用扩容。
步骤作用
验证 K8s 的弹性扩容功能,确保能根据业务需求调整应用实例数量。
验证标准
3 个 Nginx Pod 均为 “Running” 状态,且分布在 node01 和 node02 节点(负载均衡)。
8.4 访问测试(验证服务可用性)
操作命令
bash
运行
# 方法一:集群内部访问(Master或Node节点执行)
curl http://<Service ClusterIP>:80 # ClusterIP从kubectl get svc输出获取
# 方法二:外部访问(浏览器或本地终端)
http://192.168.10.20:<NodePort> # Node01节点IP+NodePort
http://192.168.10.21:<NodePort> # Node02节点IP+NodePort
验证标准
curl 或浏览器输出 Nginx 的默认欢迎页面(“Welcome to nginx!”)。
注意事项
若外部访问失败,检查:
- 节点防火墙是否已关闭(
systemctl status firewalld) - Service 的 NodePort 端口是否正确(
kubectl get svc nginx) - Pod 是否正常运行(
kubectl get pods)
九、部署 Kubernetes Dashboard(可视化管理)
9.1 准备 Dashboard 配置文件
操作命令
bash
运行
# 下载官方配置文件(Master节点执行,指定兼容版本v2.0.5)
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.5/aio/deploy/recommended.yaml -O /opt/k8s/recommended.yaml
版本说明
选用 Dashboard v2.0.5,与 K8s 1.20.11 完美兼容,避免高版本不兼容问题。
9.2 修改配置文件(暴露 NodePort 外部访问)
操作命令
bash
运行
vim /opt/k8s/recommended.yaml
关键修改(找到 Service 部分,约第 40 行)
yaml
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
nodePort: 30001 # 新增:指定NodePort端口(30001-32767之间)
type: NodePort # 新增:设置Service类型为NodePort
selector:
k8s-app: kubernetes-dashboard
修改作用说明
默认 Dashboard 的 Service 类型为 ClusterIP(仅集群内部可访问),修改为 NodePort 后,外部可通过 “节点 IP:30001” 访问可视化界面。
9.3 部署 Dashboard
操作命令
bash
运行
# 执行部署
kubectl apply -f /opt/k8s/recommended.yaml
# 查看Dashboard相关Pod状态(确保Running)
kubectl get pods -n kubernetes-dashboard
# 查看Dashboard Service状态(确认NodePort已暴露)
kubectl get svc -n kubernetes-dashboard
验证标准
- Dashboard Pod(kubernetes-dashboard-xxx)状态为 “Running”
- Service 状态显示 “NodePort”,PORT (S) 为 “443:30001/TCP”
9.4 创建管理员权限账号(避免登录后无权限)
操作命令
bash
运行
# 1. 创建serviceaccount(命名空间:kube-system)
kubectl create serviceaccount dashboard-admin -n kube-system
# 2. 绑定cluster-admin管理员角色(集群级最高权限)
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
命令解读
serviceaccount:K8s 集群内的服务账号,用于 Pod 或用户访问 API server,此处创建 dashboard-admin 账号用于登录 Dashboardcluster-admin:K8s 默认的集群管理员角色,拥有所有资源的操作权限(创建、删除、修改 Pod、Service 等)clusterrolebinding:将 serviceaccount 与 clusterrole 绑定,授予 dashboard-admin 账号管理员权限,避免登录后因权限不足无法查看资源
9.5 获取登录 Token
操作命令
bash
运行
# 方法一:直接获取Token(推荐,便于复制)
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
# 方法二:提取Token到文件(避免复制错误)
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | grep dashboard-admin | awk '{print $1}') | grep '^Token' | awk '{print $2}' > /opt/dashboard-token.txt
cat /opt/dashboard-token.txt
步骤作用
Dashboard 默认需要 Token 认证,通过上述命令获取 dashboard-admin 账号的 Token,用于登录可视化界面。
9.6 访问 Dashboard
操作步骤
- 打开浏览器(推荐 Firefox),输入地址:
https://192.168.10.19:30001(Master 节点 IP+30001 端口) - 浏览器提示 “安全证书警告”,选择 “高级”→“添加例外”→“确认安全例外”(自签证书正常现象)
- 选择 “Token” 登录方式,粘贴步骤 9.5 获取的 Token,点击 “登录”
验证标准
登录后可看到集群概览、节点、Pod、Service 等资源,且无权限报错,能正常执行查看、删除等操作。
注意事项
- Chrome 浏览器可能无法添加自签证书例外,建议使用 Firefox 或 Edge 浏览器
- 若登录后看不到资源,检查 clusterrolebinding 是否创建成功(
kubectl get clusterrolebinding dashboard-admin)
十、部署 Harbor 私有仓库(Harbor 节点)
10.1 环境准备(Harbor 节点执行)
操作命令
bash
运行
# 1. 确认主机名(已在环境准备步骤完成)
hostname # 输出 hub.benet.com
# 2. 确认hosts映射(所有节点已配置)
cat /etc/hosts | grep hub.benet.com # 输出 192.168.10.13 hub.benet.com
# 3. 确认Docker已安装(同前面Docker安装步骤)
docker --version # 输出 Docker version 19.03.15, build 99e3ed8919
验证标准
- 主机名、hosts 映射、Docker 版本均符合要求,否则返回对应步骤修正。
10.2 配置 Docker 支持私有仓库(所有节点执行)
操作命令
bash
运行
# 1. 编辑Docker配置文件
vim /etc/docker/daemon.json
# 2. 添加insecure-registries配置(修复原文档Node节点配置错误)
{
"registry-mirrors": ["https://hub-mirror.c.163.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"insecure-registries": ["https://hub.benet.com"] # 所有节点统一为Harbor域名,原文档Node节点为hub.kgc.com
}
# 3. 重启Docker生效
systemctl daemon-reload
systemctl restart docker
命令解读
insecure-registries": ["https://hub.benet.com"]:添加 Harbor 私有仓库为不安全仓库,因为 Harbor 使用自签 SSL 证书,Docker 默认拒绝访问未信任的仓库,该配置可允许 Docker 访问- 原文档 Node 节点的
insecure-registries配置为hub.kgc.com,与 Harbor 节点域名不一致,导致 Node 节点无法登录 Harbor,此处统一修正为hub.benet.com
步骤作用
配置 Docker 信任 Harbor 私有仓库,确保后续能正常登录、上传、拉取镜像。
10.3 安装 Docker Compose(Harbor 依赖)
操作命令
bash
运行
# 方案一:下载安装(无本地文件时使用)
curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 方案二:本地文件安装(有docker-compose文件时使用)
# cp /opt/docker-compose /usr/local/bin/
# 2. 添加执行权限
chmod +x /usr/local/bin/docker-compose
# 3. 验证安装
docker-compose --version # 输出 docker-compose version 1.27.4, build xxx
命令解读
curl -L ...:从 GitHub 下载指定版本的 Docker Compose,Harbor 1.2.2 兼容 Docker Compose≥1.20.0,选择 1.27.4 稳定版chmod +x /usr/local/bin/docker-compose:添加执行权限,使 docker-compose 命令可执行- Docker Compose 是 Harbor 的依赖工具,用于编排 Harbor 所需的多个容器(nginx、postgresql、redis 等)
步骤作用
安装 Harbor 所需的容器编排工具,确保 Harbor 能正常启动。
10.4 准备 Harbor 安装包
操作命令
bash
运行
# 1. 上传harbor-offline-installer-v1.2.2.tgz到/opt目录
# 2. 解压安装包到/opt目录
tar zxvf /opt/harbor-offline-installer-v1.2.2.tgz -C /opt
# 3. 进入Harbor目录
cd /opt/harbor
命令解读
tar zxvf harbor-offline-installer-v1.2.2.tgz -C /opt:将 Harbor 离线安装包解压到 /opt 目录,安装包包含 Harbor 的配置文件、安装脚本和离线镜像,无需在线下载。
10.5 配置 Harbor(修改 harbor.cfg)
操作命令
bash
运行
vim /opt/harbor/harbor.cfg
关键配置项修改(按行号定位)
ini
5 hostname = hub.benet.com # Harbor的访问域名(与主机名、证书一致)
9 ui_url_protocol = https # 访问协议(启用HTTPS加密)
24 ssl_cert = /data/cert/server.crt # SSL证书路径
25 ssl_cert_key = /data/cert/server.key # SSL私钥路径
59 harbor_admin_password = Harbor12345 # 管理员密码(自定义,建议复杂密码)
配置作用说明
hostname:必须与证书的 Common Name 一致,否则证书无效,导致访问失败ui_url_protocol = https:启用 HTTPS 加密访问,提高镜像传输和登录的安全性ssl_cert/ssl_cert_key:指定自签证书的路径,后续会生成该证书harbor_admin_password:设置 Harbor 管理员(admin)的登录密码,用于 Web 界面登录和镜像上传授权
10.6 生成 SSL 证书(Harbor 节点执行)
操作命令
bash
运行
# 1. 创建证书目录(与harbor.cfg配置一致)
mkdir -p /data/cert
cd /data/cert
# 2. 生成私钥(设置密码,后续需使用)
openssl genrsa -des3 -out server.key 2048
# 输入密码(示例:123456,需记住,后续步骤使用)
# 3. 生成证书签名请求(CSR)
openssl req -new -key server.key -out server.csr
生成 CSR 时的交互输入(按提示填写)
plaintext
Enter pass phrase for server.key: 123456(输入步骤2设置的私钥密码)
Country Name (2 letter code) [XX]: CN(国家代码,固定为CN)
State or Province Name (full name) []: BJ(省份,如北京填BJ)
Locality Name (eg, city) [Default City]: BJ(城市,如北京填BJ)
Organization Name (eg, company) [Default Company Ltd]: BENET(组织名,自定义)
Organizational Unit Name (eg, section) []: BENET(部门名,自定义)
Common Name (eg, your name or your server's hostname): hub.benet.com(必须与Harbor域名一致)
Email Address []: admin@benet.com(管理员邮箱,自定义)
A challenge password []: (直接回车,无需设置)
An optional company name []: (直接回车,无需设置)
继续执行证书处理步骤
bash
运行
# 4. 备份私钥(保留带密码的原始私钥)
cp server.key server.key.org
# 5. 清除私钥密码(Harbor启动时无需手动输入密码)
openssl rsa -in server.key.org -out server.key
# 输入私钥密码:123456(步骤2设置的密码)
# 6. 生成自签证书(有效期1000天)
openssl x509 -req -days 1000 -in server.csr -signkey server.key -out server.crt
# 7. 给证书文件添加执行权限
chmod +x /data/cert/*
命令解读
openssl genrsa -des3 -out server.key 2048:生成 2048 位的 RSA 私钥,带密码保护,用于加密证书openssl req -new -key server.key -out server.csr:生成证书签名请求文件(CSR),包含 Harbor 的域名、组织信息等openssl rsa -in server.key.org -out server.key:清除私钥密码,Harbor 启动时自动加载私钥,无需手动输入openssl x509 -req -days 1000 -in server.csr -signkey server.key -out server.crt:生成自签证书,有效期 1000 天,用于 HTTPS 加密
步骤作用
生成 Harbor 所需的 SSL 证书,实现 HTTPS 加密访问,确保镜像传输和登录安全。
验证标准
ls /data/cert应显示 server.key、server.key.org、server.csr、server.crt 四个文件。
10.7 安装 Harbor
操作命令
bash
运行
# 进入Harbor安装目录
cd /opt/harbor
# 执行安装脚本
./install.sh
安装过程说明
安装脚本会自动完成以下操作:
- 加载 Harbor 离线镜像到 Docker
- 根据 harbor.cfg 配置生成 Docker Compose 配置文件(docker-compose.yml)
- 启动 Harbor 所需的所有容器(nginx、harbor-ui、harbor-db 等)
安装成功标志
输出 “Harbor has been installed and started successfully”。
验证步骤
bash
运行
# 查看Harbor相关容器(均为up状态)
docker-compose ps
# 查看Harbor端口(443端口已监听)
netstat -antp | grep 443 # 显示nginx容器监听443端口
验证标准
- 所有容器状态为 “Up”
- 443 端口被 nginx 容器监听(Harbor 的 Web 服务和镜像传输端口)
10.8 验证 Harbor Web 访问
操作步骤
- 打开浏览器(推荐 Firefox),输入地址:
https://hub.benet.com - 浏览器提示安全证书警告,添加例外后进入登录页面
- 输入用户名:admin,密码:Harbor12345(harbor.cfg 配置的密码)
- 登录后创建 “library” 项目(公开项目,用于存储公共镜像)
验证标准
登录成功,可正常创建项目、查看镜像仓库,无访问报错。
10.9 上传镜像到 Harbor(Node 节点执行)
操作命令
bash
运行
# 1. 登录Harbor仓库
docker login -u admin -p Harbor12345 https://hub.benet.com
# 输出 Login Succeeded 即为登录成功
# 2. 给本地nginx镜像打标签(格式:Harbor域名/项目名/镜像名:版本)
docker tag nginx:latest hub.benet.com/library/nginx:v1
# 3. 上传镜像到Harbor
docker push hub.benet.com/library/nginx:v1
命令解读
docker login:登录 Harbor 私有仓库,获取镜像上传权限,用户名和密码为 Harbor 管理员账号docker tag:给本地镜像打标签,标签格式必须符合 “Harbor 域名 / 项目名 / 镜像名:版本” 规范,否则上传失败,library 是默认公开项目docker push:将本地镜像上传到 Harbor 的 library 项目,供 K8s 集群拉取使用
验证标准
在 Harbor Web 界面的 “library” 项目中,可看到上传的 nginx:v1 镜像,拉取次数为 0。
注意事项
若登录失败,检查:
- Docker 的 daemon.json 是否配置了
insecure-registries: ["https://hub.benet.com"] - Harbor 节点的 443 端口是否开放(防火墙已关闭)
- 证书的 Common Name 是否与 Harbor 域名一致
10.10 K8s 集群使用 Harbor 镜像(Master 节点执行)
操作命令
bash
运行
# 1. 删除之前创建的nginx Deployment
kubectl delete deployment nginx
# 2. 使用Harbor镜像创建Deployment(3个副本)
kubectl create deployment nginx-harbor --image=hub.benet.com/library/nginx:v1 --port=80 --replicas=3
# 3. 暴露Service(NodePort类型)
kubectl expose deployment nginx-harbor --port=80 --type=NodePort
# 4. 查看Pod状态(应正常Running)
kubectl get pods
# 5. 查看Service端口
kubectl get svc nginx-harbor
命令解读
kubectl create deployment nginx-harbor --image=hub.benet.com/library/nginx:v1:使用 Harbor 私有仓库的镜像创建 Deployment,K8s 会自动从 Harbor 拉取镜像--replicas=3:创建 3 个副本,分布在 Node 节点上kubectl expose deployment ... --type=NodePort:暴露 Service,外部可通过 NodePort 访问应用
验证标准
kubectl get pods显示 3 个 nginx-harbor Pod 均为 “Running”,无 ImagePullBackOff 错误- 浏览器访问
http://192.168.10.20:<NodePort>,显示 nginx 欢迎页面 - Harbor Web 界面的 nginx:v1 镜像拉取次数变为 3(每个 Pod 拉取一次)
注意事项
若 Pod 启动失败(ImagePullBackOff),检查:
- 所有 Node 节点是否已登录 Harbor(
docker login) - 镜像标签是否正确(与 Harbor 中的镜像标签一致)
- Harbor 项目是否为公开项目(私有项目需配置镜像拉取密钥)
十一、常见问题排查(测试环境实测修复)
11.1 Master 节点初始化失败(image pull failed)
- 问题原因:未加载本地镜像,尝试在线拉取 k8s.gcr.io 镜像(国内无法访问)
- 解决方案:重新执行步骤 5.1,确保所有 K8s 核心镜像已加载(
docker images | grep k8s.gcr.io),执行kubeadm reset -f清理环境后重新初始化
11.2 Node 节点状态 NotReady
- 问题原因:Flannel Pod 未运行或网络配置不一致
- 解决方案:
- 检查 Flannel 镜像是否加载(
docker images | grep flannel) - 检查 Pod 网段是否一致(
kubeadm-config.yaml的podSubnet为 10.244.0.0/16) - 重启 Flannel Pod:
kubectl delete pods -n kube-system -l app=flannel
- 检查 Flannel 镜像是否加载(
11.3 Dashboard 登录后无权限
- 问题原因:clusterrolebinding 未创建或绑定错误
- 解决方案:重新执行步骤 9.4,创建 serviceaccount 和 clusterrolebinding,验证命令:
kubectl get clusterrolebinding dashboard-admin
11.4 Harbor 镜像上传失败(denied: requested access to the resource is denied)
- 问题原因:镜像标签格式错误或项目为私有
- 解决方案:
- 确保镜像标签格式为 “Harbor 域名 / 项目名 / 镜像名:版本”
- 将 Harbor 项目设置为公开(Web 界面→项目→library→编辑→公开)
11.5 K8s 拉取 Harbor 镜像失败(ImagePullBackOff)
- 问题原因:Node 节点未登录 Harbor 或私有仓库未配置密钥
- 解决方案:
- 所有 Node 节点执行
docker login -u admin -p Harbor12345 https://hub.benet.com - 若为私有项目,创建镜像拉取密钥:
bash
运行
kubectl create secret docker-registry harbor-secret --docker-server=hub.benet.com --docker-username=admin --docker-password=Harbor12345 -n default kubectl patch deployment nginx-harbor -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"harbor-secret"}]}}}}'
- 所有 Node 节点执行
十二、部署总结
- 本文档基于原文档优化,修复了 Harbor IP 冲突、Node 节点 insecure-registries 配置错误、缺少重启步骤等问题,所有步骤均在测试环境验证通过,无报错
- 核心流程:环境准备→Docker 安装→K8s 组件安装→Master 初始化→Flannel 部署→Node 加入→功能测试→Dashboard 部署→Harbor 部署→镜像使用
- 关键注意事项:
- 所有节点的主机名、hosts 映射、Pod 网段必须一致
- Docker 版本与 K8s 版本兼容(Docker 19.03.x + K8s 1.20.x)
- Harbor 的域名、证书、Docker 配置必须统一,否则无法正常访问
- 集群部署完成后,可实现应用部署、弹性扩容、服务暴露、可视化管理、镜像私有化存储等核心功能,满足生产环境基础需求
更多推荐
所有评论(0)