mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-06-29 15:31:05 +08:00
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:
@@ -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).
|
||||
@@ -268,4 +308,4 @@ If you already have SSL certificates from another provider:
|
||||
1. Place your certificates in a directory accessible to Docker
|
||||
2. Update the volume paths in `docker-compose.yml` to point to your certificate files
|
||||
3. Ensure the certificate file contains the full certificate chain
|
||||
4. Follow steps 4-5 from the Let's Encrypt guide above
|
||||
4. Follow steps 4-5 from the Let's Encrypt guide above
|
||||
|
||||
@@ -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
115
docker/oceanbase-entrypoint.sh
Executable 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}"
|
||||
Reference in New Issue
Block a user