diff --git a/.gitattributes b/.gitattributes index db355084a6..6ab0760ad1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,8 @@ *.md text *.html text *.txt text +*.yml text +*.yaml text +*.conf text +*.sh text +*.js text \ No newline at end of file diff --git a/.github/workflows/docker_build.yaml b/.github/workflows/docker_build.yaml index c9f8a69654..e307c18452 100644 --- a/.github/workflows/docker_build.yaml +++ b/.github/workflows/docker_build.yaml @@ -11,8 +11,6 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Build Server Image - run: cd docker/inventree && docker build . --tag inventree:$(date +%s) - - name: Build nginx Image - run: cd docker/nginx && docker build . --tag nxinx:$(date +%s) - \ No newline at end of file + - name: Build Docker Image + run: cd docker && docker build . --tag inventree:$(date +%s) + \ No newline at end of file diff --git a/.github/workflows/docker_publish.yaml b/.github/workflows/docker_publish.yaml index 6870754ad3..75f2d67d20 100644 --- a/.github/workflows/docker_publish.yaml +++ b/.github/workflows/docker_publish.yaml @@ -7,7 +7,7 @@ on: types: [published] jobs: - server_image: + publish_image: name: Push InvenTree web server image to dockerhub runs-on: ubuntu-latest steps: @@ -20,19 +20,4 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} repository: inventree/inventree tag_with_ref: true - dockerfile: docker/inventree/Dockerfile - - nginx_image: - name: Push InvenTree nginx image to dockerhub - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@v2 - - name: Push to Docker Hub - uses: docker/build-push-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - repository: inventree/nginx - tag_with_ref: true - dockerfile: docker/nginx/Dockerfile + dockerfile: docker/Dockerfile \ No newline at end of file diff --git a/docker/inventree/Dockerfile b/docker/Dockerfile similarity index 85% rename from docker/inventree/Dockerfile rename to docker/Dockerfile index 2911da907a..9682665e04 100644 --- a/docker/inventree/Dockerfile +++ b/docker/Dockerfile @@ -30,12 +30,14 @@ ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt" ENV INVENTREE_WEB_PORT="8000" # Pass DB configuration through as environment variables -ENV INVENTREE_DB_ENGINE="${INVENTREE_DB_ENGINE}" -ENV INVENTREE_DB_NAME="${INVENTREE_DB_NAME}" -ENV INVENTREE_DB_HOST="${INVENTREE_DB_HOST}" -ENV INVENTREE_DB_PORT="${INVENTREE_DB_PORT}" -ENV INVENTREE_DB_USER="${INVENTREE_DB_USER}" -ENV INVENTREE_DB_PASSWORD="${INVENTREE_DB_PASSWORD}" +# Default configuration = postgresql +ENV INVENTREE_DB_ENGINE="postgresql" +ENV INVENTREE_DB_NAME="inventree" +ENV INVENTREE_DB_HOST="db" +ENV INVENTREE_DB_PORT="5432" + +# INVENTREE_DB_USER must be specified at run-time +# INVENTREE_DB_PASSWORD must be specified at run-time LABEL org.label-schema.schema-version="1.0" \ org.label-schema.build-date=${DATE} \ @@ -93,14 +95,16 @@ RUN pip install --no-cache-dir -U -r ${INVENTREE_SRC_DIR}/requirements.txt COPY gunicorn.conf.py ${INVENTREE_HOME}/gunicorn.conf.py # Copy startup scripts -COPY start_server.sh ${INVENTREE_SRC_DIR}/start_server.sh +COPY start_prod_server.sh ${INVENTREE_SRC_DIR}/start_prod_server.sh +COPY start_dev_server.sh ${INVENTREE_SRC_DIR}/start_dev_server.sh COPY start_worker.sh ${INVENTREE_SRC_DIR}/start_worker.sh -RUN chmod 755 ${INVENTREE_SRC_DIR}/start_server.sh +RUN chmod 755 ${INVENTREE_SRC_DIR}/start_prod_server.sh +RUN chmod 755 ${INVENTREE_SRC_DIR}/start_dev_server.sh RUN chmod 755 ${INVENTREE_SRC_DIR}/start_worker.sh # exec commands should be executed from the "src" directory WORKDIR ${INVENTREE_SRC_DIR} # Let us begin -CMD ["bash", "./start_server.sh"] +CMD ["bash", "./start_prod_server.sh"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 90b5fa2668..e48b22d4b7 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -2,9 +2,9 @@ version: "3.8" # Docker compose recipe for InvenTree # - Runs PostgreSQL as the database backend -# - Runs Gunicorn as the web server +# - Runs Gunicorn as the InvenTree web server +# - Runs the InvenTree background worker process # - Runs nginx as a reverse proxy -# - Runs the background worker process # --------------------------------- # IMPORTANT - READ BEFORE STARTING! @@ -12,6 +12,7 @@ version: "3.8" # Before running, ensure that you change the "/path/to/data" directory, # specified in the "volumes" section at the end of this file. # This path determines where the InvenTree data will be stored! +# services: # Database service @@ -25,6 +26,7 @@ services: - 5432/tcp environment: - PGDATA=/var/lib/postgresql/data/pgdb + # The pguser and pgpassword values must be the same in the other containers - POSTGRES_USER=pguser - POSTGRES_PASSWORD=pgpassword volumes: @@ -34,39 +36,23 @@ services: # InvenTree web server services # Uses gunicorn as the web server inventree: - container_name: server + container_name: inventree image: inventree/inventree:latest expose: - - 8080 + - 8000 depends_on: - db volumes: - data:/home/inventree/data - static:/home/inventree/static environment: - - INVENTREE_DB_ENGINE=postgresql - - INVENTREE_DB_NAME=inventree + # Default environment variables are configured to match the 'db' container + # Database permissions - INVENTREE_DB_USER=pguser - INVENTREE_DB_PASSWORD=pgpassword - - INVENTREE_DB_PORT=5432 - - INVENTREE_DB_HOST=db restart: unless-stopped - # nginx acts as a reverse proxy - # static files are served by nginx - # web requests are redirected to gunicorn - nginx: - container_name: nginx - image: inventree/nginx:latest - depends_on: - - inventree - ports: - # Change "1337" to the port where you want InvenTree web server to be available - - 1337:80 - volumes: - - static:/home/inventree/static - - # background worker process handles long-running or periodic tasks + # Background worker process handles long-running or periodic tasks worker: container_name: worker image: inventree/inventree:latest @@ -78,18 +64,34 @@ services: - data:/home/inventree/data - static:/home/inventree/static environment: - - INVENTREE_DB_ENGINE=postgresql - - INVENTREE_DB_NAME=inventree + # Default environment variables are configured to match the 'inventree' container - INVENTREE_DB_USER=pguser - INVENTREE_DB_PASSWORD=pgpassword - - INVENTREE_DB_PORT=5432 - - INVENTREE_DB_HOST=db + restart: unless-stopped + + # nginx acts as a reverse proxy + # static files are served by nginx + # web requests are redirected to gunicorn + # NOTE: You will need to provide a working nginx.conf file! + proxy: + container_name: proxy + image: nginx + depends_on: + - inventree + ports: + # Change "1337" to the port that you want InvenTree web server to be available on + - 1337:80 + volumes: + # Provide nginx.conf file to the container + # Refer to the provided example file as a starting point + - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro + # Static data volume is mounted to /var/www/static + - static:/var/www/static:ro restart: unless-stopped volumes: - # Static files, shared between containers - static: - # Persistent data, stored externally + # NOTE: Change /path/to/data to a directory on your local machine + # Persistent data, stored external to the container(s) data: driver: local driver_opts: @@ -98,3 +100,5 @@ volumes: # This directory specified where InvenTree data are stored "outside" the docker containers # Change this path to a local system path where you want InvenTree data stored device: /path/to/data + # Static files, shared between containers + static: \ No newline at end of file diff --git a/docker/inventree/gunicorn.conf.py b/docker/gunicorn.conf.py similarity index 100% rename from docker/inventree/gunicorn.conf.py rename to docker/gunicorn.conf.py diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 0000000000..ace56165aa --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,32 @@ +server { + + # Listen for connection on (internal) port 80 + listen 80; + + location / { + # Change 'inventree' to the name of the inventree server container, + # and '8000' to the INVENTREE_WEB_PORT (if not default) + proxy_pass http://inventree:8000; + + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + + proxy_redirect off; + + client_max_body_size 100M; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_request_buffering off; + + } + + # Redirect any requests for static files + location /static/ { + alias /var/www/static/; + autoindex on; + } + +} \ No newline at end of file diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile deleted file mode 100644 index e754597f02..0000000000 --- a/docker/nginx/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM nginx:1.19.0-alpine - -# Create user account -RUN addgroup -S inventreegroup && adduser -S inventree -G inventreegroup - -ENV HOME=/home/inventree -WORKDIR $HOME - -# Create the "static" volume directory -RUN mkdir $HOME/static - -RUN rm /etc/nginx/conf.d/default.conf -COPY nginx.conf /etc/nginx/conf.d - diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf deleted file mode 100644 index 0f25f51674..0000000000 --- a/docker/nginx/nginx.conf +++ /dev/null @@ -1,21 +0,0 @@ -upstream inventree { - server inventree:8080; -} - -server { - - listen 80; - - location / { - proxy_pass http://inventree; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $host; - proxy_redirect off; - client_max_body_size 100M; - } - - location /static/ { - alias /home/inventree/static/; - } - -} \ No newline at end of file diff --git a/docker/start_dev_server.sh b/docker/start_dev_server.sh new file mode 100644 index 0000000000..703d577ed5 --- /dev/null +++ b/docker/start_dev_server.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Create required directory structure (if it does not already exist) +if [[ ! -d "$INVENTREE_STATIC_ROOT" ]]; then + echo "Creating directory $INVENTREE_STATIC_ROOT" + mkdir $INVENTREE_STATIC_ROOT +fi + +if [[ ! -d "$INVENTREE_MEDIA_ROOT" ]]; then + echo "Creating directory $INVENTREE_MEDIA_ROOT" + mkdir $INVENTREE_MEDIA_ROOT +fi + +if [[ ! -d "$INVENTREE_BACKUP_DIR" ]]; then + echo "Creating directory $INVENTREE_BACKUP_DIR" + mkdir $INVENTREE_BACKUP_DIR +fi + +# Check if "config.yaml" has been copied into the correct location +if test -f "$INVENTREE_CONFIG_FILE"; then + echo "$INVENTREE_CONFIG_FILE exists - skipping" +else + echo "Copying config file to $INVENTREE_CONFIG_FILE" + cp $INVENTREE_SRC_DIR/InvenTree/config_template.yaml $INVENTREE_CONFIG_FILE +fi + +echo "Starting InvenTree server..." + +# Wait for the database to be ready +cd $INVENTREE_MNG_DIR +python manage.py wait_for_db + +sleep 10 + +echo "Running InvenTree database migrations and collecting static files..." + +# We assume at this stage that the database is up and running +# Ensure that the database schema are up to date +python manage.py check || exit 1 +python manage.py migrate --noinput || exit 1 +python manage.py migrate --run-syncdb || exit 1 +python manage.py collectstatic --noinput || exit 1 +python manage.py clearsessions || exit 1 + +# Launch a development server +python manage.py runserver -a 0.0.0.0:$INVENTREE_WEB_PORT \ No newline at end of file diff --git a/docker/inventree/start_server.sh b/docker/start_prod_server.sh similarity index 98% rename from docker/inventree/start_server.sh rename to docker/start_prod_server.sh index db9f1594ae..1fc8f6d111 100644 --- a/docker/inventree/start_server.sh +++ b/docker/start_prod_server.sh @@ -43,4 +43,4 @@ python manage.py collectstatic --noinput || exit 1 python manage.py clearsessions || exit 1 # Now we can launch the server -gunicorn -c $INVENTREE_HOME/gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:$INVENTREE_WEB_PORT +gunicorn -c $INVENTREE_HOME/gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:$INVENTREE_WEB_PORT \ No newline at end of file diff --git a/docker/inventree/start_worker.sh b/docker/start_worker.sh similarity index 88% rename from docker/inventree/start_worker.sh rename to docker/start_worker.sh index 7d0921a7af..ba9eb14d65 100644 --- a/docker/inventree/start_worker.sh +++ b/docker/start_worker.sh @@ -11,4 +11,4 @@ python manage.py wait_for_db sleep 10 # Now we can launch the background worker process -python manage.py qcluster +python manage.py qcluster \ No newline at end of file