Skrypt wdrozenia w repozytorium, dokumentacja komend compose
Deploy PROD / deploy (push) Successful in 10s
Deploy PROD / deploy (push) Successful in 10s
SKRYPT WDROZENIA `deploy-prod.sh` istnial wylacznie na serwerze, tak samo jak wczesniej cztery zmienne LiveKit w compose: kto odtwarzalby instancje z repozytorium, nie dostalby go wcale. Wchodzi do `scripts/` w wersji dzialajacej, z jedna zmiana: sprawdzeniem czystosci repozytorium na starcie. Powod jest praktyczny. `git merge --ff-only` odrzuca wdrozenie, gdy na serwerze sa lokalne zmiany, ale robi to CICHO: deploy konczy sie statusem "sukces", a kod nie wchodzi na serwer. Zdarzylo sie to dzis i wykrylo dopiero reczne `git log` na produkcji. Teraz skrypt przerywa i wypisuje pliki. NAZWA PROJEKTU W KOMENDACH COMPOSE README uczyl komend produkcyjnych BEZ `-p`, czyli dokladnie tych, ktore wchodza w cudzy projekt. Katalog aplikacji nazywa sie `app`, wiec compose bierze z niego nazwe projektu, a na serwerze z kilkoma aplikacjami trafia w nie te. Zdarzylo sie realnie: `up -d --force-recreate coturn` utworzylo kontener w projekcie drugiej aplikacji tego samego wlasciciela, walczacy o ten sam port 3478. Jedynym ostrzezeniem byl komunikat "Found orphan containers", latwy do przeoczenia. Poprawione 11 komend produkcyjnych plus dwie nowe sekcje: o nazwie projektu i o tym, ze `docker restart` NIE przeladowuje zmiennych z `.env` (argumenty sa zamrozone przy tworzeniu kontenera, wiec po zmianie hasla kontener wstaje ze stara wartoscia, wygladajac na dzialajacy poprawnie). Komendy lokalne zostaja bez `-p`: tam nazwa z katalogu nikomu nie wchodzi w droge. INSTRUKCJA TWORZENIA WEBINARU Uzupelniona o funkcje dodane w ostatnich dniach: link do sali trafiajacy do uczestnika automatycznie (potwierdzenie, przypomnienia, strona zgloszenia), nagrywanie wlaczane przyciskiem w panelu prowadzenia oraz rozmycie tla. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -373,7 +373,7 @@ rozjedzie sie z kodem przy dodaniu nowego ustawienia.
|
||||
### Krok 4: uruchomienie
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml --env-file .env.production up -d --build
|
||||
docker compose -p akademia -f docker-compose.prod.yml --env-file .env.production up -d --build
|
||||
```
|
||||
|
||||
Pierwszy build pobiera zaleznosci Mavena i npm, wiec trwa kilka minut.
|
||||
@@ -381,7 +381,7 @@ Pierwszy build pobiera zaleznosci Mavena i npm, wiec trwa kilka minut.
|
||||
Sprawdz, czy wszystkie kontenery dzialaja:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml --env-file .env.production ps
|
||||
docker compose -p akademia -f docker-compose.prod.yml --env-file .env.production ps
|
||||
```
|
||||
|
||||
### Krok 5: haslo administratora i pierwsze logowanie
|
||||
@@ -389,7 +389,7 @@ docker compose -f docker-compose.prod.yml --env-file .env.production ps
|
||||
Jesli `ADMIN_PASSWORD` bylo puste, odczytaj wygenerowane haslo z logu:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml --env-file .env.production \
|
||||
docker compose -p akademia -f docker-compose.prod.yml --env-file .env.production \
|
||||
logs backend | grep -A6 "UTWORZONO PIERWSZE KONTO"
|
||||
```
|
||||
|
||||
@@ -461,24 +461,68 @@ Sprawdz jeszcze:
|
||||
|
||||
```bash
|
||||
git pull
|
||||
docker compose -f docker-compose.prod.yml --env-file .env.production up -d --build
|
||||
docker compose -p akademia -f docker-compose.prod.yml --env-file .env.production up -d --build
|
||||
```
|
||||
|
||||
Migracje Flyway wykonuja sie automatycznie przy starcie backendu. Przed
|
||||
aktualizacja wykonaj kopie zapasowa, patrz sekcja nizej.
|
||||
|
||||
### Nazwa projektu jest obowiazkowa, gdy serwer dzieli kilka aplikacji
|
||||
|
||||
**`-p <nazwa>` w kazdej komendzie `docker compose`.** Bez tej flagi compose
|
||||
bierze nazwe projektu **z katalogu roboczego**, a katalogi bywaja nazwane
|
||||
ogolnie (`app`, `www`, `docker`). Na serwerze z kilkoma aplikacjami konczy sie
|
||||
to wejsciem w cudzy projekt: `up -d` restartuje wtedy nie te uslugi, a
|
||||
`up -d <usluga>` tworzy obcy kontener walczacy o ten sam port hosta.
|
||||
|
||||
Zdarzylo sie to realnie na instancji, gdzie katalog nazywal sie `app`, a na tym
|
||||
samym serwerze stala druga aplikacja w projekcie o tej samej nazwie. Jedynym
|
||||
ostrzezeniem byl latwy do przeoczenia komunikat "Found orphan containers".
|
||||
|
||||
Nazwa projektu ma odpowiadac instancji, nie katalogowi. Po kazdej recznej
|
||||
komendzie warto sprawdzic, czy nie przybylo kontenerow z obcym prefiksem:
|
||||
|
||||
```bash
|
||||
docker ps --format '{{.Label "com.docker.compose.project"}}\t{{.Names}}\t{{.Status}}' | sort
|
||||
```
|
||||
|
||||
### Zmienne z `.env` wymagaja odtworzenia kontenera, nie restartu
|
||||
|
||||
**`docker restart` NIE przeladowuje `.env`.** Argumenty uruchomienia sa
|
||||
zamrozone w konfiguracji kontenera przy jego tworzeniu, wiec po zmianie hasla
|
||||
albo klucza kontener wstaje ze **stara wartoscia**, wygladajac przy tym na
|
||||
dzialajacy poprawnie. Objawia sie to dopiero tym, ze usluga cicho nie
|
||||
uwierzytelnia sie u drugiej strony.
|
||||
|
||||
```bash
|
||||
# zmiana wartosci w .env: konieczne odtworzenie
|
||||
docker compose -p akademia -f docker-compose.prod.yml --env-file .env.production up -d --force-recreate coturn
|
||||
|
||||
# sprawdzenie, ze kontener ma wartosc z pliku, bez pokazywania sekretu
|
||||
docker inspect akademia-coturn-1 --format '{{json .Config.Cmd}}' | grep -o 'webinar:[^"]*' | cut -d: -f2 | sha256sum | cut -c1-16
|
||||
grep '^TURN_PASSWORD=' .env.production | cut -d= -f2- | sha256sum | cut -c1-16
|
||||
```
|
||||
|
||||
### Zatrzymanie i restart
|
||||
|
||||
```bash
|
||||
# restart pojedynczej uslugi
|
||||
docker compose -f docker-compose.prod.yml --env-file .env.production restart backend
|
||||
# restart pojedynczej uslugi (bez zmian w .env)
|
||||
docker compose -p akademia -f docker-compose.prod.yml --env-file .env.production restart backend
|
||||
|
||||
# zatrzymanie calosci, dane w wolumenach zostaja
|
||||
docker compose -f docker-compose.prod.yml --env-file .env.production down
|
||||
docker compose -p akademia -f docker-compose.prod.yml --env-file .env.production down
|
||||
```
|
||||
|
||||
Nie uzywaj `down -v` na produkcji: ta komenda usuwa wolumeny wraz z danymi.
|
||||
|
||||
### Wdrozenie automatyczne
|
||||
|
||||
`scripts/deploy-prod.sh` pobiera zmiany z `main` i przebudowuje obrazy.
|
||||
Wolany przez Gitea Actions po kazdym pushu, dziala takze recznie. Skrypt
|
||||
**przerywa wdrozenie, gdy repozytorium na serwerze ma lokalne zmiany**:
|
||||
`git merge --ff-only` i tak by ich nie nadpisal, ale robil to cicho, wiec
|
||||
deploy konczyl sie statusem "sukces", a kod nie wchodzil na serwer.
|
||||
|
||||
## Kopia zapasowa i odtworzenie
|
||||
|
||||
### Wykonanie kopii
|
||||
@@ -554,7 +598,7 @@ wymaga **okolo 170 GB**. Przy takiej skali warto:
|
||||
docker system df -v | grep minio-data
|
||||
|
||||
# baza
|
||||
docker compose -f docker-compose.prod.yml exec -T postgres \
|
||||
docker compose -p akademia -f docker-compose.prod.yml exec -T postgres \
|
||||
psql -U webinar -d webinar -c "SELECT pg_size_pretty(pg_database_size('webinar'));"
|
||||
```
|
||||
|
||||
@@ -602,7 +646,7 @@ oraz zaloguj sie do panelu i obejrzyj liste webinarow i zapisow.
|
||||
2. Skopiuj `env.production.kopia` z kopii jako `.env.production` i ustaw
|
||||
`chmod 600`. Zachowaj **ten sam** `JWT_SECRET`, inaczej wszyscy zostana
|
||||
wylogowani, oraz to samo `DB_PASSWORD`, bo odtwarzana baza go uzywa.
|
||||
3. Uruchom uslugi: `docker compose -f docker-compose.prod.yml --env-file .env.production up -d`.
|
||||
3. Uruchom uslugi: `docker compose -p akademia -f docker-compose.prod.yml --env-file .env.production up -d`.
|
||||
4. Odtworz dane: `./scripts/restore.sh <katalog-kopii>`.
|
||||
5. Przekieruj domene na nowy serwer i sprawdz `/api/health`.
|
||||
|
||||
@@ -634,7 +678,7 @@ albo na Jitsi nie uruchamia niczego zbednego.
|
||||
|
||||
```bash
|
||||
# uzupelnij w .env: LIVEKIT_API_KEY, LIVEKIT_API_SECRET, TURN_PASSWORD
|
||||
docker compose --profile livekit up -d
|
||||
docker compose -p akademia --profile livekit -f docker-compose.prod.yml --env-file .env.production up -d
|
||||
```
|
||||
|
||||
Ten sam klucz i sekret wpisz w panelu (`Ustawienia > Wideo`): tutaj konfiguruja
|
||||
@@ -859,7 +903,7 @@ kart testowych zmieniaja sie miedzy wersjami uslugi.
|
||||
- **Komunikat odrzucony tez jest zapisany**, z oznaczeniem `podpis niepoprawny`.
|
||||
Brak wpisu oznacza, ze notyfikacja w ogole nie dotarla: sprawdz adres
|
||||
w panelu operatora i czy domena ma wazny certyfikat.
|
||||
- `docker compose logs -f backend | grep -i autopay`
|
||||
- `docker compose -p akademia -f docker-compose.prod.yml logs -f backend | grep -i autopay`
|
||||
|
||||
### Reczne nadanie dostepu
|
||||
|
||||
|
||||
@@ -319,6 +319,7 @@
|
||||
<span class="chip">Rola: ADMIN lub MODERATOR</span>
|
||||
<span class="chip">8 zakładek</span>
|
||||
<span class="chip">Zapis jako szkic</span>
|
||||
<span class="chip">Stan na 4 września 2026</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -485,6 +486,12 @@
|
||||
<span class="name">Po webinarze</span> <span class="tech">adres nagrania, adres materiałów</span>
|
||||
<p>Oba adresy trafiają do <strong>maila podsumowującego</strong> wysyłanego automatycznie po zakończeniu. Uzupełnij je przed wysyłką podsumowania; jeśli nagranie pojawi się później, jest osobny przycisk do wysłania powiadomienia o nagraniu.</p>
|
||||
</div>
|
||||
|
||||
<div class="note tip">
|
||||
<span class="ic">💡</span>
|
||||
<p><strong>Linku do spotkania nie musisz nigdzie wpisywać ani wysyłać.</strong> Uczestnik dostaje go automatycznie: w mailu potwierdzającym zapis, w każdym przypomnieniu oraz na stronie swojego zgłoszenia. Sala otwiera się krótko przed startem — kto kliknie wcześniej, zobaczy odliczanie zamiast błędu.</p>
|
||||
<p style="margin-top:8px">Dotyczy to dostawców z własnym pokojem (LiveKit, Jitsi, Daily, Zoom). W trybie <span class="prov">NONE</span> obowiązuje link, który wkleisz w polu „Link do spotkania”.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<span class="name">Nagrania i materiały</span>
|
||||
<p>Osobna zakładka na wgranie plików do własnego składu (po zapisaniu webinaru). Alternatywa dla wklejania adresów zewnętrznych.</p>
|
||||
@@ -514,7 +521,7 @@
|
||||
<tr><th>Dostawca</th><th>Uprawnienia</th><th>Nagrywanie</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><span class="prov">LIVEKIT</span><br><span style="color:var(--ink-faint);font-size:.82rem">domyślny</span></td><td>Egzekwuje serwer (token). Uczestnik nie włączy kamery, nawet podmieniając stronę.</td><td>Automatyczne (wymaga usług Egress + Redis).</td></tr>
|
||||
<tr><td><span class="prov">LIVEKIT</span><br><span style="color:var(--ink-faint);font-size:.82rem">domyślny</span></td><td>Egzekwuje serwer (token). Uczestnik nie włączy kamery, nawet podmieniając stronę.</td><td>Prowadzący włącza przyciskiem w panelu prowadzenia. Plik trafia na Wasz serwer (wymaga usług Egress + Redis).</td></tr>
|
||||
<tr><td><span class="prov">DAILY</span></td><td>Egzekwuje serwer.</td><td>Pobierane od dostawcy po zakończeniu.</td></tr>
|
||||
<tr><td><span class="prov">ZOOM</span></td><td>Osadzone w oknie. Role jak przy Jitsi.</td><td>Po stronie Zoom.</td></tr>
|
||||
<tr><td><span class="prov">JITSI</span></td><td>Z JWT: tylko rola moderatora. Bez JWT: pokój otwarty dla każdego, kto zna adres.</td><td>Ręczne wgranie pliku.</td></tr>
|
||||
@@ -526,6 +533,19 @@
|
||||
<span class="ic">💡</span>
|
||||
<p>Wideo uczestników jest <strong>zawsze wyłączone</strong> na poziomie uprawnień. Prowadzący może w trakcie webinaru włączyć głos wybranej osobie lub — świadomie — kamerę dla wszystkich.</p>
|
||||
</div>
|
||||
|
||||
<p style="margin-top:14px"><strong>Co prowadzący ma pod ręką w trakcie spotkania</strong> (Panel → Webinary → „Prowadzenie”):</p>
|
||||
<ul class="plain">
|
||||
<li><strong>Otwarty mikrofon</strong> — każdy mówi bez proszenia o głos. Włączenie pyta o potwierdzenie, bo otwiera mikrofony całej sali naraz.</li>
|
||||
<li><strong>Wideo dla wszystkich</strong> — każdy uczestnik może włączyć kamerę.</li>
|
||||
<li><strong>Nagraj spotkanie</strong> — start i stop nagrywania. Nagranie <strong>nie startuje samo</strong>: to świadoma decyzja organizatora, a zgoda uczestników na nagranie pozostaje jego sprawą. Gotowy plik pojawia się w zakładce „Nagrania i materiały” w ciągu minuty od zatrzymania.</li>
|
||||
<li><strong>Kolejka zgłoszeń do głosu</strong>, moderacja pytań i ogłaszanie zadań.</li>
|
||||
</ul>
|
||||
|
||||
<div class="note tip">
|
||||
<span class="ic">💡</span>
|
||||
<p><strong>Rozmycie tła.</strong> Każdy, kto ma włączoną kamerę — prowadzący i prelegenci — może rozmyć swoje tło przyciskiem w lewym górnym rogu okna wideo. Włącza się i wyłącza w dowolnym momencie, bez przerywania obrazu. Przydaje się przy prowadzeniu z domu.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Wdrozenie na serwer produkcyjny.
|
||||
#
|
||||
# Wolane przez Gitea Actions (`.gitea/workflows/deploy.yml`) po kazdym pushu
|
||||
# na `main`, ale dziala takze recznie. Kopia na serwerze lezy w
|
||||
# `/opt/akademia/deploy-prod.sh` i musi byc zgodna z ta wersja.
|
||||
#
|
||||
# NAZWA PROJEKTU JEST OBOWIAZKOWA
|
||||
# -----------------------------------------------------------------------------
|
||||
# `-p akademia` NIE jest ozdobnikiem. Katalog aplikacji nazywa sie
|
||||
# `/opt/akademia/app`, wiec bez tej flagi compose bierze nazwe projektu
|
||||
# z katalogu i staje sie projektem `app`. Na tym serwerze `app` to **inna
|
||||
# aplikacja tego samego wlasciciela**, a komenda bez `-p` tworzy w niej obce
|
||||
# kontenery albo restartuje cudze uslugi. Zdarzylo sie to realnie.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
APP_DIR=/opt/akademia/app
|
||||
LOG=/opt/akademia/deploy.log
|
||||
COMPOSE="docker compose -p akademia -f docker-compose.prod.yml --env-file .env.production"
|
||||
|
||||
# Dwa deploye naraz przebudowywalyby ten sam obraz i restartowaly kontener
|
||||
# w polowie pracy drugiego. Blokada jest nieblokujaca: drugi przebieg konczy
|
||||
# sie od razu, zamiast czekac w kolejce z nieaktualnym juz kodem.
|
||||
exec 9>/opt/akademia/deploy.lock
|
||||
flock -n 9 || { echo "$(date '+%F %T') inny deploy trwa - pomijam"; exit 0; }
|
||||
|
||||
exec >>"$LOG" 2>&1
|
||||
echo "===== $(date '+%F %T') deploy start ====="
|
||||
|
||||
cd "$APP_DIR"
|
||||
|
||||
# Lokalne zmiany zatrzymuja wdrozenie, i to jest swiadome: `--ff-only` nizej
|
||||
# i tak by je odrzucil, ale robil to CICHO. Deploy konczyl sie wtedy statusem
|
||||
# "sukces", a kod nie wchodzil na serwer: rozjazd wykrywalo sie dopiero
|
||||
# recznym `git log` na produkcji. Lepiej zaswiecic na czerwono i nazwac pliki.
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "PRZERWANE: repozytorium na serwerze ma lokalne zmiany."
|
||||
echo "Wdrozenie nie ruszy, dopoki ktos ich nie przeniesie albo nie odrzuci:"
|
||||
git status --short
|
||||
echo
|
||||
echo "Zmiana warta zachowania: przenies ja do repozytorium."
|
||||
echo "Zmiana do wyrzucenia: git checkout -- <plik>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git fetch --prune origin
|
||||
LOCAL=$(git rev-parse @)
|
||||
REMOTE=$(git rev-parse '@{u}')
|
||||
|
||||
if [ "$LOCAL" = "$REMOTE" ]; then
|
||||
echo "Brak zmian ($LOCAL) - koniec."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Aktualizacja $LOCAL -> $REMOTE"
|
||||
# --ff-only: nigdy nie scalamy na produkcji. Merge z konfliktem zostawilby
|
||||
# repozytorium w stanie polowicznym, a rozwiazywanie go przez SSH na zywej
|
||||
# instancji jest ostatnia rzecza, ktora ktokolwiek chce robic.
|
||||
git merge --ff-only origin/main
|
||||
|
||||
$COMPOSE up -d --build
|
||||
|
||||
echo "===== $(date '+%F %T') deploy OK (v $REMOTE) ====="
|
||||
Reference in New Issue
Block a user