由于开发测试需求,需要容器化部署达梦数据库供开发测试,但官网已不提供docker镜像下载,遂自建一个达梦8数据库的docker镜像以便测试。
建立后的镜像可以迁移至其他环境(如群晖、宝塔面板等),日常开发测试更加方便。
基础环境
本次测试基于1panel面板环境建立,相关步骤仅供参考
达梦数据库版本:dm8_20260428_x86_Ubuntu22_64
底层镜像:ubuntu:26.04
1panel:社区版(以下简称:面板)
如对docker命令足够熟悉,可自行使用命令行方式建立容器镜像
docker镜像站请自行寻找
搭建步骤
第一步:拉取镜像
在面板中拉取ubuntu镜像,其他linux发行版可自选,不一定使用ubuntu:26.04

第二步:建立容器镜像
在面板中创建基础容器,方便镜像建立,如对镜像有具体要求,可先自行配置底包)


首次使用需要勾选伪终端(-t)和标准输入(-i),不然无法启动
2-1:自定义底包镜像
以下操作非必须
继续编辑ubuntu2604容器中的环境变量,增加时区及语言环境:
LC_ALL=zh_CN.UTF-8
LANG=zh_CN.UTF-8
TZ=Asia/Shanghai
中文环境是必要的,后期达梦数据库help输出的是中文,没有中文环境输出的是乱码
容器启动后,首行会显示:bash: warning: setlocale: LC_ALL: cannot change locale (zh_CN.UTF-8): No such file or directory
这是正常的,因为镜像中未安装中文环境
在控制台中输入:
apt update && apt upgrade -y && apt install vim wget unzip curl git telnet locales language-pack-zh-hans net-tools iputils-ping lsof scapy openssh-client openssh-server sudo cron tree tmux -y && apt-get autoremove -y && locale-gen zh_CN.UTF-8 && locale-gen zh_CN.GBK && locale-gen zh_CN.GB18030 && apt clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/* /var/log/apt/* /tmp/* /var/tmp/* /root/.cache/* /usr/share/doc/* /usr/share/man/* /usr/share/locale/* && find /var/log -type f -name "*.log" -delete && exit此操作进行了系统更新和安装了:
vim wget、unzip、curl、git、telnet、net-tools、iputils-ping、lsof、scapy、openssh-client、openssh-server、sudo、cron、tree、tmux
基础网络和运行环境,另外安装了中文语言包
最后清理了/tmp/*等目录,保证镜像纯净
如apt命令卡死,可考虑更换
安装完成后重启镜像,首行报错消失,使用apt update命令控制台能正常返回中文
如重启镜像后发现控制台存在历史记录,可反复运行:rm -rf /root/.bash_history && exit 清空控制台记录
以上步骤完成后,停止容器,导出基础镜像ubuntu26.04lts-zh

此镜像大小约为1.16 GB,未安装基础功能仅安装中文时大小约900MB,请自行裁量需求
2-2:安装dm8数据库
2-2.1:下载数据库并创建容器
前往
官网下载iso镜像,根据平台机器选择,本次使用dm8_20260428_x86_Ubuntu22_64.zip
安装包命名规则:
dm8: 数据库大版本为 dm8
20260428: 数据库版本发布日期
x86: 安装包匹配的 CPU 架构
Ubuntu22: 安装包匹配的系统版本 (Ubuntu22.04)
64: 安装包匹配的系统的位数(64 位)
解包得dm8_20260428_x86_Ubuntu22_64.iso镜像,内含DM8 Install.pdf及DMInstall.bin这两个文件,DM8 Install.pdf为安装手册,DMInstall.bin为数据库安装程序
下载完毕后,利用ubuntu26.04lts-zh镜像建立新容器dm-1,在容器>更多>目录中上传DMInstall.bin到/tmp/目录下

2-2.2:数据库容器设置
接下来步骤基本参考官方安装步骤:
接下来,若无特殊提示,均使用root权限
进入容器,执行:
# 创建用户所在的组
groupadd dinstall -g 2001
# 创建用户
useradd -G dinstall -m -d /home/dmdba -s /bin/bash -u 2001 dmdba
# 修改用户密码,自行设置,输入2遍密码
passwd dmdba使用vim,编辑/etc/security/limits.conf在最后增加加以下内容
vim /etc/security/limits.conf
dmdba soft nice 0
dmdba hard nice 0
dmdba soft as unlimited
dmdba hard as unlimited
dmdba soft fsize unlimited
dmdba hard fsize unlimited
dmdba soft nproc 65536
dmdba hard nproc 65536
dmdba soft nofile 65536
dmdba hard nofile 65536
dmdba soft core unlimited
dmdba hard core unlimited
dmdba soft data unlimited
dmdba hard data unlimited建立数据库文件存储位置,设置文件权限,同时方便后期挂载:
##实例保存目录
mkdir -p /dmdata/data
##归档保存目录
mkdir -p /dmdata/arch
##备份保存目录
mkdir -p /dmdata/dmbak
chmod -R 755 /dmdata/data
chmod -R 755 /dmdata/arch
chmod -R 755 /dmdata/dmbak2-2.3:安装数据库
在root权限下,执行:
chmod +x /tmp/DMInstall.bin确保安装文件有可执行权限
断开连接,使用dmdba用户重新进入

输入命令开始安装:
/tmp/DMInstall.bin -i其中,语言选择中文,Key文件路径选择不设置(完成docker镜像后再导入),设置时区并使用[21]: (GTM+08:00) 中国标准时间,安装目录我们默认(将程序固定在容器内)
此处为完整安装回显
安装语言:
[1]: 简体中文
[2]: English
请选择安装语言 [1]:1
解压安装程序.........
硬件架构校验通过!
time(seconds) unlimited
file(blocks) unlimited
data(kbytes) unlimited
stack(kbytes) 8192
coredump(blocks) unlimited
memory(kbytes) unlimited
locked memory(kbytes) 8192
process unlimited
nofiles 1024
vmemory(kbytes) unlimited
locks unlimited
rtprio 0
可打开文件数过少,建议至少设置为65536或更多。
欢迎使用达梦数据库安装程序
是否输入Key文件路径? (Y/y:是 N/n:否) [Y/y]:n
是否设置时区? (Y/y:是 N/n:否) [Y/y]:y
设置时区:
[ 1]: (GTM-12:00) 日界线西
[ 2]: (GTM-11:00) 萨摩亚群岛
[ 3]: (GTM-10:00) 夏威夷
[ 4]: (GTM-09:00) 阿拉斯加
[ 5]: (GTM-08:00) 太平洋时间(美国和加拿大)
[ 6]: (GTM-07:00) 亚利桑那
[ 7]: (GTM-06:00) 中部时间(美国和加拿大)
[ 8]: (GTM-05:00) 东部部时间(美国和加拿大)
[ 9]: (GTM-04:00) 大西洋时间(美国和加拿大)
[10]: (GTM-03:00) 巴西利亚
[11]: (GTM-02:00) 中大西洋
[12]: (GTM-01:00) 亚速尔群岛
[13]: (GTM) 格林威治标准时间
[14]: (GTM+01:00) 萨拉热窝
[15]: (GTM+02:00) 开罗
[16]: (GTM+03:00) 莫斯科
[17]: (GTM+04:00) 阿布扎比
[18]: (GTM+05:00) 伊斯兰堡
[19]: (GTM+06:00) 达卡
[20]: (GTM+07:00) 曼谷,河内
[21]: (GTM+08:00) 中国标准时间
[22]: (GTM+09:00) 首尔
[23]: (GTM+10:00) 关岛
[24]: (GTM+11:00) 所罗门群岛
[25]: (GTM+12:00) 斐济
[26]: (GTM+13:00) 努库阿勒法
[27]: (GTM+14:00) 基里巴斯
请选择时区 [21]:21
安装类型:
1 典型安装
2 服务器
3 客户端
4 自定义
请选择安装类型的数字序号 [1 典型安装]:1
所需空间: 1929M
请选择安装目录 [/home/dmdba/dmdbms]:
可用空间: 717G
是否确认安装路径(/home/dmdba/dmdbms)? (Y/y:是 N/n:否) [Y/y]:y
安装前小结
安装位置: /home/dmdba/dmdbms
所需空间: 1929M
可用空间: 717G
版本信息:
有效日期:
安装类型: 典型安装
是否确认安装? (Y/y:是 N/n:否):y
2026-08-06 00:00:39
[INFO] 安装达梦数据库...
2026-08-06 00:00:39
[INFO] 安装 基础 模块...
2026-08-06 00:00:47
[INFO] 安装 服务器 模块...
2026-08-06 00:00:48
[INFO] 安装 客户端 模块...
2026-08-06 00:00:52
[INFO] 安装 驱动 模块...
2026-08-06 00:00:54
[INFO] 安装 手册 模块...
2026-08-06 00:00:54
[INFO] 安装 服务 模块...
2026-08-06 00:00:55
[INFO] 移动日志文件。
2026-08-06 00:00:56
[INFO] 安装达梦数据库完成。
请以root系统用户执行命令:
/home/dmdba/dmdbms/script/root/root_installer.sh
安装结束安装完成后,将在安装目录生成log:
/home/dmdba/dmdbms/log/install.log # 记录安装过程中的安装模块、注册服务、卸载等信息
/home/dmdba/dmdbms/log/install_ant.log # 记录安装过程中的文件拷贝信息可自行删除
2-2.4设置基础环境(重要)
接下来的步骤就是本次容器化的核心
在安装完成后,提示我们:请以root系统用户执行命令:/home/dmdba/dmdbms/script/root/root_installer.sh
由于docker内没有systemctl相关,我们直接使用此文件内有用的命令(返回以root用户权限执行):
# /home/dmdba/dmdbms为安装目录
mv "/home/dmdba/dmdbms/bin/dm_svc.conf" /etc/dm_svc.conf接下来编写一个达梦数据库的初始化脚本,用来初始化数据库及数据库启停
#!/bin/bash
# dm_database_ctl.sh - 达梦数据库管理脚本
set -e
# ==================== 配置区域 ====================
DM_HOME="/home/dmdba/dmdbms"
DM_DATA="/dmdata"
DM_DATA_DIR="${DM_DATA}/data"
DM_ARCH_DIR="${DM_DATA}/arch"
DM_BAK_DIR="${DM_DATA}/dmbak"
DM_INIT_FLAG="${DM_DATA}/README.md"
DM_INI_FILE="${DM_DATA_DIR}/DM/dm.ini"
DM_KEY_SOURCE="${DM_DATA}/dm.key"
DM_KEY_LINK="${DM_HOME}/bin/dm.key"
DM_PID_DIR="${DM_HOME}/bin/pids"
DM_LOG_DIR="${DM_HOME}/log"
# 初始化参数
SYSDBA_PWD="Dmdba000"
SYSAUDITOR_PWD="Dmdba000"
PORT_NUM="5236"
PAGE_SIZE="16"
EXTENT_SIZE="32"
CASE_SENSITIVE="0"
CHARSET="1"
DB_NAME="DM"
# 服务相关配置
CUR_SERVICE_NAME="DmServiceDMSERVER"
EXEC_PROG_NAME="dmserver"
EXEC_PROG_FULL_PATH="${DM_HOME}/bin/${EXEC_PROG_NAME}"
SERVICE_PID_FILE="${DM_PID_DIR}/${CUR_SERVICE_NAME}.pid"
SERVICE_LOG_FILE="${DM_LOG_DIR}/${CUR_SERVICE_NAME}.log"
SERVICE_ERR_FILE="${DM_LOG_DIR}/${CUR_SERVICE_NAME}_err.log"
START_SERVICE_LOG_FILE="${SERVICE_LOG_FILE}"
START_SERVICE_ERR_FILE="${SERVICE_ERR_FILE}"
STARTUP_PARAMS="path=\"${DM_INI_FILE}\""
PS_STARTUP_PARAMS="path=${DM_INI_FILE}"
GREP_FULL_STR="${EXEC_PROG_FULL_PATH} ${PS_STARTUP_PARAMS}"
PRARM_START_WAIT_TIME=15
PRARM_STOP_WAIT_FLAG=true
SAVE_PROC_OUT=false
SAVE_PROC_ERR=true
KILL_PROG_WAIT_TIME=180
# 全局控制台日志开关(默认开启)
ENABLE_CONSOLE_LOG=true
# ==================== 环境变量设置 ====================
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${DM_HOME}/bin"
export DM_HOME="${DM_HOME}"
export PATH="$PATH:${DM_HOME}/bin:${DM_HOME}/tool"
export MALLOC_ARENA_MAX=4
# 颜色输出(使用ANSI转义码)
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
# 获取操作系统类型
DIST_OS=$(uname)
# ==================== 日志函数 ====================
# 输出到控制台(保留颜色)
console_echo() {
if [ "${ENABLE_CONSOLE_LOG}" = "true" ]; then
# 使用printf输出,保留颜色转义
printf "%b\n" "$1"
fi
}
# 输出到Docker日志(保留颜色)
docker_echo() {
# 使用printf输出到docker日志,保留颜色转义
printf "%b\n" "$1" > /proc/1/fd/1 2>/dev/null || true
}
# 日志函数 - 同时输出到控制台和Docker
log_info() {
local msg="${BLUE}[INFO]${NC} $1"
console_echo "$msg"
docker_echo "$msg"
}
log_success() {
local msg="${GREEN}[SUCCESS]${NC} $1"
console_echo "$msg"
docker_echo "$msg"
}
log_warn() {
local msg="${YELLOW}[WARN]${NC} $1"
console_echo "$msg"
docker_echo "$msg"
}
log_error() {
local msg="${RED}[ERROR]${NC} $1"
console_echo "$msg" >&2
docker_echo "$msg"
}
log_plain() {
console_echo "$1"
docker_echo "$1"
}
# ==================== 核心功能函数 ====================
# 检查是否已初始化
is_initialized() {
if [ -f "${DM_INIT_FLAG}" ] && [ -d "${DM_DATA_DIR}/DM" ] && [ -f "${DM_INI_FILE}" ]; then
return 0
else
return 1
fi
}
# 创建必要的目录
create_required_dirs() {
# 创建日志目录
if [ ! -d "${DM_LOG_DIR}" ]; then
mkdir -p "${DM_LOG_DIR}"
chown dmdba:dinstall "${DM_LOG_DIR}" 2>/dev/null || true
fi
# 创建PID目录
if [ ! -d "${DM_PID_DIR}" ]; then
mkdir -p "${DM_PID_DIR}"
chown dmdba:dinstall "${DM_PID_DIR}" 2>/dev/null || true
fi
}
# 创建目录并设置权限(初始化时使用)
create_directories() {
log_info "创建数据目录..."
log_plain "📁 创建数据目录: ${DM_DATA_DIR}, ${DM_ARCH_DIR}, ${DM_BAK_DIR}"
mkdir -p "${DM_DATA_DIR}"
mkdir -p "${DM_ARCH_DIR}"
mkdir -p "${DM_BAK_DIR}"
log_info "设置目录权限..."
log_plain "🔐 设置目录权限: chown dmdba:dinstall + chmod 755"
chown -R dmdba:dinstall "${DM_DATA_DIR}" 2>/dev/null || {
chown -R $(whoami):$(whoami) "${DM_DATA_DIR}" 2>/dev/null || true
}
chown -R dmdba:dinstall "${DM_ARCH_DIR}" 2>/dev/null || {
chown -R $(whoami):$(whoami) "${DM_ARCH_DIR}" 2>/dev/null || true
}
chown -R dmdba:dinstall "${DM_BAK_DIR}" 2>/dev/null || {
chown -R $(whoami):$(whoami) "${DM_BAK_DIR}" 2>/dev/null || true
}
chmod -R 755 "${DM_DATA_DIR}" 2>/dev/null || true
chmod -R 755 "${DM_ARCH_DIR}" 2>/dev/null || true
chmod -R 755 "${DM_BAK_DIR}" 2>/dev/null || true
log_success "目录创建和权限设置完成"
log_plain "✅ 目录创建和权限设置完成"
}
# 校验并修复目录权限(普通输出)
verify_and_fix_permissions() {
log_info "校验目录权限..."
local need_fix=0
if [ -d "${DM_DATA_DIR}" ]; then
local current_owner=$(stat -c "%U:%G" "${DM_DATA_DIR}" 2>/dev/null || echo "")
if [ "${current_owner}" != "dmdba:dinstall" ] && [ "${current_owner}" != "" ]; then
need_fix=1
fi
fi
if [ ${need_fix} -eq 1 ]; then
log_info "重新设置所有目录权限..."
chown -R dmdba:dinstall "${DM_DATA_DIR}" 2>/dev/null || true
chown -R dmdba:dinstall "${DM_ARCH_DIR}" 2>/dev/null || true
chown -R dmdba:dinstall "${DM_BAK_DIR}" 2>/dev/null || true
chmod -R 755 "${DM_DATA_DIR}" 2>/dev/null || true
chmod -R 755 "${DM_ARCH_DIR}" 2>/dev/null || true
chmod -R 755 "${DM_BAK_DIR}" 2>/dev/null || true
log_success "权限修复完成"
else
log_info "目录权限校验通过"
fi
}
# 显示连接信息(初始化时使用)
show_connection_info() {
local border="${GREEN}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}"
local title="${GREEN}${BOLD}║ 达梦数据库初始化成功 - 连接信息 ║${NC}"
local line="${GREEN}${BOLD}╠═══════════════════════════════════════════════════════════════╣${NC}"
local bottom="${GREEN}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}"
log_plain ""
log_plain "${border}"
log_plain "${title}"
log_plain "${line}"
log_plain "${GREEN}${BOLD}║${NC} 数据库名称: ${CYAN}${BOLD}${DB_NAME}${NC}"
log_plain "${GREEN}${BOLD}║${NC} 端口号: ${CYAN}${BOLD}${PORT_NUM}${NC}"
log_plain "${GREEN}${BOLD}║${NC} 账号: ${CYAN}${BOLD}SYSDBA${NC}"
log_plain "${GREEN}${BOLD}║${NC} 密码: ${CYAN}${BOLD}${SYSDBA_PWD}${NC}"
log_plain "${GREEN}${BOLD}║${NC} 审计账号: ${CYAN}${BOLD}SYSAUDITOR${NC}"
log_plain "${GREEN}${BOLD}║${NC} 审计密码: ${CYAN}${BOLD}${SYSAUDITOR_PWD}${NC}"
log_plain "${GREEN}${BOLD}║${NC} 数据目录: ${DM_DATA_DIR}"
log_plain "${line}"
log_plain "${GREEN}${BOLD}║${NC} 连接命令: ${YELLOW}disql SYSDBA/${SYSDBA_PWD}@localhost:${PORT_NUM}${NC}"
log_plain "${bottom}"
log_plain ""
# 保存连接信息到 README.md(不带颜色)
local plain_info=""
plain_info+="============================================================\n"
plain_info+=" 达梦数据库初始化成功 - 连接信息\n"
plain_info+="============================================================\n"
plain_info+="数据库名称: ${DB_NAME}\n"
plain_info+="端口号: ${PORT_NUM}\n"
plain_info+="账号: SYSDBA\n"
plain_info+="密码: ${SYSDBA_PWD}\n"
plain_info+="审计账号: SYSAUDITOR\n"
plain_info+="审计密码: ${SYSAUDITOR_PWD}\n"
plain_info+="数据目录: ${DM_DATA_DIR}\n"
plain_info+="------------------------------------------------------------\n"
plain_info+="连接命令: disql SYSDBA/${SYSDBA_PWD}@localhost:${PORT_NUM}\n"
plain_info+="============================================================\n"
echo -e "\n$(date '+%Y-%m-%d %H:%M:%S') - 初始化信息:" >> "${DM_INIT_FLAG}"
echo "$plain_info" >> "${DM_INIT_FLAG}"
}
# 初始化数据库
init_database() {
log_info "开始初始化达梦数据库..."
if is_initialized; then
log_warn "数据库已初始化,跳过初始化步骤"
return 0
fi
create_directories
create_required_dirs
log_info "执行 dminit 初始化命令..."
log_plain "📊 执行数据库初始化..."
log_plain " 数据库名: ${DB_NAME}"
log_plain " 端口: ${PORT_NUM}"
log_plain " 字符集: UTF-8"
log_plain " 页大小: ${PAGE_SIZE}KB"
log_plain " 区分大小写: 否"
# 执行初始化并输出到日志
local init_output=$(mktemp)
if command -v runuser &>/dev/null; then
runuser -l dmdba -c "${DM_HOME}/bin/dminit \
path=${DM_DATA_DIR} \
SYSDBA_PWD=${SYSDBA_PWD} \
SYSAUDITOR_PWD=${SYSAUDITOR_PWD} \
PORT_NUM=${PORT_NUM} \
PAGE_SIZE=${PAGE_SIZE} \
EXTENT_SIZE=${EXTENT_SIZE} \
CASE_SENSITIVE=${CASE_SENSITIVE} \
CHARSET=${CHARSET} \
DB_NAME=${DB_NAME}" > "${init_output}" 2>&1
else
su - dmdba -c "${DM_HOME}/bin/dminit \
path=${DM_DATA_DIR} \
SYSDBA_PWD=${SYSDBA_PWD} \
SYSAUDITOR_PWD=${SYSAUDITOR_PWD} \
PORT_NUM=${PORT_NUM} \
PAGE_SIZE=${PAGE_SIZE} \
EXTENT_SIZE=${EXTENT_SIZE} \
CASE_SENSITIVE=${CASE_SENSITIVE} \
CHARSET=${CHARSET} \
DB_NAME=${DB_NAME}" > "${init_output}" 2>&1
fi
# 读取并输出初始化日志
while IFS= read -r line; do
if [ -n "$line" ]; then
log_plain " ${line}"
fi
done < "${init_output}"
# 删除临时文件
rm -f "${init_output}"
if [ $? -eq 0 ] && [ -f "${DM_INI_FILE}" ]; then
log_success "数据库初始化成功"
log_plain "✅ 数据库初始化成功"
else
log_error "数据库初始化失败"
log_plain "❌ 数据库初始化失败"
return 1
fi
# 显示连接信息
show_connection_info
# 创建软链接
create_dm_key_link
log_success "初始化完成"
}
# 创建 dm.key 软链接
create_dm_key_link() {
# 删除旧链接(如果存在)
if [ -L "${DM_KEY_LINK}" ] || [ -f "${DM_KEY_LINK}" ]; then
rm -f "${DM_KEY_LINK}"
fi
# 直接创建软链接
ln -sf "${DM_KEY_SOURCE}" "${DM_KEY_LINK}"
log_plain "🔗 创建 dm.key 软链接: ${DM_KEY_LINK} -> ${DM_KEY_SOURCE}"
# 检查源文件是否存在
if [ -f "${DM_KEY_SOURCE}" ]; then
log_success "dm.key 授权文件存在"
log_plain "✅ dm.key 授权文件存在"
else
log_warn "dm.key 授权文件不存在: ${DM_DATA}/dm.key"
log_plain "⚠️ dm.key 授权文件不存在,请手动放置到 ${DM_DATA} 目录"
fi
}
# ==================== 进程管理函数(参考服务脚本) ====================
# 获取数据库进程PID
get_pid() {
local pid=""
case "$DIST_OS" in
'HP-UX')
pid=$(ps -ef | grep -F "${GREP_FULL_STR}" | grep -v "grep" | tail -1 | awk '{print $2}')
;;
'Solaris')
case "$PS_BIN" in
'/usr/ucb/ps')
pid=$(ps -auxww | fgrep "${GREP_FULL_STR}" | grep -v "grep" | tail -1 | awk '{print $2}')
;;
*)
pid=$(ps -eo pid,args | fgrep "${GREP_FULL_STR}" | grep -v "grep" | tail -1 | awk '{print $1}')
;;
esac
;;
'AIX'|'FreeBSD')
pid=$(ps -eo pid,args | grep -F "${GREP_FULL_STR}" | grep -v "grep" | tail -1 | awk '{print $1}')
;;
*)
pid=$(ps -eo pid,args | grep -F "${GREP_FULL_STR}" | grep -v "grep" | tail -1 | awk '{print $1}')
;;
esac
echo "${pid}"
}
# 检查数据库是否运行
check_database_status() {
local pid=$(get_pid)
if [ -n "${pid}" ]; then
echo "running|${pid}"
return 0
else
echo "stopped"
return 1
fi
}
# 停止进程(参考服务脚本的kill_cur_prog)
kill_cur_prog() {
local pid=$(get_pid)
if [ -z "${pid}" ]; then
return 0
fi
local KILL_SIGNAL=""
if [ "x${DCR_INI_PATH}" != "x" ] && [ "${DCR_INI_PATH}" != "%DCR_INI_PATH%" ]; then
KILL_SIGNAL="2"
fi
log_info "停止数据库进程 (PID: ${pid})..."
# 记录停止日志
if [ ! -f "${DM_LOG_DIR}/dmsvc_sh.log" ]; then
touch "${DM_LOG_DIR}/dmsvc_sh.log"
chown dmdba:dinstall "${DM_LOG_DIR}/dmsvc_sh.log" 2>/dev/null || true
fi
echo "[$(date "+%Y-%m-%d %H:%M:%S")] [localhost] [${CUR_SERVICE_NAME}] kill(signal:${KILL_SIGNAL:-15}) service($pid)" >> "${DM_LOG_DIR}/dmsvc_sh.log"
# 发送停止信号
if [ -n "${KILL_SIGNAL}" ]; then
kill "-${KILL_SIGNAL}" ${pid}
else
kill ${pid}
fi
local RETURN_CODE=$?
if [ ${RETURN_CODE} -ne 0 ]; then
echo "[$(date "+%Y-%m-%d %H:%M:%S")] [localhost] [${CUR_SERVICE_NAME}] failed to kill service($pid) (code: ${RETURN_CODE})" >> "${DM_LOG_DIR}/dmsvc_sh.log"
return ${RETURN_CODE}
fi
# 等待进程退出
if [ "${PRARM_STOP_WAIT_FLAG}" = "true" ]; then
local wait_time=0
while [ -n "$(get_pid)" ]; do
sleep 2
wait_time=$((wait_time + 2))
if [ ${wait_time} -ge ${KILL_PROG_WAIT_TIME} ]; then
log_warn "进程停止超时,强制终止..."
kill -9 ${pid}
sleep 2
if [ -n "$(get_pid)" ]; then
log_error "强制终止失败"
return 1
fi
break
fi
done
echo "[$(date "+%Y-%m-%d %H:%M:%S")] [localhost] [${CUR_SERVICE_NAME}] kill service successfully" >> "${DM_LOG_DIR}/dmsvc_sh.log"
fi
return 0
}
# 启动数据库(参考服务脚本的start_service)
start_database() {
if [ ! -f "${DM_INI_FILE}" ]; then
log_error "配置文件不存在: ${DM_INI_FILE}"
return 1
fi
if [ -n "$(get_pid)" ]; then
log_warn "数据库已经在运行"
return 0
fi
# 确保目录存在
create_required_dirs
log_info "启动数据库..."
# 记录启动日志
if [ ! -f "${DM_LOG_DIR}/dmsvc_sh.log" ]; then
touch "${DM_LOG_DIR}/dmsvc_sh.log"
chown dmdba:dinstall "${DM_LOG_DIR}/dmsvc_sh.log" 2>/dev/null || true
fi
echo "[$(date "+%Y-%m-%d %H:%M:%S")] [localhost] [${CUR_SERVICE_NAME}] start service" >> "${DM_LOG_DIR}/dmsvc_sh.log"
# 确定启动模式
local TMP_START_MODE=""
if [ "${START_MODE}" = "mount" ]; then
TMP_START_MODE="mount"
fi
# 切换用户启动
local CMD="cd ${DM_HOME}/bin && nohup ${EXEC_PROG_FULL_PATH} ${STARTUP_PARAMS} -noconsole ${TMP_START_MODE} > ${START_SERVICE_LOG_FILE} 2> ${START_SERVICE_ERR_FILE} &"
if [ "${CUR_USER_NAME}" = "root" ] && [ "$(stat -c '%U' ${DM_HOME})" != "root" ]; then
su - dmdba -c "${CMD}"
else
eval ${CMD}
fi
local RETURN_CODE=$?
if [ ${RETURN_CODE} -eq 0 ]; then
sleep ${PRARM_START_WAIT_TIME}
local pid=$(get_pid)
if [ -n "${pid}" ]; then
echo "[$(date "+%Y-%m-%d %H:%M:%S")] [localhost] [${CUR_SERVICE_NAME}] start service($pid) successfully" >> "${DM_LOG_DIR}/dmsvc_sh.log"
# 保存PID
echo ${pid} > "${SERVICE_PID_FILE}"
chown dmdba:dinstall "${SERVICE_PID_FILE}" 2>/dev/null || true
log_success "数据库启动成功 (PID: ${pid})"
return 0
else
echo "[$(date "+%Y-%m-%d %H:%M:%S")] [localhost] [${CUR_SERVICE_NAME}] failed to start service (code:${RETURN_CODE})" >> "${DM_LOG_DIR}/dmsvc_sh.log"
log_error "数据库启动失败"
if [ "${SAVE_PROC_ERR}" = "true" ] && [ -f "${START_SERVICE_ERR_FILE}" ]; then
cat "${START_SERVICE_ERR_FILE}"
fi
return 1
fi
else
log_error "启动命令执行失败 (code: ${RETURN_CODE})"
return ${RETURN_CODE}
fi
}
# 停止数据库
stop_database() {
log_info "停止数据库..."
local pid=$(get_pid)
if [ -z "${pid}" ]; then
log_warn "数据库未运行"
return 0
fi
# 使用专业的停止函数
kill_cur_prog
if [ $? -eq 0 ]; then
# 删除PID文件
rm -f "${SERVICE_PID_FILE}"
log_success "数据库已停止"
return 0
else
log_error "数据库停止失败"
return 1
fi
}
# ==================== 主命令函数 ====================
cmd_init() {
check_dmdba_user
check_dm_home
if is_initialized; then
log_warn "数据库已初始化,跳过"
return 0
fi
init_database
if [ $? -eq 0 ]; then
log_success "初始化完成"
else
log_error "初始化失败"
return 1
fi
}
cmd_start() {
check_dmdba_user
check_dm_home
if ! is_initialized; then
log_info "检测到数据库未初始化,开始自动初始化..."
init_database
if [ $? -ne 0 ]; then
log_error "自动初始化失败"
return 1
fi
else
log_info "数据库已初始化,直接启动..."
fi
verify_and_fix_permissions
# 检查dm.key(仅在启动时)
check_dm_key
start_database
if [ $? -eq 0 ]; then
log_success "数据库启动完成"
else
log_error "数据库启动失败"
return 1
fi
}
cmd_stop() {
check_dmdba_user
check_dm_home
stop_database
}
cmd_restart() {
check_dmdba_user
check_dm_home
log_info "========== 开始重启数据库 =========="
# 停止数据库(使用服务脚本的停止方式)
stop_database
local stop_result=$?
if [ ${stop_result} -ne 0 ]; then
log_error "数据库停止失败,终止重启操作"
return 1
fi
# 启动数据库(restart不检查dm.key,不创建软链接)
log_info "开始启动数据库..."
start_database
local start_result=$?
if [ ${start_result} -eq 0 ]; then
log_success "========== 数据库重启完成 =========="
else
log_error "========== 数据库重启失败 =========="
fi
return ${start_result}
}
cmd_status() {
local status=$(check_database_status)
if [[ "${status}" == running\|* ]]; then
local pid=$(echo "${status}" | cut -d'|' -f2)
log_info "数据库状态: ${GREEN}运行中${NC} (PID: ${pid})"
else
log_info "数据库状态: ${RED}已停止${NC}"
fi
if is_initialized; then
log_info "初始化状态: ${GREEN}已初始化${NC}"
else
log_info "初始化状态: ${YELLOW}未初始化${NC}"
fi
}
# ==================== 辅助函数 ====================
check_dmdba_user() {
if ! id "dmdba" &>/dev/null; then
log_error "dmdba 用户不存在"
exit 1
fi
}
check_dm_home() {
if [ ! -d "${DM_HOME}" ]; then
log_error "达梦安装目录不存在: ${DM_HOME}"
exit 1
fi
}
check_dm_key() {
if [ -f "${DM_KEY_SOURCE}" ]; then
log_success "dm.key 授权文件存在"
else
log_warn "dm.key 授权文件不存在: ${DM_DATA}/dm.key"
log_plain "⚠️ dm.key 授权文件不存在,请手动放置到 ${DM_DATA} 目录"
fi
}
cmd_help() {
cat << 'EOF'
达梦数据库管理脚本
用法: ./dm.sh {init|start|stop|restart|status|help} [--nolog]
命令:
init 初始化数据库
start 启动数据库(自动检测并初始化)
stop 停止数据库
restart 重启数据库(按标准服务脚本方式)
status 查看数据库状态
help 显示此帮助信息
选项:
--nolog 不在控制台输出日志(但Docker日志仍然输出)
示例:
./dm.sh init
./dm.sh start
./dm.sh status
./dm.sh stop
./dm.sh restart
./dm.sh start --nolog
./dm.sh restart --nolog
EOF
}
# ==================== 主程序入口 ====================
# 获取当前用户
CUR_USER_NAME=$(whoami 2>/dev/null || echo "")
if [ -z "${CUR_USER_NAME}" ]; then
CUR_USER_NAME=$(who am i | awk '{print $1}' 2>/dev/null || echo "root")
fi
# 设置PS命令
PS_BIN="/usr/bin/ps"
if [ ! -x "${PS_BIN}" ]; then
PS_BIN="/bin/ps"
if [ ! -x "${PS_BIN}" ]; then
PS_BIN="/usr/ucb/ps"
fi
fi
main() {
# 解析参数,提取命令和选项
local CMD=""
local ARGS=()
for arg in "$@"; do
case "$arg" in
--nolog)
ENABLE_CONSOLE_LOG=false
;;
init|start|stop|restart|status|help|--help|-h)
if [ -z "${CMD}" ]; then
CMD="$arg"
else
ARGS+=("$arg")
fi
;;
*)
ARGS+=("$arg")
;;
esac
done
# 如果没有命令,显示帮助
if [ -z "${CMD}" ]; then
CMD="help"
fi
# 执行命令
case "${CMD}" in
init)
cmd_init
;;
start)
cmd_start
;;
stop)
cmd_stop
;;
restart)
cmd_restart
;;
status)
cmd_status
;;
help|--help|-h)
cmd_help
;;
*)
log_error "未知命令: ${CMD}"
cmd_help
exit 1
;;
esac
}
main "$@"此脚本集成了数据库初始化及数据库管理相关功能,在初始化时可将初始化信息输出至docker日志中,方便查阅
同时针对数据库迁移,自动设置数据库目录的用户和权限组
脚本使用方法
将此脚本命名为dm.sh,并上传至/root/dm.sh
在控制台执行:
# 赋予可执行权限
chmod +x /root/dm.sh
# 建立软连接(可只建立1个,上手即可)
ln -s /root/dm.sh /usr/local/bin/dm
ln -s /root/dm.sh /usr/local/bin/dm.sh
ln -s /root/dm.sh /usr/local/bin/dm8第三步:导出dm8镜像
此时,达梦8的容器的制作到此结束,我们清空输入日志后关机导出镜像:dm8
镜像大小约4.2GB
启动容器
导出dm8后,即可使用命令行或docker-compose文件的方式创建虚拟化环境
docker-compose文件方式
networks:
dm8:
name: dm8
driver: bridge
services:
dm8:
container_name: dm8
image: dm8:latest
restart: unless-stopped
networks:
- dm8
ports:
- "5236:5236"
environment:
DM_HOME: /home/dmdba/dmdbms
LD_LIBRARY_PATH: /home/dmdba/dmdbms/bin
PATH: /home/dmdba/dmdbms/bin:/home/dmdba/dmdbms/tool:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LC_ALL: zh_CN.UTF-8
LANG: zh_CN.UTF-8
TZ: Asia/Shanghai
volumes:
- /opt/dmdata/:/dmdata
command: ["/bin/bash", "-c", "/root/dm.sh start --nolog && tail -f /dev/null"]命令行方式
docker run -d \
--name dm8 \
--restart unless-stopped \
--network dm8 \
-p 5236:5236 \
-e DM_HOME=/home/dmdba/dmdbms \
-e LD_LIBRARY_PATH=/home/dmdba/dmdbms/bin \
-e PATH=/home/dmdba/dmdbms/bin:/home/dmdba/dmdbms/tool:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
-e LC_ALL=zh_CN.UTF-8 \
-e LANG=zh_CN.UTF-8 \
-e TZ=Asia/Shanghai \
-v /opt/dmdata/:/dmdata \
dm8:latest \
/bin/bash -c "/root/dm.sh start --nolog && tail -f /dev/null"其中,dm8为导出的镜像名,根据你的进行设置
达梦数据库默认使用5236端口,如有其他端口需求可自行更改
/opt/dmdata/为你数据库在物理机的位置,可以自行设置
这里作者使用docker-compose的方式建立:

启动后容器将建立一个dm8容器并生成一个默认数据库,数据库相关信息显示在日志中

如有需求,可删除初始数据库自行建立:
# 暂停数据库
dm stop
# 删除已生成的数据库(需要保留/dmdata/README.md,启动脚本以此文件判断是否需要初始化)
rm -rf /dmdata/data/*
# 查看初始化帮助
/home/dmdba/dmdbms/bin/dminit help
#初始化示例
/home/dmdba/dmdbms/bin/dminit \
path=/dmdata/data \
SYSDBA_PWD=Dmdba000 \
SYSAUDITOR_PWD=Dmdba000 \
PORT_NUM=5236 \
PAGE_SIZE=16 \
EXTENT_SIZE=32 \
CASE_SENSITIVE=0 \
CHARSET=1 \
DB_NAME=DM
其中,path=/dmdata/data 为数据库目录,不推荐更改
PORT_NUM=5236为数据库端口,
SYSDBA_PWD和SYSAUDITOR_PWD分别为管理员密码、审计员密码
PAGE_SIZE为页大小(单位 KB),可选 4/8/16/32
EXTENT_SIZE为区大小(单位页),可选 16/32/64
CASE_SENSITIVE为是否大小写敏感(0=不敏感,1=敏感)
CHARSET为字符集(0=GB18030,1=UTF-8,2=EUC-KR)
DB_NAME为数据库名称连接数据库
使用达梦官方出品的SQLark百灵连接进行连接

查询授权情况
连接成功后,使用
sp_load_lic_info;
-- 查询授权详细信息
SELECT
DECODE(SERIES_NO, SERIES_NO, SERIES_NO) AS "序列号",
DECODE(EXPIRED_DATE, NULL, '永久', EXPIRED_DATE) AS "有效日期",
DECODE(AUTHORIZED_CUSTOMER, 'DEVELOP USER', '开发用户', AUTHORIZED_CUSTOMER) AS "授权客户",
DECODE(PROJECT_NAME, PROJECT_NAME, PROJECT_NAME) AS "项目名称",
DECODE(SUBSTR(CLUSTER_TYPE, 1, 1), '1', '数据守护授权', '0', '数据守护禁止', '未知') || '/' ||
DECODE(SUBSTR(CLUSTER_TYPE, 2, 1), '1', 'MPP授权', '0', 'MPP禁止', '未知') || '/' ||
DECODE(SUBSTR(CLUSTER_TYPE, 3, 1), '1', '读写分离授权', '0', '读写分离禁止', '未知') || '/' ||
DECODE(SUBSTR(CLUSTER_TYPE, 4, 1), '1', 'DSC授权', '0', 'DSC禁止', '未知') AS "集群类型",
DECODE(SERVER_TYPE, 1, '正式版', 2, '测试版', 3, '试用版', '其他') AS "授权类型",
DECODE(SERVER_SERIES, 'P', '个人版', 'S', '标准版', 'E', '企业版', 'A', '安全版', 'T', '可信版', 'X', '定制版', '其他') AS "产品版本",
DECODE(LIC_VERSION, LIC_VERSION, LIC_VERSION) AS "许可证版本号",
DECODE(SERVER_VER, SERVER_VER, SERVER_VER) AS "服务器版本号",
DECODE(AUTHORIZED_USER_NUMBER, AUTHORIZED_USER_NUMBER, AUTHORIZED_USER_NUMBER) AS "授权用户数",
DECODE(CONCURRENCY_USER_NUMBER, CONCURRENCY_USER_NUMBER, CONCURRENCY_USER_NUMBER) AS "并发连接数",
DECODE(MAX_CPU_NUM, MAX_CPU_NUM, MAX_CPU_NUM) AS "最大CPU数目",
DECODE(NOACTIVE_DEADLINE, NOACTIVE_DEADLINE, NOACTIVE_DEADLINE) AS "未激活状态截止日期",
DECODE(HARDWARE_ID, HARDWARE_ID, HARDWARE_ID) AS "绑定的硬件编码",
DECODE(CHECK_CODE, CHECK_CODE, CHECK_CODE) AS "校验码",
DECODE(PRODUCT_TYPE, PRODUCT_TYPE, PRODUCT_TYPE) AS "产品类型",
DECODE(CPU_TYPE, CPU_TYPE, CPU_TYPE) AS "授权运行的CPU类型",
DECODE(OS_TYPE, OS_TYPE, OS_TYPE) AS "授权运行的操作系统",
DECODE(MAX_CORE_NUM, 0, '无限制', NULL, '无限制', MAX_CORE_NUM) AS "最大CPU核个数",
DECODE(HARDWARE_TYPE, 1, 'MAC地址', 2, 'CPU ID', 3, '硬盘ID', '其他') AS "硬件绑定类型",
DECODE(DATE_GEN, DATE_GEN, DATE_GEN) AS "KEY生成日期",
DECODE(SERVER_SERIES_NAME, SERVER_SERIES_NAME, SERVER_SERIES_NAME) AS "定制版版本名称",
DECODE(TABLE_RECORD_NUMBER_LIMIT, 0, '无限制', NULL, '无限制', TABLE_RECORD_NUMBER_LIMIT || '万') AS "单表最大数据行数限制",
DECODE(TOTAL_SPACE_LIMIT, 0, '无限制', NULL, '无限制', TOTAL_SPACE_LIMIT || 'GB') AS "数据总空间大小限制"
FROM V$LICENSE;刷新并查看授权

也可使用:
sp_load_lic_info;
-- 查询授权详细信息
SELECT * FROM V$LICENSE查询完整授权信息
附:V$license视图的字段介绍
更换正式授权:
将购买的dm.key(如名称不一致请重命名)/opt/dmdata/README.md同目录下后重启数据库

即可完成数据库授权key导入
总结
本次构建成功构建出达梦8数据库docker镜像,相关思路来源于网络,非容器化唯一方法
虽使用x86环境,但相关方法仍可用在arm、海思、等平台镜像构建
如有错误欢迎指正,交流
如文章侵犯到您的利益,请第一时间联系删除
达梦数据库容器化实践
https://wcyuns.cn/archives/dm8-docker
Comments