K8S部署达梦数据库
构建安装包build-dm8-centos7.sh
#!/bin/bash
set -e
mkdir -p /data/download
cd /data/download
wget https://download.dameng.com/eco/adapter/DM8/202603/dm8_20260312_x86_CentOS7_64.zip
unzip dm8_20260312_x86_CentOS7_64.zip
ISO_PATH="/data/download/dm8_20260312_x86_CentOS7_64.iso"
HARBOR_REGISTRY="10.13.8.27:30082"
IMAGE_NAME="library/dm8"
IMAGE_TAG="centos7-8.1.1.190"
FULL_IMAGE="${HARBOR_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"
WORK_DIR="/tmp/dm8-centos7-build"
ISO_MOUNT="/mnt/dm8-iso"
echo "开始构建达梦数据库 DM8 镜像..."
rm -rf ${WORK_DIR}
mkdir -p ${WORK_DIR}/installer ${WORK_DIR}/rpms
sudo mkdir -p ${ISO_MOUNT}
echo "挂载 ISO 并复制安装文件..."
sudo mount -o loop ${ISO_PATH} ${ISO_MOUNT}
cp ${ISO_MOUNT}/DMInstall.bin ${WORK_DIR}/installer/
sudo umount ${ISO_MOUNT}
sudo rmdir ${ISO_MOUNT}
# 下载依赖包(如果已存在则跳过)
echo "下载依赖 rpm 包..."
cd ${WORK_DIR}/rpms
if [ ! -f libaio-0.3.109-13.el7.x86_64.rpm ]; then
curl -L -o libaio-0.3.109-13.el7.x86_64.rpm \
http://vault.centos.org/7.9.2009/os/x86_64/Packages/libaio-0.3.109-13.el7.x86_64.rpm
fi
if [ ! -f numactl-libs-2.0.12-5.el7.x86_64.rpm ]; then
curl -L -o numactl-libs-2.0.12-5.el7.x86_64.rpm \
http://vault.centos.org/7.9.2009/os/x86_64/Packages/numactl-libs-2.0.12-5.el7.x86_64.rpm
fi
cd ${WORK_DIR}
# 安装配置文件
cat > ${WORK_DIR}/installer/auto_install.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<DATABASE>
<LANGUAGE>ZH</LANGUAGE>
<TIME_ZONE>+08:00</TIME_ZONE>
<KEY></KEY>
<INSTALL_TYPE>1</INSTALL_TYPE>
<INSTALL_PATH>/opt/dmdbms</INSTALL_PATH>
<INSTALL_USER>dmdba</INSTALL_USER>
<INSTALL_GROUP>dinstall</INSTALL_GROUP>
<INIT_DB>n</INIT_DB>
</DATABASE>
EOF
cat > ${WORK_DIR}/Dockerfile << 'DOCKERFILE_EOF'
FROM centos:7
ENV DM_HOME=/opt/dmdbms
ENV PATH=$DM_HOME/bin:$PATH
ENV LD_LIBRARY_PATH=$DM_HOME/bin:$LD_LIBRARY_PATH
ENV DM_DATA_PATH=/opt/dmdbms/data
ENV DM_INIT_PATH=/opt/dmdbms/data
# 复制并安装依赖
COPY rpms/*.rpm /tmp/
RUN cd /tmp && \
rpm -ivh --nodeps --noscripts --notriggers *.rpm && \
rm -f /tmp/*.rpm
# 生成中文 locale
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8 2>/dev/null || true
ENV LANG=zh_CN.UTF-8 \
LC_ALL=zh_CN.UTF-8 \
LANGUAGE=zh_CN:zh
# 创建 dmdba 用户
RUN groupadd -g 1001 dinstall && \
useradd -u 1001 -g dinstall -m -d /home/dmdba -s /bin/bash dmdba && \
echo "dmdba:dameng123" | chpasswd
COPY installer/ /tmp/installer/
# 安装 DM8
RUN chmod +x /tmp/installer/DMInstall.bin && \
LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 LANGUAGE=zh_CN:zh \
/tmp/installer/DMInstall.bin -q /tmp/installer/auto_install.xml && \
echo "安装完成,验证:" && \
ls -la /opt/dmdbms/bin/dminit && \
rm -rf /tmp/installer
# 创建数据目录并设置权限
RUN mkdir -p ${DM_DATA_PATH} /var/log/dm8 && \
chown -R dmdba:dinstall ${DM_HOME} ${DM_DATA_PATH} /var/log/dm8
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
USER dmdba
WORKDIR ${DM_HOME}
EXPOSE 5236 5237
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["dmserver", "/opt/dmdbms/data/DAMENG/dm.ini"]
DOCKERFILE_EOF
# 修复后的 entrypoint.sh(移除 LENGTH_IN_CHAR)
cat > ${WORK_DIR}/docker-entrypoint.sh << 'ENTRYPOINT_EOF'
#!/bin/bash
set -e
echo "========================================="
echo "达梦数据库容器启动"
echo "========================================="
echo "当前用户: $(whoami) (UID: $(id -u))"
echo "主机名: $(hostname)"
echo ""
export LD_LIBRARY_PATH=/opt/dmdbms/bin:$LD_LIBRARY_PATH
export PATH=/opt/dmdbms/bin:$PATH
# 检查并创建数据目录
if [ ! -d "${DM_DATA_PATH}" ]; then
mkdir -p ${DM_DATA_PATH}
fi
# 确保权限
chmod 755 ${DM_DATA_PATH} 2>/dev/null || true
echo "数据目录:"
ls -la ${DM_DATA_PATH}/
# 检查是否需要初始化
echo ""
echo "检查数据库状态..."
if [ -f "${DM_DATA_PATH}/DAMENG/dm.ini" ]; then
echo "✅ dm.ini 存在"
echo "文件大小: $(stat -c%s ${DM_DATA_PATH}/DAMENG/dm.ini 2>/dev/null || wc -c < ${DM_DATA_PATH}/DAMENG/dm.ini) bytes"
else
echo "📌 需要初始化数据库"
# 清理
rm -rf ${DM_DATA_PATH}/DAMENG
echo "开始初始化..."
/opt/dmdbms/bin/dminit \
PATH="${DM_INIT_PATH}" \
DB_NAME=DAMENG \
INSTANCE_NAME=DMSERVER \
LOG_SIZE=${DM_LOG_SIZE:-256} \
SYSDBA_PWD="${SYSDBA_PWD}" \
SYSAUDITOR_PWD="${SYSAUDITOR_PWD:-${SYSDBA_PWD}}" \
PAGE_SIZE="${DM_INIT_PAGE_SIZE:-16}" \
EXTENT_SIZE="${DM_INIT_EXTENT_SIZE:-16}" \
CHARSET="${DM_INIT_CHARSET:-1}" \
CASE_SENSITIVE="${DM_INIT_CASE_SENSITIVE:-0}" \
UNICODE_FLAG="${DM_INIT_UNICODE_FLAG:-1}"
if [ $? -ne 0 ]; then
echo "❌ 初始化失败"
exit 1
fi
echo "✅ 初始化完成"
ls -la ${DM_DATA_PATH}/
ls -la ${DM_DATA_PATH}/DAMENG/
fi
# 简单粗暴地修复 dm.ini
echo ""
echo "修复 dm.ini 配置..."
cd ${DM_DATA_PATH}/DAMENG
# 备份(如果还没备份)
if [ ! -f dm.ini.bak ]; then
cp dm.ini dm.ini.bak
echo "已备份 dm.ini"
fi
# 确保 BUFFER 配置存在且合理
echo "正在优化内存配置..."
sed -i 's|^\([[:space:]]*BUFFER[[:space:]]*=\).*|\1 500|i' dm.ini
sed -i 's|^\([[:space:]]*MAX_BUFFER[[:space:]]*=\).*|\1 500|i' dm.ini
sed -i 's|^\([[:space:]]*BUFFER_POOLS[[:space:]]*=\).*|\1 3|i' dm.ini
sed -i 's|^\([[:space:]]*MAX_SESSIONS[[:space:]]*=\).*|\1 100|i' dm.ini
sed -i 's|^\([[:space:]]*RECYCLE[[:space:]]*=\).*|\1 50|i' dm.ini
# 确保权限
chown dmdba:dinstall dm.ini 2>/dev/null || true
chmod 644 dm.ini
echo "配置修复完成"
# 验证(快速检查,不会卡住)
echo "验证配置..."
if head -1 dm.ini > /dev/null 2>&1; then
echo "✅ dm.ini 可读"
else
echo "❌ dm.ini 不可读!"
exit 1
fi
# 创建必要目录
mkdir -p ctl_bak HMAIN bak 2>/dev/null || true
chown -R dmdba:dinstall . 2>/dev/null || true
# 启动
echo ""
echo "========================================="
echo "启动达梦数据库..."
echo "配置文件: $(pwd)/dm.ini"
echo "========================================="
echo ""
# 直接启动,不用 grep 检查
exec /opt/dmdbms/bin/dmserver "$(pwd)/dm.ini"
ENTRYPOINT_EOF
chmod +x ${WORK_DIR}/docker-entrypoint.sh
cd ${WORK_DIR}
# 构建
docker build --no-cache --network=host -t ${FULL_IMAGE} .
docker push ${FULL_IMAGE}
rm -rf ${WORK_DIR}
echo "✅ 镜像构建完成: ${FULL_IMAGE}"
echo ""
echo "测试命令:"
echo "kubectl run dm-test --rm -it --restart=Never \\"
echo " --image=${FULL_IMAGE} \\"
echo " --env=\"SYSDBA_PWD=Dameng@123\" \\"
echo " --env=\"SYSAUDITOR_PWD=Dameng@456\" \\"
echo " -- /bin/bash"
部署脚本 middleware/dm.sh
#!/bin/bash
# /data/k8s-deploy-templates/scripts/middleware/dm.sh
set -e
SCRIPT_DIR=$(cd "$(dirname "$0")/.." && pwd)
source "$SCRIPT_DIR/env.sh"
source "$SCRIPT_DIR/common.sh"
DM_IMAGE=${DM_IMAGE:-"10.13.8.27:30082/library/dm8:centos7-8.1.1.190"}
DM_STORAGE_SIZE=${DM_STORAGE_SIZE:-8Gi}
DM_LOG_SIZE=${DM_LOG_SIZE:-256}
DM_CPU_REQUEST=${DM_CPU_REQUEST:-2}
DM_CPU_LIMIT=${DM_CPU_LIMIT:-2}
DM_MEMORY_REQUEST=${DM_MEMORY_REQUEST:-4Gi}
DM_MEMORY_LIMIT=${DM_MEMORY_LIMIT:-4Gi}
deploy_dm() {
local PROJECT_NAME=$1
local DEPLOY_NODE=${2:-k8s-worker-test1}
local STORAGE_SIZE=${3:-$DM_STORAGE_SIZE}
log_info "开始部署达梦数据库 DM8..."
# 生成密码
local SYSDBA_PWD="Dameng@$(date +%s | sha256sum | base64 | head -c 8)"
local SYSAUDITOR_PWD="Dameng@$(date +%s | sha256sum | base64 | head -c 8)"
# 创建 Secret
kubectl create secret generic ${PROJECT_NAME}-dm-secret \
--namespace=${PROJECT_NAME} \
--from-literal=SYSDBA_PWD="${SYSDBA_PWD}" \
--from-literal=SYSAUDITOR_PWD="${SYSAUDITOR_PWD}" \
--from-literal=DM_INIT_PAGE_SIZE=16 \
--from-literal=DM_INIT_EXTENT_SIZE=16 \
--from-literal=DM_INIT_CHARSET=1 \
--from-literal=DM_INIT_CASE_SENSITIVE=0 \
--from-literal=DM_INIT_UNICODE_FLAG=1 \
--dry-run=client -o yaml | kubectl apply -f -
# 创建 PVC
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ${PROJECT_NAME}-dm-data-pvc
namespace: ${PROJECT_NAME}
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: ${STORAGE_SIZE}
EOF
# 创建 StatefulSet(修复版:InitContainer 不创建 DAMENG 目录)
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: ${PROJECT_NAME}-dm
namespace: ${PROJECT_NAME}
spec:
replicas: 1
serviceName: ${PROJECT_NAME}-dm
selector:
matchLabels:
app: ${PROJECT_NAME}-dm
template:
metadata:
labels:
app: ${PROJECT_NAME}-dm
spec:
nodeSelector:
kubernetes.io/hostname: ${DEPLOY_NODE}
# InitContainer: 只修复权限,不创建任何目录结构
initContainers:
- name: fix-data-permissions
image: ${DM_IMAGE}
command:
- /bin/bash
- -c
- |
echo "========================================="
echo "InitContainer: 修复数据目录权限"
echo "========================================="
echo "当前用户: $(whoami) (UID: $(id -u))"
# 确保挂载点目录存在
mkdir -p /opt/dmdbms/data
# 设置 /opt/dmdbms/data 目录属主为 dmdba:dinstall
# 使用数值 UID/GID 避免用户不存在的问题
chown 1001:1001 /opt/dmdbms/data
chmod 755 /opt/dmdbms/data
# 关键:不创建 DAMENG 目录!
# 让数据库初始化(dminit)自己创建
echo ""
echo "当前数据目录内容:"
ls -la /opt/dmdbms/data/ || echo " (目录为空)"
echo ""
echo "权限修复完成!"
echo "========================================="
volumeMounts:
- name: data
mountPath: /opt/dmdbms/data
securityContext:
runAsUser: 0
runAsGroup: 0
containers:
- name: dm8
image: ${DM_IMAGE}
imagePullPolicy: Always
ports:
- containerPort: 5236
name: dm-port
env:
- name: SYSDBA_PWD
valueFrom:
secretKeyRef:
name: ${PROJECT_NAME}-dm-secret
key: SYSDBA_PWD
- name: SYSAUDITOR_PWD
valueFrom:
secretKeyRef:
name: ${PROJECT_NAME}-dm-secret
key: SYSAUDITOR_PWD
- name: DM_INIT_PAGE_SIZE
valueFrom:
secretKeyRef:
name: ${PROJECT_NAME}-dm-secret
key: DM_INIT_PAGE_SIZE
- name: DM_INIT_EXTENT_SIZE
valueFrom:
secretKeyRef:
name: ${PROJECT_NAME}-dm-secret
key: DM_INIT_EXTENT_SIZE
- name: DM_INIT_CHARSET
valueFrom:
secretKeyRef:
name: ${PROJECT_NAME}-dm-secret
key: DM_INIT_CHARSET
- name: DM_INIT_CASE_SENSITIVE
valueFrom:
secretKeyRef:
name: ${PROJECT_NAME}-dm-secret
key: DM_INIT_CASE_SENSITIVE
- name: DM_INIT_UNICODE_FLAG
valueFrom:
secretKeyRef:
name: ${PROJECT_NAME}-dm-secret
key: DM_INIT_UNICODE_FLAG
volumeMounts:
- name: data
mountPath: /opt/dmdbms/data
resources:
requests:
memory: "${DM_MEMORY_REQUEST}"
cpu: "${DM_CPU_REQUEST}"
limits:
memory: "${DM_MEMORY_LIMIT}"
cpu: "${DM_CPU_LIMIT}"
volumes:
- name: data
persistentVolumeClaim:
claimName: ${PROJECT_NAME}-dm-data-pvc
EOF
# 创建 Headless Service
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: ${PROJECT_NAME}-dm-headless
namespace: ${PROJECT_NAME}
spec:
clusterIP: None
selector:
app: ${PROJECT_NAME}-dm
ports:
- port: 5236
targetPort: 5236
EOF
# 保存密码
mkdir -p /data/server/${PROJECT_NAME}
echo "SYSDBA 密码: ${SYSDBA_PWD}" > /data/server/${PROJECT_NAME}/dm_info.txt
echo "SYSAUDITOR 密码: ${SYSAUDITOR_PWD}" >> /data/server/${PROJECT_NAME}/dm_info.txt
echo "连接地址: ${PROJECT_NAME}-dm-headless.${PROJECT_NAME}.svc.cluster.local:5236" >> /data/server/${PROJECT_NAME}/dm_info.txt
log_info "等待 Pod 就绪..."
kubectl wait --for=condition=ready pod -l app=${PROJECT_NAME}-dm -n ${PROJECT_NAME} --timeout=180s || true
echo ""
echo "========================================="
echo "✅ 达梦数据库 DM8 部署完成!"
echo "========================================="
echo "密码已保存到: /data/server/${PROJECT_NAME}/dm_info.txt"
cat /data/server/${PROJECT_NAME}/dm_info.txt
}
delete_dm() {
local PROJECT_NAME=$1
kubectl delete statefulset ${PROJECT_NAME}-dm -n ${PROJECT_NAME} --ignore-not-found=true
kubectl delete service ${PROJECT_NAME}-dm-headless -n ${PROJECT_NAME} --ignore-not-found=true
kubectl delete pvc ${PROJECT_NAME}-dm-data-pvc -n ${PROJECT_NAME} --ignore-not-found=true
kubectl delete secret ${PROJECT_NAME}-dm-secret -n ${PROJECT_NAME} --ignore-not-found=true
kubectl delete pod -l app=${PROJECT_NAME}-dm -n ${PROJECT_NAME} --force --grace-period=0 --ignore-not-found=true
log_info "达梦数据库已删除"
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
case "$1" in
delete)
shift
delete_dm "$@"
;;
*)
deploy_dm "$@"
;;
esac
fi
执行部署
# 1. 完全清理旧部署
./middleware/dm.sh delete uprr
# 2. 确保 PVC 完全删除
kubectl get pvc -n uprr | grep dm
# 如果还存在,强制删除
kubectl delete pvc uprr-dm-data-pvc -n uprr --force --grace-period=0
# 3. 等待资源完全清理
sleep 10
# 4. 使用修复后的脚本重新部署
./middleware/dm.sh uprr k8s-worker-test1
# 5. 实时查看部署状态
watch -n 1 'kubectl get pod -n uprr -l app=uprr-dm'
# 6. 查看 InitContainer 日志(确认权限且无空目录)
kubectl logs -n uprr uprr-dm-0 -c fix-data-permissions
# 7. 查看主容器日志(应该看到完整的初始化过程)
kubectl logs -n uprr uprr-dm-0 -f