前言

近期使用一套线上 K8s 实训沙箱练习 kubectl 基础操作,一边执行命令探测底层架构,一边验证容器镜像调度、流量接入、租户隔离等 K8s 基础原理。本次探索目标:熟练集群查询命令、理清 Pod 镜像完整加载流程、定位 toolbox 实训终端镜像来源,同时梳理整套平台外网访问实现方式。

环境概况

整套实训平台由底层 Kubernetes 集群 + 上层 KubeSphere 多租户管理平台组成。

  1. 集群硬件架构:3 台 Master 控制节点实现控制面高可用,业务负载全部运行在单台 Worker 工作节点;控制面高可用,业务层面存在单点瓶颈

  2. K8s 集群版本:v1.33.4

  3. 实训操作终端:toolbox Pod

  4. toolbox 内置 kubectl 版本:1.28,客户端与集群版本差距巨大,存在 API 兼容性警告

  5. 租户隔离机制:每位学员自动分配独立user-xxxx命名空间,通过 RBAC 严格限制权限,学员仅拥有基础查询、创建 Pod 权限,无法访问核心密钥、宿主机配置。

  6. 资源限制:平台开启 LimitRanger,对学员创建的 Pod 强制约束 CPU、内存上下限,防止资源抢占。

探索过程

1. 测试创建 Nginx Pod,遭遇镜像拉取失败

执行命令测试调度功能:

kubectl run nginx-demo --image=nginx --port=80

Pod 状态持续流转:PendingContainerCreatingErrImagePullImagePullBackOff 更换国内公开镜像源再次尝试,依旧拉取失败。 判断:问题不只是海外镜像网络超时,平台存在访问管控,禁止 Pod 直接拉取外网公共镜像,仅放行内部私有仓库镜像。

核心知识点:kubectl 只是向 apiserver 发送创建资源指令,本身不下载镜像;真正执行镜像拉取操作的是 Worker 节点操作系统内的containerd。 containerd 镜像加速、网络策略配置文件存放于宿主机/etc/containerd/config.toml,学员容器没有权限登录节点查看、修改。

2. 全局检索私有镜像仓库登录凭证

猜想内部存在私有 Harbor 仓库,尝试筛选镜像登录密钥:

kubectl get secrets -A --field-selector type=kubernetes.io/dockerconfigjson

返回No resources found。 说明集群不存在全局统一镜像登录 Secret。镜像拉取凭证绑定平台内部服务账号,隔离在权限边界之外,普通学员无法读取。

3. Jsonpath 精准提取当前 toolbox 镜像地址

利用 jsonpath 语法精准抓取目标字段,规避大量冗余表格输出:

kubectl get pod $(hostname) -o jsonpath='{.spec.containers[0].image}'

输出私有 Harbor 镜像地址,确认 toolbox 镜像托管在平台自建私有仓库。 仓库域名支持公网 DNS 解析,但仓库开启鉴权,缺少账号密码,外部无法直接拉取镜像。

4. 外网用户如何访问这套实训平台(完整链路)

  1. 用户浏览器输入平台域名;

  2. DNS 解析域名,指向机房 / 家庭宽带的公网 IP;

  3. 请求流量抵达路由器,配置端口转发 (NAT),将公网端口流量转发至唯一 Worker 节点内网地址;

  4. Worker 节点上运行ingress-nginx网关 Pod 接收流量;

补充:ingress-nginx 部署了多副本,分散在多台节点,但路由器流量仅转发单一 Worker,其余网关实例闲置,无法实现业务流量容灾;

  1. Ingress 根据域名路由,把请求转发给 KubeSphere 前端、后台服务;

  2. 用户在网页点击开启实训环境,平台后端调用 K8s API,调度创建 toolbox Pod;

  3. 网页通过 websocket 打通终端,实现网页内直接操作 kubectl。

5. 集群资源与存储相关观察

通过资源查询能够看到平台内置监控体系:Prometheus、Grafana、日志组件等;同时大量 KubeSphere 专属 Quota 类型 Secret,用于管控每个租户资源配额,限制 Pod 数量、存储、算力消耗。

本次探索总结

  1. 多租户实训平台依靠「命名空间 + RBAC + 资源配额」三重隔离,学员权限被锁死,无法触及宿主机配置、私有仓库密钥等核心敏感信息;

  2. ImagePullBackOff不要单一归结为网络问题,网络策略、镜像黑白名单、仓库鉴权都是高频诱因;

  3. 集群架构需要区分:控制面高可用 ≠ 业务负载高可用,本案例所有业务运行在单 Worker 节点,存在明显单点风险;

  4. 外网访问内网 K8s 服务,家用环境普遍依靠路由器 NAT 端口转发实现,生产环境更多使用负载均衡;

  5. 复刻同类实训沙箱的正确思路:自行编写 Dockerfile 构建 toolbox 镜像、搭建私有 Harbor,不要尝试获取第三方平台私有镜像;

  6. kubectl 客户端版本与 K8s 集群版本尽量保持接近,跨大版本使用极易出现兼容异常。

自建实训集群参考要点

  1. 对齐 kubectl 客户端与集群版本,规避 API 兼容问题;

  2. containerd 预先配置国内镜像加速器,规划镜像访问策略,区分内部私有镜像、外部公共镜像;

  3. 合理规划节点架构,避免业务全部单点运行;

  4. 利用 NetworkPolicy、资源配额做好租户隔离,防止滥用集群资源。

拓展:如何构建同款学员沙箱 toolbox 镜像 & 镜像仓库访问方案

本次实训环境的操作终端 toolbox 是定制容器镜像,也是整个实训平台的核心载体。与其尝试抓取他人私有仓库内的镜像,不如从零自行构建,同时区分镜像构建流程私有仓库连通方案,对比梳理。

一、toolbox 沙箱镜像构建完整流程

  1. 编写 Dockerfile 选择轻量基础系统镜像,预装 kubectl、curl、nslookup、jq 等运维工具;重点:kubectl 版本与 K8s 集群版本保持一致,消除版本兼容警告

  2. 本地构建镜像

docker build -t [私有仓库地址]/public/opslab/toolbox:版本标签 .
  1. 登录私有 Harbor 仓库,推送镜像

docker login [私有仓库地址]
docker push [私有仓库地址]/public/opslab/toolbox:版本标签
  1. K8s 侧配置 编写 Pod 模板,平台后端通过 API 动态创建临时 toolbox Pod;搭配 Web Terminal 组件(xterm.js),通过 WebSocket 实现网页终端访问。

  2. 生命周期管理 实训结束自动删除 Pod,实现环境回收、租户隔离。

二、基础认知:公共镜像 vs 自制镜像构建区别

  • 公共镜像(nginx、mysql):官方预先构建完成,直接拉取即可,无法修改内部工具版本;受平台网络策略限制很容易拉取失败。

  • 自制 toolbox 镜像:自主编写 Dockerfile,自定义预装软件、调整工具版本,推送到自有私有仓库;集群内部放行访问,稳定性可控,也是实训平台普遍采用的方案。

三、K8s 节点连接私有镜像仓库两种方式

  1. 节点层面配置(containerd) 在/etc/containerd/config.toml写入仓库地址、账号密码、镜像加速器,所有 Pod 共享该配置。 本次实训集群未采用此方案,全局检索kubernetes.io/dockerconfigjson无结果。

  2. 命名空间 ServiceAccount 绑定 Secret 创建kubernetes.io/dockerconfigjson类型 Secret 存放仓库凭证,绑定服务账号。 优势:可以按租户、命名空间隔离权限;本次平台就是使用该方式,学员权限无法读取密钥,因此无法外部拉取 toolbox 镜像。

四、补充:为什么本次环境无法拉取公网 Nginx 镜像

平台做了双层限制: ① 网络策略拦截 Worker 节点访问外网镜像仓库; ② 权限管控,仅信任内部 Harbor 地址。 因此出现 ErrImagePullImagePullBackOff,单纯更换国内公开镜像域名依旧无法解决。

如果你需要,我把这段直接无缝嵌入你整篇博客。