Work on Debian/Ubuntu deployments methods
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Fred Pauchet 2022-05-11 21:36:42 +02:00
parent ad625a1b40
commit f5ae5cdac4
3 changed files with 175 additions and 126 deletions

View File

@ -1,112 +1,162 @@
\chapter{Debian}
\chapter{Debian/Ubuntu}
La première étape pour la configuration de notre hôte consiste à définir les utilisateurs et groupes de droits.
Il est faut absolument éviter de faire tourner une application en tant qu'utilisateur \textbf{root}, car la moindre faille pourrait avoir des conséquences catastrophiques.
\includegraphics{images/logos/debian-ubuntu.png}
Une fois que ces utilisateurs seront configurés, nous pourrons passer à l'étape de configuration, qui consistera à:
Le déploiement sur Debian est présenté dans le cadre d'un déploiment on-premises ou IaaS.
Nous verrons trois types de déploiements:
\begin{enumerate}
\item
Déployer les sources
\item
Démarrer un serveur implémentant une interface WSGI (\textbf{Web Server Gateway Interface}), qui sera chargé de créer autant de petits lutins travailleurs que nous le désirerons.
\item
Démarrer un superviseur, qui se chargera de veiller à la bonne santé de nos petits travailleurs, et en créer de nouveaux s'il le juge nécessaire
\item
Configurer un proxy inverse, qui s'occupera d'envoyer les requêtes d'un utilisateur externe à la machine hôte vers notre serveur applicatif, qui la communiquera à l'un des travailleurs.
\item
\textbf{Manuel}, en exécutant chaque étape une par une.
Ce type de déploiement est intéressant à réaliser au moins une fois, afin de comprendre les différents composants utilisés.
\item
\textbf{Semi-automatisé}, \textit{via} Ansible.
Cette manière se base sur ce qui aura été présenté à la première section, tout en faciliant certains aspects.
Plusieurs concepts devront cependant être abordés au préalable, ce qui pourra paraitre rebutant en première instance.
\item
\textbf{Automatisé}, qui reste un déploiement \textit{on-premise}, mais qui prépare déjà le chemin pour les containeurs.
Ce mode de déploiement-ci garde quelques contraintes, mais présente également quelques avantages.
\end{enumerate}
La machine hôte peut être louée chez Digital Ocean, Scaleway, OVH, Vultr, \ldots~
Il existe des dizaines d'hébergements typés VPS (\textbf{Virtual Private Server}).
A vous de choisir celui qui vous convient \footnote{Personnellement, j'ai un petit faible pour Hetzner Cloud}.
\begin{verbatim}
apt update
groupadd --system webapps
groupadd --system gunicorn_sockets
useradd --system --gid webapps --shell /bin/bash --home /home/gwift gwift
mkdir -p /home/gwift
chown gwift:webapps /home/gwift
\end{verbatim}
Par soucis de simplification, quelques raccourcis seront pris:
\begin{itemize}
\item
On ajoute un groupe intitulé \texttt{webapps}
La base de données sera hébergée sur la même machine que l'application
\item
On crée un groupe pour les communications via sockets
Il n'y aura pas de \textit{load balancers}
\item
On crée notre utilisateur applicatif; ses applications seront placées dans le répertoire \texttt{/home/gwift}
\item
On crée le répertoire home/gwift
\item
On donne les droits sur le répertoire /home/gwift
\ldots
\end{itemize}
\section{Dépendances systèmes}
Le choix de ces deux systèmes d'exploitation s'explique par une grande liberté, une bonne compatibilité avec différentes architectures, une bonne stabilité générale et une documentation suffisante:
\begin{itemize}
\item
Debian fonctionne sur un mécanisme de \href{https://www.debian.org/releases/}{canaux}: stable, testing et unstable.
Globalement, en choisissant le premier canal, vous aurez des paquets \textit{très} stables et des procédures de sauts de versions correctement documentées.
\item
Ubuntu fonctionne grâce à des versions \textit{Long-Term Support} \index{LTS}, supportées durant cinq ans et sortant tous les deux ans.
En pratique, en installant une version 22.04, celle-ci sera supportée jusqu'en avril 2027, ce qui vous laissera le temps de planifier le \textit{downtime}.
Entre chacun de ces versions LTS, des versions intermédiaires sont mises à dispositions tous les six mois, mais ne sont supportées que durant 9 mois.
Pour cette raison, leur utilisation sur un serveur est fortement déconseillée.
\end{itemize}
La version 3.6 de Python se trouve dans les dépôts officiels de CentOS. Si vous souhaitez utiliser une version ultérieure, il suffit de l'installer en parallèle de la version officiellement supportée par votre distribution.
Le processus de configuration à :
Pour CentOS, vous avez donc deux possibilités :
\begin{enumerate}
\item
Initialiser le système
\item
Déployer ou mettre les sources à disposition
\item
Démarrer un service implémentant une interface WSGI (\textbf{Web Server Gateway Interface}) \index{WSGI}, qui sera chargé de créer autant de petits lutins travailleurs que nous le désirerons (\textit{Gunicorn})
\item
Démarrer un superviseur, qui se chargera de veiller à la bonne santé de nos petits travailleurs, et en créer de nouveaux s'il le juge nécessaire (\textit{Supervisord})
\item
Configurer un proxy inverse, qui s'occupera d'envoyer les requêtes d'un utilisateur externe à la machine hôte vers notre serveur applicatif, qui la communiquera à l'un des travailleurs, pour exécution (\textit{Nginx, Apache, \ldots}).
\end{enumerate}
La machine hôte peut être louée chez Digital Ocean, Scaleway, OVH, Vultr, \ldots
Il existe des dizaines d'hébergements typés VPS (\textbf{Virtual Private Server}).
A vous de choisir celui qui vous convient \footnote{Personnellement, j'ai un petit faible pour Hetzner Cloud}.
\section{Initialisation du serveur}
Nous allons commencer par initialiser le système, configurer les droits utilisateurs, installer une version de l'interpréteur Python et configurer les dépendances principales.
\subsection{Configuration des droits utilisateurs}
La toute première étape pour la configuration de notre hôte consiste à définir les utilisateurs et groupes de droits.
Il est faut absolument éviter de faire tourner une application en tant qu'utilisateur \textbf{root}, car la moindre faille pourrait avoir des conséquences catastrophiques.
Dans l'ordre, nous devons réaliser les étapes suivantes :
\begin{itemize}
\item
Ajouter un nouveau groupe système, intitulé \texttt{webapps}, qui servira à partager des fichiers entre les différents composants.
L'utilisateur qui fait tourner le proxy inverse sera également ajouté à ce groupe, un peu plus tard.
\item
Ajouter un groupe qui servira à gérer la communications \textit{via sockets}, qui consiste en un ensemble normalisé de fonctions de communication entre processus \footnote{\url{https://fr.wikipedia.org/wiki/Berkeley_sockets}}
\item
Créer un utilisateur application, afin de le conserver isolé du reste du système.
Ceci est un principe de sécurité fondamental: si votre application comprend une faille qui permettrait (par exemple) de supprimer un fichier $\lambda$ dont le chemin serait passé en paramètre passer un chemin de fichier en paramètre.
Le fait d'exécuter notre application sous son propre utilisateur empêche au moins que des fichiers hors de son périmètre ne soit supprimés.
\item
Les applications seront placées dans le répertoire \texttt{/home/gwift}
\item
Octroi des droits de notre utilisateur \texttt{gwift} sur son propre répertoire \texttt{/home/gwift}.
\end{itemize}
Pour résumer, l'ensemble de ces commandes nous donne ceci:
\begin{enumerate}
\item \texttt{groupadd --system webapps}
\item \texttt{groupadd --system gunicorn\_sockets}
\item \texttt{useradd --system --gid webapps --shell /bin/bash --home /home/gwift gwift}
\item \texttt{mkdir -p /home/gwift}
\item \texttt{chown gwift:webapps /home/gwift}
\end{enumerate}
\subsection{Dépendances systèmes}
Debian et Ubuntu comprennent nativement une version récente de Python 3.
Mettez vos dépôts à jour et installez la avec les commandes suivantes:
\begin{verbatim}
yum install python36 -y
apt update
apt install python3
\end{verbatim}
Si vous souhaitez utiliser une version ultérieure, il suffit de l'installer \textbf{en parallèle} de la version officiellement supportée par votre distribution.
Ou passer par une installation alternative:
\begin{verbatim}
sudo yum -y groupinstall "Development Tools"
sudo yum -y install openssl-devel bzip2-devel libffi-devel
apt install openssl-devel bzip2-devel libffi-devel
wget https://www.python.org/ftp/python/3.8.2/Python-3.8.2.tgz
cd Python-3.8*/
./configure --enable-optimizations
sudo make altinstall
make altinstall
\end{verbatim}
\begin{itemize}
\item
\textbf{Attention !} Le paramètre \texttt{altinstall} est primordial.
Sans lui, vous écraserez l'interpréteur initialement supporté par la distribution, et cela pourrait avoir des effets de bord non souhaités.
\end{itemize}
\textbf{Attention !} Le paramètre \texttt{altinstall} est primordial.
Sans lui, vous écraserez l'interpréteur initialement supporté par la distribution, et cela pourrait avoir des effets de bord non souhaités.
\subsection{Base de données}
\section{Base de données}
On l'a déjà vu, Django se base sur un pattern type \href{https://www.martinfowler.com/eaaCatalog/activeRecord.html}{ActiveRecords} pour la gestion de la persistance des données et supporte les principaux moteurs de bases de données connus :
On l'a déjà vu, Django se base sur un pattern type \href{https://www.martinfowler.com/eaaCatalog/activeRecord.html}{ActiveRecords} pour la gestion de la persistance des données et supporte les principaux moteurs de bases de données relationnelles connus :
\begin{itemize}
\item
SQLite (en natif, mais Django 3.0 exige une version du moteur supérieure ou égale à la 3.8)
SQLite (en natif),
\item
MariaDB (en natif depuis Django 3.0),
\item
PostgreSQL au travers de psycopg2 (en natif aussi),
\item
Microsoft SQLServer grâce aux drivers {[}\ldots\hspace{0pt}à compléter{]}
Microsoft SQLServer grâce aux drivers \href{https://github.com/microsoft/mssql-django}{Microsoft}
\item
Oracle via \href{https://oracle.github.io/python-cx_Oracle/}{cx\_Oracle}.
\end{itemize}
Chaque pilote doit être utilisé précautionneusement ! Chaque version de Django n'est pas toujours compatible avec chacune des versions des pilotes, et chaque moteur de base de données nécessite parfois une
version spécifique du pilote.
Chaque pilote doit être utilisé précautionneusement !
Chaque version de Django n'est pas toujours compatible avec chacune des versions des pilotes, et chaque moteur de base de données nécessite parfois une version spécifique du pilote.
Par ce fait, vous serez parfois bloqué sur une version de Django, simplement parce que votre serveur de base de données se trouvera dans une version spécifique (eg. Django 2.3 à cause d'un Oracle 12.1).
Ci-dessous, quelques procédures d'installation pour mettre un serveur à disposition.
Les deux plus simples seront MariaDB et PostgreSQL, qu'on couvrira ci-dessous.
Oracle et Microsoft SQLServer se trouveront en annexes.
Les deux plus simples seront MariaDB et PostgreSQL, que nous couvrirons ci-dessous.
\subsection{PostgreSQL}
On commence par installer PostgreSQL.
Dans le cas de debian, on exécute la commande suivante:
Dans le cas de Debian ou Ubuntu, nous exécuterons la commande suivante:
\begin{verbatim}
# aptitude install postgresql postgresql-contrib
apt install postgresql postgresql-contrib
\end{verbatim}
Ensuite, on crée un utilisateur pour la DB:
Ensuite, nous créerons un utilisateur pour la base de données de notre application.
De la même manière que pour l'utilisateur système, il n'est pas acceptable que la chaine de connexion au moteur de base de données soient associées à un compte administrateur:
\begin{verbatim}
# su - postgres
@ -117,10 +167,9 @@ Ensuite, on crée un utilisateur pour la DB:
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
postgres@gwift:~$
\end{verbatim}
Finalement, on peut créer la DB:
Finalement, nous pouvons effectivemment créer la base de données qui hébergera les données:
\begin{verbatim}
postgres@gwift:~$ createdb --owner gwift_user gwift
@ -133,6 +182,19 @@ Finalement, on peut créer la DB:
Idem, installation, configuration, backup, tout ça.
A copier de grimboite, je suis sûr davoir des notes là-dessus.
\subsection{Comparatif PostgreSQL/MariaDB}
\begin{tabular}{lll}
Etape & PostgreSQL & MariaDB \\
\hline
Installation & \texttt{apt install postgresql postgresql-contrib} & \texttt{apt install maria-db} \\
\hline
Création de l'utilisateur & & \\
\hline
Création de la base de données & & \\
\hline
Dump & & \\
\end{tabular}
\section{Préparation de l'environment utilisateur}
@ -166,7 +228,7 @@ suivantes :
\end{verbatim}
\section{Configuration de l'application}
\subsection{Configuration de l'application}
\begin{verbatim}
SECRET_KEY=<set your secret key here>
@ -185,15 +247,14 @@ suivantes :
\end{itemize}
\section{Création des répertoires de logs}
\subsection{Création des répertoires de logs}
\begin{verbatim}
mkdir -p /var/www/gwift/static
\end{verbatim}
\section{Socket}
\subsection{Socket}
\section{Socket}
Dans le fichier \texttt{/etc/tmpfiles.d/gwift.conf}:
\begin{verbatim}
@ -207,7 +268,7 @@ Suivi de la création par systemd :
\end{verbatim}
\section{Gunicorn}
\subsection{Gunicorn}
\begin{verbatim}
#!/bin/bash
@ -234,8 +295,9 @@ Suivi de la création par systemd :
--log-file=-
\end{verbatim}
\section{Composants périphériques}
\section{Supervsion, keepalive et autoreload}
\subsection{Supervsion, keepalive et autoreload}
Pour la supervision, on passe par Supervisor.
Il existe d'autres superviseurs,
@ -257,8 +319,7 @@ On crée ensuite le fichier \texttt{/etc/supervisord.d/gwift.ini}:
redirect_stderr=true
\end{verbatim}
Et on crée les répertoires de logs, on démarre supervisord et on vérifie
qu'il tourne correctement :
Et on crée les répertoires de logs, on démarre supervisord et on vérifie qu'il tourne correctement :
\begin{verbatim}
$ mkdir /var/log/gwift
@ -291,9 +352,7 @@ qu'il tourne correctement :
ls /var/run/webapps
\end{verbatim}
On peut aussi vérifier que l'application est en train de tourner, à
l'aide de la commande \texttt{supervisorctl} :
On peut aussi vérifier que l'application est en train de tourner, à l'aide de la commande \texttt{supervisorctl} :
\begin{verbatim}
supervisorctl status gwift
@ -307,8 +366,8 @@ l'aide de la commande \texttt{supervisorctl} :
gwift: started
\end{verbatim}
\subsection{Firewall}
\section{Firewall}
\begin{verbatim}
et 443 (HTTPS).
\end{verbatim}
@ -328,7 +387,8 @@ l'aide de la commande \texttt{supervisorctl} :
\end{itemize}
\section{Reverse proxy}
\subsection{Reverse proxy}
\begin{verbatim}
yum install nginx -y
usermod -a -G gunicorn_sockets nginx
@ -339,16 +399,16 @@ On configure ensuite le fichier \texttt{/etc/nginx/conf.d/gwift.conf}:
\begin{verbatim}
yum install nginx -y
usermod -a -G gunicorn_sockets nginx
\end{verbatim}
\end{verbatim}
On configure ensuite le fichier \texttt{/etc/nginx/conf.d/gwift.conf}:
On configure ensuite le fichier \texttt{/etc/nginx/conf.d/gwift.conf}:
\begin{verbatim}
upstream gwift_app {
\begin{verbatim}
upstream gwift_app {
server unix:/var/run/webapps/gunicorn_gwift.sock fail_timeout=0;
}
}
server {
server {
listen 80;
server_name <server_name>;
root /var/www/gwift;
@ -374,9 +434,9 @@ On configure ensuite le fichier \texttt{/etc/nginx/conf.d/gwift.conf}:
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
client_max_body_size 4G;
keepalive_timeout 5;
@ -388,26 +448,26 @@ On configure ensuite le fichier \texttt{/etc/nginx/conf.d/gwift.conf}:
location /static/ {
access_log off;
expires 30d;
add_header Pragma public;
add_header Cache-Control "public";
add_header Vary "Accept-Encoding";
try_files $uri $uri/ =404;
access_log off;
expires 30d;
add_header Pragma public;
add_header Cache-Control "public";
add_header Vary "Accept-Encoding";
try_files $uri $uri/ =404;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://gwift_app;
proxy_pass http://gwift_app;
}
}
}
\end{verbatim}
}
\end{verbatim}
\begin{itemize}
\begin{itemize}
\item
Ce répertoire sera complété par la commande \texttt{collectstatic} que
l'on verra plus tard. L'objectif est que les fichiers ne demandant
@ -417,9 +477,10 @@ On configure ensuite le fichier \texttt{/etc/nginx/conf.d/gwift.conf}:
\item
Afin d'éviter que Django ne reçoive uniquement des requêtes provenant
de 127.0.0.1
\end{itemize}
\end{itemize}
\section{Mise à jour}
\begin{verbatim}
u - <user>
source ~/.venvs/<app>/bin/activate
@ -432,13 +493,12 @@ On configure ensuite le fichier \texttt{/etc/nginx/conf.d/gwift.conf}:
kill -HUP `ps -C gunicorn fch -o pid | head -n 1`
\end{verbatim}
\begin{itemize}
\item
\url{https://stackoverflow.com/questions/26902930/how-do-i-restart-gunicorn-hup-i-dont-know-masterpid-or-location-of-pid-file}
\end{itemize}
\section{Logrotate}
\subsection{Logrotate}
\begin{verbatim}
/var/log/gwift/* {
@ -450,10 +510,10 @@ On configure ensuite le fichier \texttt{/etc/nginx/conf.d/gwift.conf}:
}
\end{verbatim}
Puis on démarre logrotate avec \# logrotate -d /etc/logrotate.d/gwift pour vérifier que cela fonctionne correctement.
Puis on démarre logrotate avec \texttt{logrotate -d /etc/logrotate.d/gwift} pour vérifier que cela fonctionne correctement.
\subsection{Sauvegardes}
\section{Sauvegardes}
Les sauvegardes ont été configurées avec borg : \texttt{yum\ install\ borgbackup}.
C'est l'utilisateur gwift qui s'en occupe.
@ -466,46 +526,35 @@ C'est l'utilisateur gwift qui s'en occupe.
\end{verbatim}
Et dans le fichier crontab :
\begin{verbatim}
0 23 * * * /home/gwift/bin/backup.sh
\end{verbatim}
\section{Ansible}
On peut aussi passer par fabric, ansible, chef ou puppet.
\section{Docker-Compose}
(c/c Ced' - 2020-01-24)
Ça y est, j'ai fait un test sur mon portable avec docker et cookiecutter
pour django.
Ça y est, j'ai fait un test sur mon portable avec docker et cookiecutter pour django.
D'abords, après avoir installer docker-compose et les dépendances sous
debian, tu dois t'ajouter dans le groupe docker, sinon il faut être root
pour utiliser docker. Ensuite, j'ai relancé mon pc car juste relancé un
shell n'a pas suffit pour que je puisse utiliser docker avec mon compte.
D'abords, après avoir installer docker-compose et les dépendances sous debian, tu dois t'ajouter dans le groupe docker, sinon il faut être root pour utiliser docker. Ensuite, j'ai relancé mon pc car juste relancé un shell n'a pas suffit pour que je puisse utiliser docker avec mon compte.
Bon après c'est facile, un petit virtualenv pour cookiecutter, suivit
d'une installation du template django. Et puis j'ai suivi sans t
\url{https://cookiecutter-django.readthedocs.io/en/latest/developing-locally-docker.html}
Bon après c'est facile, un petit virtualenv pour cookiecutter, suivi d'une installation du template django.
Et puis j'ai suivi \url{https://cookiecutter-django.readthedocs.io/en/latest/developing-locally-docker.html}
Alors, il télécharge les images, fait un petit update, installe les
dépendances de dev, install les requirement pip \ldots\hspace{0pt}
Alors, il télécharge les images, fait un petit update, installe les dépendances de dev, install les requirement pip \ldots
Du coup, ça prend vite de la place: image.png
L'image de base python passe de 179 à 740 MB. Et là j'en ai pour presque
1,5 GB d'un coup.
L'image de base python passe de 179 à 740 MB. Et là j'en ai pour presque 1,5 GB d'un coup.
Mais par contre, j'ai un python 3.7 direct et postgres 10 sans rien
faire ou presque.
Mais par contre, j'ai un python 3.7 direct et postgres 10 sans rien faire ou presque.
La partie ci-dessous a été reprise telle quelle de
\href{https://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html}{la
La partie ci-dessous a été reprise telle quelle de \href{https://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html}{la
documentation de cookie-cutter-django}.
le serveur de déploiement ne doit avoir qu'un accès en lecture au dépôt
source.
On peut aussi passer par fabric, ansible, chef ou puppet.
le serveur de déploiement ne doit avoir qu'un accès en lecture au dépôt source.

View File

@ -57,7 +57,7 @@
\include{parts/deployment.tex}
\include{chapters/infrastructure.tex}
\include{chapters/deployments.tex}
\include{chapters/debian.tex}
\include{chapters/heroku.tex}
\include{chapters/kubernetes.tex}
\include{chapters/deployment-tools.tex}

View File

@ -91,10 +91,10 @@ Nous allons détailler ci-dessous trois méthodes de déploiement:
\begin{itemize}
\item
Sur une machine hôte, en embarquant tous les composants sur un même serveur. Ce ne sera pas idéal, puisqu'il ne sera pas possible de configurer un \emph{load balancer}, de routeur plusieurs basées de données, mais ce sera le premier cas de figure.
\item Dans des containers, avec Docker-Compose.
Sur une machine hôte, en embarquant tous les composants sur un même serveur.
Ce ne sera pas idéal, puisqu'il ne sera pas possible de configurer un \emph{load balancer}, de routeur plusieurs basées de données, mais ce sera le premier cas de figure.
\item
Dans des containers, avec Docker-Compose (et à nouveau sur un seul serveur)
\item
Sur une \textbf{Plateforme en tant que Service} (ou plus simplement, \textbf{PaaSPaaS}), pour faire abstraction de toute la couche de configuration du serveur.
\end{itemize}