K8S部署达梦数据库

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
posted @ 2026-05-06 03:24  明月心~  阅读(59)  评论(0)    收藏  举报