563 lines
20 KiB
TeX
563 lines
20 KiB
TeX
\chapter{Debian/Ubuntu}
|
||
|
||
\includegraphics{images/logos/debian-ubuntu.png}
|
||
|
||
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
|
||
\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}
|
||
|
||
Par soucis de simplification, quelques raccourcis seront pris:
|
||
|
||
\begin{itemize}
|
||
\item
|
||
La base de données sera hébergée sur la même machine que l'application
|
||
\item
|
||
Il n'y aura pas de \textit{load balancers}
|
||
\item
|
||
\ldots
|
||
\end{itemize}
|
||
|
||
\begin{tabular}{ll}
|
||
Avantages &
|
||
\textbf{Une grande accessibilité}: un VPS ne coûte que quelques euros par mois et permet de mettre un projet à disposition de plusieurs utilisateurs \\
|
||
\hline
|
||
Désavantages & Nécessite du temps et de l'investissement personnel \\
|
||
& Nécessite de suivre les évolutions et de prendre une petite journée par an pour appliquer les dernières mises à jour \\
|
||
& Nécessite de sécuriser soi-même son infrastructure (clés SSH, Fail2ban, \ldots) \\
|
||
& Le montage final ressemble un peu à de l'artisanat (bien qu'Ansible "professionalise" sérieusement le tout) \\
|
||
\hline
|
||
\end{tabular}
|
||
|
||
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}
|
||
|
||
Le processus de configuration à :
|
||
|
||
\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}
|
||
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}
|
||
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
|
||
make altinstall
|
||
\end{verbatim}
|
||
|
||
\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}
|
||
|
||
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),
|
||
\item
|
||
MariaDB (en natif depuis Django 3.0),
|
||
\item
|
||
PostgreSQL au travers de psycopg2 (en natif aussi),
|
||
\item
|
||
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.
|
||
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, que nous couvrirons ci-dessous.
|
||
|
||
\subsection{PostgreSQL}
|
||
|
||
Dans le cas de Debian ou Ubuntu, nous exécuterons la commande suivante:
|
||
|
||
\begin{verbatim}
|
||
apt install postgresql postgresql-contrib
|
||
\end{verbatim}
|
||
|
||
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
|
||
postgres@gwift:~$ createuser --interactive -P
|
||
Enter name of role to add: gwift_user
|
||
Enter password for new role:
|
||
Enter it again:
|
||
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
|
||
\end{verbatim}
|
||
|
||
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
|
||
postgres@gwift:~$ exit
|
||
logout
|
||
\end{verbatim}
|
||
|
||
\subsection{MariaDB}
|
||
|
||
Idem, installation, configuration, backup, tout ça.
|
||
A copier de grimboite, je suis sûr d’avoir 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}
|
||
|
||
\begin{verbatim}
|
||
su - gwift
|
||
cp /etc/skel/.bashrc .
|
||
cp /etc/skel/.bash_profile .
|
||
ssh-keygen
|
||
mkdir bin
|
||
mkdir .venvs
|
||
mkdir webapps
|
||
python3.6 -m venv .venvs/gwift
|
||
source .venvs/gwift/bin/activate
|
||
cd /home/gwift/webapps
|
||
git clone ...
|
||
\end{verbatim}
|
||
|
||
La clé SSH doit ensuite être renseignée au niveau du dépôt, afin de pouvoir y accéder.
|
||
A ce stade, on devrait déjà avoir quelque chose de fonctionnel en démarrant les commandes
|
||
suivantes :
|
||
|
||
\begin{verbatim}
|
||
# en tant qu'utilisateur 'gwift'
|
||
source .venvs/gwift/bin/activate
|
||
pip install -U pip
|
||
pip install -r requirements/base.txt
|
||
pip install gunicorn
|
||
cd webapps/gwift
|
||
gunicorn config.wsgi:application --bind localhost:3000 --settings
|
||
=config.settings_production
|
||
\end{verbatim}
|
||
|
||
|
||
\subsection{Configuration de l'application}
|
||
|
||
\begin{verbatim}
|
||
SECRET_KEY=<set your secret key here>
|
||
ALLOWED_HOSTS=*
|
||
STATIC_ROOT=/var/www/gwift/static
|
||
DATABASE=
|
||
\end{verbatim}
|
||
|
||
\begin{itemize}
|
||
\item
|
||
La variable \texttt{SECRET\_KEY} est notamment utilisée pour le
|
||
chiffrement des sessions.
|
||
\item
|
||
On fait confiance à django\_environ pour traduire la chaîne de
|
||
connexion à la base de données.
|
||
\end{itemize}
|
||
|
||
|
||
\subsection{Création des répertoires de logs}
|
||
|
||
\begin{verbatim}
|
||
mkdir -p /var/www/gwift/static
|
||
\end{verbatim}
|
||
|
||
\subsection{Socket}
|
||
|
||
Dans le fichier \texttt{/etc/tmpfiles.d/gwift.conf}:
|
||
|
||
\begin{verbatim}
|
||
D /var/run/webapps 0775 gwift gunicorn_sockets -
|
||
\end{verbatim}
|
||
|
||
Suivi de la création par systemd :
|
||
|
||
\begin{verbatim}
|
||
systemd-tmpfiles --create
|
||
\end{verbatim}
|
||
|
||
|
||
\subsection{Gunicorn}
|
||
|
||
\begin{verbatim}
|
||
#!/bin/bash
|
||
# defines settings for gunicorn
|
||
NAME="gwift"
|
||
DJANGODIR=/home/gwift/webapps/gwift
|
||
SOCKFILE=/var/run/webapps/gunicorn_gwift.sock
|
||
USER=gwift
|
||
GROUP=gunicorn_sockets
|
||
NUM_WORKERS=5
|
||
DJANGO_SETTINGS_MODULE=config.settings_production
|
||
DJANGO_WSGI_MODULE=config.wsgi
|
||
echo "Starting $NAME as `whoami`"
|
||
source /home/gwift/.venvs/gwift/bin/activate
|
||
cd $DJANGODIR
|
||
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
|
||
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
|
||
exec gunicorn ${DJANGO_WSGI_MODULE}:application \
|
||
--name $NAME \
|
||
--workers $NUM_WORKERS \
|
||
--user $USER \
|
||
--bind=unix:$SOCKFILE \
|
||
--log-level=debug \
|
||
--log-file=-
|
||
\end{verbatim}
|
||
|
||
\section{Composants périphériques}
|
||
|
||
\subsection{Supervsion, keepalive et autoreload}
|
||
|
||
Pour la supervision, on passe par Supervisor.
|
||
Il existe d'autres superviseurs,
|
||
|
||
\begin{verbatim}
|
||
yum install supervisor -y
|
||
\end{verbatim}
|
||
|
||
On crée ensuite le fichier \texttt{/etc/supervisord.d/gwift.ini}:
|
||
|
||
\begin{verbatim}
|
||
[program:gwift]
|
||
command=/home/gwift/bin/start_gunicorn.sh
|
||
user=gwift
|
||
stdout_logfile=/var/log/gwift/gwift.log
|
||
autostart=true
|
||
autorestart=unexpected
|
||
redirect_stdout=true
|
||
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 :
|
||
|
||
\begin{verbatim}
|
||
$ mkdir /var/log/gwift
|
||
$ chown gwift:nagios /var/log/gwift
|
||
$ systemctl enable supervisord
|
||
$ systemctl start supervisord.service
|
||
$ systemctl status supervisord.service
|
||
supervisord.service - Process Monitoring and Control Daemon
|
||
Loaded: loaded (/usr/lib/systemd/system/supervisord.service; enabled;
|
||
vendor preset: disabled)
|
||
Active: active (running) since Tue 2019-12-24 10:08:09 CET; 10s ago
|
||
Process: 2304 ExecStart=/usr/bin/supervisord -c /etc/supervisord.conf (code
|
||
=exited, status=0/SUCCESS)
|
||
Main PID: 2310 (supervisord)
|
||
CGroup: /system.slice/supervisord.service
|
||
- 2310 /usr/bin/python /usr/bin/supervisord -c
|
||
/etc/supervisord.conf
|
||
- 2313 /home/gwift/.venvs/gwift/bin/python3
|
||
/home/gwift/.venvs/gwift/bin/gunicorn config.wsgi:...
|
||
- 2317 /home/gwift/.venvs/gwift/bin/python3
|
||
/home/gwift/.venvs/gwift/bin/gunicorn config.wsgi:...
|
||
- 2318 /home/gwift/.venvs/gwift/bin/python3
|
||
/home/gwift/.venvs/gwift/bin/gunicorn config.wsgi:...
|
||
- 2321 /home/gwift/.venvs/gwift/bin/python3
|
||
/home/gwift/.venvs/gwift/bin/gunicorn config.wsgi:...
|
||
- 2322 /home/gwift/.venvs/gwift/bin/python3
|
||
/home/gwift/.venvs/gwift/bin/gunicorn config.wsgi:...
|
||
- 2323 /home/gwift/.venvs/gwift/bin/python3
|
||
/home/gwift/.venvs/gwift/bin/gunicorn config.wsgi:...
|
||
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} :
|
||
|
||
\begin{verbatim}
|
||
supervisorctl status gwift
|
||
gwift RUNNING pid 31983, uptime 0:01:00
|
||
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
|
||
\end{verbatim}
|
||
|
||
\subsection{Firewall}
|
||
|
||
\begin{verbatim}
|
||
et 443 (HTTPS).
|
||
\end{verbatim}
|
||
|
||
\begin{verbatim}
|
||
firewall-cmd --permanent --zone=public --add-service=http
|
||
firewall-cmd --permanent --zone=public --add-service=https
|
||
firewall-cmd --reload
|
||
\end{verbatim}
|
||
|
||
\begin{itemize}
|
||
\item
|
||
On ouvre le port 80, uniquement pour autoriser une connexion HTTP,
|
||
mais qui sera immédiatement redirigée vers HTTPS
|
||
\item
|
||
Et le port 443 (forcément).
|
||
\end{itemize}
|
||
|
||
|
||
\subsection{Unattented-upgrades}
|
||
|
||
|
||
\subsection{Healthchecks.io}
|
||
|
||
|
||
\subsection{Reverse proxy}
|
||
|
||
\begin{verbatim}
|
||
yum install nginx -y
|
||
usermod -a -G gunicorn_sockets nginx
|
||
\end{verbatim}
|
||
|
||
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}
|
||
|
||
On configure ensuite le fichier \texttt{/etc/nginx/conf.d/gwift.conf}:
|
||
|
||
\begin{verbatim}
|
||
upstream gwift_app {
|
||
server unix:/var/run/webapps/gunicorn_gwift.sock fail_timeout=0;
|
||
}
|
||
|
||
server {
|
||
listen 80;
|
||
server_name <server_name>;
|
||
root /var/www/gwift;
|
||
error_log /var/log/nginx/gwift_error.log;
|
||
access_log /var/log/nginx/gwift_access.log;
|
||
|
||
client_max_body_size 4G;
|
||
keepalive_timeout 5;
|
||
|
||
gzip on;
|
||
gzip_comp_level 7;
|
||
gzip_proxied any;
|
||
gzip_types gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
|
||
|
||
|
||
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;
|
||
}
|
||
|
||
location / {
|
||
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;
|
||
|
||
gzip on;
|
||
gzip_comp_level 7;
|
||
gzip_proxied any;
|
||
gzip_types gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
|
||
|
||
|
||
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;
|
||
}
|
||
|
||
location / {
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
\end{verbatim}
|
||
|
||
\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
|
||
aucune intelligence soit directement servis par Nginx. Cela évite
|
||
d'avoir un processus Python (relativement lent) qui doive être
|
||
instancié pour servir un simple fichier statique.
|
||
\item
|
||
Afin d'éviter que Django ne reçoive uniquement des requêtes provenant
|
||
de 127.0.0.1
|
||
\end{itemize}
|
||
|
||
\subsubsection{Let's Encrypt}
|
||
|
||
Certificats externes + communication par socket interne.
|
||
|
||
\section{Mise à jour}
|
||
|
||
\begin{verbatim}
|
||
u - <user>
|
||
source ~/.venvs/<app>/bin/activate
|
||
cd ~/webapps/<app>
|
||
git fetch
|
||
git checkout vX.Y.Z
|
||
pip install -U requirements/prod.txt
|
||
python manage.py migrate
|
||
python manage.py collectstatic
|
||
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}
|
||
|
||
\subsection{Logrotate}
|
||
|
||
\begin{verbatim}
|
||
/var/log/gwift/* {
|
||
weekly
|
||
rotate 3
|
||
size 10M
|
||
compress
|
||
delaycompress
|
||
}
|
||
\end{verbatim}
|
||
|
||
Puis on démarre logrotate avec \texttt{logrotate -d /etc/logrotate.d/gwift} pour vérifier que cela fonctionne correctement.
|
||
|
||
\subsection{Sauvegardes}
|
||
|
||
Les sauvegardes ont été configurées avec borg : \texttt{yum\ install\ borgbackup}.
|
||
|
||
C'est l'utilisateur gwift qui s'en occupe.
|
||
|
||
\begin{verbatim}
|
||
mkdir -p /home/gwift/borg-backups/
|
||
cd /home/gwift/borg-backups/
|
||
borg init gwift.borg -e=none
|
||
borg create gwift.borg::{now} ~/bin ~/webapps
|
||
\end{verbatim}
|
||
|
||
Et dans le fichier crontab :
|
||
|
||
\begin{verbatim}
|
||
0 23 * * * /home/gwift/bin/backup.sh
|
||
\end{verbatim}
|
||
|
||
\subsection{Conclusions}
|
||
|
||
Ce type de déploiement est complexe lors d'une première fois, mais est relativement rapide par la suite.
|
||
Comptez une heure ou deux lorsque vous aurez pris l'habitude.
|
||
|
||
\section{Ansible}
|
||
|
||
On peut aussi passer par fabric, ansible, chef ou puppet.
|