files | ||
group_vars | ||
roles | ||
.gitignore | ||
afpy.org.yml | ||
alain.yml | ||
ansible.cfg | ||
autoconfig.yml | ||
backup.yml | ||
bye_bbb.yml | ||
discord-irc-sync.yml | ||
discuss.yml | ||
dl.yml | ||
gitea.yml | ||
http-to-xmpp.yml | ||
inventory | ||
logs.afpy.org.yml | ||
makemake.yml | ||
munin.yml | ||
pafpy.yml | ||
ponyconf.yml | ||
pretalx.yml | ||
pycon.fr.yml | ||
pydocteur.afpy.org.yml | ||
README.md | ||
requirements.yml | ||
Vagrantfile | ||
woodpecker-agent.yml | ||
woodpecker.yml |
Playbooks Ansible de l’AFPy
On découpe nos playbooks Ansible par rôles :
pycon.yml
: Pour les pycon.frbackup.yml
: Configure rsnapshot pour sauvegarder nos serveurs.- ...
En partant de là, on peut utiliser les commandes suivantes :
Après avoir cloné ce repo, installé Ansible (dans un venv), installez les roles nécessaires via :
- ansible-galaxy install julienpalard.nginx
Récupérez le secret dans afpy/pass:
git clone https://github.com/AFPy/pass/
PASSWORD_STORE_DIR=pass/infra pass Ansible-Vault > ~/.ansible-afpy-vault
Puis pour jouer les playbooks :
- Pour tout relancer :
ansible-parallel *.yml
- Pour configurer les PyCons :
ansible-playbook pycons.yml
Faire, ne pas faire
Faire : Configurer les machines :
apt install
,- fichiers de configuration,
- créer les utilisateurs,
- éventuellement un premier
git clone
pour que ça marche si c’est un site statique.
Ne pas faire :
- Deployer. En dehors de l’éventuel premier git clone, c’est le rôle de la CI (Github Actions, ...), pas de nos playbooks.
Servers
La distinction services/serveurs :
- Un serveur contient un nombre dans son nom :
- deb2.afpy.org,
- gitea1.afpy.org,
- woodpecker1.afpy.org,
- …
- Un service ne contient pas de chiffre dans son nom :
- www.afpy.org,
- git.afpy.org,
- woodpecker.afpy.org,
- …
Une machine peut contenir un ou plusieurs services (un s’il est "gros", plusieurs s’ils sont « néglibeables » (comme un site statique).
deb2.afpy.org
♥ Machine sponsorisée par Gandi ♥
C’est un VPS V-R4 2 CPUs · 4 GB RAM
.
Elle héberge surtout des sites statiques, mais pas que :
- https://www.afpy.org (source).
- https://*.pycon.fr/* (que des sites statiuques).
- Alain le bot IRC du canal #afpy (source).
- La gate IRC—Discord (un discord-irc-sync).
- https://dl.afpy.org: un directory listing nginx des vidéos de nos conférences.
- https://logs.afpy.org: Les logs du salon IRC #afpy (source).
- https://munin.afpy.org
backup1.afpy.org
♥ Machine sponsorisée par Gandi ♥
C’est un « Gandi Cloud V5 » à Bissen au Luxembourg avec 512MB de RAM
et 512GB de disque, il sauvegarde (via rsnapshot) les autres machines
(voir backup.yml
).
Dernière vérification de backup1.afpy.org
le 4 janvier 2024 via :
ssh root@backup1.afpy.org sh check-afpy.sh
Dernière vérification de silence
(chez Julien) le 4 janvier 2024 via :
ssh root@silence sh /srv/backups/check-afpy.sh
Le script check-afpy.sh
.
check-afpy.sh
.#!/bin/sh
BASE=/srv/backups/rsnapshot_afpy
for machine in deb git discuss
do
echo "# $machine.afpy.org"
echo
rsnapshot-diff -H "$BASE/weekly.0/$machine.afpy.org" "$BASE/daily.0/$machine.afpy.org"
echo
echo
done
echo '# discuss.afpy.org'
echo
ls -lahtr $BASE/daily.0/discuss.afpy.org/var/discourse/shared/standalone/backups/default/ | sed 's/^/ /'
echo
echo
echo '# logs.afpy.org'
echo
ls -lahtr $BASE/daily.0/deb.afpy.org/var/www/logs.afpy.org/ | tail | sed 's/^/ /'
echo
echo
echo '# git.afpy.org'
echo
ls -lahtr $BASE/daily.0/git.afpy.org/var/backups/gitea/ | sed 's/^/ /'
gitea1.afpy.org
♥ Machine sponsorisée par Gandi ♥
C’est un « Gandi VPS V-R1 » 1 CPU, 1 GB RAM, 25 GB disk.
C’est la machine derrière git.afpy.org
, déployée via gitea.yml
.
Mise à jour
Pour faire une mise à jour, se connecter en root à la machine puis exécuter :
systemctl start gitea-backup.service
backupopts="-c /etc/gitea/app.ini --file /var/backups/gitea/before-upgrade.zip" gitea-upgrade.sh
(Oui, je sais, ça fait deux sauvegardes, une par nous (avec un
pg_dump
), une par le script de gitea dont le SQL n’est pas aussi
propre que celui généré par pg_dump
).
Une fois la mise à jour terminée, il est de bon goût de mettre à jour
gitea_version
dans gitea.yml
.
Sauvegardes
Les données sont sauvegardées automatiquement via rsync sur
backup1.afpy.org
(voir backup.yml
).
Côté VPS Gandi on a aussi un snapshot du volume tous les jours.
Restaurer une sauvegarde
Procédure testée le 2022-11-29 par mdk.
Voici la procédure pour restaurer une sauvegarde sur une nouvelle machine « from scratch ».
Commander une nouvelle machine
Typiquement chez Gandi une V-R1: 1 CPU · 1 GB RAM
, avec une Debian
11, n’oubliez pas d’y mettre une clé SSH.
Nommer la machine
Typiquement gitea2.afpy.org
, configurer les DNS, en profiter pour
réduire le TTL de git.afpy.org puisqu’il faudra le changer à la fin.
Autoriser à se ssh en root
ssh debian@giteatest.afpy.org sudo cp /home/debian/.ssh/authorized_keys /root/.ssh/
Ajouter la machine dans l’inventaire Ansible
Ça devra donc ressembler à :
[gitea]
gitea2.afpy.org
On peut probablement supprimer l’autre qui ne marche plus...
Lancer Ansible
ansible-playbook gitea.yml
rsync la sauvegarde
J’utilise du ssh agent forwarding
, si vous n’en utilisez-pas vous
aurez peut-être à rsync sur votre machine d’abord.
Adapté de : https://docs.gitea.io/en-us/backup-and-restore/#restore-command-restore
Donc, depuis gitea2:
cd /var/lib/gitea/
rsync -vah backup1.afpy.org:/srv/backups/rsnapshot_afpy/daily.0/git.afpy.org/var/backups/gitea/ ./
systemctl stop gitea
rm -fr data custom
unzip gitea.zip
rm gitea.zip
mv app.ini /etc/gitea/app.ini
mv repos data/gitea-repositories
chown -R git:git .
sudo --user git psql -d gitea < gitea.sql
rm gitea.sql
Puis passer le playbook gitea.yml
pour remettre les bons droits partout (le playbook démarrera aussi gitea
).
Tester et mettre à jour git.afpy.org
Un rapide test peut être effectué via :
curl --resolve git.afpy.org:IP_DE_LA_NOUVELLE_MACHINE https://git.afpy.org
Puis il faut mettre à jour le CNAME de git.afpy.org pour le faire pointer vers la nouvelle machine.
woodpecker1.afpy.org
♥ Machine sponsorisée par Gandi ♥
C’est un « Gandi VPS V-R1 » 1 CPU, 1 GB RAM, 25 GB disk.
C’est Woodpecker CI lié à notre forge.
Il ne fait tourner aucune tâche, ce sont les agents qui font tourner les tâches. Si vous avez une machine de libre, vous êtes invités à proposer un agent. Il suffit de :
- Installer une Debian.
- Y ajouter nos authorized_keys.
- Nous donner son IP.
Un agent n’a pas besoin d’IPv4, donc une vieille machine recyclée planquée chez vous sans NAT mais avec de l’IPv6 ça suffit. Pas de Raspberry PI par contre, nous n’avons pour le moment pas de tâches à faire tourner sur arm64.
boole.mdk.woodpecker-agents.afpy.org
♥ Machine sponsorisée par Julien Palard ♥
C’est un vieux laptop à moi, 4 cœurs, 8GB de RAM, planqué sous mon bureau.
Il sert uniquement d’agent au Woodpecker, et c’est pour le moment le seul.
discourse1.afpy.org
♥ Machine sponsorisée par Gandi ♥
C’est un VPS V-R4 2 CPUs · 4 GB RAM
.
Elle héberge https://discuss.afpy.org une instance Discourse.
Déplacement du Discourse vers une nouvelle machine
Le 31 janvier 2023 Julien a déplacé le Discourse de deb2 à discourse1.
Voici la procédure
- Ajouter les enregistrements A et AAAA de la machine.
- Baisser le TTL du CNAME
discuss.afpy.org
. - Mettre à jour le SPF pendant qu’on y est.
- Configurer le reverse DNS de la nouvelle machine.
- Côté Ansible, ajouter la machine au groupe
[discourse]
dans le fichierinventory
. - Copier sa clé ssh sur la machine dans
/root/.ssh/authorized_keys
. - Lancer
ansible-playbook discuss.yml
. - Lancer à la main dans
/var/discourse/
:./launcher rebuild app
(ça prend ~10mn). - Sur l’ancienne machine, faire une sauvegarde, soit via https://discuss.afpy.org/admin/backups, soit :
./launcher enter app discourse backup exit
- Copier une sauvegarde dans
/var/discourse/shared/standalone/backups/default/
. - Restaurer la sauvegarde :
cd /var/discourse ./launcher enter app discourse enable_restore discourse restore afpy-2023-01-31-215204-v20230130053144.tar.gz exit
Bien tester l’envoi d’emails.
Rôles utilisés
On utilies ces rôles Ansible :
roles/nginx
Ce rôle configure un nginx avec Letsencrypt en DNS-01 via l’API Gandi (nos domaines étant chez Gandi).
L’avantage du DNS-01 c’est qu’on peut configurer un nouveau serveur avant que le DNS ne pointe sur lui.
julienpalard.nginx
Ce rôle configure un nginx avec Letsencrypt en HTTP-01, on l’utilise
assez peu maintenant, on l’utilise là où on ne peut pas faire de
DNS-01 (pour fr.pycon.org
par exemple).
Voir la doc.
common
common est un rôle "de base" permettant d’avoir une conf "normale" sur toutes nos machines (emacs et vim installés, nos authorized-keys, pas de mlocate, hostname propre, firewall, ce genre de broutilles).
exim
Le playbook exim configure une clé DKIM et signe les mails avec. Mais un humain doit la propager sur les DNS.
Le nom d’hote est le nom du serveur, donc pour deb2
,
d=deb2.afpy.org
, et le selecteur vaut le nom de domaine avec des
-
, soit s=deb2-afpy-org
.
TL;DR la configuration qu’il faut faire ressemble à :
deb2-afpy-org._domainkey.deb2.afpy.org. IN TXT "v=DKIM1; k=rsa; p=MIG...QAB"
La clé publique se situe dans /etc/exim4/dkim/*.pem
et est donc récupérable via :
ssh root@deb2.afpy.org cat /etc/exim4/dkim/deb2-afpy-org.pem | grep -v ^- | tr -d '\n'
Côté IPv6 c’est pas joli :
- Gandi ne nous fournit pas de /64 en IPv6, notre /64 se fait donc régulièrement bloquer à cause des voisins. cf. https://slash64.net/.
- Certaines de nos machines n’ont que de l’IPv6 (backup1, l’agent woodpecker chez mdk).
- Certains MX n’ont pas d’IPv6 du tout (protonmail, galae, …).
Résultat :
- Faire passer les mails des machines IPv6-only par des machines qui ont une IPv4 ne marche pas, l’IPv6 étant désactivé sur les exim à cause de l’absence de /64, pour les forcer à délivrer en IPv4.
- Nos machines en IPv6 n’envoient pas d’email, du tout.
Tâches
Redimentionner un disque sur un VPS
- Agrandir le volume via l'interface web,
- agrandir la partition via
growpart /dev/xvda 1
, - agrandir le filesystem via
resize2fs /dev/xvda1
.