Skip to main content

Upgrade de version majeure d'une BDD Postgres avec Docker

Je voulais mettre à jour mon TeslaMate de la version 1.26.1 vers la 1.27.1. Simple, avec Docker, mais au moment de pull/up -d, le container de BDD me crache l'erreur suivante à la figure : 

postgres_1        | FATAL:  database files are incompatible with server
postgres_1        | DETAIL:  The data directory was initialized by PostgreSQL version 13, which is not compatible with this version 14.6.

C'est assez clair comme explication : les données ont été créées avec une version antérieure de Postgres et ne sont pas compatibles avec la nouvelle version. Mettons-nous au travail pour upgrade les datas dans la bonne version. 

En fait la procédure est assez simple sur le papier : 

  1. On BACKUP (toujours toujours toujours) 
  2. On détruit les données (on a un backup, NORMALEMENT) ainsi que le container Postgres en version 13
  3. On recréé un container Postgres en version 14
  4. On restore le backup

Dans les faits, ça donne : 

On dump la BDD (On fait une sauvegarde, quoi)

docker-compose exec -T database pg_dump -U teslamate teslamate > ./backup/teslamate.bck

On stoppe la stack docker teslamate (On a pas envie qu'un container écrive dans la BDD pendant qu'on manipe) et on dégage les container, tant qu'à faire. De toute façon on va mettre à jour.

docker-compose down

On supprime le dossier ./data/db ou se trouvent les données de la DB

rm -R ./data/db

On modifie le docker-compose.yml pour y mettre à jour les versions des images (Je reste en 1.26 pour teslamate pour l'instant, afin de ne pas télescoper les manips sur la BDD avec des migrations de la nouvelle version 1.27). En somme on modifie

image: postgres:13

en

image: postgres:14

Le fichier complet : 

version: "3"

services:
  teslamate:
    image: teslamate/teslamate:1.26
    restart: always
    environment:
      - DATABASE_USER=teslamate
      - DATABASE_PASS=MoNp@sSw0rdSuPerfOrt
      - DATABASE_NAME=teslamate
      - DATABASE_HOST=database
      - MQTT_HOST=mosquitto
      - ENCRYPTION_KEY=unecledechiffrementtreslonguepourchiffremontokenperso
      - VIRTUAL_HOST=teslamate.caliko.net
      - VIRTUAL_PORT=4000
      - LETSENCRYPT_EMAIL=dorian@email.com
      - LETSENCRYPT_HOST=teslamate.caliko.net
    ports:
      - 4000:4000
    volumes:
      - ./import:/opt/app/import
    cap_drop:
      - all

  database:
    image: postgres:14
    restart: always
    environment:
      - POSTGRES_USER=teslamate
      - POSTGRES_PASSWORD=MoNp@sSw0rdSuPerfOrt
      - POSTGRES_DB=teslamate
    volumes:
      - ./data/db:/var/lib/postgresql/data

  graf:
    image: teslamate/grafana:1.26
    restart: always
    environment:
      - DATABASE_USER=teslamate
      - DATABASE_PASS=MoNp@sSw0rdSuPerfOrt
      - DATABASE_NAME=teslamate
      - DATABASE_HOST=database
      - VIRTUAL_HOST=teslagraf.caliko.net
      - VIRTUAL_PORT=3000
      - LETSENCRYPT_EMAIL=dorian@email.com
      - LETSENCRYPT_HOST=teslagraf.caliko.net
    ports:
      - 3000:3000
    volumes:
      - ./data/grafana:/var/lib/grafana

  mosquitto:
    image: eclipse-mosquitto:2
    restart: always
    command: mosquitto -c /mosquitto-no-auth.conf
    expose:
      - 1883
    volumes:
      - ./conf/mosquitto:/mosquitto/config
      - ./data/mosquitto:/mosquitto/data

networks:
  default:
    external:
      name: reverse-proxy

 

Une fois que c'est fait, je commence par lancer uniquement le container postgres : 

docker-compose up -d database

J'attends quelques secondes que tout s'initialise (le serveur va démarrer et lancer les premières actions sur la DB pour l'initialiser, je rappelle qu'on a tout supprimé. Mais on a un backup ! )

Une fois démarré (on peut faire un docker logs teslamate_database_1 pour voir ce qui se passe), on supprime le schéma initial (Pas forcément nécessaire, mais dans le doute, je repars raiment de 0) : 

docker-compose exec -T database psql -U teslamate << .
drop schema public cascade;
create schema public;
create extension cube;
create extension earthdistance;
CREATE OR REPLACE FUNCTION public.ll_to_earth(float8, float8)
    RETURNS public.earth
    LANGUAGE SQL
    IMMUTABLE STRICT
    PARALLEL SAFE
    AS 'SELECT public.cube(public.cube(public.cube(public.earth()*cos(radians(\$1))*cos(radians(\$2))),public.earth()*cos(radians(\$1))*sin(radians(\$2))),                                                                                                                                                                public.earth()*sin(radians(\$1)))::public.earth';
.

Le résultat : 

image-1671748552606.png

On importe maintenant le backup fait en première étape 

docker-compose exec -T database psql -U teslamate -d teslamate < ./backup/teslamate.bck

Là, en fonction de la taille du backup ça peut être plus ou moins long. Pas mal de choses vont défiler à l'écran, pas de panique si rien ne se passe pendant quelques secondes. L'important, c'est qu'au moment ou le prompt est rendu, on n'ait aucune erreur affichée. Sinon, il faut analyser pourquoi. 

Maintenant on a un container Postgres en version 14, avec les données utilisables. 

Je stoppe et supprime le container avec un docker-compose down puis je lance la stack complète avec docker-compose up -d

J'ai maintenant un TeslaMate en version 1.26.1 et une BDD Postgres en version 14. Reste à mettre à jour TeslaMate, et là c'est bien plus simple. On reprend notre fichier docker-compose.yml et on change les tags teslamate/teslamate:1.26 et teslamate/grafana:1.26 pour les passer en version 1.27. 

Un docker-compose up -d plus tard, nous voilà avec le tout à jour ! 

image-1671749027326.png