Fix: OceanBase tenant startup drift and docs (#15829)

### What problem does this PR solve?

OceanBase could start without the `ragflow` tenant, so RAGFlow failed to
connect with `root@ragflow`. This PR adds a safe startup reconcile step
and documents the required host limits before using OceanBase.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
- [x] Documentation Update
This commit is contained in:
Idriss Sbaaoui
2026-06-09 13:04:05 +08:00
committed by GitHub
parent 93e4f6bc09
commit faf78d3069
3 changed files with 162 additions and 1 deletions

View File

@@ -119,6 +119,46 @@ The [.env](./.env) file contains important environment variables for Docker.
- `EMBEDDING_BATCH_SIZE`
The number of text chunks processed in a single batch during embedding vectorization. Defaults to `16`.
### OceanBase prerequisites
Before setting `DOC_ENGINE=oceanbase`, make sure the host OS allows the file descriptor and core dump limits OceanBase expects.
1. Set host limits:
```bash
sudo tee /etc/security/limits.d/99-oceanbase.conf >/dev/null <<'EOF'
root soft nofile 655350
root hard nofile 655350
* soft nofile 655350
* hard nofile 655350
* soft core unlimited
* hard core unlimited
EOF
```
2. Make sure PAM limits are enabled:
```bash
grep -E 'pam_limits\.so' /etc/pam.d/common-session /etc/pam.d/common-session-noninteractive
```
If missing, add them:
```bash
echo 'session required pam_limits.so' | sudo tee -a /etc/pam.d/common-session
echo 'session required pam_limits.so' | sudo tee -a /etc/pam.d/common-session-noninteractive
```
3. Log out and log back in, or reboot.
4. Verify the effective limit:
```bash
ulimit -n
```
Expected: `655350`, or at least `20000`.
## 🐋 Service configuration
[service_conf.yaml](./service_conf.yaml) specifies the system-level configuration for RAGFlow and is used by its API server and task executor. In a dockerized setup, this file is automatically created based on the [service_conf.yaml.template](./service_conf.yaml.template) file (replacing all environment variables by their values).

View File

@@ -104,10 +104,16 @@ services:
profiles:
- oceanbase
image: oceanbase/oceanbase-ce:4.4.1.0-100000032025101610
entrypoint: ["bash", "/root/boot/ragflow-oceanbase-entrypoint.sh"]
ulimits:
nofile:
soft: 655350
hard: 655350
volumes:
- ./oceanbase/data:/root/ob
- ./oceanbase/conf:/root/.obd/cluster
- ./oceanbase/init.d:/root/boot/init.d
- ./oceanbase-entrypoint.sh:/root/boot/ragflow-oceanbase-entrypoint.sh:ro
ports:
- ${OCEANBASE_PORT:-2881}:2881
env_file: .env

115
docker/oceanbase-entrypoint.sh Executable file
View File

@@ -0,0 +1,115 @@
#!/bin/bash
set -euo pipefail
log() {
echo "[ragflow-ob-entrypoint] $*"
}
ob_sys() {
obclient -h127.0.0.1 -P2881 -uroot@sys -p"${OB_SYS_PASSWORD}" -Doceanbase -A -N -e "$1"
}
ob_tenant_with_password() {
obclient -h127.0.0.1 -P2881 -uroot@"${OB_TENANT_NAME}" -p"${OB_TENANT_PASSWORD}" -A -N -e "$1"
}
ob_tenant_without_password() {
obclient -h127.0.0.1 -P2881 -uroot@"${OB_TENANT_NAME}" -A -N -e "$1"
}
wait_for_sys() {
for _ in $(seq 1 120); do
if ob_sys "SELECT 1" >/dev/null 2>&1; then
return 0
fi
sleep 1
done
return 1
}
tenant_exists() {
ob_sys "SELECT 1 FROM oceanbase.DBA_OB_TENANTS WHERE tenant_name='${OB_TENANT_NAME}'" 2>/dev/null | grep -q '^1$'
}
wait_for_tenant_password() {
for _ in $(seq 1 60); do
if ob_tenant_with_password "SELECT 1" >/dev/null 2>&1; then
return 0
fi
sleep 1
done
return 1
}
ensure_tenant_ready() {
if ob_tenant_with_password "SELECT 1" >/dev/null 2>&1; then
log "tenant ${OB_TENANT_NAME} accepts the configured password"
return 0
fi
if tenant_exists; then
for _ in $(seq 1 120); do
if ob_tenant_with_password "SELECT 1" >/dev/null 2>&1; then
log "tenant ${OB_TENANT_NAME} became reachable with the configured password"
return 0
fi
if ob_tenant_without_password "SELECT 1" >/dev/null 2>&1; then
log "tenant ${OB_TENANT_NAME} exists with an empty root password; applying OB_TENANT_PASSWORD"
ob_tenant_without_password "ALTER USER root IDENTIFIED BY '${OB_TENANT_PASSWORD}'" >/dev/null 2>&1 || {
log "warning: failed to update the tenant root password"
return 1
}
wait_for_tenant_password && return 0
log "warning: tenant password update did not become effective in time"
return 1
fi
sleep 1
done
log "warning: tenant ${OB_TENANT_NAME} exists but never accepted the configured or empty password during reconciliation"
return 1
fi
log "tenant ${OB_TENANT_NAME} is missing; creating it with the configured password"
if ! obd cluster tenant create obcluster -n "${OB_TENANT_NAME}" -o "${OB_SCENARIO:-htap}" --password "${OB_TENANT_PASSWORD}" >/dev/null 2>&1; then
log "warning: failed to create tenant ${OB_TENANT_NAME}"
return 1
fi
if wait_for_tenant_password; then
return 0
fi
log "warning: tenant ${OB_TENANT_NAME} did not become connectable in time"
return 1
}
ensure_database() {
if ob_tenant_with_password "CREATE DATABASE IF NOT EXISTS \`${OCEANBASE_DOC_DBNAME}\`" >/dev/null 2>&1; then
log "database ${OCEANBASE_DOC_DBNAME} is ready in tenant ${OB_TENANT_NAME}"
return 0
fi
log "warning: failed to ensure database ${OCEANBASE_DOC_DBNAME}"
return 1
}
reconcile_oceanbase() {
if ! wait_for_sys; then
log "warning: sys tenant never became reachable; skipping reconciliation"
return 0
fi
ensure_tenant_ready || return 0
ensure_database || return 0
}
/usr/sbin/sshd
/root/boot/start.sh &
start_pid=$!
reconcile_oceanbase || true &
wait "${start_pid}"