Compare commits
9 commits
dfb4de6288
...
f5bedb97f0
| Author | SHA1 | Date | |
|---|---|---|---|
| f5bedb97f0 | |||
| 0b3fcdbbc2 | |||
| 97c53a48fb | |||
| 0579527e10 | |||
| 532b32b5c7 | |||
| e30218354d | |||
| ef6f58b4e5 | |||
| 3b464983ce | |||
| 8582daf4c0 |
3 changed files with 180 additions and 0 deletions
29
systemd/gunicorn.conf.py
Normal file
29
systemd/gunicorn.conf.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Gunicorn configuration for FastAPI
|
||||||
|
import multiprocessing
|
||||||
|
|
||||||
|
# Server socket
|
||||||
|
bind = "127.0.0.1:8000"
|
||||||
|
backlog = 2048
|
||||||
|
|
||||||
|
# Worker processes
|
||||||
|
# Rule of thumb: (2 * CPU cores) + 1
|
||||||
|
workers = multiprocessing.cpu_count() * 2 + 1
|
||||||
|
worker_class = "uvicorn.workers.UvicornWorker"
|
||||||
|
worker_connections = 1000
|
||||||
|
timeout = 30
|
||||||
|
keepalive = 2
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
accesslog = "/var/log/karl/access.log"
|
||||||
|
errorlog = "/var/log/karl/error.log"
|
||||||
|
loglevel = "info"
|
||||||
|
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
|
||||||
|
|
||||||
|
# Process naming
|
||||||
|
proc_name = "karl"
|
||||||
|
|
||||||
|
# Graceful shutdown
|
||||||
|
graceful_timeout = 30
|
||||||
|
|
||||||
|
# Preload app for faster worker spawning
|
||||||
|
preload_app = True
|
||||||
119
systemd/install.sh
Normal file
119
systemd/install.sh
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# --- Kolory do logowania ---
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
log() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||||
|
err() { echo -e "${RED}[ERROR]${NC} $1" >&2; exit 1; }
|
||||||
|
|
||||||
|
# --- Sprawdzenie uprawnień roota ---
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
err "Ten skrypt wymaga uprawnień roota. Uruchom z sudo."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 1. Wykrycie menedżera pakietów (apt / dnf) ---
|
||||||
|
if command -v apt-get &>/dev/null; then
|
||||||
|
PKG_MGR="apt-get"
|
||||||
|
PKG_UPDATE="apt-get update -y"
|
||||||
|
PKG_INSTALL="apt-get install -y"
|
||||||
|
elif command -v dnf &>/dev/null; then
|
||||||
|
PKG_MGR="dnf"
|
||||||
|
PKG_UPDATE="dnf check-update || true"
|
||||||
|
PKG_INSTALL="dnf install -y"
|
||||||
|
else
|
||||||
|
err "Nie znaleziono obsługiwanego menedżera pakietów (apt/dnf)."
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Wykryto menedżer pakietów: $PKG_MGR"
|
||||||
|
$PKG_UPDATE
|
||||||
|
|
||||||
|
# --- 2. Instalacja python3, curl, unzip ---
|
||||||
|
log "Instalacja python3, curl, unzip..."
|
||||||
|
$PKG_INSTALL python3 python3-pip curl unzip, git
|
||||||
|
$PKG_INSTALL python3-venv || true
|
||||||
|
|
||||||
|
# --- 3. Instalacja Dockera (jeśli nie zainstalowany) ---
|
||||||
|
if command -v docker &>/dev/null; then
|
||||||
|
log "Docker już zainstalowany — pomijam."
|
||||||
|
else
|
||||||
|
log "Instalacja Dockera..."
|
||||||
|
curl -fsSL https://get.docker.com | bash
|
||||||
|
systemctl enable --now docker
|
||||||
|
log "Docker zainstalowany i uruchomiony."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 4. Utworzenie użytkownika 'karl' ---
|
||||||
|
if id "karl" &>/dev/null; then
|
||||||
|
log "Użytkownik 'karl' już istnieje — pomijam."
|
||||||
|
else
|
||||||
|
log "Tworzenie użytkownika 'karl'..."
|
||||||
|
useradd -m -s /bin/bash karl
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 5. Dodanie 'karl' do grupy 'docker' ---
|
||||||
|
log "Dodawanie użytkownika 'karl' do grupy 'docker'..."
|
||||||
|
usermod -aG docker karl
|
||||||
|
|
||||||
|
# --- 6. Pobranie i rozpakowanie archiwum ---
|
||||||
|
APP_URL="${1:?Podaj URL archiwum ZIP jako pierwszy argument}"
|
||||||
|
APP_DIR="/opt/karl"
|
||||||
|
|
||||||
|
mkdir -p "$APP_DIR"
|
||||||
|
chown karl: "$APP_DIR"
|
||||||
|
|
||||||
|
# --- 7. Backup i czyszczenie istniejącego katalogu ---
|
||||||
|
if [[ -d "$APP_DIR" ]] && [[ -n "$(ls -A "$APP_DIR" 2>/dev/null)" ]]; then
|
||||||
|
log "Katalog $APP_DIR istnieje i nie jest pusty — tworzenie backupu..."
|
||||||
|
CONFIG_DIR="$APP_DIR/config"
|
||||||
|
if [[ -d "$CONFIG_DIR" ]]; then
|
||||||
|
BACKUP_DIR="/home/karl/backups"
|
||||||
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||||
|
BACKUP_PATH="$BACKUP_DIR/config_backup_$TIMESTAMP"
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
cp -r "$CONFIG_DIR" "$BACKUP_PATH"
|
||||||
|
chown -R karl:karl "$BACKUP_DIR"
|
||||||
|
log "Backup utworzony: $BACKUP_PATH"
|
||||||
|
else
|
||||||
|
log "Katalog config nie istnieje — pomijam backup."
|
||||||
|
fi
|
||||||
|
log "Usuwanie katalogu $APP_DIR..."
|
||||||
|
rm -rf "$APP_DIR"
|
||||||
|
log "Katalog $APP_DIR usunięty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 8. Instalacja / aktualizacja ---
|
||||||
|
log "Pobieranie archiwum z: $APP_URL"
|
||||||
|
mkdir -p "$APP_DIR"
|
||||||
|
TMPZIP=$(mktemp /tmp/karl-app-XXXXXX.zip)
|
||||||
|
curl -fSL -o "$TMPZIP" "$APP_URL"
|
||||||
|
unzip -o "$TMPZIP" -d "$APP_DIR"
|
||||||
|
rm -f "$TMPZIP"
|
||||||
|
chown -R karl:karl "$APP_DIR"
|
||||||
|
log "Aplikacja rozpakowana do $APP_DIR"
|
||||||
|
|
||||||
|
# --- 9. Instalacja uv i synchronizacja zależności (uv sync) ---
|
||||||
|
sudo -u karl bash -c "cd /opt/karl/app && python3 -m venv .venv && source .venv/bin/activate && pip install uv && uv sync"
|
||||||
|
|
||||||
|
# --- 10. Kopiowanie pliku usługi systemd ---
|
||||||
|
SERVICE_SRC="$APP_DIR/systemd/karl.service"
|
||||||
|
SERVICE_DST="/etc/systemd/system/karl.service"
|
||||||
|
|
||||||
|
if [[ ! -f "$SERVICE_SRC" ]]; then
|
||||||
|
err "Nie znaleziono pliku $SERVICE_SRC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Kopiowanie $SERVICE_SRC -> $SERVICE_DST"
|
||||||
|
cp "$SERVICE_SRC" "$SERVICE_DST"
|
||||||
|
chmod 644 "$SERVICE_DST"
|
||||||
|
|
||||||
|
# --- 11. Przeładowanie systemctl i uruchomienie usługi ---
|
||||||
|
log "Przeładowanie systemd i włączanie usługi karl..."
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable karl.service
|
||||||
|
systemctl start karl.service
|
||||||
|
|
||||||
|
log "Instalacja zakończona pomyślnie! ✅"
|
||||||
32
systemd/karl.service
Normal file
32
systemd/karl.service
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Karl
|
||||||
|
After=network.target
|
||||||
|
Wants=network.target
|
||||||
|
StartLimitBurst=3
|
||||||
|
StartLimitIntervalSec=60
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=karl
|
||||||
|
WorkingDirectory=/opt/karl
|
||||||
|
ExecStart=/opt/karl/.venv/bin/python3 /opt/karl/src/karl/__init__.py
|
||||||
|
|
||||||
|
# Graceful reload (sends SIGHUP)
|
||||||
|
ExecReload=/bin/kill -s HUP $MAINPID
|
||||||
|
|
||||||
|
# Restart on failure
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5s
|
||||||
|
|
||||||
|
# Security hardening
|
||||||
|
NoNewPrivileges=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ReadWritePaths=/var/log/karl /opt/karl/repository
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
SyslogIdentifier=karl
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
Loading…
Add table
Add a link
Reference in a new issue