$kernelink route --hydrate --safe

页面加载 /
跳到正文
auth://account/session

登录工作区

使用 Emlog 账户继续访问你的内容与互动记录。

忘记密码?

打开 Emlog 原生登录页

13.md
workspace / posts
~/posts/13.md 阅读中

Docker 部署人大金仓 KingbaseES:license、数据目录和启动排障

人大金仓(KingbaseES)的容器部署和 MySQL、Redis 那类镜像不太一样。镜像由厂商提供,里面带着授权文件,启动校验严格,出问题时日志又经常误导人。这篇把部署、license 挂载和"库起不来"的排查顺序讲清楚,路径以厂商镜像的实际布局为准。

一、镜像

金仓的镜像不挂在公共仓库,来源一般是两个:

  • 厂商给的镜像 tar 包,docker load -i kingbase-v8r6.tar 导入
  • 内部私有仓库,docker pull <仓库地址>/kingbase:v8r6

导入后确认:

docker images | grep -i kingbase

镜像名和 tag 按实际导入的写,后面的 compose 里统一用 kingbase:v8r6 举例。

二、目录规划

sudo mkdir -p /data/kingbase/{data,license}
宿主机路径 容器内路径 说明
/data/kingbase/data 数据目录 必须挂出来,容器重建不丢库
/data/kingbase/license/license.dat .../bin/license.dat 授权文件,建议单独挂载

容器内的安装目录不是统一的,先看一眼实际布局再写挂载路径:

docker run --rm --entrypoint ls kingbase:v8r6 /home/kingbase/install/kingbase

常见的几处:

  • 安装目录:/home/kingbase/install/kingbase
  • 授权文件:/home/kingbase/install/kingbase/bin/license.dat
  • 服务端程序:同目录下的 bin/kingbase、bin/sys_ctl、bin/ksql
  • 数据目录:由镜像或 entrypoint 决定,通常在 kingbase 用户主目录下

数据目录的属主要和容器里的 kingbase 用户对上:

docker run --rm --entrypoint id kingbase:v8r6 kingbase
sudo chown -R <输出的uid>:<输出的gid> /data/kingbase/data

三、启动

services:
  kingbase:
    image: kingbase:v8r6
    container_name: kingbase8
    restart: unless-stopped
    privileged: true
    environment:
      TZ: Asia/Shanghai
      DB_MODE: mysql
    ports:
      - "54321:54321"
    volumes:
      - /data/kingbase/data:/home/kingbase/data
      - /data/kingbase/license/license.dat:/home/kingbase/install/kingbase/bin/license.dat
    shm_size: 1gb

几点说明:

  1. DB_MODE 决定兼容模式(Oracle / MySQL / PG),建库前定好,后面改不了。用 MySQL 兼容模式就写 mysql。
  2. privileged 和 command: /usr/sbin/init:有的厂商镜像把完整系统打包进来,用 systemd 启动,这种镜像必须开特权模式。如果镜像是单进程启动的,这两项可以去掉,以 docker inspect 看到的 entrypoint 为准。
  3. shm_size 默认只有 64 MB,跑并发查询时容易报共享内存不足,给到 1 GB 比较稳。
  4. 端口映射写成 127.0.0.1:54321:54321 更安全,只给本机或反向代理访问。

四、license 的三个坑

金仓只在启动时校验授权,运行中的实例不会因为到期被踢出去,但下一次重启就起不来。这是它和普通数据库最不一样的地方。

坑一:license 在容器可写层里

不挂卷的时候,license 的实体在容器内的安装目录下。docker restart 能保住,docker rm 之后重建,就退回镜像里那份旧证。镜像里那份往往是打包时的临时授权,可能早就过期了。

所以 license 要单独挂出来:

    volumes:
      - /data/kingbase/license/license.dat:/home/kingbase/install/kingbase/bin/license.dat

坑二:挂载不能加 :ro

这个镜像的 entrypoint 启动时会对安装目录做 chown。挂载点设成只读,chown 直接失败:

chown: changing ownership of '/home/kingbase/install/kingbase/bin/license.dat': Read-only file system

随后服务起不来,报 sys_ctl: could not start server。所以 license 的挂载必须是可写的。

坑三:宿主机文件要先存在

如果宿主机上 license.dat 不存在,Docker 会把挂载点创建成一个目录,容器里的金仓读到目录,报错形态和"授权无效"完全不一样,很容易查错方向。

顺序必须是:

# 1. 先放文件
sudo cp license_xxx.dat /data/kingbase/license/license.dat
# 2. 改属主,和容器内 kingbase 用户一致
sudo chown <uid>:<gid> /data/kingbase/license/license.dat
chmod 640 /data/kingbase/license/license.dat
# 3. 再改 compose 挂载

改完挂载启动,容器内 entrypoint 那次 chown 会真的改掉宿主机文件的属主,这是 bind mount 共享 inode 的正常结果,不是事故。

五、初始化

多数厂商镜像的 entrypoint 会在数据目录为空时自动 initdb,已经有数据就跳过。手工初始化也可以,用 kingbase 用户执行:

docker exec -u kingbase kingbase8 \
  /home/kingbase/install/kingbase/bin/initdb \
  -D /home/kingbase/data -U SYSTEM --pwfile=/tmp/pw

-U 指定超级用户,后面所有连接都用这个用户名。--pwfile 里放初始密码,不要用 -W 交互输入,容器里没有终端。

注意 initdb 的字符集和兼容模式要和 DB_MODE 一致,建库之后再改,等于重建。

六、验证库到底起没起

这一步最容易被误导。sys_ctl 在 license 校验之前就把 pid 文件写出来了,所以日志里出现 server started,不代表库活着。判定存活只看这三条:

# 1. 进程状态,退出码为 0 才算
docker exec -u kingbase kingbase8 \
  /home/kingbase/install/kingbase/bin/sys_ctl status -D /home/kingbase/data

# 2. 端口在监听。这个镜像里可能没有 ss/netstat,直接看 /proc
docker exec kingbase8 grep -i ':D431' /proc/net/tcp /proc/net/tcp6

# 3. 日志里出现 ready 字样
docker exec kingbase8 tail -50 /home/kingbase/data/sys_log/*.log

54321 的十六进制是 0xD431,这也是为什么要在 /proc/net/tcp 里搜这个字符串。容器里没有 ss 的时候,docker exec kingbase8 ss -lntp 会静默无输出,不能当成"端口没监听"。

三条都过了,再连库:

docker exec -u kingbase kingbase8 \
  ksql -U SYSTEM -p 54321 -d test -c "select version();"

镜像的 entrypoint 在 initdb 时会把本地连接认证改成 trust,容器内连库不需要密码。外网连接受 kingbase.conf 里的 listen_addresses 和 sys_hba.conf 控制,默认只允许本地。

七、换 license 的标准动作

授权到期后,启动日志是这样的:

FATAL: XX000: License file expired.
LOCATION: KesMasterMain, master.c:961

换证按顺序做,少一步就会遇到"换了还是起不来":

# 1. 备份旧证和当前配置
sudo cp -a /data/kingbase/license/license.dat \
  /data/kingbase/license/license.dat.bak-$(date +%F)

# 2. 覆盖新证,注意保住 inode 和属主
sudo cat new_license.dat > /data/kingbase/license/license.dat
sudo chown <uid>:<gid> /data/kingbase/license/license.dat

# 3. 清掉上次启动失败留下的 socket 和 pid 残留
docker exec kingbase8 sh -c '
  ts=$(date +%s)
  mkdir -p /tmp/kingbase-stale-$ts
  mv /tmp/.s.KINGBASE.54321* /tmp/kingbase-stale-$ts/ 2>/dev/null || true'

# 4. 用 kingbase 用户启动,root 会被拒绝
docker exec -u kingbase kingbase8 \
  /home/kingbase/install/kingbase/bin/sys_ctl start -D /home/kingbase/data

用 cat > 就地覆盖而不是删除重写,是为了保住文件 inode,已经挂载的路径不用重建容器。/tmp/.s.KINGBASE.54321 和对应的 .lock 文件是上次启动失败留下的,不清掉会报:

another server might be running; trying to start server anyway
lock file "/tmp/.s.KINGBASE.54321.lock" already exists

残留文件用 mv 挪走而不是 rm,出问题时还能看一眼时间戳,判断上一次启动尝试发生在什么时候。

还有一条:镜像里通常挂着一个 cron 看门狗,每分钟尝试拉起数据库。手工启动时如果撞上它,会看到 another server is running,等一分钟再试,或者先停掉看门狗。

八、备份

逻辑备份用 sys_dump,参数和 PostgreSQL 的 pg_dump 基本一致:

docker exec -u kingbase kingbase8 \
  sys_dump -U SYSTEM -p 54321 -d app -F c -f /tmp/app.dump
docker cp kingbase8:/tmp/app.dump /backup/app-$(date +%F).dump

恢复:

docker cp /backup/app-2026-10-29.dump kingbase8:/tmp/app.dump
docker exec -u kingbase kingbase8 \
  sys_restore -U SYSTEM -p 54321 -d app /tmp/app.dump

数据库本身可以直接停库后复制数据目录,但和 MySQL 一样,热复制没有意义。

九、常见报错

现象 原因 处理
FATAL: XX000: License file expired 授权到期 按第七节换证
sys_ctl: could not start server 原因很多,先看 sys_log 最后 50 行 优先查 license 和 socket 残留
another server might be running / lock file ... already exists 上次启动失败留下的 socket 和 pid 清 /tmp/.s.KINGBASE.54321*
WARNING: max_connections should be less than or equal than N (restricted by license) 授权带连接数上限,配置被压到上限值 核对应用连接池,别超上限
chown: ... Read-only file system license 挂载加了 :ro 去掉只读
Is a directory 指向 license 路径 宿主机文件不存在,Docker 建了目录 先放文件再改 compose
Permission denied 写数据目录 目录属主和容器内 kingbase 用户不一致 chown 成对应 uid
could not create shared memory segment 容器 /dev/shm 太小 加大 shm_size
进程在,端口连不上 监听地址、防火墙、端口映射 容器内看 /proc/net/tcp,宿主机看 ss -lntp
docker logs 里 server started 但库连不上 sys_ctl 在 license 校验前就报成功 用第六节的三条标准重新判断

十、限制

  • 授权是硬中断:到期不影响运行中的实例,但任何一次重启、宿主机重启、容器重建都会当场起不来。到期日要单独记,别等出事再查。
  • 授权可能带并发连接数上限,配置里写再大也会被压下来,这个值只能问发证方。
  • 容器重建会退回镜像内的旧授权,所以 license 必须挂卷,且换证后要检查挂载是否还在。
  • 单实例部署没有高可用,做主备是另一套配置(sys_hba.conf、复制槽、recovery.conf 这一套),不在容器化本身的范围里。
🤞 分享