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í.