rip Docker, long live systemd
This commit is contained in:
parent
b7116cb13f
commit
7c4bb9acca
15 changed files with 184 additions and 201 deletions
|
|
@ -1,27 +0,0 @@
|
|||
.env
|
||||
.env.example
|
||||
.git/
|
||||
.github/
|
||||
.pre-commit-config.yaml
|
||||
.pytest_cache/
|
||||
.ruff_cache/
|
||||
.venv
|
||||
.vscode/
|
||||
.vscode/
|
||||
*.json
|
||||
*.log
|
||||
*.py[codz]
|
||||
**/__pycache__/
|
||||
*$py.class
|
||||
archive/
|
||||
check_these_please/
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
env.bak/
|
||||
env/
|
||||
ENV/
|
||||
responses/
|
||||
staticfiles/
|
||||
tests/
|
||||
venv.bak/
|
||||
venv/
|
||||
|
|
@ -31,3 +31,7 @@ EMAIL_USE_SSL=False
|
|||
|
||||
# Connection timeout in seconds
|
||||
EMAIL_TIMEOUT=10
|
||||
|
||||
# Where to store Twitch API responses
|
||||
TTVDROPS_IMPORTED_DIR=/mnt/fourteen/Data/Responses/imported
|
||||
TTVDROPS_BROKEN_DIR=/mnt/fourteen/Data/Responses/broken
|
||||
|
|
|
|||
46
.github/workflows/docker.yaml
vendored
46
.github/workflows/docker.yaml
vendored
|
|
@ -1,10 +1,10 @@
|
|||
name: Test and Build Docker Image
|
||||
name: Run Pytest
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: "0 14 * * *" # Run every day at 14:00 CET
|
||||
- cron: "0 14 * * 0" # Run weekly at 14:00 UTC
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
|
@ -16,23 +16,7 @@ jobs:
|
|||
DJANGO_SECRET_KEY: 1234567890
|
||||
|
||||
steps:
|
||||
- uses: docker/login-action@v3
|
||||
if: github.event_name != 'pull_request'
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: thelovinator1
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: astral-sh/ruff-action@v3
|
||||
with:
|
||||
version: "latest"
|
||||
- run: ruff check --exit-non-zero-on-fix --verbose
|
||||
- run: ruff format --check --verbose
|
||||
|
||||
- run: docker build --check .
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.14
|
||||
|
|
@ -40,29 +24,3 @@ jobs:
|
|||
- uses: astral-sh/setup-uv@v7
|
||||
- run: uv sync --all-extras --dev
|
||||
- run: uv run pytest
|
||||
|
||||
- run: uv run python manage.py makemigrations --check
|
||||
env:
|
||||
TESTING: True
|
||||
- run: uv run python manage.py migrate
|
||||
env:
|
||||
TESTING: True
|
||||
- run: uv run python manage.py collectstatic --noinput
|
||||
- id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
env:
|
||||
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/thelovinator1/ttvdrops
|
||||
tags: |
|
||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
|
||||
|
||||
- uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
annotations: ${{ steps.meta.outputs.annotations }}
|
||||
|
|
|
|||
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
|
@ -79,6 +79,7 @@
|
|||
"ttvdrops",
|
||||
"twid",
|
||||
"twitchgamedata",
|
||||
"usermod",
|
||||
"venv",
|
||||
"wrongpassword",
|
||||
"wsgi",
|
||||
|
|
|
|||
30
Dockerfile
30
Dockerfile
|
|
@ -1,30 +0,0 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
FROM python:3.14-slim-trixie
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||||
|
||||
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
|
||||
ENV UV_NO_DEV=1
|
||||
ENV UV_PYTHON_DOWNLOADS=0
|
||||
ENV UV_NO_CACHE=1
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app/
|
||||
|
||||
RUN uv sync
|
||||
RUN chmod +x /app/start.sh
|
||||
|
||||
ENV PATH="/app/.venv/bin:$PATH"
|
||||
|
||||
RUN groupadd -g 1000 ttvdrops \
|
||||
&& useradd -m -u 1000 -g 1000 -d /home/ttvdrops -s /bin/sh ttvdrops \
|
||||
&& mkdir -p /home/ttvdrops/.local/share/TTVDrops \
|
||||
&& chown -R ttvdrops:ttvdrops /home/ttvdrops /app
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD curl -f http://localhost:8000/ || exit 1
|
||||
|
||||
VOLUME ["/home/ttvdrops/.local/share/TTVDrops"]
|
||||
EXPOSE 8000
|
||||
USER ttvdrops
|
||||
ENTRYPOINT [ "/app/start.sh" ]
|
||||
CMD ["uv", "run", "gunicorn", "config.wsgi:application", "--workers", "27", "--bind", "0.0.0.0:8000"]
|
||||
91
README.md
91
README.md
|
|
@ -2,6 +2,74 @@
|
|||
|
||||
Get notified when a new drop is available on Twitch
|
||||
|
||||
## TL;DR (Arch Linux + PostgreSQL)
|
||||
|
||||
Install and initialize Postgres, then start the service:
|
||||
|
||||
```bash
|
||||
sudo pacman -S postgresql
|
||||
sudo -u postgres initdb -D /var/lib/postgres/data
|
||||
sudo systemctl enable --now postgresql
|
||||
```
|
||||
|
||||
Create a local role and database:
|
||||
|
||||
```bash
|
||||
sudo -u postgres createuser -P ttvdrops
|
||||
sudo -u postgres createdb -O ttvdrops ttvdrops
|
||||
```
|
||||
|
||||
Point Django at the unix socket used by Arch (`/run/postgresql`):
|
||||
|
||||
```bash
|
||||
POSTGRES_USER=ttvdrops
|
||||
POSTGRES_PASSWORD=your_password
|
||||
POSTGRES_DB=ttvdrops
|
||||
POSTGRES_HOST=/run/postgresql
|
||||
POSTGRES_PORT=5432
|
||||
```
|
||||
|
||||
### Linux (Systemd)
|
||||
|
||||
```bash
|
||||
sudo useradd --create-home --home-dir /home/ttvdrops --shell /bin/fish ttvdrops
|
||||
sudo passwd ttvdrops
|
||||
sudo usermod -aG wheel ttvdrops
|
||||
su - ttvdrops
|
||||
git clone https://github.com/TheLovinator1/ttvdrops.git
|
||||
cd ttvdrops
|
||||
uv sync --no-dev
|
||||
|
||||
# Modify .env with the correct database credentials and other settings, then run migrations:
|
||||
uv run python manage.py migrate
|
||||
```
|
||||
|
||||
Install the systemd service from the repo:
|
||||
|
||||
```bash
|
||||
sudo install -m 0644 tools/systemd/ttvdrops.socket /etc/systemd/system/ttvdrops.socket
|
||||
sudo install -m 0644 tools/systemd/ttvdrops.service /etc/systemd/system/ttvdrops.service
|
||||
```
|
||||
|
||||
Enable and start the service:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now ttvdrops.socket
|
||||
sudo systemctl enable --now ttvdrops.service
|
||||
|
||||
curl --unix-socket /run/ttvdrops/ttvdrops.sock http://ttvdrops.lovinator.space
|
||||
```
|
||||
|
||||
Install and enable timers:
|
||||
|
||||
```bash
|
||||
sudo install -m 0644 tools/systemd/ttvdrops-backup.{service,timer} /etc/systemd/system/
|
||||
sudo install -m 0644 tools/systemd/ttvdrops-import-drops.{service,timer} /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now ttvdrops-backup.timer ttvdrops-import-drops.timer
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
|
|
@ -42,3 +110,26 @@ Optional arguments:
|
|||
```bash
|
||||
uv run python manage.py backup_db --output-dir "<path>" --prefix "ttvdrops"
|
||||
```
|
||||
|
||||
### How the duck does permissions work on Linux?
|
||||
|
||||
```bash
|
||||
sudo groupadd responses
|
||||
sudo usermod -aG responses lovinator
|
||||
sudo usermod -aG responses ttvdrops
|
||||
|
||||
sudo chown -R lovinator:responses /mnt/fourteen/Data/Responses
|
||||
sudo chown -R lovinator:responses /mnt/fourteen/Data/ttvdrops
|
||||
sudo chmod -R 2775 /mnt/fourteen/Data/Responses
|
||||
sudo chmod -R 2775 /mnt/fourteen/Data/ttvdrops
|
||||
|
||||
# Import dir
|
||||
sudo setfacl -b /mnt/fourteen/Data/Responses /mnt/fourteen/Data/Responses/imported
|
||||
sudo setfacl -m g:responses:rwx /mnt/fourteen/Data/Responses /mnt/fourteen/Data/Responses/imported
|
||||
sudo setfacl -d -m g:responses:rwx /mnt/fourteen/Data/Responses /mnt/fourteen/Data/Responses/imported
|
||||
|
||||
# Backup dir
|
||||
sudo setfacl -b /mnt/fourteen/Data/ttvdrops
|
||||
sudo setfacl -m g:responses:rwx /mnt/fourteen/Data/ttvdrops
|
||||
sudo setfacl -d -m g:responses:rwx /mnt/fourteen/Data/ttvdrops
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,89 +0,0 @@
|
|||
services:
|
||||
ttvdrops_postgres:
|
||||
container_name: ttvdrops_postgres
|
||||
image: docker.io/pgautoupgrade/pgautoupgrade:latest
|
||||
command:
|
||||
- "-c"
|
||||
- "max_connections=200"
|
||||
- "-c"
|
||||
- "shared_buffers=4GB"
|
||||
- "-c"
|
||||
- "effective_cache_size=12GB"
|
||||
- "-c"
|
||||
- "maintenance_work_mem=1GB"
|
||||
- "-c"
|
||||
- "checkpoint_completion_target=0.9"
|
||||
- "-c"
|
||||
- "wal_buffers=16MB"
|
||||
- "-c"
|
||||
- "default_statistics_target=100"
|
||||
- "-c"
|
||||
- "random_page_cost=1.1"
|
||||
- "-c"
|
||||
- "effective_io_concurrency=200"
|
||||
- "-c"
|
||||
- "work_mem=20MB"
|
||||
- "-c"
|
||||
- "huge_pages=off"
|
||||
- "-c"
|
||||
- "min_wal_size=1GB"
|
||||
- "-c"
|
||||
- "max_wal_size=4GB"
|
||||
- "-c"
|
||||
- "max_worker_processes=12"
|
||||
- "-c"
|
||||
- "max_parallel_workers_per_gather=4"
|
||||
- "-c"
|
||||
- "max_parallel_workers=12"
|
||||
- "-c"
|
||||
- "max_parallel_maintenance_workers=4"
|
||||
environment:
|
||||
- POSTGRES_DB=ttvdrops
|
||||
- POSTGRES_USER=ttvdrops
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
ports:
|
||||
- "5442:5432"
|
||||
volumes:
|
||||
- /mnt/Docker/Data/ttvdrops/postgres:/var/lib/postgresql
|
||||
shm_size: '8gb'
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- internal
|
||||
|
||||
ttvdrops:
|
||||
container_name: ttvdrops
|
||||
image: ghcr.io/thelovinator1/ttvdrops:latest
|
||||
expose:
|
||||
- "8000"
|
||||
user: 1000:1000
|
||||
environment:
|
||||
- DEBUG=False
|
||||
- DJANGO_SECRET_KEY=$(DJANGO_SECRET_KEY)
|
||||
- TWITCH_CLIENT_ID=$(TWITCH_CLIENT_ID)
|
||||
- TWITCH_CLIENT_SECRET=$(TWITCH_CLIENT_SECRET)
|
||||
- EMAIL_HOST=smtp.gmail.com
|
||||
- EMAIL_PORT=587
|
||||
- EMAIL_HOST_USER=$(EMAIL_HOST_USER)
|
||||
- EMAIL_HOST_PASSWORD=$(EMAIL_HOST_PASSWORD)
|
||||
- EMAIL_USE_TLS=True
|
||||
- EMAIL_USE_SSL=False
|
||||
- POSTGRES_DB=ttvdrops
|
||||
- POSTGRES_USER=ttvdrops
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- POSTGRES_HOST=ttvdrops_postgres
|
||||
- POSTGRES_PORT=5432
|
||||
volumes:
|
||||
- /mnt/Docker/Data/ttvdrops/data:/home/ttvdrops/.local/share/TTVDrops
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- web
|
||||
- internal
|
||||
depends_on:
|
||||
ttvdrops_postgres:
|
||||
condition: service_started
|
||||
|
||||
networks:
|
||||
web:
|
||||
external: true
|
||||
internal:
|
||||
driver: bridge
|
||||
|
|
@ -20,7 +20,9 @@ dependencies = [
|
|||
"pydantic",
|
||||
"pygments",
|
||||
"python-dotenv",
|
||||
"systemd; sys_platform == 'linux'",
|
||||
"tqdm",
|
||||
"setproctitle>=1.3.7",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
|
|
|
|||
11
start.sh
11
start.sh
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "Running database migrations..."
|
||||
uv run python manage.py migrate --noinput
|
||||
|
||||
echo "Collecting static files..."
|
||||
uv run python manage.py collectstatic --noinput
|
||||
|
||||
echo "Starting Django server..."
|
||||
exec "$@"
|
||||
10
tools/systemd/ttvdrops-backup.service
Normal file
10
tools/systemd/ttvdrops-backup.service
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=TTVDrops database backup
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=ttvdrops
|
||||
Group=ttvdrops
|
||||
WorkingDirectory=/home/ttvdrops/ttvdrops
|
||||
EnvironmentFile=/home/ttvdrops/ttvdrops/.env
|
||||
ExecStart=/usr/bin/uv run python manage.py backup_db
|
||||
9
tools/systemd/ttvdrops-backup.timer
Normal file
9
tools/systemd/ttvdrops-backup.timer
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=Nightly TTVDrops database backup
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 02:15:00
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
12
tools/systemd/ttvdrops-import-drops.service
Normal file
12
tools/systemd/ttvdrops-import-drops.service
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=TTVDrops import drops from pending directory
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=ttvdrops
|
||||
Group=ttvdrops
|
||||
WorkingDirectory=/home/ttvdrops/ttvdrops
|
||||
EnvironmentFile=/home/ttvdrops/ttvdrops/.env
|
||||
ExecStart=/usr/bin/uv run python manage.py better_import_drops /mnt/fourteen/Data/Responses/pending
|
||||
-ExecStartPost=/usr/bin/uv run python manage.py download_box_art
|
||||
-ExecStartPost=/usr/bin/uv run python manage.py download_campaign_images
|
||||
10
tools/systemd/ttvdrops-import-drops.timer
Normal file
10
tools/systemd/ttvdrops-import-drops.timer
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Frequent TTVDrops import drops timer
|
||||
|
||||
[Timer]
|
||||
OnBootSec=0
|
||||
OnUnitActiveSec=1min
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
32
tools/systemd/ttvdrops.service
Normal file
32
tools/systemd/ttvdrops.service
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
[Unit]
|
||||
Description=TTVDrops
|
||||
Requires=ttvdrops.socket
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=ttvdrops
|
||||
Group=ttvdrops
|
||||
WorkingDirectory=/home/ttvdrops/ttvdrops
|
||||
EnvironmentFile=/home/ttvdrops/ttvdrops/.env
|
||||
RuntimeDirectory=ttvdrops
|
||||
UMask=0077
|
||||
ExecStart=/usr/bin/uv run gunicorn config.wsgi:application --bind unix:/run/ttvdrops/ttvdrops.sock --workers 13 --name ttvdrops --max-requests-jitter 50 --max-requests 1200
|
||||
ExecReload=/bin/kill -s HUP $MAINPID
|
||||
|
||||
NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=no
|
||||
ReadWritePaths=/home/ttvdrops/ttvdrops /run/ttvdrops /mnt/fourteen/Data/Responses
|
||||
PrivateDevices=yes
|
||||
CapabilityBoundingSet=
|
||||
AmbientCapabilities=
|
||||
RestrictRealtime=yes
|
||||
LockPersonality=yes
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
11
tools/systemd/ttvdrops.socket
Normal file
11
tools/systemd/ttvdrops.socket
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[Unit]
|
||||
Description=TTVDrops Socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/ttvdrops/ttvdrops.sock
|
||||
SocketUser=ttvdrops
|
||||
SocketGroup=ttvdrops
|
||||
SocketMode=0660
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
Loading…
Add table
Add a link
Reference in a new issue