From d80d297d972b1075c3766e4833478eb149e93299 Mon Sep 17 00:00:00 2001 From: Adrian Priestley Date: Wed, 1 Jan 2025 10:35:47 -0330 Subject: [PATCH] feat(deployment): Implement containerized deployment configuration - Add additional environment variables for Python optimization - Update Dockerfile with new dependencies: eventlet, gevent, tornado - Create docker-compose.yml and configure services for web and nginx - Implement example configurations for web host settings and gunicorn - Establish nginx configuration for reverse proxy - Remove outdated docker-compose.yml from root directory --- Dockerfile | 10 ++++-- deploy/docker-compose.yml | 36 +++++++++++++++++++ deploy/example_config.yaml | 9 +++++ deploy/example_gunicorn.conf.py | 11 ++++++ deploy/example_nginx.conf | 64 +++++++++++++++++++++++++++++++++ deploy/example_selflaunch.yaml | 11 ++++++ docker-compose.yml | 22 ------------ 7 files changed, 139 insertions(+), 24 deletions(-) create mode 100644 deploy/docker-compose.yml create mode 100644 deploy/example_config.yaml create mode 100644 deploy/example_gunicorn.conf.py create mode 100644 deploy/example_nginx.conf create mode 100644 deploy/example_selflaunch.yaml delete mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile index 0601b7adec..a81f24513d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,8 @@ RUN if [ "$ARCHITECTURE" = "x86_64" ]; then \ #Archipelago FROM python:3.12-slim AS archipelago ENV VIRTUAL_ENV=/opt/venv +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 WORKDIR /app COPY . . @@ -40,8 +42,12 @@ RUN apt-get update; \ RUN python -m venv $VIRTUAL_ENV; \ . $VIRTUAL_ENV/bin/activate -#hadolint ignore=DL3042 -RUN pip install -r WebHostLib/requirements.txt gunicorn==23.0.0; \ +# hadolint ignore=DL3042 +RUN pip install -r WebHostLib/requirements.txt \ + gunicorn==23.0.0 \ + eventlet==0.38.2 \ + gevent==24.11.1 \ + tornado==6.4.2; \ python ModuleUpdate.py -y RUN cythonize -i _speedups.pyx diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml new file mode 100644 index 0000000000..2dc7c7621f --- /dev/null +++ b/deploy/docker-compose.yml @@ -0,0 +1,36 @@ +services: + web: + build: + context: .. + entrypoint: > + sh -c "python WebHost.py --config_override selflaunch.yaml & gunicorn -c gunicorn.conf.py" + volumes: + - static_volume:/app/WebHostLib + - output_volume:/app/output + - sprites_alttpr_volume:/app/sprites/alttpr + - sprites_custom_volume:/app/sprites/custom + - ./example_config.yaml:/app/config.yaml + - ./example_selflaunch.yaml:/app/selflaunch.yaml + - ./example_gunicorn.conf.py:/app/gunicorn.conf.py + environment: + #Bind gunicorn to 0.0.0.0:8000 + - PORT=8000 + network_mode: host + + nginx: + image: nginx:stable-alpine + volumes: + - static_volume:/app/WebHostLib + - ./example_nginx.conf:/etc/nginx/nginx.conf + ports: + - 8080:80 + depends_on: + - web + extra_hosts: + - "host.docker.internal:host-gateway" + +volumes: + static_volume: + output_volume: + sprites_alttpr_volume: + sprites_custom_volume: diff --git a/deploy/example_config.yaml b/deploy/example_config.yaml new file mode 100644 index 0000000000..ef6301a6e8 --- /dev/null +++ b/deploy/example_config.yaml @@ -0,0 +1,9 @@ +# Refer to ../docs/webhost configuration sample.yaml + +# We'll be hosting VIA gunicorn +SELFHOST: false +SELFLAUNCH: false + +# Host Address. This is the address encoded into the patch that will be used for client auto-connect. +# Set as your local IP to serve over LAN. +HOST_ADDRESS: localhost diff --git a/deploy/example_gunicorn.conf.py b/deploy/example_gunicorn.conf.py new file mode 100644 index 0000000000..1c9cb6ca33 --- /dev/null +++ b/deploy/example_gunicorn.conf.py @@ -0,0 +1,11 @@ +import multiprocessing + +workers = multiprocessing.cpu_count() * 2 + 1 +wsgi_app = "WebHost:get_app()" +accesslog = "-" +access_log_format = ( + '%({x-forwarded-for}i)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' +) +worker_class = "sync" # "sync" | eventlet" | "gevent" | "tornado" +forwarded_allow_ips = "*" +loglevel = "debug" diff --git a/deploy/example_nginx.conf b/deploy/example_nginx.conf new file mode 100644 index 0000000000..2d4d8a6cf4 --- /dev/null +++ b/deploy/example_nginx.conf @@ -0,0 +1,64 @@ +worker_processes 1; + +user nobody nogroup; +# 'user nobody nobody;' for systems with 'nobody' as a group instead +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; # increase if you have lots of clients + accept_mutex off; # set to 'on' if nginx worker_processes > 1 + # 'use epoll;' to enable for Linux 2.6+ + # 'use kqueue;' to enable for FreeBSD, OSX + use epoll; +} + +http { + include mime.types; + # fallback in case we can't determine a type + default_type application/octet-stream; + access_log /var/log/nginx/access.log combined; + sendfile on; + + upstream app_server { + # fail_timeout=0 means we always retry an upstream even if it failed + # to return a good HTTP response + + # for UNIX domain socket setups + # server unix:/tmp/gunicorn.sock fail_timeout=0; + + # for a TCP configuration + server host.docker.internal:8000 fail_timeout=0; + } + + server { + # use 'listen 80 deferred;' for Linux + # use 'listen 80 accept_filter=httpready;' for FreeBSD + listen 80 deferred; + client_max_body_size 4G; + + # set the correct host(s) for your site + # server_name example.com www.example.com; + + keepalive_timeout 5; + + # path for static files + root /app/WebHostLib; + + location / { + # checks for static file, if not found proxy to app + try_files $uri @proxy_to_app; + } + + location @proxy_to_app { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $http_host; + # we don't want nginx trying to do something clever with + # redirects, we set the Host: header above already. + proxy_redirect off; + + proxy_pass http://app_server; + } + } +} diff --git a/deploy/example_selflaunch.yaml b/deploy/example_selflaunch.yaml new file mode 100644 index 0000000000..87719a0e8e --- /dev/null +++ b/deploy/example_selflaunch.yaml @@ -0,0 +1,11 @@ +# Refer to ../docs/webhost configuration sample.yaml + +# We'll be hosting VIA gunicorn +SELFHOST: false +SELFLAUNCH: true +JOB_THRESHOLD: 0 + +# Maximum concurrent world gens +GENERATORS: 8 + +HOSTERS: 5 diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index afca1722b1..0000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,22 +0,0 @@ -services: - web: - build: - context: . - command: python WebHost.py - volumes: - - static_volume:/app/WebHostLib - - ./config.yaml:/app/config.yaml - expose: - - 5000 - nginx: - image: nginx:stable-alpine - volumes: - - static_volume:/app/WebHostLib - - ./nginx.conf:/etc/nginx/conf.d/default.conf - ports: - - 7235:80 - depends_on: - - web - -volumes: - static_volume: