使用 Redis Sentinel 保障 Harbor 会话一致性

解读

在国内金融、运营商、政务云等生产级 Harbor 场景中,会话漂移是升级、故障转移时最头疼的问题:用户登录后突然 401,镜像 push 到一半提示未授权,根本原因是 Harbor 默认把 session 存在本地文件系统,多实例部署时无法共享。Redis Sentinel 作为高可用、可横向扩展的内存数据存储,能在秒级完成主从切换,天然适合给 Harbor 提供无状态化的共享 Session 存储,从而实现“一次登录、多实例漫游”。面试官问这道题,想确认你是否理解 Harbor 的会话机制、是否能把 Sentinel 的高可用特性与 Docker 容器化交付结合起来,并能在国内常见的三机房五节点网络环境下给出可落地的方案。

知识点

  1. Harbor 会话生命周期:beego 框架生成 sessionId → 默认落地 /data/session → 返回 harbor-session Cookie。
  2. Redis Sentinel 三角色:master、slave、sentinel;通过 +switch-master 事件完成主观下线→客观下线→故障转移;国内机房延迟 15 ms 以内可保证 <30 s 切换。
  3. Docker 化 Sentinel 的固定节点标识:使用 hostname: sentinel-<index> 并挂载 /etc/hosts,防止容器漂移后 sentinel 找不到 master。
  4. 镜像层安全:Redis 基础镜像必须≤30 MB,采用非 root(uid 1001)运行,关闭 CONFIG 命令,启用 requirepass + ACL file 双重鉴权,满足等保 2.0 对容器内进程最小权限要求。
  5. 网络策略:在 Docker Swarm 或 Kubernetes 中,Redis 集群与 Harbor Core 组件放在同一 Overlay 网络,通过服务名解析,避免跨宿主机 SNAT 导致 Sentinel 返回 Docker 内网 IP 无法直通。
  6. 数据一致性:Harbor 对 session 的操作为单行读写,无需 Redis 事务;开启 appendonly yes 并设置 appendfsync everysec,在容器异常退出时可最多丢失 1 秒会话,国内互联网场景可接受。
  7. 监控告警:使用Prometheus redis_exporter 采集 redis_connected_clientsmaster_link_down_since_seconds,通过阿里云 SLS 或腾讯云 CLS 做日志聚类,触发短信+飞书告警。

答案

步骤 1:准备 Redis Sentinel 容器化编排

FROM redis:7.0-alpine
RUN addgroup -g 1001 redis && adduser -D -u 1001 -G redis redis
COPY sentinel.conf /usr/local/etc/sentinel.conf
USER 1001
ENTRYPOINT ["redis-sentinel", "/usr/local/etc/sentinel.conf"]

sentinel.conf 关键段:

sentinel monitor harbor-session <master-host> 6379 2
sentinel down-after-milliseconds harbor-session 5000
sentinel parallel-syncs harbor-session 1
sentinel failover-timeout harbor-session 15000
sentinel auth-pass harbor-session <redacted>

使用 Docker Compose 三节点示例:

services:
  redis-master:
    image: redis:7.0-alpine
    hostname: redis-master
    command: redis-server --requirepass <redacted> --appendonly yes
    volumes: ["redis-data:/data"]
    networks: [harbor-overlay]
    deploy:
      placement:
        constraints: [node.labels.redis == master]

  redis-slave:
    image: redis:7.0-alpine
    command: redis-server --slaveof redis-master 6379 --masterauth <redacted> --requirepass <redacted> --appendonly yes
    networks: [harbor-overlay]
    deploy:
      replicas: 2

  sentinel:
    image: internal-harbor.example.com/library/redis-sentinel:7.0
    networks: [harbor-overlay]
    deploy:
      replicas: 3
      endpoint_mode: dnsrr

步骤 2:Harbor 对接外部 Redis
修改 harbor.yml

external_redis:
  host: harbor-session.sentinel:26379
  sentinel_master_set: harbor-session
  password: <redacted>
  registry_db_index: 1
  jobservice_db_index: 2
  chartmuseum_db_index: 3

步骤 3:验证高可用

  1. 登录 Harbor 并记录 Cookie;
  2. docker kill 掉 redis-master 容器,Sentinel 完成切换后,刷新页面仍保持登录状态
  3. 通过 redis-cli -p 26379 sentinel get-master-addr-by-name harbor-session 确认新主;
  4. 使用 ab -n 1000 -c 50 压测 /api/v2.0/users/current401 比例 = 0 即达标。

步骤 4:CI/CD 固化
在 GitLab CI 中增加 redis-failover-test job,自动拉起 Kind 集群 → 部署 Harbor + Sentinel → 模拟故障 → 断言 Session 不丢,流水线通过后方可合并主干,确保后续版本升级不会回退。

拓展思考

  1. 如果监管要求跨城双活,Redis Sentinel 无法满足 RPO=0,可引入Redis Cluster + 仲裁层 CRDT 方案,但需评估跨城延迟 30 ms 对 Harbor 登录 RT 的影响。
  2. 当 Harbor 实例数 >20 时,Sentinel 频繁切换会造成脑裂,可改用Kubernetes Operator 托管 Redis,通过预选举降低切换次数,同时利用PodDisruptionBudget保证滚动升级时最小副本数。
  3. 国内信创环境需替换为麒麟 V10 + ARM64 Redis,镜像需重新编译,注意alpine 的 musl 与 glibc 差异,建议在 Dockerfile 里使用多阶段构建先在同 CPU 架构节点编译 redis-sentinel,再 copy 到运行时镜像,避免跨架构拉取延迟。