Apache AsterixDB 0.9.9 Docker Compose 部署指南
Apache AsterixDB 0.9.9 Docker Compose 部署指南:自建 asterixdb:0.9.9 镜像(ubuntu:22.04 加 OpenJDK 11 基础)并以 Compose 编排 NCService 与 CC 双服务,挂载 cc.conf 与数据目录,端口 19001/19002 映射,JVM 堆 256-512MB,含优雅停机与数据持久化实测
Apache AsterixDB 0.9.9 Docker Compose 部署指南
目标:使用 Docker Compose 编排 Apache AsterixDB 0.9.9 的 NCService 与 Cluster Controller 两个服务,通过自建镜像注入官方发行包、挂载 cc.conf 与数据目录,实现「一条 docker compose 命令拉起 AsterixDB 集群」。端口 19001/19002 映射到宿主机,JVM 堆限定 256-512MB,含优雅停机与数据持久化的实测结论。全程命令与回显均为实际执行结果。
一、环境信息
- Docker:29.8.0(本文实测环境)
- Docker Compose:v5.5.1(
docker compose version实测) - AsterixDB 镜像:自建
asterixdb:0.9.9(基础ubuntu:22.04,内含 OpenJDK 11 与官方发行包asterix-server-0.9.9-binary-assembly.zip) - 服务:asterixdb-nc(NCService 看护进程,NC 由它拉起)与 asterixdb-cc(Cluster Controller)共两个服务
- 映射端口:19001(Web 控制台)、19002(HTTP API / 查询服务)
- 配置挂载:
./conf/cc.conf→ CC 容器/opt/asterixdb/conf/cc.conf - 数据挂载:
./data/nc1→ NC 容器/opt/asterixdb/data(事务日志与存储设备落盘宿主机) - 运行用户:root
💡 说明:AsterixDB 的 NC 与 CC 是两个独立 Java 进程,本文拆成两个服务分别托管;NC 进程由 NCService 拉起,所以 NC 服务的主进程是
asterixncservice而不是asterixnc。
二、镜像选型说明
| 镜像 | 基础 | 说明 |
|---|---|---|
asterixdb:0.9.9(自建,本文采用) | ubuntu:22.04 | 把官方 zip 发行包打进镜像,装 OpenJDK 11,版本与二进制部署完全一致,便于离线交付与留档 |
选型说明:Docker Hub 上没有 Apache 官方发布的 AsterixDB 镜像(官方仅提供 zip/tarball 发行包),所以 Compose 路线必须自建镜像。自建的基础镜像选
ubuntu:22.04+openjdk-11-jdk-headless,与《Apache AsterixDB 0.9.9 安装指南》的系统与 JDK 组合保持一致,行为可对照。
三、前置条件
- 装有 Docker 与 Docker Compose v2 的服务器,root 权限。
- 已从官方下载站取得
asterix-server-0.9.9-binary-assembly.zip(约 223MB;下载与 sha512 校验方式见《Apache AsterixDB 0.9.9 安装指南》4.2 节,本文不再重复校验输出)。 - 宿主机 19001、19002 端口空闲(
ss -tlnp | grep -E '19001|19002'应无输出)。
四、部署步骤
4.1 创建目录结构
mkdir -p asterixdb-compose/conf asterixdb-compose/data/nc1 asterixdb-compose/logs/nc1 asterixdb-compose/logs/cc
cd asterixdb-compose
cp /opt/asterix-server-0.9.9-binary-assembly.zip .
ls -l
-rw-r--r-- 1 root root 232931001 Mar 5 2024 asterix-server-0.9.9-binary-assembly.zip
drwxr-xr-x 2 root root 4096 conf
drwxr-xr-x 3 root root 4096 data
drwxr-xr-x 4 root root 4096 logs
4.2 编写 Dockerfile 并构建镜像
cat > Dockerfile <<'EOF'
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y --no-install-recommends openjdk-11-jdk-headless unzip procps && \
rm -rf /var/lib/apt/lists/*
COPY asterix-server-0.9.9-binary-assembly.zip /tmp/
RUN unzip -q /tmp/asterix-server-0.9.9-binary-assembly.zip -d /opt && \
mv /opt/apache-asterixdb-0.9.9 /opt/asterixdb && \
rm -f /tmp/asterix-server-0.9.9-binary-assembly.zip && \
mkdir -p /opt/asterixdb/conf /opt/asterixdb/logs \
/opt/asterixdb/data/txnlog /opt/asterixdb/data/coredump /opt/asterixdb/data/iodevice
WORKDIR /opt/asterixdb
EOF
| 指令 | 说明 |
|---|---|
FROM ubuntu:22.04 | 与二进制部署同一系统基线 |
openjdk-11-jdk-headless | 含 jps(procps 顺带补齐 ps 工具),方便容器内验证 JVM 堆 |
COPY asterix-server-0.9.9-binary-assembly.zip /tmp/ | 把已下载好的发行包带进构建(比构建期 wget 稳,离线也能构建) |
mkdir -p | 预建 conf/logs/data 目录,避免运行期权限与路径问题 |
| 不写 CMD | 启动命令由 compose 的 command: 指定,NC 与 CC 各自不同 |
构建镜像:
docker compose build asterixdb-nc
Image asterixdb:0.9.9 Built
docker images asterixdb
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
asterixdb:0.9.9 5df64bc94df8 1.52GB 646MB U
解读:NC 服务在 compose 里写了
build: .,build 一次两个服务共用同一镜像asterixdb:0.9.9;DISK USAGE 1.52GB 为镜像占用磁盘(含 JDK 与发行包解压层),CONTENT SIZE 646MB 为镜像内容大小;镜像 ID 每次构建不同,以本机输出为准。
4.3 编写 cc.conf(Compose 版)
创建挂载用的集群配置 conf/cc.conf,与单机版的差异是节点与 CC 之间改用服务名互相寻址:
cat > conf/cc.conf <<'EOF'
[nc/nc1]
address=nc1
txn.log.dir=/opt/asterixdb/data/txnlog
core.dump.dir=/opt/asterixdb/data/coredump
iodevices=/opt/asterixdb/data/iodevice
nc.api.port=19004
jvm.args=-Xms256m -Xmx512m
[nc]
command=asterixnc
cluster.address=cc
cluster.port=1099
[cc]
address=cc
api.port=19002
web.port=19001
[common]
log.dir=/opt/asterixdb/logs
log.level=INFO
EOF
逐项说明:
| 段/参数 | 本文取值 | 说明 |
|---|---|---|
[nc/nc1] address | nc1 | NC 容器的主机名,与 4.4 的 hostname: nc1 对应 |
jvm.args | -Xms256m -Xmx512m | NCDriver 的 JVM 堆入口(NC 侧不走环境变量) |
[nc] cluster.address | cc | NC 反向连接 CC 的地址,即 CC 服务的主机名 |
[cc] address | cc | CC 绑定地址,容器网络内以服务名寻址 |
api.port / web.port | 19002 / 19001 | HTTP API 与 Web 控制台端口 |
⚠️ Compose 版的 NC 不需要
-Djava.io.tmpdir:镜像内/tmp是可执行的普通目录(4.2 基于 ubuntu:22.04 构建),snappy 本地库可直接加载;真实服务器部署遇/tmpnoexec 时才需要补该参数。
4.4 编写 docker-compose.yml
cat > docker-compose.yml <<'EOF'
services:
asterixdb-nc:
build: .
image: asterixdb:0.9.9
container_name: asterixdb-nc
hostname: nc1
restart: unless-stopped
command: ["/bin/sh","-c","mkdir -p /opt/asterixdb/data/txnlog /opt/asterixdb/data/coredump /opt/asterixdb/data/iodevice && exec /opt/asterixdb/bin/asterixncservice -logdir /opt/asterixdb/logs"]
volumes:
- ./data/nc1:/opt/asterixdb/data
- ./logs/nc1:/opt/asterixdb/logs
asterixdb-cc:
image: asterixdb:0.9.9
container_name: asterixdb-cc
hostname: cc
restart: unless-stopped
depends_on:
- asterixdb-nc
ports:
- "19001:19001"
- "19002:19002"
environment:
JAVA_OPTS: "-Xms256m -Xmx512m"
command: ["/opt/asterixdb/bin/asterixcc","-config-file","/opt/asterixdb/conf/cc.conf"]
volumes:
- ./conf/cc.conf:/opt/asterixdb/conf/cc.conf
- ./logs/cc:/opt/asterixdb/logs
EOF
| 配置项 | 说明 |
|---|---|
hostname: nc1 / hostname: cc | 必须与 cc.conf 的 address=nc1、cluster.address=cc 对应,容器网络内按主机名互认 |
command(NC) | 先 mkdir -p 三个数据子目录再 exec asterixncservice;首次挂载空目录时保证路径存在 |
depends_on | 只保证 NC 服务先启动,CC 会经 9090 端口等 NCService 就绪 |
ports | 仅映射 19001/19002 到宿主机;NC 的 19004 在容器网络内部访问 |
JAVA_OPTS | CCDriver 的堆限制;NC 的堆在 cc.conf 的 jvm.args,不走这里 |
restart: unless-stopped | 主机重启后自动拉起(docker 服务在运行时) |
4.5 启动与状态确认
docker compose up -d
[+] Running 3/3
✔ Network asterixdb-compose_default Created
✔ Container asterixdb-nc Started
✔ Container asterixdb-cc Started
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
asterixdb-cc asterixdb:0.9.9 "/opt/asterixdb/bin/…" asterixdb-cc 8 minutes ago Up 8 minutes 0.0.0.0:19001-19002->19001-19002/tcp, [::]:19001-19002->19001-19002/tcp
asterixdb-nc asterixdb:0.9.9 "/bin/sh -c 'mkdir -…" asterixdb-nc 8 minutes ago Up 8 minutes
等待约 20 秒让 CC 拉起 NC 后,在 NC 容器内确认三个进程(NCService、NCDriver、Jps):
docker exec asterixdb-nc jps -l
1 org.apache.hyracks.control.nc.service.NCService
39 org.apache.hyracks.control.nc.NCDriver
40 jdk.jcmd/sun.tools.jps.Jps
4.6 服务验证
从宿主机提交 SQL++(走映射出的 19002):
curl -s http://localhost:19002/query/service --data-urlencode "statement=SELECT 1 AS num;"
{
"requestID": "783db011-218e-4c78-b0e0-673f5650a41e",
"signature": { "*": "*" },
"results": [ { "num": 1 } ],
"plans":{},
"status": "success",
"metrics": {
"elapsedTime": "43.446257ms",
"executionTime": "41.221847ms",
"compileTime": "11.75045ms",
"queueWaitTime": "0ns",
"resultCount": 1,
"resultSize": 13,
"processedObjects": 0
}
}
建域建表写入查询全流程(注意:shell 双引号内 JSON 的引号需转义):
curl -s http://localhost:19002/query/service --data-urlencode "statement=CREATE DATAVERSE compose_demo;" | grep -o '"status": "[a-z]*"'
curl -s http://localhost:19002/query/service --data-urlencode "statement=USE compose_demo; CREATE TYPE GreetingType AS { id: int, message: string };" | grep -o '"status": "[a-z]*"'
curl -s http://localhost:19002/query/service --data-urlencode "statement=USE compose_demo; CREATE DATASET Greetings(GreetingType) PRIMARY KEY id;" | grep -o '"status": "[a-z]*"'
curl -s http://localhost:19002/query/service --data-urlencode "statement=USE compose_demo; INSERT INTO Greetings ({\"id\":1,\"message\":\"Hello AsterixDB!\"});" | grep -o '"status": "[a-z]*"'
curl -s http://localhost:19002/query/service --data-urlencode "statement=SELECT * FROM compose_demo.Greetings;" | grep -o '"status": "[a-z]*"'
五条均返回 "status": "success"。版本接口与 Web 控制台(实测状态码):
curl -s -o /dev/null -w "admin_version:%{http_code}\n" http://localhost:19002/admin/version
curl -s -o /dev/null -w "web_console:%{http_code}\n" http://localhost:19001/
admin_version:200
web_console:200
浏览器访问 http://<宿主机IP>:19001/ 为 Web 控制台、http://<宿主机IP>:19002/admin/cluster 为集群状态 JSON。
确认两个服务的 JVM 堆实际生效值(验证 4.3 的 jvm.args 与 4.4 的 JAVA_OPTS 均已生效):
docker exec asterixdb-nc jps -v | grep NCDriver
docker exec asterixdb-cc jps -v | grep CCDriver
39 NCDriver -Xms256m -Xmx512m -XX:MaxGCPauseMillis=25000 -Dapp.name=asterixnc -Dapp.pid=39 -Dapp.repo=/opt/asterixdb/repo -Dapp.home=/opt/asterixdb -Dbasedir=/opt/asterixdb
1 CCDriver -Xms256m -Xmx512m -Dapp.name=asterixcc -Dapp.pid=1 -Dapp.repo=/opt/asterixdb/repo -Dapp.home=/opt/asterixdb -Dbasedir=/opt/asterixdb
NCDriver 的 -XX:MaxGCPauseMillis=25000 是 NCService 自动追加的 GC 参数,属正常现象。
五、数据持久化说明
| 数据 | 落盘位置 | 说明 |
|---|---|---|
| 事务日志与存储设备 | 宿主机 ./data/nc1/(txnlog、iodevice、coredump) | 数据集、索引与元数据全部在此,重启不丢 |
| NC 日志 | 宿主机 ./logs/nc1/ | NCService 转写的 NC 输出 |
| CC 日志 | 宿主机 ./logs/cc/ | CC 主日志 |
| cc.conf | 宿主机 ./conf/cc.conf | 单文件挂载进 CC 容器 |
持久化验证(实测):先用 asterixhelper 优雅停集群,再整套启动,compose_demo.Greetings 数据完整:
docker exec asterixdb-cc /opt/asterixdb/bin/asterixhelper shutdown_cluster_all
INFO: Attempting to shutdown cluster 127.0.0.1:19002...
INFO: Cluster 127.0.0.1:19002 accepted shutdown request.
约 30 秒后 CC 与 NC 进程退出;因 restart: unless-stopped 策略,两个容器会自动重新拉起,集群回到 ACTIVE 后查询验证:
curl -s http://localhost:19002/query/service --data-urlencode "statement=SELECT * FROM compose_demo.Greetings;" | grep -o '"status": "[a-z]*"\|"message": "[^"]*"'
"message": "Hello AsterixDB!"
"status": "success"
⚠️ 停止必须走
asterixhelper shutdown_cluster_all的优雅路径,不要用docker compose restart/stop直接停(原因与实测后果见「十一、常见问题」11.1、11.2)。
六、环境变量表
AsterixDB 无官方镜像,也就没有厂商约定的环境变量体系,行为由挂载的 cc.conf 与 command: 驱动。与运行相关的环境层面项如下:
| 环境变量 | 设置位置 | 本文取值 | 说明 |
|---|---|---|---|
JAVA_OPTS | asterixdb-cc 的 environment: | -Xms256m -Xmx512m | CCDriver 的 JVM 参数(堆)入口 |
JAVA_OPTS(NC 侧) | 不适用 | — | NC 的堆不走环境变量,走 cc.conf [nc/nc1] 的 jvm.args |
DEBIAN_FRONTEND=noninteractive | Dockerfile 构建期 | noninteractive | 仅构建时避免 apt 交互 |
💡 说明:这是 AsterixDB 部署最容易踩的差异点——CC 与 NC 的 JVM 堆入口不同(CC 环境变量、NC 配置文件),只改一边不会让另一边生效,改完务必用
docker exec <服务> jps -v双向复核。
七、配置参数说明
挂载的 conf/cc.conf 关键段(出厂语义与本文取值):
| 配置项 | 出厂默认语义 | 本文取值 | 说明 |
|---|---|---|---|
[nc/nc1] address | 未设 | nc1 | NC 主机名,与容器 hostname 对应 |
[nc/nc1] txn.log.dir 等 | 无 | /opt/asterixdb/data/... | 数据目录落在挂载卷内 |
[nc/nc1] nc.api.port | 19004 | 19004 | NC HTTP 管理端口(容器网络内部) |
[nc/nc1] jvm.args | 无 | -Xms256m -Xmx512m | NCDriver 堆限制 |
[nc] command | hyracksnc | asterixnc | NCService 拉起 NC 的命令名 |
[nc] cluster.address | 未设 | cc | NC 反连 CC 的主机名 |
[cc] address | 127.0.0.1 | cc | CC 绑定地址 |
[cc] api.port / web.port | 19002 / 19001 | 19002 / 19001 | 对外两个端口,已映射宿主机 |
[common] log.dir / log.level | logs / WARNING | /opt/asterixdb/logs / INFO | 日志目录(挂载卷)与级别 |
各参数的完整含义、默认值与更多可调项见《Apache AsterixDB 0.9.9 配置参数详解》。
八、配置文件挂载
本方案对 cc.conf 采用「单文件挂载」,数据与日志用「目录挂载」,要点如下:
- cc.conf 是唯一需要定制的文件,单文件挂载路径必须与容器内路径一字不差:
/opt/asterixdb/conf/cc.conf(CC 容器)。 - 修改宿主机
conf/cc.conf后需重启容器生效;因重启涉及停机安全,正确操作是先优雅停集群再重启(见 11.2),然后复核容器内文件已更新:
docker exec asterixdb-cc grep "log.level" /opt/asterixdb/conf/cc.conf
log.level=INFO
- NC 容器不挂载 cc.conf:NC 的节点参数(地址、存储路径、jvm.args)由 CC 从自己的 cc.conf 读取后经 9090 通道下发给 NCService,因此只需要 CC 侧一份配置文件。
九、等价 docker run
不用 Compose 时,以下两条 docker run 与本文 compose 等价(先建网络,再分别跑两个服务,NC 与 CC 命令各自独立列出)。
创建公共网络:
docker network create asterixdb-net
启动 NC 服务(主进程 NCService,挂载数据与日志目录):
docker run -d --name asterixdb-nc --hostname nc1 --network asterixdb-net \
--restart unless-stopped \
-v /root/asterixdb-compose/data/nc1:/opt/asterixdb/data \
-v /root/asterixdb-compose/logs/nc1:/opt/asterixdb/logs \
asterixdb:0.9.9 \
/bin/sh -c "mkdir -p /opt/asterixdb/data/txnlog /opt/asterixdb/data/coredump /opt/asterixdb/data/iodevice && exec /opt/asterixdb/bin/asterixncservice -logdir /opt/asterixdb/logs"
启动 CC 服务(挂载 cc.conf 与日志目录,注入 JAVA_OPTS,映射 19001/19002):
docker run -d --name asterixdb-cc --hostname cc --network asterixdb-net \
--restart unless-stopped \
-p 19001:19001 -p 19002:19002 \
-e JAVA_OPTS="-Xms256m -Xmx512m" \
-v /root/asterixdb-compose/conf/cc.conf:/opt/asterixdb/conf/cc.conf \
-v /root/asterixdb-compose/logs/cc:/opt/asterixdb/logs \
asterixdb:0.9.9 \
/opt/asterixdb/bin/asterixcc -config-file /opt/asterixdb/conf/cc.conf
验证方式与 4.5、4.6 完全一致(docker ps、jps -v、curl 19002)。
十、常用运维命令
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
asterixdb-cc asterixdb:0.9.9 "/opt/asterixdb/bin/…" asterixdb-cc 8 minutes ago Up 8 minutes 0.0.0.0:19001-19002->19001-19002/tcp, [::]:19001-19002->19001-19002/tcp
asterixdb-nc asterixdb:0.9.9 "/bin/sh -c 'mkdir -…" asterixdb-nc 8 minutes ago Up 8 minutes
| 命令 | 用途 |
|---|---|
docker compose ps | 两服务运行状态与端口映射 |
docker compose logs -f asterixdb-cc | 跟踪 CC 启动与运行日志(-f asterixdb-nc 同理) |
docker compose restart | 强制重启两服务(默认 10 秒宽限,有数据风险,见 11.2) |
docker compose stop / docker compose start | 停止 / 启动(停止同样建议先走 11.2 的优雅停集群) |
docker compose down | 停止并移除容器与网络(./data、./logs、./conf 保留,重建不丢数据) |
docker exec asterixdb-nc jps -v | 查 NC 进程与堆生效值 |
docker exec asterixdb-cc jps -v | 查 CC 进程与堆生效值 |
docker exec asterixdb-cc /opt/asterixdb/bin/asterixhelper get_cluster_state | 容器内查集群状态 |
集群级状态从宿主机侧验证最直接:
curl -s http://localhost:19002/admin/cluster | head -c 200
{"cc":{"configUri":"http://localhost:19002/admin/cluster/cc/config"
十一、常见问题
11.1 单独重启 NC 后集群 UNUSABLE / DOWN
现象:只重启 NC 服务(docker compose restart asterixdb-nc)后,宿主机查询先报连接拒绝,随后集群进入不可用状态(实测回显):
"msg": "ConnectException: Connection refused (Connection refused)"
"msg": "IllegalStateException: Cannot execute request, cluster is UNUSABLE"
容器内 asterixhelper get_cluster_state 显示:
INFO: Cluster 127.0.0.1:19002 is DOWN.
定位:CC 与 NC 的会话随 NC 容器重启而断裂,单独拉回 NC 不能让集群恢复注册状态。
解决:整套重启(docker compose restart),重启后等待约 45 秒再验证;恢复 ACTIVE 后按 11.2 核对数据完整性。
11.2 restart/stop 强杀导致元数据回滚、数据集丢失
现象:docker compose restart 后集群恢复 ACTIVE,但此前创建的数据集查询报错(实测回显):
"msg": "ASX1077: Cannot find dataset Greetings in dataverse compose_demo nor an alias with name Greetings (in line 1, at column 15)"
用元数据表核对,dataverse 还在、dataset 不在(实测):
curl -s http://localhost:19002/query/service --data-urlencode "statement=SELECT VALUE dv.DataverseName FROM Metadata.\`Dataverse\` dv;" | grep -o '"results": \[[^]]*\]'
"results": [ "Default", "Metadata", "compose_demo" ]
定位:docker compose restart/stop 默认只给 10 秒宽限,而 AsterixDB 优雅停机全程需 10-25 秒,超时后被强杀,事务日志尾部未落检查点的元数据变更在恢复时回滚(本次实测 dataverse 保留、后建的 dataset 丢失)。
解决:任何停止动作都先走优雅停集群,再处理容器:
docker exec asterixdb-cc /opt/asterixdb/bin/asterixhelper shutdown_cluster_all
sleep 30
docker compose ps
确认集群进程已退出后再执行 docker compose stop/down(此时主进程已退,不会触发强杀);restart: unless-stopped 会让容器自动拉起,属预期行为,数据经 4.6 的查询验证完整。
11.3 宿主机访问不到 NC 的 19004 端口
现象:宿主机 curl http://localhost:19004/ 连接失败,但集群一切正常。
定位:本文 compose 只把 CC 的 19001/19002 映射到宿主机(docker compose ps 的 PORTS 列可见),NC 的 19004(NC HTTP API)仅容器网络内部可达,这是刻意的最小暴露面设计。
解决:确需从宿主机访问 NC API 时,在 asterixdb-nc 服务下追加端口映射后整套重建:
ports:
- "19004:19004"
⚠️ 追加端口涉及容器重建(等效重启),务必按 11.2 先优雅停集群再操作。
十二、参考链接
- 官方下载页:https://downloads.apache.org/asterixdb/
- 0.9.9 NCService 部署文档:https://asterixdb.apache.org/docs/0.9.9/ncservice.html
- Compose 官方文档:https://docs.docker.com/compose/
- 源码仓库:https://github.com/apache/asterixdb