Pod资源管理与Harbor镜像仓库:Kubernetes基础链路实战指南

发布时间:2026/10/19 4:25:31
Pod资源管理与Harbor镜像仓库:Kubernetes基础链路实战指南
1. 先搞清楚Pod 到底是什么为什么它是 K8s 的第一课我接触 Kubernetes 这几年见过太多人一上来就折腾 Deployment、Service、Ingress结果 Pod 的概念模模糊糊。等到真正排查问题的时候才发现连这两个容器为什么不能互相访问重启后 IP 怎么变了这类基础问题都解释不清。所以这篇文章我想把 Pod 资源管理和后面要讲的 Harbor 镜像仓库串在一起讲因为这两个东西恰恰是 K8s 里最基础也最容易忽略的部分。先说一个最直白的类比Pod 就像一台逻辑主机。你在一台物理机上可以同时跑多个进程它们共享网络、共享文件系统视图在 K8s 里Pod 就是这样一个最小调度单元里面有若干个容器它们共享同一个网络命名空间、共享同一个存储卷因此彼此之间可以用 localhost 直接通信。我刚学 K8s 的时候有个误区以为最小调度单元是容器。其实不是。你可以直接创建一个容器但在生产环境里几乎没人这么干因为单个容器缺少伴生能力——比如日志收集、网络代理、配置热更新这些辅助功能往往需要一个 sidecar 容器配合主容器一起运行。把它们放进同一个 PodK8s 才能保证它们永远调度到同一个节点上一起启动、一起停止。这个设计直接决定了资源管理的粒度。你给 Pod 设置 CPU 和内存的 requests、limitsK8s 调度器就根据这些数值决定 Pod 落在哪个节点上kubelet 则根据这些数值决定要不要对容器做驱逐或杀死。所以Pod 资源管理的核心不是给 Pod 分多少资源这么简单而是在调度、运行、回收三个环节中如何用资源声明来控制集群行为。另外Harbor 和 Pod 有什么关系关系非常大。你的 Pod 镜像从哪来从镜像仓库来。如果你的集群想要拉取私有镜像就需要配置 imagePullSecrets而 Harbor 恰恰是我们最常用的私有镜像仓库之一。很多团队把 Harbor 部署好后发现 Pod 一直 ImagePullBackOff排查了半天最后发现是 Secret 里的 dockerconfigjson 格式不对或者证书没配。这篇文章我就把 Pod 资源管理和 Harbor 创建这两条线串起来讲正好覆盖从镜像准备到Pod 运行的完整链路。适合谁来读我建议三类人认真看刚接触 K8s 的运维/开发想把资源配额概念理清楚的平台工程师以及需要在离线环境里搭建私有镜像仓库的小团队。我会尽量少堆术语把命令和概念掰开揉碎讲。2. 资源管理的内核requests 和 limits 到底怎么填2.1 为什么要区分 requests 和 limits很多初学者把 requests 和 limits 当成一回事觉得我申请了资源K8s 就会给我预留。实际情况不是这样的。requests 是调度依据limits 是运行约束。调度器在决定 Pod 放到哪个节点时只看各节点上已分配资源的 requests 总和。比如说节点 A 有 4 核 CPU上面已经跑了一堆 Podrequests 总和到了 3.8 核那新 Pod 即使只 request 0.5 核调度器也会认为放不下了宁可选一个 requests 总和更低的节点。为什么因为调度器要防止节点资源超卖得太厉害出现 CPU 和内存争抢。而 limits 是 kubelet 在容器运行时的约束。CPU limits 通过 CFS 配额来实现限制的是 CPU 时间片内存 limits 直接决定 cgroup 的内存上限超过之后容器可能被 OOM Killer 杀掉或者触发 kubelet 的驱逐流程。我在实际项目中见过一个很典型的翻车案例某服务内存增长有波动团队图省事把 requests 和 limits 设置成完全一样比如都是 2Gi。结果业务高峰期内存冲到 2Gi 以上容器直接被 OOM 杀掉重启后又冲上去反复自杀。后来把 limits 放宽到 3Girequests 保持 2Gi问题就没了。当然这不是说 requests 永远要小于 limits有些无状态服务为了保障服务质量确实会设置 requests limits也就是所谓的 guaranteed QoS。关键是要理解这两者的语义区别再根据业务特征做选择。2.2 配置示例与 QoS 等级下面是一个典型的 Pod 资源声明我习惯把资源配置写在 Deployment 的模板里而不是裸 Pod 里apiVersion: apps/v1 kind: Deployment metadata: name: demo-app spec: replicas: 3 selector: matchLabels: app: demo-app template: metadata: labels: app: demo-app spec: containers: - name: main image: harbor.example.com/library/demo-app:1.2.0 ports: - containerPort: 8080 resources: requests: cpu: 500m memory: 512Mi limits: cpu: 2 memory: 1Gi这里有几个细节值得说。第一cpu 的单位 millicores。500m 表示 0.5 个 CPU 核心。如果写成2就是 2 个完整核心。注意 CPU 是可压缩资源就算 Pod 超过 CPU limits它也只是被限流不会被杀死但内存是不可压缩资源一旦超过 limits轻则容器被杀重则节点进入内存压力状态。第二requests 和 limits 的组合决定了 Pod 的 QoS 等级K8s 会据此在资源紧张时决定先杀谁。如果你给所有容器都设置了 requests 和 limits且每个资源的 requests 等于 limits那么这个 Pod 是 Guaranteed 等级优先级最高如果所有容器至少设置了 requests 或 limits 之一但存在 requests 小于 limits 的情况Pod 是 Burstable如果一个 Pod 里某个容器没有任何 requests 和 limits那整个 Pod 是 BestEffort节点内存不够时先杀它。我之前做过一个优化把集群里一批离线计算任务的 Pod 全部设为 BestEffort在线业务设为 Guaranteed。结果确实有效在线业务在高峰期几乎没有再被驱逐过。这个方法在资源紧张且业务优先级分明的集群里非常实用很多人只知道配置 resources却不知道 QoS 等级对驱逐顺序的影响。第三内存的 requests 也会影响驱逐。kubelet 会周期性检查节点的内存压力如果节点内存不足会根据 QoS 等级、实际内存使用和 requests 的偏差来驱逐 Pod。注意驱逐依据的是内存使用量是否超过 requests而不是超过 limits。所以你把 requests 设置得很低实际上会增加 Pod 被驱逐的风险——因为 kubelet 认为你只需要这么点内存。2.3 怎么从监控数据反推 requests 数值很多人填 requests 全凭感觉。我的做法是先不加 requests裸跑业务几天看监控里的 CPU 和内存 P95 甚至 P99 分位数然后按这个数值的 1.2 到 1.5 倍设 requests按 P99 的 1.5 到 2 倍设 limits。为什么要留余量因为调度器依据 requests 做容量规划如果你把 requests 设得比实际占用还高集群里能塞的 Pod 数量会大幅下降资源利用率很难看反过来如果 requests 设得比实际占用低太多节点超卖严重又会有驱逐和 OOM 风险。内存的 requests 建议尽量接近实际占用不要为了预留而盲目调大。因为内存不像 CPU不用就是浪费。CPU 的 requests 倒是可以稍微保守一点毕竟多数服务的 CPU 使用率本来就有周期性波动。我还习惯给关键服务设置 PodDisruptionBudget配合资源声明一起用。这样即使节点要维护或者被驱逐也能保证最少可用副本数不至于因为驱逐把整个服务打挂。这一套组合拳下来集群的稳定性会有质的提升。3. Harbor 部署私有镜像仓库从零到可用3.1 为什么选 Harbor 而不是 RegistryDocker 官方有 Registry 镜像两个命令就能起一个仓库但它的功能太少了没有 Web 界面、没有镜像清理策略、没有项目级别的权限控制。团队小的时候还能忍一旦人多了乱传镜像、删不掉垃圾镜像、权限混乱的问题全冒出来。Harbor 解决了这些痛点。它本身是一个完整的应用层服务包含 Web UI、RBAC 权限、镜像复制、漏洞扫描、垃圾回收、审计日志等模块。底层存储和 Docker Registry 兼容所以你可以直接推拉镜像不需要改客户端工具。Harbor 还支持 OIDC 对接企业身份认证这一点对稍微成规模的团队来说特别重要不用每来一个同事就在 Harbor 里手动建账号。部署方式上我推荐两种如果是测试环境用 docker-compose 最快如果生产环境更建议用 Helm Chart 部署到已有的 K8s 集群里。下面我把两种方式都讲一遍重点说配置细节因为 Harbor 的很多坑恰恰在配置文件里。3.2 基于 docker-compose 的快速部署Harbor 官方提供离线安装包在发布页面下载 harbor-offline-installer-xxx.tgz 后解压出来是一个 harbor 目录。我最开始部署的时候直接在官网下载、解压、复制配置结果连证书都没配就去改 harbor.yml跑起来以后登录报错白白浪费时间。正确的流程是wget https://github.com/goharbor/harbor/releases/download/v2.11.1/harbor-offline-installer-v2.11.1.tgz tar -xzvf harbor-offline-installer-v2.11.1.tgz cd harbor cp harbor.yml.tmpl harbor.yml然后编辑 harbor.yml。这一步有几个关键项hostname: harbor.example.com http: port: 80 https: port: 443 certificate: /data/certs/harbor.example.com.crt private_key: /data/certs/harbor.example.com.key harbor_admin_password: 此处写一个强密码 database: password: 数据库密码也要改 data_volume: /data/harbor我看到很多新手直接保留默认的 harbor_admin_password这等于把仓库大门敞开了尤其是 Harbor 还自带漏洞扫描、镜像复制功能万一真被人进来传恶意镜像后果很严重。所以第一件事就是改默认密码。配置改完后执行sudo ./install.sh这个脚本会先检查 Docker 是否正常、docker-compose 是否可用然后自动启动一系列容器。注意安装完成后访问https://harbor.example.com时如果浏览器提示证书不受信任别急着忽略——你需要把 Harbor 的 CA 证书加到 Docker 客户端的信任列表里否则后面docker login即使成功docker pull也可能因为证书问题失败。具体的证书处理放后面用单独的章节讲。3.3 基于 Helm 部署到 K8s 集群如果你的 K8s 集群已经搭好我更推荐用 Helm 部署 Harbor这样可以利用 K8s 的副本调度和存储能力。先添加 Helm 仓库helm repo add harbor https://helm.goharbor.io helm repo update然后准备一个 values.yaml至少覆盖这几个关键配置expose: type: ingress tls: enabled: true secretName: harbor-tls ingress: hosts: core: harbor.example.com controller: default externalURL: https://harbor.example.com persistence: enabled: true persistentVolumeClaim: registry: existingClaim: harbor-registry-pvc database: existingClaim: harbor-database-pvc redis: existingClaim: harbor-redis-pvc harborAdminPassword: 同样要改强密码这里最容易踩的坑是PVC 的容量规划。registry 用来存镜像 blob增长会非常快我建议至少给 200Gidatabase 存元数据虽然不大但 I/O 频繁建议用高性能存储redis 只做缓存崩溃了可以重启恢复普通存储就行。Helm 部署命令helm install harbor harbor/harbor -n harbor -f values.yaml部署完成后用kubectl get pods -n harbor查看所有 Pod 是否 Running。Harbor 会启动多个组件core、registry、portal、database、redis、jobservice 等。如果某个 Pod 反复重启先看日志大多数问题集中在数据库连接失败或者 PVC 权限不对。3.4 在 Harbor 里创建项目和镜像推送Harbor 安装好以后Web 界面登录左侧菜单进入项目点击新建项目。这里有一个很关键的选择项目访问级别。公开意味着任何人都可以拉取该项目下的镜像适合放一些基础镜像私有则只允许有权限的用户或机器人账号访问。我建议默认全部私有因为镜像本身包含业务代码和依赖信息暴露出去相当于泄露源信息。项目名称我喜欢用团队名/应用名的语义比如team-ai/ocr-service。但注意Harbor 项目名称和镜像命名空间是直接对应的。你创建一个项目叫demo那么推送命令就是docker tag demo-app:1.2.0 harbor.example.com/demo/demo-app:1.2.0 docker login harbor.example.com docker push harbor.example.com/demo/demo-app:1.2.0推送成功后在 Harbor 的镜像仓库页面就能看到demo/demo-app这个镜像tag 是 1.2.0。这个 tag 在 K8s 里就是harbor.example.com/demo/demo-app:1.2.0可以直接写进 Pod 的镜像字段。这里我想特别提醒一个 tag 规范问题。很多人图方便每次构建都用latest作为 tag。这在测试环境问题不大但生产环境一旦需要回滚你根本不知道哪个 latest 对应哪个版本。我经历过一次线上事故就是因为 latest 被覆盖回滚时拉回来的镜像竟然是最新的结果事故扩大了。所以建议至少采用语义化版本构建时间的双 tag 策略一个稳定版本号 tag一个带 Git commit 的 tag像1.2.0和1.2.0-abc1234。这样既有可读性又能精确定位。4. Pod 拉取镜像的关键环节imagePullSecrets 与证书信任4.1 为什么 Pod 拉取 Harbor 私有镜像会失败很多人在 Harbor 里把镜像推上去了但在 K8s 里创建 Pod 时一直卡在 ImagePullBackOff翻事件记录显示Failed to pull image ... pull access denied。原因很简单K8s 集群里的节点在拉取镜像时需要向 Harbor 提供认证信息而默认情况下节点并没有这些信息。你可以在命令行执行docker login harbor.example.com登录成功后在 shell 里手动 pull 镜像但这只对当前节点生效。集群有三个节点调度器把 Pod 放到另一个节点上照样拉不到镜像。正确的做法是把认证信息做成 Secret然后引用到 Pod 或 Deployment 里。4.2 创建 dockerconfigjson 类型的 Secret创建 Secret 的推荐方式是用 docker login 先生成本地认证文件然后让 kubectl 基于这个文件生成 Secretdocker login harbor.example.com kubectl create secret generic harbor-registry-secret \ --from-file.dockerconfigjson$HOME/.docker/config.json \ --typekubernetes.io/dockerconfigjson \ -n demo执行成功后Secret 的类型就是kubernetes.io/dockerconfigjson里面保存了 base64 编码的 docker 认证信息。你可以用下面命令验证kubectl get secret harbor-registry-secret -n demo -o yaml看到.dockerconfigjson字段下确实有内容说明创建成功。如果在生产环境里有多套集群、多个命名空间我建议用外部 Secrets 工具同步比如常用的 External Secrets Operator或者直接用 Helm 模板在每个命名空间动态生成。这里先不展开但记住 DoctrineSecret 是按命名空间隔离的每个命名空间都要单独创建除非你开启了跨命名空间的 secrets 同步机制。4.3 在 Deployment 中引用 Secret创建好 Secret 后在 Deployment 的 spec 里加imagePullSecretsapiVersion: apps/v1 kind: Deployment metadata: name: demo-app namespace: demo spec: replicas: 2 selector: matchLabels: app: demo-app template: metadata: labels: app: demo-app spec: imagePullSecrets: - name: harbor-registry-secret containers: - name: main image: harbor.example.com/demo/demo-app:1.2.0 resources: requests: cpu: 500m memory: 512Mi limits: cpu: 2 memory: 1Gi注意imagePullSecrets 作用于整个 Pod它会应用到 Pod 里所有容器。如果你的 Pod 里有多个容器并且各自的镜像仓库不同也可以给每个容器单独配置imagePullSecrets但在容器级别配置时K8s 只会为对应容器处理认证信息不会影响其他容器。4.4 证书不信任导致的拉取失败私有 Harbor 如果使用的是自签证书最常见的问题是 Docker 客户端和 K8s 节点都不信任该证书表现为x509: certificate signed by unknown authority。解决方法分两层。第一层让 Docker 客户端信任 CA。把 Harbor 的 CA 证书复制到/etc/docker/certs.d/harbor.example.com/ca.crt然后重启 Dockersudo mkdir -p /etc/docker/certs.d/harbor.example.com sudo cp harbor-ca.crt /etc/docker/certs.d/harbor.example.com/ca.crt sudo systemctl restart docker第二层让 K8s 节点信任 CA。需要把 CA 证书添加到节点的系统证书库sudo cp harbor-ca.crt /usr/local/share/ca-certificates/harbor-ca.crt sudo update-ca-certificates如果是 containerd 运行时可能还需要在/etc/containerd/certs.d/harbor.example.com/hosts.toml里配置信任。这个文件内容大致如下server https://harbor.example.com [host.https://harbor.example.com] ca [/etc/containerd/certs.d/harbor.example.com/ca.crt] capabilities [pull, resolve]改完以后重启 containerd。说实话这一层非常隐蔽很多人排查了半天最后发现是 containerd 没有配置 registry 的信任信息。如果你是离线环境或者内网环境提前把这些 CA 分发给所有节点非常重要。5. 实操案例从推镜像到 Pod 正常运行全流程5.1 准备镜像并推送假设我们要部署一个简单的 Nginx 服务修改首页内容后再推送到 Harbor。先在本地执行docker pull nginx:1.25 docker tag nginx:1.25 harbor.example.com/demo/nginx-custom:1.0.0 docker push harbor.example.com/demo/nginx-custom:1.0.0这里我没有先docker login实际会失败。正确顺序是docker login harbor.example.com docker push harbor.example.com/demo/nginx-custom:1.0.0登录后 Docker 会把认证信息写进~/.docker/config.json。推送成功后Harbor Web 界面刷新项目库能看到一个nginx-custom镜像tag 是 1.0.0。5.2 创建命名空间与 Secret接下来在 K8s 集群里创建命名空间和 Secretkubectl create namespace demo kubectl create secret docker-registry harbor-secret \ --docker-serverharbor.example.com \ --docker-usernameadmin \ --docker-passwordxxxxx \ --namespace demo这里我用的是kubectl create secret docker-registry也可以像我前面说的用--from-file.dockerconfigjson。两种效果一样看个人习惯。我一般更喜欢前者因为参数直观后者适合复用已有的 docker 登录状态。5.3 编写 Deployment 与 Service下面把 nginx Deployment 和 Service 写在一起方便一次性应用apiVersion: apps/v1 kind: Deployment metadata: name: nginx-custom namespace: demo spec: replicas: 2 selector: matchLabels: app: nginx-custom template: metadata: labels: app: nginx-custom spec: imagePullSecrets: - name: harbor-secret containers: - name: nginx image: harbor.example.com/demo/nginx-custom:1.0.0 ports: - containerPort: 80 resources: requests: cpu: 250m memory: 256Mi limits: cpu: 1 memory: 512Mi --- apiVersion: v1 kind: Service metadata: name: nginx-custom namespace: demo spec: selector: app: nginx-custom ports: - port: 80 targetPort: 80应用kubectl apply -f nginx-deployment.yaml然后观察 Pod 状态kubectl get pods -n demo -w如果一切正常你会看到 Pod 从 Pending 变成 ContainerCreating最后变成 Running。如果卡在 ImagePullBackOff用kubectl describe pod pod名称 -n demo查看事件大概率能直接看到认证失败或证书错误的原因。5.4 验证访问与资源配置的效果验证 Pod 是否正常对外服务可以先执行kubectl get svc -n demo拿到 ClusterIP 后在集群内找个节点或者直接进入 Pod 里用 curl 测试kubectl exec -it deploy/nginx-custom -n demo -- curl http://localhost能看到我们改过的 Nginx 首页内容说明镜像里改的静态文件已经生效。这个时候再回头看资源配置。我特意把 requests 设成 250m CPU 和 256Mi 内存limits 设成 1 CPU 和 512Mi 内存。你可以用kubectl top pods -n demo看一下实际占用。负载低的时候Pod 的实际内存可能只有几十 MiCPU 几乎为 0但配额已经保留好了。这也是 K8s 资源管理的一个特点requests 决定你占用的名义资源即使你不用调度器也不会把这部分分给其他 Pod。所以我们要时刻记住requests 设置过高等于浪费集群容量。6. 常见问题与排查思路6.1 Pod 一直 Pending最直接的原因是调度器找不到满足条件的节点。用kubectl describe pod查看事件如果出现0/3 nodes are available加上Insufficient cpu或Insufficient memory说明节点的可分配资源不足。这个时候不要急着加节点先用kubectl describe node 节点名查看已分配和可分配资源。很多时候是某个命名空间里有一堆僵尸 Deployment 占了 requests清理掉就能释放大量容量。还有一种是node.kubernetes.io/not-ready这种节点状态问题通常是节点网络或 kubelet 异常需要单独排查节点。6.2 ImagePullBackOff 的各种原因这个状态几乎天天见原因分三类认证失败、证书不可信、镜像 tag 不存在。认证失败时事件里会出现pull access denied或unauthorized。先把 Secret 删掉重建确保 docker 登录信息正确然后检查 Deployment 的imagePullSecrets名称是否和 Secret 匹配。有个很容易忽视的坑K8s 集群如果配置了 imagePullSecrets但 Secret 所在命名空间不对也会失败。很多人创建 Secret 的时候忘了指定-n demo结果 Secret 落在 default 命名空间Pod 引用不到自然失败。证书不可信时事件里会出现x509: certificate signed by unknown authority。处理方案就是我前面说的把 CA 加到节点和 containerd 的信任列表里。镜像 tag 不存在时事件里一般显示manifest unknown。检查一下 Harbor 项目里是否有这个 tag有时候你推的是1.0.0但 Deployment 里写成了1.0.0-linux-amd64就完全对不上。6.3 内存 OOM 反复重启如果 Pod 一直 CrashLoopBackOffkubectl logs里有Killed或者OOMKilled说明内存超限。先看监控里的实际内存趋势然后调整 limits。注意OOM 的原因可能是 limits 设置太低也可能是内存泄漏。我的建议是先把 limits 调大到前一天的 P99 数值的 1.5 倍观察是否稳定如果趋势还在持续上涨那基本就是业务代码的问题需要从应用侧解决。6.4 Harbor 垃圾回收后的镜像不可用Harbor 的垃圾回收功能可以在 Web 界面对话框中执行但很多人在不了解机制的情况下直接点立即回收结果项目里看不到某些旧镜像而部署历史还在引用。Harbor 的 GC 会把未被引用的 blob 删掉但镜像 manifest 如果被项目引用不会删。所以遇到GC 后 Pod 拉取失败多半是你手动删除了某些 tag又或者在 GC 前执行了旧的构建。这个问题的解决办法是定期维护镜像 tag别依赖 GC 做清理。6.5 机器人账号的使用Harbor 支持创建机器人账号这个功能非常实用。不用创建真实的用户只需在项目页面的机器人账户处创建一个带 pull 权限的账号然后把它用于 K8s 的 imagePullSecrets。这样即使机器人账号被泄露权限也仅限于拉取镜像不能修改项目配置。我在生产集群里的标准做法就是每个命名空间创建一个独立的机器人账号并把 Secret 的生命周期和命名空间绑定。这个做法不光安全还能在团队交接时减少账号冲突。7. 个人经验总结与扩展建议踩过这么多次坑之后我越来越觉得 K8s 和 Harbor 的组合需要一套固定的落地习惯而不是边踩坑边解决问题。第一资源管理一定要有监控支撑。没有监控就谈不上设 requests 和 limits。我推荐至少采集 CPU、内存、网络、磁盘四个维度的指标保留 30 天方便做容量规划。你在设置资源配额时参考的实际数据比任何经验公式都可靠。第二镜像仓库的账号和证书管理一定要提前设计。Harbor 部署完成后先花半小时创建好项目、机器人账号、分发 CA 证书到所有节点后边就能省下大量排查时间。尤其是 containerd 的 hosts.toml 配置很多节点系统重启后如果 containerd 服务重新生成配置你需要确认配置还会存在否则又是一次灵异事件。第三把 Deployment 的更新策略和镜像 tag 结合起来。我比较推荐使用不可变 tag比如 Git commit 短哈希或者构建流水号这样配合kubectl rollout status可以很清楚地看到当前线上跑的是哪个版本。如果使用 latest你就得依赖imagePullPolicy: Always但这在生产环境里极其危险因为你永远不确定拉回来的是什么。第四Harbor 的镜像复制功能可以顺手用起来。如果你有多套集群或者灾备需求可以在 Harbor 里配置复制规则把demo项目镜像同步到另一个 Harbor 实例。这样即使主 Harbor 挂了备用集群也能正常拉取镜像。注意复制时选择 TCP 还是 HTTP 的协议证书不匹配也会导致复制失败。最后再分享一个小技巧排查 Pod 拉取镜像问题时不要只看 K8s 事件还要看节点上的容器运行时日志。如果用的是 containerd一般是journalctl -u containerd -n 100可以看到具体的认证请求和拉取过程。很多时候 K8s 层面的报错信息是二次封装过的真正的错误藏在 containerd 日志里。这套流程走通之后你会发现从 Harbor 推镜像到 K8s 跑 Pod 是一条非常顺畅的链路。理解了 Pod 资源管理的内核再配一套健康的私有镜像仓库你的集群才能算真正迈入了稳定运行的门槛。后面如果还想深入可以继续研究 HPA 弹性伸缩、调度器自定义资源、亲和性和反亲和性策略。但先把今天的 Pod 资源和 Harbor 创建这两块基础打牢后面的每一层知识都能站得住脚。