Uruchom całą misję w kontenerach
Otrzymujesz działający kod Angular + Spring Boot. Twoim zadaniem jest przygotowanie obrazów, uruchomienie PostgreSQL, połączenie usług i zapisanie całej konfiguracji w Docker Compose.
Cel ćwiczenia
Z1: git switch --detach Z1. Bieżący starter do zajęć nr 2 używa .NET + MySQL; nie mieszaj jego konfiguracji z poleceniami poniżej.Najpierw uruchomisz każdy komponent osobno poleceniami Docker.
Zadanie 0 — instalacja środowiska w domu
To zadanie wykonaj przed laboratorium na własnym komputerze. Instrukcja zakłada pracę na Windowsie z Rancher Desktop. Polecenia Docker możesz później wykonywać z PowerShella, Windows Terminal albo terminala WSL.
Wymagania komputera
- Windows 11 z aktualnymi poprawkami,
- włączona wirtualizacja sprzętowa,
- stałe połączenie z Internetem podczas instalacji i pobierania obrazów,
- zalecane co najmniej 8 GB RAM i 4 rdzenie procesora.
1. Zainstaluj WSL 2
Otwórz PowerShell jako administrator i wykonaj:
wsl --installUruchom ponownie komputer. Następnie otwórz zwykły PowerShell i sprawdź instalację:
wsl --update
wsl --status
wsl --list --verboseDystrybucja widoczna na liście powinna używać wersji 2. Nie musisz wykonywać ćwiczenia w terminalu Linuksa — WSL 2 jest potrzebny Rancher Desktop jako warstwa uruchomieniowa dla kontenerów.
Instrukcja instalacji WSL w Microsoft Learn
2. Zainstaluj Rancher Desktop
- Pobierz aktualny instalator MSI, korzystając z oficjalnej instrukcji Rancher Desktop.
- Uruchom instalator. Na własnym komputerze możesz zezwolić na instalację usługi uprzywilejowanej, aby publikowanie portów nie było ograniczone wyłącznie do
127.0.0.1. - Uruchom Rancher Desktop i poczekaj na zakończenie pierwszej konfiguracji.
- Wybierz Preferences → Container Engine → dockerd (moby). Ten silnik udostępnia Docker API i polecenie
docker. - W Preferences → Kubernetes wyłącz Enable Kubernetes. Kubernetes nie jest potrzebny w tym laboratorium, a jego wyłączenie zmniejsza zużycie zasobów.
3. Zainstaluj pozostałe narzędzia
- Wymagane: Git for Windows do pobrania repozytorium i wysłania rozwiązania.
- Potrzebne w zadaniu 2: DataGrip albo inny klient PostgreSQL zaakceptowany przez prowadzącego.
- Opcjonalne: IntelliJ IDEA lub Visual Studio Code do wygodnej edycji plików.
Nie musisz instalować lokalnie PostgreSQL, JDK, Mavena, Node.js ani nginx. W docelowym rozwiązaniu te narzędzia i procesy będą dostarczane przez obrazy kontenerów.
4. Sprawdź instalację
Upewnij się, że Rancher Desktop jest uruchomiony, a następnie otwórz nowy terminal i wykonaj:
docker version
docker compose version
docker info
docker run --rm hello-world
git --versionPolecenie z obrazem hello-world pobierze niewielki obraz testowy, uruchomi kontener i usunie go po zakończeniu.
Pokaż ściągę z poleceń Docker
docker version— pokazuje wersję klienta oraz serwera. Obie sekcje potwierdzają, że terminal łączy się z działającym silnikiem.docker compose version— sprawdza dostępność Docker Compose.docker info— wyświetla informacje o aktywnym silniku, liczbie kontenerów i obrazów.docker run --rm <obraz>— pobiera obraz, jeśli nie ma go lokalnie, tworzy kontener, uruchamia go i usuwa po zakończeniu dzięki opcji--rm.
hello-world. Kontenera może już nie być na liście, ponieważ opcja --rm usuwa go po zakończeniu.wsl --status i wirtualizację w Menedżerze zadań.Przygotowanie stanowiska
- Otwórz link do zadania przekazany przez prowadzącego w GitHub Classroom.
- Zaakceptuj zadanie. GitHub Classroom automatycznie utworzy Twoje indywidualne repozytorium z kodem startowym.
- Na stronie utworzonego repozytorium wybierz Code → HTTPS i skopiuj adres.
- Otwórz PowerShell, Windows Terminal albo terminal WSL i sklonuj repozytorium. Wybierz środowisko, w którym działają polecenia
gitidocker.
docker version
docker compose version
git --version
git clone <ADRES_TWOJEGO_REPOZYTORIUM>
cd <NAZWA_TWOJEGO_REPOZYTORIUM>Od tego momentu wszystkie polecenia wykonuj wewnątrz sklonowanego repozytorium. To właśnie w nim zapisujesz rozwiązanie i wysyłasz zmiany do GitHub Classroom.
backend, frontend i docs oraz plik README.md.Docelowa architektura
przeglądarka → port hosta
port 8080 kontenera
port 5432 kontenera
Przeglądarka musi mieć dostęp do frontendu i API przez porty hosta. Backend i baza powinny komunikować się we wspólnej sieci Dockera po nazwie kontenera.
Projekt startowy
Aplikacja zarządza listą misji kosmicznych. Backend udostępnia CRUD pod /api/missions, a frontend wyświetla rekordy i pozwala dodawać oraz usuwać misje.
<Twoje repozytorium z GitHub Classroom>/
├── backend/ # Spring Boot + Maven
├── frontend/ # Angular
├── docs/ # mockupy i kontrakt API
├── .env.example
└── README.mdKontrola przed konteneryzacją
Możesz uruchomić aplikacje lokalnie, aby odróżnić problemy aplikacji od problemów konfiguracji Docker. Nie jest to jednak konfiguracja końcowa.
Zadanie 1 — PostgreSQL
Uruchom oficjalny obraz PostgreSQL jako kontener. Samodzielnie dobierz:
- nazwę kontenera, bazę, użytkownika i hasło,
- mapowanie portu umożliwiające dostęp z hosta,
- named volume dla katalogu danych,
- wspólną sieć dla bazy i późniejszego API.
Przykładowe uruchomienie
Poniższe polecenia działają w PowerShellu, Windows Terminal oraz terminalu WSL:
docker network create mission-net
docker volume create postgres-data
docker run -d --name mission-db --network mission-net -p 5432:5432 -e POSTGRES_DB=mission_control -e POSTGRES_USER=mission -e POSTGRES_PASSWORD=mission-pass -v postgres-data:/var/lib/postgresql/data postgres:17mission-db— nazwa kontenera,5432:5432— port hosta i port PostgreSQL w kontenerze,mission_control— nazwa tworzonej bazy,mission/mission-pass— użytkownik i hasło używane wyłącznie w ćwiczeniu,postgres-data— named volume przechowujący dane.
POSTGRES_DB, POSTGRES_USER i POSTGRES_PASSWORD. Sprawdź dokumentację obrazu przed uruchomieniem.Po starcie sprawdź kontener i jego logi:
docker ps
docker logs mission-dbZapisz swoje polecenie — przyda się podczas tworzenia Compose.
Pokaż ściągę z poleceń Docker
docker network create <nazwa>— tworzy sieć, do której można dołączać kontenery.docker volume create <nazwa>— tworzy nazwany wolumen na trwałe dane.docker run [opcje] <obraz>— tworzy i uruchamia kontener z obrazu. Przydatne opcje:-duruchamia w tle,--namenadaje nazwę,--networkdołącza do sieci,-p <host>:<kontener>publikuje port,-e <klucz>=<wartość>ustawia zmienną, a-v <wolumen>:<ścieżka>montuje dane.docker ps— pokazuje działające kontenery; opcja-auwzględnia zatrzymane.docker logs <kontener>— wyświetla logi; opcja-fśledzi nowe wpisy.
mission-db ma stan uruchomiony, obraz postgres:17 i opublikowany port 5432. Otwórz szczegóły kontenera i odszukaj zmienne środowiskowe oraz zamontowany wolumen. W zakładkach Images i Volumes powinny być widoczne odpowiednio obraz PostgreSQL oraz postgres-data.Zadanie 2 — połączenie przez DataGrip
Utwórz nowe źródło danych PostgreSQL. Użyj hosta localhost, opublikowanego portu oraz danych podanych przy starcie kontenera.
- Test Connection kończy się powodzeniem.
- Widać właściwą bazę i schemat.
- Po uruchomieniu backendu pojawia się tabela
missions. - Potrafisz wykonać zapytanie
SELECT.
mission-db potwierdź publikację portu używanego przez DataGrip. W zakładce Logs sprawdź, czy PostgreSQL zakończył inicjalizację i jest gotowy do przyjmowania połączeń.Zadanie 3 — obraz backendu
W katalogu backend utwórz wieloetapowy Dockerfile. Pierwszy etap ma zbudować plik JAR za pomocą Mavena, a drugi uruchomić go na obrazie JRE.
# Szkielet — uzupełnij obrazy, ścieżki i polecenia
FROM ... AS build
WORKDIR ...
COPY ...
RUN ...
FROM ...
WORKDIR ...
COPY --from=build ...
EXPOSE ...
ENTRYPOINT [...]Dodaj .dockerignore. Obraz nie powinien zawierać repozytorium Git, ustawień IDE ani lokalnego katalogu target.
Konfiguracja połączenia
Spring Boot odczytuje ustawienia ze zmiennych DB_URL, DB_USERNAME i DB_PASSWORD. W adresie JDBC użyj nazwy kontenera bazy, a nie localhost.
Pokaż ściągę z poleceń Docker
docker build -t <nazwa>:<tag> <kontekst>— buduje obraz z plikuDockerfile. Kontekst to katalog plików dostępnych dla instrukcjiCOPY; często wskazuje się go kropką.docker image ls— wyświetla lokalne obrazy i pozwala sprawdzić nazwę, tag oraz rozmiar wyniku budowania.docker run [opcje] <nazwa-obrazu>:<tag>— uruchamia kontener z przygotowanego obrazu; konfigurację aplikacji można przekazać opcjami-e,--networki-p.
DB_*, opublikowany port i brak błędów połączenia z bazą w Logs.Zadanie 4 — obraz frontendu
Przygotuj wieloetapowy obraz: Node buduje aplikację Angular, a lekki serwer HTTP udostępnia wynik. Skonfiguruj przekierowanie ścieżki /api do backendu lub przygotuj właściwy adres API na etapie budowania.
Przygotowanie konfiguracji nginx
W projekcie startowym znajduje się szkielet docs/mockups/nginx.conf.mockup. Na jego podstawie utwórz plik frontend/nginx.conf, uzupełnij znaczniki <...> i dopiero wtedy skopiuj ten plik w Dockerfile do katalogu konfiguracji nginx.
frontend/proxy.conf.json jest używany przez ng serve podczas pracy lokalnej. Kontener produkcyjny uruchamia nginx, dlatego potrzebuje osobnego pliku nginx.conf. Nazwa hosta w proxy_pass powinna wskazywać kontener lub usługę backendu, a nie localhost.Pokaż przykładowy plik nginx.conf
Przykład zakłada, że backend jest dostępny w sieci Docker pod nazwą api i słucha na porcie 8080. Jeśli używasz innej nazwy kontenera lub usługi, zmień ją w proxy_pass.
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://api:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}# Szkielet
FROM node:... AS build
WORKDIR ...
COPY package*.json ./
RUN ...
COPY . .
RUN ...
FROM nginx:...
COPY --from=build ...
COPY nginx.conf ...
EXPOSE ...Preferowane rozwiązanie: przeglądarka wysyła żądania do /api, a nginx przekazuje je do kontenera API. Dzięki temu nie trzeba kodować adresu hosta w aplikacji.
Pokaż ściągę z poleceń Docker
docker build -t <nazwa>:<tag> <kontekst>— buduje obraz i oznacza go nazwą oraz tagiem. Opcja-f <plik>pozwala wskazać Dockerfile o innej nazwie lub w innym miejscu.docker run [opcje] <obraz>— uruchamia kontener. Opcja-p <port-hosta>:<port-kontenera>udostępnia serwer HTTP przeglądarce.docker logs <kontener>— pomaga sprawdzić, czy nginx wystartował i czy obsługuje żądania.
Zadanie 5 — komponent po komponencie
- Utwórz sieć.
- Uruchom PostgreSQL z wolumenem.
- Zbuduj obraz backendu.
- Uruchom backend w tej samej sieci i przekaż zmienne.
- Sprawdź endpoint
/actuator/healthoraz CRUD. - Zbuduj obraz frontendu.
- Uruchom frontend w tej samej sieci.
- Dodaj misję w interfejsie i zobacz rekord w DataGrip.
curl http://localhost:8080/actuator/health
curl http://localhost:8080/api/missions
docker ps
docker logs <nazwa-api>Pokaż ściągę z poleceń Docker
docker network create <nazwa>— tworzy wspólną sieć; kontenery dołączone przez--network <nazwa>mogą odwoływać się do siebie po nazwach.docker build -t <obraz> <kontekst>— buduje obraz aplikacji.docker run -d --name <kontener> [opcje] <obraz>— uruchamia nazwany kontener w tle. Powtarzaj polecenie osobno dla każdego komponentu, dobierając jego sieć, porty i zmienne.docker ps,docker logs <kontener>idocker exec -it <kontener> <polecenie>— służą kolejno do sprawdzenia stanu, logów i wykonania polecenia wewnątrz działającego kontenera.
Zadanie 6 — usuń środowisko
Zatrzymaj i usuń utworzone kontenery oraz własną sieć. Usuń obrazy aplikacji, aby Compose musiał je ponownie zbudować. Na razie zachowaj wolumen i sprawdź, czy potrafisz go wskazać.
Następnie usuń także wolumen. To świadomie destrukcyjny krok dotyczący wyłącznie danych ćwiczenia — potwierdź nazwę poleceniem docker volume ls.
Pokaż ściągę z poleceń Docker
docker stop <kontener>— zatrzymuje działający kontener.docker rm <kontener>— usuwa zatrzymany kontener; opcja-fwymusza zatrzymanie i usunięcie.docker network ls/docker network rm <sieć>— wyświetla lub usuwa sieć, której nie używa już żaden kontener.docker image ls/docker image rm <obraz>— wyświetla lub usuwa lokalny obraz.docker volume ls/docker volume rm <wolumen>— wyświetla lub usuwa wolumen. Usunięcie wolumenu oznacza utratę zapisanych w nim danych.
postgres-data nadal istnieje w Volumes; usuń wyłącznie wolumen tego ćwiczenia i sprawdź, czy zniknął z listy.Zadanie 7 — Docker Compose
W katalogu głównym projektu utwórz compose.yaml opisujący trzy usługi. Nie kopiuj poleceń docker run jako tekstu — przełóż ich parametry na deklarację.
services:
db:
# obraz, środowisko, wolumen, healthcheck
api:
# build, środowisko, zależność od zdrowej bazy
frontend:
# build, port, zależność od API
volumes:
# nazwany wolumen danych
networks:
# opcjonalna jawna siećWymagania
- hasła są pobierane z pliku
.env, którego nie commitujesz, .env.exampleopisuje wymagane klucze bez prawdziwych sekretów,- baza posiada healthcheck,
- API startuje po uzyskaniu gotowości bazy,
- tylko porty potrzebne hostowi są publikowane,
- dane PostgreSQL znajdują się w named volume.
docker compose config
docker compose up --build -d
docker compose ps
docker compose logs -f
docker compose downPokaż ściągę z poleceń Docker Compose
docker compose config— sprawdza składnię i pokazuje wynikową konfigurację po uwzględnieniu zmiennych.docker compose build— buduje obrazy usług posiadających sekcjębuild.docker compose up [opcje]— tworzy i uruchamia usługi;--buildwcześniej buduje obrazy, a-dpozostawia środowisko w tle.docker compose ps— pokazuje stan usług należących do projektu.docker compose logs [-f] [usługa]— wyświetla logi wszystkich albo wskazanej usługi;-fśledzi nowe wpisy.docker compose down— usuwa kontenery i sieć projektu, ale domyślnie zachowuje named volumes. Opcja-vusuwa także wolumeny i ich dane.
docker compose down grupa kontenerów powinna zniknąć, a wolumen z danymi pozostać.Diagnostyka
API zgłasza connection refused
Sprawdź nazwę hosta w JDBC, sieć obu kontenerów, gotowość PostgreSQL i logi. W kontenerze localhost oznacza ten sam kontener.
Frontend zwraca 502
Sprawdź nazwę usługi API w konfiguracji nginx, port procesu backendu oraz logi obu usług.
DataGrip nie łączy się z bazą
Sprawdź publikację portu na hosta. Komunikacja między kontenerami nie wymaga publikacji, ale DataGrip działający w Windows jej potrzebuje.
Zmiana hasła nie działa
Zmienne inicjalizacyjne obrazu bazy działają przy tworzeniu pustego katalogu danych. Istniejący wolumen zachowuje wcześniejszą konfigurację.
Kryteria ukończenia
- PostgreSQL działa w kontenerze i przechowuje dane w wolumenie.
- DataGrip łączy się z bazą przez port hosta.
- Backend i frontend posiadają wieloetapowe Dockerfile.
- Frontend wywołuje API, a API zapisuje dane w PostgreSQL.
- Kontenery komunikują się po nazwach usług.
- Całość uruchamia się poleceniem
docker compose up --build. - Dane pozostają po
docker compose downi ponownym starcie. - Sekrety nie znajdują się w kodzie ani historii obrazu.
- Potrafisz znaleźć błąd za pomocą
ps,logs,inspectiexec.
Pytania do samodzielnego sprawdzenia
- Dlaczego API nie powinno używać
localhostjako hosta bazy?Pokaż odpowiedź
Wewnątrz kontenera
localhostwskazuje ten sam kontener, czyli API, a nie PostgreSQL. Kontenery działające we wspólnej sieci powinny komunikować się przez nazwę kontenera lub nazwę usługi zdefiniowaną w Compose. - Czym różni się port kontenera od portu publikowanego na hoście?
Pokaż odpowiedź
Port kontenera jest dostępny w jego własnej przestrzeni sieciowej oraz dla innych kontenerów w tej samej sieci. Publikacja w postaci
<port-hosta>:<port-kontenera>przekierowuje ruch z hosta do kontenera i umożliwia dostęp np. z przeglądarki lub DataGrip. - Co stanie się z danymi po usunięciu kontenera bazy bez wolumenu?
Pokaż odpowiedź
Dane zapisane wyłącznie w zapisywalnej warstwie kontenera zostaną usunięte razem z kontenerem. Named volume przechowuje je poza cyklem życia kontenera, dlatego można podłączyć go do nowej instancji bazy.
- Dlaczego warto rozdzielić etap budowania i uruchamiania obrazu?
Pokaż odpowiedź
Etap budowania może zawierać kompilator, Maven, Node i kod źródłowy, których aplikacja nie potrzebuje podczas działania. Do obrazu końcowego trafiają tylko artefakty i środowisko uruchomieniowe, dzięki czemu obraz jest mniejszy i zawiera mniej zbędnych narzędzi.
- Czy
depends_ongwarantuje gotowość bazy bez healthcheck?Pokaż odpowiedź
Nie. Samo uruchomienie kontenera nie oznacza, że PostgreSQL zakończył inicjalizację i przyjmuje połączenia. Należy zdefiniować
healthcheckbazy i uzależnić start API od warunkuservice_healthy; aplikacja powinna również potrafić ponawiać połączenie. - Kiedy DataGrip wymaga publikacji portu, a kiedy publikacja nie jest potrzebna?
Pokaż odpowiedź
DataGrip uruchomiony w Windows łączy się z bazą przez hosta, dlatego port PostgreSQL musi być opublikowany. Publikacja nie jest potrzebna do komunikacji API z bazą — kontenery w tej samej sieci korzystają z nazwy usługi i wewnętrznego portu bazy.
- Jak sprawdzić wartości konfiguracji wynikowej Compose?
Pokaż odpowiedź
Użyj
docker compose config. Polecenie sprawdza składnię i pokazuje konfigurację po połączeniu plików oraz podstawieniu zmiennych środowiskowych. - Jak usunąć środowisko bez usuwania danych?
Pokaż odpowiedź
Użyj
docker compose downbez opcji-v. Kontenery i sieć projektu zostaną usunięte, ale named volumes pozostaną i mogą zostać ponownie podłączone przy następnym uruchomieniu.