Add Docker files (and Docker compose stack) and document usage
This commit is contained in:
parent
fb92e1f9c1
commit
0f12c3fa74
6 changed files with 204 additions and 22 deletions
21
Dockerfile
Normal file
21
Dockerfile
Normal file
|
@ -0,0 +1,21 @@
|
|||
FROM python:3.13-alpine
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN pip install --no-cache-dir poetry
|
||||
|
||||
ENV INVENTORY_STATIC_FILES=/static INVENTORY_MEDIA_FILES=/media
|
||||
RUN mkdir -p "$INVENTORY_MEDIA_FILES" && mkdir -p "$INVENTORY_STATIC_FILES"
|
||||
|
||||
COPY pyproject.toml /usr/src/app
|
||||
COPY poetry.lock /usr/src/app
|
||||
|
||||
RUN poetry install --no-root --no-interaction --no-cache
|
||||
COPY manage.py ./manage.py
|
||||
COPY inventory ./inventory
|
||||
COPY inventory_project ./inventory_project
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
RUN poetry run python manage.py collectstatic
|
||||
|
||||
CMD [ "/bin/sh", "/entrypoint.sh" ]
|
95
Readme.md
95
Readme.md
|
@ -9,17 +9,19 @@ what area of your workshop you have to search for to find the part you
|
|||
currently need. It has been optimized to store information for electronics
|
||||
parts and small other hardware like screws, nuts and bolts.
|
||||
|
||||
### Prerequisites
|
||||
### Prerequisites for manual install or docker Standalone
|
||||
|
||||
As configured by default you will need the following:
|
||||
|
||||
- A postgres database named `inventory` with a postgres user `inventory` that
|
||||
may connect without password or by default with the password `inventory`
|
||||
|
||||
### Installation (manual)
|
||||
|
||||
You will need:
|
||||
- Python > 3.10
|
||||
- Poetry to install requirements and create a virtualenv
|
||||
|
||||
### Installation
|
||||
|
||||
This is a standard Django 5.1 application, if you know how to deploy those the
|
||||
following might sound familiar:
|
||||
|
||||
|
@ -27,16 +29,28 @@ following might sound familiar:
|
|||
- Github `git clone https://github.com/dunkelstern/inventory.git`
|
||||
- ForgeJo: `git clone https://git.dunkelstern.de/dunkelstern/inventory.git`
|
||||
2. Change to checkout: `cd inventory`
|
||||
3. Install virtualenv and dependencies: `poetry install --no-root`
|
||||
3. Install virtualenv and dependencies:
|
||||
```
|
||||
poetry install --no-root
|
||||
```
|
||||
4. If you want to use the system in another language than the default english set it
|
||||
up in the `inventory_project/settings.py`:
|
||||
```python
|
||||
LANGUAGE_CODE = 'en-us' # or something like 'de-de'
|
||||
```
|
||||
see the settings file for defined languages.
|
||||
5. If you changed the language rebuild the translation files: `poetry run python manage.py compilemessages`
|
||||
6. Migrate the Database: `poetry run python manage.py migrate`
|
||||
7. Create an admin user: `poetry run python manage.py createsuperuser`
|
||||
5. If you changed the language rebuild the translation files:
|
||||
```
|
||||
poetry run python manage.py compilemessages
|
||||
```
|
||||
6. Migrate the Database:
|
||||
```
|
||||
poetry run python manage.py migrate
|
||||
```
|
||||
7. Optionally create an admin user. If not done manually the application will prompt you on first run.
|
||||
```
|
||||
poetry run python manage.py createsuperuser
|
||||
```
|
||||
8. Run the server
|
||||
- Development server (not for deployment!): `poetry run python manage.py runserver`
|
||||
- Deployment via `gunicorn` on port 8000: `poetry run gunicorn inventory_project.wsgi -b 0.0.0.0:8000`
|
||||
|
@ -44,6 +58,73 @@ following might sound familiar:
|
|||
Then login on `http://localhost:8000/admin/` for the Django admin interface or
|
||||
go to `http://localhost:8000` to enter the inventory management system directly
|
||||
|
||||
### Installation (Standalone Docker)
|
||||
|
||||
#### Building yourself
|
||||
|
||||
1. Checkout repository:
|
||||
- Github `git clone https://github.com/dunkelstern/inventory.git`
|
||||
- ForgeJo: `git clone https://git.dunkelstern.de/dunkelstern/inventory.git`
|
||||
2. Change to checkout: `cd inventory`
|
||||
3. Build Docker image: `docker build -t 'dunkelstern/inventory:latest' .`
|
||||
|
||||
next steps below
|
||||
|
||||
#### Pulling from docker hub
|
||||
|
||||
1. Pull Docker image: `docker pull 'dunkelstern/inventory:latest'`
|
||||
|
||||
next steps below
|
||||
|
||||
#### Next steps
|
||||
|
||||
1. Install a PostgreSQL DB somewhere and create a user and DB.
|
||||
2. Setup environment (put everything in a `.env` file):
|
||||
```
|
||||
INVENTORY_DB_HOST=
|
||||
INVENTORY_DB_NAME=
|
||||
INVENTORY_DB_USER=
|
||||
INVENTORY_DB_PASSWORD=
|
||||
|
||||
INVENTORY_SECRET_KEY=
|
||||
INVENTORY_EXTERNAL_URL=http://localhost:8000
|
||||
INVENTORY_DEBUG=FALSE
|
||||
|
||||
INVENTORY_LANGUAGE=en-us
|
||||
INVENTORY_TIMEZONE=UTC
|
||||
|
||||
INVENTORY_PAGE_SIZE=25
|
||||
```
|
||||
3. Create a media directory for uploaded files: `mkdir -p media`
|
||||
4. Run the container:
|
||||
```
|
||||
docker run \
|
||||
--name inventory \
|
||||
-d \
|
||||
--restart=always \
|
||||
--env-file=.env \
|
||||
-p 8000:8000 \
|
||||
--volume ./media:/media \
|
||||
dunkelstern/inventory:latest
|
||||
```
|
||||
5. The onboarding process will start on first call of the application and prompt to create an admin user.
|
||||
|
||||
### Installation (Docker compose)
|
||||
|
||||
1. Checkout repository:
|
||||
- Github `git clone https://github.com/dunkelstern/inventory.git`
|
||||
- ForgeJo: `git clone https://git.dunkelstern.de/dunkelstern/inventory.git`
|
||||
2. Change to checkout: `cd inventory`
|
||||
3. Copy `default.env` to `override.env` and check settings. Use a long random string for `INVENTORY_SECRET_KEY`!
|
||||
4. Build the stack: `docker-compose up --build -d`
|
||||
5. You can reach the application on port 8000
|
||||
6. The onboarding process will start on first call of the application and prompt to create an admin user.
|
||||
|
||||
The compose stack will create two volumes:
|
||||
|
||||
- `inventory_dbdata` which contains the PostgreSQL database directory
|
||||
- `inventory_mediafiles` which will contain any uploaded file
|
||||
|
||||
### Additional information
|
||||
|
||||
1. The initial DB migration pre-populates the database with some useful defaults
|
||||
|
|
17
default.env
Normal file
17
default.env
Normal file
|
@ -0,0 +1,17 @@
|
|||
# override this with a long random string (used for CSRF protection)
|
||||
INVENTORY_SECRET_KEY=""
|
||||
|
||||
# override with URL the service will be available under
|
||||
INVENTORY_EXTERNAL_URL="https://inventory.example.com"
|
||||
|
||||
# keep this to FALSE for deployments
|
||||
INVENTORY_DEBUG="FALSE"
|
||||
|
||||
# if you want to run the service in another language, override this
|
||||
INVENTORY_LANGUAGE="en-us"
|
||||
|
||||
# if you want the service to use local time then override this
|
||||
INVENTORY_TIMEZONE="UTC"
|
||||
|
||||
# This is the default pagination size
|
||||
INVENTORY_PAGE_SIZE="25"
|
46
docker-compose.yaml
Normal file
46
docker-compose.yaml
Normal file
|
@ -0,0 +1,46 @@
|
|||
name: inventory
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:17-alpine
|
||||
restart: always
|
||||
shm_size: 128mb
|
||||
environment:
|
||||
POSTGRES_PASSWORD: inventory
|
||||
POSTGRES_USER: inventory
|
||||
POSTGRES_DB: inventory
|
||||
volumes:
|
||||
- dbdata:/var/lib/postgresql/data
|
||||
|
||||
inventory:
|
||||
image: dunkelstern/inventory
|
||||
build: .
|
||||
restart: always
|
||||
depends_on:
|
||||
- db
|
||||
env_file:
|
||||
- path: ./default.env
|
||||
required: true
|
||||
- path: ./override.env
|
||||
required: false
|
||||
environment:
|
||||
INVENTORY_DB_HOST: db
|
||||
INVENTORY_DB_NAME: inventory
|
||||
INVENTORY_DB_USER: inventory
|
||||
INVENTORY_DB_PASSWORD: inventory
|
||||
ports:
|
||||
- name: web
|
||||
target: 8000
|
||||
host_ip: 127.0.0.1
|
||||
published: "8000"
|
||||
protocol: tcp
|
||||
app_protocol: http
|
||||
mode: host
|
||||
volumes:
|
||||
- mediafiles:/media
|
||||
links:
|
||||
- db
|
||||
|
||||
volumes:
|
||||
dbdata:
|
||||
mediafiles:
|
8
entrypoint.sh
Normal file
8
entrypoint.sh
Normal file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
|
||||
cd /usr/src/app
|
||||
|
||||
# poetry run python manage.py collectstatic --noinput
|
||||
poetry run python manage.py migrate --noinput
|
||||
|
||||
exec poetry run gunicorn inventory_project.wsgi -b 0.0.0.0:8000
|
|
@ -10,10 +10,12 @@ For the full list of settings and their values, see
|
|||
https://docs.djangoproject.com/en/3.0/ref/settings/
|
||||
"""
|
||||
|
||||
from typing import List
|
||||
import os
|
||||
import sys
|
||||
import asyncio
|
||||
import socket
|
||||
from urllib.parse import urlparse
|
||||
from uuid import uuid4
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
if sys.platform == 'win32':
|
||||
|
@ -23,19 +25,25 @@ if sys.platform == 'win32':
|
|||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Externally visible URL of the server
|
||||
SERVER_URL = "http://127.0.0.1:8000"
|
||||
SERVER_URL = os.environ.get('INVENTORY_EXTERNAL_URL', "http://127.0.0.1:8000")
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'nqo*a(^g$8#0%&+*_7#b_7ybn-znk4#=45_(qy-lq-^v675pqk'
|
||||
SECRET_KEY = os.environ.get('INVENTORY_SECRET_KEY', uuid4().hex)
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS: List[str] = []
|
||||
DEBUG = (os.environ.get('INVENTORY_DEBUG', "FALSE") == "TRUE")
|
||||
|
||||
parsed_url = urlparse(SERVER_URL)
|
||||
ALLOWED_HOSTS: list[str] = [
|
||||
'.localhost',
|
||||
'127.0.0.1',
|
||||
'[::1]',
|
||||
parsed_url.hostname,
|
||||
socket.gethostbyname('localhost')
|
||||
]
|
||||
|
||||
# Application definition
|
||||
|
||||
|
@ -89,9 +97,10 @@ ASGI_APPLICATION = 'inventory_project.asgi.application'
|
|||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': 'inventory',
|
||||
'USER': 'inventory',
|
||||
'PASSWORD': 'inventory'
|
||||
'HOST': os.environ.get('INVENTORY_DB_HOST', 'localhost'),
|
||||
'NAME': os.environ.get('INVENTORY_DB_NAME', 'inventory'),
|
||||
'USER': os.environ.get('INVENTORY_DB_USER', 'inventory'),
|
||||
'PASSWORD': os.environ.get('INVENTORY_DB_PASSWORD', 'inventory')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,9 +131,9 @@ LANGUAGES = [
|
|||
("en", _("English")),
|
||||
]
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
LANGUAGE_CODE = os.environ.get('INVENTORY_LANGUAGE', 'en-us')
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
TIME_ZONE = os.environ.get('INVENTORY_TIMEZONE', 'UTC')
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
|
@ -137,13 +146,13 @@ USE_TZ = True
|
|||
# https://docs.djangoproject.com/en/3.0/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||
STATIC_ROOT = os.environ.get('INVENTORY_STATIC_FILES', os.path.join(BASE_DIR, 'static'))
|
||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
||||
|
||||
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
SERVE_MEDIA_FILES = DEBUG
|
||||
MEDIA_ROOT = os.environ.get('INVENTORY_MEDIA_FILES', os.path.join(BASE_DIR, 'media'))
|
||||
SERVE_MEDIA_FILES = True
|
||||
|
||||
# Default page size for paginated content
|
||||
PAGE_SIZE = 25
|
||||
PAGE_SIZE = int(os.environ.get('INVENTORY_PAGE_SIZE', "25"))
|
||||
|
|
Loading…
Reference in a new issue