☰
Harbor与Rancher搭建私有化Kubernetes镜像发布平台实战
2026/10/22 3:22:20 网站建设 项目流程

前一阵给某公司搭了一套私有化应用发布环境,用到的核心组件就是两个:Harbor管镜像仓库,Rancher管Kubernetes集群。简单说,Harbor负责让镜像在内网“存得下、拉得动、审得清”,Rancher负责让工作负载“发得上、滚得稳、看得见”。这篇文章把从0到1的完整流程、配置参数、以及我实际踩过的坑都写出来,适合正在做私有化交付的运维、开发同学参考。

整套链路并不复杂,核心就一条:开发或CI把镜像推到Harbor,Rancher管理的K8s集群通过镜像拉取凭据从Harbor获取镜像,然后调度到节点上跑起来。但真落地的时候,证书、凭据、存储、版本兼容这些前置工作才是大头。下面按实际搭建顺序展开。

1. 方案拆解:私有化场景下为什么绕不开这两个组件

1.1 私有化交付的三个核心痛点

先说第一个场景:客户环境完全内网隔离,外网不通,常见的公网镜像仓库根本访问不了。这时候如果还抱着“docker pull一下”的思维,项目根本交付不了,所有镜像必须先存在内网某个“本地仓库”里,这个仓库就是Harbor的定位。

第二点是安全审计和追溯。私有化环境通常有甲方审计要求,至少要知道谁在什么时间推送了哪个镜像、这个镜像包含了什么版本、有没有漏洞。Harbor自带项目权限、操作日志、漏洞扫描,这些是裸的registry镜像仓库给不了的。

第三点是多环境一致性。测试环境、预发布、生产环境不能各自手工docker build然后load,那样时间一长没人知道哪个镜像对应哪个版本。统一从Harbor拉取固定tag,才能保证环境之间只差配置,不差代码。

Rancher解决的是另一层问题:多套K8s集群的管理。一个项目可能包含开发集群、生产集群,每个集群里有多个命名空间、多套应用,如果全靠kubectl操作,权限控制和可视化都跟不上。Rancher把这些统一收口,开发、测试、运维在UI上就能完成发布和回滚。

1.2 Harbor和Rancher的职责边界

可以用一句话分清边界:Harbor管“静态的镜像”,Rancher管“运行的负载”。

具体来说,Harbor承担的是镜像构建后的存储分发,包括registry、项目空间、用户和机器人账号、镜像保留策略、跨机房复制。Rancher承担的是集群生命周期、节点管理、工作负载、配置字典、密钥、服务发现、负载均衡、应用商店。两者之间并不是强绑定,但私有化场景中互操作最常见的就是:Rancher通过imagePullSecret从Harbor拉镜像,并且通过私有CA证书完成TLS信任。

数据流向也很直接:开发把代码构建成镜像,push到Harbor;Rancher创建Deployment时指定镜像地址,调度器把Pod分配到节点,节点上的容器运行时从Harbor把镜像拉下来,启动容器。整个过程中,Harbor是镜像源,Rancher是编排者,缺一不可。

1.3 版本选型与兼容性

这是很多人忽略的一步。Rancher本身是一个管理平面,对它来说最关键的是与Kubernetes版本的兼容矩阵,和与容器运行时的兼容情况。Harbor版本相对独立,需要关注的是与docker compose、containerd、以及底层操作系统之间兼容性。

我的建议是不要盲目追最新版。私有化环境交出去以后,升级周期非常长,必须选择已经稳定迭代了至少一两个minor版本的产品。可以用下面这张表做选型参考,具体版本号以官方支持矩阵为准。

组件定位选型要点
Harbor镜像仓库优先离线安装包,选择你熟悉数据层的版本
RancherK8s管理对照K8s版本兼容矩阵,不要跨大版本跳跃
Kubernetes容器编排选择Rancher支持且节点系统兼容的稳定版本
容器运行时节点组件containerd优先,配置简单且资源占用低

版本之间最好整体做一次“组合验证”:Harbor、Rancher、K8s、节点OS都固定下来,然后跑一遍完整的构建、推送、部署、回滚测试。只有验证通过再交付,后续能少一大半问题。

2. 环境准备与初始化

2.1 机器规划与资源评估

私有化环境没有统一的硬件标准,但可以按我的经验给一个最小参考。

管理机跑Harbor和Rancher,建议8核16GB内存起步,磁盘至少200GB,因为Harbor的数据库、镜像元数据、Rancher的etcd都会落在这台机器上。如果还要跑漏洞扫描和镜像复制,磁盘建议放到500GB。

业务节点至少两台,每台4核8GB内存,系统盘100GB,数据盘按需挂载。如果跑有状态服务,需要额外准备存储卷,可以是本地目录、NFS或者云平台块存储,前提是得先评估好容量。

镜像存储容量这里给一个估算公式:仓库空间 = 日均镜像数 × 平均镜像大小 × 保留天数 × 1.2。假设每天构建20个镜像,每个1.5GB,保留30天,那么20 × 1.5 × 30 = 900GB,再预留20%给垃圾回收执行期的临时空间,差不多要1.1TB。这个数字在上线前就要跟客户谈清楚,否则Harbor磁盘满了以后,推送和拉取会一起挂掉。

2.2 基础系统配置

所有节点都需要做这几项操作:配置静态IP和主机名解析、统一时间同步、关闭swap、加载br_netfilter内核模块、配置容器运行时。

时间同步不能省,K8s和Harbor的证书校验、调度器、etcd都需要依赖时间一致性。时间错乱会导致证书验证失败,而且这种问题非常隐蔽。建议所有节点配置内网NTP源,并且监控时间偏移量。

主机名解析也很关键。Harbor和Rancher的域名建议用内网DNS解析,比如Harbor叫registry.example.internal,Rancher叫rancher.example.internal。不要用IP地址直接访问,因为证书签发、服务跳转、镜像推送都依赖稳定的域名,一旦IP变了,后续改动代价极大。

交换分区一定要关,至少保证系统不在磁盘慢速换页和容器内存回收之间来回摇摆。这一步在K8s初始化阶段就会校验,如果在worker节点上还开着swap,kubelet会直接拒绝启动。

2.3 自建CA证书

私有化环境最大的坎是TLS证书。公网证书没法给内网域名签发,所以正常路线是自己搭建一个内网CA,然后用这个CA给Harbor、Rancher、以及后续的Ingress地址签发证书。

为什么一定要做CA而不是用HTTP?因为Harbor和K8s节点之间的镜像拉取是HTTPS,如果手贱配置成insecure-registry,短时间能用,但任何一个安全评审都会让你改掉。而且insecure模式一旦遇上镜像损坏、中间人篡改,你根本无法察觉。正规做法是生成根证书,把根证书分发到所有节点、Docker/containerd的信任目录,并更新证书链。

自签证书有几个细节要注意:证书的SAN(Subject Alternative Name)必须同时包含域名和访问IP;证书有效期不要设太长,也别太短,我一般设3到5年,并在日历上留好到期提醒;Rancher访问证书和Harbor镜像证书建议用不同的域名,避免后面改配置互相影响。

3. Harbor私有镜像仓库部署与配置

3.1 配置Harbor安装文件

在私有化环境,最稳妥的方式是使用离线安装包。下载离线包后,在管理机上解压,然后修改harbor.yml配置。

harbor.yml里最重要的几项是:

  • hostname:必须是客户端会访问的域名,比如registry.example.internal
  • http.port和https.port:一般默认就行,但如果是管理机已占用端口,要提前改掉
  • certificate:指向刚才生成的Harbor证书和私钥路径
  • harbor_admin_password:初始管理员密码,必须改成强密码并记录到密码库
  • data_volume:指定所有持久化数据的存放路径,建议放到独立数据盘,比如/data/harbor

如果Harbor需要对外开放HTTPS,但是访问方没有统一信任根证书,可以把根证书也下载到Harbor的nginx目录下,作为中间证书一起下发,减少客户端的证书链报错。

配置完以后,运行./install.sh,Harbor会以docker-compose形式拉起多个组件。这里我建议先不要加漏洞扫描器,第一版环境先确保仓库稳定,后续按需要再启用。

3.2 验证Harbor服务状态

安装完成以后,浏览器访问https://registry.example.internal,用配置的管理员账号登录。首次登录后先把管理员密码在系统设置里再确认一遍,接着创建项目。

Harbor项目模型需要解释一下:项目类似“团队空间”,镜像命名是registry域名/项目名/镜像名:tag。私有化场景建议项目按业务线分,不要全部都堆在library公共项目里。

接着创建用户。普通开发账号给“开发者”权限,只允许push和pull;CI机器人账号建议创建“机器人账户”,权限设置为指定项目下的只读或者推送,并且记录好token。机器人账户是长期运行的关键,可以随时轮转,不影响具体开发人员。

3.3 配置镜像保留策略和垃圾回收

镜像版本只增不减,是每个Harbor仓库都会遇到的事。时间一长,存储盘被垃圾镜像塞满,拉取和推送都会变慢。

我建议在项目属性里配置保留策略:按tag数量保留最近30个,或者按时间保留最近30天。这样自动化构建产生的历史版本不会无限累积,同时线上回滚还能找到最近几天的版本。

垃圾回收需要在UI上手动触发,或者通过API创建定时任务。执行GC时Harbor会进入只读模式,所以建议放在凌晨低峰期。GC不是立刻清磁盘,它只是标记可回收的blob,需要等到blob被真正删除后才释放空间。执行GC后观察磁盘占用,如果空间没有减少,多半是有tag还在引用,这时检查保留策略是否生效。

3.4 配置Harbor跨机房复制(可选)

有些客户要求两地三中心,镜像需要从主中心复制到备份中心。Harbor自带复制功能,可以在“管理”里配置复制规则,把某个项目或者全部项目推送到另一套Harbor。

跨机房复制最容易忘的点是两端CA证书互信。如果两套Harbor都用了各自私有的根证书,那么复制时需要把对方的根证书导入到本地的信任范围。否则复制规则会一直报证书校验失败,但日志里又只看得到握手错误。

复制方式我推荐用“推送模式”,即主中心主动把新镜像推送到备份中心,这样备份中心不需要开放外部端口,在一定程度上降低暴露面。

4. Rancher部署与Kubernetes集群接入

4.1 部署Rancher Server

Rancher Server本身可以运行在单容器里,也可以部署成K8s集群里的高可用模式。对于项目初期的私有化交付,我倾向于先用单容器跑Rancher,因为简单、便于排错,后续如果节点规模上去了再迁移。

以Docker方式启动时,需要把/var/lib/rancher挂载到宿主机数据盘,比如:

docker run -d --name rancher \ --restart=unless-stopped \ -p 443:443 -p 80:80 \ -v /data/rancher:/var/lib/rancher \ -v /data/certs:/etc/rancher/ssl \ rancher/rancher:稳定版本号

注意这里不能直接写latest,要指定具体的镜像版本号。否则Rancher大版本升级时,单容器启动可能自动拉取新版本,导致配置不兼容。挂载证书目录时,需要把之前签发的Rancher证书文件和key文件放进去,并保证权限是600或644,否则nginx读取不到证书会启动失败。

启动后访问https://rancher.example.internal,设置管理员密码,完成引导。

4.2 创建或导入Kubernetes集群

Rancher Server起来后,下一步是接入集群。有两种路线:一种是从零创建自定义集群,Rancher通过SSH在节点上自动安装K8s;另一种是导入已有的K8s集群。

我建议在私有化交付时用自定义集群方式,因为Rancher能统一管理节点角色、版本升级、以及后续的节点扩容。创建集群时选择“自定义”,填好集群名称,然后指定节点角色。

节点角色分配建议:管理机不承担业务负载,可以作为etcd和controlplane节点;为稳妥至少要有两个etcd节点,但小环境至少保证一个etcd加一个controlplane。worker节点就放实际应用。

在UI上生成节点注册命令后,到对应节点上执行。执行过程会花几分钟,Rancher后台会安装容器运行时、kubelet、kube-proxy等。如果节点上之前装过其他版本K8s,最好先清理干净,否则集群加入过程中会出现各种冲突。

4.3 配置Harbor凭据与镜像仓库

集群创建完成以后,首先要配置Harbor的拉取凭据。Rancher并不需要显式“添加镜像仓库”,真正起作用的是K8s的Secret。

在目标命名空间下创建Secret,类型选“Docker Registry”,填Harbor地址registry.example.internal、机器人账号和密钥。比如在demo-ns命名空间下创建harbor-secret。

这一步有个我经常提醒别人的坑:创建完Secret并不是全局生效的,它只对当前命名空间有效。所以每个要部署应用的命名空间都需要创建一份Secret。工作负载在部署时,需要把这个Secret添加到imagePullSecrets中,Pod调度到节点后,kubelet才能用这个Secret去Harbor拉取镜像。

如果多个命名空间都需要同一份凭据,可以用脚本批量创建,但注意不要把所有命名空间塞进默认Secret,避免权限扩散。

4.4 配置私有CA信任到所有节点

光有Secret还不够,节点上的容器运行时也必须信任Harbor的CA证书。否则Secret即使正确,kubelet在拉取镜像时依然会报x509证书校验失败。

处理方式是把根证书复制到每个节点的/etc/docker/certs.d/registry.example.internal/目录(如果使用Docker),并命名为ca.crt;如果使用containerd,则放到/etc/containerd/certs.d/registry.example.internal/下,或者使用类似路径让containerd识别。

很多团队会忽略这个步骤,导致在管理端明明能拉镜像,节点上一拉就失败,而且报错信息里看不到明文密码错误,只见证书问题。这个问题排查起来耗时很长,所以初始化节点时就应该把信任链做成标准动作。

5. 用Harbor和Rancher完成一次应用发布

5.1 构建镜像并推送到Harbor

设定一个实际场景:发布一个名为order-svc的订单服务。先在开发构建机上执行登录:

docker login registry.example.internal -u 'robot$cicd' -p 'token字符串'

登录成功后再构建镜像:

docker build -t registry.example.internal/demo/order-svc:1.0.0 . docker push registry.example.internal/demo/order-svc:1.0.0

镜像tag规范非常重要。强烈推荐版本号或者时间戳+commit号,比如1.0.0或20250612-abc1234。至少能让人一眼看出版本归属。不要用latest作为唯一tag,私有化环境下无版本号等于不可追踪。

如果镜像构建依赖基础镜像,而构建机又无法访问外网,需要提前把基础镜像导入Harbor,并在Dockerfile里通过域名引用Harbor中的基础镜像。这会增加一条构建前提,好处是让整个构建链完全内网化。

5.2 在Rancher中创建工作负载

登录Rancher,进入目标集群和目标命名空间,点击“工作负载”创建Deployment。

填写镜像名时直接填完整地址:registry.example.internal/demo/order-svc:1.0.0。下一步添加imagePullSecret,选择刚才创建的harbor-secret,否则Pod会一直ImagePullBackOff。

资源限制是私有化交付的重点。不要只填Requests不填Limits,也不要把Limits设成跟Requests一样高,否则节点利用率很低。以一个订单服务为例,压测得出单实例需要1核CPU、512MB内存,突发峰值可以到1.5核和1GB内存。那么Requests设1核/512MB,Limits设2核/1GB比较合理,既能保证QoS等级,又给突发流量留了余量。

副本数可以通过公式估算:副本数 = 期望峰值QPS / 单实例QPS × 1.3。如果单实例支持200QPS,期望峰值是800QPS,那么副本数约为800 / 200 × 1.3 = 5.2,取整6个,预留约30%冗余。

健康检查一定要配上。就绪探针建议用HTTP探针访问应用的/healthz路径,探针刚启动时给一个initialDelaySeconds,比如10秒,避免应用还没初始化就被杀掉。

5.3 启动滚动更新与回滚

Deployment的默认发布方式是滚动更新。为了保证发布过程中不出现长时间停机,建议配置:

  • maxSurge: 25%,允许新Pod先起来,超出期望副本数25%
  • maxUnavailable: 0%,保证老Pod在所有新Pod就绪前不被杀掉
  • minReadySeconds: 30秒,让Pod至少稳定运行30秒后才认为“可用”

配置好后,升级镜像tag从1.0.0到1.0.1。Rancher会在界面上展示新老Pod的实时状态。如果新版本异常,可以通过“回滚”操作选择上一个部署版本。

回滚的底层就是kubectl rollout undo,Rancher只是把历史工作负载配置做成可视化了。但要注意,回滚只恢复应用配置,镜像tag仍是当前指定的tag。如果新tag已经推到Harbor,旧tag又被垃圾回收删除了,就会拉不到旧镜像。所以发布前务必要确保旧tag还在仓库中,这也是前面制定保留策略的意义之一。

5.4 灰度发布的一种轻量做法

私有化场景不一定有完整的灰度平台,但可以用Rancher的多工作负载实现。把order-svc拆成两个Deployment:order-svc-stable和order-svc-canary,前端入口通过Service指向两组Pod。先升级canary副本到1个,验证接口和日志稳定后,再把stable副本数量逐步调整到0。

这种做法不需要引入额外组件,适合没有流量网关的小规模交付。如果后续灰度需求变大,再考虑接入其他流量治理能力,但那是后话,初版链路不需要一次做满。

6. 实际踩坑与排查技巧

6.1 常见问题速查表

现象原因解决方法
Pod状态ImagePullBackOff节点不信任Harbor证书或imagePullSecret缺失检查节点CA信任目录,确认Deployment的imagePullSecrets
推送镜像时返回401登录凭据错误或机器人账户权限不足重新生成机器人token,确认项目权限和过期时间
Harbor GC后磁盘没变小仍有tag引用旧blob触发保留策略清理,低峰期再执行GC
Rancher Server端口起不来证书文件权限或路径不对检查证书目录权限和nginx日志,确保证书链完整
节点加入集群慢节点初始化未清理旧K8s或swap未关清干净旧状态,关闭swap并重试
镜像仓库空间满保留策略未配置或残留超大镜像配置保留策略,排查大blob项目

这六类问题我基本都遇到过。尤其证书相关,一旦出现“x509: certificate signed by unknown authority”报错,直接按“节点CA信任不对”排查,不要浪费时间去翻应用日志。

6.2 几条值得长期保留的习惯

第一,Harbor的机器人账户要建细粒度权限。给CI的token只开指定项目的推送权限,给业务节点的拉取token只开只读权限。所有token都设置到期策略,到期前主动轮转,避免一个泄露的token影响所有项目。

第二,每次发布前手工给镜像打个“golden”标签。比如正式上线前,把当前版本镜像另外打个order-svc:prod-golden-20250612。一旦线上跑了一段时间需要快速回退,直接指向这个标签,而不是依赖可能被回收的普通tag。

第三,日志和磁盘告警一定要在交付前配好。Rancher Server节点最容易因为容器日志、编排日志、审计日志把磁盘写满。磁盘满了以后,etcd会触发告警,集群调度可能停止,严重情况下K8s会出现只读错误。所以至少配置两个阈值:磁盘使用率85%告警、95%紧急处理。

第四,Harbor的GC和镜像保留策略要结合业务节奏。不要在发布高峰期跑GC,否则并发推送可能报500或超时。把GC定在凌晨两三点,执行前看一眼是否有长期镜像同步任务在跑。

6.3 升级和备份的底线操作

私有化环境的升级比互联网环境更谨慎。Rancher在升级前必须对etcd做快照,快照不是备份Rancher容器本身,而是备份后端K8s数据。可以用Rancher UI触发etcd快照,也可以直接在etcd节点手动执行快照命令,两者至少保留一份。

Harbor升级前需要备份两处:data_volume里除了registry数据,还有数据库数据。最稳妥方式是停机后直接对数据卷做文件快照,然后小版本跳级升级,不要跨多个大版本直接升。

我在实际项目里踩过最狠的坑就是Rancher所在节点磁盘被日志写满,etcd告警,整个集群调度都受影响。后来在所有组件层面统一加了日志轮转和磁盘告警,才算是把这个隐患堵住。工具链本身不难,难的是把证书、凭据、资源预留这些基础项做扎实。如果你也正在搭私有化发布链路,建议先按这套流程在小环境完整跑一遍,再把镜像保留策略和告警补上,后面交付会省心很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询