File size: 4,008 Bytes
7547388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9d97138
 
50e1d54
9d97138
 
4dba5fe
9d97138
68eccd8
 
7547388
 
4272b82
50e1d54
 
9d97138
 
 
 
 
 
50e1d54
 
4415019
7547388
 
50e1d54
7547388
 
 
 
 
 
 
 
 
 
 
 
 
 
9d97138
 
7547388
9d97138
 
50e1d54
 
7547388
9d97138
 
7547388
 
 
 
 
 
 
9d97138
7547388
 
 
 
 
9d97138
50e1d54
 
 
9d97138
7547388
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
FROM node:22-alpine AS pyodide-assets
ARG PYODIDE_VERSION=0.27.7
WORKDIR /build
COPY scripts/vendor_pyodide_packages.mjs ./vendor_pyodide_packages.mjs
RUN npm install --global --ignore-scripts --omit=dev pyodide@${PYODIDE_VERSION} codemirror@5.65.16 jszip@3.10.1 \
    && node ./vendor_pyodide_packages.mjs /usr/local/lib/node_modules/pyodide https://cdn.jsdelivr.net/pyodide/v${PYODIDE_VERSION}/full/

FROM python:3.11-slim AS python-dependencies
ARG PIP_TOOLS_VERSION=7.6.1
ARG PIP_AUDIT_VERSION=2.10.1
WORKDIR /build
COPY requirements.txt .
RUN python -m pip install --no-cache-dir pip-tools==${PIP_TOOLS_VERSION} pip-audit==${PIP_AUDIT_VERSION} \
    && pip-compile --resolver=backtracking --generate-hashes --output-file=requirements.lock requirements.txt \
    && pip-audit --strict -r requirements.lock

FROM python:3.11-slim

# System deps for OpenCV headless, Pygame, MediaPipe + CJK fonts
RUN apt-get update && apt-get install -y --no-install-recommends \
    libglib2.0-0 \
    libgl1 \
    libgomp1 \
    libgles2 \
    libegl1 \
    bubblewrap \
    util-linux \
    fonts-wqy-zenhei \
    fonts-wqy-microhei \
    fonts-noto-cjk \
    && rm -rf /var/lib/apt/lists/*

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    SDL_VIDEODRIVER=dummy \
    SDL_AUDIODRIVER=dummy \
    PORT=7860 \
    MAX_CONCURRENT_RUNNERS=3 \
    RUNNER_ISOLATION_MODE=process \
    RUNNER_STARTS_PER_IP_PER_HOUR=120 \
    RUNNER_START_COOLDOWN_SEC=0.75 \
    SESSION_TIMEOUT_SEC=900 \
    PROJECT_CACHE_TTL_SEC=10 \
    ENABLE_HSTS=1 \
    CLASSROOM_COURSE_QUOTA_MB=1024 \
    CLASSROOM_MAX_VERSIONS_PER_KIND=100 \
    CLASSROOM_CHECKPOINTS_PER_HOUR=60 \
    CLASSROOM_SUBMISSIONS_PER_HOUR=20 \
    CLASSROOM_VERSION_COOLDOWN_MS=1500 \
    CLASSROOM_WS_CONNECTIONS_PER_MINUTE=300 \
    CLASSROOM_WS_MESSAGES_PER_MINUTE=300 \
    RUNNER_MEMORY_LIMIT_MB=3072 \
    RUNNER_CPU_LIMIT_SEC=900 \
    RUNNER_TMP_LIMIT_MB=256 \
    RUNNER_PROJECT_LIMIT_MB=128 \
    RUNNER_PROJECT_FILE_LIMIT=2000

WORKDIR /app
COPY --from=python-dependencies /build/requirements.lock /tmp/requirements.lock
COPY requirements.txt .

# Base image without TensorFlow (smaller / faster cold start).
# To include Keras demos: COPY requirements-ml.txt . && pip install -r requirements-ml.txt
RUN python -m pip install --no-cache-dir --require-hashes -r /tmp/requirements.lock

COPY . .
COPY --from=python-dependencies /build/requirements.lock /app/requirements.lock
COPY --from=pyodide-assets /usr/local/lib/node_modules/pyodide /app/classroom_static/vendor/pyodide
COPY --from=pyodide-assets /usr/local/lib/node_modules/codemirror/lib/codemirror.js /app/classroom_static/vendor/codemirror/codemirror.js
COPY --from=pyodide-assets /usr/local/lib/node_modules/codemirror/lib/codemirror.css /app/classroom_static/vendor/codemirror/codemirror.css
COPY --from=pyodide-assets /usr/local/lib/node_modules/codemirror/theme/material-darker.css /app/classroom_static/vendor/codemirror/material-darker.css
COPY --from=pyodide-assets /usr/local/lib/node_modules/codemirror/mode/python/python.js /app/classroom_static/vendor/codemirror/python.js
COPY --from=pyodide-assets /usr/local/lib/node_modules/jszip/dist/jszip.min.js /app/classroom_static/vendor/jszip/jszip.min.js

RUN groupadd --gid 10001 telearn \
    && useradd --uid 10001 --gid 10001 --create-home --shell /usr/sbin/nologin telearn \
    && mkdir -p /app/projects /app/models /app/static /app/classroom_data /tmp/telearn_runner /tmp/telearn_classroom \
    && chown -R telearn:telearn /app/projects /app/classroom_data /tmp/telearn_runner /tmp/telearn_classroom \
    && chmod 700 /tmp/telearn_runner /tmp/telearn_classroom

# Healthcheck for orchestrators
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
    CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:%s/health' % __import__('os').environ.get('PORT','7860'))" || exit 1

USER telearn

CMD uvicorn server:app --host 0.0.0.0 --port $PORT --ws-max-size 1048576 --ws-max-queue 8