-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Expand file tree
/
Copy pathDockerfile
More file actions
159 lines (125 loc) · 5.42 KB
/
Copy pathDockerfile
File metadata and controls
159 lines (125 loc) · 5.42 KB
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# syntax=docker/dockerfile:1
ARG NODE_VERSION=22
ARG PYTHON_VERSION=3.13
ARG UV_VERSION=0.12.3
################################ Overview
# This Dockerfile builds a Label Studio environment.
# Build context is the repository root.
# Stages:
# 1. "uv" - Pinned uv binary.
# 2. "frontend-builder" - Compiles the frontend assets using Bun.
# 3. "venv-builder" - Prepares the virtualenv environment.
# 4. "production" - Final image with Label Studio, Nginx, and other dependencies.
# label-studio-sdk is a git-pinned dependency in pyproject.toml/uv.lock
# (maintained by the monorepo sync); uv fetches it during the build.
################################ Stage: uv (pinned uv binary)
FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv
################################ Stage: frontend-builder (build frontend assets)
FROM --platform=${BUILDPLATFORM} oven/bun:1.3-alpine AS frontend-builder
ENV BUILD_NO_SERVER=true \
BUILD_NO_HASH=true \
BUILD_NO_CHUNKS=true \
BUILD_MODULE=true \
NODE_ENV=production \
NODE_OPTIONS="--max-old-space-size=4096"
WORKDIR /label-studio/web
RUN apk add --no-cache git
COPY web/package.json \
web/bun.lock \
./
RUN --mount=type=cache,target=/root/.bun/install/cache,id=bun-install-cache-lso,sharing=locked \
bun install --frozen-lockfile --prefer-offline
COPY web ./
# Target path for django-manifest-plugin → label_studio/core/static/js/manifest.json (collectstatic input).
RUN mkdir -p /label-studio/label_studio/core/static/js
COPY pyproject.toml ../pyproject.toml
RUN --mount=type=cache,target=/root/.bun/install/cache,id=bun-install-cache-lso,sharing=locked \
bun run build
################################ Stage: venv-builder (prepare the virtualenv)
FROM python:${PYTHON_VERSION}-alpine AS venv-builder
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
UV_CACHE_DIR="/.uv-cache" \
UV_PROJECT_ENVIRONMENT="/label-studio/.venv" \
UV_LINK_MODE="copy" \
UV_COMPILE_BYTECODE=1 \
UV_PYTHON_DOWNLOADS=never \
PATH="/label-studio/.venv/bin:$PATH"
RUN apk add --no-cache \
build-base \
git \
linux-headers \
python3-dev \
pcre2-dev
# Install uv
COPY --from=uv /uv /usr/local/bin/uv
WORKDIR /label-studio
# --- Phase 1: Install dependencies (highly cacheable) ---
# Copy only manifest files — no source code. This layer is invalidated only
# when pyproject.toml or uv.lock change, preserving expensive C-extension
# builds across source edits. label-studio-sdk comes from its git pin.
COPY pyproject.toml uv.lock README.md ./
ARG INCLUDE_DEV=false
RUN --mount=type=cache,target=/.uv-cache,id=uv-cache-alpine,sharing=locked \
if [ "$INCLUDE_DEV" = "true" ]; then \
uv sync --frozen --no-install-project --group test --extra uwsgi; \
else \
uv sync --frozen --no-install-project --no-dev --extra uwsgi; \
fi
# --- Phase 2: Install project (only reruns on source changes) ---
COPY label_studio ./label_studio
# Vite emits this path in frontend-builder; collectstatic must see it before STATIC_ROOT is populated.
COPY --from=frontend-builder /label-studio/label_studio/core/static/js/manifest.json ./label_studio/core/static/js/manifest.json
COPY --from=frontend-builder /label-studio/label_studio/core/static/js/sw.js ./label_studio/core/static/js/sw.js
COPY --from=frontend-builder /label-studio/label_studio/core/static/js/sw.js.map ./label_studio/core/static/js/sw.js.map
RUN --mount=type=cache,target=/.uv-cache,id=uv-cache-alpine,sharing=locked \
if [ "$INCLUDE_DEV" = "true" ]; then \
uv sync --frozen --group test --extra uwsgi; \
else \
uv sync --frozen --no-dev --extra uwsgi; \
fi
# Collect static files
RUN DJANGO_SETTINGS_MODULE=core.settings.label_studio python3 ./label_studio/manage.py collectstatic --no-input
################################### Stage: prod
FROM python:${PYTHON_VERSION}-alpine AS production
ENV LS_DIR=/label-studio \
HOME=/label-studio \
LABEL_STUDIO_BASE_DATA_DIR=/label-studio/data \
OPT_DIR=/opt/heartex/instance-data/etc \
PATH="/label-studio/.venv/bin:$PATH" \
DJANGO_SETTINGS_MODULE=core.settings.label_studio \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
WORKDIR $LS_DIR
# install prerequisites for app
RUN apk upgrade --no-cache && apk add --no-cache \
expat \
glib \
nginx \
bash \
procps
RUN set -eux; \
mkdir -p $LS_DIR $LABEL_STUDIO_BASE_DATA_DIR $OPT_DIR && \
chown -R 1001:0 $LS_DIR $LABEL_STUDIO_BASE_DATA_DIR $OPT_DIR /var/log/nginx /etc/nginx
COPY --chown=1001:0 deploy/default.conf /etc/nginx/nginx.conf
COPY --chown=1001:0 LICENSE LICENSE
COPY --chown=1001:0 licenses licenses
COPY --chown=1001:0 deploy deploy
# Copy files from build stages
COPY --chown=1001:0 --from=venv-builder /label-studio $LS_DIR
COPY --chown=1001:0 --from=frontend-builder /label-studio/web/dist $LS_DIR/web/dist
ARG COMMIT_VERSION=N/A
ARG COMMIT_BRANCH=N/A
ARG COMMIT_MESSAGE=N/A
ARG COMMIT_DATE=N/A
ARG COMMIT_SHA=N/A
ENV COMMIT_VERSION=${COMMIT_VERSION} \
COMMIT_BRANCH=${COMMIT_BRANCH} \
COMMIT_MESSAGE=${COMMIT_MESSAGE} \
COMMIT_DATE=${COMMIT_DATE} \
COMMIT_SHA=${COMMIT_SHA}
RUN echo "info = {'message': '${COMMIT_MESSAGE}', 'commit': '${COMMIT_SHA}', 'date': '${COMMIT_DATE}', 'branch': '${COMMIT_BRANCH}', 'version': '${COMMIT_VERSION}'}" > $LS_DIR/label_studio/core/version_.py
USER 1001
EXPOSE 8080
ENTRYPOINT ["./deploy/docker-entrypoint.sh"]
CMD ["label-studio"]