1- # Build sqlbot
2- FROM ghcr.io/1panel-dev/maxkb-vector-model:v1.0.1 AS vector-model
3- FROM --platform=${BUILDPLATFORM} registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-base:latest AS sqlbot-ui-builder
4- ENV SQLBOT_HOME=/opt/sqlbot
5- ENV APP_HOME=${SQLBOT_HOME}/app
6- ENV UI_HOME=${SQLBOT_HOME}/frontend
7- ENV DEBIAN_FRONTEND=noninteractive
8-
9- RUN mkdir -p ${APP_HOME} ${UI_HOME}
10-
11- COPY frontend /tmp/frontend
12- RUN cd /tmp/frontend && npm install && npm run build && mv dist ${UI_HOME}/dist
13-
14-
15- FROM registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-base:latest AS sqlbot-builder
16- # Set build environment variables
17- ENV PYTHONUNBUFFERED=1
18- ENV SQLBOT_HOME=/opt/sqlbot
19- ENV APP_HOME=${SQLBOT_HOME}/app
20- ENV UI_HOME=${SQLBOT_HOME}/frontend
21- ENV PYTHONPATH=${SQLBOT_HOME}/app
22- ENV PATH="${APP_HOME}/.venv/bin:$PATH"
23- ENV UV_COMPILE_BYTECODE=1
24- ENV UV_LINK_MODE=copy
25- ENV DEBIAN_FRONTEND=noninteractive
26-
27- # Create necessary directories
28- RUN mkdir -p ${APP_HOME} ${UI_HOME}
1+ # syntax=docker/dockerfile:1
2+ ARG SQLBOT_RUNTIME_IMAGE=registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-python-pg:latest
3+ ARG NODE_IMAGE=node:22-bookworm-slim
294
30- WORKDIR ${APP_HOME}
31-
32- COPY --from=sqlbot-ui-builder ${UI_HOME} ${UI_HOME}
33- # Install dependencies
34- RUN test -f "./uv.lock" && \
35- --mount=type=cache,target=/root/.cache/uv \
36- --mount=type=bind,source=backend/uv.lock,target=uv.lock \
37- --mount=type=bind,source=backend/pyproject.toml,target=pyproject.toml \
38- uv sync --frozen --no-install-project || echo "uv.lock file not found, skipping intermediate-layers"
5+ FROM ghcr.io/1panel-dev/maxkb-vector-model:v1.0.1 AS vector-model
396
40- COPY ./backend ${APP_HOME}
7+ FROM --platform=$BUILDPLATFORM ${NODE_IMAGE} AS sqlbot-ui-builder
8+ WORKDIR /tmp/frontend
9+ COPY frontend/ ./
10+ RUN npm install && npm run build
11+
12+ FROM ${SQLBOT_RUNTIME_IMAGE} AS runtime-base
13+ # Rebuild Dockerfile-base first, then point this build at the rebuilt image.
14+ RUN if ! node -e 'if (process.versions.node.split(".")[0] !== "22") process.exit(1)' \
15+ || [ -e /opt/dmdbms/bin/libssl.so ] \
16+ || ! dpkg --compare-versions "$(dpkg-query -W -f='${Version}' libharfbuzz0b)" ge '6.0.0+dfsg-3+sqlbot1' \
17+ || dpkg-query -W libtiff6 >/dev/null 2>&1; then \
18+ echo 'Rebuild Dockerfile-base and set SQLBOT_RUNTIME_IMAGE to the new image.' >&2; \
19+ exit 1; \
20+ fi
21+
22+ FROM runtime-base AS driver-toolchain
23+ RUN apt-get -o APT::Update::Error-Mode=any update \
24+ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
25+ build-essential libpq-dev libssl-dev libkrb5-dev pkg-config \
26+ && rm -rf /var/lib/apt/lists/*
27+ # Match the FreeTDS release used by pymssql 2.4.6 wheels and link it to
28+ # the runtime's maintained OpenSSL and Kerberos libraries.
29+ RUN set -eu; \
30+ curl -fsSL --retry 3 https://www.freetds.org/files/stable/freetds-1.5.19.tar.gz -o /tmp/freetds.tar.gz; \
31+ echo 'ff70d0c8ae8dd23e7b1314274d6e9d30b479998415760b3fa656754b737c2bd6 /tmp/freetds.tar.gz' | sha256sum -c -; \
32+ mkdir /tmp/freetds; \
33+ tar -xzf /tmp/freetds.tar.gz --strip-components=1 -C /tmp/freetds; \
34+ cd /tmp/freetds; \
35+ ./configure --prefix=/usr/local --sysconfdir=/etc/freetds --enable-msdblib \
36+ --with-tdsver=auto --with-openssl=yes --with-gnutls=no --enable-krb5 \
37+ --disable-static --disable-odbc --disable-apps --disable-server --disable-pool; \
38+ make -j "$(nproc)" ; \
39+ make install; \
40+ install -D -m 0644 COPYING_LIB.txt /usr/local/share/doc/freetds/COPYING_LIB.txt; \
41+ ldconfig; \
42+ cd /; \
43+ rm -rf /tmp/freetds /tmp/freetds.tar.gz
44+ ENV LINK_FREETDS_STATICALLY=NO \
45+ PYMSSQL_FREETDS=/usr/local
46+
47+ FROM driver-toolchain AS sqlbot-builder
48+ ENV PYTHONUNBUFFERED=1 \
49+ PYTHONPATH=/opt/sqlbot/app \
50+ UV_COMPILE_BYTECODE=1 \
51+ UV_LINK_MODE=copy \
52+ UV_PYTHON_DOWNLOADS=never
53+ WORKDIR /opt/sqlbot/app
54+ COPY backend/ ./
55+
56+ # Resolve the security constraints together with the application dependencies.
57+ # Elasticsearch 7.17.13 permits urllib3 2.x on Python 3.11. The source-built
58+ # PostgreSQL and SQL Server drivers use the same patched OS libraries as runtime.
59+ RUN python - <<'PY'
60+ from pathlib import Path
61+
62+ project = Path('pyproject.toml' )
63+ contents = project.read_text()
64+ for old, new in (
65+ ('psycopg[binary]<4.0.0,>=3.1.13' , 'psycopg[c]<4.0.0,>=3.1.13' ),
66+ ('psycopg2-binary (>=2.9.12,<3.0.0)' , 'psycopg2 (>=2.9.12,<3.0.0)' ),
67+ ('elasticsearch[requests] (>=7.10,<8.0)' , 'elasticsearch[requests] (>=7.17.13,<8.0)' ),
68+ ('dmpython==2.5.22' , 'dmpython==2.6.1' ),
69+ ):
70+ assert contents.count(old) == 1, old
71+ contents = contents.replace(old, new)
72+ contents = contents.replace(
73+ '[tool.uv]\n ' ,
74+ '[tool.uv]\n constraint-dependencies = ["idna>=3.7", "setuptools>=78.1.1", "urllib3>=2.2.2,<3", "pymssql==2.4.6"]\n ' ,
75+ 1,
76+ )
77+ project.write_text(contents)
78+ PY
4179
42- # Final sync to ensure all dependencies are installed
4380RUN --mount=type=cache,target=/root/.cache/uv \
44- uv sync --extra cpu --default-index https://pypi.org/simple
45-
46- # Build g2-ssr
47- FROM registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-base:latest AS ssr-builder
81+ uv sync --no-dev --extra cpu --python /usr/local/bin/python3.11 \
82+ --default-index https://pypi.org/simple \
83+ --no-binary-package psycopg2 --no-binary-package pymssql \
84+ && uv pip check --python .venv/bin/python \
85+ && .venv/bin/python -c 'import psycopg, psycopg2, pymssql; assert psycopg.pq.__impl__ == "c"'
4886
87+ FROM ${NODE_IMAGE} AS ssr-builder
4988WORKDIR /app
50-
51- # Install build dependencies
52- RUN apt-get update && apt-get install -y --no-install-recommends \
53- build-essential python3 pkg-config \
54- libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev \
55- libpixman-1-dev libfreetype6-dev \
89+ RUN apt-get -o APT::Update::Error-Mode=any update \
90+ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
91+ build-essential python3 pkg-config \
92+ libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev \
93+ libpixman-1-dev libfreetype6-dev \
5694 && rm -rf /var/lib/apt/lists/*
57-
58- # configure npm
59- RUN npm config set fund false \
60- && npm config set audit false \
61- && npm config set progress false
62-
63- COPY g2-ssr/app.js g2-ssr/package.json /app/
64- COPY g2-ssr/charts/* /app/charts/
65- RUN npm install
66-
67- # Runtime stage
68- FROM registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-python-pg:latest
69-
95+ COPY g2-ssr/app.js g2-ssr/package.json ./
96+ COPY g2-ssr/charts/ ./charts/
97+ # g2-ssr uses canvas. Drop the unused node-canvas fork, which targets old V8.
98+ # Build the Node 22-compatible canvas release against distro libraries.
99+ RUN npm pkg delete dependencies.node-canvas dependencies.nan \
100+ && npm pkg set 'overrides.canvas=^3.2.3' \
101+ && npm_config_build_from_source=true npm install --no-fund --no-audit --no-progress
102+
103+ FROM runtime-base
104+ COPY --from=driver-toolchain /usr/local/lib/libsybdb.so.5.* /usr/local/lib/
105+ COPY --from=driver-toolchain /etc/freetds/ /etc/freetds/
106+ COPY --from=driver-toolchain /usr/local/share/doc/freetds/COPYING_LIB.txt /usr/local/share/doc/freetds/COPYING_LIB.txt
107+ RUN ldconfig
70108RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
71109 echo "Asia/Shanghai" > /etc/timezone
72110
@@ -75,6 +113,8 @@ ENV PYTHONUNBUFFERED=1
75113ENV SQLBOT_HOME=/opt/sqlbot
76114ENV PYTHONPATH=${SQLBOT_HOME}/app
77115ENV PATH="${SQLBOT_HOME}/app/.venv/bin:$PATH"
116+ # The DM SSL symlinks need the wheel's hashed crypto library at load time.
117+ ENV LD_LIBRARY_PATH="${SQLBOT_HOME}/app/.venv/lib/python3.11/site-packages/dmpython.libs:$LD_LIBRARY_PATH"
78118
79119ENV POSTGRES_DB=sqlbot
80120ENV POSTGRES_USER=root
@@ -83,14 +123,23 @@ ENV POSTGRES_PASSWORD=Password123@pg
83123# Copy necessary files from builder
84124COPY start.sh /opt/sqlbot/app/start.sh
85125COPY g2-ssr/*.ttf /usr/share/fonts/truetype/liberation/
86- COPY --from=sqlbot-builder ${SQLBOT_HOME} ${SQLBOT_HOME}
87- COPY --from=ssr-builder /app /opt/sqlbot/g2-ssr
126+ COPY --from=sqlbot-builder /opt/sqlbot/app/ /opt/sqlbot/app/
127+ COPY --from=sqlbot-ui-builder /tmp/frontend/dist/ /opt/sqlbot/frontend/dist/
128+ COPY --from=ssr-builder /app/ /opt/sqlbot/g2-ssr/
88129COPY g2-ssr/supervisord.conf /etc/supervisor/conf.d/g2-ssr.conf
89130COPY --from=vector-model /opt/maxkb/app/model /opt/sqlbot/models
90131
91132WORKDIR ${SQLBOT_HOME}/app
92133
93- RUN mkdir -p /opt/sqlbot/images /opt/sqlbot/g2-ssr/logs
134+ RUN set -eu; \
135+ mkdir -p /opt/sqlbot/images /opt/sqlbot/g2-ssr/logs; \
136+ dmssl="$SQLBOT_HOME/app/.venv/lib/python3.11/site-packages/dmssl" ; \
137+ for library in libssl.so libcrypto.so; do \
138+ test -f "$dmssl/$library" ; \
139+ ln -s "$dmssl/$library" "$DM_HOME/bin/$library" ; \
140+ done; \
141+ python -c 'import ctypes, os, ssl; import dmPython, psycopg, psycopg2, pymssql; assert psycopg.pq.__impl__ == "c"; ctypes.CDLL(os.environ["DM_HOME"] + "/bin/libssl.so")' ; \
142+ node -e "require('/opt/sqlbot/g2-ssr/node_modules/@antv/g2-ssr')"
94143
95144EXPOSE 3000 8000 8001 5432
96145
0 commit comments