diff --git a/Dockerfile b/Dockerfile index 486af93cd8a3..9c91c086e2b8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -95,10 +95,9 @@ ENV TESTING=false ARG COMMIT ENV GIT_COMMIT_HASH=$COMMIT -# curl for used by healthcheck RUN apt-get update \ && apt-get install --no-install-recommends -y \ - curl gosu \ + gosu \ tesseract-ocr-all \ && apt-get autoremove \ && rm -rf /var/lib/apt/lists/* @@ -107,9 +106,6 @@ RUN apt-get update \ COPY --from=builder-base $POETRY_HOME $POETRY_HOME COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH -# copy CRF++ Binary from crfpp -ENV CRF_MODEL_URL=https://github.com/mealie-recipes/nlp-model/releases/download/v1.0.0/model.crfmodel - ENV LD_LIBRARY_PATH=/usr/local/lib COPY --from=crfpp /usr/local/lib/ /usr/local/lib COPY --from=crfpp /usr/local/bin/crf_learn /usr/local/bin/crf_learn @@ -130,14 +126,14 @@ RUN . $VENV_PATH/bin/activate && poetry install -E pgsql --no-dev WORKDIR / # Grab CRF++ Model Release -RUN curl -L0 $CRF_MODEL_URL --output $MEALIE_HOME/mealie/services/parser_services/crfpp/model.crfmodel +RUN python $MEALIE_HOME/mealie/scripts/install_model.py VOLUME [ "$MEALIE_HOME/data/" ] ENV APP_PORT=9000 EXPOSE ${APP_PORT} -HEALTHCHECK CMD curl -f http://localhost:${APP_PORT}/docs || exit 1 +HEALTHCHECK CMD python $MEALIE_HOME/mealie/scripts/healthcheck.py || exit 1 RUN chmod +x $MEALIE_HOME/mealie/run.sh ENTRYPOINT $MEALIE_HOME/mealie/run.sh diff --git a/docker-compose.yml b/docker-compose.yml index 034403a41cef..a5da2ed1803c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,10 @@ services: mealie-frontend: container_name: mealie-frontend image: mealie-frontend:dev + deploy: + resources: + limits: + memory: 500M build: context: ./frontend dockerfile: Dockerfile @@ -34,6 +38,10 @@ services: - THEME_DARK_ERROR=#EF5350 mealie: container_name: mealie-api + deploy: + resources: + limits: + memory: 1000M build: context: ./ target: production @@ -57,6 +65,7 @@ services: # ===================================== # Web Concurrency + WEB_GUNICORN: true WORKERS_PER_CORE: 0.5 MAX_WORKERS: 1 WEB_CONCURRENCY: 1 diff --git a/docs/docs/documentation/getting-started/installation/backend-config.md b/docs/docs/documentation/getting-started/installation/backend-config.md index 78ec7c0e5c8b..5f67c86d1a42 100644 --- a/docs/docs/documentation/getting-started/installation/backend-config.md +++ b/docs/docs/documentation/getting-started/installation/backend-config.md @@ -54,6 +54,7 @@ Changing the webworker settings may cause unforeseen memory leak issues with Mea | Variables | Default | Description | | ---------------- | :-----: | --------------------------------------------------------------------------------------------------------------------------------- | +| WEB_GUNICORN | false | Enables Gunicorn to manage Uvicorn web for multiple works | | WORKERS_PER_CORE | 1 | Set the number of workers to the number of CPU cores multiplied by this value (Value \* CPUs). More info [here][workers_per_core] | | MAX_WORKERS | 1 | Set the maximum number of workers to use. Default is not set meaning unlimited. More info [here][max_workers] | | WEB_CONCURRENCY | 1 | Override the automatic definition of number of workers. More info [here][web_concurrency] | @@ -68,5 +69,5 @@ Changing the webworker settings may cause unforeseen memory leak issues with Mea | LDAP_TLS_INSECURE | False | Do not verify server certificate when using secure LDAP | | LDAP_TLS_CACERTFILE | None | File path to Certificate Authority used to verify server certificate (e.g. `/path/to/ca.crt`) | | LDAP_BIND_TEMPLATE | None | Templated DN for users, `{}` will be replaced with the username (e.g. `cn={},dc=example,dc=com`, `{}@example.com`) | -| LDAP_BASE_DN | None | Starting point when searching for users authentication (e.g. `CN=Users,DC=xx,DC=yy,DC=de`) | +| LDAP_BASE_DN | None | Starting point when searching for users authentication (e.g. `CN=Users,DC=xx,DC=yy,DC=de`) | | LDAP_ADMIN_FILTER | None | Optional LDAP filter, which tells Mealie the LDAP user is an admin (e.g. `(memberOf=cn=admins,dc=example,dc=com)`) | diff --git a/docs/docs/documentation/getting-started/installation/postgres.md b/docs/docs/documentation/getting-started/installation/postgres.md index 4dd1cf7fefaf..cc659389fabf 100644 --- a/docs/docs/documentation/getting-started/installation/postgres.md +++ b/docs/docs/documentation/getting-started/installation/postgres.md @@ -25,6 +25,10 @@ services: mealie-api: image: hkotel/mealie:api-v1.0.0beta-4 container_name: mealie-api + deploy: + resources: + limits: + memory: 1000M # (4) depends_on: - postgres volumes: @@ -66,3 +70,4 @@ volumes:

**Note** that both containers must be on the same docker-network for this to work. 2. To access the mealie interface you only need to expose port 3000 on the mealie-frontend container. Here we expose port 9925 on the host, feel free to change this to any port you like. 3. Mounting the data directory to the frontend is now required to access the images/assets directory. This can be mounted read-only. Internally the frontend containers runs a Caddy proxy server that serves the assets requested to reduce load on the backend API. +4. Setting an explicit memory limit is recommended. Python can pre-allocate larger amounts of memory than is necessary if you have a machine with a lot of RAM. This can cause the container to idle at a high memory usage. Setting a memory limit will improve idle performance. diff --git a/docs/docs/documentation/getting-started/installation/sqlite.md b/docs/docs/documentation/getting-started/installation/sqlite.md index 3cdc7bee29f9..6bb8ce166ca5 100644 --- a/docs/docs/documentation/getting-started/installation/sqlite.md +++ b/docs/docs/documentation/getting-started/installation/sqlite.md @@ -25,6 +25,10 @@ services: mealie-api: image: hkotel/mealie:api-v1.0.0beta-4 container_name: mealie-api + deploy: + resources: + limits: + memory: 1000M # (4) volumes: - mealie-data:/app/data/ environment: @@ -49,3 +53,4 @@ volumes:

**Note** that both containers must be on the same docker-network for this to work. 2. To access the mealie interface you only need to expose port 3000 on the mealie-frontend container. Here we expose port 9925 on the host, feel free to change this to any port you like. 3. Mounting the data directory to the frontend is now required to access the images/assets directory. This can be mounted read-only. Internally the frontend containers runs a Caddy proxy server that serves the assets requested to reduce load on the backend API. +4. Setting an explicit memory limit is recommended. Python can pre-allocate larger amounts of memory than is necessary if you have a machine with a lot of RAM. This can cause the container to idle at a high memory usage. Setting a memory limit will improve idle performance. diff --git a/mealie/run.sh b/mealie/run.sh index c2c0217fec24..054a4676cdbf 100755 --- a/mealie/run.sh +++ b/mealie/run.sh @@ -41,11 +41,6 @@ init() { poetry run python /app/mealie/db/init_db.py } -# Migrations -# TODO -# Migrations -# Set Port from ENV Variable - if [ "$ARG1" == "reload" ]; then echo "Hot Reload!" @@ -63,6 +58,11 @@ else GUNICORN_PORT=${API_PORT:-9000} # Start API - # uvicorn mealie.app:app --host 0.0.0.0 --port 9000 - gunicorn mealie.app:app -b 0.0.0.0:$GUNICORN_PORT -k uvicorn.workers.UvicornWorker -c /app/gunicorn_conf.py --preload + + if [ $WEB_GUNICORN == 'true' ]; then + echo "Starting Gunicorn" + gunicorn mealie.app:app -b 0.0.0.0:$GUNICORN_PORT -k uvicorn.workers.UvicornWorker -c /app/gunicorn_conf.py --preload + else + uvicorn mealie.app:app --host 0.0.0.0 --port $GUNICORN_PORT + fi fi diff --git a/mealie/scripts/healthcheck.py b/mealie/scripts/healthcheck.py new file mode 100644 index 000000000000..9b1f36475c6a --- /dev/null +++ b/mealie/scripts/healthcheck.py @@ -0,0 +1,23 @@ +import os + +import requests + + +def main(): + port = os.getenv("API_PORT") + + if port is None: + port = 9000 + + url = f"http://127.0.0.1:{port}/api/app/about" + + r = requests.get(url) + + if r.status_code == 200: + exit(0) + else: + exit(1) + + +if __name__ == "__main__": + main() diff --git a/mealie/scripts/install_model.py b/mealie/scripts/install_model.py new file mode 100644 index 000000000000..8c540dac9bd7 --- /dev/null +++ b/mealie/scripts/install_model.py @@ -0,0 +1,21 @@ +import requests + +from mealie.services.parser_services import crfpp + +MODEL_URL = "https://github.com/mealie-recipes/nlp-model/releases/download/v1.0.0/model.crfmodel" + + +def main(): + """ + Install the model into the crfpp directory + """ + + r = requests.get(MODEL_URL, stream=True, allow_redirects=True) + with open(crfpp.MODEL_PATH, "wb") as f: + for chunk in r.iter_content(chunk_size=1024): + if chunk: + f.write(chunk) + + +if __name__ == "__main__": + main()