[Docker] komunikácia kontajnerov front-end - back-end nefunguje
Dobrý deň,
vytváram jednoduchu web. multikontajnerovu aplikáciu za pouzitia Docker Desktop. Celkovo je tvorená 4 kontajnermi:
- noSQL databaza MongoDb
- MongoDB admin rozhranie na zobrazenie obsahu databazy z nazvom mongo-express
- backend v Node.js (server vytvorený v Express.js) na komunikáciu z databazou a frontendom (používa vlastný obraz vytvorený cez Dockerfile založený na node)
- frontend je statická web. stránka HTML/CSS + Vanilla JS (používa vlastný obraz vytvorený cez Dockerfile založený na nginx)
všetky kontajneri sú v spoločnej sieti todo-net, problém je, že komunikácia medzi backendom a frontendom nefunguje. Porty vyzeraju nasledovne:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9275ff88b217 todo-nginx "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:3000->80/tcp todo-client
569837f97ded todo-node "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 5000/tcp todo-server
92d1bcc3c6b2 mongo-express "tini -- /docker-ent…" 2 hours ago Up 2 hours 0.0.0.0:8081->8081/tcp mongodb-ui
6c327048c0c8 mongo "docker-entrypoint.s…" 2 hours ago Up 2 hours 27017/tcp mongodb
komunikácia medzi databazou a backendom, alebo databazou a mongo-express tiež funguje, t.j. že cez toho admin klienta vidím dáta, kt. sú v databáze. Problémové kontajneri spusťam príkazmi:
docker build -t todo-node .
docker run --name todo-server --network todo-net --rm -d todo-node
docker build -t todo-nginx .
docker run --name todo-client -p 3000:80 --network todo-net --rm -d todo-nginx
Kod v express.js vyzerá nasledovne:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.get('/todos', (req, res) => {
... // toto odosiela data na front-end
})
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server is running on port ${PORT}...`));
jeho Dockerfile:
FROM node
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 5000
CMD ["node", "server.js"]
na front-ende sa dáta volajú cez fetch:
fetch("http://todo-server:5000/todos").then(res => res.json()).then(data => console.log(data))
// chyba! (vid. screen z konzole)
Frontend evidentně nezná "todo-server". A tomu se asi nedá divit, když ten kód běží u klienta, který je někde jinde.
ved sú v spoločnej sieti, ako by som to mohol upravit aby todo-server poznal? Lebo viem ze express vie tiez vyrenderovat stranku cez views, no chcel som to mat takto... aby boli backend a frontend oddelene v samostatných kontajneroch.
Klient (tedy ten, kdo si tu stránku otevře v browseru) je taky ve společné síti?
myslel som v spoločnej Docker sieti --network todo-net.
Pozri vieš mi napísať ako by sa to dalo opraviť tak, aby to šlo ako som chcel, t.j. frontend a backend v samostatnom kontajneri, ktore vedia komunikovať.
Alebo proste napíš, že sa to takto nedá. Lebo ono ta apka je funkčna...funguje to ak backend pri spustení kontajnera nastavim ako -p 5000:5000, vtedy node.js beží normálne na localhoste a ide získať data ako fetch("http://localhost:5000/todos"), takto to funguje bez problemov...
Len mi natom kus vadí, že musím obsadit zbytočne jeden port 5000, ktorý sa realne nedá využiť len iba zobrazuje json.
Takže dá sa to tak či nie? Aby som zbytočne nezabíjal čas tým čo aj tak nepôjde... nikdy. To je aj dovod prečo sem píšem.
Tak jinak. Jakou adresu zadáváš do prohlížeče, když si chceš tu stránku otevřít? Protože stejnou adresu nejspíš budeš muset zadat do toho frontendového kódu. A v nginixu pak nastavit pravidlo, aby requesty na určitou adresu (tady třeba to "/todos") přesměrovával jinam.
Chápeš doufám, že JS kód v HTML stránce se vykonává v prohlížeči konkrétního uživatele a ne tam, kde je ten HTML soubor na serveru?
ten nginx teda vytvorí samostatný server (podobný tomu node.js) vnútri svojho kontajnera na vlastnom porte 80? Preto to nejde a ani nepojde?
Ano, jedna z funkcí nginxu je webový server. Ale tak to snad víš a proto sis ho tam dal, ne?
Nicméně to není ta hlavní příčina, kterou zdá si mi stále nechápeš. A to je to, že ten JS obsahující fetch() se vykonává na klientovi.