Jak spustit Python aplikaci v Dockeru

Možná si pamatujete, nebo stále zažíváte takovou tu situaci, kdy vám program funguje krásně na vašem počítači, ale pošlete jej kolegovi a on ho zaboha nespustí. Nebo co hůř, aplikaci nainstalujete na produkční server a ta se prostě nerozběhne. Příčin může být spousta: jiný operační systém, jiná verze operačního systému, špatná verze knihoven potřebných pro chod aplikace, jiné adresářové cesty atd. Nejedná se prostě o laboratorní prostředí, ve kterém by se aplikace spouštěla vždycky stejně. A právě tady přichází na řadu Docker.

Stručně řečeno je Docker virtualizační nástroj, pomocí kterého můžete vytvořit virtuální stroj, kontejner, ve kterém běží operační systém v konkrétní verzi, všechny potřebné knihovny pro běh vaší aplikace a aplikace samotná. Máte plnou kontrolu nad tím, co je v kontejneru nainstalováno, v jakých verzích a v jakých cestách. Pokud spustíte kontejner na svém počítači a všechno bude běžet jak má, je vysoká pravděpodobnost, že tomu bude i na cizím počítači, případně nějakém serveru.

Jak vytvořit Docker image

K vytvoření image, obrazu, který se po spuštění stane kontejnerem, budeme potřebovat naši python aplikaci (můžeme použít například tu, ze článku První webová stránka ve Flasku) a Dockerfile, což je takový náš "recept", jak se má image sestavit. Jedná se o textový soubor obsahující za sebou jdoucí příkazy, pomocí nichž se vrstva po vrstvě tvoří výsledný spustitelný obraz.

FROM debian:bullseye

COPY projekt /app

RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip install uwsgi
RUN pip install -r /app/requirements.txt

WORKDIR /app
EXPOSE 5000

CMD ["uwsgi", "--http", ":5000", "--wsgi-file", "manage.py", "--callable", "app"]

Zkusíme si Dockerfile projít řádek po řádku. Na prvním řádku máme příkaz FROM, který nám říká z jakého základního image budeme vycházet. V rámci maximálního zjednodušení si klidně můžeme docker kontejner představit jako cibuli, která se skládá z vrstev, a každý jeden příkaz v Dockerfile nám přidává jednu vrstvu výsledné cibule. FROM je naše jádro. Příkazem RUN spustíme příkaz v kontejneru. Jelikož vycházíme z Debian image, můžeme použít apt-get pro nainstalování potřebných knihoven. Pokud příkazy dává smysl spouštět dohromady (jako tady update && install), spouštějte je dohromady. Vrstvy se totiž cachují a šetříme tak místo a čas. Příkazem WORKDIR se v kontejneru přepneme do konkrétního adresáře a další příkazy pak můžeme spouštět relativně vůči němu. EXPOSE říká, jaké porty chceme z kontejneru vystavovat ven. Jelikož aplikaci spouštíme na portu 5000, bude to právě tento port. Poslední příkaz je CMD, kterým říkáme, co se má uvnitř kontejneru spustit.

Jak spustit Docker image

"Ubalený" image získá svůj hash, který vypadá podobně jako 7bbd36e21811d305f8a3b2b825dd8e12f42dda8cb52bbfad3815e9c3f2410b0b. Takový image můžeme spustit pomocí příkazu docker run [hash]. 💁‍♂️ Pro zajímavost: pokud se dá docker image jedinečně identifikovat pomocí prvních N znaků hashe, stačí nám právě ty ke spuštění. Můžeme tedy vyzkoušet image spustit pomocí docker run 7bbd3 (nahraďte začátkem svého hashe).

Pokud je všechno v pořádku, měl by se nám spustit kontejner a na standardním výstupu bychom měli vidět uwsgi hlášky. Kontejner nám běží, ale i když máme v Dockerfile EXPOSE nějakého portu, zatím se do aplikace nedostaneme. Při spouštění kontejneru budeme muset využít přepínač -p, který nám zpropaguje port ven do hostujícího stroje. Zkusme:

docker run -p 5000:5000 7bbd3

Po tomto spuštění kontejneru si můžeme otevřít okno prohlížeče a zadat do něj http://localhost:5000. Pokud jsme všechno udělali správně, měla by se nám zobrazit naše webová stránka napsaná v Pythonu a spuštěná v Dockeru. 💪

Užitečné příkaz

  • docker build -f ./Dockerfile
  • docker ps
    • zobrazí seznam spuštěných kontejnerů
  • docker images
    • zobrazí seznam existujících obrazů
  • docker logs [id kontejneru]
    • zobrazí logy (poslané na standardní výstup) daného kontejneru
    • můžeme přidat přepínač -f (follow), který bude výstup neustále číst
  • docker stop [id kontejneru]
    • zastaví spuštěný kontejner
  • docker rm [id kontejneru]
    • smaže existující kontejner
  • docker rmi [id image]
    • smaže vytvořený obraz
  • docker exec [id kontejneru] [příkaz]
    • nad spuštěným kontejnerem spustí zadaný příkaz
    • přepínačem -it můžeme přejít do interaktivního režimu a tak nad běžícím kontejnerem například spustit bash
  • docker run [id image]
    • spustí se aplikace definovaná v Dockerfile
    • můžeme přidat další parametr, kterým "přepíšeme", co se má vlastně v dockeru spustit.
    • přepínačem -it můžeme spustit interaktivní režim, takže například nad vytvořeným obrazem nějaké linuxové distribuce spustit bash.
  • docker tag [id image] [tag]
    • tímto příkazem můžeme "otagovat", "pojmenovat" image nějakým vypovídajícím názvem, než hashem, který nám vznikne při ubalení. 
Štítky
Úroveň znalostí
Začátečník