Ressusciter un site vieux de dix ans

Comment j'ai utilisé Docker pour ramener mon site vieux de dix ans à la vie

Récemment, je suis retombé sur le code source d’un de mes vieux sites web, Mine the Cyril. C’était un site avec des actus, des comptes, un forum, même une plateforme de streams : bref, tout ce que je (et quelques modèles) pouvais faire.

J’ai décidé de le relancer, pour un petit coup de nostalgie (et pour voir à quel point c’était gênant).

Cependant, je voulais garder les modifications au minimum, voir ne pas en faire du tout, ce qui voulais donc dire utiliser du vieux logiciel.

C’est parti !

Rapidement, plusieurs problèmes sont apparus :

  1. Le site est fait avec PHP 5 et l’extension mysql, depuis retirée
  2. Je n’ai pas de sauvegardes de la base de données MySQL (j’étaisje suis stupide)

Voyons comment j’ai résolu ces deux problèmes, en commençant par le premier.

Faire tourner du vieux logiciel

PHP a beaucoup changé durant la dernière décennie. On est passé de la version 5 à la version 8, chaque version améliorant le langage, et qui pourrais oublier PHP 6 ?

Mais aujourd’hui, on est bloqués dans le passé, et en 2014-2015, ça signifiait PHP version 5. Bon, voyant comment faire tourner PHP 5 ces jours-ci.

Docker à la rescousse ?

Bon, j’ai besoin d’une version de PHP vieille de dix ans et d’un serveur web. Ma première idée est simple :

Je sais, je peux trouver ça sur Docker Hub !

Et c’est ce que j’ai fait. Il existe une variante de l’image php qui vient avec le serveur web Apache, avec les tags apache. Pour PHP 5, l’image à utiliser et donc php:5-apache.

J’ai donc ouvert le code source dans mon éditeur actuel, Visual Studio Code, par opposition à mon éditeur de l’époque, Microsoft WebMatrix (vous vous souvenez ?), et j’ai créé un fichier Dockerfile et un fichier docker-compose.yml.

Voici le contenu de mon Dockerfile :

FROM php:5-apache
RUN apt-get update && apt-get install -y \
  libfreetype6-dev \
  libjpeg62-turbo-dev \
  libpng-dev \
  && docker-php-ext-configure gd --with-freetype --with-jpeg \
  && docker-php-ext-install -j$(nproc) gd \
  && docker-php-ext-install -j$(nproc) mysql
COPY ./ /var/www/html/
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

Ce Dockerfile est basé sur l’image Docker PHP 5 avec serveur web Apache, met à jour et installe les paquets supplémentaires nécessaires à l’extension de manipulation d’images GD, installe et active ladite extension, ainsi que l’extension mysql.

Et voici le contenu de mon fichier Docker compose :

services:
  adminer:
    image: adminer
    restart: always
    depends_on:
      - db
    ports:
      - 8080:8080
  web:
    build:
      context: .
      dockerfile: Dockerfile
    restart: always
    depends_on:
      - db
    ports:
      - 80:80
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: flfg1bqk
      MYSQL_USER: flfg1bqk
      MYSQL_PASSWORD: <redacted>
      MYSQL_RANDOM_ROOT_PASSWORD: "1"
    volumes:
      - db:/var/lib/mysql
volumes:
  db:

Ce fichier compose inclut Adminer pour gérer la base de données, une base de données MySQL 5.7 et un service web principal qui exécutera notre code, construit à l’aide du Dockerfile ci-dessus.

Ça part en prod !

Maintenant que j’ai un Docker file et un fichier Docker compose qui devraient marcher (spoiler : non), j’ai lancé tout ça et attendu.

Malheureusement, un problème arrive lors du build de l’image Docker, dans l’étape 2, celle qui installe les paquets supplémentaires pour gd, l’extension de manipulation d’images.

Err:9 http://deb.debian.org/debian stretch/main amd64 Packages
  404  Not Found
Ign:10 http://deb.debian.org/debian stretch/main all Packages
Ign:11 http://deb.debian.org/debian stretch-updates/main all Packages
Err:12 http://deb.debian.org/debian stretch-updates/main amd64 Packages
  404  Not Found
Reading package lists...
W: The repository 'http://security.debian.org/debian-security stretch/updates Release' does not have a Release file.
W: The repository 'http://deb.debian.org/debian stretch Release' does not have a Release file.
W: The repository 'http://deb.debian.org/debian stretch-updates Release' does not have a Release file.
E: Failed to fetch http://security.debian.org/debian-security/dists/stretch/updates/main/binary-amd64/Packages  404  Not Found [IP: 151.101.130.132 80]
E: Failed to fetch http://deb.debian.org/debian/dists/stretch/main/binary-amd64/Packages  404  Not Found
E: Failed to fetch http://deb.debian.org/debian/dists/stretch-updates/main/binary-amd64/Packages  404  Not Found
E: Some index files failed to download. They have been ignored, or old ones used instead.

Comme on peut voir, il cherche à charger depuis deb.debian.org. Le problème, c’est qu’il tombe sur un 404. En y allant avec mon navigateur, et en fouillant, pas moyen de trouver un répertoire stretch. Il a disparu.

Il se trouve que l’image php:5-apache est basée sur Debian 9, comprenez Debian Stretch, ce qui explique pourquoi il cherche les paquets pour stretch. Mais pourquoi les paquets ne sont pas disponibles ?

Un peu plus tard, j’ai réalisé que Debian 9 n’était plus supporté, il est en fin de vie. Mais contrairement à ce que je pensais, quand une version de Debian est en fin de vie, ses répertoires sont éventuellement supprimés.

Pourquoi, Debian? Pourquoi ?

Il s’avère que les dépôts Debian pour les anciennes versions sont régulièrement archivés sous archive.debian.org, et vous devez modifier votre fichier /etc/apt/sources.list pour refléter ce changement, sinon vous obtiendrez une erreur lors de la tentative de mise à jour ou d’installation de paquets.

Debian publie plusieurs images Docker pour les versions Debian en fin de vie, j’ai donc téléchargé et exécuté l’image debian/eol:stretch pour voir ce que contient le fichier sources.list :

# deb http://snapshot.debian.org/archive/debian-archive/20240331T102506Z/debian stretch main
deb http://archive.debian.org/debian stretch main
# deb http://snapshot.debian.org/archive/debian-archive/20240331T102506Z/debian-security stretch/updates main
deb http://archive.debian.org/debian-security stretch/updates main

Il semblerait donc que nous devions remplacer deb.debian.org par archive.debian.org et, en théorie, tout devrait bien se passer.

Plus facile que je pensais

Bien, remplaçons simplement le fichier sources.list de l’image php:5-apache par celui de debian/eol:stretch, en copiant manuellement un fichier sources.list modifié à l’aide de l’instruction COPY, afin d’obtenir le fichier suivant à la fin :

FROM php:5-apache
COPY sources.list /etc/apt/sources.list
RUN apt-get update && apt-get install -y \
  libfreetype6-dev \
  libjpeg62-turbo-dev \
  libpng-dev \
  && docker-php-ext-configure gd --with-freetype --with-jpeg \
  && docker-php-ext-install -j$(nproc) gd \
  && docker-php-ext-install -j$(nproc) mysql
COPY ./ /var/www/html/
RUN rm /var/www/html/comptes/.htaccess
RUN rm /var/www/html/lives/.htaccess
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

Et ça compile ! Enfin, ça compile sur deux de mes trois machines, car mon vieux portable Ubuntu affiche une erreur du genre « Le compilateur ne fonctionne pas ». Bref.

Garde tes données proches de toi

Maintenant que nous avons un service web fonctionnel, jetons un œil à la base de données. Une base de données pour laquelle nous n’avons ni données ni structure, pour rappel ?

Il nous faut plus de données

Comme vous pouvez l’imaginer, je ne pourrai pas récupérer les données originales de la base de données. J’ai (bêtement) oublié d’en faire des sauvegardes, et Olympe, mon hébergeur gratuit de l’époque, a fermé ses portes il y a une dizaine d’années. Je peux cependant essayer de recréer la structure de la base de données et d’y insérer des exemples de données.

C’est donc ce que j’ai fait : j’ai lancé le site, observé les dysfonctionnements et créé des tables avec les colonnes attendues. J’ai également consulté le code source. Dans ma recherche, deux fichiers SQL trouvés dans le code source m’ont été d’une grande aide et m’ont permis d’avancer considérablement.

Une capture d’écran de la BDD dans Adminer

J’ai tout exporté dans un seul fichier SQL et je l’ai copié sur le service de base de données en utilisant un volume comme ceci :

db:
  image: mysql:5.7
  restart: always
  environment:
    MYSQL_DATABASE: flfg1bqk
    MYSQL_USER: flfg1bqk
    MYSQL_PASSWORD: <redacted>
    MYSQL_RANDOM_ROOT_PASSWORD: "1"
  volumes:
    - ./database.sql:/docker-entrypoint-initdb.d/database.sql:ro
    - db:/var/lib/mysql

Base de données connectée

Dernière étape avant que le service web puisse accéder à la base de données : configurer un alias DNS. En effet, le code source utilise sql.olympe.in comme nom d’hôte de la base de données ; il me fallait donc un moyen d’indiquer à Docker de le rediriger vers le service de base de données.

J’ai essayé plusieurs méthodes, en créant un réseau personnalisé et en attribuant manuellement des adresses IP, en utilisant des alias, mais finalement, il a suffi d’ajouter un lien vers le service web :

web:
  build:
    context: .
    dockerfile: Dockerfile
  restart: always
  depends_on:
    - db
  ports:
    - 80:80
  links:
    - db:sql.olympe.in

Les fichiers qui fonctionnent

Voici les fichier finaux, Dockerfile et docker-compose.yml, si ça vous intéresse :

FROM php:5-apache
COPY sources.list /etc/apt/sources.list
RUN apt-get update && apt-get install -y \
  libfreetype6-dev \
  libjpeg62-turbo-dev \
  libpng-dev \
  && docker-php-ext-configure gd --with-freetype --with-jpeg \
  && docker-php-ext-install -j$(nproc) gd \
  && docker-php-ext-install -j$(nproc) mysql
COPY ./ /var/www/html/
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
services:
  adminer:
    image: adminer
    restart: always
    depends_on:
      - db
    ports:
      - 8080:8080
  web:
    build:
      context: .
      dockerfile: Dockerfile
    restart: always
    depends_on:
      - db
    ports:
      - 80:80
    links:
      - db:sql.olympe.in
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: flfg1bqk
      MYSQL_USER: flfg1bqk
      MYSQL_PASSWORD: <redacted>
      MYSQL_RANDOM_ROOT_PASSWORD: "1"
    volumes:
      - ./database.sql:/docker-entrypoint-initdb.d/database.sql:ro
      - db:/var/lib/mysql
volumes:
  db:

C’est grave docteur ?

Maintenant que ça fonctionne, à quel point c’est nul ? Eh bien, après m’être baladé dessus et lu un peu le code source, on peut clairement voir que j’étais en train d’apprendre à programmer.

Une capture d’écran du site fonctionnel

À le refaire aujourd’hui, je ferais plein de trucs différemment. Mais ça n’a pas d’importance. Au moins, ça marche encore dix ans plus tard, et avec un peu de chance, pour encore dix ans de plus.

Merci d’avoir lu !