ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Redis在OKD/OpenShift部署实践:手动YAML与Operator管理全面对比

Redis在OKD/OpenShift部署实践:手动YAML与Operator管理全面对比 最近在帮团队把一套基于 Redis 的业务系统迁移到 OKD/OpenShift 4.x 环境顺带把 Redis 的部署方式从手工 YAML 改成了 Operator 管理。整个过程不算复杂但中间踩了不少坑尤其是 Security Context 权限、持久化绑定、故障转移这些环节光排查问题就花了一个下午。这篇梳理一下手动部署和 Operator 管理两种方式的完整对比给正在评估技术选型的朋友做个参考也聊聊我实测下来的真实体会。如果你还没在 Kubernetes 系平台里跑过 Redis可以先把这篇文章当成一份“从零到生产”的笔记看。文中涉及的资源清单、Operator 安装流程和故障排查方式都可以直接在 OKD 或 OpenShift 环境里复现。我会尽量把选择背后的原因讲清楚而不是只丢一堆 YAML 让你抄。1. 现实场景OKD/OpenShift 上跑 Redis 的价值与挑战1.1 为什么要把 Redis 放进 OKD/OpenShiftOKD 是 OpenShift 的社区版两者在核心架构上基本一致都内置了完整的 Kubernetes 能力还额外带了 Operator Lifecycle Manager、内置监控、安全上下文控制和多租户隔离等企业级特性。把 Redis 跑在这类平台上直接带来的好处是资源管理、弹性伸缩和运维流程可以跟其他应用统一不用再单独维护一套虚拟机或物理机。Redis 在业务里的角色通常是缓存、会话存储、队列或分布式锁。这些场景对数据可靠性和响应速度要求很高一旦没部署好小则缓存雪崩大则会话数据丢失。传统做法是直接在服务器上安装 Redis然后靠脚本、cron 和人工盯监控来维持运行放到容器平台之后Pod 重建、存储挂载、网络策略这些底层操作全都交给平台处理运维同学可以把精力放在 Redis 本身的配置、性能和数据结构设计上。1.2 部署 Redis 的两种路线概览在 OKD/OpenShift 上部署 Redis目前主流的有两条路线。一是手动部署也就是自己写 StatefulSet、Deployment、ConfigMap、Service、PVC 这些资源把 Redis 单实例或主从架构通过原生 Kubernetes 对象定义出来。这种方式灵活度高想怎么调就怎么调但所有高可用逻辑、故障转移、升级策略都要自己写Redis 本身没做到的事平台也不会替你补。二是 Operator 管理也就是通过 OLM 安装一个 Redis Operator然后用自定义资源来描述“我想要一个什么样的 Redis 集群”。Operator 会负责把底层的 StatefulSet、Service、PVC、监控、备份、哨兵或集群配置自动生成并持续维护。跟手动方式相比它把大量运维知识固化成了代码实现的效果更接近“声明式运维”。两条路线各有利弊。下面我分别拆开讲然后再做全方位对比。2. 手动部署 Redis 的完整实践2.1 基础设施清单设计与核心参数手动部署的第一步是设计一组基础清单。日常我至少会准备这几个对象一个命名空间、一个 ConfigMap 放 Redis 配置、一个 StatefulSet 管理 Pod 和存储、一个 Headless Service 提供稳定的网络标识。如果要做外部访问再加一个 NodePort 或 Route。其中 ConfigMap 通常长这样apiVersion: v1 kind: ConfigMap metadata: name: redis-config data: redis.conf: | appendonly yes appendfsync everysec maxmemory 256mb maxmemory-policy allkeys-lruappendonly yes开启 AOF 持久化appendfsync everysec表示每秒刷盘一次这是数据安全与性能之间比较稳妥的折中。maxmemory和maxmemory-policy是防止 Redis 无脑占用容器内存的关键参数。容器平台通常会设内存 limit一旦 Redis 超过 limit 可能会被 OOM Kill所以提前设好内存上限配合 LRU 淘汰策略能避免很多线上问题。2.2 为什么优先选择 StatefulSet 而不是 Deployment单实例 Redis 我建议用 StatefulSet而不是 Deployment。很多人图省事用 Deployment几行代码就搞定但 Redis 是有状态服务它的数据必须存到持久卷上而且 Pod 重建之后主机名和网络标识最好保持稳定。Deployment 创建的 Pod 名字是随机后缀换一台节点重建之后之前的粘性就没了StatefulSet 则有稳定的 Pod 命名和稳定的存储绑定。下面是一个常见的单实例 Redis StatefulSetapiVersion: apps/v1 kind: StatefulSet metadata: name: redis spec: serviceName: redis replicas: 1 selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis image: redis:7.0 ports: - containerPort: 6379 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi volumeMounts: - name: data mountPath: /data volumes: - name: data persistentVolumeClaim: claimName: redis-data volumeClaimTemplates: - metadata: name: data spec: accessModes: [ReadWriteOnce] resources: requests: storage: 10Gi注意这里我同时写了volumes和volumeClaimTemplates刚开始容易混淆。两个选一个用就行。如果希望系统自动为每个副本生成独立的 PVC就用volumeClaimTemplates如果你先手动创建好具体的 PVC再用volumes绑定也是可以的。我自己的习惯是生产环境使用 StorageClass 动态供给时倾向volumeClaimTemplates维护成本低。2.3 服务暴露与配置挂载的细节Redis 需要给应用访问时通常配一个 Headless Service方便集群内部通过主机名解析apiVersion: v1 kind: Service metadata: name: redis spec: clusterIP: None selector: app: redis ports: - name: redis port: 6379 targetPort: 6379ClusterIP 设为 None 后StatefulSet 的每个 Pod 都能获得稳定的 DNS 名字比如redis-0.redis.namespace.svc。这在做主从复制或哨兵配置时非常关键。你可以在 ConfigMap 里直接用类似replicaof redis-0.redis.namespace.svc 6379的写法让从节点自动找到主节点。挂载配置时要注意直接把整个/data目录挂成 volume 是常见的因为 Redis 默认把 RDB 和 AOF 文件放在/data。如果挂载点不对数据落不到 PVC 上Pod 一重启数据就没了。检查方式很简单进 Pod 执行redis-cli CONFIG GET dir看看当前工作目录是不是卷挂载路径。2.4 OpenShift 特有权限坑Security Context在 OKD/OpenShift 上跑 Redis最容易遇到的是 Security Context 问题。OpenShift 默认的安全策略会拒绝以 root 用户运行的容器而官方 Redis 镜像在某些版本里恰恰会以 root 启动或者监听了低端口导致权限报错。你可能会看到类似container has runAsNonRoot and image will run as root的拒绝信息。解决办法有两种。一种是创建一个允许指定用户运行的 ServiceAccount并绑定到合适的 SCC另一种是直接用官方提供的 UBI 基础镜像构建 Redis 镜像设置好任意用户 ID 都可运行。这个环节说大不大但每次新建项目都容易踩一遍建议提前把 ServiceAccount 和 SCC 梳理成项目模板省得后面反复配。2.5 手动部署的优缺点手动部署最大的优点是透明。你能精确控制每一个参数出了问题也容易排查因为你清楚每条配置是怎么来的。它最大的缺点也很明显如果要做高可用光靠一个 StatefulSet 是不够的你还需要 Redis Sentinel 或 Redis Cluster这意味着要再维护一组哨兵 Pod、再写故障转移脚本、再处理主从切换后客户端重连的问题。我见过不少团队用手动方式搭了一套 Redis 主从加哨兵刚开始跑得挺好后来出现一次节点维护哨兵选主后新主节点上的数据是旧的因为持久化策略没有同步调整整个业务缓存全部错乱。这种问题不是不能解决而是解决成本非常高需要你把 Redis 的故障转移原理吃透还要和平台调度策略磨合。这时候Operator 的价值就体现出来了。3. Operator 管理 Redis 的实践3.1 Operator 到底是什么为什么适合 RedisOperator 本质上是一个“应用领域的控制器”。它把人类运维 Redis 的经验比如健康检查、故障转移、备份恢复、配置变更、版本升级编码成一段持续运行的逻辑。这个逻辑会一直盯着自定义资源的状态一旦发现实际状态和期望状态有偏差就自动执行操作把它拉回期望状态。用生活化的类比来说手动部署就像你雇了一个新手运维所有操作都要你把步骤写在文档里他照着做Operator 则像一个经验丰富的老运维你只要告诉他“我要一个 3 节点的 Redis 集群数据要持久化”他会自己搞定后面的所有事还会定期检查集群健康出问题自动修复。Redis 这类有状态服务特别适合 Operator因为它拥有复制、哨兵、集群管理、持久化、重分片等一套复杂生命周期。这些逻辑如果全部靠人写在脚本里维护成本高得吓人交给 Operator 之后反而稳定可靠得多。3.2 在 OKD/OpenShift 上安装 Redis Operator在 OKD/OpenShift 里安装 Operator通常不用手动 kubectl apply CRD。打开 OpenShift 控制台的 OperatorHub搜索 Redis会看到几个候选 Operator比如 Redis Enterprise Operator 或社区维护的 Redis Operator。选择信任来源的 Operator 后一般会要求选择一个安装模式。安装模式通常有两种单命名空间模式Operator 只管理某个指定项目里的 Redis 实例全集群模式Operator 可以管理整个集群多个项目下的 Redis。单实例体验最低成本选单命名空间以后想扩也可以再重新安装成集群模式。安装完成后OLM 会自动创建 Operator 的 Deployment、CRD、RBAC 和 Webhook。这个过程会在项目的openshift-operators或者其他命名空间里跑起来一个或多个控制器 Pod。可以通过oc get csv查看 ClusterServiceVersion 状态当状态变成 Succeeded说明 Operator 已经被成功注册。3.3 声明式创建 Redis 实例Operator 装好后就可以用自定义资源声明要的 Redis 实例。以 Redis Enterprise Operator 为例资源大致长这样apiVersion: app.redislabs.com/v1 kind: RedisEnterpriseCluster metadata: name: redis spec: size: 3 persistenceEnabled: true storageClassName: managed-csi podAntiAffinity: true我只填了几个关键字段Operator 就会在后台创建整套基础设施StatefulSet、Service、Secret、PV/PVC、哨兵配置、监控 exporter以及集群初始化任务。相比手动写几百行 YAML这种方式明显更接近“告诉平台你要什么而不是告诉平台怎么做”。不同 Operator 的 CRD 会略有差异但核心思路一致。社区里有不少 Redis Operator 用RedisCluster或Redis作为 Kind。创建前建议先oc explain rediscluster.spec看一下字段说明或者直接查 Operator 的文档避免因为字段名不对导致资源无法创建。3.4 Operator 自动维护哪些能力一个成熟 Redis Operator 通常会自动处理这几件事自动生成 StatefulSet 和固定网络标识自动配置持久化存储并管理 PVC自动启停并维护 Redis 主从或集群拓扑自动执行故障转移在节点不可用时重新选举主节点自动处理配置变更并把新配置滚动应用到全部节点定期做备份支持按时间点恢复集成 Prometheus metrics提供默认告警规则这些能力不是一次性任务而是持续运行的控制循环。比如某个 Redis 节点对应的工作节点宕机Kubernetes 会把 Pod 调度到别的可用节点但 Redis 集群的主从关系、IP 变化后的客户端发现都需要额外处理。Operator 会在检测到异常后自动把故障节点摘除、触发主从切换、更新服务路由整个过程可以不用人盯着。不过要清醒地认识到Operator 不是万能的。Redis 本身的性能瓶颈、慢查询、大 Key、热 Key、内存碎片等问题Operator 并不能替你优化该做的数据建模和性能调优还是要做。4. 全面对比手动部署 vs Operator 管理4.1 部署效率与可维护性对比手动部署第一次搭建可能只要半小时因为一个单实例 Redis 并不复杂。但随着需求增加加主从、加哨兵、配持久化、配监控每一层都要手动扩展工作量成倍增长。而且每个人的写法不一样今天这个环境用 Deployment明天那个环境用 StatefulSet风格很难统一。Operator 部署首次需要安装 Operator投入的时间比手动写 YAML 更长可能一个多小时。但之后就方便了创建一个 Redis 实例就是提交一个 CR 的事多套环境之间的配置也容易保持一致性。后续加节点、改配置也是改 CR 就能完成。我个人更看重长期的可维护性所以生产环境偏好 Operator。4.2 高可用与故障自愈能力手动部署 Redis 单实例Pod 如果挂了平台会自动拉起新 Pod但数据是否完整取决于持久化配置。想要主从自动切换就必须额外搭 Sentinel。手动搭 Sentinel 本身不难难在如何和 Kubernetes 的网络模型适配以及如何避免哨兵误判。比如网络抖动触发哨兵投票主从切换期间缓存不可用这种故障在手动方式下几乎无法避免。Operator 方案里故障转移逻辑被内置到了 Reconciler 中。节点失联后Operator 会根据优先级重新选举主节点并自动在 Service 层面更新端点客户端的连接不会长时间断掉。当然真正的故障转移耗时还取决于很多因素但只要 Operator 本身健康整体流程是自动化的。为了更直观理解我列一下两者的运维工作量对比运维环节手动部署Operator 管理搭建单实例简单半小时需要先装 Operator搭建主从手工配置复制关系声明式指定副本数实现高可用手动部署 SentinelOperator 内置故障转移集群扩容手动增加节点并调整槽位CR 改 size 即可版本升级手动改镜像并滚动验证Operator 支持滚动升级备份恢复自己写 CronJobOperator 管理备份与恢复监控集成手动部署 Prometheus exporter通常自带 metrics 和告警规则4.3 持久化和数据可靠性持久化几乎是所有有状态应用的命门。手动部署时很容易犯两个错误一个是不挂 PVC只把数据写在容器可写层Pod 一重建数据全丢另一个是 PVC 绑定的存储类型不对本地存储导致 Pod 调度到其他节点后数据无法访问。我在 OKD 上建议优先使用平台提供的 CSI 存储类并提前验证扩容能力。Operator 管理持久化通常做得更规范。比如 Redis Enterprise Operator 在创建集群时就会创建持久卷声明模板并把数据目录、备份目录分开管理。这样即使某个节点损坏新 Pod 调度后也能挂载上同一份数据最大限度减少数据丢失风险。4.4 升级与配置变更Redis 版本升级是大家容易忽视的环节。手动部署时升级 Redis 需要改镜像 tag还要手动执行滚动更新并且要关注主从顺序先升从再升主避免数据不一致。更麻烦的是如果跨大版本升级比如从 6.x 升到 7.x很多配置项会有变化手动升级很难全部覆盖检查。Operator 把升级也做成了自动化。声明式改一个镜像版本Operator 会按拓扑顺序逐个升级节点并在升级时保留持久化数据还会验证节点状态不符合条件就不会继续。整个过程比手动滚动要稳得多。我实际用过一次 Operator 从 Redis 6.2 升到 7.0全程没有什么人工参与比手动的压力小很多。4.5 资源占用与控制权Operator 不是零成本的它本身也要占用控制平面资源。一个 Operator Pod 大约需要几十到几百 MB 内存如果你的集群里 Node 数量很少这个开销相对明显。另外Operator 会带来额外的抽象层底层细节被封装后排查问题时需要理解 Operator 的行为逻辑对排障能力要求反而更高。手动部署则控制权最高你可以为某个极端的业务场景做定制化配置比如特殊的集群拓扑、自定义的网络策略、精确到毫秒的主从同步参数等。Operator 再灵活最终也只能支持它设计好的那些场景。所以如果业务非常特殊Operator 不一定是最优选手动部署的灵活性无可替代。4.6 学习成本与团队协作手动部署的学习曲线集中在 Kubernetes 基础学习成本相对平缓团队成员只要懂 StatefulSet、PVC 和 Service就能参与维护。Operator 则要求理解自定义资源、控制器和 OLM 机制入门门槛高一些。但是团队一旦熟悉了 Operator后续维护不同应用的思路可以复用因为其他中间件比如 Kafka、PostgreSQL 也都有 Operator。这里有个现实问题很多团队招人时要求“懂 Redis”但懂 Redis 的人不一定懂 Operator 和 Kubernetes。如果团队成员对控制平面调度逻辑不熟悉遇到奇怪问题可能无从下手。建议在引入 Operator 之前先确保团队有 1 到 2 个人能把 Pod 启动、调度、健康检查、服务发现这些基本链路讲清楚。5. 常见问题与排查技巧实录5.1 Pod 一直处于 CreateContainerConfigError 或 CrashLoopBackOff这个在我手动部署时遇到频率最高。CreateContainerConfigError通常是 ConfigMap 或 Secret 找不到检查一下资源是否创建在同一个命名空间名字是否一致。CrashLoopBackOff则要进日志看具体原因OpenShift 里可以用oc logs redis-0 --previous查上次启动日志。日志如果是权限类报错就去查服务账户和 SCC如果是数据目录无法写入检查挂载目录的权限特别是镜像用非 root 用户启动时PVC 目录属主可能还是 root需要把 fsGroup 或 SecurityContext 调整好。5.2 在 OpenShift 上遇到 imagePullBackOffOpenShift 集群通常默认要求镜像仓库配置可信证书如果你的 Redis 镜像是从外部私有仓库拉的经常遇到imagePullBackOff。解决方法要么把仓库证书加入集群可信列表要么直接使用平台内置的镜像流或者把镜像上传到平台自带的 registry。另外国内网络环境访问 Docker Hub 经常不稳定这也是imagePullBackOff的一个真实原因。稳妥的做法是提前把 Redis 镜像上传到可信 registry再在 Deployment 里指定完整镜像地址不要依赖默认拉取。5.3 数据不持久化或 PVC 无法动态供给数据丢失是 Redis 部署里最致命的问题。排查思路是三步先确认 PVC 状态是否是 Bound再进入 Pod 执行redis-cli CONFIG GET dir确认目录在挂载卷下最后测试模拟删除 Pod看看新 Pod 是否恢复原数据。如果 PVC 一直停留在 Pending大概率是 StorageClass 没配置或者默认存储类不存在。OpenShift 安装时如果没安装 CSI 驱动PVC 动态供给就会失败。你可以在 YAML 里显式指定一个已存在的 storageClassName比如managed-csi、gp2、standard具体以平台实际为准。5.4 端口冲突和 Service 不稳定Redis 主从之间使用 6379 通信Sentinel 使用 26379集群模式还会用到 16379、16380 等端口。在 OpenShift 里需要注意 Service 的 targetPort 不能配错尤其是同一命名空间下多个 Redis 实例时端口很容易混乱。我排查过的一个案例是应用连接 Redis 偶发超时后来发现 Service 的 selector 匹配到了两个不同的 Redis Pod流量被负载分发到了错误节点。这类问题在手动部署里很常见因为手动方式下 selector 标签全靠人写写错一个字符就能造成诡异现象。Operator 管理通常不会出这种问题因为标签、selector 和服务都是系统自动生成的。5.5 Operator 安装后创建 CR 一直不 Ready如果是 Operator 方式遇到创建 Redis 实例后状态长时间不 Ready优先看 Operator 日志。日志里有很明确的信息比如存储类不支持、PVC 数量不足、节点资源不够、镜像仓库认证失败等。还有一个隐蔽问题OpenShift 的默认项目可能限制了 Pod 的安全上下文而 Operator 生成的 Pod 需要更宽松的 SCC。这时你需要为 Operator 使用的 ServiceAccount 绑定一个合适的 SCC。不要一上来就放开 all 权限先确定是哪个安全属性不满足再针对性地调整。5.6 监控告警接入的常见遗漏OpenShift 自带监控栈但默认不会自动采集所有用户项目的 metrics。手动部署 Redis 时就算通过 exporter 暴露了 metrics也要记得创建 ServiceMonitor 并给命名空间打上openshift.io/cluster-monitoringtrue这类标签否则 Prometheus 根本不会来抓数据。Operator 管理通常会把 ServiceMonitor 作为附带资源自动创建但并不是每个 Operator 都会自动创建有些仅创建 ServiceServiceMonitor 还需要你自己补。所以无论哪种方式我都建议最后检查一下 Prometheus 的 Targets 里是否能看到 Redis 的 exporter看不到就把监控链路重新顺一遍。写在最后的个人建议如果今天让我重新选一次测试环境或开发环境我会继续用手动部署因为快方便调试生产环境我倾向直接用 Operator尤其是需要多副本和高可用的 Redis 集群。理由很简单人的精力是有限的与其天天盯故障转移和升级流程不如把这类重复性极高的操作交给 Operator把时间留给业务和性能优化。还有一点不少朋友以为有了 Operator 就不需要懂内部原理这个想法很危险。我实操之后最大的感受是Operator 只是把运维动作自动化了判断和调优还是得靠人。你越理解 StatefulSet、PVC、SCC 和 Redis 复制原理越能把 Operator 用得顺手。反正我现在排查问题依然是先看 Operator 生成出来的底层资源再决定下一步怎么改。希望这篇内容能让你少走一些弯路。
返回列表