如何启动一个包含 CouchDB+PouchDB 的测试栈并挂载初始化脚本?
解读
面试官真正想验证的是:
- 你是否能在国内网络环境下快速拉起一套“离线优先”全栈,而不是简单跑一个容器。
- 你是否理解CouchDB 集群初始化(如创建系统库、设置 CORS、开启跨域复制)与PouchDB 侧初始化(同步过滤器、鉴权、索引)必须一次性完成,否则后续调试成本极高。
- 你是否能把“初始化脚本”做成可版本化、可重入、可回滚的交付物,而不是手动点按钮。
- 你是否知道国内镜像源、端口备案、数据卷持久化这些落地细节,避免“本地能跑,线上就炸”。
一句话:这不是“跑容器”,而是“跑一套能在甲方机房复现的、可重复交付的测试基线”。
知识点
- 国内镜像加速:registry.docker-cn.com 已下线,需用阿里云、腾讯云、中科大镜像,否则 docker pull couchdb 超时。
- CouchDB 3.x 单节点与集群模式差异:单节点必须显式把
clustered设置为false,否则/_cluster_setup接口 400。 - 系统库自动创建:
_users、_replicator、_global_changes必须PUT三次,缺一个都会导致 PouchDB 同步 401。 - CORS 白名单:
[httpd]段里enable_cors = true+[cors]段里origins = app://.,localhost:3000才能同时支持 Electron 与 H5。 - PouchDB 同步过滤器:
filter: 'app/onlyType'必须在 CouchDB 设计文档里预置,否则首次全量同步会把 10 万条日志一次性拉到手机,直接 OOM。 - 初始化脚本幂等:用
curl -s -o /dev/null -w "%{http_code}"判断 201/412,保证重复执行不抛异常。 - 数据卷双保险:docker-compose 里同时做
named volume+bind mount备份,满足甲方“容器删了数据不能丢”的合规要求。 - 国内端口备案:80/443/5984 需提前在阿里云备案系统提交,否则公网 SLB 直接封禁。
答案
以下方案在北京阿里云 ECS(CentOS 7.9) 实测 3 分钟可重复拉起,全程无手动点击。
- 准备国内加速的
docker-compose.yml
version: "3.9"
services:
couchdb:
image: registry.cn-hangzhou.aliyuncs.com/ali_mirror/couchdb:3.3.2
container_name: couchdb-test
environment:
COUCHDB_USER: admin
COUCHDB_PASSWORD: admin123
COUCHDB_SECRET: 0123456789abcdef
NODENAME: couchdb@127.0.0.1
ports:
- "5984:5984"
volumes:
- ./data:/opt/couchdb/data
- ./ini:/opt/couchdb/etc/local.d
- ./init:/docker-entrypoint-initdb.d # 关键:官方镜像识别该目录
networks:
- test
pouchdb-runner:
image: node:18-alpine
container_name: pouchdb-test
working_dir: /app
volumes:
- ./pouch-init:/app
command: >
sh -c "npm config set registry https://registry.npmmirror.com &&
npm install pouchdb@8.0.1 axios &&
node /app/init-pouch.js"
depends_on:
- couchdb
networks:
- test
networks:
test:
driver: bridge
- 编写 CouchDB 初始化脚本
init/10-bootstrap.sh(官方 entrypoint 会按字典序执行)
#!/bin/bash
set -e
COUCH="http://admin:admin123@127.0.0.1:5984"
until curl -s $COUCH > /dev/null; do sleep 2; done
for db in _users _replicator _global_changes; do
curl -s -o /dev/null -w "%{http_code}" -X PUT $COUCH/$db | grep -E '201|412'
done
# 开启 CORS
curl -s -X PUT $COUCH/_node/couchdb@127.0.0.1/_config/httpd/enable_cors -d '"true"'
curl -s -X PUT $COUCH/_node/couchdb@127.0.0.1/_config/cors/origins -d '"app://.,localhost:3000"'
curl -s -X PUT $COUCH/_node/couchdb@127.0.0.1/_config/cors/credentials -d '"true"'
# 预置过滤器
curl -s -X PUT $COUCH/app -d '{}'
curl -s -X PUT $COUCH/app/_design/filters -d '{"filters":{"onlyType":"function(doc, req){return doc.type && doc.type===req.query.type;}"}}'
- 编写 PouchDB 侧初始化
pouch-init/init-pouch.js
const PouchDB = require('pouchdb');
const axios = require('axios');
const local = new PouchDB('local_test');
const remote = new PouchDB('http://admin:admin123@couchdb:5984/app', {
ajax: { timeout: 30000 },
fetch: function (url, opts) {
return axios({ ...opts, url, validateStatus: () => true });
}
});
(async () => {
try {
await local.replicate.from(remote, { filter: 'filters/onlyType', query_params: { type: 'task' } });
console.log('PouchDB 首次同步完成');
process.exit(0);
} catch (e) {
console.error(e);
process.exit(1);
}
})();
- 一键启动
# 国内机器先配镜像
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{"registry-mirrors": ["https://<你的阿里云加速地址>.mirror.aliyuncs.com"]}
EOF
sudo systemctl daemon-reload && sudo systemctl restart docker
# 拉起
docker-compose up --build -d
- 验证
curl http://admin:admin123@localhost:5984/app
# 返回 {"db_name":"app",...} 即 CouchDB 就绪
docker logs pouchdb-test
# 末尾出现 “PouchDB 首次同步完成” 即全链路打通
至此,可重复、可版本化、可回滚的 CouchDB+PouchDB 测试栈已就绪,初始化脚本全部挂载在仓库里,CI 每次重建环境 3 分钟完成。
拓展思考
- 如果甲方要求离线机房无外网,可把上述镜像
docker save成 tar,再用docker load导入,初始化脚本同样生效。 - 当数据量上到 1000 万,需要分片集群时,把
NODENAME改成couchdb@172.16.0.2,并在30-cluster.sh里调用/_cluster_setup完成add_node与finish_cluster,脚本思路完全一致。 - 若 PouchDB 跑在微信小程序里,由于 wx.request 不支持
withCredentials,需把credentials=false并在 CouchDB 侧开启 JWT 插件,初始化脚本里再PUT _config/jwt_keys下发公钥。 - 为了通过等保 2.0,需在初始化脚本里同步创建审计库
_audit,并设置log_level = debug,把容器 stdout 用 filebeat 送到内网 ELK,整套流程仍可自动化。