首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
Harbor证书更新全链路指南:服务端与客户端避坑实践
📅 2026/10/16 8:10:30
✍️ 爱科研究院
👁 阅读 3,247
1. 证书到期这件事为什么总在半夜找上门做运维的人大概都有过这种体验凌晨两点被监控告警叫醒打开一看镜像仓库的Web界面打不开CI流水线全线飘红所有节点的镜像拉取全部超时。登录服务器一查日志满屏的x509: certificate has expired or is not yet valid。没错证书过期了。Harbor作为企业级容器镜像仓库默认通过HTTPS对外提供服务而HTTPS依赖TLS证书。无论是自签证书还是从正规CA机构申请的证书都有有效期。自签证书通常一年商业证书现在最长也就一年出头。一旦证书过期整个镜像仓库的推送和拉取链路会瞬间瘫痪所有依赖它的Kubernetes集群、CI/CD流水线、开发人员的本地环境全部受影响。这个问题的麻烦之处在于它不像磁盘满了那样有渐进过程而是到点就死没有任何缓冲。更麻烦的是很多团队在最初部署Harbor时用的是自签证书证书文件散落在各个节点、Docker配置、containerd配置、Kubernetes的Secret里更新的时候如果只换了Harbor服务端的证书客户端那边不跟着换照样报错。所以这篇文章想聊的不只是怎么执行几条命令把证书换掉而是把整个证书更新的完整链路讲清楚证书怎么生成、Harbor怎么加载、客户端怎么信任、更新后怎么验证、哪些地方容易漏掉。这套流程我在不同规模的环境里反复做过多次踩过的坑足够写一篇避坑指南了。提示本文讨论的是Harbor自身HTTPS证书的更新不涉及任何网络代理或跨境访问相关内容。所有操作均在合规的内网或公网环境下进行。2. 先搞清楚Harbor的证书到底用在哪些地方很多人一上来就急着替换证书文件结果换完之后发现有的节点好了、有的节点还在报错。根本原因是没有理清Harbor证书的完整使用链路。在动手之前先把这张证书地图画出来后面操作才不会漏。2.1 服务端Harbor核心组件加载的证书Harbor的架构里对外提供HTTPS服务的入口是harbor-core和harbor-portal前面的nginx在较新版本中是harbor-nginx或内置的proxy容器。这个nginx容器在启动时会读取挂载进来的证书文件默认路径是/etc/harbor/ssl/下的server.crt和server.key具体路径取决于你的harbor.yml配置。在harbor.yml中HTTPS配置段长这样https: port: 443 certificate: /your/cert/path/yourdomain.crt private_key: /your/cert/path/yourdomain.key这里有个关键点harbor.yml里配置的路径是宿主机上的路径Harbor的prepare脚本会把这些文件复制到common/config/nginx/cert/目录下然后通过volume挂载到nginx容器里。所以更新证书时你改的是宿主机上的源文件但真正生效的是复制后的副本。2.2 客户端Docker和containerd的信任链服务端证书换好了客户端如果不信任新证书照样拉不了镜像。客户端的信任机制分两种Docker把CA证书放到/etc/docker/certs.d/yourdomain.com/ca.crt然后重启Docker服务。containerd把CA证书放到/etc/containerd/certs.d/yourdomain.com/ca.crt或者在config.toml中配置ca字段。如果是Kubernetes集群还要考虑kubelet使用的容器运行时是Docker还是containerd两者的证书目录不同。很多团队在升级Kubernetes版本时把Docker换成了containerd但更新证书时还按Docker的老路径去放结果就是kubelet拉镜像一直失败。2.3 中间层负载均衡和反向代理如果Harbor前面还挂了负载均衡器比如Nginx、HAProxy或者云厂商的LB那么LB上也可能配置了证书。这种情况下客户端看到的是LB的证书而不是Harbor本身的证书。更新时要么只更新LB证书要么两层都更新取决于你的架构。我见过一种典型情况Harbor前面挂了一个Nginx做反向代理Nginx上配了证书Harbor自己也配了证书。结果更新时只换了Nginx的Harbor的还是旧的。虽然客户端访问没问题但Harbor内部组件之间通信时用的是自己的证书导致某些功能异常。2.4 一张表看清所有需要更新的位置位置文件路径生效方式容易遗漏Harbor服务端harbor.yml配置的路径重新执行prepare并重启否Docker客户端/etc/docker/certs.d/domain/ca.crt重启Docker经常漏containerd客户端/etc/containerd/certs.d/domain/ca.crt重启containerd经常漏Kubernetes Secretkubectl get secret中的tls类型更新Secret内容容易漏负载均衡器取决于LB类型重载配置视架构而定其他节点各节点本地路径逐节点更新最容易漏这张表建议在操作前打印出来每完成一项打个勾避免遗漏。3. 生成新证书自签和CA签发的不同处理方式证书更新第一步是拿到新证书。根据你原来的证书类型处理方式不同。3.1 自签证书的重新生成如果原来用的是自签证书那更新时继续自签就行。自签证书的好处是完全自主可控不依赖外部CA适合纯内网环境。生成自签证书的核心是创建一个自己的CA然后用这个CA去签发服务器证书。先创建CA私钥和CA证书openssl genrsa -out ca.key 4096 openssl req -x509 -new -nodes -sha512 -days 3650 \ -subj /CCN/STBeijing/LBeijing/Oexample/OUPersonal/CNMyCA \ -key ca.key \ -out ca.crt然后生成服务器私钥和CSRopenssl genrsa -out yourdomain.com.key 4096 openssl req -sha512 -new \ -subj /CCN/STBeijing/LBeijing/Oexample/OUPersonal/CNyourdomain.com \ -key yourdomain.com.key \ -out yourdomain.com.csr这里有个关键细节CN字段必须和你的Harbor访问域名完全一致。如果通过IP访问CN就写IP。但更推荐用域名因为IP地址变动时证书就得重新签。接下来需要创建一个extfile指定SANSubject Alternative Namecat v3.ext -EOF authorityKeyIdentifierkeyid,issuer basicConstraintsCA:FALSE keyUsage digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage serverAuth subjectAltName alt_names [alt_names] DNS.1yourdomain.com DNS.2*.yourdomain.com IP.1192.168.1.100 EOFSAN这个字段非常重要。现代浏览器和很多客户端已经不再检查CN字段而是检查SAN。如果SAN里没有你访问时用的域名或IP证书就会被判定为不匹配。我见过有人CN写对了但SAN没写结果Chrome直接拒绝访问。最后用CA签发服务器证书openssl x509 -req -sha512 -days 3650 \ -extfile v3.ext \ -CA ca.crt -CAkey ca.key -CAcreateserial \ -in yourdomain.com.csr \ -out yourdomain.com.crt3.2 CA签发证书的更新流程如果原来是从正规CA机构申请的证书更新流程通常是生成新的CSR提交给CACA审核后签发新证书。这个过程可能需要几天时间所以一定要提前规划不要等到证书快过期了才动手。拿到CA签发的新证书后通常会得到一个证书链文件包含服务器证书和中间CA证书和一个私钥文件。证书链的顺序很重要服务器证书在前中间CA在后。顺序错了某些客户端会报unable to get local issuer certificate。3.3 证书格式的转换有时候CA给的是PFX或P12格式的证书需要转换成PEM格式openssl pkcs12 -in yourdomain.pfx -nocerts -nodes -out yourdomain.key openssl pkcs12 -in yourdomain.pfx -clcerts -nokeys -out yourdomain.crt转换后记得检查私钥是否加密。如果私钥有密码Harbor启动时会失败因为nginx无法交互式输入密码。用这个命令去掉密码openssl rsa -in yourdomain.key -out yourdomain.key3.4 验证新证书的正确性在替换之前先用openssl验证一下证书和私钥是否匹配、证书链是否完整# 检查证书和私钥是否匹配 openssl x509 -noout -modulus -in yourdomain.com.crt | openssl md5 openssl rsa -noout -modulus -in yourdomain.com.key | openssl md5 # 两个md5值必须一致 # 检查证书有效期 openssl x509 -noout -dates -in yourdomain.com.crt # 检查SAN字段 openssl x509 -noout -text -in yourdomain.com.crt | grep -A1 Subject Alternative Name这三个检查做完基本可以确认证书没问题了。我习惯在替换前把这些验证跑一遍避免替换后才发现证书有问题那时候排查起来更麻烦。4. 替换Harbor服务端证书的完整操作证书准备好了接下来是替换。这一步的核心是让Harbor重新加载新证书。4.1 备份现有配置和证书任何变更操作之前备份是第一位的。需要备份的东西包括# 备份harbor.yml cp /path/to/harbor/harbor.yml /path/to/harbor/harbor.yml.bak # 备份旧证书 cp /path/to/cert/yourdomain.com.crt /path/to/cert/yourdomain.com.crt.old cp /path/to/cert/yourdomain.com.key /path/to/cert/yourdomain.com.key.old # 备份Harbor的配置目录 cp -r /path/to/harbor/common/config /path/to/harbor/common/config.bak备份不只是为了回滚更重要的是在出问题时能快速对比新旧配置的差异。我有一次更新后Harbor起不来就是靠对比备份的配置发现是harbor.yml里证书路径写错了。4.2 替换证书文件并重新生成配置把新证书放到harbor.yml中配置的路径下覆盖旧文件。然后执行cd /path/to/harbor ./prepareprepare脚本会做几件事读取harbor.yml生成docker-compose.yml把证书文件复制到common/config/nginx/cert/目录。如果这一步报错通常是harbor.yml格式有问题或者证书路径不对。执行完prepare后建议检查一下证书是否被正确复制ls -la /path/to/harbor/common/config/nginx/cert/ # 确认文件时间戳是刚刚更新的4.3 重启Harbor服务重启有两种方式取决于你的Harbor版本和部署方式# 方式一docker-compose方式 docker-compose down docker-compose up -d # 方式二使用Harbor自带的脚本 docker-compose stop docker-compose start推荐用down再up的方式因为restart有时候不会重新读取挂载的证书文件。down会完全销毁容器up时重新创建确保新证书被加载。重启完成后检查容器状态docker-compose ps # 所有容器应该是Up状态如果有容器反复重启查看日志docker-compose logs nginx docker-compose logs harbor-core4.4 验证服务端证书已生效用openssl直接连接Harbor的443端口查看返回的证书信息openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2/dev/null | openssl x509 -noout -dates -subject输出的日期应该是新证书的有效期。如果还是旧日期说明证书没有正确加载需要检查prepare是否执行成功、容器是否真正重启了。注意有些环境里Harbor前面有缓存层或者CDN可能需要额外清理缓存才能看到新证书。内网环境一般不存在这个问题。5. 客户端信任更新比服务端更容易翻车的环节服务端证书换好了只是完成了一半。客户端不信任新证书照样拉不了镜像。而且客户端这一侧涉及的面更广更容易出问题。5.1 Docker客户端的证书更新Docker信任自签证书的方式是在/etc/docker/certs.d/下创建以域名命名的目录把CA证书放进去mkdir -p /etc/docker/certs.d/yourdomain.com cp ca.crt /etc/docker/certs.d/yourdomain.com/ca.crt systemctl restart docker注意这里放的是CA证书不是服务器证书。很多人把yourdomain.com.crt放进去了结果Docker还是不信任。因为Docker需要的是签发服务器证书的那个CA的证书用来验证服务器证书的合法性。如果用的是CA机构签发的证书通常操作系统已经内置了这些CA的根证书Docker会自动信任不需要手动放。但如果是自签CA就必须手动放。5.2 containerd客户端的证书更新containerd的证书配置方式和Docker不同。在较新版本的containerd中推荐使用certs.d目录mkdir -p /etc/containerd/certs.d/yourdomain.com cp ca.crt /etc/containerd/certs.d/yourdomain.com/ca.crt systemctl restart containerd如果containerd版本较老可能需要在config.toml中配置[plugins.io.containerd.grpc.v1.cri.registry.configs.yourdomain.com.tls] ca_file /etc/containerd/certs.d/yourdomain.com/ca.crt改完配置后重启containerd。这里有个坑containerd重启后已经运行的Pod不会自动重新拉取镜像需要重建Pod才能验证。5.3 Kubernetes集群中的证书更新Kubernetes集群里kubelet通过容器运行时拉取镜像。如果容器运行时是containerd按上面的方式配置即可。但如果是Dockerkubelet会调用Docker的APIDocker的证书配置生效。另外如果集群中有使用imagePullSecrets的方式拉取镜像还需要更新对应的Secretkubectl create secret docker-registry harbor-secret \ --docker-serveryourdomain.com \ --docker-usernameadmin \ --docker-passwordyourpassword \ --dry-runclient -o yaml | kubectl apply -f -注意imagePullSecrets里存的是认证信息不是TLS证书。TLS证书的信任是节点级别的和Secret无关。但更新Secret可以确保认证信息也是最新的。5.4 批量更新多节点的脚本思路如果集群节点很多逐台登录更新效率太低。可以写一个简单的脚本批量分发#!/bin/bash DOMAINyourdomain.com CA_FILE/path/to/ca.crt NODES(node1 node2 node3) for node in ${NODES[]}; do echo Updating $node... scp $CA_FILE $node:/etc/docker/certs.d/$DOMAIN/ca.crt scp $CA_FILE $node:/etc/containerd/certs.d/$DOMAIN/ca.crt ssh $node systemctl restart docker containerd done这个脚本只是示例实际使用时需要根据你的节点列表和目录结构调整。关键是确保每个节点上的证书文件都更新了并且对应的服务都重启了。5.5 验证客户端信任是否生效在客户端节点上执行# 测试Docker docker login yourdomain.com docker pull yourdomain.com/library/nginx:latest # 测试containerd crictl pull yourdomain.com/library/nginx:latest如果登录和拉取都成功说明客户端信任已经生效。如果报x509错误检查CA证书路径和文件内容是否正确。6. 更新后必做的验证清单和常见故障排查证书更新完成后不能只看Harbor的Web界面能打开就认为万事大吉。需要做一轮完整的验证确保所有链路都正常。6.1 分层验证清单验证层级验证方法预期结果服务端证书openssl s_client查看证书日期显示新有效期Web界面浏览器访问Harbor地址正常打开无证书警告Docker推送docker push测试镜像推送成功Docker拉取docker pull测试镜像拉取成功containerd拉取crictl pull测试镜像拉取成功Kubernetes Pod创建测试PodPod正常运行CI流水线触发一次构建流水线通过这个清单建议每次更新证书后都跑一遍。看起来繁琐但比起生产环境出问题后再排查这点时间投入完全值得。6.2 常见故障一Harbor容器启动失败现象执行docker-compose up -d后harbor-core或nginx容器反复重启。排查步骤# 查看容器日志 docker-compose logs --tail100 nginx # 常见错误信息 # cannot load certificate - 证书路径不对或文件不存在 # key values mismatch - 证书和私钥不匹配 # permission denied - 证书文件权限不对证书文件权限问题很常见。nginx容器内的进程通常以非root用户运行如果证书文件权限是600且属主是root容器内可能读不到。解决办法是确保证书文件至少是644权限chmod 644 yourdomain.com.crt chmod 644 yourdomain.com.key6.3 常见故障二客户端报certificate signed by unknown authority这个错误说明客户端不信任服务端证书。原因通常是CA证书没有放到客户端的信任目录CA证书放错了位置比如放到了/etc/docker/certs.d/但文件名不是ca.crt客户端服务没有重启排查时先在客户端执行openssl s_client -connect yourdomain.com:443 -servername yourdomain.com -CAfile /etc/docker/certs.d/yourdomain.com/ca.crt如果这个命令能成功验证说明CA证书本身没问题问题出在Docker或containerd的配置上。6.4 常见故障三部分节点正常部分节点报错这种一半好一半坏的情况几乎可以肯定是某些节点没有更新证书。排查方法# 在所有节点上检查证书文件的时间戳 for node in node1 node2 node3; do echo $node ssh $node ls -la /etc/docker/certs.d/yourdomain.com/ca.crt done对比各节点的时间戳找出没有更新的节点。另外也要检查各节点的Docker/containerd版本是否一致不同版本对证书目录的要求可能不同。6.5 常见故障四浏览器访问正常但命令行工具报错浏览器和命令行的证书验证机制不同。浏览器可能允许你手动信任自签证书但命令行工具如docker、curl、skopeo默认严格验证。如果浏览器能打开但命令行报错说明CA证书没有被系统或工具信任。对于curl可以临时用-k跳过验证来确认是证书问题curl -k https://yourdomain.com/api/v2.0/systeminfo如果-k能成功去掉-k就失败那百分之百是证书信任问题。6.6 一个容易被忽略的点证书链完整性如果CA签发的证书包含中间证书而你在Harbor上只配置了服务器证书没有把中间证书拼进去某些客户端会报unable to get local issuer certificate。解决办法是把服务器证书和中间证书按顺序拼接cat yourdomain.com.crt intermediate.crt fullchain.crt然后在harbor.yml中配置fullchain.crt。这个细节在自签证书场景下不存在但用商业证书时经常遇到。7. 把证书更新这件事做成可重复的流程证书更新不是一次性的任务而是每年都要做一次甚至多次的常规运维操作。与其每次临时抱佛脚不如把它流程化、自动化。7.1 建立证书台账用一个简单的表格记录所有证书的信息域名证书类型签发日期到期日期负责人更新方式harbor.example.com自签2024-01-012025-01-01运维A脚本更新registry.example.comCA签发2024-03-152025-03-15运维B手动更新这个台账放在团队共享的地方到期前一个月开始提醒。我见过太多团队因为人员变动证书到期了没人知道最后半夜被叫起来处理。7.2 设置到期监控除了人工台账还应该有自动监控。最简单的方式是用一个定时任务检查证书有效期#!/bin/bash DOMAINyourdomain.com EXPIRY$(echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2/dev/null | openssl x509 -noout -enddate | cut -d -f2) EXPIRY_EPOCH$(date -d $EXPIRY %s) NOW_EPOCH$(date %s) DAYS_LEFT$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 )) if [ $DAYS_LEFT -lt 30 ]; then echo WARNING: Certificate for $DOMAIN expires in $DAYS_LEFT days fi把这个脚本放到监控系统里每天跑一次剩余天数少于30天就告警。这样就不会出现证书过期了才知道的情况。7.3 自动化更新的可行性对于自签证书完全可以做到自动化更新用脚本生成新证书、替换文件、执行prepare、重启服务、分发到各节点。整个流程可以串成一个脚本定时执行。对于CA签发的证书自动化程度取决于CA是否提供API。有些CA支持通过API自动续签那就方便很多。如果不支持至少可以把生成CSR和分发证书这两步自动化中间的人工审核环节保留。7.4 更新窗口的选择证书更新会导致Harbor短暂不可用重启期间所以应该选择业务低峰期执行。但如果是紧急更新证书已经过期那就没得选了只能尽快恢复。我的建议是在证书到期前两周内选择一个低峰期主动更新而不是等到过期后被动处理。主动更新可以从容地做验证和回滚准备被动处理则是在压力下操作容易出错。7.5 回滚方案更新前备份旧证书和配置如果更新后出现无法快速解决的问题可以回滚# 恢复旧证书 cp yourdomain.com.crt.old yourdomain.com.crt cp yourdomain.com.key.old yourdomain.com.key # 恢复配置 cp harbor.yml.bak harbor.yml # 重新prepare并重启 ./prepare docker-compose down docker-compose up -d回滚后客户端也需要同步回滚CA证书。所以回滚不是单方面的需要服务端和客户端一起回滚。这也是为什么建议在低峰期更新——万一需要回滚影响面可控。7.6 我个人的几条经验第一永远不要在生产环境直接操作。先在测试环境完整走一遍流程确认没问题再上生产。测试环境的价值就在于让你把坑踩完。第二更新前先确认所有节点的容器运行时类型和版本。Docker和containerd的证书配置方式不同版本不同配置方式也可能不同。提前摸清楚比更新时手忙脚乱强。第三把更新步骤写成文档每一步都写清楚命令和预期结果。下次更新时直接照着文档做不用重新回忆。文档里还要记录这次更新时遇到的问题和解决办法形成知识积累。第四更新完成后不要马上离开观察至少半小时。看看监控有没有异常告警看看CI流水线有没有报错。有些问题不是立即显现的可能过几分钟才暴露出来。第五如果团队有多个人负责运维确保至少两个人熟悉这个流程。不要出现只有某一个人会更新证书的情况人员变动时这就是个定时炸弹。证书更新这件事技术难度不算高但涉及面广、细节多、容易遗漏。把它当成一个标准化流程来对待比每次临时应对要靠谱得多。希望这篇内容能帮你在下一次证书到期时从容应对而不是半夜被告警叫醒。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/16 8:10:30
RAG标配未必是向量数据库:Elasticsearch混合检索方案详解
2026/10/16 8:05:30
小程序开发必知:全局4个文件与页面四件套深度拆解
2026/10/16 8:05:30
Keil C51 V9.00安装与授权指南:8051老工程维护环境搭建
2026/10/16 9:15:48
Rufus UEFI 启动盘完整指南:一张盘在新老机器上都能点亮
2026/10/16 9:15:48
ObjectARX DockControlBar实现CAD屏幕菜单的原理与实践
2026/10/16 9:15:48
ActiveMQ + C# 生产级消息队列实战:连接池、重试、死信与JSON序列化
2026/10/16 9:15:48
rsync拉取备份:断点续传与状态同步的运维核心能力
2026/10/16 9:15:48
【CoRL 2025】X-Sim:用「真实—仿真—真实」闭环从人类视频学会机器人操作|从机器人数据采集成本视角
2026/10/16 9:10:45
声明式之后,怎么证明更新策略真的生效了
2026/10/16 0:04:49
HCIA-AI V3.5 模拟题库从零搭建:知识点标签、组卷算法与错题分析
2026/10/16 0:04:49
游戏项目Shader清理实战:静态扫描与动态验证双轨并行
2026/10/16 0:04:49
比特币白皮书深度拆解:从双重支付到共识机制的核心设计
2026/10/16 1:17:36
流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南
2026/10/16 1:17:35
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别
2026/10/16 1:17:35
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容
2026/10/16 1:17:35
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/15 5:07:59
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/15 8:10:01
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)