بناء تطبيق Python
تجعل عجلات Python (wheels) وأدوات البناء التقسيم النظيف يستحقّ العناء. جمّع وثبّت كل شيء في بيئة افتراضية مكتفية ذاتيًا في مرحلة البناء، ثم انسخ ذلك الدليل الواحد إلى أساس python نحيل للتشغيل. لا تصل المُجمِّعات والترويسات التي تحتاجها بعض الحزم عند التثبيت إلى الصورة التي تنشرها.
يبني هذا على ghcr.io/quenchworks/images/python:3.13. ولحلّ الاعتماديات هناك ghcr.io/quenchworks/images/uv (مثبّت وحلّال سريع) وghcr.io/quenchworks/images/poetry.
ملف Dockerfile المتعدد المراحل
# Build stage: build a venv with everything installed into it.FROM ghcr.io/quenchworks/images/python:3.13 AS buildWORKDIR /appENV VIRTUAL_ENV=/opt/venv \ PATH="/opt/venv/bin:$PATH"
RUN ["python", "-m", "venv", "/opt/venv"]COPY requirements.txt ./RUN ["pip", "install", "--no-cache-dir", "-r", "requirements.txt"]COPY . .
# Runtime stage: copy the venv onto a clean python base, run nonroot.FROM ghcr.io/quenchworks/images/python:3.13 AS runtimeWORKDIR /appENV VIRTUAL_ENV=/opt/venv \ PATH="/opt/venv/bin:$PATH" \ PYTHONUNBUFFERED=1COPY --from=build /opt/venv /opt/venvCOPY --from=build /app /appUSER 1001EXPOSE 8000CMD ["python", "-m", "app"]# Build stage: uv resolves and installs into a project venv, fast.FROM ghcr.io/quenchworks/images/uv:0.11 AS buildWORKDIR /appENV UV_PROJECT_ENVIRONMENT=/opt/venv \ UV_COMPILE_BYTECODE=1
# Install dependencies first (cached) from the lockfile, then the project.COPY pyproject.toml uv.lock ./RUN ["uv", "sync", "--frozen", "--no-install-project", "--no-dev"]COPY . .RUN ["uv", "sync", "--frozen", "--no-dev"]
FROM ghcr.io/quenchworks/images/python:3.13 AS runtimeWORKDIR /appENV PATH="/opt/venv/bin:$PATH" \ PYTHONUNBUFFERED=1COPY --from=build /opt/venv /opt/venvCOPY --from=build /app /appUSER 1001EXPOSE 8000CMD ["python", "-m", "app"]# Build stage: Poetry installs into a venv at a known path.FROM ghcr.io/quenchworks/images/poetry:2 AS buildWORKDIR /appENV POETRY_VIRTUALENVS_IN_PROJECT=true \ POETRY_NO_INTERACTION=1
COPY pyproject.toml poetry.lock ./RUN ["poetry", "install", "--only", "main", "--no-root"]COPY . .RUN ["poetry", "install", "--only", "main"]
FROM ghcr.io/quenchworks/images/python:3.13 AS runtimeWORKDIR /appENV PATH="/app/.venv/bin:$PATH" \ PYTHONUNBUFFERED=1COPY --from=build /app/.venv /app/.venvCOPY --from=build /app /appUSER 1001EXPOSE 8000CMD ["python", "-m", "app"]ماذا تفعل كل مرحلة
- البناء. أنشئ بيئة افتراضية في مسار ثابت وثبّت كل اعتمادية داخلها. تحمل هذه المرحلة الحلّال، وأي خلفيات بناء، واعتماديات بناء العجلات. تثبيت الاعتماديات قبل نسخ بقية المصدر يُبقي تلك الطبقة مخزّنة حين يتغيّر كودك وحده.
- التشغيل. ابدأ من جديد من
python:3.13، وانسخ البيئة الافتراضية والتطبيق، وضع البيئة الافتراضية علىPATH، وانزل إلىuid 1001، وابدأ. لا شيء من سلسلة أدوات البناء يُشحن.
التالي
- تخدم بخادم WSGI/ASGI؟ ضعه في البيئة الافتراضية (gunicorn و uvicorn) واستدعِه مباشرة بصيغة exec:
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]. - ثبّت بالبصمة الرقمية ليجري كل بناء بالضبط على الأساس الذي جرى فحصه وتوقيعه.