Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/workflows/build_and_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ on:
default: false
required: true
type: boolean
runtimeBaseImage:
description: 'SQLBot runtime base image (optional tag or digest override)'
required: false
type: string
architecture:
description: 'Architecture'
required: true
Expand Down Expand Up @@ -80,8 +84,10 @@ jobs:
username: ${{ secrets.ALIYUN_REGISTRY_USERNAME }}
password: ${{ secrets.ALIYUN_REGISTRY_PASSWORD }}
- name: Docker Buildx (build-and-push)
env:
SQLBOT_RUNTIME_IMAGE: ${{ inputs.runtimeBaseImage || 'registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-python-pg:latest' }}
run: |
docker buildx build --provenance=false --sbom=false --output "type=image,push=true" ${{ steps.prepare.outputs.buildx_args }}
docker buildx build --build-arg SQLBOT_RUNTIME_IMAGE --provenance=false --sbom=false --output "type=image,push=true" ${{ steps.prepare.outputs.buildx_args }}

build-and-push-to-dockerhub:
if: ${{ contains(github.event.inputs.registry, 'dockerhub') }}
Expand Down Expand Up @@ -128,5 +134,7 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker Buildx (build-and-push)
env:
SQLBOT_RUNTIME_IMAGE: ${{ inputs.runtimeBaseImage || 'registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-python-pg:latest' }}
run: |
docker buildx build --output "type=image,push=true" ${{ steps.prepare.outputs.buildx_args }}
docker buildx build --build-arg SQLBOT_RUNTIME_IMAGE --output "type=image,push=true" ${{ steps.prepare.outputs.buildx_args }}
4 changes: 2 additions & 2 deletions .github/workflows/build_base_and_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
password: ${{ secrets.ALIYUN_REGISTRY_PASSWORD }}
- name: Docker Buildx (build-and-push)
run: |
docker buildx build -f Dockerfile-base --output "type=image,push=true,oci-mediatypes=false" --provenance=false --sbom=false ${{ steps.prepare.outputs.buildx_args }}
docker buildx build --pull -f Dockerfile-base --output "type=image,push=true,oci-mediatypes=false" --provenance=false --sbom=false ${{ steps.prepare.outputs.buildx_args }}

build-and-push-to-dockerhub:
if: ${{ contains(github.event.inputs.registry, 'dockerhub') }}
Expand Down Expand Up @@ -105,4 +105,4 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker Buildx (build-and-push)
run: |
docker buildx build -f Dockerfile-base --output "type=image,push=true,oci-mediatypes=false" --provenance=false --sbom=false ${{ steps.prepare.outputs.buildx_args }}
docker buildx build --pull -f Dockerfile-base --output "type=image,push=true,oci-mediatypes=false" --provenance=false --sbom=false ${{ steps.prepare.outputs.buildx_args }}
179 changes: 114 additions & 65 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,72 +1,110 @@
# Build sqlbot
FROM ghcr.io/1panel-dev/maxkb-vector-model:v1.0.1 AS vector-model
FROM --platform=${BUILDPLATFORM} registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-base:latest AS sqlbot-ui-builder
ENV SQLBOT_HOME=/opt/sqlbot
ENV APP_HOME=${SQLBOT_HOME}/app
ENV UI_HOME=${SQLBOT_HOME}/frontend
ENV DEBIAN_FRONTEND=noninteractive

RUN mkdir -p ${APP_HOME} ${UI_HOME}

COPY frontend /tmp/frontend
RUN cd /tmp/frontend && npm install && npm run build && mv dist ${UI_HOME}/dist


FROM registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-base:latest AS sqlbot-builder
# Set build environment variables
ENV PYTHONUNBUFFERED=1
ENV SQLBOT_HOME=/opt/sqlbot
ENV APP_HOME=${SQLBOT_HOME}/app
ENV UI_HOME=${SQLBOT_HOME}/frontend
ENV PYTHONPATH=${SQLBOT_HOME}/app
ENV PATH="${APP_HOME}/.venv/bin:$PATH"
ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy
ENV DEBIAN_FRONTEND=noninteractive

# Create necessary directories
RUN mkdir -p ${APP_HOME} ${UI_HOME}
# syntax=docker/dockerfile:1
ARG SQLBOT_RUNTIME_IMAGE=registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-python-pg:latest
ARG NODE_IMAGE=node:22-bookworm-slim

WORKDIR ${APP_HOME}

COPY --from=sqlbot-ui-builder ${UI_HOME} ${UI_HOME}
# Install dependencies
RUN test -f "./uv.lock" && \
--mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=backend/uv.lock,target=uv.lock \
--mount=type=bind,source=backend/pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project || echo "uv.lock file not found, skipping intermediate-layers"
FROM ghcr.io/1panel-dev/maxkb-vector-model:v1.0.1 AS vector-model

COPY ./backend ${APP_HOME}
FROM --platform=$BUILDPLATFORM ${NODE_IMAGE} AS sqlbot-ui-builder
WORKDIR /tmp/frontend
COPY frontend/ ./
RUN npm install && npm run build

FROM ${SQLBOT_RUNTIME_IMAGE} AS runtime-base
# Rebuild Dockerfile-base first, then point this build at the rebuilt image.
RUN if ! node -e 'if (process.versions.node.split(".")[0] !== "22") process.exit(1)' \
|| [ -e /opt/dmdbms/bin/libssl.so ] \
|| ! dpkg --compare-versions "$(dpkg-query -W -f='${Version}' libharfbuzz0b)" ge '6.0.0+dfsg-3+sqlbot1' \
|| dpkg-query -W libtiff6 >/dev/null 2>&1; then \
echo 'Rebuild Dockerfile-base and set SQLBOT_RUNTIME_IMAGE to the new image.' >&2; \
exit 1; \
fi

FROM runtime-base AS driver-toolchain
RUN apt-get -o APT::Update::Error-Mode=any update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential libpq-dev libssl-dev libkrb5-dev pkg-config \
&& rm -rf /var/lib/apt/lists/*
# Match the FreeTDS release used by pymssql 2.4.6 wheels and link it to
# the runtime's maintained OpenSSL and Kerberos libraries.
RUN set -eu; \
curl -fsSL --retry 3 https://www.freetds.org/files/stable/freetds-1.5.19.tar.gz -o /tmp/freetds.tar.gz; \
echo 'ff70d0c8ae8dd23e7b1314274d6e9d30b479998415760b3fa656754b737c2bd6 /tmp/freetds.tar.gz' | sha256sum -c -; \
mkdir /tmp/freetds; \
tar -xzf /tmp/freetds.tar.gz --strip-components=1 -C /tmp/freetds; \
cd /tmp/freetds; \
./configure --prefix=/usr/local --sysconfdir=/etc/freetds --enable-msdblib \
--with-tdsver=auto --with-openssl=yes --with-gnutls=no --enable-krb5 \
--disable-static --disable-odbc --disable-apps --disable-server --disable-pool; \
make -j "$(nproc)"; \
make install; \
install -D -m 0644 COPYING_LIB.txt /usr/local/share/doc/freetds/COPYING_LIB.txt; \
ldconfig; \
cd /; \
rm -rf /tmp/freetds /tmp/freetds.tar.gz
ENV LINK_FREETDS_STATICALLY=NO \
PYMSSQL_FREETDS=/usr/local

FROM driver-toolchain AS sqlbot-builder
ENV PYTHONUNBUFFERED=1 \
PYTHONPATH=/opt/sqlbot/app \
UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy \
UV_PYTHON_DOWNLOADS=never
WORKDIR /opt/sqlbot/app
COPY backend/ ./

# Resolve the security constraints together with the application dependencies.
# Elasticsearch 7.17.13 permits urllib3 2.x on Python 3.11. The source-built
# PostgreSQL and SQL Server drivers use the same patched OS libraries as runtime.
RUN python - <<'PY'
from pathlib import Path

project = Path('pyproject.toml')
contents = project.read_text()
for old, new in (
('psycopg[binary]<4.0.0,>=3.1.13', 'psycopg[c]<4.0.0,>=3.1.13'),
('psycopg2-binary (>=2.9.12,<3.0.0)', 'psycopg2 (>=2.9.12,<3.0.0)'),
('elasticsearch[requests] (>=7.10,<8.0)', 'elasticsearch[requests] (>=7.17.13,<8.0)'),
('dmpython==2.5.22', 'dmpython==2.6.1'),
):
assert contents.count(old) == 1, old
contents = contents.replace(old, new)
contents = contents.replace(
'[tool.uv]\n',
'[tool.uv]\nconstraint-dependencies = ["idna>=3.7", "setuptools>=78.1.1", "urllib3>=2.2.2,<3", "pymssql==2.4.6"]\n',
1,
)
project.write_text(contents)
PY

# Final sync to ensure all dependencies are installed
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --extra cpu --default-index https://pypi.org/simple

# Build g2-ssr
FROM registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-base:latest AS ssr-builder
uv sync --no-dev --extra cpu --python /usr/local/bin/python3.11 \
--default-index https://pypi.org/simple \
--no-binary-package psycopg2 --no-binary-package pymssql \
&& uv pip check --python .venv/bin/python \
&& .venv/bin/python -c 'import psycopg, psycopg2, pymssql; assert psycopg.pq.__impl__ == "c"'

FROM ${NODE_IMAGE} AS ssr-builder
WORKDIR /app

# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential python3 pkg-config \
libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev \
libpixman-1-dev libfreetype6-dev \
RUN apt-get -o APT::Update::Error-Mode=any update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential python3 pkg-config \
libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev \
libpixman-1-dev libfreetype6-dev \
&& rm -rf /var/lib/apt/lists/*

# configure npm
RUN npm config set fund false \
&& npm config set audit false \
&& npm config set progress false

COPY g2-ssr/app.js g2-ssr/package.json /app/
COPY g2-ssr/charts/* /app/charts/
RUN npm install

# Runtime stage
FROM registry.cn-qingdao.aliyuncs.com/dataease/sqlbot-python-pg:latest

COPY g2-ssr/app.js g2-ssr/package.json ./
COPY g2-ssr/charts/ ./charts/
# g2-ssr uses canvas. Drop the unused node-canvas fork, which targets old V8.
# Build the Node 22-compatible canvas release against distro libraries.
RUN npm pkg delete dependencies.node-canvas dependencies.nan \
&& npm pkg set 'overrides.canvas=^3.2.3' \
&& npm_config_build_from_source=true npm install --no-fund --no-audit --no-progress

FROM runtime-base
COPY --from=driver-toolchain /usr/local/lib/libsybdb.so.5.* /usr/local/lib/
COPY --from=driver-toolchain /etc/freetds/ /etc/freetds/
COPY --from=driver-toolchain /usr/local/share/doc/freetds/COPYING_LIB.txt /usr/local/share/doc/freetds/COPYING_LIB.txt
RUN ldconfig
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone

Expand All @@ -75,6 +113,8 @@ ENV PYTHONUNBUFFERED=1
ENV SQLBOT_HOME=/opt/sqlbot
ENV PYTHONPATH=${SQLBOT_HOME}/app
ENV PATH="${SQLBOT_HOME}/app/.venv/bin:$PATH"
# The DM SSL symlinks need the wheel's hashed crypto library at load time.
ENV LD_LIBRARY_PATH="${SQLBOT_HOME}/app/.venv/lib/python3.11/site-packages/dmpython.libs:$LD_LIBRARY_PATH"

ENV POSTGRES_DB=sqlbot
ENV POSTGRES_USER=root
Expand All @@ -83,14 +123,23 @@ ENV POSTGRES_PASSWORD=Password123@pg
# Copy necessary files from builder
COPY start.sh /opt/sqlbot/app/start.sh
COPY g2-ssr/*.ttf /usr/share/fonts/truetype/liberation/
COPY --from=sqlbot-builder ${SQLBOT_HOME} ${SQLBOT_HOME}
COPY --from=ssr-builder /app /opt/sqlbot/g2-ssr
COPY --from=sqlbot-builder /opt/sqlbot/app/ /opt/sqlbot/app/
COPY --from=sqlbot-ui-builder /tmp/frontend/dist/ /opt/sqlbot/frontend/dist/
COPY --from=ssr-builder /app/ /opt/sqlbot/g2-ssr/
COPY g2-ssr/supervisord.conf /etc/supervisor/conf.d/g2-ssr.conf
COPY --from=vector-model /opt/maxkb/app/model /opt/sqlbot/models

WORKDIR ${SQLBOT_HOME}/app

RUN mkdir -p /opt/sqlbot/images /opt/sqlbot/g2-ssr/logs
RUN set -eu; \
mkdir -p /opt/sqlbot/images /opt/sqlbot/g2-ssr/logs; \
dmssl="$SQLBOT_HOME/app/.venv/lib/python3.11/site-packages/dmssl"; \
for library in libssl.so libcrypto.so; do \
test -f "$dmssl/$library"; \
ln -s "$dmssl/$library" "$DM_HOME/bin/$library"; \
done; \
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")'; \
node -e "require('/opt/sqlbot/g2-ssr/node_modules/@antv/g2-ssr')"

EXPOSE 3000 8000 8001 5432

Expand Down
Loading
Loading