From 6ab05d33b750afe069f399b801ebd424b5d98a15 Mon Sep 17 00:00:00 2001 From: scragly <29337040+scragly@users.noreply.github.com> Date: Sun, 20 Oct 2019 05:14:49 +1000 Subject: Set default example.com dev site to pythondiscord.local:8000 --- manage.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'manage.py') diff --git a/manage.py b/manage.py index d2996488..dc4aef08 100755 --- a/manage.py +++ b/manage.py @@ -112,6 +112,19 @@ class SiteManager: print("Database could not be found, exiting.") sys.exit(1) + @staticmethod + def set_dev_site_name() -> None: + """Set the development site domain in admin from default example.""" + # import Site model now after django setup + from django.contrib.sites.models import Site + query = Site.objects.filter(id=1) + site = query.get() + if site.domain == "example.com": + query.update( + domain="pythondiscord.local:8000", + name="pythondiscord.local:8000" + ) + def prepare_server(self) -> None: """Perform preparation tasks before running the server.""" django.setup() @@ -125,6 +138,7 @@ class SiteManager: call_command("collectstatic", interactive=False, clear=True, verbosity=self.verbosity) if self.debug: + self.set_dev_site_name() self.create_superuser() def run_server(self) -> None: -- cgit v1.2.3 From a8d4ac9841fe7be63aed2ba33b171c21f0eb5f33 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Sat, 14 Nov 2020 21:18:04 +0100 Subject: Banish UWSGI from my life, replace with gunicorn. This gets rid of various uwsgi stuff that we will no longer be needing. Enter; gunicorn. --- .dockerignore | 3 -- Pipfile | 2 +- docker/uwsgi.ini | 38 -------------- docs/deployment.md | 146 ----------------------------------------------------- manage.py | 7 +-- 5 files changed, 3 insertions(+), 193 deletions(-) delete mode 100644 docker/uwsgi.ini delete mode 100644 docs/deployment.md (limited to 'manage.py') diff --git a/.dockerignore b/.dockerignore index 61fa291a..b6334213 100644 --- a/.dockerignore +++ b/.dockerignore @@ -15,9 +15,6 @@ pydis_site/apps/home/tests pydis_site/apps/staff/tests CHANGELOG.md CONTRIBUTING.md -docker -!docker/uwsgi.ini -!docker/wheels docker-compose.yml Dockerfile.local docs diff --git a/Pipfile b/Pipfile index 27a2a452..add1f97b 100644 --- a/Pipfile +++ b/Pipfile @@ -16,7 +16,7 @@ requests = "~=2.21" pygments = "~=2.3.1" wiki = "~=0.6.0" pyyaml = "~=5.1" -pyuwsgi = {version = "~=2.0", sys_platform = "!='win32'"} +gunicorn = "~=20.0.4" django-allauth = "~=0.41" sentry-sdk = "~=0.14" gitpython = "~=3.1.7" diff --git a/docker/uwsgi.ini b/docker/uwsgi.ini deleted file mode 100644 index 3f35258c..00000000 --- a/docker/uwsgi.ini +++ /dev/null @@ -1,38 +0,0 @@ -[uwsgi] -### Exposed ports -# uWSGI protocol socket -socket = :4000 - -### File settings -# WSGI application -wsgi = pydis_site.wsgi:application -# Directory to move into at startup -chdir = /app - -### Concurrency options -# Run a master to supervise the workers -master = true -# Keep a minimum of 1 worker -cheaper = 1 -# Allow a maximum of 4 workers -workers = 4 -# Automatically set up meanginful process names -auto-procname = true -# Prefix process names with `pydis_site : ` -procname-prefix-spaced = pydis_site : - -### Worker options -# Kill workers if they take more than 30 seconds to respond. -harakiri = 30 - -### Startup settings -# Exit if we can't load the app -need-app = true -# `setuid` to an unprivileged user -uid = 1500 -# Do not use multiple interpreters -single-interpreter = true - -### Hook setup -# Gracefully kill workers on `SIGQUIT` -hook-master-start = unix_signal:3 gracefully_kill_them_all diff --git a/docs/deployment.md b/docs/deployment.md deleted file mode 100644 index e561b5d0..00000000 --- a/docs/deployment.md +++ /dev/null @@ -1,146 +0,0 @@ -# Deployment -The default Dockerfile should do a good job at running a solid web server that -automatically adjusts its worker count based on traffic. This is managed by -uWSGI. You need to configure the `DATABASE_URL` and `SECRET_KEY` variables. If -you want to deploy to a different host than the default, configure the -`ALLOWED_HOSTS` variable. - -## Static file hosting -You can either collect the static files in the container and use uWSGI to host -them, or put them on your host and manage them through a web server running on -the host like nginx. - -## Database migrations -To bring the schema up-to-date, first stop an existing database container, then -start a container that just runs the migrations and exits, and then starts the -main container off the new container again. - -## Ansible task -An example Ansible task to deploy the site is shown below, it should read fairly -humanly and give you a rough idea of steps needed to deploy the site. - -```yml -- name: ensure the `{{ pysite_pg_username }}` postgres user exists - become: yes - become_user: postgres - postgresql_user: - name: "{{ pysite_pg_username }}" - password: "{{ pysite_pg_password }}" - when: pysite_pg_host == 'localhost' - -- name: ensure the `{{ pysite_pg_database }}` postgres database exists - become: yes - become_user: postgres - postgresql_db: - name: "{{ pysite_pg_database }}" - owner: "{{ pysite_pg_username }}" - when: pysite_pg_host == 'localhost' - -- name: ensure the `{{ pysite_hub_repository }}` image is up-to-date - become: yes - docker_image: - name: "{{ pysite_hub_repository }}" - force: yes - -- name: ensure the nginx HTTP vhosts are up-to-date - become: yes - template: - src: "nginx/{{ item.key }}.http.conf.j2" - dest: "/etc/nginx/sites-available/{{ item.value }}.http.conf" - with_dict: "{{ pysite_domains }}" - notify: reload nginx - -- name: ensure the nginx HTTPS vhosts are up-to-date - become: yes - template: - src: "nginx/{{ item.key }}.https.conf.j2" - dest: "/etc/nginx/sites-available/{{ item.value }}.https.conf" - with_dict: "{{ pysite_domains }}" - notify: reload nginx - -- name: ensure the nginx HTTP vhosts are symlinked to `/etc/nginx/sites-enabled` - become: yes - file: - src: /etc/nginx/sites-available/{{ item.value }}.http.conf - dest: /etc/nginx/sites-enabled/{{ item.value }}.http.conf - state: link - with_dict: "{{ pysite_domains }}" - notify: reload nginx - -- name: ensure we have HTTPS certificates - include_role: - name: thefinn93.letsencrypt - vars: - letsencrypt_cert_domains: "{{ pysite_domains | dict2items | map(attribute='value') | list }}" - letsencrypt_email: "webmaster@example.com" - letsencrypt_renewal_command_args: '--renew-hook "systemctl restart nginx"' - letsencrypt_webroot_path: /var/www/_letsencrypt - -- name: ensure the nginx HTTPS vhosts are symlinked to `/etc/nginx/sites-enabled` - become: yes - file: - src: /etc/nginx/sites-available/{{ item.value }}.https.conf - dest: /etc/nginx/sites-enabled/{{ item.value }}.https.conf - state: link - with_dict: "{{ pysite_domains }}" - notify: reload nginx - -- name: ensure the web container is absent - become: yes - docker_container: - name: pysite - state: absent - -- name: ensure the `{{ pysite_static_file_dir }}` directory exists - become: yes - file: - path: "{{ pysite_static_file_dir }}" - state: directory - owner: root - group: root - -- name: collect static files - become: yes - docker_container: - image: "{{ pysite_hub_repository }}" - name: pysite-static-file-writer - command: python manage.py collectstatic --noinput - detach: no - cleanup: yes - network_mode: host - env: - DATABASE_URL: "{{ pysite_pg_database_url }}" - SECRET_KEY: "me-dont-need-no-secret-key" - STATIC_ROOT: "/html" - volumes: - - "/var/www/pythondiscord.com:/html" - -- name: ensure the database schema is up-to-date - become: yes - docker_container: - image: "{{ pysite_hub_repository }}" - name: pysite-migrator - detach: no - cleanup: yes - command: python manage.py migrate - network_mode: host - env: - DATABASE_URL: "postgres://{{ pysite_pg_username }}:{{ pysite_pg_password }}@{{ pysite_pg_host }}/{{ pysite_pg_database }}" - SECRET_KEY: "me-dont-need-no-secret-key" - -- name: ensure the website container is started - become: yes - docker_container: - image: "{{ pysite_hub_repository }}" - name: pysite - network_mode: host - restart: yes - restart_policy: unless-stopped - ports: - - "127.0.0.1:4000:4000" - env: - ALLOWED_HOSTS: "{{ pysite_domains | dict2items | map(attribute='value') | join(',') }}" - DATABASE_URL: "postgres://{{ pysite_pg_username }}:{{ pysite_pg_password }}@{{ pysite_pg_host }}/{{ pysite_pg_database }}" - PARENT_HOST: pysite.example.com - SECRET_KEY: "{{ pysite_secret_key }}" -``` diff --git a/manage.py b/manage.py index d4748a3a..62352177 100755 --- a/manage.py +++ b/manage.py @@ -10,7 +10,6 @@ import django from django.contrib.auth import get_user_model from django.core.management import call_command, execute_from_command_line - DEFAULT_ENVS = { "DJANGO_SETTINGS_MODULE": "pydis_site.settings", "SUPER_USERNAME": "admin", @@ -156,10 +155,8 @@ class SiteManager: call_command("runserver", "0.0.0.0:8000") return - import pyuwsgi - - # Run uwsgi for production server - pyuwsgi.run(["--ini", "docker/uwsgi.ini"]) + # Run gunicorn for production server + os.system("gunicorn --preload -b 0.0.0.0:8000 pydis_site.wsgi:application --threads 8 -w 4") def main() -> None: -- cgit v1.2.3 From f57357e9f468797493e811e67998345ad4ee0e7a Mon Sep 17 00:00:00 2001 From: Joe Banks Date: Sat, 14 Nov 2020 21:55:04 +0000 Subject: Don't call gunicorn using os.system, patch sys.argv and call the module --- manage.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'manage.py') diff --git a/manage.py b/manage.py index 62352177..446b1af3 100755 --- a/manage.py +++ b/manage.py @@ -7,6 +7,7 @@ import time from typing import List import django +import gunicorn.app.wsgiapp from django.contrib.auth import get_user_model from django.core.management import call_command, execute_from_command_line @@ -155,8 +156,18 @@ class SiteManager: call_command("runserver", "0.0.0.0:8000") return - # Run gunicorn for production server - os.system("gunicorn --preload -b 0.0.0.0:8000 pydis_site.wsgi:application --threads 8 -w 4") + # Patch the arguments for gunicorn + sys.argv = [ + "gunicorn", + "--preload", + "-b", "0.0.0.0:8000", + "pydis_site.wsgi:application", + "--threads", "8", + "-w", "4" + ] + + # Run gunicorn for the production server. + gunicorn.app.wsgiapp.run() def main() -> None: -- cgit v1.2.3 From 862a982115bc6feb46c082484740765b0eac5caa Mon Sep 17 00:00:00 2001 From: Joe Banks Date: Sat, 5 Dec 2020 15:40:04 +0000 Subject: Update gunicorn configuration options --- manage.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'manage.py') diff --git a/manage.py b/manage.py index 446b1af3..36442eab 100755 --- a/manage.py +++ b/manage.py @@ -163,7 +163,10 @@ class SiteManager: "-b", "0.0.0.0:8000", "pydis_site.wsgi:application", "--threads", "8", - "-w", "4" + "-w", "4", + "--max-requests-jitter", "1000", + "--statsd_host", "graphite.default.svc.cluster.local:8125", + "--statsd_prefix", "site", ] # Run gunicorn for the production server. -- cgit v1.2.3 From 702afad1ee0973c8b46b641bba1665dc7c490b06 Mon Sep 17 00:00:00 2001 From: Joe Banks Date: Sat, 5 Dec 2020 15:43:21 +0000 Subject: Switch underscores for dashes in gunicorn CLI options --- manage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'manage.py') diff --git a/manage.py b/manage.py index 36442eab..3dee15c0 100755 --- a/manage.py +++ b/manage.py @@ -165,8 +165,8 @@ class SiteManager: "--threads", "8", "-w", "4", "--max-requests-jitter", "1000", - "--statsd_host", "graphite.default.svc.cluster.local:8125", - "--statsd_prefix", "site", + "--statsd-host", "graphite.default.svc.cluster.local:8125", + "--statsd-prefix", "site", ] # Run gunicorn for the production server. -- cgit v1.2.3 From 4e0ec7b5d7a7fe9cce28f795ef376435ed01c944 Mon Sep 17 00:00:00 2001 From: Joe Banks Date: Sun, 6 Dec 2020 12:43:50 +0000 Subject: Update manage.py Co-authored-by: Sebastiaan Zeeff <33516116+SebastiaanZ@users.noreply.github.com> --- manage.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'manage.py') diff --git a/manage.py b/manage.py index 3dee15c0..a025e7b1 100755 --- a/manage.py +++ b/manage.py @@ -164,7 +164,8 @@ class SiteManager: "pydis_site.wsgi:application", "--threads", "8", "-w", "4", - "--max-requests-jitter", "1000", + "--max-requests", "1000", + "--max-requests-jitter", "50", "--statsd-host", "graphite.default.svc.cluster.local:8125", "--statsd-prefix", "site", ] -- cgit v1.2.3 From 97d0ece403870a5a2184350608cda448808d70ac Mon Sep 17 00:00:00 2001 From: Joe Banks Date: Thu, 25 Feb 2021 16:57:32 +0000 Subject: Reduce worker count from 4 to 2 We'll be creating a second site instance to allow for rolling restarts, so it makes sense to half this so when we double the requests we'll effectively have 4 workers again. --- manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'manage.py') diff --git a/manage.py b/manage.py index a025e7b1..fb5ee40c 100755 --- a/manage.py +++ b/manage.py @@ -163,7 +163,7 @@ class SiteManager: "-b", "0.0.0.0:8000", "pydis_site.wsgi:application", "--threads", "8", - "-w", "4", + "-w", "2", "--max-requests", "1000", "--max-requests-jitter", "50", "--statsd-host", "graphite.default.svc.cluster.local:8125", -- cgit v1.2.3