← Vissza a bloghoz Útmutató

Python alkalmazás dockerizálása lépésről lépésre

Csomagold konténerbe a Python (Flask/FastAPI) alkalmazásod: helyes alapkép-választás, requirements cache, nem-root felhasználó és karcsú végső image.

A Python az egyik legnépszerűbb nyelv webes API-k és háttérszolgáltatások írásához, és pont ezért érdemes konténerbe csomagolni: a Python verziók, a rendszerkönyvtárak és a virtualenv-ek dzsungelét a Docker egyetlen, hordozható image-be zárja. Ebben a cikkben egy valódi Flask (és FastAPI) alkalmazást dockerizálunk — kiválasztjuk a megfelelő alapképet, cache-barátra építjük a függőségtelepítést, nem root felhasználót használunk, és produkciós alkalmazásszervert teszünk a konténerbe.

A példa alkalmazás

Induljunk egy minimális Flask appból. A projekt szerkezete:

my-api/
├── requirements.txt
├── app.py

Az app.py:

from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/")
def index():
    return jsonify(message="Helló a konténerből!")

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

A requirements.txt:

flask==3.0.3
gunicorn==22.0.0

A gunicorn lesz a produkciós WSGI-szerver — a Flask beépített fejlesztői szervere nem éles használatra való. Ha a Dockerfile alapjait még csiszolnád, nézd meg a Dockerfile írása lépésről lépésre cikket.

A .dockerignore

Mint mindig, itt is a .dockerignore-ral kezdünk, hogy a build kontextus tiszta maradjon:

__pycache__
*.pyc
*.pyo
.venv
venv
.env
.git
.pytest_cache
.mypy_cache

⚠️ Figyelem: A .venv (virtualenv) mappát mindenképp hagyd ki! Egy hoston létrehozott virtualenv abszolút útvonalakat és platformfüggő binárisokat tartalmaz, amelyek a konténerben elromlanak. A függőségeket a konténerben telepítjük újra, tisztán.

Az alap Dockerfile

A Dockerfile sorrendje itt is a cache-elésről szól — a requirements.txt a forrás elé kerül:

FROM python:3.12-slim

WORKDIR /app

# Tisztább, kiszámíthatóbb Python-viselkedés konténerben
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

# Először csak a függőséglista
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Most jön a forráskód
COPY . .

EXPOSE 8000

CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

A fontos döntések:

  • python:3.12-slim – a slim változat lényegesen kisebb a teljes image-nél, de a alpine-nal ellentétben glibc-alapú, így nem ütközöl bele a Python natív csomagok (pl. numpy, psycopg2) fordítási gondjaiba. Pythonhoz a slim általában a legjobb arany középút.
  • COPY requirements.txt a forrás előtt – amíg a függőséglistád nem változik, a pip install réteg a cache-ből jön, és nem telepít újra mindent minden kódváltozásnál.
  • pip install --no-cache-dir – a pip letöltési cache-ét nem visszük be az image-be, így kisebb marad.
  • PYTHONUNBUFFERED=1 – a logok azonnal megjelennek, nem ragadnak be a pufferbe; ez konténerben aranyat ér a hibakereséshez.

Build és futtatás

docker build -t my-api:1.0 .
docker run -d -p 8000:8000 --name my-api my-api:1.0

A http://localhost:8000 címen máris válaszol a gunicorn által kiszolgált alkalmazás.

Nem root felhasználó

Alapból a konténer root-ként fut, ami felesleges kockázat. Hozzunk létre egy dedikált felhasználót, és váltsunk rá:

FROM python:3.12-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Dedikált, jogosultság nélküli felhasználó létrehozása
RUN useradd --create-home appuser
USER appuser

EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

💡 Tipp: A USER appuser legyen a függőségtelepítés után, de a futtatás előtt. Így a telepítéshez még megvannak a root-jogok, de maga az alkalmazás már korlátozott jogosultságokkal fut — ez a biztonság egyik legolcsóbb nyeresége.

FastAPI változat

Ha Flask helyett FastAPI-t használsz, csak a szerver és a parancs változik. A requirements.txt:

fastapi==0.111.0
uvicorn[standard]==0.30.1

Az alkalmazás (app.py) és a CMD:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def index():
    return {"message": "Helló a konténerből!"}
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

A FastAPI aszinkron, ezért a uvicorn (ASGI-szerver) a megfelelő futtató. Nagyobb terhelésnél a gunicorn-t is használhatod uvicorn workerekkel, de a fenti egy worker is bőven elég az induláshoz.

Multi-stage build (opcionális, karcsúsításhoz)

Ha natív kiterjesztéseket fordító csomagokat használsz, a fordítóeszközöket nem érdemes a végső image-be vinni. Egy multi-stage build a függőségeket egy builder szakaszban telepíti, majd csak a kész csomagokat másolja át:

FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
ENV PYTHONUNBUFFERED=1
COPY --from=builder /install /usr/local
COPY . .
RUN useradd --create-home appuser
USER appuser
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

Így a végső image csak a futtatáshoz szükséges dolgokat tartalmazza.

Virtualenv vs. konténer

Gyakori kérdés: kell-e virtualenv a konténerben? Röviden: nem feltétlenül. A konténer maga is egy izolált környezet, így a globális pip install itt teljesen rendben van — nincs más Python-projekt, amivel ütközhetne. A virtualenv-et a hoston a .dockerignore-ral kihagyod, a konténerben pedig a rendszerszintű telepítés a bevett gyakorlat.

Összefoglalás

A Python alkalmazások dockerizálásának receptje letisztult: válassz python:3.12-slim alapot, kezdd a .dockerignore-ral (a __pycache__ és a .venv menjen ki), másold be előbb a requirements.txt-t a cache kedvéért, telepíts --no-cache-dir-rel, futtass nem root felhasználóként, és tegyél a konténerbe produkciós szervert (gunicorn Flaskhoz, uvicorn FastAPI-hoz). A virtualenv-et nyugodtan elhagyhatod — a konténer maga az izoláció. Ha natív csomagokkal dolgozol, egy multi-stage build tovább karcsúsítja a végeredményt.

Ha most kezded, nézd meg a Kezdő lépések útmutatót és a Telepítés oldalt, illetve hogy a konténerek hogyan biztosítják ezt az izolációt, olvasd el a Hogyan működik cikket. Fogd a saját Flask vagy FastAPI appodat, és próbáld ki ezt a Dockerfile-t még ma!