diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..49d6a18 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +# Kontekst obrazu backendu - panel ma własny Dockerfile w frontend/. +frontend/ + +__pycache__/ +*.pyc +.git/ +.env +config/ +uploads/ +downloads/ diff --git a/.gitignore b/.gitignore index 3fdf392..3cb8c27 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ downloads/ .DS_Store config/ uploads/ + +# Panel budowany jest z frontend/ i trafia do własnego obrazu. +node_modules/ +frontend/dist/ diff --git a/Dockerfile b/Dockerfile index 2e89168..0a208cb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.13-slim -# Install system dependencies including opus and ffmpeg +# Zależności systemowe: opus dla głosu, ffmpeg do dekodowania audio RUN apt-get update && apt-get install -y \ libopus0 \ libopus-dev \ @@ -8,17 +8,15 @@ RUN apt-get update && apt-get install -y \ build-essential \ && rm -rf /var/lib/apt/lists/* -# Set working directory WORKDIR /app -# Copy requirements first to leverage Docker cache +# Zależności przed źródłami, aby korzystać z cache warstw. COPY requirements.txt . - -# Install Python dependencies RUN pip install --no-cache-dir -r requirements.txt -# Copy the rest of the application COPY . . -# Command to run the bot -CMD ["python", "-u", "main.py"] \ No newline at end of file +EXPOSE 8000 + +# Serwis wystawia wyłącznie API i steruje botem - panel ma własny obraz. +CMD ["python", "-u", "main.py"] diff --git a/compose.yaml b/compose.yaml index 7f52657..e5f64b7 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,15 +1,39 @@ services: + # Bot Discorda wraz z API sterującym. Nie serwuje żadnych plików panelu. discord-bot: build: context: . dockerfile: Dockerfile - container_name: zyrarbot - ports: - - "80:8000" + container_name: zyrarbot-api environment: - DISCORD_TOKEN=${DISCORD_TOKEN} + - GUILD_ID=${GUILD_ID:-} - PYTHONUNBUFFERED=1 volumes: - ./config:/app/config - ./uploads:/app/uploads + # Port wystawiony do debugowania API; panel łączy się siecią wewnętrzną. + ports: + - "8000:8000" + networks: + - zyrarbot restart: unless-stopped + + # Panel webowy: statyczny build Vue serwowany przez nginx, który przekazuje + # /api i /ws do kontenera bota - dzięki temu przeglądarka widzi jedno źródło. + panel: + build: + context: ./frontend + dockerfile: Dockerfile + container_name: zyrarbot-panel + ports: + - "80:80" + depends_on: + - discord-bot + networks: + - zyrarbot + restart: unless-stopped + +networks: + zyrarbot: + driver: bridge diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..c75968d --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,4 @@ +node_modules/ +dist/ +*.tsbuildinfo +README.md diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..9da19cd --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,22 @@ +# --- Etap 1: budowa panelu --------------------------------------------------- +FROM node:22-alpine AS build + +WORKDIR /app + +# Zależności instalujemy przed skopiowaniem źródeł, aby korzystać z cache warstw. +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +# --- Etap 2: serwowanie przez nginx ------------------------------------------ +FROM nginx:1.27-alpine + +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=build /app/dist /usr/share/nginx/html + +EXPOSE 80 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \ + CMD wget -qO- http://localhost/ >/dev/null || exit 1 diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..82487d1 --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,51 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # Nazwa usługi backendu z compose.yaml; zmienna wymusza rozwiązywanie DNS + # w czasie żądania, więc nginx wstaje nawet gdy bot jeszcze się nie podniósł. + resolver 127.0.0.11 valid=10s ipv6=off; + set $backend "http://discord-bot:8000"; + + # Aplikacja jednostronicowa - nieznane ścieżki oddajemy index.html. + location / { + try_files $uri $uri/ /index.html; + } + + # Artefakty Vite mają skrót treści w nazwie, więc można je cache'ować na stałe. + location /assets/ { + expires 1y; + add_header Cache-Control "public, immutable"; + try_files $uri =404; + } + + location /api/ { + proxy_pass $backend; + 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; + + # Wysyłanie plików wideo/audio na serwer - bez limitu rozmiaru. + client_max_body_size 0; + proxy_request_buffering off; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + } + + location /ws { + proxy_pass $backend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + + # Panel trzyma połączenie otwarte i odbiera stan raz na sekundę. + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + } +}