Update production
This commit is contained in:
parent
c22dfe89fd
commit
8bb5ec1730
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
|
@ -74,7 +74,7 @@ Il ne nous reste plus qu'à mettre à jour la DB. On commance par créer le fich
|
||||||
|
|
||||||
(gwift)gwift@gwift:~$ touch gwift/gwift/settings/local.py
|
(gwift)gwift@gwift:~$ touch gwift/gwift/settings/local.py
|
||||||
|
|
||||||
Et le contenu de local.py, avec la clé secrète et les paramètres pour se connecter à la DB:
|
Et le contenu de local.py, avec la clé secrète, les paramètres pour se connecter à la DB et l'endroit où mettre les fichiers statics (voir point suivant):
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -88,6 +88,12 @@ Et le contenu de local.py, avec la clé secrète et les paramètres pour se conn
|
||||||
|
|
||||||
# Allowed host needed to be defined in production
|
# Allowed host needed to be defined in production
|
||||||
ALLOWED_HOSTS = ["sever_name.com", "www.sever_name.com"]
|
ALLOWED_HOSTS = ["sever_name.com", "www.sever_name.com"]
|
||||||
|
|
||||||
|
# Be sure to force https for csrf cookie
|
||||||
|
CSRF_COOKIE_SECURE = True
|
||||||
|
|
||||||
|
# Same for session cookie
|
||||||
|
SESSION_COOKIE_SECURE = True
|
||||||
|
|
||||||
# DB
|
# DB
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
|
@ -100,6 +106,13 @@ Et le contenu de local.py, avec la clé secrète et les paramètres pour se conn
|
||||||
'PORT': '', # Set to empty string for default.
|
'PORT': '', # Set to empty string for default.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add static root
|
||||||
|
STATIC_ROOT = "/webapps/gwift/gwift/static"
|
||||||
|
|
||||||
|
STATICFILES_DIRS = [
|
||||||
|
os.path.join(BASE_DIR, "static"),
|
||||||
|
]
|
||||||
|
|
||||||
Finalement, on peut mettre à jour la DB et créer un super utilisateur:
|
Finalement, on peut mettre à jour la DB et créer un super utilisateur:
|
||||||
|
|
||||||
|
@ -108,6 +121,24 @@ Finalement, on peut mettre à jour la DB et créer un super utilisateur:
|
||||||
(gwift)gwift@gwift:~$ python manage.py migrate
|
(gwift)gwift@gwift:~$ python manage.py migrate
|
||||||
(gwift)gwift@gwift:~$ python manage.py createsuperuser
|
(gwift)gwift@gwift:~$ python manage.py createsuperuser
|
||||||
|
|
||||||
|
Fichiers statics
|
||||||
|
================
|
||||||
|
|
||||||
|
Django n'est pas fait pour servir les fichiers statics. Tous les fichiers statics doivent donc être déplacés dans un répertoire pour que Nginx puisse les servir facilement.
|
||||||
|
|
||||||
|
On commence par créer le répertoire où mettre les fichiers statics comme configuré dans le fichier local.py:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
(gwift)gwift@gwift:~$ mkdir /webapps/gwift/gwift/static
|
||||||
|
|
||||||
|
Et on utilise django pour copier tous les fichiers statics au bon endroit:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
(gwift)gwift@gwift:~$ python manage.py collectstatic
|
||||||
|
|
||||||
|
|
||||||
Test
|
Test
|
||||||
====
|
====
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
*************
|
||||||
|
Gunicorn
|
||||||
|
*************
|
||||||
|
|
||||||
|
Nous allons utiliser ``gunicorn`` comme serveur d'applications, le serveur fourni par django n'étant pas fait pour être utilisé en production.
|
||||||
|
|
||||||
|
Gunicorn a déjà été installé lors de la préparation de l'environnement. De même que ``setproctitle``, qui est nécessaire pour donner le nom de l'application aux processus python lancés par gunicorn.
|
||||||
|
|
||||||
|
Nous pouvons donc directement tester s'il fonctionne:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
(gwift)gwift@gwift:~$ gunicorn gwift.wsgi:application --bind esever_name.com:8000
|
||||||
|
|
||||||
|
Et en se rendant sur server_name.com:8000/admin, on obtient la même chose qu'avec le serveur de django:
|
||||||
|
|
||||||
|
.. image:: production/admin_without_static.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Nous allons maintenant créer un ficheir qui se chargera de lancer gunicorn correctement, que l'on sauve dans ``/webapps/gwift/gwift/bin/gunicorn_start``:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Define settings for gunicorn
|
||||||
|
NAME="gwift" # Name of the application
|
||||||
|
DJANGODIR=/webapps/gwift/gwift/gwift # Django project directory
|
||||||
|
SOCKFILE=/webapps/gwift/gwift/run/gunicorn.sock # we will communicte using this unix socket
|
||||||
|
USER=gwift # the user to run as
|
||||||
|
GROUP=webapps # the group to run as
|
||||||
|
NUM_WORKERS=3 # how many worker processes should Gunicorn spawn
|
||||||
|
DJANGO_SETTINGS_MODULE=gwift.settings # which settings file should Django use
|
||||||
|
DJANGO_WSGI_MODULE=gwift.wsgi # WSGI module name
|
||||||
|
|
||||||
|
echo "Starting $NAME as `whoami`"
|
||||||
|
|
||||||
|
# Activate the virtual environment
|
||||||
|
source /webapps/gwift/.virtualenvs/gwift/bin/activate
|
||||||
|
cd $DJANGODIR
|
||||||
|
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
|
||||||
|
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
|
||||||
|
|
||||||
|
# Create the run directory if it doesn't exist
|
||||||
|
RUNDIR=$(dirname $SOCKFILE)
|
||||||
|
test -d $RUNDIR || mkdir -p $RUNDIR
|
||||||
|
|
||||||
|
# Start your Django Unicorn
|
||||||
|
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
|
||||||
|
exec gunicorn ${DJANGO_WSGI_MODULE}:application \
|
||||||
|
--name $NAME \
|
||||||
|
--workers $NUM_WORKERS \
|
||||||
|
--user=$USER --group=$GROUP \
|
||||||
|
--bind=unix:$SOCKFILE \
|
||||||
|
--log-level=debug \
|
||||||
|
--log-file=-
|
||||||
|
|
||||||
|
Explications:
|
||||||
|
|
||||||
|
* NUM_WORKERS : gunicorn lance autant de worker que ce nombre. Un worker représente l'équivallant d'une instance de django et ne peut traiter qu'une requête à la fois. Traditionnellement, on créé autant de worker que le double du nombre de processeurs plus un.
|
||||||
|
* SOCKFILE : on configure gunicorn pour communiquer via un socket unix, ce qui est plus efficace de le faire par tcp/ip
|
||||||
|
|
||||||
|
Le script se charge donc de définir les options de configuration de gunicorn, de lancer l'environnement virtuel et ensuite gunicorn.
|
||||||
|
|
||||||
|
On peut le tester avec la commande suivante (hors environnement virtuel):
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
gwift@gwift:~$ source /webapps/gwift/gwift/bin/gunicorn_start
|
||||||
|
|
||||||
|
Et avec un petit ``ps`` dans un autre shell:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
gwift@gwift:~$ ps -u gwift -F
|
||||||
|
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
|
||||||
|
gwift 31983 15685 0 18319 15084 1 Apr29 ? 00:00:01 gunicorn: master [gwift]
|
||||||
|
gwift 31992 31983 0 35636 29312 1 Apr29 ? 00:00:00 gunicorn: worker [gwift]
|
||||||
|
gwift 31993 31983 0 35634 29280 2 Apr29 ? 00:00:00 gunicorn: worker [gwift]
|
||||||
|
gwift 31994 31983 0 35618 29228 0 Apr29 ? 00:00:00 gunicorn: worker [gwift]
|
||||||
|
|
||||||
|
On voit donc bien qu'il y a un maître et trois workers.
|
|
@ -2,15 +2,50 @@
|
||||||
Monitoring
|
Monitoring
|
||||||
**********
|
**********
|
||||||
|
|
||||||
|
Pour lancer et surveiller gunicorn, nous allons utiliser supervisord, qui est un démon sous lunix permettant de lancer d'autre programmes.
|
||||||
|
|
||||||
|
On commence par l'installer:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
[program:simple]
|
$$$ aptitude install supervisor
|
||||||
command={{ virtualenv_path }}/bin/gunicorn simple.app:app -w {{ workers }} --log-file={{ appdir }}/logs/gunicorn.log --bind 127.0.0.1:{{ proxy_port }}
|
|
||||||
directory={{ appdir }}/
|
On crée ensuite une fichier de configuration, ``/etc/supervisor/conf.d/gwift.conf``, qui sera lu au démarage de supervisord.
|
||||||
environment=PATH="{{ virtualenv_path }}/bin"
|
|
||||||
user=nobody
|
.. code-block:: shell
|
||||||
autostart=true
|
|
||||||
autorestart=true
|
[program:gwift]
|
||||||
killasgroup = true
|
command = /webapps/gwift/gwift/bin/gunicorn_start ; Command to start
|
||||||
redirect_stdout=true
|
user = gwift ; User to run as
|
||||||
redirect_stderr=true
|
stdout_logfile = /webapps/gwift/gwift/logs/gunicorn_supervisor.log ; Where to write log messages
|
||||||
|
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8 ; Set UTF-8 as default encoding
|
||||||
|
autostart=true ; Start the program when supervisord is starting
|
||||||
|
autorestart=unexpected ; Restart program if it exited anormaly
|
||||||
|
redirect_stdout=true ; Redirect program output to the log file
|
||||||
|
redirect_stderr=true ; Redirect program error to the log file
|
||||||
|
|
||||||
|
On peut alors démarer supervisor:
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$$$ service supervisor start
|
||||||
|
|
||||||
|
On peut vérifier que notre site est bien en train de tourner, à l'aide de la commande ``supervisorctl``:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$$$ supervisorctl status gwift
|
||||||
|
gwift RUNNING pid 31983, uptime 0:01:00
|
||||||
|
|
||||||
|
Pour gérer le démarage ou l'arrêt de notre application, nous pouvons effectuer les commandes suivantes:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$$$ supervisorctl stop gwift
|
||||||
|
gwift: stopped
|
||||||
|
root@ks3353535:/etc/supervisor/conf.d# supervisorctl start gwift
|
||||||
|
gwift: started
|
||||||
|
root@ks3353535:/etc/supervisor/conf.d# supervisorctl restart gwift
|
||||||
|
gwift: stopped
|
||||||
|
gwift: started
|
||||||
|
|
|
@ -7,6 +7,12 @@ FrontEnd
|
||||||
|
|
||||||
Nginx est là pour agir en tant que front-end Web. A moins d'avoir configuré un mécanisme de cache type `Varnish <https://www.varnish-cache.org/>`_, c'est lui qui va recevoir la requête envoyée par l'utilisateur, gérer les fichiers et les informations statiques, et transmettre toute la partie dynamique vers Gunicorn.
|
Nginx est là pour agir en tant que front-end Web. A moins d'avoir configuré un mécanisme de cache type `Varnish <https://www.varnish-cache.org/>`_, c'est lui qui va recevoir la requête envoyée par l'utilisateur, gérer les fichiers et les informations statiques, et transmettre toute la partie dynamique vers Gunicorn.
|
||||||
|
|
||||||
|
Pour l'installer, on effectue la commande suivante:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$$$ aptitude install nginx
|
||||||
|
|
||||||
L'exemple ci-dessous se compose de plusieurs grandes parties: commune (par défaut), static, uploads, racine.
|
L'exemple ci-dessous se compose de plusieurs grandes parties: commune (par défaut), static, uploads, racine.
|
||||||
|
|
||||||
Partie commune
|
Partie commune
|
||||||
|
@ -18,7 +24,7 @@ Partie commune
|
||||||
* keepalive ??
|
* keepalive ??
|
||||||
* La compression Gzip doit-elle être activée ?
|
* La compression Gzip doit-elle être activée ?
|
||||||
* Avec quels paramètres ? [gzip_comp_level 7, gzip_proxied any]
|
* Avec quels paramètres ? [gzip_comp_level 7, gzip_proxied any]
|
||||||
* Quels types de fichiers GZip doit-il prendre en compte ? [
|
* Quels types de fichiers GZip doit-il prendre en compte ?
|
||||||
* Où les fichiers de logs doivent-ils être stockés ? [/logs/access.log & /logs/error.log]
|
* Où les fichiers de logs doivent-ils être stockés ? [/logs/access.log & /logs/error.log]
|
||||||
|
|
||||||
Fichiers statiques
|
Fichiers statiques
|
||||||
|
@ -36,13 +42,33 @@ Si vous souhaitez implémenter un mécanisme d'accès géré, supprimez cette pa
|
||||||
Racine
|
Racine
|
||||||
------
|
------
|
||||||
|
|
||||||
La partie racine de votre domaine ou sous-domaine fera simplement le *pass_through* vers l'instance Gunicorn. En gros, et comme déjà expliqué, Gunicorn tourne en local sur un port (eg. 8001); la requête qui arrive sur le port 80 ou 443 est prise en compte par NGinx, puis transmise à Gunicorn sur le port 8001. Ceci est complétement transparent pour l'utilisateur de notre application.
|
La partie racine de votre domaine ou sous-domaine fera simplement le *pass_through* vers l'instance Gunicorn via un socket unix. En gros, et comme déjà expliqué, Gunicorn tourne en local sur un port (eg. 8001); la requête qui arrive sur le port 80 ou 443 est prise en compte par NGinx, puis transmise à Gunicorn sur le port 8001. Ceci est complétement transparent pour l'utilisateur de notre application.
|
||||||
|
|
||||||
|
On délare un upstream pour préciser à nginx comment envoyer les requêtes à gunicorn:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
upstream gwift_server {
|
||||||
|
# fail_timeout=0 means we always retry an upstream even if it failed
|
||||||
|
# to return a good HTTP response (in case the Unicorn master nukes a
|
||||||
|
# single worker for timing out).
|
||||||
|
|
||||||
|
server unix:/directory/to/gunicorn.sock fail_timeout=0;
|
||||||
|
}
|
||||||
|
|
||||||
Au final
|
Au final
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
|
upstream gwift_server {
|
||||||
|
# fail_timeout=0 means we always retry an upstream even if it failed
|
||||||
|
# to return a good HTTP response (in case the Unicorn master nukes a
|
||||||
|
# single worker for timing out).
|
||||||
|
|
||||||
|
server unix:/directory/to/gunicorn.sock fail_timeout=0;
|
||||||
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
client_max_body_size 4G;
|
client_max_body_size 4G;
|
||||||
|
@ -58,7 +84,7 @@ Au final
|
||||||
error_log {{ cwd }}/logs/error.log;
|
error_log {{ cwd }}/logs/error.log;
|
||||||
|
|
||||||
location /static/ {
|
location /static/ {
|
||||||
alias {{ static_root }}/;
|
alias /webapps/gwift/gwift/static;
|
||||||
gzip on;
|
gzip on;
|
||||||
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js;
|
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js;
|
||||||
gzip_comp_level 9;
|
gzip_comp_level 9;
|
||||||
|
@ -80,10 +106,23 @@ Au final
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
|
|
||||||
proxy_pass http://127.0.0.1:{{ proxy_port }};
|
proxy_pass http://gwift_server;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dans notre cas, et à adbater suivant les besoins, nous avans créé le fichier ``/etc/nginx/sites-available/gwift`` et créé un lien symbolique dans ``/etc/nginx/sites-enabled/gwift`` pour l'activer. Ensuite, nous pouvons redémarer nginx:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$$$ service nginx restart
|
||||||
|
|
||||||
|
Et maintenant, si on se connecte à notre server sur www.sever_name.com/admin, nous obtenons le site suivant:
|
||||||
|
|
||||||
|
.. image:: production/admin_with_static.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Où l'on peut voir que la mise en forme est correcte, ce qui signifie que les fichiers statics sont bien servis par nginx.
|
||||||
|
|
||||||
Modules complémentaires
|
Modules complémentaires
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue