如何关闭 HTTP 组件仅保留 replication?

解读

在国内生产环境中,CouchDB 常被部署在政务内网、金融 DMZ、物联网边缘节点等场景,安全基线要求“非必要服务一律关停”。HTTP API 一旦暴露,就意味着任何能解析 5984 端口的进程都可触发读写,因此部分架构师希望只保留 4369(epmd)与 5986(集群通信)端口,让节点之间仍能完成多主复制,而外部客户端无法再走 REST 接口写数据。
面试时,考官不仅想看你会不会“关端口”,更想确认你对CouchDB 内部管线、BEAM 虚拟机、chttpd/couch_httpd 模块、OTP 应用树的理解深度,以及能否在不破坏集群元数据的前提下完成灰度变更。

知识点

  1. CouchDB 的 HTTP 栈由两层构成
    • couch_httpd:早期单进程 acceptor,负责 /_utils、/_config 等路径。
    • chttpd:3.x 默认的“集群 HTTP”,基于 Ranch,监听 [chttpd] port = 5984
      二者均挂在 couch_primary_services OTP 应用树下,与 replication 不在同一监督分支
  2. Replication 依赖的是内部 Erlang RPC 与 _replicator 数据库不依赖 5984 端口;节点间走 Erlang 分布式协议(4369 及随机高位),所以关闭 HTTP 不会中断复制
  3. 关闭方式有三种粒度
    • 配置层:把端口写成 0 或绑定到 127.0.0.1
    • 代码层:在 etc/vm.args-couch_httpd start false-chttpd start false
    • 打包层:重新编译 couch.app.src,把 couch_httpdchttpdapplications 列表摘除。
  4. 国内等保要求需同步完成主机防火墙(firewalld/iptables)CouchDB 配置双重收敛,并留**5986(集群维护端口)**给运维审计。
  5. 灰度顺序:先关 chttpd → 观察 _replicator 作业 → 再关 couch_httpd → 重启单节点 → 滚动到全集群,每一步回滚方案需提前写好 systemd 模板与 ini 备份

答案

  1. 登录任一节点,先确认复制正常:
    curl -s http://127.0.0.1:5984/_replicator | jq '._replication_state'
  2. 修改 local.ini,追加两行:
    [chttpd]
    port = 0
    bind_address = 127.0.0.1
    [httpd]
    port = 0
    bind_address = 127.0.0.1
  3. 可选加固:在 vm.args 末尾加
    -couch_httpd start false
    -chttpd start false
  4. systemctl restart couchdb,确认监听:
    ss -lntp | grep 5984 # 应无结果
    ss -lntp | grep 4369 # epmd 仍在
  5. 在另一节点写一条连续复制
    curl -X PUT http://<admin>:<pwd>@127.0.0.1:5986/_replicator/edge2dmz -d '{"source":"edge","target":"http://<admin>:<pwd>@dmz:5986/db"}'
    返回 201 且状态持续 “triggered” 即证明仅关闭 HTTP API,复制未受影响
  6. 最后把变更同步到 ansible playbook,并关闭公网安全组 5984 入方向,完成等保收敛。

拓展思考

  • 如果未来需要临时开放只读 REST,可再启一个 Nginx + lua-resty-couchdb 的只读反向代理,只允许 GET /{db}/{doc} 与 GET /{db}/_changes,不暴露 /_config、/_users,实现“零信任”最小化暴露。
  • 在 K8s 侧,可用 CouchDB 3.3 的 sidecar 模式,把 chttpd 容器端口从 service 里摘除,只保留 couchdb@127.0.0.1 的 headless service 给 StatefulSet,让 Prometheus 通过 5986/_node/_stats 拉指标,兼顾监控与安全。
  • **国内信创环境(鲲鹏 + 麒麟 V10)**下,Erlang 版本锁在 23.x,关闭 HTTP 后需验证 OTP 的 distribution over TLS 是否仍兼容,否则节点间会报 ** Connection attempt from disallowed node **,需要在 etc/vm.args-proto_dist inet_tls 并导入国密证书。