Zabalenie služby do Docker obrazu

o tom, ako distribuovať svoju aplikáciu vo forme Docker obrazu

Video pre cvičenie

Motivácia

Na minulom cvičení sme si vytvorili jednoduchú notifikačnú službu s názvom Notifier, pomocou ktorej bude môcť ktokoľvek, kto je šúčasťou infraštruktúry Smart department posielať notifikácie pomocou knižnice Apprise. A keďže budeme chcieť na vytvorenej službe zarobiť obrovské prachy, pokúsime sa ju dnes zabaliť do Docker obrazu, aby sme ju tým pádom vedeli nasadiť kdekoľvek.

Docker Logo: Mobydock

Ciele

  • naučiť sa vytvoriť Docker obraz pre svoju aplikáciu

  • extrahovať konfiguráciu aplikácie mimo jej kód

  • naučiť sa ovládať aplikáciu bežiacu v kontajneri pomocou premenných prostredia

Postup

Make Something Working

V prvom kroku sa pokúsime spraviť nutné minimum na to, aby sme vytvorili Docker obraz s našou službou. Nutné minimum znamená, že neaplikujeme best practices, ale že sa sústredíme len na to, aby sme službu ako Docker kontajner vedeli úspešne spustiť.

Task

Vo svojom projekte vytvorte súbor Dockerfile, pomocou ktorého vytvoríme Docker obraz služby.

Súbor Dockerfile vytvorte v koreňovom priečinku vášho projektu. Podoba projektu po jeho vytvorení bude vyzerať nasledovne:

./
├── Dockerfile
├── readme.md
├── requirements.txt
└── src/
    ├── main.py
    └── models.py

Task

Vytvorte minimálny funkčný Docker obraz.

Vytvorenie každého Docker obrazu sa obyčajne skladá z týchto základných častí:

  • výber základného obrazu pomocou kľúčového slova FROM,
  • inštalácia potrebných balíkov pre spustenie aplikácie pomocou kľúčového slova RUN,
  • prekopírovanie zdrojových súborov aplikácie pomoocu kľúčového slova COPY, a
  • spustenie aplikácie pri spustení kontajnera pomocou kľúčového slova CMD alebo ENTRYPOINT

Základná podoba tohto súboru bude pre nás vyzerať nasledovne:

# base image
FROM python:3.14-slim

# mkdir /app && cd /app
WORKDIR /app

# install requirements/dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir --requirement requirements.txt \
    && rm requirements.txt

# copy src files
COPY src/ .

# command to run when container starts
CMD [ "/usr/bin/env", "python3", "main.py" ]

Task

Na základe vytvoreného súboru Dockerfile vytvorte Docker obraz s názvom notifier.

Docker obraz môžete vytvoriť nasledovným príkazom:

$ docker image build --tag notifier .

Overiť si úspešne vytvorený obraz môžete spustením príkazu na vypísanie zoznamu všetkých obrazov:

REPOSITORY                           TAG                 IMAGE ID       CREATED        SIZE
notifier                             latest              2a290634240b   6 hours ago    154MB
python                               3.14-slim           88fe63acba12   4 weeks ago    119MB

Task

Overte vytvorený Docker obraz spustením kontajnera.

Overiť vytvorený obraz môžete spustením nasledujúceho príkazu z príkazového riadku:

$ docker container run --rm -it notifier

Kontajner sa síce spustí, ale okamžite sa ukončí.

Running Container with Application Settings

Po spustení sa kontajner okamžite ukončil, pretože nedostal potrebnú konfiguráciu. Ako teda zabezpečiť, aby sme do kontajnera vedeli vniesť konfiguračné hodnoty prostredníctvom premenných prostredia?

V tomto kroku pripravíme všetko potrebné na to, aby sa kontajner spustil spolu s konfiguráciou uloženou v environmentálnych premenných.

Task

Spustite kontajner z vytvoreného obrazu spolu s premennými prostredia.

Vlastnosti služby je možné nastaviť pri spustení kontajneru pomocou premenných prostredia. To je možné urobiť opäť viacerými spôsobmi:

  1. Pomocou IDE - Premenné prostredia je možné nastaviť v dialógu pre spustenie ako aplikácie z prostredia, tak aj pre spustenie kontajnera zo súboru Dockerfile.

  2. Z príkazového riadku pomocou voľby --env príkazu:

    $ docker container run --rm -it \
        --name notifier \
        --env NOTIFIER_BROKER=147.232.205.176 \
        --env NOTIFIER_PORT=8883 \
        --env NOTIFIER_USERNAME=student \
        --env NOTIFIER_PASSWORD=dgRk9cQ8sU4fCO \
        --env NOTIFIER_SSL=true \
        --env NOTIFIER_TOPIC_PREFIX=services/notifier \
        --env NOTIFIER_UID=ab123cd \
        notifier
  3. Z príkazového riadku pomocou voľby --env-file, pomocou ktorej zadáme umiestnenie súboru s premennými prostredia:

    $ docker container run --rm -it \
        --name notifier \
        --env-file local.env \
        notifier
  4. Kombináciou volieb --env a --env-file:

    $ docker container run --rm -it \
        --name notifier \
        --env-file local.env \
        --env NOTIFIER_BROKER=mother.fei.tuke.sk \
        notifier

Task

Overte, že sa v kontajneri naozaj predmetné premenné prostredia nachádzajú.

Vypísať zoznam premenných prostredia je možné zadaním príkazu printenv vo vnútri kontajneru. To zabezpečíme týmto príkazom:

$ docker container run --rm -it \
    --env-file local.env \
    notifier printenv

Publishing Image to Repository

Obraz sme vytvorili a je pripravený na používanie. Vypublikujeme ho do repozitára hub.docker.com, aby sme ho vedeli použiť odkiaľkoľvek a rovnako, aby ho vedel použiť ktokoľvek.

Task

Prihláste sa do účtu hub.docker.com.

$ docker login

Task

Odošlite do svojho účute v repozitári hub.docker.com vytvorený obraz služby notifier.

Najprv označkovať obraz:

$ docker image tag notifier:latest USER/notifier:latest
$ docker image tag notifier:latest USER/notifier:2025
$ docker image tag notifier:latest USER/notifier:2025.1

Následne obraz odošleme spolu so všetkými značkami:

$ docker image push --all-tags USER/notifier

Task

Overte úspešnosť odoslania.

Ak ste postupovali správne, tak po zobrazení svojho profilu na serveri hub.docker.com, uvidíte svoj obraz.

(Some) Best Practices

Ak sa budete snažiť nasadzovať svoje riešenia vo forme Docker kontajnerov, určite budete hľadať spôsoby, ako to robiť čo najlepšie. Na internete nájdete obrovské množstvo videí a iných zdrojov, ktoré sa vám budú snažiť ponúkať tie najlepšie best practices. My sa v tomto kroku pozrieme na niekoľko z nich.

Task

Zabezpečte, aby sa aplikácia v kontajneri spustila pod právami používateľa pythonista.

Používateľa treba v obraze najprv vytvoriť. To je možné napr. nasledovným rozšírením príkazu RUN v súbore Dockerfile:

RUN groupadd --gid 1000 pythonista \
    && useradd --uid 1000 --gid 1000 --no-create-home pythonista \
    && pip install --no-cache-dir --requirement requirements.txt \
    && rm requirements.txt

Po poslednom príkaze RUN použíjeme príkaz USER s uvedením mena používateľa, pod ktorým sa spustí aplikácia v kontajneri. Výsledný súbor Dockerfile bude vyzerať nasledovne:

FROM python:3.14-slim

WORKDIR /app
COPY requirements.txt .
RUN groupadd --gid 1000 pythonista \
    && useradd --uid 1000 --gid 1000 --no-create-home pythonista \
    && pip install --no-cache-dir --requirement requirements.txt \
    && rm requirements.txt
COPY src/ .

USER maker
CMD [ "/usr/bin/env", "python3", "main.py" ]

Task

Overte úspešnosť vykonaných zmien.

Do spusteného kontajnera sa môžete dostať spustením interpretera príkazov v ňom. To je možné opäť pomocou vývojového prostredia ako aj priamo z príkazového riadku príkazom:

$ docker container exec --it notifier bash

Meno používateľa uvidíte rovno v prompte alebo si aktuálneho používateľa spolu s jeho skupinou môžete zistiť spustením príkazu id v kontajneri:

$ id
uid=1000(maker) gid=1000(maker) groups=1000(maker)

Task

Vytvorte samostatný skript healthcheck.py, pomocou ktorého zabezpečíte kontrolu stavu služby.

Healthcheck mechanizmus je veľmi dôležitý a umožní nám overiť, či služba naozaj funguje tak, ako má. V našom prípade spravíme jednoduché overenie, ktoré bude vyzerať asi takto:

  1. Pripojíme sa na MQTT broker. Tým overíme aj to, či konfigurácia, ktorú pre službu máme, je správna.

  2. Prihlásime sa na odber témy o stave našej služby. Po jej prijatí overíme, či služba stále pracuje a nedošlo náhodou k uviaznutiu v kóde, kedy proces zostal spustený, ale prestal komunikovať s MQTT brokerom. Netreba zabudnúť overiť situáciu, ak správa prijatá nebola.

  3. Odpojíme sa.

Dôležité však bude nastaviť návratový kód (tzv. exit status) podľa výsledku kontroly. To znamená, že:

  • ak kontrola prebehla neúspešne (nesprávna konfigurácia, nesprávna správa v téme /status, žiadna prijatá správa z témy /status, správa offline), ukončite aplikáciu s kódom 1
  • ak kontrola prebehla úspešne, ukončite aplikáciu s kódom 0

Task

Overte správnosť svojej implementácie.

Skontrolujte stavový kód sputenej aplikácie pre všetky možné prípady.

Task

Pridajte do súboru Dockerfile kontrolu stavu zdravia pomocou kľúčového slova HEALTHCHECK.

Kontrolu zdravia nastavte nasledovne:

  • interval kontrol nastavte na každých 30 sekúnd
  • interval timeout nastavte na 10 sekúnd
  • stav nezdravý vyhláste po 3 pokusoch

Výsledná konfigurácia môže vyzerať takto:

HEALTHCHECK \
    --interval=30s \
    --timeout=10s \
    --retries=3 \
    CMD /usr/bin/env python3 /app/healthcheck.py || exit 1

Task

Overte správnosť svojej konfigurácie.

Ďalšie úlohy

  1. Aktualizujte súbor readme.md a spravte z neho podklad pre opis obrazu pre váš obraz na stránke hub.docker.com.

Ďalšie zdroje