Add Docker support with Dockerfile and entrypoin
This commit is contained in:
parent
75296c903a
commit
0e1b1f5a35
9 changed files with 208 additions and 2 deletions
|
|
@ -50,3 +50,6 @@ DB_ENGINE=sqlite
|
|||
#DB_PASSWORD=
|
||||
#DB_HOST=localhost
|
||||
#DB_PORT=5432
|
||||
|
||||
# SQLite settings (only used when DB_ENGINE=sqlite)
|
||||
#DB_PATH=/app/data/db.sqlite3
|
||||
|
|
|
|||
32
.forgejo/workflows/docker.yml
Normal file
32
.forgejo/workflows/docker.yml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: Docker
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set image tag
|
||||
id: meta
|
||||
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Login to Forgejo registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: git.sinfonie.org
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Build image
|
||||
run: |
|
||||
docker build -t git.sinfonie.org/sinfonie/photo26:${{ steps.meta.outputs.TAG }} .
|
||||
|
||||
- name: Push image
|
||||
run: |
|
||||
docker push git.sinfonie.org/sinfonie/photo26:${{ steps.meta.outputs.TAG }}
|
||||
|
||||
19
Dockerfile
Normal file
19
Dockerfile
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
FROM python:3.11-slim
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
# Create volume mount points
|
||||
RUN mkdir -p /app/media /app/static /app/data
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
RUN chmod +x entrypoint.sh
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
72
README.md
72
README.md
|
|
@ -66,6 +66,78 @@ run and to maintain.
|
|||
```./maintenance_tool.sh```
|
||||
|
||||
|
||||
## Docker install
|
||||
|
||||
1. Create a `docker-compose.yml` (a ready-to-use file is provided in the repository):
|
||||
|
||||
```yaml
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
photo26:
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:16
|
||||
container_name: photo26-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: photo26
|
||||
POSTGRES_USER: photo26
|
||||
POSTGRES_PASSWORD: change-me
|
||||
volumes:
|
||||
- ./postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- photo26
|
||||
|
||||
photo26:
|
||||
image: git.sinfonie.org/sinfonie/photo26:latest
|
||||
container_name: photo26-app
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
environment:
|
||||
DB_ENGINE: postgres
|
||||
DB_NAME: photo26
|
||||
DB_USER: photo26
|
||||
DB_PASSWORD: change-me
|
||||
DB_HOST: db
|
||||
DB_PORT: 5432
|
||||
SECRET_KEY: change-me
|
||||
EXTRA_HOSTS: photos.example.org
|
||||
volumes:
|
||||
- ./media:/app/media
|
||||
ports:
|
||||
- "8080:8000"
|
||||
networks:
|
||||
- photo26
|
||||
```
|
||||
|
||||
2. Start the stack:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
On first start the container will run migrations and create a default admin account automatically.
|
||||
|
||||
3. **Default credentials** — change these immediately after first login:
|
||||
|
||||
| Field | Value |
|
||||
|----------|-----------------|
|
||||
| Username | `admin` |
|
||||
| Password | `admin` |
|
||||
| Email | `admin@localhost` |
|
||||
|
||||
Admin panel: `http://localhost:8080/admin/`
|
||||
|
||||
4. **Passwords to change** in `docker-compose.yml` before going to production:
|
||||
- `POSTGRES_PASSWORD` / `DB_PASSWORD` — database password
|
||||
- `SECRET_KEY` — Django secret key (use a long random string)
|
||||
- Log in to the admin panel and change the `admin` user password
|
||||
|
||||
---
|
||||
|
||||
6. *Enjoy \o/*
|
||||
|
||||
In development, you can launch the development server using:
|
||||
|
|
|
|||
40
docker-compose.yml
Normal file
40
docker-compose.yml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
version: "3.9"
|
||||
|
||||
networks:
|
||||
photo26:
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:16
|
||||
container_name: photo26-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: photo26
|
||||
POSTGRES_USER: photo26
|
||||
POSTGRES_PASSWORD: change-me
|
||||
volumes:
|
||||
- ./postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- photo26
|
||||
|
||||
photo26:
|
||||
image: git.sinfonie.org/sinfonie/photo26:latest
|
||||
container_name: photo26-app
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
environment:
|
||||
DB_ENGINE: postgres
|
||||
DB_NAME: photo26
|
||||
DB_USER: photo26
|
||||
DB_PASSWORD: change-me
|
||||
DB_HOST: db
|
||||
DB_PORT: 5432
|
||||
SECRET_KEY: change-me
|
||||
EXTRA_HOSTS: photos.example.org
|
||||
volumes:
|
||||
- ./media:/app/media
|
||||
ports:
|
||||
- "8080:8000"
|
||||
networks:
|
||||
- photo26
|
||||
7
entrypoint.sh
Normal file
7
entrypoint.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
python manage.py collectstatic --noinput
|
||||
python manage.py migrate --noinput
|
||||
python manage.py create_default_admin
|
||||
exec gunicorn photo21.wsgi:application --bind 0.0.0.0:8000 --workers 3
|
||||
|
|
@ -153,7 +153,7 @@ elif _db_engine == "sqlite":
|
|||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||
"NAME": config("DB_PATH", default=os.path.join(BASE_DIR, "db.sqlite3")),
|
||||
"OPTIONS": {
|
||||
"timeout": 10,
|
||||
},
|
||||
|
|
|
|||
32
photologue/management/commands/create_default_admin.py
Normal file
32
photologue/management/commands/create_default_admin.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Create default admin user (admin@localhost / admin) if it does not exist"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
User = get_user_model()
|
||||
email = "admin@localhost"
|
||||
username = "admin"
|
||||
password = "admin"
|
||||
|
||||
if User.objects.filter(username=username).exists():
|
||||
self.stdout.write("Default admin already exists, skipping.")
|
||||
return
|
||||
|
||||
user = User.objects.create_superuser(username=username, email=email, password=password)
|
||||
|
||||
# Mark the email as verified via allauth
|
||||
try:
|
||||
from allauth.account.models import EmailAddress
|
||||
EmailAddress.objects.create(
|
||||
user=user,
|
||||
email=email,
|
||||
primary=True,
|
||||
verified=True,
|
||||
)
|
||||
except Exception as e:
|
||||
self.stderr.write(f"Could not create allauth EmailAddress: {e}")
|
||||
|
||||
self.stdout.write(f"Default admin created: {username} / {password}")
|
||||
|
|
@ -7,5 +7,6 @@ Pillow>=6.0.0
|
|||
django-debug-toolbar>=3.2.0
|
||||
python-decouple>=3.6
|
||||
whitenoise>=6.0
|
||||
psycopg2>=2.9
|
||||
psycopg2-binary>=2.9
|
||||
requests>=2.25
|
||||
gunicorn>=21.0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue