Ga naar hoofdinhoud

Online zetten: je site in een image

Hier bouw je op verder: Door mappen lopen met cd en ls

Weet je dit niet meer zeker? Lees het terug voordat je verdergaat.

Je site moet een image worden. Wat erin moet, schrijf je op in een bestand: de Dockerfile. Docker volgt dat recept stap voor stap, en bewaart het resultaat als image. Je werkt in je project in Ubuntu, dat je in les 9 kloonde, met VS Code vanuit Ubuntu.

De Dockerfile​

Maak naast main.py een bestand Dockerfile, zonder extensie, met hoofdletter D:

FROM python:3.13-slim

WORKDIR /app

COPY requirements.txt .
RUN python -m pip install -r requirements.txt

COPY . .

CMD ["fastapi", "run", "main.py", "--port", "8000"]

Elke regel is een stap:

RegelWat Docker doet
FROM python:3.13-slimbegin met een image van Docker Hub: een kleine Linux met Python 3.13 erop
WORKDIR /appmaak de map /app en ga erin staan
COPY requirements.txt .kopieer requirements.txt uit je project naar /app
RUN python -m pip install -r requirements.txtinstalleer de packages uit je lijst (les 4)
COPY . .kopieer de rest van je project naar /app
CMD [...]dit commando start een container: fastapi run, op poort 8000

RUN gebeurt één keer, tijdens het bouwen. CMD gebeurt elke keer dat een container start. Een virtual environment is hier niet nodig: in het image draait alleen jouw site, en die mag Python voor zichzelf hebben.

Er staat fastapi run, net als in les 11. Maar er staat geen --host: in een container moet je site op 0.0.0.0 luisteren. In de volgende les zie je waarom.

Wat er niet in hoort​

COPY . . kopieert alles uit je map. Ook .venv uit les 10, en de databases die ontstonden toen je site in Ubuntu draaide. Dat hoort niet in je image: .venv is van jouw Ubuntu, en een database met wachtwoorden zit dan in elk image dat je deelt.

Maak daarom naast de Dockerfile een bestand .dockerignore, dat werkt als .gitignore:

.venv
__pycache__
.git
*.db

Bouwen​

docker build -t gastenboek .

-t gastenboek geeft het image een naam (een tag). De punt aan het eind betekent: de Dockerfile en de bestanden staan in deze map. Docker laat elke stap zien:

=> [1/5] FROM docker.io/library/python:3.13-slim
=> [2/5] WORKDIR /app
=> [3/5] COPY requirements.txt .
=> [4/5] RUN python -m pip install -r requirements.txt
=> [5/5] COPY . .
=> naming to docker.io/library/gastenboek:latest

De eerste keer duurt het een minuut: Docker haalt het Python-image op en installeert alle packages. Bij de pip-stap staat een waarschuwing:

WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead
Waarom mag die waarschuwing blijven staan?

Op je eigen computer is het een goed advies: daar delen Ubuntu en jij dezelfde Python, en daarom maakte je in les 10 een virtual environment. In een image draait alleen jouw site, en het image gooi je weg en bouw je opnieuw zodra er iets mis is. Hier mag je de waarschuwing laten staan, net als de [notice] dat er een nieuwe pip is.

Kijk daarna welke images er zijn:

docker images

Ruim 300 MB, en dat is bijna allemaal Linux, Python en de packages uit je lijst. Je eigen code is een paar kilobyte.

De tweede keer​

Bouw nog een keer, zonder iets te veranderen:

docker build -t gastenboek .

Binnen een seconde is het klaar, met CACHED bij elke stap:

=> CACHED [2/5] WORKDIR /app
=> CACHED [3/5] COPY requirements.txt .
=> CACHED [4/5] RUN python -m pip install -r requirements.txt
=> CACHED [5/5] COPY . .

Docker bewaart het resultaat van elke stap: de cache. Is een stap gelijk aan de vorige keer, en alles ervoor ook, dan pakt hij dat resultaat. Verandert er iets, dan doet hij die stap opnieuw, en alle stappen erna. Daarom staat COPY requirements.txt . apart, vóór COPY . .: de trage pip-stap hangt alleen af van je lijst met packages.

Zet de Dockerfile en .dockerignore in git:

git add Dockerfile .dockerignore
git commit -m "Dockerfile toegevoegd"
git push
Controlevraag
Je zet een nieuw package in requirements.txt en bouwt opnieuw. Welke stappen doet Docker opnieuw?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

Er gaat iets mis​

failed to read dockerfile​

ERROR: failed to build: failed to solve: failed to read dockerfile: open Dockerfile: no such file or directory

Oorzaak: in deze map staat geen bestand dat precies Dockerfile heet. Je staat in een andere map, of het bestand heet dockerfile, Dockerfile.txt of DockerFile.

Oplossing: ga met cd naar je project, en kijk met ls hoe het bestand heet. Linux maakt verschil tussen hoofdletters en kleine letters.

No matching distribution found​

ERROR: No matching distribution found for pywin32==306

Oorzaak: in requirements.txt staat een package dat alleen op Windows bestaat. In het image draait Linux.

Oplossing: haal die regel uit requirements.txt, zoals in les 4, en bouw opnieuw.

The legacy builder is deprecated​

DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/

Oorzaak: docker-buildx is niet geïnstalleerd. Docker bouwt dan op de oude manier; dat werkt nog, maar je ziet de stappen anders.

Oplossing: sudo apt install docker-buildx.

Opdrachten​

Opdracht 1: Run - Een tekst in een template​

Verander een tekst in een template, en bouw opnieuw. Welke stappen staan er nu als CACHED, en welke niet?

Antwoord
docker build -t gastenboek .
=> CACHED [2/5] WORKDIR /app
=> CACHED [3/5] COPY requirements.txt .
=> CACHED [4/5] RUN python -m pip install -r requirements.txt
=> [5/5] COPY . .

Tot en met de pip-stap is er niets veranderd, want requirements.txt is gelijk. Pas de stap die je hele map kopieert, ziet een ander bestand, en die doet Docker opnieuw. Daarom is het in een paar seconden klaar.

Opdracht 2: Investigate - Wat zit erin?​

Start een container van je image, maar met bash in plaats van de server: docker run --rm -it gastenboek bash. Kijk met ls wat er in /app staat, en met python --version welke Python het is. Staat .venv erin? Typ exit als je klaar bent.

Antwoord

In /app staan je bestanden: Dockerfile, main.py, requirements.txt, README.md, static en templates. Geen .venv en geen .db, want die hield .dockerignore buiten het image. python --version geeft Python 3.13 met een nummer erachter, ook als je in Ubuntu of op Windows een andere versie hebt. Een woord achter de naam van het image vervangt de CMD, en --rm gooit de container weg zodra je exit typt.

Door naar les 16: een container draaien.