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 AsterixDBAsterixDB2026/10/13

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] addressnc1NC 容器的主机名,与 4.4 的 hostname: nc1 对应
jvm.args-Xms256m -Xmx512mNCDriver 的 JVM 堆入口(NC 侧不走环境变量)
[nc] cluster.addressccNC 反向连接 CC 的地址,即 CC 服务的主机名
[cc] addressccCC 绑定地址,容器网络内以服务名寻址
api.port / web.port19002 / 19001HTTP API 与 Web 控制台端口

⚠️ Compose 版的 NC 不需要 -Djava.io.tmpdir:镜像内 /tmp 是可执行的普通目录(4.2 基于 ubuntu:22.04 构建),snappy 本地库可直接加载;真实服务器部署遇 /tmp noexec 时才需要补该参数。

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_OPTSCCDriver 的堆限制;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_OPTSasterixdb-cc 的 environment:-Xms256m -Xmx512mCCDriver 的 JVM 参数(堆)入口
JAVA_OPTS(NC 侧)不适用—NC 的堆不走环境变量,走 cc.conf [nc/nc1] 的 jvm.args
DEBIAN_FRONTEND=noninteractiveDockerfile 构建期noninteractive仅构建时避免 apt 交互

💡 说明:这是 AsterixDB 部署最容易踩的差异点——CC 与 NC 的 JVM 堆入口不同(CC 环境变量、NC 配置文件),只改一边不会让另一边生效,改完务必用 docker exec <服务> jps -v 双向复核。

七、配置参数说明

挂载的 conf/cc.conf 关键段(出厂语义与本文取值):

配置项出厂默认语义本文取值说明
[nc/nc1] address未设nc1NC 主机名,与容器 hostname 对应
[nc/nc1] txn.log.dir 等无/opt/asterixdb/data/...数据目录落在挂载卷内
[nc/nc1] nc.api.port1900419004NC HTTP 管理端口(容器网络内部)
[nc/nc1] jvm.args无-Xms256m -Xmx512mNCDriver 堆限制
[nc] commandhyracksncasterixncNCService 拉起 NC 的命令名
[nc] cluster.address未设ccNC 反连 CC 的主机名
[cc] address127.0.0.1ccCC 绑定地址
[cc] api.port / web.port19002 / 1900119002 / 19001对外两个端口,已映射宿主机
[common] log.dir / log.levellogs / 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 先优雅停集群再操作。

十二、参考链接