Installation Docker

Afin de faciliter l’installation du serveur SAINet, un container est mis à disposition sur Docker Hub (dès la version 4.9). En utilisant cette image, combinée aux autres services nécessaires, aucune installation particulière (en dehors de Docker) n’est nécessaire sur la machine hôte.

Paramètres

Afin de pouvoir configurer SAINet, les paramètres ci-dessous doivent être connus au préalable.

Paramètre Variable Description
user SAINET_UPDATE_USERNAME Identifiant pour accéder aux paquets d’installation et de mises à jour.
password SAINET_UPDATE_PASSWORD Mot de passe pour accéder aux paquets d’installation et de mises à jour.
customer id SAINET_CUSTOMER_FILE Identifiant du client au sein de SAINet.
environment id SAINET_ENV_NAME Identifiant de l’environnement d’installation. Cette valeur est en lien avec le serveur sur lequel l’application va être installée.
mobile SAINET_MOBILE_ENABLED Détermine si la partie mobile doit être déployée, notamment pour permettre l’accès à l’application par browser / tablette.
Base de données SAINET_DATABASE_MYSQL_* Paramètres de connexion à la base de données.

Configuration système

Sous Debian, 2 paquets doivent être installés:

apt-get install docker docker-compose
systemctl start docker

L’utilisateur courant (<user>) doit ensuite faire partie du groupe docker afin de pouvoir gérer le service. Avec l’utilisateur root, exécuter la commande suivante:

gpasswd -a <user> docker

L’utilisateur devra ensuite se reconnecter afin d’avoir ses accès à jour.

Note:

Pour éviter de se reconnecter, il est possible d’utiliser la commande newgrp docker.

Configuration automatique

Un projet est mis à disposition par SAI ERP pour automatiser l’initialisation et la mise à jour de SAINet dans un environnement Docker.

Initialisation

Si le projet git est directement utilisé, commencer par les étapes suivantes:

  • Cloner le projet (avec HTTPS).
  • Passer sur la branche nécessaire (git checkout stable/4.9.x).
Info:

Si les fichiers vous ont été procurés au préalable, l’étape ci-dessus n’est pas nécessaire.

Lorsque SAINet est déployé pour la première fois:

  • Remplacer les <to_define> par les valeurs appropriées dans docker-compose.yml.
  • Exécuter ./sainet-up.sh.

A la fin du script, en pressant Enter, les logs Docker sont affichés directement dans la console afin de pouvoir suivre le déploiement de SAINet. A la fin du déploiement, les logs montrent ceci:

================================================
SAINet Embedded Server version 4.9.4.
The domain payara is now up and running. (inst:PYA, env:#local)
The GlassFish/Payara installation dir is /tmp/gfembed14043435345614509593tmp
The SAINet runtime dir is <runtime>
Ports used: HTTP=9090, HTTPS=9191, ADMIN=5858
URL: http://<url>/SNV4SRV-ws-war/EPS
Host: sagittarius/127.0.1.1
================================================
You can use <ctrl> + C to shut it down.

Cela indique que le serveur SAINet est prêt et qu’il faut simplement faire <ctrl> + C pour quitter l’affichage des logs. Cela ne va pas arrêter le serveur SAINet comme lors d’une exécution directe ! La commande <ctrl> + C peut être faite à tout moment sans impact, comme lorsque l’on utilise la commande docker logs -f <container_id>.

Désormais, SAINet est entièrement fonctionnel avec les services nécessaires. Après l’initialisation, il est possible de se connecter à SAINet avec les identifiants saierp / bootStrap373746.

Mise à jour majeure

Attention:

Il est fortement recommandé de faire une sauvegarde de la base de données avant toute mise à jour majeure ! Le script sainet-up.sh propose d’en faire une automatiquement.

Lorsqu’une mise à jour majeure doit être effectuée, cela implique généralement des modifications de système. La procédure suivante doit être appliquée:

  • Stocker les modifications courante (git stash).
  • Mettre à jour (git pull) et passer sur la branche désirée (git checkout stable/4.9.x).
  • Réappliquer les modifications (git stash pop) et corriger les éventuels conflits.
  • (Une fois les conflits corrigés, revenir dans un état normal (git add -u . && git reset)).
  • Exécuter ./sainet-up.sh.
Note:

Dans le cas où git n’est pas utilisé, il est recommandé d’utiliser les nouveaux fichiers et de reprendre les configurations nécessaires avant d’exécuter ./sainet-up.sh.

Le script va prendre en charge les migrations nécessaires (surtout sur la base de données) et redémarrer les containers.

Configuration minimale

Voici une configuration minimale (docker-compose.yml) permettant de démarrer SAINet:

version: "3.0"

services:
  sainet_app:
    restart: always
    image: saierp/sainet:4.9
    volumes:
      - "./sainet:/sainet"

    environment:
      # java options
      - JAVA_OPTIONS=-Xmx4096m
      
      # database configuration
      - SAINET_DATABASE_MYSQL_HOST=<to_define>
      - SAINET_DATABASE_MYSQL_SCHEMA=<to_define>
      - SAINET_DATABASE_MYSQL_USER=<to_define>
      - SAINET_DATABASE_MYSQL_PASSWORD=<to_define>
      
      # global configuration
      - SAINET_CUSTOMER_FILE=<to_define>
      - SAINET_ENV_NAME=<to_define>
      #- SAINET_EXTERNAL_URL=<to_define>
      
      # update configuration
      - SAINET_UPDATE_USERNAME=<to_define>
      - SAINET_UPDATE_PASSWORD=<to_define>
      - SAINET_UPDATE_MODE=release
      
      # backup configuration
      - SAINET_BACKUP_UPDATE_ENABLED=true
      - SAINET_BACKUP_CRON_CONFIG=0 2 * * *
      - SAINET_BACKUP_RETENTION_DAYS=7
Note:

Le dossier /sainet doit être utilisé en tant que volume car celui-ci contient tous les fichiers qui doivent être persistants.

Les variables d’environnement principales sont les suivantes:

Variable Description
JAVA_OPTIONS Options spécifiques à Java. Il est recommandé de spécifier au moins la propriété -Xmx avec une valeur minimale de 2048m.
SAINET_DATABASE_MYSQL_* Configuration d’accès à la base de données.
SAINET_CUSTOMER_FILE Identifiant du client au sein de SAINet, transmis par SAI ERP.
SAINET_ENV_NAME Identifiant de l’environnement d’installation, transmis par SAI ERP. Cette valeur est en lien avec le serveur sur lequel l’application va être installée.
SAINET_EXTERNAL_URL Permet de spécifier l’URL externe complète par laquelle le serveur SAINet peut être atteint (par exemple https://sainet.mydomain.com/SNV4SRV-ws-war/EPS).
SAINET_UPDATE_USERNAME / SAINET_UPDATE_PASSWORD Identifiant / mot de passe pour les mises à jour automatiques, transmis par SAI ERP. Ces valeurs sont nécessaires pour initialiser l’image.
SAINET_BACKUP_UPDATE_ENABLED Détermine si une sauvegarde de la base de données doit être effectuée avant d’appliquer une mise à jour automatique. Cela peut s’avérer superflu, voir problématique si la base de données est volumineuse (>= 10 Go).
SAINET_BACKUP_CRON_CONFIG Configuration cron pour les mises à jour automatiques. Cette variable peut être supprimée pour désactiver les sauvegardes automatiques.
SAINET_BACKUP_RETENTION_DAYS Nombre de jours de rétention des sauvegardes automatiques. Cette variable peut être mise à zéro pour ne pas supprimer les sauvegardes, ou simplement supprimée pour désactiver les sauvegardes automatiques.
Attention:

Le container offre la possibilité de faire des sauvegardes automatiques, mais cela reste basique et n’est pas suffisant pour un serveur de production.

Configuration complète

La configuration ci-dessous déclare plusieurs services utilisés par SAINet:

ID Description Volume
sainet_db Base de données sainet/mariadb
sainet_redis Cache Redis (lorsque le mobile est déployé, cf SAINET_MOBILE_ENABLED aucun
sainet_traefik Serveur HTTP/HTTPS pour la gestion des communications et certificats SSL sainet/certificates
sainet_app Serveur SAINet sainet/app
Note:

Il est nécessaire de créer les dossiers sainet/mariadb, sainet/certificates et sainet/app.

version: "3.0"

services:
  sainet_app:
    restart: always
    image: saierp/sainet:4.9
    depends_on:
      - sainet_db
      - sainet_redis
    volumes:
      - "./sainet/app:/sainet"

    environment:
      # java options
      - JAVA_OPTIONS=-Xmx4096m
      
      # database configuration
      - SAINET_DATABASE_MYSQL_HOST=sainet_db
      - SAINET_DATABASE_MYSQL_SCHEMA=sainet_prod
      - SAINET_DATABASE_MYSQL_USER=dbuser
      - SAINET_DATABASE_MYSQL_PASSWORD=dbpassword
      
      # global configuration
      - SAINET_CUSTOMER_FILE=<to_define>
      - SAINET_ENV_NAME=<to_define>
      #- SAINET_EXTERNAL_URL=<to_define>
      
      # mobile configuration
      - SAINET_MOBILE_ENABLED=true
      - SAINET_REDIS_URL=redis://sainet_redis

      # update configuration
      - SAINET_UPDATE_USERNAME=<to_define>
      - SAINET_UPDATE_PASSWORD=<to_define>
      - SAINET_UPDATE_MODE=release
      
      # backup configuration
      - SAINET_BACKUP_UPDATE_ENABLED=true
      - SAINET_BACKUP_CRON_CONFIG=0 2 * * *
      - SAINET_BACKUP_RETENTION_DAYS=7

    labels:
      # URL mapping
      - "traefik.http.routers.sainet_app.rule=Host(`<to_define>`)"
      #- "traefik.http.routers.sainet_app.rule=PathPrefix(`/`)"
      
      - "traefik.http.routers.sainet_app.entrypoints=websecure"
      - "traefik.http.services.sainet_app.loadbalancer.server.port=9090"
      - "traefik.http.routers.sainet_app.tls.certresolver=le"

  sainet_db:
    restart: always
    image: mariadb:10.4
    volumes:
      - "./sainet/mariadb:/var/lib/mysql"
    environment:
      - MYSQL_DATABASE=sainet_prod
      - MYSQL_USER=dbuser
      - MYSQL_PASSWORD=dbpassword
      - MYSQL_ROOT_PASSWORD=dbroot
    command:
      - --max-allowed-packet=1024M
      - --default-time-zone=Europe/Zurich
    labels:
      - "traefik.enable=false"
  
  sainet_redis:
    restart: always
    image: redis:6-alpine
    labels:
      - "traefik.enable=false"
  
  sainet_traefik:
    restart: always
    image: traefik:v2.3
    depends_on:
      - sainet_app
    command:
      - --providers.docker
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.le.acme.email=<to_define>
      - --certificatesresolvers.le.acme.storage=/sainet/certificates/acme.json
      - --certificatesresolvers.le.acme.caserver=https://acme-v02.api.letsencrypt.org/directory
      - --certificatesresolvers.le.acme.tlschallenge=true
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "./sainet/certificates:/sainet/certificates"
    ports:
      - "80:80"
      - "443:443"
    labels:
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
      - "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"
      - "traefik.http.routers.redirs.entrypoints=web"
      - "traefik.http.routers.redirs.middlewares=redirect-to-https"

Service MariaDB

Ce service gère la base de données de SAINet.

  • La TimeZone (--default-time-zone) doit être mise à Europe/Zurich (nécessite un chargement manuel des TimeZone dans un container).
  • L’option --max-allowed-packet doit être mise à 1024M afin de pouvoir dumper/restaurer la base de données (certaines tables contiennent de gros fichiers).
  • Lors d’une mise à jour de la base, la commande mysql_upgrade doit être exécutée.
Info:

Ces opérations sont gérées automatiquement par le script sainet-up.sh.

Service Traefik

Ce service gère toutes les communications avec les requêtes externes.

  • Les connexions HTTP sont automatiquement redirigées en HTTPS.
  • En arrière-plan, les requêtes sont redirigées sur SAINet (port 9090).
  • Le certificat SSL est créé/renouvellé automatiquement (voir ci-dessous).

Certificats dynamiques

La configuration ci-dessus utilise Let’s Encrypt afin d’obtenir un certificat SSL. Celui-ci sera renouvellé automatiquement par Traefik.

Afin que le certificat SSL puisse être créé/renouvelé automatiquement, il est nécessaire que la règle de routing dans le label traefik.http.routers.sainet_app.rule permette à Traefik d’identifier l’hôte. Typiquement, voici un label qui fonctionnera:

traefik.http.routers.sainet_app.rule=Host(`sainet.mydomain.com`)

Au contraire, l’utilisation de la règle ci-dessous ne permettra pas à Traefik d’obtenir un certificat SSL valide et fournira un certificat auto-signé (qui proviquera des alertes lorsque SAINet est accédé à travers un navigateur Web):

traefik.http.routers.sainet_app.rule=PathPrefix(`/`)
Note:

Lorsque la règle Host(sainet.mydomain.com) est utilisée, il ne sera pas possible d’accéder à SAINet via une autre URL que https://sainet.mydomain.com (typiquement localhost), Traefik retournera une erreur 404. Dans ce cas, il faudra temporairement utiliser la règle PathPrefix('/').

Certificats statiques

Lorsque les certificats ne sont pas renouvelables automatiquement via Let’s Encrypt ou un autre organisme supporté par traefik, il est possible de configurer ce dernier pour utiliser des certificats statiques. Pour ce faire, appliquer la procédure suivante (dans le service sainet_traefik):

  1. Enlever toutes les options --certificatesresolvers.*.
  2. Ajouter l’option --providers.file.directory=/certificates/config juste après l’option --providers.docker.
  3. Ajouter le volume ./sainet/certificates:/certificates.
  4. Créer les dossiers sainet/certificates/config et sainet/certificates/files.
  5. Placer les fichiers pem et key dans sainet/certificates/files.
  6. Créer le fichier sainet/certificates/config/tls.yml avec le contenu suivant (ajuster <file> avec les noms de fichiers corrects):
tls:
  certificates:
    - certFile: /certificates/files/<file>.pem
      keyFile: /certificates/files/<file>.key

Création des containers

Pour créer les différents containers:

docker-compose pull
docker-compose up -d

Une fois le serveur SAINet démarré, il est possible de se connecter à SAINet avec les identifiants saierp / bootStrap373746.

Info:

Pour suivre les logs de démarrage du service SAINet, utiliser la commande docker logs -f $(docker ps | grep sainet_app | awk '{print $1}')

Mise à jour majeure

Attention:

Il est fortement recommandé de faire une sauvegarde de la base de données avant toute mise à jour majeure !

Afin d’appliquer une mise à jour majeure, il suffit de changer la version du container SAINet dans docker-compose.yml et de relancer la commande docker-compose up -d. La nouvelle version sera automatiquement téléchargée et appliquée.

Importation

Dans un processus de migration (typiquement pour la préparation d’une mise à jour majeure), il est nécessaire de pouvoir importer les données actuellement en production sur un serveur de test. Une fois les données remontées, il suffit de redémarrer le container sainet_app et ce dernier appliquera automatiquement les mises à jour nécessaires.

Note:

La base de données importée doit provenir d’un serveur avec une version antérieure ou égale à celui déployé dans le container, sinon ce dernier refusera de démarrer.

Concernant la GED, les fichiers peuvent simplement être copiés dans le répertoire ./sainet/app/runtime/edms/ged.

Version actuelle

Dans un container docker, il est possible d’obtenir la version actuelle de SAINet avec la commande suivante:

docker exec <container_id> java -jar /sainet/sainet-server.jar --version
Info:

Le <container_id> peut être obtenu avec la commande docker ps --filter "name=sainet_app" --format "{{.ID}}".

Mise à jour forcée

Si la mise à jour doit vraiment être forcée, la solution la plus simple consiste à supprimer le fichier ./sainet/app/sainet-server.jar et à relancer le container. Cela provoquera le téléchargement de la dernière version mineure du type de version configuré. Pour ce genre de cas, il est donc conseillé de spécifier SAINET_UPDATE_MODE=rc (voire même SAINET_UPDATE_MODE=snapshot si nécessaire) afin que le container puisse redémarrer sur une version plus récente et évite de forcer un rollback.

Attention:

Avec cette procédure, la mise à jour sera forcée, même si la base de données est plus récente. Cela peut provoquer un rollback de certaines modifications et conduire à des incohérences.

En utilisant le projet, il est possible de faire cela en utilisant la commande suivante:

./sainet-up.sh --force-update

Sauvegarde

Lorsque la configuration complète est utilisée, tous les fichiers persistants se trouvent dans le répertoire ./sainet. Par conséquent, ce répertoire peut simplement être copié sur un emplacement physique différent.

Info:

Selon la valeur des variables SAINET_BACKUP_RETENTION_DAYS et SAINET_BACKUP_UPDATE_ENABLED, les sauvegardes automatiques de la base de données sont conservés dans ./sainet/app/backups et ./sainet/app/update_backups.

Sauvegarde manuelle

Il est possible d’effectuer une sauvegarde manuelle de la base de données avec la commande suivante:

docker exec <container_id> /bin/bash /bin/backup.sh
Note:

Le nom du fichier de sauvegarde ne contenant que la date du jour, si la commande est lancée plusieurs fois, la sauvegarde du jour sera écrasée.

Restauration

Pour restaurer une sauvegarde complète, il suffit de remettre le contenu sauvegardé du dossier ./sainet en place et de simplement relancer les containers avec la commande docker-compose up -d.