Sauvegarde de base de données avec mysqldump et logrotate

Cela faisait plus d’un an que j’avais vaguement mentionné la question de la sauvegarde d’Unicoda et des autres services que j’héberge. Jusqu’à présent, je m’étais contenté de quelques sauvegardes manuelles effectuées de temps à autre, lorsque le contenu avait bien évolué ou que la sauvegarde précédente commençait à dater. Je me suis donc intéressé aux différentes solutions qu’on rencontre sur le net : rsync, rclone, duplicity, script bash, bacula, pour ne citer que quelque-uns des outils. Si l’automatisation de la sauvegarde ne m’avait jamais semblé essentielle, c’est que j’étais conscient des risques et me reposait sur la duplication RAID de l’hébergeur (pour le risque de défaut matériel), mais surtout, parce que la majorité des informations était généralement présente en local sur l’une ou l’autre de mes machines. Après les récents changements de serveurs et le passage à l’auto-hébergement de nombreux services, la sauvegarde devient critique. Commençons donc par nous pencher sur la sauvegarde des données du serveur SQL.

Pour exporter les données d’un serveur MySQL, la commande mysqldump est tout indiquée. Pour sauvegarder l’intégralité des bases du serveur avec l’utilisateur root, on pourra par exemple utiliser :

mysqldump -u root -p --all-databases > all_databases.sql

De la même manière, il est possible de n’extraire qu’une seule base de données :

mysqldump -u [user] -p maBase > maBDD.sql

Il est possible de spécifier le mot de passe de l’utilisateur directement dans la commande via -p[motDePasse] ou encore -p'[motDePasse]’.  Une fois en possession d’une copie de notre base, l’import s’effectue simplement en utilisant :

mysql -u [user] -p maNouvelleBase < maBDD.sql

J’ai eu l’occasion de mettre à l’épreuve cette méthode lors des différentes migrations d’Unicoda; toujours avec succès et sans jamais rencontrer de problème.

Maintenant que nous avons une façon de sauvegarder les données de MySQL, il est temps de s’intéresser à l’automatisation du processus.  Afin de régler la question de l’accumulation des fichiers de sauvegarde, j’ai décidé d’utiliser logrotate, en détournant quelque peu son usage pour l’appliquer à mes sauvegardes SQL et non à des fichiers de logs. Avant toutes choses, je crée un nouvel utilisateur au niveau de MySQL en le limitant aux droits Lock Tables et Select sur la base que je veux sauvegarder.

GRANT LOCK TABLES, SELECT ON maBase.* TO '<user>'@'localhost' IDENTIFIED BY '<password>';

On passe ensuite à la configuration de logrotate pour notre fichier de sauvegarde. J’ajoute donc un fichier dans /etc/logrotate.d/sauvegarde-base-sql avec le contenu suivant :

/var/backups/mysql/maBDD.sql.gz {
  daily
  dateext
  rotate 21
  nocompress
  create
  postrotate
  mysqldump --single-transaction --add-drop-table -u user -pmonMotDePasse baseASauvegarder > /var/backups/mysql/maBDD.sql
  gzip -9f /var/backups/mysql/maBDD.sql
  chown user:user /var/backups/mysql/maBDD.sql.gz
  chmod 640 /var/backups/mysql/maBDD.sql.gz
  endscript
}

Côté paramètres :

  • L’exécution est journalière.
  • La date est ajoutée au fichier lors de la rotation.
  • On conserve 21 fichiers.
  • Pas de compression
  • Le nouveau fichier est créé avec les mêmes permissions et le même propriétaire que le précédent (create).
  • On indique les commandes à exécuter après rotation (postrotate) à savoir :
    • Extraction des données de la base
    • Compression du fichier
    • Modification du propriétaire
    • Modification des droits

Enfin, on prépare l’état initial du script en ajoutant un fichier vide de départ :

sudo touch /var/backups/mysql/maBDD.sql.gz

Il est alors possible de tester l’exécution avec l’instruction suivante (débug avec -d et mode verbeux avec -v) :

sudo logrotate -f /etc/logrotate.d/sauvegarde-base-sql

La restauration de la base s’effectue avec la commande d’import décrite plus haut, il faudra bien sûr au préalable décompresser le fichier de sauvegarde :

gunzip maBDD.sql.gz

Grâce à cette configuration, je dispose désormais de 21 jours de sauvegarde de ma base SQL, le tout entièrement automatisé. Logrotate me permet de bénéficier simplement de la rotation de mes fichiers de sauvegarde. Il aurait été aussi possible d’utiliser un script bash et une tâche cron pour un résultat similaire, mais cela aurait nécessité de s’occuper de la partie gestion des anciens fichiers; ce que logrotate fait très bien pour moi. Dans le prochain article dédié à la sauvegarde, je décrirai la solution que j’ai retenue pour la sauvegarde distante des fichiers du serveur, dont ces exports SQL.

Par ailleurs, n’hésitez pas à partager votre manière de sauvegarder votre base de données dans les commentaires.

Source : scottlinux, LeaseWeb Labs, Linode.

Positionner un GameObject dans la hiérarchie (Unity3D)

Alors voilà, mon problème aujourd’hui est de positionner un gameObject fraichement initialisé dans mon script dans la hiérarchie d’un autre gameObject étant devenu son parent (SetParent()).

Pour cela j’ai trouvé la fonction setSiblingIndex() à appliquer sur le « transform » de votre objet à positionner dans la hiérarchie.

Le code :

 public void chargeAllButtonMap(){
        int i = 1;
        foreach (MapInfo mi in Global.param.tableMapInfo) {
            GameObject buttonMap = Instantiate(buttonMapPrefab, Vector3.zero, Quaternion.identity) as GameObject;
            buttonMap.transform.SetParent(mappemonde.transform);
            buttonMap.transform.SetSiblingIndex (1);
            buttonMap.name = "buttonMap_" + i.ToString("D3");
            buttonMap.transform.localPosition = new Vector3 (mi.x, mi.y);
            buttonMap.transform.localScale = new Vector3 (1, 1, 1);

            ActionButonLoadMap ablm = buttonMap.GetComponent<ActionButonLoadMap>();
            ablm.idPartieIs = i.ToString("D3");
            i++;
        }

        buttonIsCharged = true;
    }

Le résultat :

Mes boutons se placent bien à l’index 1 entre Image et AcheterMapPanel. Ils ne seront plus affiché devant mon objet AcheterMapPanel mais bien derrière.

HTTPS par défaut

Comme évoqué le mois dernier, j’ai effectué aujourd’hui quelques changements de configuration du côté d’Apache. L’intégralité du flux HTTP est désormais redirigé vers HTTPS à l’aide d’un simple :

Redirect permanent / https://www.unicoda.com/

J’ai effectué un test de requête avec Postman en essayant de récupérer l’une des images du site en HTTP et en précisant de ne pas suivre automatiquement les redirections. J’obtiens alors le message suivant:

 <h1>Moved Permanently</h1>
 <p>The document has moved 
   <a href="https://www.unicoda.com/wp-content/uploads/2012/09/cropped-022232111.jpg">here</a>.
 </p>

, ce qui est positif.

Le changement devrait donc être transparent, les navigateurs modernes et les moteurs de recherche étant capable de gérer automatiquement la redirection, comme l’explique clairement la documentation Mozilla.

Limitation des requêtes externes

Je me plains souvent de toutes ces requêtes externes qu’effectuent les sites que j’ai l’occasion de consulter. J’utilise bien entendu un certain nombre d’extensions pour tenter de limiter au maximum les requêtes non indispensables à l’affichage des informations qui m’intéresse sur une page web.

Pour être cohérent, j’avais donc commencé à faire la chasse aux requêtes externes sur Unicoda, en commençant par arrêter de récupérer la police d’écriture sur les serveurs de Google et en décidant de modifier la façon d’intégrer une vidéo pour proposer un lien plutôt que de charger tous les scripts nécessaires à la lecture par défaut.

Il restait sur Unicoda des requêtes vers Gravatar, c’est ce que l’on peut reprocher à WordPress: intégrer des services externes par défaut, sans proposer la possibilité de désactiver la fonctionnalité. Pour éviter dans la mesure du possible les requêtes externes vers Gravatar, j’ai donc ajouté l’extension Harrys Gravatar Cache, afin de disposer d’une copie locale des images pour une durée de 4 semaines. En théorie, plus aucune requêtes vers Gravatar, sauf pour renouveler le cache périodiquement, ce que font d’ailleurs très bien les robots parcourant le web. Petit point négatif, l’extension ne semble pas fonctionner pour les images présentes dans l’interface d’administration…

La prochaine étape pour Unicoda consistera certainement en la mise en place d’une redirection du flux HTTP vers HTTPS. Cela fait plusieurs années que j’ai mis en place le flux HTTPS, l’initiative Let’s Encrypt ayant grandement facilité tout le processus de mise en place et de gestion. Le premier problème que j’identifie pour le moment se situe du côté du header Strict-Transport-Security et son paramètre max-age, qui pourrait poser problème si le flux HTTPS devenait inopérant (faible probabilité, mais pas impossible. En cas de besoin, il semble possible de désactiver la fonctionnalité en indiquant la valeur 0 pour max-age). Le second concerne l’impact de la redirection sur les flux RSS. Et bien sûr, en parallèle, je continue de réfléchir à l’automatisation de la sauvegarde du site.

[i3] Gestion du volume au clavier

Mon clavier actuel dispose d’une molette permettant de régler le volume. Après plusieurs essais infructueux visant à faire varier le volume via la molette dans i3, j’ai repris dernièrement le problème du début, pour enfin arriver à une configuration fonctionnelle.

Je me suis donc replongé dans la documentation d’i3 qui indique d’utiliser xev pour capturer les informations sur les touches que l’on souhaite configurer. Installation donc avec pacman sous Arch Linux : pacman -S xorg-xev. Il est ensuite possible de démarrer le programme via la commande xev. Si je fais bouger la molette vers le bas, j’obtiens les événements suivants dans xev:

MappingNotify event, serial 33, synthetic NO, window 0x0,
    request MappingKeyboard, first_keycode 8, count 248

KeyPress event, serial 33, synthetic NO, window 0x2a00001,
    root 0x2a4, subw 0x0, time 14668027, (482,-109), root:(486,1198),
    state 0x10, keycode 122 (keysym 0x1008ff11, XF86AudioLowerVolume), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyRelease event, serial 34, synthetic NO, window 0x2a00001,
    root 0x2a4, subw 0x0, time 14668030, (482,-109), root:(486,1198),
    state 0x10, keycode 122 (keysym 0x1008ff11, XF86AudioLowerVolume), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

Tout ceci n’est pas très lisible ici, mais nous pouvons tout de même isoler les informations intéressantes en particulier keycode 122 et XF86AudioLowerVolume. Pour ma part, je choisis d’utiliser le keysysm XF86AudioLowerVolume, et utiliserai donc bindsym, pour utiliser le keycode, on utilisera bindcode (non testé). En résumé, pour diminuer le volume XF86AudioLowerVolume, pour l’augmenter XF86AudioRaiseVolume et pour couper le son XF86AudioMute.

Il faut maintenant s’intéresser à la commande à effectuer dans les différents cas. Pour le contrôle du volume, je décide de passer par pactl, abréviation de PulseAudio Control. La commande est de la forme :

pactl set-sink-volume SINK VOLUME

Le paramètre SINK correspond à la sortie sonore que l’on souhaite contrôler. Pour être en mesure de déterminer son numéro, j’utilise la commande pactl list. Parmi les informations renvoyées, il faut chercher les lignes suivantes Carte #0, Carte #1, … Dans mon cas, la carte 0 indique « HDMI Audio Controller », il s’agit donc de la sortie sonore du port HDMI de mon ordinateur. Pour la carte 1, c’est déjà mieux puisqu’il est affiché « Audio interne ». Pour des informations plus concises, on utilise pactl list sinks short et on sélectionne la carte portant la mention RUNNING.

Petit test rapide, casque sur les oreilles, fond musical, j’exécute la commande suivante dans mon terminal : pactl set-sink-volume 1 -5%. Bingo ! Le volume diminue. J’en profite tout de suite pour tester la commande permettant de couper le son : pactl set-sink-mute 1 toggle. Cela fonctionne. J’ouvre donc le fichier de configuration d’i3 pour y ajouter les lignes suivantes :

bindsym XF86AudioLowerVolume exec pactl set-sink-volume 1 -5%
bindsym XF86AudioRaiseVolume exec pactl set-sink-volume 1 +5%
bindsym XF86AudioMute exec pactl set-sink-mute 1 toggle

Rechargement de la configuration.

Trois lignes de configuration qui me permettent désormais de contrôler le volume directement au niveau de mon clavier, sans avoir à le modifier dans l’application diffusant le flux audio. Pour simplifier la mise en place d’une telle configuration, on essayera de toujours procéder en trois étapes. En premier lieu, validation de la commande que l’on souhaite appeler, puis test de la prise en compte de la touche sur une commande fonctionnelle connue, et enfin réunion des étapes précédentes pour configuration finale. L’essentiel étant surtout de ne pas se hâter (« Ne soyez pas si hâtif, maître Meriadoc ! ») pour éviter de se retrouver, après configuration, sans effet visible ou audible et, de ne pas pouvoir alors, isoler immédiatement la source du problème.