Nedávno som narazil na zdanlivo ľahko riešiteľný problém, ktorý sa v
konečnom dôsledku ukázal trochu zložitejším. Predstavte si aplikáciu, ktorá
sa pripája k databáze. Nič zvláštne. Súbor docker-compose.yml by mohol
vyzerať napríklad takto:
version: '3.2'
services:
db:
image: postgresql:12
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_NON_ROOT_USER: ${POSTGRES_USER}
POSTGRES_NON_ROOT_USER_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- ${STORAGE_PATH}/${INSTANCE_NAME}/db:/var/lib/postgresql/data
app:
image: myapp:1
depends_on:
- db
environment:
INSTANCE_NAME: ${INSTANCE_NAME}
DB_HOST: db
DB_NAME: ${POSTGRES_DB}
DB_USER: ${POSTGRES_USER}
DB_PASSWORD: ${POSTGRES_PASSWORD}
links:
- db:db
volumes:
- ${STORAGE_PATH}/${INSTANCE_NAME}/data:/srv/web/data
ports:
- "${INSTANCE_PORT}:8080"
Vidíme, že kontajner app beží vedľa kontajnera db. Po spustení služby
príkazom docker-compose up -d chceme overiť, že oba kontajnery bežia a
aké porty vystavujú (alebo v prípade databázy skrývajú). Jedným zo spôsobov
je využiť argument --format príkazu docker ps nasledovne:
docker ps --format "table {{.Names}}\t{{.Ports}}"
Výsledok tohto príkazu by mohol vyzerať takto:
NAMES PORTS
app_1 0.0.0.0:8080->8080/tcp
db_1 5432/tcp
Pridávanie ďalších daemonov #
Jednou z výhod ekosystému Docker je možnosť horizontálneho škálovania
služieb. Ak by sme teda chceli spustiť ďalšiu inštanciu služby na rovnakom
hostiteľovi, mohli by sme jednoducho skopírovať adresár služby a upraviť
premenné v súbore .env. Dve premenné, ktoré musia byť zmenené, sú
INSTANCE_NAME a predovšetkým INSTANCE_PORT. Zmena portu je potrebná,
pretože inak by sa kontajnery pokúšali naviazať na rovnaký port, čo
očividne nechceme.
Tento daemon môže byť spustený rovnakým spôsobom ako predchádzajúci. Na
sledovanie bežiacich kontajnerov trochu upravíme príkaz docker ps, aby
sme rozlíšili kontajnery patriace rôznym službám:
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"
Výstup by mohol byť podobný tomuto:
CONTAINER ID NAMES PORTS
0cd27fa1c363 app_1 0.0.0.0:8080->8080/tcp
bd2832c8f6fc app_1 0.0.0.0:8081->8080/tcp
057a4002ce66 db_1 5432/tcp
347a51256c16 db_1 5432/tcp
Všimnite si, že aplikácie sú naviazané na porty 8080 a 8081 na hostiteľskom
systéme. V tomto prístupe je jeden veľký problém. Okrem ID kontajnera
totiž, v závislosti od ostatných aspektov konfigurácie kontajnera, nemusí
byť nič ľahko dostupné v celom výstupe docker ps, čo by nám skutočne
pomohlo rozlíšiť ľudsky čitateľnou formou, o čom sú tie kontajnery.
Labels prichádzajú na pomoc! #
Jedným zo spôsobov riešenia tohto problému je použitie takzvaných labels. Labels umožňujú nastaviť metadáta väčšine Docker objektov, vrátane:
- Images
- Containers
- Local daemons
- Volumes
- Networks
- Swarm nodes
- Swarm services
Podľa dokumentácie možno labels použiť na organizáciu images, zaznamenávanie informácií o licenciách, anotovanie vzťahov medzi kontajnermi, volumes a sieťami, alebo akýmkoľvek spôsobom, ktorý má zmysel pre vašu firmu alebo aplikáciu.
Label môžete ľahko zadať za behu, ale pre jeho trvalejšie zachovanie ho
možno pridať do Dockerfile cez inštrukciu LABEL:
LABEL instance=red # or instance=blue
Po priradení labels a upravení parametra formátu tak, aby zahŕňal labels (ktoré sú predvolene skryté):
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}\t{{.Labels}}"
Výstup môže vyzerať takto:
CONTAINER ID NAMES PORTS LABELS
0cd27fa1c363 app_1 0.0.0.0:8080->8080/tcp instance=red
bd2832c8f6fc app_1 0.0.0.0:8081->8080/tcp instance=blue
057a4002ce66 db_1 5432/tcp
347a51256c16 db_1 5432/tcp
Toto je pekný prístup, keď je Dockerfile pod našou kontrolou, ale to vždy neplatí. Tvrdím, že toto je skôr výnimka ako norma.
Dockerfile nie je môj vlastný #
Tento problém bol vyriešený vo verzii Compose file 3.3. Detaily nájdete v jej dokumentácii. Pridanie labels do Compose súboru je pohodlnejšie, keď je vám služba distribuovaná cez neho.
Pre úplnosť, upravený Compose súbor by mohol vyzerať takto:
version: '3.3' # version bumped to 3.3 or higher
services:
db:
image: postgresql:12
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_NON_ROOT_USER: ${POSTGRES_USER}
POSTGRES_NON_ROOT_USER_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- ${STORAGE_PATH}/${INSTANCE_NAME}/db:/var/lib/postgresql/data
app:
image: myapp:1
depends_on:
- db
environment:
INSTANCE_NAME: ${INSTANCE_NAME}
DB_HOST: db
DB_NAME: ${POSTGRES_DB}
DB_USER: ${POSTGRES_USER}
DB_PASSWORD: ${POSTGRES_PASSWORD}
links:
- db:db
volumes:
- ${STORAGE_PATH}/${INSTANCE_NAME}/data:/srv/web/data
ports:
- "${INSTANCE_PORT}:8080"
labels: # labels in Compose file instead of Dockerfile
- "instance-name": ${INSTANCE_NAME}
Takto je pri zobrazení labels cez príkaz docker ps viditeľný aj názov
inštancie.