chore: import upstream snapshot with attribution
CI / lint (push) Has been cancelled
CI / js-syntax (push) Successful in 10m24s
CI / deps-audit (push) Has been cancelled
CI / test (push) Failing after 24m55s
CI / sast-bandit (push) Failing after 11m13s
CI / trivy (push) Failing after 9m32s
Docker Publish / build-and-push (push) Failing after 34m3s
CI / lint (push) Has been cancelled
CI / js-syntax (push) Successful in 10m24s
CI / deps-audit (push) Has been cancelled
CI / test (push) Failing after 24m55s
CI / sast-bandit (push) Failing after 11m13s
CI / trivy (push) Failing after 9m32s
Docker Publish / build-and-push (push) Failing after 34m3s
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
# Two-stage build:
|
||||
# * builder -- has gcc/build-essential/curl/unzip/pip etc.; produces
|
||||
# an isolated /opt/venv with all Python deps installed
|
||||
# and a fetched deno binary.
|
||||
# * runner -- only the runtime needs: Python (slim), ffmpeg,
|
||||
# ca-certificates, the venv copied from the builder,
|
||||
# and our app code. No compilers, no pip cache, no
|
||||
# download tooling -- shaves ~150-300 MB off the
|
||||
# single-stage image and reduces attack surface.
|
||||
|
||||
# ─── Stage 1: builder ────────────────────────────────────────────
|
||||
FROM python:3.12-slim AS builder
|
||||
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PIP_NO_CACHE_DIR=1 \
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
|
||||
# Build deps for pip wheels that fall back to source compilation
|
||||
# (numpy/scipy ship manylinux wheels, but smaller deps occasionally
|
||||
# need a compiler). Plus curl/unzip to fetch deno.
|
||||
RUN apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
curl \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# deno -- yt-dlp uses it as the JS runtime for YouTube format
|
||||
# extraction. Staged here so the runner doesn't need curl/unzip.
|
||||
ARG TARGETARCH
|
||||
RUN case "${TARGETARCH:-$(dpkg --print-architecture)}" in \
|
||||
amd64) DENO_ARCH=x86_64-unknown-linux-gnu ;; \
|
||||
arm64) DENO_ARCH=aarch64-unknown-linux-gnu ;; \
|
||||
*) echo "Unsupported arch: ${TARGETARCH}" && exit 1 ;; \
|
||||
esac \
|
||||
&& curl -fsSL -o /tmp/deno.zip "https://github.com/denoland/deno/releases/latest/download/deno-${DENO_ARCH}.zip" \
|
||||
&& unzip /tmp/deno.zip -d /usr/local/bin \
|
||||
&& rm /tmp/deno.zip \
|
||||
&& /usr/local/bin/deno --version
|
||||
|
||||
# Isolated venv -- the runner stage copies /opt/venv wholesale,
|
||||
# inheriting all installed deps without dragging in pip caches,
|
||||
# /var/lib/apt state, or build tools.
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
WORKDIR /app
|
||||
COPY pyproject.toml ./
|
||||
COPY app/ ./app/
|
||||
COPY static/ ./static/
|
||||
# The version is git-derived (hatch-vcs), but the build context has no .git, so
|
||||
# pin it explicitly: `docker build --build-arg VERSION=0.7.0-alpha.4 ...`
|
||||
# (defaults to 0.0.0 for ad-hoc local builds). #169
|
||||
ARG VERSION=0.0.0
|
||||
RUN SETUPTOOLS_SCM_PRETEND_VERSION="${VERSION#v}" pip install . --timeout 300
|
||||
|
||||
# ─── Stage 2: runner ─────────────────────────────────────────────
|
||||
FROM python:3.12-slim AS runner
|
||||
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PATH="/opt/venv/bin:$PATH" \
|
||||
TORCH_HOME=/cache/torch \
|
||||
XDG_CACHE_HOME=/cache
|
||||
|
||||
# Runtime-only OS deps. ffmpeg has many shared libs (libav*, libsw*,
|
||||
# libpostproc), so we install via apt rather than copy-pasting binaries
|
||||
# and chasing transitive .so dependencies. ca-certificates is needed
|
||||
# for HTTPS to YouTube.
|
||||
RUN apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ffmpeg \
|
||||
ca-certificates \
|
||||
gosu \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Deno binary fetched in stage 1 (single self-contained file).
|
||||
COPY --from=builder /usr/local/bin/deno /usr/local/bin/deno
|
||||
|
||||
# Pre-built Python virtualenv with all our deps. The PATH env above
|
||||
# means `python`, `uvicorn`, `pip`, etc. resolve into the venv with
|
||||
# no further configuration.
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
|
||||
# Application code -- copied to /app rather than only relied-on via
|
||||
# site-packages because app/core/config.py derives STATIC_DIR from
|
||||
# __file__'s parent chain, and the cwd-rooted /app/app version sits
|
||||
# earlier on sys.path than the venv install of `app`. Without the
|
||||
# COPY, STATIC_DIR would resolve into site-packages where static/
|
||||
# wasn't included by hatchling's wheel target.
|
||||
WORKDIR /app
|
||||
COPY app/ ./app/
|
||||
COPY static/ ./static/
|
||||
|
||||
# Create the app user and own all non-bind-mounted paths. /app/jobs is a
|
||||
# bind mount at runtime -- the entrypoint script re-chowns it to app:app
|
||||
# before dropping privileges, handling the case where Docker creates the
|
||||
# host directory as root on first run.
|
||||
RUN groupadd --system --gid 1001 app \
|
||||
&& useradd --system --uid 1001 --gid app --home /app --no-create-home app \
|
||||
&& mkdir -p /cache /jobs \
|
||||
&& chown -R app:app /app /cache /jobs
|
||||
|
||||
COPY build/docker-entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
EXPOSE 8000
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
Reference in New Issue
Block a user