Kontejnery a Docker Compose

Jak se služby balí do Docker image a jak je Compose spouští – stejně na PC i ve cloudu.

Na této stránce

V jedné větě: Každá služba má Dockerfile, ze kterého vznikne image s hotovou aplikací; Docker Compose podle deploy/compose.yaml spustí všechny kontejnery, propojí je sítí a dá jim trvalé disky (volumes).

Přirovnání: Image je krabice s nábytkem i návodem – všude se poskládá stejně. Compose je plánek bytu: kam co patří a co je s čím propojené.

Image služeb (Dockerfile)

flowchart LR
    subgraph build["Fáze build (SDK, ~800 MB)"]
        r["dotnet restore<br/>(jen .csproj – cache)"] --> p["dotnet publish<br/>pro cílovou architekturu"]
    end
    subgraph final["Výsledná image (runtime, ~120 MB)"]
        app["/app – zkompilovaná aplikace<br/>+ příručka (Web)"]
        data[("/data – databáze, klíče, logy")]
    end
    p -->|"COPY --from=build"| app
Rozhodnutí Proč
Multi-stage build V produkční image není SDK ani zdrojáky – menší a bezpečnější.
Nejdřív COPY *.csproj + restore Docker si vrstvu pamatuje; při změně kódu se balíčky nestahují znovu.
--platform=$BUILDPLATFORM + -a $TARGETARCH Kompiluje se nativně, výstup pro ARM i x86 – VM v cloudu je ARM.
Uživatel app (ne root) Kdyby někdo aplikaci napadl, nemá v kontejneru práva roota.
Data v /data Na tuhle složku se připojí volume – data přežijí nový image.
Konfigurace přes ENV Cesty k DB, klíčům a logům jde přepsat proměnnou prostředí (12-factor).

Kód: Dockerfile Webu, Dockerfile skladu, .dockerignore (do image se nesmí dostat lokální databáze, logy ani tajnosti).

Sestavení ručně (z kořene repozitáře): docker build -f src/MiniShop.Web/Dockerfile -t minishop-web .

Docker Compose

flowchart TB
    subgraph net["síť Compose 'minishop'"]
        web["web :8080"]
        inv["inventory-api :8080<br/>(zvenku nedostupný)"]
        mq["rabbitmq :5672"]
        dash["aspire-dashboard<br/>OTLP :18889"]
    end
    wv[("web-data<br/>ordering.db, journeys.db,<br/>users.db, klíče, logy")]
    iv[("inventory-data<br/>inventory.db, images/")]
    rv[("rabbitmq-data<br/>fronty")]
    web --- wv
    inv --- iv
    mq --- rv
    web -->|"depends_on: healthy"| inv
    web --> mq
    inv --> mq
    web -.->|telemetrie| dash
    inv -.->|telemetrie| dash

Co dřív dělal Aspire AppHost, dělá teď compose.yaml:

Aspire (AppHost) Compose
AddRabbitMQ(...) služba rabbitmq (image rabbitmq:4-management)
AddProject<...>("inventory-api") služba inventory-api – jméno je zároveň DNS adresa v síti
WithReference(messaging) proměnná ConnectionStrings__messaging
WithReference(inventoryApi) proměnná Services__inventory-api__http__0
WaitFor(...) depends_on + condition: service_healthy
dashboard služba aspire-dashboard (image mcr.microsoft.com/dotnet/aspire-dashboard)

Důležité detaily:

  • Healthcheck .NET služeb – image nemá curl, proto bash otevře TCP spojení přes /dev/tcp a pošle ručně GET /health. Compose pak ví, kdy je služba opravdu připravená.
  • Volumes přežijí docker compose down i nový image. Smaže je jen docker compose down -v.
  • Sklad není publikovaný ven – dostane se k němu jen Web uvnitř sítě Compose.
  • Pevný hostname: rabbitmq – RabbitMQ ukládá data do složky podle jména stroje; bez něj by po novém kontejneru „nenašel“ své fronty.

Lokálně vs. v cloudu

cd deploy && cp .env.example .env && docker compose up -d --build     # PC → http://localhost:8080

Na VM se navíc načte doplněk compose.cloud.yaml (řádek COMPOSE_FILE=compose.yaml:compose.cloud.yaml v production.env):

  • přidá Caddy (HTTPS, heslo) – viz Doména, HTTPS a přístup,
  • Webu a dashboardu odebere publikované porty (ports: !reset []) – ven jde jen přes Caddy,
  • image se berou z GHCR (IMAGE_PREFIX=ghcr.io/ftichy/, IMAGE_TAG=sha-…), lokálně se staví z build:.

Data Protection klíče

ASP.NET podepisuje antiforgery token formulářů klíči. V kontejneru by se po každém restartu (= každém nasazení) vytvořily nové a otevřený formulář objednávky by skončil chybou 400. Proto je Web ukládá do /data/keys na volume.

Na internetu