ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Helm安装Rancher与Ingress证书更新全流程实战

Helm安装Rancher与Ingress证书更新全流程实战

1. 先搞清楚这次要解决的问题

helm安装rancher这件事本身并不复杂,跑过一遍的人都知道,真正让人头疼的是后续证书维护。尤其是当ingress证书快过期、或者你准备从内网测试证书切换到正式CA签发的证书时,更新流程里藏着不少坑。这篇文章就围绕helm部署Rancher和更新ingress证书这两条主线,把方案选型、实操命令、踩坑记录一次讲清楚。适合正在用Rancher管理K8s集群、同时又自己维护证书的运维同学参考,也欢迎第一次接触Rancher的朋友当一篇入门指南来看。

先说一个常见的误区:很多人以为“更新ingress证书”就是把tls secret里的证书换掉,然后等ingress controller自动生效。这个思路对一般的Nginx Ingress项目成立,放到Rancher场景下就不够了。Rancher的架构里,证书不只是给浏览器看的,它还承担着Rancher server和下游集群agent之间的信任校验。如果只换了门面、没换内部信任链,后续扩容集群、注册新节点、甚至刷新已有集群的连接都会出问题。所以你要更新的不是一个secret,而是一整条证书链路上的相关组件。

这篇文章我会先讲清楚Rancher里证书的层次结构,再给出一套从helm安装到证书更新的完整操作流程。中间会穿插我自己实测过的命令和踩坑记录,最后整理一份问题排查速查表。内容可能比一般教程啰嗦一点,但每个命令背后的原因我都会解释,免得你照着抄完还是一头雾水。

2. 上手前先理清Rancher的证书层次

2.1 Rancher里到底有几层证书

Rancher部署之后,证书并不是只有一张。大概可以分成三个层次来看。

第一层是用户访问Rancher UI时看到的ingress证书。你通过浏览器访问https://rancher.example.com,看到的证书就是这一层。它挂在cattle-system命名空间下的ingress资源上,一般对应一个名为tls-rancher-ingress的secret。

第二层是Rancher内部组件之间的通信证书。Rancher server内部有多个组件,比如cattle-controllers、api-server相关的模块,它们之间通过TLS通信。在开启私有CA的场景下,这层证书由一个内部CA统一签发,相关secret在cattle-system命名空间里,名字类似tls-rancher-internal-ca。这层证书一般不需要你手动更新,它们由Rancher自己管理,但如果那个内部CA的根证书变了,麻烦就来了。

第三层是Rancher server与下游集群agent之间建立信任所用的CA证书。每当你把一个K8s集群导入Rancher,集群里的agent会拿到一个“集群注册令牌”,其中包含一个CA证书,agent用这个CA来校验Rancher server的身份。如果这台server的CA变了,已经注册的集群会失联,新增集群时也会失败。

搞清楚这三层之后,你再回头看“更新ingress证书”这个需求,就会发现它其实有两种情况。一种是证书确实是同一张,只是快过期了,换一张同CA签发的新的,这种情况简单,换tls secret就完事。另一种是你换了整套CA,比如从内部测试CA切到公司正式CA,那么上面三层全部要动,少动一个都会出问题。很多线上事故就是这么来的。

2.2 为什么证书方案会影响后续更新难度

Rancher安装时,ingress.tls.source这个参数决定了ingress证书的来源。常用的有三个值:rancher、secret、letsEncrypt。我先说说三者的区别,因为这直接决定你后续更新证书的工作量。

rancher模式是让Rancher通过自身的证书管理功能来签发证书,需要配合cert-manager使用。这种模式下,证书更新基本是自动的,你几乎不用管,但前提是你接受Rancher自己作为签发方,浏览器会给出不可信警告。

letsEncrypt模式也依赖cert-manager,适合有公网域名、且不想自己维护证书的场景。它会自动申请和续期,省心,但是对网络环境和域名所有权有要求。

secret模式是最灵活也最显示水平的一种。你把证书内容做成secret放到命名空间里,通过--set ingress.tls.source=secret让Rancher的ingress去引用它。企业内网环境或者有独立CA团队的公司,基本都会选这个模式。因为证书由你自己的CA体系签发,浏览器也信任,合规审计也方便,唯一的问题就是证书过期时你要手动更新,这正是本文重点要讲的场景。

如果你还没装Rancher,我建议你现在就决定好采用哪种模式。因为装完之后再想从rancher模式切换成secret模式,涉及的操作比装的时候就选好要复杂得多,不只是改一个values文件那么简单。我见过好几个同事在测试环境随手用rancher模式装的,后来要接公司统一证书体系,只能整条链重新梳理一遍。

3. 用Helm安装Rancher的全过程

3.1 前置条件与版本选型

动手之前,先确认几件事。Helm要是v3版本,helm version看一下,v2虽然也能装Rancher,但现在已经不是主流用法,不建议在新环境里使用了。Kubernetes集群版本要按照Rancher官方支持矩阵来,过早过晚的版本都会有兼容性问题,我自己习惯装比官方最低要求高一两个小版本的K8s,留出缓冲。域名需要提前准备好,并且DNS解析指向集群的ingress入口,这个不提前搞定,后面就算装好了也访问不了。

还要提醒一句:Rancher是有License机制的。虽然社区版可以免费用,但生产环境用的话,建议了解清楚授权情况。我见过有公司装完了才发现没法激活,又要回滚的场景。这不是技术问题,但比技术问题更麻烦。

组件版本之间别乱搭配。我自己测试过一套组合,Helm 3.14配K8s 1.28配Rancher 2.8,用下来很稳。不是说老版本不行,而是你遇到问题去查文档时,这种新组合的坑别人已经踩得差不多了,报错信息其实好找。

3.2 添加Helm仓库与创建命名空间

Helm仓库地址是官方charts仓库,执行下面两条命令把仓库加进来并同步索引:

helm repo add rancher-latest https://charts.rancher.io helm repo update

注意仓库名的选择,我自己习惯用rancher-latest,因为它对应的是最新稳定版本。有些教程会让人用rancher-stable,其实两个都是官方仓库,只是更新策略不太一样。如果你要装指定版本,先helm search repo rancher -l列出所有版本,再通过--version参数指定。

接着创建命名空间。Rancher默认的命名空间是cattle-system,这个强一致,别改成别的名字,否则后续很多命令和文档就对不上了。

kubectl create namespace cattle-system

3.3 准备证书Secret

这一步是整个安装过程里最容易埋雷的地方。准备两个文件:证书文件(fullchain.pem)和私钥文件(key.pem)。我用词很严格,是fullchain.pem,不是单单一个cert.pem。如果你的证书链里有中间CA证书,必须把站点证书和中间证书合并成一个fullchain文件,顺序是站点证书在前、中间证书在后。只传一个站点证书的话,很多浏览器会报“证书链不完整”,特别是用了私有CA签发的证书时,这个问题几乎必现。

生成secret的命令:

kubectl -n cattle-system create secret tls tls-rancher-ingress \ --cert=fullchain.pem \ --key=key.pem

这里我提一个备用方案,如果后面证书更新频繁,建议用下面这种幂等写法,即使secret已存在也不会报错:

kubectl -n cattle-system create secret tls tls-rancher-ingress \ --cert=fullchain.pem \ --key=key.pem \ --dry-run=client -o yaml | kubectl apply -f -

这个命令先通过dry-run生成secret的yaml,再通过管道喂给apply,如果secret不存在就创建,如果存在就更新,整个过程不会中断服务。后面讲证书更新的时候还会再用到这个思路。

3.4 执行helm install

安装命令如下,我加了比较实用的参数,并逐一说明它们的作用。

helm install rancher rancher-latest/rancher \ --namespace cattle-system \ --set hostname=rancher.example.com \ --set bootstrapPassword=admin123 \ --set replicas=3 \ --set ingress.tls.source=secret \ --set privateCA=true

replicas=3是生产环境建议值,Rancher的controller组件支持多副本,单副本在集群节点重启时会短暂不可用,三副本能扛住单个节点故障。如果只是测试环境,1个副本就够。bootstrapPassword是安装后首次登录的初始密码,安装后第一件事建议改掉。privateCA=true是配合私有CA证书用的,如果你的证书是由私有CA签的,这个参数务必设为true,让Rancher内部信任这个CA。如果你的证书是公网CA签的,那不要设这个参数。这个坑我踩过一次,明明证书是公开信任的,还设了privateCA,结果Rancher内部组件之间做校验时反而互相不认账。

安装过程大概两三分钟,期间可以用以下命令观察进度:

kubectl -n cattle-system rollout status deploy/rancher

看到deployment "rancher" successfully rolled out就说明装好了。

3.5 验证安装结果与证书生效情况

装完之后别急着登录,先在命令行验证一下证书链是否正确。用openssl来验证最直接:

openssl s_client -connect rancher.example.com:443 -servername rancher.example.com < /dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

这个命令会打印出服务器实际下发的证书主体、签发者和有效期。检查三件事:签发者和你的CA是否一致;subject里的域名和hostname是否匹配;有效期是否覆盖当前日期。如果这三项都正常,再用浏览器访问一下,确认没有证书告警,就可以继续了。

4. 更新ingress证书的核心操作流程

4.1 什么场景下需要更新证书

证书更新不是一个高频操作,但一旦需要,往往是比较紧急的情况。我归纳一下常遇到的三种:

第一种是证书即将过期。这个是最常见的。公司内部CA签发的证书有效期一般是一年,一年一到就得换。很多运维没有做证书到期监控,都是浏览器报警了才发现。

第二种是换了CA签发方。比如公司从自建CA切换到第三方商业CA,或者从测试CA切到正式CA。这时候不只是证书文件变了,整个信任链都变了。

第三种是更换访问域名。域名从rancher-old.example.com切到rancher.example.com,新域名的证书也要同步替换。

不管是哪种情况,操作的核心都是更新ingress引用的那个TLS secret。不同的是换CA或者换域名时,还要额外处理内部信任链。

4.2 更新TLS Secret的正确姿势

拿到新的fullchain和key之后,用前面提到的幂等方式更新secret:

kubectl -n cattle-system create secret tls tls-rancher-ingress \ --cert=new-fullchain.pem \ --key=new-key.pem \ --dry-run=client -o yaml | kubectl apply -f -

执行完成后,先看secret里的内容是不是新的:

kubectl -n cattle-system get secret tls-rancher-ingress -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -subject -dates

这里有个细节需要提醒:很多人在执行create secret时遇到AlreadyExists报错,就顺手kubectl delete secret再重新create,这个操作是有隐患的。删除和重建之间有一个时间窗口,如果此时有请求打进来,ingress会短暂找不到证书,表现就是502或者TLS握手直接失败。而dry-run管道方式可以做到原子替换,虽然底层也是先删后建,但通过apply的方式对控制器来说是平滑过渡的。我的建议是养成这个习惯,别在线上环境用delete加create。

4.3 Ingress如何感知证书变化

更新完secret,接下来的问题是:ingress什么时候生效?

如果集群里用的是标准的Nginx Ingress Controller,它会监听Secret资源的变化。你更新secret的几秒之内,controller会自动重新加载配置,新证书就会生效。这个过程一般不需要人工干预,但也不是绝对的。如果你的Ingress Controller版本比较老,或者部署时限制了监听范围,就可能出现不自动加载的情况。

为了方便排查,更新secret之后可以这样验证一下:

kubectl -n cattle-system get ingress rancher -o yaml | grep -A5 tls

确认ingress引用的是tls-rancher-ingress这个secret。然后稍等十几秒,再次用openssl验证线上证书。

如果等了很久证书还是旧的,可以主动触发一下Ingress Controller的Reload,最保险的方法是把对应的controller pod删掉重建。但生产环境删pod之前先确认有多个副本,或者确认重建不会导致服务中断。Nginx Ingress Controller在滚动重建的过程中会自动加载最新的Secret内容。

如果是RKE2或者K3s自带的Traefik作为Ingress Controller,机制也类似,它同样会watch Secret变化。不过Traefik对证书更新的响应时间可能稍慢,我自己遇到时一般等30秒内就会自动生效,如果超时就检查Traefik日志。

4.4 换CA时,内部信任链也要同步调整

这一步是我最想强调的。如果你只是同一张CA下续期,跳到本章结束,不需要看这节。但如果你的CA换了,也就是新证书的“issuer”和旧证书不一样了,那么你还需要做一件事:把新的CA同步给Rancher内部组件。

先看一下当前cattle-system里有哪些CA相关secret:

kubectl -n cattle-system get secret | grep -E "tls-rancher|internal-ca"

以tls-rancher-internal-ca为代表,Rancher内部组件以及agent通信都会用到这些CA。换CA之后,需要把新的根证书更新到这个secret里。这里没有一键命令,我的做法是先把新的CA文件准备好,然后更新对应secret:

kubectl -n cattle-system create secret generic tls-rancher-internal-ca \ --from-file=ca.pem=new-ca.pem \ --dry-run=client -o yaml | kubectl apply -f -

注意secret类型和字段名,要以你的实际环境为准。这一步做完,重启Rancher的pod,让它用新的CA重新建立内部信任:

kubectl -n cattle-system rollout restart deploy/rancher

这里要特别谨慎,如果你对Rancher的信任链机制不是很熟,建议在维护窗口操作,并且提前备份旧的secret。备份命令很简单:

kubectl -n cattle-system get secret tls-rancher-ingress -o yaml > ingress-cert-backup.yaml kubectl -n cattle-system get secret tls-rancher-internal-ca -o yaml > internal-ca-backup.yaml

一旦操作出问题,可以立刻kubectl apply -f恢复。

另外,换CA之后还有一个隐藏影响:已经导入Rancher的下游集群agent,它们保存的是旧CA。Rancher server换了新CA,agent在建立连接时会发现校验失败。典型症状就是集群列表里所有集群都变成“Unavailable”,agent pods反复CrashLoopBackOff。解决方式是对每个下游集群重新生成注册命令并应用agent manifest。这一步操作逻辑说起来简单,实际执行时要小心,尤其不要影响到集群里正在运行的工作负载。

4.5 完整更新流程的时序图

我画一个简化版的操作时序,方便你执行时心里有数:

  1. 备份现有secret,保留回滚方案。
  2. 更新ingress对应的tls secret。
  3. 验证ingress证书是否生效。
  4. 检查新证书的CA与旧证书是否一致。如果不一致,进入第5步。
  5. 更新内部CA相关secret。
  6. 重启Rancher deployment。
  7. 检查下游集群连接状态,如有异常,重新生成集群注册命令。

5. 常见问题与排查技巧实录

5.1 证书显示没更新的排查顺序

有次我在测试环境更新证书后,浏览器里看到的还是旧证书,折腾半天才发现问题根本不在Rancher,而在Ingress Controller的缓存。这里我按排查优先级列一下:

先看secret内容对不对。用前面提过的命令检查secret里的证书日期。如果secret里的内容已经是新证书,而浏览器看到的还是旧的,说明问题在下一层。

再看ingress代理层。测试时不要用浏览器,用curl绕过缓存直接验证:

curl -vI https://rancher.example.com 2>&1 | grep -i "subject\|issuer"

如果curl显示的证书是新的,浏览器却显示旧证书,那就是浏览器缓存了HSTS或者证书状态。换个无痕窗口试试,基本就解决了。

如果curl显示的也是旧证书,再检查Ingress Controller pod。查看它的日志,看有没有加载最新secret的记录。如果一直是旧证书,手动删掉controller pod强制重生,一般能解决。

还有一类低级问题:你同时存在多个secret,ingress实际引用的不是你想更新的那一个。这种情况我会先把ingress的yaml里tls部分的secretName抄出来,跟实际更新的secret名字对一遍。别笑,真有人把证书更新到tls-rancher,ingress引用的却是tls-rancher-ingress,折腾半天毫无进展。

5.2 更新证书导致新增节点失败的原因

有次更新公司内某套Rancher的证书后,第二天运维反馈说新增K8s节点一直失败。排了半天发现就是CA信任链的问题。

现象是这样的:新证书是新的CA签发的,ingress层面看起来一切正常,浏览器访问也正常。但是新节点的kubelet通过Rancher agent注册时,它拿到的CA还是旧的,于是agent到Rancher server之间的TLS校验失败,表现为“certificate signed by unknown authority”。

解决办法就是我4.4节里说的,同步更新内部CA,并且确保agent侧拿到的是新CA。如果你是新增一个全新的集群,直接在Rancher UI里重新生成集群注册命令,复制里面最新的CA字段,粘贴到新集群执行,就没有这个问题。

5.3 证书更新后集群显示Unavailable

前面提到过,这个坑往往不是立刻出现,而是过了一段时间才暴露。因为agent和server之间的长连接可能一直保持。等到连接断开、agent重连的时候,它发现自己不再信任这个server了,才会报错。

遇到这种情况,先别慌,先确认Rancher pod里的CA是不是和集群agent里的CA一致。方法是在Rancher server pod里执行命令查看内部CA指纹,再在出问题的集群里查看agent pod的CA指纹,对不上就能确认是这个问题。

修复办法:到出问题的集群里,查看agent相关的secret,确认它的ca.pem是不是新CA。如果不是,把它换成新CA,然后重启agent相关pod。换的时候同样建议备份。Rancher官方对这种情况有一个专门的说明文档,核心思路就是让agent的CA和server保持一致。

5.4 问题排查速查表

我把上面遇到的问题整理成一个表,方便你到时候直接对照:

症状可能原因处理方向
浏览器提示证书不信任证书链不完整,secret里只有站点证书没包含中间证书重新生成fullchain,把中间证书拼进去,更新secret
浏览器看到旧证书浏览器缓存或HSTS换无痕窗口验证,清除浏览器缓存
curl看到旧证书Ingress Controller没有加载新secret查看controller日志,删除controller pod强制重载
新增节点注册失败agent侧的CA是旧的重新生成集群注册命令,应用新manifest
已有集群显示Unavailableserver CA变了,agent校验失败手动更新agent的CA,再重启agent pod
secret更新时报AlreadyExistscreate时没有加dry-run管道换成apply方式更新,避免先删后建
证书合法但访问502更新secret的瞬间有请求,或controller的worker没有准备好稍后重试,确认controller pod正常

这个表格基本上覆盖了我从安装到维护过程中遇到的绝大多数问题。如果你还有别的报错,按“先验证内容、再排查链路、最后看日志”这个顺序走一遍,通常能找到原因。

最后分享两个实在的体会。第一,证书相关操作一定要在低峰期做,并且手边留好回滚方案。Rancher的证书链路涉及的不只是访问入口,还有agent注册链路,操作不当影响面比你想的大。第二,给证书到期做个监控提醒,不要等浏览器报警了再去处理。我在实际操作中最怕的就是半夜被电话叫起来换证书,那种状态下很容易出错。提前在日历上把证书到期日标出来,提前两周准备替换文件,比什么技巧都管用。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进