mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-19 16:16:45 +00:00
feat(database): unify recipe host ports and add Consul, Elasticsearch
This commit is contained in:
@@ -11,13 +11,13 @@ make db-verify DB=postgresql@17.4
|
|||||||
make db-down DB=postgresql@17.4
|
make db-down DB=postgresql@17.4
|
||||||
```
|
```
|
||||||
|
|
||||||
Every network recipe uses the standard database port plus one on the host. The default password is `123456`, and the default database is `dbx`; Redis uses DB 0 and the `dbx:` key prefix. Container names follow `dbx-<product>-<version>`. Versions of the same database share the default host port, so use `DB_PORT` when running them concurrently. `DB_PORT` and `DB_PASSWORD` override the default host port and password. Ports bind to `127.0.0.1` by default. To allow remote access explicitly, set `DB_BIND_ADDRESS=0.0.0.0`, choose a strong `DB_PASSWORD`, and protect the host with firewall rules. `make db-reset` deletes the named volume and therefore requires `CONFIRM=1`:
|
Each product has a dedicated `101xx`-`115xx` default host-port range, so checked-in recipes can run together without using common service ports or colliding across versions. The default password is `123456`, and the default database is `dbx`; Redis uses DB 0 and the `dbx:` key prefix. Container names follow `dbx-<product>-<version>`. `DB_PORT` and `DB_PASSWORD` override the primary host port and password; service-specific variables override auxiliary ports. Ports bind to `127.0.0.1` by default. To allow remote access explicitly, set `DB_BIND_ADDRESS=0.0.0.0`, choose a strong `DB_PASSWORD`, and protect the host with firewall rules. `make db-reset` deletes the named volume and therefore requires `CONFIRM=1`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make db-reset DB=redis@7.4 CONFIRM=1
|
make db-reset DB=redis@7.4 CONFIRM=1
|
||||||
```
|
```
|
||||||
|
|
||||||
The primary Make targets are `db-list`, `db`, `db-verify`, `db-down`, `db-reset`, and `db-check`. Run `make db` to print one copyable start command for every recipe. `make db-completion` prints Bash, Zsh, and PowerShell completion setup; the scripts in `completion/` dynamically complete recipe selectors. The targets avoid POSIX-shell conditionals and work with GNU Make in PowerShell, Git Bash, or WSL. For diagnosis, use the lower-level `pnpm db:env -- info|status|logs|shell <product> <version>` commands.
|
The primary Make targets are `db-list`, `db`, `db-verify`, `db-down`, `db-reset`, and `db-check`. `make db-list` groups recipe versions by product and shows each container-to-host default port mapping, image, and supported platform. Run `make db` to print one copyable start command for every recipe. For connection types supported by DBX, a completed startup also prints a prefilled `dbx://connection/new` link; on macOS with DBX Desktop installed, run `open '<link>'` to open the new-connection dialog. The link can contain a password, so do not save it in shared terminal history, logs, or tickets. Recipes with no compatible DBX connection type explicitly report that no deep link is available. `make db-completion` prints Bash, Zsh, and PowerShell completion setup; the scripts in `completion/` dynamically complete recipe selectors. The targets avoid POSIX-shell conditionals and work with GNU Make in PowerShell, Git Bash, or WSL. For diagnosis, use the lower-level `pnpm db:env -- info|status|logs|shell <product> <version>` commands.
|
||||||
|
|
||||||
## Recipe layout
|
## Recipe layout
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ make db-verify DB=postgresql@17.4
|
|||||||
make db-down DB=postgresql@17.4
|
make db-down DB=postgresql@17.4
|
||||||
```
|
```
|
||||||
|
|
||||||
所有网络数据库默认使用标准端口 `+1` 的宿主端口,默认密码统一为 `123456`,默认数据库名为 `dbx`;Redis 使用 DB 0 和 `dbx:` 键前缀。容器名统一为 `dbx-<product>-<version>`。同一种数据库的不同版本共用默认宿主端口,并行启动时请使用 `DB_PORT` 覆盖其中一个端口。`DB_PORT` 和 `DB_PASSWORD` 可以覆盖默认主机端口和密码。端口默认仅绑定 `127.0.0.1`;如需远程访问,必须显式设置 `DB_BIND_ADDRESS=0.0.0.0`,同时使用强密码和防火墙限制访问。`make db-reset` 会删除命名卷及其数据,因此必须显式传入 `CONFIRM=1`:
|
每个产品都有专属的 `101xx` 至 `115xx` 默认宿主端口段,因此所有已提交配方可同时启动,且不会占用常见服务端口或在版本间冲突。默认密码统一为 `123456`,默认数据库名为 `dbx`;Redis 使用 DB 0 和 `dbx:` 键前缀。容器名统一为 `dbx-<product>-<version>`。`DB_PORT` 和 `DB_PASSWORD` 可覆盖主连接端口和密码;辅助端口使用各服务原有的专属环境变量覆盖。端口默认仅绑定 `127.0.0.1`;如需远程访问,必须显式设置 `DB_BIND_ADDRESS=0.0.0.0`,同时使用强密码和防火墙限制访问。`make db-reset` 会删除命名卷及其数据,因此必须显式传入 `CONFIRM=1`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make db-reset DB=redis@7.4 CONFIRM=1
|
make db-reset DB=redis@7.4 CONFIRM=1
|
||||||
```
|
```
|
||||||
|
|
||||||
主要 Make 目标为 `db-list`、`db`、`db-verify`、`db-down`、`db-reset` 和 `db-check`。执行 `make db` 会为每个配方输出一条可直接复制的启动命令。`make db-completion` 会输出 Bash、Zsh 和 PowerShell 补全加载命令,`completion/` 中的脚本会动态补全配方选择器。目标不再依赖 POSIX Shell 条件语法,可在 PowerShell、Git Bash 或 WSL 中通过 GNU Make 使用。诊断时可使用底层命令 `pnpm db:env -- info|status|logs|shell <product> <version>`。
|
主要 Make 目标为 `db-list`、`db`、`db-verify`、`db-down`、`db-reset` 和 `db-check`。`make db-list` 会按产品归并展示各版本,并列出每项默认的容器到宿主机端口映射、镜像和支持平台。执行 `make db` 会为每个配方输出一条可直接复制的启动命令;对于 DBX 已支持的连接类型,启动完成后还会输出预填的 `dbx://connection/new` 链接,可在已安装 DBX 桌面端的 macOS 上通过 `open '<链接>'` 打开新建连接窗口。该链接可能包含密码,请不要将其写入共享终端历史、日志或工单。没有对应 DBX 连接类型的配方会显示深链不可用。`make db-completion` 会输出 Bash、Zsh 和 PowerShell 补全加载命令,`completion/` 中的脚本会动态补全配方选择器。目标不再依赖 POSIX Shell 条件语法,可在 PowerShell、Git Bash 或 WSL 中通过 GNU Make 使用。诊断时可使用底层命令 `pnpm db:env -- info|status|logs|shell <product> <version>`。
|
||||||
|
|
||||||
## 配方结构
|
## 配方结构
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Database Recipe Template
|
# Database Recipe Template
|
||||||
|
|
||||||
Create `deploy/database/<product>/<version>/` with `recipe.json`, `compose.yaml`, and an `init/` directory. Set `defaultPort` in `recipe.json` to the native service port; the connection port and Compose `DB_PORT` fallback must both be `defaultPort + 1`.
|
Create `deploy/database/<product>/<version>/` with `recipe.json`, `compose.yaml`, and an `init/` directory. Set `defaultPort` to the native service port, then declare every default host mapping in `hostPorts`. `connection.port` and the Compose `DB_PORT` fallback must both match `hostPorts.DB_PORT`.
|
||||||
|
|
||||||
Every recipe must use a pinned image, default its host binding to `${DB_BIND_ADDRESS:-127.0.0.1}`, use the standard port plus one by default, set `container_name` to `dbx-<product>-<version>`, use password `123456`, and initialize database `dbx`. Redis-like services without named databases use DB 0 and the `dbx:` key prefix.
|
Every recipe must use a pinned image, default its host binding to `${DB_BIND_ADDRESS:-127.0.0.1}`, allocate unique host ports from its product's `101xx`-`115xx` range, set `container_name` to `dbx-<product>-<version>`, use password `123456`, and initialize database `dbx`. Redis-like services without named databases use DB 0 and the `dbx:` key prefix.
|
||||||
|
|
||||||
Add both a non-interactive `smoke.steps` command and an interactive `shell` command to `recipe.json`, then run:
|
Add both a non-interactive `smoke.steps` command and an interactive `shell` command to `recipe.json`, then run:
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ services:
|
|||||||
container_name: dbx-clickhouse-24.8
|
container_name: dbx-clickhouse-24.8
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-8124}:8123"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10600}:8123"
|
||||||
environment:
|
environment:
|
||||||
CLICKHOUSE_DB: dbx
|
CLICKHOUSE_DB: dbx
|
||||||
CLICKHOUSE_USER: default
|
CLICKHOUSE_USER: default
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 8123,
|
"defaultPort": 8123,
|
||||||
"connection": { "host": "127.0.0.1", "port": 8124, "username": "default", "password": "123456", "database": "dbx" },
|
"connection": { "host": "127.0.0.1", "port": 10600, "username": "default", "password": "123456", "database": "dbx" },
|
||||||
|
"hostPorts": { "DB_PORT": 10600 },
|
||||||
"shell": ["clickhouse-client", "--user", "default", "--password", "${DB_PASSWORD}", "--database", "dbx"],
|
"shell": ["clickhouse-client", "--user", "default", "--password", "${DB_PASSWORD}", "--database", "dbx"],
|
||||||
"smoke": { "steps": [{ "name": "query initialized row", "command": ["clickhouse-client", "--user", "default", "--password", "${DB_PASSWORD}", "--database", "dbx", "--query", "SELECT note FROM dbx_smoke WHERE id = 1"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "query initialized row", "command": ["clickhouse-client", "--user", "default", "--password", "${DB_PASSWORD}", "--database", "dbx", "--query", "SELECT note FROM dbx_smoke WHERE id = 1"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
services:
|
||||||
|
database:
|
||||||
|
image: docker.cnb.cool/znb/images/consul:2.0.2
|
||||||
|
container_name: dbx-consul-2.0.2
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- agent
|
||||||
|
- -dev
|
||||||
|
- -client=0.0.0.0
|
||||||
|
- -ui
|
||||||
|
- -data-dir=/consul/data
|
||||||
|
ports:
|
||||||
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10900}:8500"
|
||||||
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${CONSUL_GRPC_PORT:-10901}:8502"
|
||||||
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${CONSUL_DNS_PORT:-10902}:8600/tcp"
|
||||||
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${CONSUL_DNS_PORT:-10902}:8600/udp"
|
||||||
|
volumes:
|
||||||
|
- data:/consul/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "consul", "members", "-http-addr=http://127.0.0.1:8500"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 30
|
||||||
|
start_period: 10s
|
||||||
|
volumes:
|
||||||
|
data:
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Consul development data
|
||||||
|
|
||||||
|
The Consul development agent starts without ACL authentication. `make db-verify DB=consul@2.0.2` writes and reads the `dbx/smoke` KV value.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"database": "consul",
|
||||||
|
"name": "Consul",
|
||||||
|
"version": "2.0.2",
|
||||||
|
"displayVersion": "2.0.2",
|
||||||
|
"image": "docker.cnb.cool/znb/images/consul:2.0.2",
|
||||||
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
|
"service": "database",
|
||||||
|
"defaultPort": 8500,
|
||||||
|
"connection": { "host": "127.0.0.1", "port": 10900, "authentication": "none", "database": "dbx", "grpcPort": 10901, "dnsPort": 10902 },
|
||||||
|
"hostPorts": { "DB_PORT": 10900, "CONSUL_GRPC_PORT": 10901, "CONSUL_DNS_PORT": 10902 },
|
||||||
|
"shell": ["consul", "members", "-http-addr=http://127.0.0.1:8500"],
|
||||||
|
"smoke": { "steps": [{ "name": "write a Consul KV smoke value", "command": ["consul", "kv", "put", "-http-addr=http://127.0.0.1:8500", "dbx/smoke", "DBX smoke"], "expect": "Success! Data written" }, { "name": "read the Consul KV smoke value", "command": ["consul", "kv", "get", "-http-addr=http://127.0.0.1:8500", "dbx/smoke"], "expect": "DBX smoke" }] }
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
services:
|
||||||
|
database:
|
||||||
|
image: docker.cnb.cool/znb/images/elasticsearch:6.8
|
||||||
|
container_name: dbx-elasticsearch-6.8
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-11500}:9200"
|
||||||
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${ELASTICSEARCH_TRANSPORT_PORT:-11501}:9300"
|
||||||
|
environment:
|
||||||
|
discovery.type: single-node
|
||||||
|
xpack.ml.enabled: "false"
|
||||||
|
volumes:
|
||||||
|
- data:/usr/share/elasticsearch/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl --fail --silent 'http://127.0.0.1:9200/_cluster/health?wait_for_status=yellow&timeout=1s' >/dev/null"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 30
|
||||||
|
start_period: 20s
|
||||||
|
volumes:
|
||||||
|
data:
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Elasticsearch 6.8 smoke data
|
||||||
|
|
||||||
|
`make db-verify DB=elasticsearch@6.8` indexes and reads the `dbx-smoke` document. Elasticsearch runs in single-node development mode without authentication.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"database": "elasticsearch",
|
||||||
|
"name": "Elasticsearch",
|
||||||
|
"version": "6.8",
|
||||||
|
"displayVersion": "6.8",
|
||||||
|
"image": "docker.cnb.cool/znb/images/elasticsearch:6.8",
|
||||||
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
|
"service": "database",
|
||||||
|
"defaultPort": 9200,
|
||||||
|
"connection": { "host": "127.0.0.1", "port": 11500, "authentication": "none", "database": "dbx", "transportPort": 11501 },
|
||||||
|
"hostPorts": { "DB_PORT": 11500, "ELASTICSEARCH_TRANSPORT_PORT": 11501 },
|
||||||
|
"shell": ["bash"],
|
||||||
|
"smoke": { "steps": [{ "name": "index a smoke document", "command": ["bash", "-c", "curl --fail --silent --show-error -X PUT -H 'Content-Type: application/json' -d '{\"message\":\"DBX smoke\"}' 'http://127.0.0.1:9200/dbx-smoke/_doc/1?refresh=true'"], "expect": "\"result\"" }, { "name": "read the smoke document", "command": ["bash", "-c", "curl --fail --silent --show-error http://127.0.0.1:9200/dbx-smoke/_doc/1"], "expect": "DBX smoke" }] }
|
||||||
|
}
|
||||||
@@ -18,8 +18,8 @@ services:
|
|||||||
- --logger=zap
|
- --logger=zap
|
||||||
- --log-outputs=stderr
|
- --log-outputs=stderr
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-2380}:2379"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10700}:2379"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${ETCD_PEER_PORT:-2381}:2380"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${ETCD_PEER_PORT:-10701}:2380"
|
||||||
volumes:
|
volumes:
|
||||||
- data:/etcd-data
|
- data:/etcd-data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 2379,
|
"defaultPort": 2379,
|
||||||
"connection": { "host": "127.0.0.1", "port": 2380, "username": "root", "password": "123456", "database": "dbx", "peerPort": 2381 },
|
"connection": { "host": "127.0.0.1", "port": 10700, "username": "root", "password": "123456", "database": "dbx", "peerPort": 10701 },
|
||||||
|
"hostPorts": { "DB_PORT": 10700, "ETCD_PEER_PORT": 10701 },
|
||||||
"bootstrap": {
|
"bootstrap": {
|
||||||
"check": { "command": ["/usr/local/bin/etcdctl", "--endpoints=http://127.0.0.1:2379", "--user", "root:${DB_PASSWORD}", "auth", "status"], "expect": "Authentication Status: true" },
|
"check": { "command": ["/usr/local/bin/etcdctl", "--endpoints=http://127.0.0.1:2379", "--user", "root:${DB_PASSWORD}", "auth", "status"], "expect": "Authentication Status: true" },
|
||||||
"steps": [
|
"steps": [
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ services:
|
|||||||
container_name: dbx-kafka-4.3
|
container_name: dbx-kafka-4.3
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-9093}:9092"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-11300}:9092"
|
||||||
environment:
|
environment:
|
||||||
KAFKA_NODE_ID: 1
|
KAFKA_NODE_ID: 1
|
||||||
KAFKA_PROCESS_ROLES: broker,controller
|
KAFKA_PROCESS_ROLES: broker,controller
|
||||||
KAFKA_LISTENERS: EXTERNAL://0.0.0.0:9092,CONTROLLER://0.0.0.0:9094,INTERNAL://0.0.0.0:9095
|
KAFKA_LISTENERS: EXTERNAL://0.0.0.0:9092,CONTROLLER://0.0.0.0:9094,INTERNAL://0.0.0.0:9095
|
||||||
KAFKA_ADVERTISED_LISTENERS: EXTERNAL://${KAFKA_ADVERTISED_HOST:-localhost}:${DB_PORT:-9093},INTERNAL://database:9095
|
KAFKA_ADVERTISED_LISTENERS: EXTERNAL://${KAFKA_ADVERTISED_HOST:-localhost}:${DB_PORT:-11300},INTERNAL://database:9095
|
||||||
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
|
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
|
||||||
KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
|
KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
|
||||||
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,INTERNAL:PLAINTEXT
|
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,INTERNAL:PLAINTEXT
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 9092,
|
"defaultPort": 9092,
|
||||||
"connection": { "host": "127.0.0.1", "port": 9093, "authentication": "none", "database": "dbx", "internalPort": 9095 },
|
"connection": { "host": "127.0.0.1", "port": 11300, "authentication": "none", "database": "dbx", "internalPort": 9095 },
|
||||||
|
"hostPorts": { "DB_PORT": 11300 },
|
||||||
"shell": ["/bin/bash"],
|
"shell": ["/bin/bash"],
|
||||||
"smoke": { "steps": [{ "name": "create, produce, and consume a smoke message", "command": ["/bin/bash", "-ec", "/opt/kafka/bin/kafka-topics.sh --bootstrap-server database:9095 --create --if-not-exists --topic dbx-smoke --partitions 1 --replication-factor 1; printf 'DBX smoke\\n' | /opt/kafka/bin/kafka-console-producer.sh --bootstrap-server database:9095 --topic dbx-smoke; /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server database:9095 --topic dbx-smoke --from-beginning --max-messages 1 --timeout-ms 10000"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "create, produce, and consume a smoke message", "command": ["/bin/bash", "-ec", "/opt/kafka/bin/kafka-topics.sh --bootstrap-server database:9095 --create --if-not-exists --topic dbx-smoke --partitions 1 --replication-factor 1; printf 'DBX smoke\\n' | /opt/kafka/bin/kafka-console-producer.sh --bootstrap-server database:9095 --topic dbx-smoke; /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server database:9095 --topic dbx-smoke --from-beginning --max-messages 1 --timeout-ms 10000"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ services:
|
|||||||
container_name: dbx-mariadb-10.11
|
container_name: dbx-mariadb-10.11
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-3307}:3306"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10200}:3306"
|
||||||
environment:
|
environment:
|
||||||
MARIADB_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
MARIADB_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
||||||
MARIADB_DATABASE: dbx
|
MARIADB_DATABASE: dbx
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 3306,
|
"defaultPort": 3306,
|
||||||
"connection": { "host": "127.0.0.1", "port": 3307, "username": "root", "password": "123456", "database": "dbx" },
|
"connection": { "host": "127.0.0.1", "port": 10200, "username": "root", "password": "123456", "database": "dbx" },
|
||||||
|
"hostPorts": { "DB_PORT": 10200 },
|
||||||
"shell": ["mariadb", "-uroot", "-p${DB_PASSWORD}", "-Ddbx"],
|
"shell": ["mariadb", "-uroot", "-p${DB_PASSWORD}", "-Ddbx"],
|
||||||
"smoke": { "steps": [{ "name": "query initialized row", "command": ["mariadb", "-uroot", "-p${DB_PASSWORD}", "-Ddbx", "-Nse", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "query initialized row", "command": ["mariadb", "-uroot", "-p${DB_PASSWORD}", "-Ddbx", "-Nse", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ services:
|
|||||||
container_name: dbx-mongodb-5.0
|
container_name: dbx-mongodb-5.0
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-27018}:27017"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10400}:27017"
|
||||||
environment:
|
environment:
|
||||||
MONGO_INITDB_ROOT_USERNAME: root
|
MONGO_INITDB_ROOT_USERNAME: root
|
||||||
MONGO_INITDB_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
MONGO_INITDB_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 27017,
|
"defaultPort": 27017,
|
||||||
"connection": { "host": "127.0.0.1", "port": 27018, "username": "root", "password": "123456", "database": "dbx", "authSource": "admin" },
|
"connection": { "host": "127.0.0.1", "port": 10400, "username": "root", "password": "123456", "database": "dbx", "authSource": "admin" },
|
||||||
|
"hostPorts": { "DB_PORT": 10400 },
|
||||||
"shell": ["mongosh", "--quiet", "--host", "127.0.0.1", "--port", "27017", "--username", "root", "--password", "${DB_PASSWORD}", "--authenticationDatabase", "admin", "dbx"],
|
"shell": ["mongosh", "--quiet", "--host", "127.0.0.1", "--port", "27017", "--username", "root", "--password", "${DB_PASSWORD}", "--authenticationDatabase", "admin", "dbx"],
|
||||||
"smoke": { "steps": [{ "name": "query initialized document over TCP", "command": ["mongosh", "--quiet", "--host", "127.0.0.1", "--port", "27017", "--username", "root", "--password", "${DB_PASSWORD}", "--authenticationDatabase", "admin", "dbx", "--eval", "db.dbx_smoke.findOne({_id: 1}).note"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "query initialized document over TCP", "command": ["mongosh", "--quiet", "--host", "127.0.0.1", "--port", "27017", "--username", "root", "--password", "${DB_PASSWORD}", "--authenticationDatabase", "admin", "dbx", "--eval", "db.dbx_smoke.findOne({_id: 1}).note"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ services:
|
|||||||
container_name: dbx-mongodb-8.2
|
container_name: dbx-mongodb-8.2
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-27018}:27017"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10401}:27017"
|
||||||
environment:
|
environment:
|
||||||
MONGO_INITDB_ROOT_USERNAME: root
|
MONGO_INITDB_ROOT_USERNAME: root
|
||||||
MONGO_INITDB_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
MONGO_INITDB_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 27017,
|
"defaultPort": 27017,
|
||||||
"connection": { "host": "127.0.0.1", "port": 27018, "username": "root", "password": "123456", "database": "dbx", "authSource": "admin" },
|
"connection": { "host": "127.0.0.1", "port": 10401, "username": "root", "password": "123456", "database": "dbx", "authSource": "admin" },
|
||||||
|
"hostPorts": { "DB_PORT": 10401 },
|
||||||
"shell": ["mongosh", "--quiet", "--host", "127.0.0.1", "--port", "27017", "--username", "root", "--password", "${DB_PASSWORD}", "--authenticationDatabase", "admin", "dbx"],
|
"shell": ["mongosh", "--quiet", "--host", "127.0.0.1", "--port", "27017", "--username", "root", "--password", "${DB_PASSWORD}", "--authenticationDatabase", "admin", "dbx"],
|
||||||
"smoke": { "steps": [{ "name": "query initialized document over TCP", "command": ["mongosh", "--quiet", "--host", "127.0.0.1", "--port", "27017", "--username", "root", "--password", "${DB_PASSWORD}", "--authenticationDatabase", "admin", "dbx", "--eval", "db.dbx_smoke.findOne({_id: 1}).note"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "query initialized document over TCP", "command": ["mongosh", "--quiet", "--host", "127.0.0.1", "--port", "27017", "--username", "root", "--password", "${DB_PASSWORD}", "--authenticationDatabase", "admin", "dbx", "--eval", "db.dbx_smoke.findOne({_id: 1}).note"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ services:
|
|||||||
container_name: dbx-mysql-5.7
|
container_name: dbx-mysql-5.7
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-3307}:3306"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10100}:3306"
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
MYSQL_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
||||||
MYSQL_DATABASE: dbx
|
MYSQL_DATABASE: dbx
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 3306,
|
"defaultPort": 3306,
|
||||||
"connection": { "host": "127.0.0.1", "port": 3307, "username": "root", "password": "123456", "database": "dbx" },
|
"connection": { "host": "127.0.0.1", "port": 10100, "username": "root", "password": "123456", "database": "dbx" },
|
||||||
|
"hostPorts": { "DB_PORT": 10100 },
|
||||||
"shell": ["mysql", "-uroot", "-p${DB_PASSWORD}", "-Ddbx"],
|
"shell": ["mysql", "-uroot", "-p${DB_PASSWORD}", "-Ddbx"],
|
||||||
"smoke": { "steps": [{ "name": "query initialized row", "command": ["mysql", "-uroot", "-p${DB_PASSWORD}", "-Ddbx", "-Nse", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "query initialized row", "command": ["mysql", "-uroot", "-p${DB_PASSWORD}", "-Ddbx", "-Nse", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ services:
|
|||||||
container_name: dbx-mysql-8.4
|
container_name: dbx-mysql-8.4
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-3307}:3306"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10101}:3306"
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
MYSQL_ROOT_PASSWORD: "${DB_PASSWORD:-123456}"
|
||||||
MYSQL_DATABASE: dbx
|
MYSQL_DATABASE: dbx
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 3306,
|
"defaultPort": 3306,
|
||||||
"connection": { "host": "127.0.0.1", "port": 3307, "username": "root", "password": "123456", "database": "dbx" },
|
"connection": { "host": "127.0.0.1", "port": 10101, "username": "root", "password": "123456", "database": "dbx" },
|
||||||
|
"hostPorts": { "DB_PORT": 10101 },
|
||||||
"shell": ["mysql", "-uroot", "-p${DB_PASSWORD}", "-Ddbx"],
|
"shell": ["mysql", "-uroot", "-p${DB_PASSWORD}", "-Ddbx"],
|
||||||
"smoke": { "steps": [{ "name": "query initialized row", "command": ["mysql", "-uroot", "-p${DB_PASSWORD}", "-Ddbx", "-Nse", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "query initialized row", "command": ["mysql", "-uroot", "-p${DB_PASSWORD}", "-Ddbx", "-Nse", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ services:
|
|||||||
container_name: dbx-nacos-2.5
|
container_name: dbx-nacos-2.5
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-8849}:8848"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-11000}:8848"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_GRPC_PORT:-9849}:9848"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_GRPC_PORT:-11001}:9848"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_RAFT_PORT:-9850}:9849"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_RAFT_PORT:-11002}:9849"
|
||||||
environment:
|
environment:
|
||||||
MODE: standalone
|
MODE: standalone
|
||||||
PREFER_HOST_MODE: hostname
|
PREFER_HOST_MODE: hostname
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 8848,
|
"defaultPort": 8848,
|
||||||
"connection": { "host": "127.0.0.1", "port": 8849, "username": "nacos", "password": "123456", "database": "dbx", "namespace": "public" },
|
"connection": { "host": "127.0.0.1", "port": 11000, "username": "nacos", "password": "123456", "database": "dbx", "namespace": "public", "grpcPort": 11001, "raftPort": 11002 },
|
||||||
|
"hostPorts": { "DB_PORT": 11000, "NACOS_GRPC_PORT": 11001, "NACOS_RAFT_PORT": 11002 },
|
||||||
"bootstrap": {
|
"bootstrap": {
|
||||||
"check": { "command": ["curl", "--fail", "--silent", "--show-error", "--request", "POST", "http://127.0.0.1:8848/nacos/v1/auth/login", "--data-urlencode", "username=nacos", "--data-urlencode", "password=${DB_PASSWORD}"], "expect": "accessToken" },
|
"check": { "command": ["curl", "--fail", "--silent", "--show-error", "--request", "POST", "http://127.0.0.1:8848/nacos/v1/auth/login", "--data-urlencode", "username=nacos", "--data-urlencode", "password=${DB_PASSWORD}"], "expect": "accessToken" },
|
||||||
"steps": [{ "name": "initialize administrator password", "command": ["sh", "-ec", "curl --fail --silent --show-error --request POST --data-urlencode \"password=$1\" http://127.0.0.1:8848/nacos/v1/auth/users/admin >/dev/null; curl --fail --silent --show-error --request POST http://127.0.0.1:8848/nacos/v1/auth/login --data-urlencode username=nacos --data-urlencode \"password=$1\" | grep -q '\"accessToken\"'; printf 'administrator initialized\\n'", "sh", "${DB_PASSWORD}"], "expect": "administrator initialized" }]
|
"steps": [{ "name": "initialize administrator password", "command": ["sh", "-ec", "curl --fail --silent --show-error --request POST --data-urlencode \"password=$1\" http://127.0.0.1:8848/nacos/v1/auth/users/admin >/dev/null; curl --fail --silent --show-error --request POST http://127.0.0.1:8848/nacos/v1/auth/login --data-urlencode username=nacos --data-urlencode \"password=$1\" | grep -q '\"accessToken\"'; printf 'administrator initialized\\n'", "sh", "${DB_PASSWORD}"], "expect": "administrator initialized" }]
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
services:
|
services:
|
||||||
database:
|
database:
|
||||||
image: docker.cnb.cool/znb/images/nacos-server:v3.2.2
|
image: docker.cnb.cool/znb/images/nacos-server:v3.2.3
|
||||||
container_name: dbx-nacos-3.2
|
container_name: dbx-nacos-3.2
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_CONSOLE_PORT:-8010}:8080"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_CONSOLE_PORT:-11004}:8080"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-8849}:8848"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-11003}:8848"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_GRPC_PORT:-9849}:9848"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_GRPC_PORT:-11005}:9848"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_RAFT_PORT:-9850}:9849"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${NACOS_RAFT_PORT:-11006}:9849"
|
||||||
environment:
|
environment:
|
||||||
MODE: standalone
|
MODE: standalone
|
||||||
PREFER_HOST_MODE: hostname
|
PREFER_HOST_MODE: hostname
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
{
|
{
|
||||||
"database": "nacos",
|
"database": "nacos",
|
||||||
"name": "Nacos",
|
"name": "Nacos",
|
||||||
"version": "3.2.2",
|
"version": "3.2.3",
|
||||||
"displayVersion": "3.2",
|
"displayVersion": "3.2",
|
||||||
"image": "docker.cnb.cool/znb/images/nacos-server:v3.2.2",
|
"image": "docker.cnb.cool/znb/images/nacos-server:v3.2.3",
|
||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 8848,
|
"defaultPort": 8848,
|
||||||
"connection": { "host": "127.0.0.1", "port": 8849, "username": "nacos", "password": "123456", "database": "dbx", "namespace": "public", "consolePort": 8010 },
|
"connection": { "host": "127.0.0.1", "port": 11003, "username": "nacos", "password": "123456", "database": "dbx", "namespace": "public", "consolePort": 11004, "grpcPort": 11005, "raftPort": 11006 },
|
||||||
|
"hostPorts": { "DB_PORT": 11003, "NACOS_CONSOLE_PORT": 11004, "NACOS_GRPC_PORT": 11005, "NACOS_RAFT_PORT": 11006 },
|
||||||
"bootstrap": {
|
"bootstrap": {
|
||||||
"check": { "command": ["curl", "--fail", "--silent", "--show-error", "--request", "POST", "http://127.0.0.1:8848/nacos/v3/auth/user/login", "--data-urlencode", "username=nacos", "--data-urlencode", "password=${DB_PASSWORD}"], "expect": "accessToken" },
|
"check": { "command": ["curl", "--fail", "--silent", "--show-error", "--request", "POST", "http://127.0.0.1:8848/nacos/v3/auth/user/login", "--data-urlencode", "username=nacos", "--data-urlencode", "password=${DB_PASSWORD}"], "expect": "accessToken" },
|
||||||
"steps": [{ "name": "initialize administrator password", "command": ["sh", "-ec", "curl --fail --silent --show-error --request POST --data-urlencode \"password=$1\" http://127.0.0.1:8848/nacos/v3/auth/user/admin >/dev/null; curl --fail --silent --show-error --request POST http://127.0.0.1:8848/nacos/v3/auth/user/login --data-urlencode username=nacos --data-urlencode \"password=$1\" | grep -q '\"accessToken\"'; printf 'administrator initialized\\n'", "sh", "${DB_PASSWORD}"], "expect": "administrator initialized" }]
|
"steps": [{ "name": "initialize administrator password", "command": ["sh", "-ec", "curl --fail --silent --show-error --request POST --data-urlencode \"password=$1\" http://127.0.0.1:8848/nacos/v3/auth/user/admin >/dev/null; curl --fail --silent --show-error --request POST http://127.0.0.1:8848/nacos/v3/auth/user/login --data-urlencode username=nacos --data-urlencode \"password=$1\" | grep -q '\"accessToken\"'; printf 'administrator initialized\\n'", "sh", "${DB_PASSWORD}"], "expect": "administrator initialized" }]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ services:
|
|||||||
container_name: dbx-postgresql-14.23
|
container_name: dbx-postgresql-14.23
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-5433}:5432"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10300}:5432"
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: "${DB_PASSWORD:-123456}"
|
POSTGRES_PASSWORD: "${DB_PASSWORD:-123456}"
|
||||||
POSTGRES_DB: dbx
|
POSTGRES_DB: dbx
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 5432,
|
"defaultPort": 5432,
|
||||||
"connection": { "host": "127.0.0.1", "port": 5433, "username": "postgres", "password": "123456", "database": "dbx" },
|
"connection": { "host": "127.0.0.1", "port": 10300, "username": "postgres", "password": "123456", "database": "dbx" },
|
||||||
|
"hostPorts": { "DB_PORT": 10300 },
|
||||||
"shell": ["env", "PGPASSWORD=${DB_PASSWORD}", "psql", "-h", "127.0.0.1", "-p", "5432", "-U", "postgres", "-d", "dbx"],
|
"shell": ["env", "PGPASSWORD=${DB_PASSWORD}", "psql", "-h", "127.0.0.1", "-p", "5432", "-U", "postgres", "-d", "dbx"],
|
||||||
"smoke": { "steps": [{ "name": "query initialized row over TCP", "command": ["env", "PGPASSWORD=${DB_PASSWORD}", "psql", "-h", "127.0.0.1", "-p", "5432", "-U", "postgres", "-d", "dbx", "-Atc", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "query initialized row over TCP", "command": ["env", "PGPASSWORD=${DB_PASSWORD}", "psql", "-h", "127.0.0.1", "-p", "5432", "-U", "postgres", "-d", "dbx", "-Atc", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ services:
|
|||||||
container_name: dbx-postgresql-17.4
|
container_name: dbx-postgresql-17.4
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-5433}:5432"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10301}:5432"
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: "${DB_PASSWORD:-123456}"
|
POSTGRES_PASSWORD: "${DB_PASSWORD:-123456}"
|
||||||
POSTGRES_DB: dbx
|
POSTGRES_DB: dbx
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 5432,
|
"defaultPort": 5432,
|
||||||
"connection": { "host": "127.0.0.1", "port": 5433, "username": "postgres", "password": "123456", "database": "dbx" },
|
"connection": { "host": "127.0.0.1", "port": 10301, "username": "postgres", "password": "123456", "database": "dbx" },
|
||||||
|
"hostPorts": { "DB_PORT": 10301 },
|
||||||
"shell": ["env", "PGPASSWORD=${DB_PASSWORD}", "psql", "-h", "127.0.0.1", "-p", "5432", "-U", "postgres", "-d", "dbx"],
|
"shell": ["env", "PGPASSWORD=${DB_PASSWORD}", "psql", "-h", "127.0.0.1", "-p", "5432", "-U", "postgres", "-d", "dbx"],
|
||||||
"smoke": { "steps": [{ "name": "query initialized row over TCP", "command": ["env", "PGPASSWORD=${DB_PASSWORD}", "psql", "-h", "127.0.0.1", "-p", "5432", "-U", "postgres", "-d", "dbx", "-Atc", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "query initialized row over TCP", "command": ["env", "PGPASSWORD=${DB_PASSWORD}", "psql", "-h", "127.0.0.1", "-p", "5432", "-U", "postgres", "-d", "dbx", "-Atc", "SELECT note FROM dbx_smoke WHERE id=1"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
command: ["bin/pulsar", "standalone", "--advertised-address", "localhost"]
|
command: ["bin/pulsar", "standalone", "--advertised-address", "localhost"]
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-6651}:6650"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-11400}:6650"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${PULSAR_WEB_PORT:-8081}:8080"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${PULSAR_WEB_PORT:-11401}:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- data:/pulsar/data
|
- data:/pulsar/data
|
||||||
- conf:/pulsar/conf
|
- conf:/pulsar/conf
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 6650,
|
"defaultPort": 6650,
|
||||||
"connection": { "host": "127.0.0.1", "port": 6651, "authentication": "none", "database": "dbx", "namespace": "public/default", "webPort": 8081 },
|
"connection": { "host": "127.0.0.1", "port": 11400, "authentication": "none", "database": "dbx", "namespace": "public/default", "webPort": 11401 },
|
||||||
|
"hostPorts": { "DB_PORT": 11400, "PULSAR_WEB_PORT": 11401 },
|
||||||
"shell": ["/bin/bash"],
|
"shell": ["/bin/bash"],
|
||||||
"smoke": { "steps": [{ "name": "produce a smoke message", "command": ["bin/pulsar-client", "produce", "persistent://public/default/dbx-smoke", "--messages", "DBX smoke"], "expect": "1 messages successfully produced" }] }
|
"smoke": { "steps": [{ "name": "produce a smoke message", "command": ["bin/pulsar-client", "produce", "persistent://public/default/dbx-smoke", "--messages", "DBX smoke"], "expect": "1 messages successfully produced" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ services:
|
|||||||
container_name: dbx-qdrant-1.8
|
container_name: dbx-qdrant-1.8
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-6334}:6333"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-11200}:6333"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${QDRANT_GRPC_PORT:-6335}:6334"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${QDRANT_GRPC_PORT:-11201}:6334"
|
||||||
environment:
|
environment:
|
||||||
QDRANT__SERVICE__API_KEY: "${DB_PASSWORD:-123456}"
|
QDRANT__SERVICE__API_KEY: "${DB_PASSWORD:-123456}"
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 6333,
|
"defaultPort": 6333,
|
||||||
"connection": { "host": "127.0.0.1", "port": 6334, "username": "", "password": "123456", "database": "dbx", "grpcPort": 6335 },
|
"connection": { "host": "127.0.0.1", "port": 11200, "username": "", "password": "123456", "database": "dbx", "grpcPort": 11201 },
|
||||||
|
"hostPorts": { "DB_PORT": 11200, "QDRANT_GRPC_PORT": 11201 },
|
||||||
"shell": ["bash"],
|
"shell": ["bash"],
|
||||||
"smoke": { "steps": [{ "name": "reject an unauthenticated collection request", "command": ["bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/6333; printf 'GET /collections HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3; cat <&3"], "expect": "403 Forbidden" }, { "name": "query collections with the configured API key", "command": ["bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/6333; printf 'GET /collections HTTP/1.1\\r\\nHost: localhost\\r\\napi-key: %s\\r\\nConnection: close\\r\\n\\r\\n' \"$1\" >&3; cat <&3", "bash", "${DB_PASSWORD}"], "expect": "collections" }] }
|
"smoke": { "steps": [{ "name": "reject an unauthenticated collection request", "command": ["bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/6333; printf 'GET /collections HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3; cat <&3"], "expect": "403 Forbidden" }, { "name": "query collections with the configured API key", "command": ["bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/6333; printf 'GET /collections HTTP/1.1\\r\\nHost: localhost\\r\\napi-key: %s\\r\\nConnection: close\\r\\n\\r\\n' \"$1\" >&3; cat <&3", "bash", "${DB_PASSWORD}"], "expect": "collections" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ services:
|
|||||||
# Keep the password in container env so CMD-SHELL can quote it safely.
|
# Keep the password in container env so CMD-SHELL can quote it safely.
|
||||||
REDIS_PASSWORD: "${DB_PASSWORD:-123456}"
|
REDIS_PASSWORD: "${DB_PASSWORD:-123456}"
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-6380}:6379"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10500}:6379"
|
||||||
volumes:
|
volumes:
|
||||||
- data:/data
|
- data:/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64"],
|
"platforms": ["linux/amd64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 6379,
|
"defaultPort": 6379,
|
||||||
"connection": { "host": "127.0.0.1", "port": 6380, "password": "123456", "database": 0 },
|
"connection": { "host": "127.0.0.1", "port": 10500, "password": "123456", "database": 0 },
|
||||||
|
"hostPorts": { "DB_PORT": 10500 },
|
||||||
"shell": ["redis-cli", "-a", "${DB_PASSWORD}"],
|
"shell": ["redis-cli", "-a", "${DB_PASSWORD}"],
|
||||||
"smoke": { "steps": [{ "name": "seed smoke key", "command": ["redis-cli", "-a", "${DB_PASSWORD}", "SET", "dbx:smoke", "DBX smoke"], "expect": "OK" }, { "name": "read smoke key", "command": ["redis-cli", "-a", "${DB_PASSWORD}", "GET", "dbx:smoke"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "seed smoke key", "command": ["redis-cli", "-a", "${DB_PASSWORD}", "SET", "dbx:smoke", "DBX smoke"], "expect": "OK" }, { "name": "read smoke key", "command": ["redis-cli", "-a", "${DB_PASSWORD}", "GET", "dbx:smoke"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ services:
|
|||||||
# Keep the password in container env so CMD-SHELL can quote it safely.
|
# Keep the password in container env so CMD-SHELL can quote it safely.
|
||||||
REDIS_PASSWORD: "${DB_PASSWORD:-123456}"
|
REDIS_PASSWORD: "${DB_PASSWORD:-123456}"
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-6380}:6379"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10501}:6379"
|
||||||
volumes:
|
volumes:
|
||||||
- data:/data
|
- data:/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 6379,
|
"defaultPort": 6379,
|
||||||
"connection": { "host": "127.0.0.1", "port": 6380, "username": "default", "password": "123456", "database": 0 },
|
"connection": { "host": "127.0.0.1", "port": 10501, "username": "default", "password": "123456", "database": 0 },
|
||||||
|
"hostPorts": { "DB_PORT": 10501 },
|
||||||
"shell": ["redis-cli", "-a", "${DB_PASSWORD}"],
|
"shell": ["redis-cli", "-a", "${DB_PASSWORD}"],
|
||||||
"smoke": { "steps": [{ "name": "seed smoke key", "command": ["redis-cli", "-a", "${DB_PASSWORD}", "SET", "dbx:smoke", "DBX smoke"], "expect": "OK" }, { "name": "read smoke key", "command": ["redis-cli", "-a", "${DB_PASSWORD}", "GET", "dbx:smoke"], "expect": "DBX smoke" }] }
|
"smoke": { "steps": [{ "name": "seed smoke key", "command": ["redis-cli", "-a", "${DB_PASSWORD}", "SET", "dbx:smoke", "DBX smoke"], "expect": "OK" }, { "name": "read smoke key", "command": ["redis-cli", "-a", "${DB_PASSWORD}", "GET", "dbx:smoke"], "expect": "DBX smoke" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ services:
|
|||||||
image: docker.cnb.cool/znb/images/rnacos:v0.8.5
|
image: docker.cnb.cool/znb/images/rnacos:v0.8.5
|
||||||
container_name: dbx-rnacos-0.8
|
container_name: dbx-rnacos-0.8
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-8849}:8848"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-11100}:8848"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${RNACOS_GRPC_PORT:-9849}:9848"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${RNACOS_GRPC_PORT:-11101}:9848"
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${RNACOS_CONSOLE_PORT:-10849}:10848"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${RNACOS_CONSOLE_PORT:-11102}:10848"
|
||||||
volumes:
|
volumes:
|
||||||
- data:/io
|
- data:/io
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 8848,
|
"defaultPort": 8848,
|
||||||
"connection": { "host": "127.0.0.1", "port": 8849, "username": "admin", "password": "123456", "database": "dbx", "namespace": "public", "grpcPort": 9849, "consolePort": 10849 },
|
"connection": { "host": "127.0.0.1", "port": 11100, "username": "admin", "password": "123456", "database": "dbx", "namespace": "public", "grpcPort": 11101, "consolePort": 11102 },
|
||||||
|
"hostPorts": { "DB_PORT": 11100, "RNACOS_GRPC_PORT": 11101, "RNACOS_CONSOLE_PORT": 11102 },
|
||||||
"shell": ["bash"],
|
"shell": ["bash"],
|
||||||
"smoke": { "steps": [{ "name": "check the HTTP health endpoint", "command": ["bash", "-ec", "exec 3<>/dev/tcp/127.0.0.1/8848; printf 'GET /health HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3; cat <&3"], "expect": "success" }] }
|
"smoke": { "steps": [{ "name": "check the HTTP health endpoint", "command": ["bash", "-ec", "exec 3<>/dev/tcp/127.0.0.1/8848; printf 'GET /health HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3; cat <&3"], "expect": "success" }] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ services:
|
|||||||
container_name: dbx-zookeeper-3.9
|
container_name: dbx-zookeeper-3.9
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-2182}:2181"
|
- "${DB_BIND_ADDRESS:-127.0.0.1}:${DB_PORT:-10800}:2181"
|
||||||
volumes:
|
volumes:
|
||||||
- data:/data
|
- data:/data
|
||||||
- datalog:/datalog
|
- datalog:/datalog
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"platforms": ["linux/amd64", "linux/arm64"],
|
"platforms": ["linux/amd64", "linux/arm64"],
|
||||||
"service": "database",
|
"service": "database",
|
||||||
"defaultPort": 2181,
|
"defaultPort": 2181,
|
||||||
"connection": { "host": "127.0.0.1", "port": 2182, "username": "root", "password": "123456", "database": "dbx", "authScheme": "digest" },
|
"connection": { "host": "127.0.0.1", "port": 10800, "username": "root", "password": "123456", "database": "dbx", "authScheme": "digest" },
|
||||||
|
"hostPorts": { "DB_PORT": 10800 },
|
||||||
"bootstrap": {
|
"bootstrap": {
|
||||||
"check": { "command": ["sh", "-ec", "printf 'addauth digest root:%s\\nget /dbx\\nquit\\n' \"$1\" | zkCli.sh -server 127.0.0.1:2181", "sh", "${DB_PASSWORD}"], "expect": "DBX smoke" },
|
"check": { "command": ["sh", "-ec", "printf 'addauth digest root:%s\\nget /dbx\\nquit\\n' \"$1\" | zkCli.sh -server 127.0.0.1:2181", "sh", "${DB_PASSWORD}"], "expect": "DBX smoke" },
|
||||||
"steps": [{ "name": "create Digest-protected smoke node", "command": ["sh", "-ec", "printf 'addauth digest root:%s\\ncreate /dbx \"DBX smoke\" auth:root:%s:cdrwa\\nquit\\n' \"$1\" \"$1\" | zkCli.sh -server 127.0.0.1:2181", "sh", "${DB_PASSWORD}"], "expect": "Created /dbx" }]
|
"steps": [{ "name": "create Digest-protected smoke node", "command": ["sh", "-ec", "printf 'addauth digest root:%s\\ncreate /dbx \"DBX smoke\" auth:root:%s:cdrwa\\nquit\\n' \"$1\" \"$1\" | zkCli.sh -server 127.0.0.1:2181", "sh", "${DB_PASSWORD}"], "expect": "Created /dbx" }]
|
||||||
|
|||||||
@@ -9,63 +9,77 @@ description: 为 DBX 开发与验证启动可重复创建的本地数据库实
|
|||||||
|
|
||||||
## 可用配方
|
## 可用配方
|
||||||
|
|
||||||
| 数据库 | 版本目录 | Docker Hub 官方镜像 | Compose 使用的 CNB 镜像 | 默认宿主端口 | 容器名 |
|
| 数据库 | 版本目录 | 官方上游镜像 | Compose 使用的 CNB 镜像 | 默认宿主端口 | 容器名 |
|
||||||
| --- | --- | --- | --- | ---: | --- |
|
| --- | --- | --- | --- | ---: | --- |
|
||||||
| ClickHouse | `clickhouse/24.8` | `clickhouse/clickhouse-server:24.8.14.39` | `docker.cnb.cool/znb/images/clickhouse-server:24.8.14.39` | `8124` | `dbx-clickhouse-24.8` |
|
| ClickHouse | `clickhouse/24.8` | `clickhouse/clickhouse-server:24.8.14.39` | `docker.cnb.cool/znb/images/clickhouse-server:24.8.14.39` | `10600` | `dbx-clickhouse-24.8` |
|
||||||
| etcd | `etcd/3.7` | `gcr.io/etcd-development/etcd:v3.7.0` | `docker.cnb.cool/znb/images/etcd:v3.7.0` | `2380` | `dbx-etcd-3.7` |
|
| Consul | `consul/2.0.2` | `hashicorp/consul:2.0.2` | `docker.cnb.cool/znb/images/consul:2.0.2` | `10900` | `dbx-consul-2.0.2` |
|
||||||
| Kafka | `kafka/4.3` | `apache/kafka:4.3.1` | `docker.cnb.cool/znb/images/kafka:4.3.1` | `9093` | `dbx-kafka-4.3` |
|
| Elasticsearch | `elasticsearch/6.8` | `docker.elastic.co/elasticsearch/elasticsearch:6.8` | `docker.cnb.cool/znb/images/elasticsearch:6.8` | `11500` | `dbx-elasticsearch-6.8` |
|
||||||
| MariaDB | `mariadb/10.11` | `mariadb:10.11.11` | `docker.cnb.cool/znb/images/mariadb:10.11.11` | `3307` | `dbx-mariadb-10.11` |
|
| etcd | `etcd/3.7` | `gcr.io/etcd-development/etcd:v3.7.0` | `docker.cnb.cool/znb/images/etcd:v3.7.0` | `10700` | `dbx-etcd-3.7` |
|
||||||
| MongoDB | `mongodb/5.0` | `mongo:5.0.5` | `docker.cnb.cool/znb/images/mongo:5.0.5` | `27018` | `dbx-mongodb-5.0` |
|
| Kafka | `kafka/4.3` | `apache/kafka:4.3.1` | `docker.cnb.cool/znb/images/kafka:4.3.1` | `11300` | `dbx-kafka-4.3` |
|
||||||
| MongoDB | `mongodb/8.2` | `mongo:8.2.3-noble` | `docker.cnb.cool/znb/images/mongo:8.2.3-noble` | `27018` | `dbx-mongodb-8.2` |
|
| MariaDB | `mariadb/10.11` | `mariadb:10.11.11` | `docker.cnb.cool/znb/images/mariadb:10.11.11` | `10200` | `dbx-mariadb-10.11` |
|
||||||
| MySQL | `mysql/5.7` | `mysql:5.7.44` | `docker.cnb.cool/znb/images/mysql:5.7.44` | `3307` | `dbx-mysql-5.7` |
|
| MongoDB | `mongodb/5.0` | `mongo:5.0.5` | `docker.cnb.cool/znb/images/mongo:5.0.5` | `10400` | `dbx-mongodb-5.0` |
|
||||||
| MySQL | `mysql/8.4` | `mysql:8.4.6` | `docker.cnb.cool/znb/images/mysql:8.4.6` | `3307` | `dbx-mysql-8.4` |
|
| MongoDB | `mongodb/8.2` | `mongo:8.2.3-noble` | `docker.cnb.cool/znb/images/mongo:8.2.3-noble` | `10401` | `dbx-mongodb-8.2` |
|
||||||
| Nacos | `nacos/2.5` | `nacos/nacos-server:v2.5.2` | `docker.cnb.cool/znb/images/nacos-server:v2.5.2` | `8849` | `dbx-nacos-2.5` |
|
| MySQL | `mysql/5.7` | `mysql:5.7.44` | `docker.cnb.cool/znb/images/mysql:5.7.44` | `10100` | `dbx-mysql-5.7` |
|
||||||
| Nacos | `nacos/3.2` | `nacos/nacos-server:v3.2.2` | `docker.cnb.cool/znb/images/nacos-server:v3.2.2` | `8849` | `dbx-nacos-3.2` |
|
| MySQL | `mysql/8.4` | `mysql:8.4.6` | `docker.cnb.cool/znb/images/mysql:8.4.6` | `10101` | `dbx-mysql-8.4` |
|
||||||
| PostgreSQL | `postgresql/14.23` | `postgres:14.23` | `docker.cnb.cool/znb/images/postgres:14.23` | `5433` | `dbx-postgresql-14.23` |
|
| Nacos | `nacos/2.5` | `nacos/nacos-server:v2.5.2` | `docker.cnb.cool/znb/images/nacos-server:v2.5.2` | `11000` | `dbx-nacos-2.5` |
|
||||||
| PostgreSQL | `postgresql/17.4` | `postgres:17.4` | `docker.cnb.cool/znb/images/postgres:17.4` | `5433` | `dbx-postgresql-17.4` |
|
| Nacos | `nacos/3.2` | `nacos/nacos-server:v3.2.3` | `docker.cnb.cool/znb/images/nacos-server:v3.2.3` | `11003` | `dbx-nacos-3.2` |
|
||||||
| Pulsar | `pulsar/4.2` | `apachepulsar/pulsar:4.2.3` | `docker.cnb.cool/znb/images/pulsar:4.2.3` | `6651` | `dbx-pulsar-4.2` |
|
| PostgreSQL | `postgresql/14.23` | `postgres:14.23` | `docker.cnb.cool/znb/images/postgres:14.23` | `10300` | `dbx-postgresql-14.23` |
|
||||||
| Qdrant | `qdrant/1.8` | `qdrant/qdrant:v1.8.3` | `docker.cnb.cool/znb/images/qdrant:v1.8.3` | `6334` | `dbx-qdrant-1.8` |
|
| PostgreSQL | `postgresql/17.4` | `postgres:17.4` | `docker.cnb.cool/znb/images/postgres:17.4` | `10301` | `dbx-postgresql-17.4` |
|
||||||
| Redis | `redis/3.0.7` | `redis:3.0.7-alpine` | `docker.cnb.cool/znb/images/redis:3.0.7-alpine` | `6380` | `dbx-redis-3.0.7` |
|
| Pulsar | `pulsar/4.2` | `apachepulsar/pulsar:4.2.3` | `docker.cnb.cool/znb/images/pulsar:4.2.3` | `11400` | `dbx-pulsar-4.2` |
|
||||||
| Redis | `redis/7.4` | `redis:7.4.9-alpine` | `docker.cnb.cool/znb/images/redis:7.4.9-alpine` | `6380` | `dbx-redis-7.4` |
|
| Qdrant | `qdrant/1.8` | `qdrant/qdrant:v1.8.3` | `docker.cnb.cool/znb/images/qdrant:v1.8.3` | `11200` | `dbx-qdrant-1.8` |
|
||||||
| r-nacos | `rnacos/0.8` | `qingpan/rnacos:v0.8.5` | `docker.cnb.cool/znb/images/rnacos:v0.8.5` | `8849` | `dbx-rnacos-0.8` |
|
| Redis | `redis/3.0.7` | `redis:3.0.7-alpine` | `docker.cnb.cool/znb/images/redis:3.0.7-alpine` | `10500` | `dbx-redis-3.0.7` |
|
||||||
| ZooKeeper | `zookeeper/3.9` | `zookeeper:3.9.5` | `docker.cnb.cool/znb/images/zookeeper:3.9.5` | `2182` | `dbx-zookeeper-3.9` |
|
| Redis | `redis/7.4` | `redis:7.4.9-alpine` | `docker.cnb.cool/znb/images/redis:7.4.9-alpine` | `10501` | `dbx-redis-7.4` |
|
||||||
|
| r-nacos | `rnacos/0.8` | `qingpan/rnacos:v0.8.5` | `docker.cnb.cool/znb/images/rnacos:v0.8.5` | `11100` | `dbx-rnacos-0.8` |
|
||||||
|
| ZooKeeper | `zookeeper/3.9` | `zookeeper:3.9.5` | `docker.cnb.cool/znb/images/zookeeper:3.9.5` | `10800` | `dbx-zookeeper-3.9` |
|
||||||
|
|
||||||
所有网络数据库的默认宿主端口都比标准端口大 `1`,并且该约定由配方校验器强制检查。默认密码统一为 `123456`,默认数据库名为 `dbx`。Redis 不支持命名数据库,因此使用 DB 0,并以 `dbx:` 作为冒烟键前缀。Compose 默认使用 CNB 镜像列;Docker Hub 列保留官方上游地址,便于核对来源或直接拉取。Redis 3.0.7 仅支持 amd64;在 arm64 主机上启动时会单独提醒,Docker 将使用模拟运行。其余配方均支持 amd64 和 arm64。
|
每个产品使用专属的 `101xx` 至 `115xx` 宿主端口段,校验器会验证全部声明的默认映射位于正确范围且全局唯一。默认密码统一为 `123456`,默认数据库名为 `dbx`。Redis 不支持命名数据库,因此使用 DB 0,并以 `dbx:` 作为冒烟键前缀。Compose 默认使用 CNB 镜像列;官方上游镜像列保留原始镜像地址,便于核对来源或直接拉取。Redis 3.0.7 仅支持 amd64;在 arm64 主机上启动时会单独提醒,Docker 将使用模拟运行。其余配方均支持 amd64 和 arm64。
|
||||||
|
|
||||||
Nacos 使用管理员用户名 `nacos`、密码 `123456` 和默认 `public` 命名空间。V3 配方额外在 `http://127.0.0.1:8010` 暴露 Web 控制台;V2 控制台使用主端口 `8849`。如需并行运行两个 Nacos 版本,请为其中一个版本设置 `NACOS_CONSOLE_PORT`、`NACOS_GRPC_PORT` 和 `NACOS_RAFT_PORT`。
|
Nacos 使用管理员用户名 `nacos`、密码 `123456` 和默认 `public` 命名空间。V2 的 HTTP、gRPC 和 Raft 宿主端口为 `11000`、`11001`、`11002`;V3 的 HTTP、Web 控制台、gRPC 和 Raft 宿主端口为 `11003`、`11004`、`11005`、`11006`。两个版本默认即可并行运行。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=8818 NACOS_CONSOLE_PORT=8010 NACOS_GRPC_PORT=9818 NACOS_RAFT_PORT=9819 make db DB=nacos@3.2
|
DB_PORT=11030 NACOS_CONSOLE_PORT=11031 NACOS_GRPC_PORT=11032 NACOS_RAFT_PORT=11033 make db DB=nacos@3.2
|
||||||
```
|
```
|
||||||
|
|
||||||
r-nacos 使用管理员账号 `admin` 和密码 `123456`。DBX 配方的 HTTP、gRPC 和 Web 控制台宿主端口默认分别为 `8849`、`9849`、`10849`;上游单机 Compose 使用 `8848:8848`、`9848:9848`、`10848:10848`。若需避开本机端口冲突,可使用以下自定义宿主端口映射(不是上游默认值):
|
r-nacos 使用管理员账号 `admin` 和密码 `123456`。DBX 配方的 HTTP、gRPC 和 Web 控制台宿主端口默认分别为 `11100`、`11101`、`11102`;上游单机 Compose 使用 `8848:8848`、`9848:9848`、`10848:10848`。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=3848 RNACOS_GRPC_PORT=3748 RNACOS_CONSOLE_PORT=3048 make db DB=rnacos@0.8
|
DB_PORT=11130 RNACOS_GRPC_PORT=11131 RNACOS_CONSOLE_PORT=11132 make db DB=rnacos@0.8
|
||||||
```
|
```
|
||||||
|
|
||||||
etcd 会创建密码为 `123456` 的 `root` 用户、授予 root 角色并开启认证。默认客户端和 peer 主机端口为 `2380`、`2381`。如需使用上游 Docker 命令中的端口,可执行:
|
etcd 会创建密码为 `123456` 的 `root` 用户、授予 root 角色并开启认证。默认客户端和 peer 主机端口为 `10700`、`10701`。如需使用上游 Docker 命令中的端口,可执行:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=2379 ETCD_PEER_PORT=2380 make db DB=etcd@3.7
|
DB_PORT=2379 ETCD_PEER_PORT=2380 make db DB=etcd@3.7
|
||||||
```
|
```
|
||||||
|
|
||||||
Qdrant 将 `123456` 作为管理员 API Key。在 DBX 中请将用户名留空,并把 API Key 填入密码字段,驱动会通过 HTTP 请求头 `api-key` 发送。HTTP 和 gRPC 默认主机端口分别为 `6334`、`6335`。如需使用上游 Docker 命令中的端口,可执行:
|
Qdrant 将 `123456` 作为管理员 API Key。在 DBX 中请将用户名留空,并把 API Key 填入密码字段,驱动会通过 HTTP 请求头 `api-key` 发送。HTTP 和 gRPC 默认主机端口分别为 `11200`、`11201`。如需使用上游 Docker 命令中的端口,可执行:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=6333 QDRANT_GRPC_PORT=6334 make db DB=qdrant@1.8
|
DB_PORT=6333 QDRANT_GRPC_PORT=6334 make db DB=qdrant@1.8
|
||||||
```
|
```
|
||||||
|
|
||||||
ZooKeeper 使用 Digest 凭据 `root` / `123456` 保护 `/dbx` 节点。默认主机端口为 `2182`;设置 `DB_PORT=2181` 即可匹配上游 Docker 命令。ZooKeeper 的 Digest ACL 模型保护单个节点,并不提供全局登录开关。
|
ZooKeeper 使用 Digest 凭据 `root` / `123456` 保护 `/dbx` 节点。默认主机端口为 `10800`;设置 `DB_PORT=2181` 即可匹配上游 Docker 命令。ZooKeeper 的 Digest ACL 模型保护单个节点,并不提供全局登录开关。
|
||||||
|
|
||||||
Kafka 和 Pulsar 均为刻意保持未认证的单节点开发配方:Kafka 使用 PLAINTEXT,Pulsar 使用 standalone,因此不要将它们暴露到远程网络。Kafka 如需使用常用端口,可执行 `DB_PORT=9092 make db DB=kafka@4.3`;Pulsar 使用常用端口可执行 `DB_PORT=6650 PULSAR_WEB_PORT=8080 make db DB=pulsar@4.2`。
|
Kafka 和 Pulsar 均为刻意保持未认证的单节点开发配方:Kafka 使用 PLAINTEXT,Pulsar 使用 standalone,因此不要将它们暴露到远程网络。Kafka 如需使用常用端口,可执行 `DB_PORT=9092 make db DB=kafka@4.3`;Pulsar 使用常用端口可执行 `DB_PORT=6650 PULSAR_WEB_PORT=8080 make db DB=pulsar@4.2`。
|
||||||
|
|
||||||
Redis 3.0.7 和 Redis 7.4.9 用于覆盖兼容性的两个端点。Redis 3 早于 ACL、RESP3、Streams 及许多现代命令,Redis 7 则覆盖当前协议与命令集。对这个实验室而言,同时保留 6.2 和 7.4 所提供的兼容性覆盖更小。
|
Redis 3.0.7 和 Redis 7.4.9 用于覆盖兼容性的两个端点。Redis 3 早于 ACL、RESP3、Streams 及许多现代命令,Redis 7 则覆盖当前协议与命令集。对这个实验室而言,同时保留 6.2 和 7.4 所提供的兼容性覆盖更小。
|
||||||
|
|
||||||
同一数据库的不同版本默认会共用宿主机端口。通常一次启动一个版本;需要并行对比时,为其中一个版本指定其他端口:
|
Consul 为单节点开发模式,使用 `agent -dev -client=0.0.0.0 -ui` 启动,不启用 ACL。HTTP API 与 UI、gRPC 和 DNS 的默认宿主端口分别为 `10900`、`10901` 和 `10902`;DNS 同时开放 TCP 和 UDP。以下命令可使用本地常用端口 `8500`、`8502` 和 `8600`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=13307 make db DB=mysql@5.7
|
DB_PORT=8500 CONSUL_GRPC_PORT=8502 CONSUL_DNS_PORT=8600 make db DB=consul@2.0.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Elasticsearch 6.8 以未认证的单节点开发集群运行,并禁用机器学习功能。HTTP API 和 transport 默认宿主端口为 `11500`、`11501`;以下命令可使用上游端口 `9200`、`9300`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DB_PORT=9200 ELASTICSEARCH_TRANSPORT_PORT=9300 make db DB=elasticsearch@6.8
|
||||||
|
```
|
||||||
|
|
||||||
|
所有已提交配方都有唯一的默认宿主端口分配,因此版本和产品可默认并行运行。仅在本地规范需要不同端口时使用 `DB_PORT`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DB_PORT=10150 make db DB=mysql@5.7
|
||||||
make db DB=mysql@8.4
|
make db DB=mysql@8.4
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -79,15 +93,17 @@ make db-list
|
|||||||
make db DB=postgresql@17.4
|
make db DB=postgresql@17.4
|
||||||
make db-verify DB=postgresql@17.4
|
make db-verify DB=postgresql@17.4
|
||||||
make db DB=rnacos@0.8
|
make db DB=rnacos@0.8
|
||||||
|
make db DB=consul@2.0.2
|
||||||
|
make db DB=elasticsearch@6.8
|
||||||
```
|
```
|
||||||
|
|
||||||
不带参数执行 `make db` 会输出当前全部支持的、可直接复制启动的命令,以及可选参数。传入 `DB=product@version` 后,`db` 会等待 Compose 健康检查通过并输出 DBX 连接字段。`db-verify` 还会在数据库容器中执行配方中的冒烟命令,并校验预期输出;提交数据库相关修复前推荐执行此命令。
|
不带参数执行 `make db` 会输出当前全部支持的、可直接复制启动的命令,以及可选参数。传入 `DB=product@version` 后,`db` 会等待 Compose 健康检查通过并输出 DBX 连接字段;对于 DBX 已支持的连接类型,还会输出预填完成的 `dbx://connection/new` 深链。复制该链接到浏览器或终端执行 `open '<链接>'`,即可打开桌面端的新建连接窗口。使用前请先安装并启动一次 DBX 桌面端以注册 `dbx://` 协议。深链可能包含密码,因此不要将其写入共享终端历史、日志或工单。尚未具备 DBX 连接类型的配方会明确显示深链不可用,例如 Consul、Nacos、Kafka、Pulsar 和 r-nacos。`db-verify` 还会在数据库容器中执行配方中的冒烟命令,并校验预期输出;提交数据库相关修复前推荐执行此命令。
|
||||||
|
|
||||||
## 命令和变量
|
## 命令和变量
|
||||||
|
|
||||||
| Make 目标 | 用途 |
|
| Make 目标 | 用途 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `make db-list` | 列出数据库版本、镜像和支持的平台 |
|
| `make db-list` | 列出数据库版本、容器到宿主机端口映射、镜像和支持的平台 |
|
||||||
| `make db DB=product@version` | 创建、等待环境就绪并输出连接字段 |
|
| `make db DB=product@version` | 创建、等待环境就绪并输出连接字段 |
|
||||||
| `make db-verify DB=product@version` | 启动并运行冒烟检查 |
|
| `make db-verify DB=product@version` | 启动并运行冒烟检查 |
|
||||||
| `make db-down DB=product@version` | 停止环境但保留数据卷 |
|
| `make db-down DB=product@version` | 停止环境但保留数据卷 |
|
||||||
|
|||||||
@@ -9,63 +9,77 @@ The Database Test Lab provides small, pinned Docker Compose environments for tes
|
|||||||
|
|
||||||
## Available recipes
|
## Available recipes
|
||||||
|
|
||||||
| Database | Version directory | Official Docker Hub image | CNB image used by Compose | Default host port | Container name |
|
| Database | Version directory | Official upstream image | CNB image used by Compose | Default host port | Container name |
|
||||||
| --- | --- | --- | --- | ---: | --- |
|
| --- | --- | --- | --- | ---: | --- |
|
||||||
| ClickHouse | `clickhouse/24.8` | `clickhouse/clickhouse-server:24.8.14.39` | `docker.cnb.cool/znb/images/clickhouse-server:24.8.14.39` | `8124` | `dbx-clickhouse-24.8` |
|
| ClickHouse | `clickhouse/24.8` | `clickhouse/clickhouse-server:24.8.14.39` | `docker.cnb.cool/znb/images/clickhouse-server:24.8.14.39` | `10600` | `dbx-clickhouse-24.8` |
|
||||||
| etcd | `etcd/3.7` | `gcr.io/etcd-development/etcd:v3.7.0` | `docker.cnb.cool/znb/images/etcd:v3.7.0` | `2380` | `dbx-etcd-3.7` |
|
| Consul | `consul/2.0.2` | `hashicorp/consul:2.0.2` | `docker.cnb.cool/znb/images/consul:2.0.2` | `10900` | `dbx-consul-2.0.2` |
|
||||||
| Kafka | `kafka/4.3` | `apache/kafka:4.3.1` | `docker.cnb.cool/znb/images/kafka:4.3.1` | `9093` | `dbx-kafka-4.3` |
|
| Elasticsearch | `elasticsearch/6.8` | `docker.elastic.co/elasticsearch/elasticsearch:6.8` | `docker.cnb.cool/znb/images/elasticsearch:6.8` | `11500` | `dbx-elasticsearch-6.8` |
|
||||||
| MariaDB | `mariadb/10.11` | `mariadb:10.11.11` | `docker.cnb.cool/znb/images/mariadb:10.11.11` | `3307` | `dbx-mariadb-10.11` |
|
| etcd | `etcd/3.7` | `gcr.io/etcd-development/etcd:v3.7.0` | `docker.cnb.cool/znb/images/etcd:v3.7.0` | `10700` | `dbx-etcd-3.7` |
|
||||||
| MongoDB | `mongodb/5.0` | `mongo:5.0.5` | `docker.cnb.cool/znb/images/mongo:5.0.5` | `27018` | `dbx-mongodb-5.0` |
|
| Kafka | `kafka/4.3` | `apache/kafka:4.3.1` | `docker.cnb.cool/znb/images/kafka:4.3.1` | `11300` | `dbx-kafka-4.3` |
|
||||||
| MongoDB | `mongodb/8.2` | `mongo:8.2.3-noble` | `docker.cnb.cool/znb/images/mongo:8.2.3-noble` | `27018` | `dbx-mongodb-8.2` |
|
| MariaDB | `mariadb/10.11` | `mariadb:10.11.11` | `docker.cnb.cool/znb/images/mariadb:10.11.11` | `10200` | `dbx-mariadb-10.11` |
|
||||||
| MySQL | `mysql/5.7` | `mysql:5.7.44` | `docker.cnb.cool/znb/images/mysql:5.7.44` | `3307` | `dbx-mysql-5.7` |
|
| MongoDB | `mongodb/5.0` | `mongo:5.0.5` | `docker.cnb.cool/znb/images/mongo:5.0.5` | `10400` | `dbx-mongodb-5.0` |
|
||||||
| MySQL | `mysql/8.4` | `mysql:8.4.6` | `docker.cnb.cool/znb/images/mysql:8.4.6` | `3307` | `dbx-mysql-8.4` |
|
| MongoDB | `mongodb/8.2` | `mongo:8.2.3-noble` | `docker.cnb.cool/znb/images/mongo:8.2.3-noble` | `10401` | `dbx-mongodb-8.2` |
|
||||||
| Nacos | `nacos/2.5` | `nacos/nacos-server:v2.5.2` | `docker.cnb.cool/znb/images/nacos-server:v2.5.2` | `8849` | `dbx-nacos-2.5` |
|
| MySQL | `mysql/5.7` | `mysql:5.7.44` | `docker.cnb.cool/znb/images/mysql:5.7.44` | `10100` | `dbx-mysql-5.7` |
|
||||||
| Nacos | `nacos/3.2` | `nacos/nacos-server:v3.2.2` | `docker.cnb.cool/znb/images/nacos-server:v3.2.2` | `8849` | `dbx-nacos-3.2` |
|
| MySQL | `mysql/8.4` | `mysql:8.4.6` | `docker.cnb.cool/znb/images/mysql:8.4.6` | `10101` | `dbx-mysql-8.4` |
|
||||||
| PostgreSQL | `postgresql/14.23` | `postgres:14.23` | `docker.cnb.cool/znb/images/postgres:14.23` | `5433` | `dbx-postgresql-14.23` |
|
| Nacos | `nacos/2.5` | `nacos/nacos-server:v2.5.2` | `docker.cnb.cool/znb/images/nacos-server:v2.5.2` | `11000` | `dbx-nacos-2.5` |
|
||||||
| PostgreSQL | `postgresql/17.4` | `postgres:17.4` | `docker.cnb.cool/znb/images/postgres:17.4` | `5433` | `dbx-postgresql-17.4` |
|
| Nacos | `nacos/3.2` | `nacos/nacos-server:v3.2.3` | `docker.cnb.cool/znb/images/nacos-server:v3.2.3` | `11003` | `dbx-nacos-3.2` |
|
||||||
| Pulsar | `pulsar/4.2` | `apachepulsar/pulsar:4.2.3` | `docker.cnb.cool/znb/images/pulsar:4.2.3` | `6651` | `dbx-pulsar-4.2` |
|
| PostgreSQL | `postgresql/14.23` | `postgres:14.23` | `docker.cnb.cool/znb/images/postgres:14.23` | `10300` | `dbx-postgresql-14.23` |
|
||||||
| Qdrant | `qdrant/1.8` | `qdrant/qdrant:v1.8.3` | `docker.cnb.cool/znb/images/qdrant:v1.8.3` | `6334` | `dbx-qdrant-1.8` |
|
| PostgreSQL | `postgresql/17.4` | `postgres:17.4` | `docker.cnb.cool/znb/images/postgres:17.4` | `10301` | `dbx-postgresql-17.4` |
|
||||||
| Redis | `redis/3.0.7` | `redis:3.0.7-alpine` | `docker.cnb.cool/znb/images/redis:3.0.7-alpine` | `6380` | `dbx-redis-3.0.7` |
|
| Pulsar | `pulsar/4.2` | `apachepulsar/pulsar:4.2.3` | `docker.cnb.cool/znb/images/pulsar:4.2.3` | `11400` | `dbx-pulsar-4.2` |
|
||||||
| Redis | `redis/7.4` | `redis:7.4.9-alpine` | `docker.cnb.cool/znb/images/redis:7.4.9-alpine` | `6380` | `dbx-redis-7.4` |
|
| Qdrant | `qdrant/1.8` | `qdrant/qdrant:v1.8.3` | `docker.cnb.cool/znb/images/qdrant:v1.8.3` | `11200` | `dbx-qdrant-1.8` |
|
||||||
| r-nacos | `rnacos/0.8` | `qingpan/rnacos:v0.8.5` | `docker.cnb.cool/znb/images/rnacos:v0.8.5` | `8849` | `dbx-rnacos-0.8` |
|
| Redis | `redis/3.0.7` | `redis:3.0.7-alpine` | `docker.cnb.cool/znb/images/redis:3.0.7-alpine` | `10500` | `dbx-redis-3.0.7` |
|
||||||
| ZooKeeper | `zookeeper/3.9` | `zookeeper:3.9.5` | `docker.cnb.cool/znb/images/zookeeper:3.9.5` | `2182` | `dbx-zookeeper-3.9` |
|
| Redis | `redis/7.4` | `redis:7.4.9-alpine` | `docker.cnb.cool/znb/images/redis:7.4.9-alpine` | `10501` | `dbx-redis-7.4` |
|
||||||
|
| r-nacos | `rnacos/0.8` | `qingpan/rnacos:v0.8.5` | `docker.cnb.cool/znb/images/rnacos:v0.8.5` | `11100` | `dbx-rnacos-0.8` |
|
||||||
|
| ZooKeeper | `zookeeper/3.9` | `zookeeper:3.9.5` | `docker.cnb.cool/znb/images/zookeeper:3.9.5` | `10800` | `dbx-zookeeper-3.9` |
|
||||||
|
|
||||||
Every network recipe uses a host port one greater than the database standard port, and the recipe validator enforces that contract. The default password is `123456`, and the default database is `dbx`. Redis has no named databases, so it uses DB 0 with a `dbx:` smoke-key prefix. Compose uses the CNB image column; the Docker Hub column preserves the official upstream reference for provenance and direct pulls. Redis 3.0.7 is amd64-only; on arm64 hosts the command prints an architecture warning and Docker uses emulation. Every other recipe supports both amd64 and arm64.
|
Each product uses a dedicated `101xx`-`115xx` host-port range, and the validator verifies that every declared default mapping is in the correct range and globally unique. The default password is `123456`, and the default database is `dbx`. Redis has no named databases, so it uses DB 0 with a `dbx:` smoke-key prefix. Compose uses the CNB image column; the official upstream image column preserves the original image reference for provenance and direct pulls. Redis 3.0.7 is amd64-only; on arm64 hosts the command prints an architecture warning and Docker uses emulation. Every other recipe supports both amd64 and arm64.
|
||||||
|
|
||||||
Nacos uses the `nacos` administrator, password `123456`, and its default `public` namespace. Its V3 recipe also exposes the web console at `http://127.0.0.1:8010`; V2 serves its console on the main `8849` port. Set `NACOS_CONSOLE_PORT`, `NACOS_GRPC_PORT`, and `NACOS_RAFT_PORT` when running an Nacos version alongside another one.
|
Nacos uses the `nacos` administrator, password `123456`, and its default `public` namespace. V2 uses HTTP, gRPC, and Raft host ports `11000`, `11001`, and `11002`; V3 uses HTTP `11003`, web console `11004`, gRPC `11005`, and Raft `11006`. The two versions can run together by default.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=8818 NACOS_CONSOLE_PORT=8010 NACOS_GRPC_PORT=9818 NACOS_RAFT_PORT=9819 make db DB=nacos@3.2
|
DB_PORT=11030 NACOS_CONSOLE_PORT=11031 NACOS_GRPC_PORT=11032 NACOS_RAFT_PORT=11033 make db DB=nacos@3.2
|
||||||
```
|
```
|
||||||
|
|
||||||
r-nacos uses the `admin` administrator and password `123456`. The DBX recipe defaults its HTTP, gRPC, and web-console host ports to `8849`, `9849`, and `10849`; the upstream standalone Compose file publishes `8848:8848`, `9848:9848`, and `10848:10848`. To avoid local port conflicts, use this custom host-port mapping (not the upstream defaults):
|
r-nacos uses the `admin` administrator and password `123456`. The DBX recipe defaults its HTTP, gRPC, and web-console host ports to `11100`, `11101`, and `11102`; the upstream standalone Compose file publishes `8848:8848`, `9848:9848`, and `10848:10848`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=3848 RNACOS_GRPC_PORT=3748 RNACOS_CONSOLE_PORT=3048 make db DB=rnacos@0.8
|
DB_PORT=11130 RNACOS_GRPC_PORT=11131 RNACOS_CONSOLE_PORT=11132 make db DB=rnacos@0.8
|
||||||
```
|
```
|
||||||
|
|
||||||
etcd creates the `root` user with password `123456`, grants the root role, then enables authentication. Its default client and peer ports are `2380` and `2381`. To use the upstream Docker command's ports, run:
|
etcd creates the `root` user with password `123456`, grants the root role, then enables authentication. Its default client and peer ports are `10700` and `10701`. To use the upstream Docker command's ports, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=2379 ETCD_PEER_PORT=2380 make db DB=etcd@3.7
|
DB_PORT=2379 ETCD_PEER_PORT=2380 make db DB=etcd@3.7
|
||||||
```
|
```
|
||||||
|
|
||||||
Qdrant uses `123456` as its administrator API key. In DBX, leave the username empty and enter the key as the password so the driver sends it in the `api-key` HTTP header. Its HTTP and gRPC ports default to `6334` and `6335`. To use the ports in the upstream Docker command, run:
|
Qdrant uses `123456` as its administrator API key. In DBX, leave the username empty and enter the key as the password so the driver sends it in the `api-key` HTTP header. Its HTTP and gRPC ports default to `11200` and `11201`. To use the ports in the upstream Docker command, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=6333 QDRANT_GRPC_PORT=6334 make db DB=qdrant@1.8
|
DB_PORT=6333 QDRANT_GRPC_PORT=6334 make db DB=qdrant@1.8
|
||||||
```
|
```
|
||||||
|
|
||||||
ZooKeeper uses Digest credentials `root` / `123456` to protect the `/dbx` node. Its default host port is `2182`; use `DB_PORT=2181` to match the upstream Docker command. ZooKeeper's Digest ACL model protects individual nodes rather than providing a global login switch.
|
ZooKeeper uses Digest credentials `root` / `123456` to protect the `/dbx` node. Its default host port is `10800`; use `DB_PORT=2181` to match the upstream Docker command. ZooKeeper's Digest ACL model protects individual nodes rather than providing a global login switch.
|
||||||
|
|
||||||
Kafka and Pulsar are deliberately unauthenticated single-node development recipes. Kafka uses PLAINTEXT and Pulsar uses standalone mode, so do not expose either service remotely. Use `DB_PORT=9092 make db DB=kafka@4.3` for Kafka's usual port, and `DB_PORT=6650 PULSAR_WEB_PORT=8080 make db DB=pulsar@4.2` for Pulsar's usual ports.
|
Kafka and Pulsar are deliberately unauthenticated single-node development recipes. Kafka uses PLAINTEXT and Pulsar uses standalone mode, so do not expose either service remotely. Use `DB_PORT=9092 make db DB=kafka@4.3` for Kafka's usual port, and `DB_PORT=6650 PULSAR_WEB_PORT=8080 make db DB=pulsar@4.2` for Pulsar's usual ports.
|
||||||
|
|
||||||
Redis 3.0.7 and Redis 7.4.9 intentionally cover the compatibility endpoints. Redis 3 predates ACLs, RESP3, Streams, and many modern commands, while Redis 7 covers the current protocol and command set. Keeping 6.2 and 7.4 together would provide less compatibility coverage for this lab.
|
Redis 3.0.7 and Redis 7.4.9 intentionally cover the compatibility endpoints. Redis 3 predates ACLs, RESP3, Streams, and many modern commands, while Redis 7 covers the current protocol and command set. Keeping 6.2 and 7.4 together would provide less compatibility coverage for this lab.
|
||||||
|
|
||||||
Versions of the same product intentionally share that default host port. Start them one at a time, or give one version another port when comparing versions concurrently:
|
Consul runs as a single-node development agent with `agent -dev -client=0.0.0.0 -ui` and no ACLs. Its HTTP API and UI, gRPC, and DNS host ports default to `10900`, `10901`, and `10902`; DNS is published over both TCP and UDP. Use the following command to match the usual local ports `8500`, `8502`, and `8600`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DB_PORT=13307 make db DB=mysql@5.7
|
DB_PORT=8500 CONSUL_GRPC_PORT=8502 CONSUL_DNS_PORT=8600 make db DB=consul@2.0.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Elasticsearch 6.8 runs as an unauthenticated single-node development cluster with machine-learning features disabled. Its HTTP API and transport host ports default to `11500` and `11501`; use the following command to match the upstream ports `9200` and `9300`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DB_PORT=9200 ELASTICSEARCH_TRANSPORT_PORT=9300 make db DB=elasticsearch@6.8
|
||||||
|
```
|
||||||
|
|
||||||
|
Every checked-in recipe has a unique default host-port allocation, so versions and products can run concurrently. Use `DB_PORT` only when a local policy requires a different host port:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DB_PORT=10150 make db DB=mysql@5.7
|
||||||
make db DB=mysql@8.4
|
make db DB=mysql@8.4
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -79,15 +93,17 @@ make db-list
|
|||||||
make db DB=postgresql@17.4
|
make db DB=postgresql@17.4
|
||||||
make db-verify DB=postgresql@17.4
|
make db-verify DB=postgresql@17.4
|
||||||
make db DB=rnacos@0.8
|
make db DB=rnacos@0.8
|
||||||
|
make db DB=consul@2.0.2
|
||||||
|
make db DB=elasticsearch@6.8
|
||||||
```
|
```
|
||||||
|
|
||||||
`make db` without parameters prints every currently supported copy-and-paste start command, plus optional parameters. With `DB=product@version`, it waits for the Compose health check and prints the DBX connection fields. `db-verify` also runs the recipe's smoke command inside the database container and checks its expected output. It is the preferred command before reporting a database-specific fix.
|
`make db` without parameters prints every currently supported copy-and-paste start command, plus optional parameters. With `DB=product@version`, it waits for the Compose health check and prints the DBX connection fields. For database types supported by DBX, it also prints a prefilled `dbx://connection/new` deep link. Copy the link into a browser or run `open '<link>'` to open the new-connection dialog in DBX Desktop. Install and open DBX Desktop once before use so the operating system registers the `dbx://` protocol. The deep link can contain a password, so do not save it in shared terminal history, logs, or tickets. Recipes without a compatible DBX connection type explicitly report that no deep link is available, including Consul, Nacos, Kafka, Pulsar, and r-nacos. `db-verify` also runs the recipe's smoke command inside the database container and checks its expected output. It is the preferred command before reporting a database-specific fix.
|
||||||
|
|
||||||
## Commands and variables
|
## Commands and variables
|
||||||
|
|
||||||
| Make target | Purpose |
|
| Make target | Purpose |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `make db-list` | List database versions, images, and supported platforms |
|
| `make db-list` | List database versions, container-to-host port mappings, images, and supported platforms |
|
||||||
| `make db DB=product@version` | Create, wait for, and print the connection fields |
|
| `make db DB=product@version` | Create, wait for, and print the connection fields |
|
||||||
| `make db-verify DB=product@version` | Start and run smoke checks |
|
| `make db-verify DB=product@version` | Start and run smoke checks |
|
||||||
| `make db-down DB=product@version` | Stop the environment while keeping its data volume |
|
| `make db-down DB=product@version` | Stop the environment while keeping its data volume |
|
||||||
|
|||||||
+167
-8
@@ -10,6 +10,35 @@ export const DEFAULT_RECIPES_ROOT = join(REPO_ROOT, 'deploy', 'database');
|
|||||||
const DEFAULT_MAKEFILE_PATH = join(REPO_ROOT, 'Makefile');
|
const DEFAULT_MAKEFILE_PATH = join(REPO_ROOT, 'Makefile');
|
||||||
const DEFAULT_PASSWORD = '123456';
|
const DEFAULT_PASSWORD = '123456';
|
||||||
const DEFAULT_DATABASE = 'dbx';
|
const DEFAULT_DATABASE = 'dbx';
|
||||||
|
const DEFAULT_HOST_PORT_RANGES = {
|
||||||
|
mysql: [10100, 10199],
|
||||||
|
mariadb: [10200, 10299],
|
||||||
|
postgresql: [10300, 10399],
|
||||||
|
mongodb: [10400, 10499],
|
||||||
|
redis: [10500, 10599],
|
||||||
|
clickhouse: [10600, 10699],
|
||||||
|
etcd: [10700, 10799],
|
||||||
|
zookeeper: [10800, 10899],
|
||||||
|
consul: [10900, 10999],
|
||||||
|
nacos: [11000, 11099],
|
||||||
|
rnacos: [11100, 11199],
|
||||||
|
qdrant: [11200, 11299],
|
||||||
|
kafka: [11300, 11399],
|
||||||
|
pulsar: [11400, 11499],
|
||||||
|
elasticsearch: [11500, 11599],
|
||||||
|
};
|
||||||
|
const DBX_DEEP_LINK_TYPES = {
|
||||||
|
clickhouse: 'clickhouse',
|
||||||
|
elasticsearch: 'elasticsearch',
|
||||||
|
etcd: 'etcd',
|
||||||
|
mariadb: 'mariadb',
|
||||||
|
mongodb: 'mongodb',
|
||||||
|
mysql: 'mysql',
|
||||||
|
postgresql: 'postgres',
|
||||||
|
qdrant: 'qdrant',
|
||||||
|
redis: 'redis',
|
||||||
|
zookeeper: 'zookeeper',
|
||||||
|
};
|
||||||
|
|
||||||
export function discoverRecipes(root = DEFAULT_RECIPES_ROOT) {
|
export function discoverRecipes(root = DEFAULT_RECIPES_ROOT) {
|
||||||
if (!existsSync(root)) return [];
|
if (!existsSync(root)) return [];
|
||||||
@@ -45,6 +74,22 @@ export function formatTable(headers, rows) {
|
|||||||
return [headers, ...rows].map(renderRow).join('\n');
|
return [headers, ...rows].map(renderRow).join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatBorderedTable(headers, rows, groupByFirstColumn = false) {
|
||||||
|
const widths = headers.map((header, index) => Math.max(
|
||||||
|
header.length,
|
||||||
|
...rows.map((row) => String(row[index] ?? '').length),
|
||||||
|
));
|
||||||
|
const border = `+${widths.map((width) => '-'.repeat(width + 2)).join('+')}+`;
|
||||||
|
const renderRow = (row) => `| ${row.map((value, index) => String(value ?? '').padEnd(widths[index])).join(' | ')} |`;
|
||||||
|
const body = [];
|
||||||
|
for (const [index, row] of rows.entries()) {
|
||||||
|
body.push(renderRow(row));
|
||||||
|
if (groupByFirstColumn && index < rows.length - 1 && rows[index + 1][0] !== '') body.push(border);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [border, renderRow(headers), border, ...body, border].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
export function discoverMakeTargets(makefilePath = DEFAULT_MAKEFILE_PATH) {
|
export function discoverMakeTargets(makefilePath = DEFAULT_MAKEFILE_PATH) {
|
||||||
if (!existsSync(makefilePath)) return [];
|
if (!existsSync(makefilePath)) return [];
|
||||||
const source = readFileSync(makefilePath, 'utf8').replace(/\\\r?\n/g, ' ');
|
const source = readFileSync(makefilePath, 'utf8').replace(/\\\r?\n/g, ' ');
|
||||||
@@ -119,18 +164,95 @@ export function expectedContainerName(recipe) {
|
|||||||
return `dbx-${recipe.database}-${recipe.displayVersion}`.toLowerCase().replace(/[^a-z0-9_.-]+/g, '-');
|
return `dbx-${recipe.database}-${recipe.displayVersion}`.toLowerCase().replace(/[^a-z0-9_.-]+/g, '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function defaultHostPortMappings(compose) {
|
||||||
|
const mappings = [];
|
||||||
|
const pattern = /^\s*-\s*["']?\$\{DB_BIND_ADDRESS:-127\.0\.0\.1\}:\$\{([A-Z][A-Z0-9_]*):-([0-9]+)\}:([0-9]+)(?:\/(tcp|udp))?["']?\s*$/;
|
||||||
|
for (const line of compose.split(/\r?\n/)) {
|
||||||
|
const match = line.match(pattern);
|
||||||
|
if (!match) continue;
|
||||||
|
mappings.push({ environment: match[1], hostPort: Number(match[2]), containerPort: Number(match[3]), protocol: match[4] || 'tcp' });
|
||||||
|
}
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recipePortMappings(recipe) {
|
||||||
|
const composePath = join(recipe.directory, 'compose.yaml');
|
||||||
|
if (!existsSync(composePath)) return '';
|
||||||
|
const mappings = defaultHostPortMappings(readFileSync(composePath, 'utf8')).sort((left, right) => (
|
||||||
|
left.hostPort - right.hostPort
|
||||||
|
|| left.containerPort - right.containerPort
|
||||||
|
|| left.protocol.localeCompare(right.protocol)
|
||||||
|
));
|
||||||
|
return mappings.map((mapping) => {
|
||||||
|
const sharesPortWithAnotherProtocol = mappings.some((candidate) => (
|
||||||
|
candidate !== mapping
|
||||||
|
&& candidate.containerPort === mapping.containerPort
|
||||||
|
&& candidate.hostPort === mapping.hostPort
|
||||||
|
&& candidate.protocol !== mapping.protocol
|
||||||
|
));
|
||||||
|
const sourcePort = sharesPortWithAnotherProtocol
|
||||||
|
? `${mapping.containerPort}/${mapping.protocol}`
|
||||||
|
: mapping.containerPort;
|
||||||
|
return `${sourcePort} -> ${mapping.hostPort}`;
|
||||||
|
}).join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function databaseListRows(recipes) {
|
||||||
|
let previousDatabase = null;
|
||||||
|
return recipes.map((recipe) => {
|
||||||
|
const database = recipe.database === previousDatabase ? '' : recipe.name;
|
||||||
|
previousDatabase = recipe.database;
|
||||||
|
return [database, recipe.displayVersion, recipePortMappings(recipe), recipe.image, recipe.platforms.join(',')];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateHostPorts(recipe) {
|
||||||
|
const errors = [];
|
||||||
|
const hostPorts = recipe.hostPorts;
|
||||||
|
if (!hostPorts || typeof hostPorts !== 'object' || Array.isArray(hostPorts)) return ['hostPorts must be a non-empty object'];
|
||||||
|
const entries = Object.entries(hostPorts);
|
||||||
|
if (entries.length === 0) return ['hostPorts must be a non-empty object'];
|
||||||
|
const [start, end] = DEFAULT_HOST_PORT_RANGES[recipe.database] ?? [];
|
||||||
|
if (!start) {
|
||||||
|
errors.push(`database ${recipe.database} has no allocated default host port range`);
|
||||||
|
}
|
||||||
|
for (const [environment, port] of entries) {
|
||||||
|
if (!/^[A-Z][A-Z0-9_]*$/.test(environment)) errors.push(`hostPorts key ${environment} must be an environment variable name`);
|
||||||
|
if (!Number.isInteger(port) || port < start || port > end) {
|
||||||
|
errors.push(`hostPorts.${environment} must be an integer in the ${start}-${end} range`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (new Set(entries.map(([, port]) => port)).size !== entries.length) errors.push('hostPorts must not reuse a port within a recipe');
|
||||||
|
if (recipe.connection?.port !== hostPorts.DB_PORT) errors.push('connection.port must match hostPorts.DB_PORT');
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateHostPortAllocation(recipes) {
|
||||||
|
const errors = [];
|
||||||
|
const owners = new Map();
|
||||||
|
for (const recipe of recipes) {
|
||||||
|
for (const [environment, port] of Object.entries(recipe.hostPorts ?? {})) {
|
||||||
|
if (!Number.isInteger(port)) continue;
|
||||||
|
const owner = `${recipeSelector(recipe)} (${environment})`;
|
||||||
|
const existing = owners.get(port);
|
||||||
|
if (existing) errors.push(`host port ${port} is allocated to both ${existing} and ${owner}`);
|
||||||
|
else owners.set(port, owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
export function validateRecipe(recipe) {
|
export function validateRecipe(recipe) {
|
||||||
const errors = [];
|
const errors = [];
|
||||||
for (const field of ['database', 'version', 'displayVersion', 'service', 'connection', 'smoke', 'shell', 'defaultPort']) {
|
for (const field of ['database', 'version', 'displayVersion', 'service', 'connection', 'hostPorts', 'smoke', 'shell', 'defaultPort']) {
|
||||||
if (recipe[field] === undefined) errors.push(`missing ${field}`);
|
if (recipe[field] === undefined) errors.push(`missing ${field}`);
|
||||||
}
|
}
|
||||||
if (!recipe.image || !/^[^\s]+:[^\s]+$/.test(recipe.image)) errors.push('image must be a pinned image reference');
|
if (!recipe.image || !/^[^\s]+:[^\s]+$/.test(recipe.image)) errors.push('image must be a pinned image reference');
|
||||||
if (recipe.connection?.host !== '127.0.0.1') errors.push('connection.host must be 127.0.0.1');
|
if (recipe.connection?.host !== '127.0.0.1') errors.push('connection.host must be 127.0.0.1');
|
||||||
if (!Number.isInteger(recipe.defaultPort) || recipe.defaultPort < 1 || recipe.defaultPort > 65534) {
|
if (!Number.isInteger(recipe.defaultPort) || recipe.defaultPort < 1 || recipe.defaultPort > 65534) {
|
||||||
errors.push('defaultPort must be an integer between 1 and 65534');
|
errors.push('defaultPort must be an integer between 1 and 65534');
|
||||||
} else if (recipe.connection?.port !== recipe.defaultPort + 1) {
|
|
||||||
errors.push('connection.port must be defaultPort + 1');
|
|
||||||
}
|
}
|
||||||
|
errors.push(...validateHostPorts(recipe));
|
||||||
if (recipe.connection?.authentication === 'none') {
|
if (recipe.connection?.authentication === 'none') {
|
||||||
if (recipe.connection.password !== undefined) errors.push('unauthenticated recipes must not declare connection.password');
|
if (recipe.connection.password !== undefined) errors.push('unauthenticated recipes must not declare connection.password');
|
||||||
} else if (recipe.connection?.password !== DEFAULT_PASSWORD) errors.push(`connection.password must be ${DEFAULT_PASSWORD}`);
|
} else if (recipe.connection?.password !== DEFAULT_PASSWORD) errors.push(`connection.password must be ${DEFAULT_PASSWORD}`);
|
||||||
@@ -162,8 +284,18 @@ export function validateRecipe(recipe) {
|
|||||||
errors.push('compose.yaml ports must default every mapping to 127.0.0.1 via DB_BIND_ADDRESS');
|
errors.push('compose.yaml ports must default every mapping to 127.0.0.1 via DB_BIND_ADDRESS');
|
||||||
}
|
}
|
||||||
if (!serviceHasNamedVolume(compose, recipe.service)) errors.push('target service must mount a named volume');
|
if (!serviceHasNamedVolume(compose, recipe.service)) errors.push('target service must mount a named volume');
|
||||||
if (!compose.includes(`\${DB_PORT:-${recipe.connection?.port}}:${recipe.defaultPort}`)) {
|
const portMappings = defaultHostPortMappings(compose);
|
||||||
errors.push('compose.yaml must default DB_PORT to connection.port and target defaultPort');
|
const mappedPorts = new Map();
|
||||||
|
for (const mapping of portMappings) {
|
||||||
|
const previousPort = mappedPorts.get(mapping.environment);
|
||||||
|
if (previousPort !== undefined && previousPort !== mapping.hostPort) {
|
||||||
|
errors.push(`compose.yaml uses conflicting defaults for ${mapping.environment}`);
|
||||||
|
}
|
||||||
|
mappedPorts.set(mapping.environment, mapping.hostPort);
|
||||||
|
}
|
||||||
|
const configuredPorts = Object.entries(recipe.hostPorts ?? {});
|
||||||
|
if (mappedPorts.size !== configuredPorts.length || configuredPorts.some(([environment, port]) => mappedPorts.get(environment) !== port)) {
|
||||||
|
errors.push('compose.yaml port defaults must match recipe hostPorts');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const initDirectory = join(recipe.directory, 'init');
|
const initDirectory = join(recipe.directory, 'init');
|
||||||
@@ -289,6 +421,24 @@ export function expandSmokeCommand(command, recipe, environment = process.env) {
|
|||||||
return command.map((value) => value.replace(/\$\{(DB_PASSWORD|DB_PORT)\}/g, (_, name) => values[name]));
|
return command.map((value) => value.replace(/\$\{(DB_PASSWORD|DB_PORT)\}/g, (_, name) => values[name]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function dbxConnectionDeepLink(recipe, environment = process.env) {
|
||||||
|
const type = DBX_DEEP_LINK_TYPES[recipe.database];
|
||||||
|
if (!type) return null;
|
||||||
|
|
||||||
|
const { connection } = recipe;
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
type,
|
||||||
|
name: `${recipe.name} ${recipe.version} (local)`,
|
||||||
|
host: connection.host,
|
||||||
|
port: environment.DB_PORT || String(connection.port),
|
||||||
|
database: String(connection.database),
|
||||||
|
});
|
||||||
|
if (connection.username) params.set('user', connection.username);
|
||||||
|
if (connection.password) params.set('password', environment.DB_PASSWORD || connection.password);
|
||||||
|
if (connection.urlParams) params.set('url_params', connection.urlParams);
|
||||||
|
return `dbx://connection/new?${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
function ensureBootstrap(recipe) {
|
function ensureBootstrap(recipe) {
|
||||||
if (!recipe.bootstrap) return;
|
if (!recipe.bootstrap) return;
|
||||||
// Keep one-shot setup synchronous after Compose health checks so --wait cannot return before credentials exist.
|
// Keep one-shot setup synchronous after Compose health checks so --wait cannot return before credentials exist.
|
||||||
@@ -310,6 +460,9 @@ function printConnection(recipe) {
|
|||||||
if (process.env.DB_PASSWORD) connection.password = process.env.DB_PASSWORD;
|
if (process.env.DB_PASSWORD) connection.password = process.env.DB_PASSWORD;
|
||||||
console.log(`${recipe.name} (${recipe.version})`);
|
console.log(`${recipe.name} (${recipe.version})`);
|
||||||
for (const [key, value] of Object.entries(connection)) console.log(`${key}: ${value}`);
|
for (const [key, value] of Object.entries(connection)) console.log(`${key}: ${value}`);
|
||||||
|
const deepLink = dbxConnectionDeepLink(recipe);
|
||||||
|
if (deepLink) console.log(`DBX connection link: ${deepLink}`);
|
||||||
|
else console.log(`DBX connection link: unavailable (DBX has no compatible ${recipe.name} connection type)`);
|
||||||
if (recipe.notes) console.log(`notes: ${recipe.notes}`);
|
if (recipe.notes) console.log(`notes: ${recipe.notes}`);
|
||||||
const warning = architectureWarning(recipe);
|
const warning = architectureWarning(recipe);
|
||||||
if (warning) console.warn(`warning: ${warning}`);
|
if (warning) console.warn(`warning: ${warning}`);
|
||||||
@@ -317,6 +470,11 @@ function printConnection(recipe) {
|
|||||||
|
|
||||||
function checkRecipes(recipes) {
|
function checkRecipes(recipes) {
|
||||||
let failed = false;
|
let failed = false;
|
||||||
|
const allocationErrors = validateHostPortAllocation(recipes);
|
||||||
|
if (allocationErrors.length > 0) {
|
||||||
|
failed = true;
|
||||||
|
for (const error of allocationErrors) console.error(`FAIL host port allocation: ${error}`);
|
||||||
|
}
|
||||||
for (const recipe of recipes) {
|
for (const recipe of recipes) {
|
||||||
const errors = validateRecipe(recipe);
|
const errors = validateRecipe(recipe);
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
@@ -368,9 +526,10 @@ export function main(argv = process.argv.slice(2)) {
|
|||||||
const recipes = discoverRecipes();
|
const recipes = discoverRecipes();
|
||||||
|
|
||||||
if (command === 'list') {
|
if (command === 'list') {
|
||||||
console.log(formatTable(
|
console.log(formatBorderedTable(
|
||||||
['DATABASE', 'VERSION', 'IMAGE', 'PLATFORMS'],
|
['DATABASE', 'VERSION', 'PORTS (CONTAINER -> HOST)', 'IMAGE', 'PLATFORMS'],
|
||||||
recipes.map((recipe) => [recipe.database, recipe.displayVersion, recipe.image, recipe.platforms.join(',')]),
|
databaseListRows(recipes),
|
||||||
|
true,
|
||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,19 +4,20 @@ import { mkdtempSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import { tmpdir } from 'node:os';
|
import { tmpdir } from 'node:os';
|
||||||
import { spawnSync } from 'node:child_process';
|
import { spawnSync } from 'node:child_process';
|
||||||
import { DEFAULT_RECIPES_ROOT, allPortMappingsDefaultToLoopback, architectureWarning, assertResetConfirmed, discoverMakeTargets, discoverRecipes, expandSmokeCommand, expectedContainerName, formatTable, parseDatabaseSelection, platformForArchitecture, recipeSelector, resolveRecipe, serviceHasNamedVolume, validateRecipe, validateRenderedCompose } from './database-env.mjs';
|
import { DEFAULT_RECIPES_ROOT, allPortMappingsDefaultToLoopback, architectureWarning, assertResetConfirmed, databaseListRows, dbxConnectionDeepLink, defaultHostPortMappings, discoverMakeTargets, discoverRecipes, expandSmokeCommand, expectedContainerName, formatBorderedTable, formatTable, parseDatabaseSelection, platformForArchitecture, recipeSelector, resolveRecipe, serviceHasNamedVolume, validateHostPortAllocation, validateRecipe, validateRenderedCompose } from './database-env.mjs';
|
||||||
|
|
||||||
const bashAvailable = spawnSync('bash', ['--version'], { stdio: 'ignore' }).status === 0;
|
const bashAvailable = spawnSync('bash', ['--version'], { stdio: 'ignore' }).status === 0;
|
||||||
const zshAvailable = spawnSync('zsh', ['--version'], { stdio: 'ignore' }).status === 0;
|
const zshAvailable = spawnSync('zsh', ['--version'], { stdio: 'ignore' }).status === 0;
|
||||||
const dockerComposeAvailable = spawnSync('docker', ['compose', 'version'], { stdio: 'ignore' }).status === 0;
|
const dockerComposeAvailable = spawnSync('docker', ['compose', 'version'], { stdio: 'ignore' }).status === 0;
|
||||||
|
|
||||||
function fixture(database, version) {
|
function fixture(database, version) {
|
||||||
|
const hostPort = { mysql: 10100, postgresql: 10300, redis: 10500 }[database] ?? 10100;
|
||||||
const root = mkdtempSync(join(tmpdir(), 'dbx-db-env-'));
|
const root = mkdtempSync(join(tmpdir(), 'dbx-db-env-'));
|
||||||
const directory = join(root, database, version);
|
const directory = join(root, database, version);
|
||||||
mkdirSync(join(directory, 'init'), { recursive: true });
|
mkdirSync(join(directory, 'init'), { recursive: true });
|
||||||
writeFileSync(join(directory, 'init', '001-smoke.txt'), 'fixture initialization');
|
writeFileSync(join(directory, 'init', '001-smoke.txt'), 'fixture initialization');
|
||||||
writeFileSync(join(directory, 'recipe.json'), JSON.stringify({ database, version, displayVersion: version, name: database, image: 'test:1', platforms: ['linux/amd64'], service: 'database', defaultPort: 1234, connection: { host: '127.0.0.1', port: 1235, password: '123456', database: database === 'redis' ? 0 : 'dbx' }, smoke: { steps: [{ name: 'smoke', command: ['true'], expect: 'true' }] }, shell: ['true'] }));
|
writeFileSync(join(directory, 'recipe.json'), JSON.stringify({ database, version, displayVersion: version, name: database, image: 'test:1', platforms: ['linux/amd64'], service: 'database', defaultPort: 1234, connection: { host: '127.0.0.1', port: hostPort, password: '123456', database: database === 'redis' ? 0 : 'dbx' }, hostPorts: { DB_PORT: hostPort }, smoke: { steps: [{ name: 'smoke', command: ['true'], expect: 'true' }] }, shell: ['true'] }));
|
||||||
writeFileSync(join(directory, 'compose.yaml'), `services:\n database:\n image: test:1\n platform: linux/amd64\n container_name: dbx-${database}-${version}\n ports:\n - "\${DB_BIND_ADDRESS:-127.0.0.1}:\${DB_PORT:-1235}:1234"\n volumes:\n - data:/var/lib/database\n healthcheck:\n test: ["CMD", "true"]\nvolumes:\n data:\n`);
|
writeFileSync(join(directory, 'compose.yaml'), `services:\n database:\n image: test:1\n platform: linux/amd64\n container_name: dbx-${database}-${version}\n ports:\n - "\${DB_BIND_ADDRESS:-127.0.0.1}:\${DB_PORT:-${hostPort}}:1234"\n volumes:\n - data:/var/lib/database\n healthcheck:\n test: ["CMD", "true"]\nvolumes:\n data:\n`);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +60,35 @@ test('formats lists as left-aligned tables with dynamic column widths', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('formats bordered tables with header and group separators', () => {
|
||||||
|
assert.equal(
|
||||||
|
formatBorderedTable(
|
||||||
|
['DATABASE', 'VERSION'],
|
||||||
|
[['MySQL', '5.7'], ['', '8.4'], ['PostgreSQL', '17.4']],
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
'+------------+---------+\n'
|
||||||
|
+ '| DATABASE | VERSION |\n'
|
||||||
|
+ '+------------+---------+\n'
|
||||||
|
+ '| MySQL | 5.7 |\n'
|
||||||
|
+ '| | 8.4 |\n'
|
||||||
|
+ '+------------+---------+\n'
|
||||||
|
+ '| PostgreSQL | 17.4 |\n'
|
||||||
|
+ '+------------+---------+',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('groups database versions and shows every container-to-host port mapping', () => {
|
||||||
|
const rows = databaseListRows(discoverRecipes());
|
||||||
|
const mysql57 = rows.find((row) => row[1] === '5.7');
|
||||||
|
const mysql84 = rows.find((row) => row[1] === '8.4');
|
||||||
|
const consul = rows.find((row) => row[0] === 'Consul');
|
||||||
|
|
||||||
|
assert.deepEqual(mysql57.slice(0, 3), ['MySQL', '5.7', '3306 -> 10100']);
|
||||||
|
assert.deepEqual(mysql84.slice(0, 3), ['', '8.4', '3306 -> 10101']);
|
||||||
|
assert.equal(consul[2], '8500 -> 10900, 8502 -> 10901, 8600/tcp -> 10902, 8600/udp -> 10902');
|
||||||
|
});
|
||||||
|
|
||||||
test('discovers all public Make targets for shell completion', () => {
|
test('discovers all public Make targets for shell completion', () => {
|
||||||
const targets = discoverMakeTargets();
|
const targets = discoverMakeTargets();
|
||||||
for (const target of ['help', 'build', 'test', 'docs', 'db', 'db-verify', 'db-completion']) {
|
for (const target of ['help', 'build', 'test', 'docs', 'db', 'db-verify', 'db-completion']) {
|
||||||
@@ -140,6 +170,8 @@ test('uses the approved CNB mirror images and matching recipe versions', () => {
|
|||||||
);
|
);
|
||||||
assert.deepEqual(recipes, {
|
assert.deepEqual(recipes, {
|
||||||
'clickhouse@24.8': { version: '24.8.14.39', image: 'docker.cnb.cool/znb/images/clickhouse-server:24.8.14.39', platforms: ['linux/amd64', 'linux/arm64'] },
|
'clickhouse@24.8': { version: '24.8.14.39', image: 'docker.cnb.cool/znb/images/clickhouse-server:24.8.14.39', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
|
'consul@2.0.2': { version: '2.0.2', image: 'docker.cnb.cool/znb/images/consul:2.0.2', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
|
'elasticsearch@6.8': { version: '6.8', image: 'docker.cnb.cool/znb/images/elasticsearch:6.8', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
'etcd@3.7': { version: '3.7.0', image: 'docker.cnb.cool/znb/images/etcd:v3.7.0', platforms: ['linux/amd64', 'linux/arm64'] },
|
'etcd@3.7': { version: '3.7.0', image: 'docker.cnb.cool/znb/images/etcd:v3.7.0', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
'kafka@4.3': { version: '4.3.1', image: 'docker.cnb.cool/znb/images/kafka:4.3.1', platforms: ['linux/amd64', 'linux/arm64'] },
|
'kafka@4.3': { version: '4.3.1', image: 'docker.cnb.cool/znb/images/kafka:4.3.1', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
'mariadb@10.11': { version: '10.11.11', image: 'docker.cnb.cool/znb/images/mariadb:10.11.11', platforms: ['linux/amd64', 'linux/arm64'] },
|
'mariadb@10.11': { version: '10.11.11', image: 'docker.cnb.cool/znb/images/mariadb:10.11.11', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
@@ -148,7 +180,7 @@ test('uses the approved CNB mirror images and matching recipe versions', () => {
|
|||||||
'mysql@5.7': { version: '5.7.44', image: 'docker.cnb.cool/znb/images/mysql:5.7.44', platforms: ['linux/amd64', 'linux/arm64'] },
|
'mysql@5.7': { version: '5.7.44', image: 'docker.cnb.cool/znb/images/mysql:5.7.44', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
'mysql@8.4': { version: '8.4.6', image: 'docker.cnb.cool/znb/images/mysql:8.4.6', platforms: ['linux/amd64', 'linux/arm64'] },
|
'mysql@8.4': { version: '8.4.6', image: 'docker.cnb.cool/znb/images/mysql:8.4.6', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
'nacos@2.5': { version: '2.5.2', image: 'docker.cnb.cool/znb/images/nacos-server:v2.5.2', platforms: ['linux/amd64', 'linux/arm64'] },
|
'nacos@2.5': { version: '2.5.2', image: 'docker.cnb.cool/znb/images/nacos-server:v2.5.2', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
'nacos@3.2': { version: '3.2.2', image: 'docker.cnb.cool/znb/images/nacos-server:v3.2.2', platforms: ['linux/amd64', 'linux/arm64'] },
|
'nacos@3.2': { version: '3.2.3', image: 'docker.cnb.cool/znb/images/nacos-server:v3.2.3', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
'postgresql@14.23': { version: '14.23', image: 'docker.cnb.cool/znb/images/postgres:14.23', platforms: ['linux/amd64', 'linux/arm64'] },
|
'postgresql@14.23': { version: '14.23', image: 'docker.cnb.cool/znb/images/postgres:14.23', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
'postgresql@17.4': { version: '17.4', image: 'docker.cnb.cool/znb/images/postgres:17.4', platforms: ['linux/amd64', 'linux/arm64'] },
|
'postgresql@17.4': { version: '17.4', image: 'docker.cnb.cool/znb/images/postgres:17.4', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
'pulsar@4.2': { version: '4.2.3', image: 'docker.cnb.cool/znb/images/pulsar:4.2.3', platforms: ['linux/amd64', 'linux/arm64'] },
|
'pulsar@4.2': { version: '4.2.3', image: 'docker.cnb.cool/znb/images/pulsar:4.2.3', platforms: ['linux/amd64', 'linux/arm64'] },
|
||||||
@@ -181,8 +213,8 @@ test('configures r-nacos with its admin account and console port', () => {
|
|||||||
const recipe = discoverRecipes().find((item) => recipeSelector(item) === 'rnacos@0.8');
|
const recipe = discoverRecipes().find((item) => recipeSelector(item) === 'rnacos@0.8');
|
||||||
assert.equal(recipe.connection.username, 'admin');
|
assert.equal(recipe.connection.username, 'admin');
|
||||||
assert.equal(recipe.connection.password, '123456');
|
assert.equal(recipe.connection.password, '123456');
|
||||||
assert.equal(recipe.connection.grpcPort, 9849);
|
assert.equal(recipe.connection.grpcPort, 11101);
|
||||||
assert.equal(recipe.connection.consolePort, 10849);
|
assert.equal(recipe.connection.consolePort, 11102);
|
||||||
|
|
||||||
const compose = readFileSync(join(recipe.directory, 'compose.yaml'), 'utf8');
|
const compose = readFileSync(join(recipe.directory, 'compose.yaml'), 'utf8');
|
||||||
assert.match(compose, /RNACOS_CONSOLE_PORT/);
|
assert.match(compose, /RNACOS_CONSOLE_PORT/);
|
||||||
@@ -257,6 +289,46 @@ test('smoke commands use password and port overrides without invoking a shell',
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('generates DBX deep links from effective recipe connection values', () => {
|
||||||
|
const recipe = discoverRecipes().find((item) => recipeSelector(item) === 'postgresql@17.4');
|
||||||
|
assert.ok(recipe);
|
||||||
|
|
||||||
|
const link = dbxConnectionDeepLink(recipe, { DB_PORT: '15433', DB_PASSWORD: 'p@ss & word' });
|
||||||
|
assert.ok(link);
|
||||||
|
const params = new URL(link).searchParams;
|
||||||
|
assert.equal(params.get('type'), 'postgres');
|
||||||
|
assert.equal(params.get('name'), 'PostgreSQL 17.4 (local)');
|
||||||
|
assert.equal(params.get('host'), '127.0.0.1');
|
||||||
|
assert.equal(params.get('port'), '15433');
|
||||||
|
assert.equal(params.get('user'), 'postgres');
|
||||||
|
assert.equal(params.get('password'), 'p@ss & word');
|
||||||
|
assert.equal(params.get('database'), 'dbx');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('prints a DBX deep link only for compatible connection types', () => {
|
||||||
|
const repoRoot = join(DEFAULT_RECIPES_ROOT, '..', '..');
|
||||||
|
const postgres = spawnSync(process.execPath, ['scripts/database-env.mjs', 'info', 'postgresql', '17.4'], {
|
||||||
|
cwd: repoRoot,
|
||||||
|
encoding: 'utf8',
|
||||||
|
});
|
||||||
|
assert.equal(postgres.status, 0, postgres.stderr);
|
||||||
|
assert.match(postgres.stdout, /DBX connection link: dbx:\/\/connection\/new\?type=postgres&/);
|
||||||
|
|
||||||
|
const elasticsearch = spawnSync(process.execPath, ['scripts/database-env.mjs', 'info', 'elasticsearch', '6.8'], {
|
||||||
|
cwd: repoRoot,
|
||||||
|
encoding: 'utf8',
|
||||||
|
});
|
||||||
|
assert.equal(elasticsearch.status, 0, elasticsearch.stderr);
|
||||||
|
assert.match(elasticsearch.stdout, /DBX connection link: dbx:\/\/connection\/new\?type=elasticsearch&/);
|
||||||
|
|
||||||
|
const consul = spawnSync(process.execPath, ['scripts/database-env.mjs', 'info', 'consul', '2.0.2'], {
|
||||||
|
cwd: repoRoot,
|
||||||
|
encoding: 'utf8',
|
||||||
|
});
|
||||||
|
assert.equal(consul.status, 0, consul.stderr);
|
||||||
|
assert.match(consul.stdout, /DBX connection link: unavailable \(DBX has no compatible Consul connection type\)/);
|
||||||
|
});
|
||||||
|
|
||||||
test('MongoDB commands pass reserved-character passwords as a distinct argument', () => {
|
test('MongoDB commands pass reserved-character passwords as a distinct argument', () => {
|
||||||
const password = 'p@ss/word#with?reserved&characters';
|
const password = 'p@ss/word#with?reserved&characters';
|
||||||
for (const recipe of discoverRecipes().filter((item) => item.database === 'mongodb')) {
|
for (const recipe of discoverRecipes().filter((item) => item.database === 'mongodb')) {
|
||||||
@@ -355,10 +427,35 @@ test('allows recipes that explicitly declare no authentication', () => {
|
|||||||
assert.deepEqual(validateRecipe(recipe), []);
|
assert.deepEqual(validateRecipe(recipe), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('requires every recipe port to be one greater than its database default port', () => {
|
test('requires the primary connection port to match the allocated DB_PORT', () => {
|
||||||
const [recipe] = discoverRecipes(fixture('postgresql', '17.4'));
|
const [recipe] = discoverRecipes(fixture('postgresql', '17.4'));
|
||||||
recipe.connection.port = 5432;
|
recipe.connection.port = 10301;
|
||||||
assert.match(validateRecipe(recipe).join('; '), /connection.port must be defaultPort \+ 1/);
|
assert.match(validateRecipe(recipe).join('; '), /connection.port must match hostPorts.DB_PORT/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('requires Compose port defaults to match the declared host-port allocation', () => {
|
||||||
|
const [recipe] = discoverRecipes(fixture('postgresql', '17.4'));
|
||||||
|
const composePath = join(recipe.directory, 'compose.yaml');
|
||||||
|
writeFileSync(composePath, readFileSync(composePath, 'utf8').replace('DB_PORT:-10300', 'DB_PORT:-10301'));
|
||||||
|
assert.match(validateRecipe(recipe).join('; '), /compose.yaml port defaults must match recipe hostPorts/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('allocates unique default host ports across checked-in recipes', () => {
|
||||||
|
const recipes = discoverRecipes();
|
||||||
|
assert.deepEqual(validateHostPortAllocation(recipes), []);
|
||||||
|
const duplicate = structuredClone(recipes[0]);
|
||||||
|
duplicate.hostPorts = { DB_PORT: recipes[1].hostPorts.DB_PORT };
|
||||||
|
assert.match(validateHostPortAllocation([recipes[1], duplicate]).join('; '), /host port .* is allocated to both/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parses every declared default host-port mapping, including shared UDP and TCP DNS', () => {
|
||||||
|
const consul = discoverRecipes().find((recipe) => recipeSelector(recipe) === 'consul@2.0.2');
|
||||||
|
assert.ok(consul);
|
||||||
|
const mappings = defaultHostPortMappings(readFileSync(join(consul.directory, 'compose.yaml'), 'utf8'));
|
||||||
|
assert.deepEqual(mappings.filter((mapping) => mapping.environment === 'CONSUL_DNS_PORT'), [
|
||||||
|
{ environment: 'CONSUL_DNS_PORT', hostPort: 10902, containerPort: 8600, protocol: 'tcp' },
|
||||||
|
{ environment: 'CONSUL_DNS_PORT', hostPort: 10902, containerPort: 8600, protocol: 'udp' },
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('reports missing smoke structures without throwing a TypeError', () => {
|
test('reports missing smoke structures without throwing a TypeError', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user