镜像构建历史
# 2026-09-27 13:39:59 0.00B 配置容器启动时运行的命令
ENTRYPOINT ["/app/entrypoint.sh"]
# 2026-09-27 13:39:59 0.00B 指定检查容器健康状态的命令
HEALTHCHECK {Test:[CMD-SHELL python /app/healthcheck.py] Interval:30s Timeout:10s StartPeriod:1m0s StartInterval:0s Retries:3}
# 2026-09-27 13:39:59 0.00B 声明容器运行时监听的端口
EXPOSE [3782/tcp 8001/tcp]
# 2026-09-27 13:39:59 370.00B 执行命令并创建新的镜像层
RUN /bin/sh -c cat > /app/healthcheck.py <<'EOF'
from pathlib import Path
import json
import urllib.request
port = 8001
settings_path = Path("/app/data/user/settings/system.json")
try:
settings = json.loads(settings_path.read_text(encoding="utf-8"))
port = int(settings.get("backend_port") or port)
except Exception:
pass
urllib.request.urlopen(f"http://localhost:{port}/health/ready", timeout=5).close()
EOF # buildkit
# 2026-09-27 13:39:59 7.40KB 执行命令并创建新的镜像层
RUN /bin/sh -c sed -i 's/\r$//' /app/entrypoint.sh && chmod +x /app/entrypoint.sh # buildkit
# 2026-09-27 13:39:59 7.40KB 执行命令并创建新的镜像层
RUN /bin/sh -c cat > /app/entrypoint.sh <<'EOF'
#!/bin/bash
set -e
echo "============================================"
echo "🚀 Starting DeepTutor"
echo "============================================"
export DEEPTUTOR_IGNORE_PROCESS_ENV_OVERRIDES=1
# Docker is JSON-driven. Ignore runtime env names even if the host or a stale
# Compose environment provides them; the entrypoint re-exports values from
# data/user/settings/*.json below.
for key in \
BACKEND_PORT \
BACKEND_WORKERS \
DEEPTUTOR_BACKEND_WORKERS \
FRONTEND_PORT \
NEXT_PUBLIC_API_BASE_EXTERNAL \
NEXT_PUBLIC_API_BASE \
CORS_ORIGIN \
CORS_ORIGINS \
DISABLE_SSL_VERIFY \
CHAT_ATTACHMENT_DIR \
AUTH_ENABLED \
NEXT_PUBLIC_AUTH_ENABLED \
AUTH_USERNAME \
AUTH_PASSWORD_HASH \
AUTH_TOKEN_EXPIRE_HOURS \
AUTH_COOKIE_SECURE \
POCKETBASE_URL \
POCKETBASE_PORT \
POCKETBASE_EXTERNAL_URL \
POCKETBASE_ADMIN_EMAIL \
POCKETBASE_ADMIN_PASSWORD \
DEEPTUTOR_API_BASE_URL \
DEEPTUTOR_AUTH_ENABLED; do
unset "$key"
done
# Runtime user for supervisord children (`user=deeptutor`). Default 1000:1000
# matches ordinary Docker and rootless keep-id. Unraid/NAS bind mounts are
# often owned by another host user that *reverts* in-container chown; set
# PUID/PGID to that owner instead of running the app as root.
PUID="${PUID:-${DEEPTUTOR_PUID:-1000}}"
PGID="${PGID:-${DEEPTUTOR_PGID:-1000}}"
export PUID PGID
if [ "$(id -u)" -eq 0 ]; then
case "$PUID$PGID" in
''|*[!0-9]*)
echo "❌ PUID and PGID must be non-root integers (got PUID=${PUID} PGID=${PGID})"
exit 1
;;
esac
if [ "$PUID" -eq 0 ] || [ "$PGID" -eq 0 ]; then
echo "❌ PUID/PGID must be non-root so the app does not run as root (got PUID=${PUID} PGID=${PGID})"
exit 1
fi
echo "👤 Runtime user deeptutor → uid=${PUID} gid=${PGID}"
if [ "$(id -g deeptutor)" != "$PGID" ]; then
if getent group "$PGID" >/dev/null 2>&1; then
usermod -g "$PGID" deeptutor
else
groupmod -o -g "$PGID" deeptutor
fi
fi
if [ "$(id -u deeptutor)" != "$PUID" ]; then
usermod -o -u "$PUID" deeptutor
fi
else
echo "👤 Rootless runtime uid=$(id -u) gid=$(id -g); skipping PUID remap"
fi
# Initialize user data directories if empty
echo "📁 Checking data directories..."
echo " Ensuring runtime settings and workspace layout..."
python -c "
from pathlib import Path
from deeptutor.services.setup import init_user_directories
init_user_directories(Path('/app'))
" || echo " ⚠️ Directory initialization failed (volume writability check follows)"
# Re-chown /app/data to the (possibly remapped) deeptutor user. Named Docker
# volumes are typically root-owned and need this. Bind mounts on Unraid/NFS
# often reject chown and keep the host owner — do NOT swallow that with
# `|| true`; warn and let the writability probe fail-fast if the runtime
# user still cannot write.
if [ "$(id -u)" -eq 0 ]; then
if chown -R deeptutor:deeptutor /app/data; then
echo " ✅ /app/data owned by deeptutor (uid=${PUID} gid=${PGID})"
else
echo " ⚠️ chown /app/data failed (common on Unraid/NFS bind mounts that reject ownership changes)."
echo " The app will run as uid=${PUID} gid=${PGID}; the volume must already be writable by that user."
echo " Set PUID/PGID to the host owner of the bind mount rather than running as root."
fi
else
echo " Skipping chown under rootless runtime"
fi
echo "📁 Verifying /app/data is writable by the runtime user..."
python -c "from deeptutor.services.setup.data_volume import check_container_data_volume; check_container_data_volume()"
# Optional dependencies (#762). A container is disposable, so anything
# `docker exec … pip install`ed into a running one is gone at the next
# `compose down`. Declare them on the deployment instead and every container
# started from it has them:
#
# environment:
# DEEPTUTOR_EXTRAS: "math-animator,partners"
# DEEPTUTOR_APT_PACKAGES: "ffmpeg"
#
# Both steps are idempotent — a warm container only pays a check — and neither
# is allowed to be fatal: a missing wheel leaves that one feature unavailable,
# exactly as it was before, rather than taking the whole deployment down.
# The pip cache lives on the data volume so a rebuild reuses the downloads it
# already paid for instead of fetching them again.
export PIP_CACHE_DIR="${PIP_CACHE_DIR:-/app/data/.cache/pip}"
mkdir -p "$PIP_CACHE_DIR" 2>/dev/null || true
if [ -n "${DEEPTUTOR_APT_PACKAGES:-}" ]; then
echo "🔧 Ensuring system packages: ${DEEPTUTOR_APT_PACKAGES}"
apt_missing=""
for pkg in $(echo "${DEEPTUTOR_APT_PACKAGES}" | tr ',' ' '); do
dpkg -s "$pkg" >/dev/null 2>&1 || apt_missing="$apt_missing $pkg"
done
if [ -z "$apt_missing" ]; then
echo " ✅ System packages already present"
elif ! (apt-get update -qq && apt-get install -y --no-install-recommends $apt_missing); then
echo " ⚠️ apt-get failed; these packages stay unavailable:$apt_missing"
fi
fi
if [ -n "${DEEPTUTOR_EXTRAS:-}" ]; then
echo "🔧 Ensuring Python extras: ${DEEPTUTOR_EXTRAS}"
python /app/scripts/install_extras.py "${DEEPTUTOR_EXTRAS}" || true
if [ "$(id -u)" -eq 0 ]; then
if ! chown -R deeptutor:deeptutor "$PIP_CACHE_DIR"; then
echo " ⚠️ chown pip cache failed; continuing if the runtime user can still write it"
fi
fi
fi
echo "⚙️ Loading runtime JSON settings..."
eval "$(python - <<'PY'
import shlex
from deeptutor.services.config import export_runtime_settings_to_env
for key, value in export_runtime_settings_to_env(overwrite=True).items():
print(f"export {key}={shlex.quote(str(value))}")
PY
)"
export BACKEND_PORT=${BACKEND_PORT:-8001}
export FRONTEND_PORT=${FRONTEND_PORT:-3782}
# DEEPTUTOR_API_BASE_URL and DEEPTUTOR_AUTH_ENABLED are exported by the
# export_runtime_settings_to_env eval above (see render_environment in
# deeptutor/services/config/runtime_settings.py). web/proxy.ts reads them at
# request time to rewrite /api/* and /ws/* to the backend and to gate the login
# redirect. Keeping them in the single JSON-backed exporter means the Docker and
# `deeptutor start` paths stay in sync.
echo "📌 API Base URL (proxy): ${DEEPTUTOR_API_BASE_URL:-http://localhost:${BACKEND_PORT}}"
echo "📌 Auth enabled: ${DEEPTUTOR_AUTH_ENABLED:-false}"
echo "📌 Backend Port: ${BACKEND_PORT}"
echo "📌 Frontend Port: ${FRONTEND_PORT}"
echo "============================================"
echo "📦 Configuration loaded from:"
echo " - data/user/settings/system.json"
echo " - data/user/settings/auth.json"
echo " - data/user/settings/integrations.json"
echo " - data/user/settings/model_catalog.json"
echo " - data/user/settings/main.yaml"
echo " - data/user/settings/agents.yaml"
echo "============================================"
# Hand off to supervisord as PID 1. The daemon-level config deliberately omits
# `user=` so supervisord inherits PID 1's UID and stays portable across rootful
# and rootless-keep-id runtimes; children drop to the deeptutor user via
# per-program `user=`. Full rationale lives next to the [supervisord] section
# in the build step that writes /etc/supervisor/supervisord.conf.
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
EOF # buildkit
# 2026-09-27 13:39:59 278.00B 执行命令并创建新的镜像层
RUN /bin/sh -c sed -i 's/\r$//' /app/start-frontend.sh && chmod +x /app/start-frontend.sh # buildkit
# 2026-09-27 13:39:59 278.00B 执行命令并创建新的镜像层
RUN /bin/sh -c cat > /app/start-frontend.sh <<'EOF'
#!/bin/bash
set -e
FRONTEND_PORT=${FRONTEND_PORT:-3782}
FRONTEND_HOST=${FRONTEND_HOST:-0.0.0.0}
echo "[Frontend] 🚀 Starting Next.js frontend on ${FRONTEND_HOST}:${FRONTEND_PORT}..."
export PORT=${FRONTEND_PORT}
export HOSTNAME=${FRONTEND_HOST}
exec node /app/web/server.js
EOF # buildkit
# 2026-09-27 13:39:59 1.69KB 执行命令并创建新的镜像层
RUN /bin/sh -c sed -i 's/\r$//' /app/start-backend.sh && chmod +x /app/start-backend.sh # buildkit
# 2026-09-27 13:39:58 1.69KB 执行命令并创建新的镜像层
RUN /bin/sh -c cat > /app/start-backend.sh <<'EOF'
#!/bin/bash
set -e
BACKEND_PORT=${BACKEND_PORT:-8001}
BACKEND_HOST=${BACKEND_HOST:-0.0.0.0}
BACKEND_WORKERS=${BACKEND_WORKERS:-1}
echo "[Backend] 🚀 Starting FastAPI backend on ${BACKEND_HOST}:${BACKEND_PORT}..."
# Run uvicorn directly - the application's logging system already handles:
# 1. Console output (visible in docker logs)
# 2. File logging to data/user/logs/ai_tutor_*.log
#
# BACKEND_HOST defaults to 0.0.0.0 (LAN-reachable, matches bridge-mode
# port publishing). Set BACKEND_HOST=127.0.0.1 when running with
# network_mode: host to keep the backend on loopback only.
#
# --ws-max-size: chat attachments travel base64 inside one WS message; derive
# the frame cap from the configured attachment policy (system.json) so uploads
# the policy allows are not severed by uvicorn's 16MB default.
#
# --timeout-keep-alive: the frontend proxy (web/proxy.ts) forwards over Node's
# http.globalAgent, which reaps idle sockets on a 5s timer — identical to
# uvicorn's default, so both ends raced to close the same socket and the loser's
# request died with ECONNRESET (a 500 in the UI). Stay well above the proxy's
# reaper so the client is the only side retiring idle connections.
WS_MAX_SIZE=$(python -c "from deeptutor.services.config import get_ws_max_size; print(get_ws_max_size())" 2>/dev/null || echo 16777216)
KEEP_ALIVE=$(python -c "from deeptutor.services.config import HTTP_KEEP_ALIVE_TIMEOUT; print(HTTP_KEEP_ALIVE_TIMEOUT)" 2>/dev/null || echo 300)
exec python -m uvicorn deeptutor.api.main:app --host ${BACKEND_HOST} --port ${BACKEND_PORT} --workers ${BACKEND_WORKERS} --no-access-log --no-proxy-headers --ws-max-size ${WS_MAX_SIZE} --timeout-keep-alive ${KEEP_ALIVE}
EOF # buildkit
# 2026-09-27 13:39:58 548.00B 执行命令并创建新的镜像层
RUN /bin/sh -c sed -i 's/\r$//' /etc/supervisor/conf.d/programs.conf # buildkit
# 2026-09-27 13:39:58 548.00B 执行命令并创建新的镜像层
RUN /bin/sh -c cat > /etc/supervisor/conf.d/programs.conf <<'EOF'
[program:backend]
command=/bin/bash /app/start-backend.sh
directory=/app
user=deeptutor
autostart=true
autorestart=true
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/dev/fd/2
stderr_logfile_maxbytes=0
environment=PYTHONPATH="/app",PYTHONUNBUFFERED="1"
[program:frontend]
command=/bin/bash /app/start-frontend.sh
directory=/app/web
user=deeptutor
autostart=true
autorestart=true
startsecs=5
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/dev/fd/2
stderr_logfile_maxbytes=0
environment=NODE_ENV="production"
EOF # buildkit
# 2026-09-27 13:39:58 150.00B 执行命令并创建新的镜像层
RUN /bin/sh -c sed -i 's/\r$//' /etc/supervisor/supervisord.conf # buildkit
# 2026-09-27 13:39:58 150.00B 执行命令并创建新的镜像层
RUN /bin/sh -c cat > /etc/supervisor/supervisord.conf <<'EOF'
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/tmp/supervisord.pid
[include]
files = /etc/supervisor/conf.d/programs.conf
EOF # buildkit
# 2026-09-27 13:39:58 0.00B 执行命令并创建新的镜像层
RUN /bin/sh -c mkdir -p /etc/supervisor/conf.d # buildkit
# 2026-09-27 13:39:58 36.41MB 执行命令并创建新的镜像层
RUN /bin/sh -c groupadd --system --gid 1000 deeptutor && useradd --system --uid 1000 --gid 1000 --no-create-home --shell /usr/sbin/nologin deeptutor && chown -R deeptutor:deeptutor /app/data /app/web/.next # buildkit
# 2026-09-27 13:39:57 0.00B 执行命令并创建新的镜像层
RUN /bin/sh -c mkdir -p data/user/settings data/memory data/user/workspace/memory data/user/workspace/notebook data/user/workspace/co-writer/audio data/user/workspace/co-writer/tool_calls data/user/workspace/chat/chat data/user/workspace/chat/deep_solve data/user/workspace/chat/deep_question data/user/workspace/chat/deep_research/reports data/user/workspace/chat/math_animator data/user/workspace/chat/_detached_exec data/user/logs data/knowledge_bases # buildkit
# 2026-09-27 13:39:57 1.02KB 复制新文件或目录到容器中
COPY requirements.txt ./ # buildkit
# 2026-09-27 13:39:57 8.11KB 复制新文件或目录到容器中
COPY requirements/ ./requirements/ # buildkit
# 2026-09-27 13:39:57 19.62KB 复制新文件或目录到容器中
COPY pyproject.toml ./ # buildkit
# 2026-09-27 13:39:57 85.11KB 复制新文件或目录到容器中
COPY scripts/ ./scripts/ # buildkit
# 2026-09-27 13:39:57 218.25KB 复制新文件或目录到容器中
COPY deeptutor_cli/ ./deeptutor_cli/ # buildkit
# 2026-09-27 13:39:57 11.33MB 复制新文件或目录到容器中
COPY deeptutor/ ./deeptutor/ # buildkit
# 2026-09-27 13:39:57 2.44MB 复制新文件或目录到容器中
COPY /app/web/public/ ./web/public/ # buildkit
# 2026-09-27 13:39:56 16.44MB 复制新文件或目录到容器中
COPY /app/web/.next/static/ ./web/.next/static/ # buildkit
# 2026-09-27 13:39:56 99.52MB 复制新文件或目录到容器中
COPY /app/web/.next/standalone/ ./web/ # buildkit
# 2026-09-27 13:38:10 79.88KB 复制新文件或目录到容器中
COPY /usr/local/bin /usr/local/bin # buildkit
# 2026-09-27 13:38:09 846.33MB 复制新文件或目录到容器中
COPY /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages # buildkit
# 2026-09-27 13:36:26 236.94KB 执行命令并创建新的镜像层
RUN /bin/sh -c ln -sf /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && ln -sf /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx && node --version && npm --version # buildkit
# 2026-09-27 13:36:25 11.52MB 复制新文件或目录到容器中
COPY /usr/local/lib/node_modules /usr/local/lib/node_modules # buildkit
# 2026-09-27 13:36:25 124.83MB 复制新文件或目录到容器中
COPY /usr/local/bin/node /usr/local/bin/node # buildkit
# 2026-09-27 13:36:25 909.38MB 执行命令并创建新的镜像层
RUN /bin/sh -c apt-get update && apt-get install -y --no-install-recommends curl ca-certificates bash git supervisor libgl1 libglib2.0-0 libsm6 libxext6 libxrender1 libreoffice-writer libreoffice-calc libreoffice-impress fonts-noto-cjk fonts-liberation && rm -rf /var/lib/apt/lists/* # buildkit
# 2026-09-27 13:35:09 0.00B 设置工作目录为/app
WORKDIR /app
# 2026-09-27 13:35:09 0.00B 设置环境变量 PYTHONDONTWRITEBYTECODE PYTHONUNBUFFERED PYTHONIOENCODING MALLOC_ARENA_MAX MALLOC_TRIM_THRESHOLD_ NODE_ENV DEEPTUTOR_IGNORE_PROCESS_ENV_OVERRIDES
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PYTHONIOENCODING=utf-8 MALLOC_ARENA_MAX=2 MALLOC_TRIM_THRESHOLD_=131072 NODE_ENV=production DEEPTUTOR_IGNORE_PROCESS_ENV_OVERRIDES=1
# 2026-09-27 13:35:09 0.00B 添加元数据标签
LABEL maintainer=DeepTutor Team description=DeepTutor: AI-Powered Personalized Learning Assistant
# 2026-09-19 09:06:49 0.00B 设置默认要执行的命令
CMD ["python3"]
# 2026-09-19 09:06:49 36.00B 执行命令并创建新的镜像层
RUN /bin/sh -c set -eux; for src in idle3 pip3 pydoc3 python3 python3-config; do dst="$(echo "$src" | tr -d 3)"; [ -s "/usr/local/bin/$src" ]; [ ! -e "/usr/local/bin/$dst" ]; ln -svT "$src" "/usr/local/bin/$dst"; done # buildkit
# 2026-09-19 09:06:49 42.43MB 执行命令并创建新的镜像层
RUN /bin/sh -c set -eux; savedAptMark="$(apt-mark showmanual)"; apt-get update; apt-get install -y --no-install-recommends dpkg-dev g++ gcc gnupg libbluetooth-dev libbz2-dev libc6-dev libdb-dev libffi-dev libgdbm-dev liblzma-dev libncursesw5-dev libreadline-dev libsqlite3-dev libssl-dev make tk-dev uuid-dev wget xz-utils zlib1g-dev ; wget -O python.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz"; echo "$PYTHON_SHA256 *python.tar.xz" | sha256sum -c -; wget -O python.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc"; GNUPGHOME="$(mktemp -d)"; export GNUPGHOME; gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$GPG_KEY"; gpg --batch --verify python.tar.xz.asc python.tar.xz; gpgconf --kill all; rm -rf "$GNUPGHOME" python.tar.xz.asc; mkdir -p /usr/src/python; tar --extract --directory /usr/src/python --strip-components=1 --file python.tar.xz; rm python.tar.xz; cd /usr/src/python; gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; ./configure --build="$gnuArch" --enable-loadable-sqlite-extensions --enable-optimizations --enable-option-checking=fatal --enable-shared $(test "${gnuArch%%-*}" != 'riscv64' && echo '--with-lto') --with-ensurepip ; nproc="$(nproc)"; EXTRA_CFLAGS="$(dpkg-buildflags --get CFLAGS)"; LDFLAGS="$(dpkg-buildflags --get LDFLAGS)"; LDFLAGS="${LDFLAGS:-} -Wl,--strip-all"; make -j "$nproc" "EXTRA_CFLAGS=${EXTRA_CFLAGS:-}" "LDFLAGS=${LDFLAGS:-}" ; rm python; make -j "$nproc" "EXTRA_CFLAGS=${EXTRA_CFLAGS:-}" "LDFLAGS=${LDFLAGS:-} -Wl,-rpath='\$\$ORIGIN/../lib'" python ; make install; cd /; rm -rf /usr/src/python; find /usr/local -depth \( \( -type d -a \( -name test -o -name tests -o -name idle_test \) \) -o \( -type f -a \( -name '*.pyc' -o -name '*.pyo' -o -name 'libpython*.a' \) \) \) -exec rm -rf '{}' + ; ldconfig; apt-mark auto '.*' > /dev/null; apt-mark manual $savedAptMark; find /usr/local -type f -executable -not \( -name '*tkinter*' \) -exec ldd '{}' ';' | awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); printf "*%s\n", so }' | sort -u | xargs -rt dpkg-query --search | awk 'sub(":$", "", $1) { print $1 }' | sort -u | xargs -r apt-mark manual ; apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; apt-get dist-clean; export PYTHONDONTWRITEBYTECODE=1; python3 --version; pip3 install --disable-pip-version-check --no-cache-dir --no-compile 'setuptools==79.0.1' 'wheel==0.46.3' ; pip3 --version # buildkit
# 2026-09-19 08:59:27 0.00B 设置环境变量 PYTHON_SHA256
ENV PYTHON_SHA256=91bcdebfdde239a003ae93738a7fce0f9230fee5c4bc2b86f6e6e8c6f98aabe8
# 2026-09-19 08:59:27 0.00B 设置环境变量 PYTHON_VERSION
ENV PYTHON_VERSION=3.11.16
# 2026-09-19 08:59:27 0.00B 设置环境变量 GPG_KEY
ENV GPG_KEY=A035C8C19219BA821ECEA86B64E628F8D684696D
# 2026-09-19 08:59:27 3.81MB 执行命令并创建新的镜像层
RUN /bin/sh -c set -eux; apt-get update; apt-get install -y --no-install-recommends ca-certificates netbase tzdata ; apt-get dist-clean # buildkit
# 2026-09-19 08:59:27 0.00B 设置环境变量 LANG
ENV LANG=C.UTF-8
# 2026-09-19 08:59:27 0.00B 设置环境变量 PATH
ENV PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# 2026-09-18 08:00:00 78.81MB
# debian.sh --arch 'amd64' out/ 'trixie' '@1789689600'
镜像信息
{
"Id": "sha256:38babc2b502d023d132c386730d1d0b220af4d838688e4c8e3ed80d2fc5999a9",
"RepoTags": [
"ghcr.io/hkuds/deeptutor:1.6.12",
"swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/hkuds/deeptutor:1.6.12"
],
"RepoDigests": [
"ghcr.io/hkuds/deeptutor@sha256:e4326ac3429003ed0035c3ea62909a7ca1db66224ccf5bc5cdb16bd261132fd6",
"swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/hkuds/deeptutor@sha256:63629a346b6c664c42a5af208eff11c94ae4db9d3cc060c6dab619699a1391e6"
],
"Parent": "",
"Comment": "buildkit.dockerfile.v0",
"Created": "2026-09-27T05:39:59.38342155Z",
"Container": "",
"ContainerConfig": null,
"DockerVersion": "",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3782/tcp": {},
"8001/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"LANG=C.UTF-8",
"GPG_KEY=A035C8C19219BA821ECEA86B64E628F8D684696D",
"PYTHON_VERSION=3.11.16",
"PYTHON_SHA256=91bcdebfdde239a003ae93738a7fce0f9230fee5c4bc2b86f6e6e8c6f98aabe8",
"PYTHONDONTWRITEBYTECODE=1",
"PYTHONUNBUFFERED=1",
"PYTHONIOENCODING=utf-8",
"MALLOC_ARENA_MAX=2",
"MALLOC_TRIM_THRESHOLD_=131072",
"NODE_ENV=production",
"DEEPTUTOR_IGNORE_PROCESS_ENV_OVERRIDES=1"
],
"Cmd": null,
"Healthcheck": {
"Test": [
"CMD-SHELL",
"python /app/healthcheck.py"
],
"Interval": 30000000000,
"Timeout": 10000000000,
"StartPeriod": 60000000000,
"Retries": 3
},
"Image": "",
"Volumes": null,
"WorkingDir": "/app",
"Entrypoint": [
"/app/entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"description": "DeepTutor: AI-Powered Personalized Learning Assistant",
"maintainer": "DeepTutor Team",
"org.opencontainers.image.created": "2026-09-27T05:35:01.814Z",
"org.opencontainers.image.description": "DeepTutor: Lifelong Personalized Tutoring. https://deeptutor.info/.",
"org.opencontainers.image.licenses": "Apache-2.0",
"org.opencontainers.image.revision": "ef2d9e5c3c99fd073742c5aadc2bb9584b1e503b",
"org.opencontainers.image.source": "https://github.com/HKUDS/DeepTutor",
"org.opencontainers.image.title": "DeepTutor",
"org.opencontainers.image.url": "https://github.com/HKUDS/DeepTutor",
"org.opencontainers.image.version": "1.6.12"
}
},
"Architecture": "amd64",
"Os": "linux",
"Size": 2183919091,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/7e95657a9525994f1af9f19cfa4915ed984e876c468e0c1c747de1cc2b8c7932/diff:/var/lib/docker/overlay2/54473de81ae2ddcecd0a5625a30b7ef531e8042de849d95af3ba137db57643d5/diff:/var/lib/docker/overlay2/d7585ce0d7899ab6141aab73662c9f7957716ca1f0cc4e9de70f90a081858f96/diff:/var/lib/docker/overlay2/bc01a306eefc2de3e043d693777338c96d4f4641450caa2ad7e484dc81203386/diff:/var/lib/docker/overlay2/e8eb229cd89053cc3a473aeb6cd3f4b5fa88932b2f3f3281425945ab77a6af5f/diff:/var/lib/docker/overlay2/c2bb2c74fc5bfbdf924ef585ae10bad8e321fd333a5b0533ec28a2328b38efd0/diff:/var/lib/docker/overlay2/45a23bdc1a74756cfc9174b4021ed3938521e6a34b5b5e9d82e4aee696512b09/diff:/var/lib/docker/overlay2/d995b8af82680789eb5b0e34325c02077ce3956e1a8fa3c80f3b741371b54180/diff:/var/lib/docker/overlay2/fce18411f0ad5f6219385e00311fa1241a7344acd6504db8d7bff369ba23d8a0/diff:/var/lib/docker/overlay2/f2f7e65d87d6a56f0acb4c29842886b0f0196dff181e63c8267a35055fb849ec/diff:/var/lib/docker/overlay2/3001da0cb368e2086d964369b825f8a4d23f595f08dd1405530b50c4718f6745/diff:/var/lib/docker/overlay2/052f14cde9854dc38f512d4480765b15b0fbb0fcb1317323f39886b6b1c95a48/diff:/var/lib/docker/overlay2/67fec82e3bda2b2444a4ef460a4ac4f47a10b0d1e22d11e84cd7d63b72365845/diff:/var/lib/docker/overlay2/3151e0fc5df6e554cb104b0e7277d86babdab990819c9a4f4e17c54206c7a41c/diff:/var/lib/docker/overlay2/671219be5dab23a63f8ac963a6f4ded3086482b156ca7c3f1b8683dcbeb7ea65/diff:/var/lib/docker/overlay2/6594232589a4b2873f859c56f4e469d01c25de464b0da0e296c061f82456436c/diff:/var/lib/docker/overlay2/f8c368cc7a12182b051a611d24e35b3adb6087ad280f11978a2c2ea3ed2e7e10/diff:/var/lib/docker/overlay2/66df40c1038a98f80b007789d253553e73400bc3e867cc7fe7ac6ed847b2da47/diff:/var/lib/docker/overlay2/a331d81f39cea0c935b643bb3a77dc3aa8608a8494b7c784c77f0e16301a936d/diff:/var/lib/docker/overlay2/dd1e51c73e3aca91763d3dce74c457dd5eda333ff37b123d3c9b41aeed8e259f/diff:/var/lib/docker/overlay2/b253fe22ee4e544879f8179c72f7c71cc04f7f48870c89522e5dd44afa3a7822/diff:/var/lib/docker/overlay2/0df863e1b333f62c15ffa21d2c9aec82c3292ed48a3251e113fb4177585cb3d8/diff:/var/lib/docker/overlay2/c52854160e3651f060624597d52f55bdec287c926d4234b24201947227a90ad2/diff:/var/lib/docker/overlay2/20eb99c8eedcb406bd087dfb15125626c27287977bc8c7ca18520c5602feb92a/diff:/var/lib/docker/overlay2/470c7c794f9818518452367f083e887a680dfed7e1bb4ec28ca572befbcf8c94/diff:/var/lib/docker/overlay2/0fb659a2256655435f12cbf0319a8532b8a1e673fecd940c357d7f9fb9648fe8/diff:/var/lib/docker/overlay2/d74add87abb2a721985bbc4949f975b9d070774db754937e61f6593046257813/diff:/var/lib/docker/overlay2/63ad6361fdf9c5bd69cb90b673bef3d931e0ee905b77d63aa5543186bd6ee340/diff:/var/lib/docker/overlay2/2e32f16302627832ad7f11298b38181d07ba5814247bb8629e1be73f256a6c2c/diff:/var/lib/docker/overlay2/98285e8e8b5aa930fc331316dc7d40b31f9e7fd81aa943de28039f91e93611ad/diff:/var/lib/docker/overlay2/1e26fc23a256eef1fe8d2b8bf8fe6acf91113d8646a7c0d5879ba830d98ebd8c/diff:/var/lib/docker/overlay2/986956bbaed6a249072448ac9dd9b1136bd83b38789772ef13d813b5edbbdd1e/diff:/var/lib/docker/overlay2/0a54ab216a0bfe377756c5ffaeb38009fe74e9c0fd29729892c12e08f9ef4057/diff",
"MergedDir": "/var/lib/docker/overlay2/b44274a208dbd999b9adcc85f54bf223d7b408650c9a175a29ca48d62d18b4c7/merged",
"UpperDir": "/var/lib/docker/overlay2/b44274a208dbd999b9adcc85f54bf223d7b408650c9a175a29ca48d62d18b4c7/diff",
"WorkDir": "/var/lib/docker/overlay2/b44274a208dbd999b9adcc85f54bf223d7b408650c9a175a29ca48d62d18b4c7/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:a6dc765193a52cbaede3c93a9ff48b9540948dd0774bbe7031fcb5847606f9ac",
"sha256:a5c84380b3657bb723a1f71fa963f1e3a3f01e2c6bcba12e3b9a0d336158c7a9",
"sha256:4a01ba3ac604812ef31dab0006efecd1d572676f7a68afa169a9d57883025006",
"sha256:d190d09d7bd91836f809045799a7024a54026b3da5de1ccb811627fcf9878b92",
"sha256:17c1febaf83170ca4dd3a5e9bfe73e96293bb5320c98a781cbe380a2308eaf0c",
"sha256:798a78ad1ff36debc9e78f784c145b82caa0b181816b11027fdcb2d7e52ec296",
"sha256:429a2a72cd9d380574588592047f2fc9caf79262323ec1bbb4414ea20cff1720",
"sha256:eab7d6303c5621b78177d26b3b23edb8ce9efb96936691f16e4a6205ce1208a2",
"sha256:c39ea175af2efa39576127d376b7f7211a338936e6db6979b994eba48657b830",
"sha256:2fa8fd14ac6522d78651ec9b67104fa89c4364cb374f77d11561dbf223dca8b5",
"sha256:b85709e4d037e7de5ab3e83cb063c51199ed612067a2ef5bdf69dd8073a1c842",
"sha256:9563725e2d28c3766f99442b5786602d9cef502e1c67f74fd4bcaae60c96c354",
"sha256:dd76b826647a2c8c5f6ab353e66d5ac0033c77ebe2ce3db7d486fee13f119efa",
"sha256:2d7232aa4127d82946bb76f364e5e0df3e1bf6331affd8bfa092dcd390e2e7ee",
"sha256:a82202fd325979f8bae522ce470a774773ebd688e10e3d1cb5df3c006c18d9b0",
"sha256:f175b8ea2ce3edf12ad31e0b85886d6f0b1a6e43d4bd9448b745d4cd186239c8",
"sha256:43b840ba4e62df45a7fada30f650d226030d6a0cfdad147c30cd1a704f21e4ee",
"sha256:1aedd2a5fc6f6c85a0ca789ef3c3fdcbe81ccb5e73bd22c949264e3fc1297982",
"sha256:455cc6d27d94d6a3f2b18f86fc064e617a56f055664a232a1ea25dce43b62b66",
"sha256:a67673b8af04c2720c1e5cf230d2e1be1dada6e55cf7e1a4762ec225e47842dd",
"sha256:40a1b06d3341f899928438fe4807d795a3a1c8da4285024e84612254f8bf7e69",
"sha256:fda5bf63314286e89faa99493840086c45f3b1396fbed16a69537f4cae4a2c1c",
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
"sha256:746211eb9cb8a04a546a0db67c2e9f4bd0566c25b16168d9ddc2fe384bffb079",
"sha256:06dff61de7b2674acc7c0dba92c1951597a0dc72c323b6a03d1aa62b07e8281d",
"sha256:eb948ab046a2e983ed4d79df4eab980466ace996a2b53482022226635fcab9e6",
"sha256:eb948ab046a2e983ed4d79df4eab980466ace996a2b53482022226635fcab9e6",
"sha256:2974228405810e44847734747fa84ee10098317fcc3bdc8670842ae6f14407c8",
"sha256:9ff2be2eff43e73a07df7a80d732503841847787b0f6e535dcfe36a6ebc503cd",
"sha256:a986ae60a662970154f13c61127d00f1dbabdcb5f8b220e280411083a43c9f95",
"sha256:b465aa2c604477e042a8b24b1a71724df8ab182bd649adc18cc039ff09c08b29",
"sha256:5d6c77640c0e76abcaf4686a7c14dec4a09b17c3df9adf4ee20c6ecbb49b6d22",
"sha256:5e0563dc8df24eaf079fba0d48114f4172890bdb29c1947d94e299d436aaeb65",
"sha256:03cdfa674ec8a1635990b82bff0bdd895b9753ebb0ae9980f03236f32a65ba92"
]
},
"Metadata": {
"LastTagTime": "2026-10-01T11:48:16.49619948+08:00"
}
}