-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Première dockerization #32
base: master
Are you sure you want to change the base?
Conversation
Merci pour ce gros boulot ! Il me reste à tester tout cela. B. |
De façon générale, si les modifs du pull request n'induisent pas de régressions dans le master, l'inclusion dans le master est de mise = principe KISS. Pour le cas particulier de ce PR, le seul impact réel du commit est la création d'un fichier config par défaut qui court-circuite la partie de procédure d'install visant à construire une config et à initialiser la base. Ces parties sont maintenant prises en charge par docker. Il ne reste plus dans l'install d'origine que la partie initialisation applicative d'utilisée (actuellement réduite à créer un premier utilisateur applicatif). Vue la simplicité et l'efficacité d'une dockerisation, la procédure ainsi remplacée s'en trouvé dépréciée de fait. On peut même se poser la question de sa suppression à moyen terme si aucun cas d'usage ne la justifiant se présente. Car il n'est jamais trés bon d'avoir du code d'install méllangé au code applicatif, surtout s'il est ancien ou peu utilisé. En complément, l'approche dockerisée permet de documenter clairement les étapes nécessaire à l'installation de EHR pour permettre une personalisation de la procédure (modification ou dérivation). Ceci est démontré dans la dockerisation du module GynObs qui a été facile et rapide. Le même processus peut être appliqué à tous les mods actuels ou à venir. En synthèse :
Cdt, |
Bon, j'ai peur que cela ne soit pas aussi simple :-) B. |
…rations & add docker in docker setup
J'ai mis à jour la branche bugeaud/MedShakeEHR-base afin qu'il soit compatible avec le principe actuel de chargement de la configuration. En complément d'un ensemble de docker compose, on a également une version "docker-in-docker" qui propose un conteneur unique (cf. scriptes "single") ainsi qu'un Dockerfile par défaut. Ceci va nous permettre d'instancier des Medshake EHR à la volée/demande via les services cloud. Le README est mis à jour en conséquence. Le principe général : un système de substitution de variables effectue le remplacement automatique (lors de la phase de config) des fichiers identifié par un suffixe +envsubst. Il crée ainsi des fichiers de configuration "legacy" sur la base des variables d'environement EHR_* correspondant aux différents besoins. Ceci permet de conteneriser sans toucher à l'existant. Bon tests |
Bonjour B. |
Bonjour Bertrand, RTFM ;-) Focalises dans un premier temps la conf Docker, et laisse de coté la Docker-in-Docker. Je pense qu'il serait interessant de faire un point audio pour vous présenter tout ceci de vive voix dans les jours/semaines à venir. ++ |
Salut B. |
Oups, j'ai utilisé un type expression qui n'est effectivement pas disponible sur tout les shells. Pour contourner temporairement et continuer ton test, tu peux modifier la 1e ligne : Je ferais des tests pour voir si je peux faire un plus simple eval à la place qui marche sur un maximum de shells. Dans le cas contraire, je ferais un commit avec le forçage à bash pour l'instant sur les scripts. Dis-moi si tu vois d'autres soucis ... ++ |
J'ai fait un commit pour corriger ce point. Pour l'instant j'ai laissé Bash en requis. Si celà pose un soucis, le scripte pourra être repris plus tard car il y a peu d'adhérence avec le reste de la dockerisation. |
De nouveau bloqué : ./docker-ehr-prepare.sh Et pas de retour du prompt. B. |
Grr. Effectivement, si la config n'a pas de dhclient, le test ne peut pas passer. Par contre l'absence d'invite est surprenante ... J'ai corrigé le test dans mon master. Sachant que je n'ai pas vu de solution portable pour obtenir le premier dhcp de résolution ... ceux qui ne seront pas en dhclient n'auront pas de contournement automatique du problème de EAI_RETRY pour l'instant. Pour info, ce problème apparait sur certains hébergement qui ont une limitation de la bande passante vers les DNS public de posé au niveau des hébergeurs. ++ |
Un peu chinois pour moi la réponse. Mon test est fait sur une mint 19. Je vais essayer de comprendre ce qui manque. (Je serais un peu moins réactif ce mois d’août concernant l'EHR car je dois upgrader medshake.net) . B. |
Re, Si tu lance cette appli docker sur une serveur maison ou chez un hébergeur qui n'a pas cette contrainte, le forçage du DNS local n'est pas un pré-requis. |
… override scripts in child images.
Je l'ai pourtant de opérationel sur 2 environements : 1 env dev Jammy/docker direct et prod 1 env jammy/lxc/docker depuis plusieurs années. Il peut toujours y avoir un delta mais je ve vois pas lequel. L'avez-vous testé aussi sans virt pour confirmer que c'est KO sur debian bare aussi ? |
Je n'ai pas de machine physique à réinstaller sans données sensibles actuellement donc je ne pourrai pas. J'avais testé il y a 2-3 ans sans aboutir sur une machine physique, mais je ne me rappelle plus si c'était le même problème. Je peux à la rigueur tester sur une VM VirtualBox, et un conteneur LXC, mais j'ai retesté d'autre projet sur la VM et |
J'ai avancé sur les tests : Ubuntu desktop live CD ça marche et j'aboutis. Debian 11 netinstall (avec environnement Gnome 3) ça marche et j'aboutis. Dans les deux les scripts du DNS s'exécutent bien avec le message final |
Ajout de section build automatique
Je retrouve un peu de temps pour pouvoir contribuer. |
j'ai corrigé le souci de volume et j'ai mis à jour l'image en 7.3 |
Le problème de EHR est la nécessité de modifier le fichier de config positionné pour avoir un lancement initial pour la partie web en gardant un entrypoint le plus simple/basique possible. Car les JSON contrairement aux .conf d'Apache HTTP ne permettent pas de directement récupérer les valeurs d'une variable d'env. Au minimum il faut utilisateur et mdp vers la base et idéalement le nom du serveur/vh. Sachant que le reste des paramètres sont ensuite récupérés en base. J'ai testé une approche par surcharge par ENV des fichiers de config sur API-CCAM-NGAP dans le cadre de l'automatisation car elle est similaire dans son fonctionnement à EHR (voir https://github.com/bugeaud/API-CCAM-NGAP/blob/master/public_html/index.php#L49-55 ) et nécessaire en plus à EHR pour les tarifs automatiques. A date, l'automatisation fonctionne déjà sur la partie CCAM via un simple docker-compose up et des deux images sur dockerhub (web et db). Il me reste à automatiser la partie NGAP et documenter le tout. Ensuite je reviendrais sur ce PR d'EHR pour faire une intégration similaire mais avec un préfixe spécifique de variable type "EHR_" et supprimer les scripts qui seront devenues obsolètes. On aura ainsi un ensemble propre et automatisé : EHR, API, ORTHANC Un peu comme Orthanc, je pense qu'il nous faut anticiper plusieurs images pour EHR, une "all" avec un maximum de mods ajoutés lors du BUILD et des variantes par spécialités avec base et le mod de la spécialité pour ceux qui veulent optimiser leur stockage. |
Pour l'entrypoint j'ai fait comme ça pour passer les variables : #!/bin/bash
set -e
if [ ! -e /var/www/html/public_html/index.php ]; then
echo "Copie de MedShakeEHR ..."
cp -pr /usr/src/medshakeehr/* /var/www/html/
cd /var/www/html && \
composer install -n --no-plugins --no-scripts --no-cache --no-ansi --no-progress --no-dev -o && \
cd public_html && \
composer install -n --no-plugins --no-scripts --no-cache --no-ansi --no-progress --no-dev -o
fi
if [ ! -e /var/www/html/config/config.yml ]; then
echo "Configuration absente, création ..."
echo "
sqlRootId: ""
sqlRootPwd: ""
sqlNotCreatDb: true
protocol: $PROTO://
host: $VIRTUAL_HOST
port: $PORT
urlHostSuffixe: ""
webDirectory: /var/www/html/public_html/
stockageLocation: /var/www/html/stockage/
backupLocation: /var/www/html/backups/
workingDirectory: /var/www/html/public_html/workingDirectory/
cookieDomain: $VIRTUAL_HOST
cookieDuration: $COOKIED
fingerprint: $FINGERPRINT
sqlServeur: db
sqlBase: $MYSQL_DATABASE
sqlUser: $MYSQL_USER
sqlPass: $MYSQL_PASSWORD
sqlVarPassword: $SQLVARPSWD
templatesFolder: /var/www/html/templates/
twigEnvironnementCache: false
twigEnvironnementAutoescape: false
twigDebug: false
configForm: ""
" > /var/www/html/config/config.yml
fi
uid="$(id -u)"
if [ "$uid" = 0 ]; then
chown -R www-data:www-data /var/www/html/
fi
exec "$@" |
Bon, comme vous avez vu, j'ai lavé mon cerveau ces derniers jours en faisant pas mal de choses sur le code PHP. |
Il n'y a pas de problème à utiliser une base pour stocker des paramètres applicatifs surtout si cette application a une approche de progiciel ( cas de EHR) et doit rester à la main le plus possibles de non techniciens tels des utilisateurs finaux. C’est donc un bon choix général pour ce type de logiciel.
La question est : où mettre ces paramètres pré-requis d’une façon simple, accessible mais la plus sécurisée possible ? Ces paramètres doivent être connus de l’administrateur technique (personne ou système automatisé) et ils ne doivent pas être modifiés par d’autres administrateurs. Dans le cas présent les paramètres peuvent théoriquement être stockés en base ou dans le fichier de config YML. Actuellement, nous avons l’ordre suivant de précédence des paramètres (par ordre de priorité, inverse de l’ordre de chargement) :
Dans l’application API-CCAM-NGAP, j’ai introduit (pour test) une nouvelle possibilité, la surcharge par variable d’environnement, nous obtenons ainsi l’ordre de précédence :
Cette approche m’a permis de positionner les paramètres pré-requis au lancement via les variables d’environnement selon le besoin et de garder un fichier de config le plus générique pouvant être librement mis à la main d’un utilisateur technique qui peut le personnaliser selon ces besoins sur les autres paramètres. Les autres administrateurs gardant enfin le contrôle sur la surcharge via l'IHM. La dockerisation proposée par @marsante s’appuie sur la génération au lancement du conteneur (de l’app si tu préfères) pour générer un fichier config.yml minimum à la volée. Cette approche plus simple de premier abord ne différentie pas les paramètres pré-requis des autres. Car du fait de l’absence de mécanisme de surcharge dans les fichier YML, l’utilisateur qui veut changer d’autres paramètres du config.yml (hors ceux pré-requis) via config.yml va devoir reprendre en main l’ensemble du fichier (contenant aussi les fameux pré-requis à la main du mécanisme de lancement) ainsi que modifier le mécanisme de lancement pour surcharger le fonctionnement par défaut. Ceci est plus compliqué a gérer et mélenge les genres entre le périmètre applicatif et son déploiement (ici docker). Enfin par exemple, une simple erreur de formatage du config YML va empêcher purement et simplement le chargement de l’application. Les paramètres pré-requis sont généralement gérés de de façons dans docker via :
Je pense qu’il serait intéressant de rajouter dans EHR la récuparation des paramètres pré-requis par variable d’environnement sur le modèle du test de API-CCAM-NGAP, ainsi que de clarifier :
Ceci permettra de simplifier tout lancement automatisé initial de l’application qu’il soit dans ou hors docker. La nette séparation entre paramètres pré-requis et autres permettra aussi de simplifier la gestion et la maintenance des instances de EHR en limitant les erreurs et les opérations. |
Pour mon implémentation, il n'y a rien besoin de plus. Ou à la rigueur la présence d'un équivalent wp-content pour WordPress où serait rangé l'ensemble des modules, des plugins, fichiers personnalisés. Je pense pouvoir proposer un script prochainement pour directement récupérer les mises à jour et modules via l'interface (par contre, je suis nul en interface, il faudra probablement m'aider dessus). Concernant les avantages de mon image, elle est construite suivant les recommandations de l'image php et n'embarque que le strict nécessaire (830mo). Le ssl, la base de donnée sont gérées par des images officielles. Ça permet de retirer les scripts bash externes, de limiter la maintenance du projet et de bien compartimenter. L'image par ailleurs est lançable sur Windows et macOS ce qui ouvre la possibilité de développer à d'autre écosystème. J'ai optimisé aussi la mise en cache des layers pour que l'image soit plus rapidement buildable et plus économe en ressource. Il n'y a pas besoin de modifier la structure du dépôt du projet. Je peux le proposer comme pour le dossier vagrant dans un dossier ou dans un repo séparé. Mon image peut être lancée avec un docker lancé en root, mais via l'utilisateur non privilégié www-data, ou avec un utilisateur arbitraire ou avec une installation docker rootless. Le config.yml utilise des variables pour les principaux réglages. Je peux en rajouter au besoin et surtout, elles peuvent être très simplement surchargée, en faisant un docker cp dans un sens puis dans l'autre. Une fois configuré le container n'y touche plus. J'essayerai les secrets dans la semaine voir si ça peut marcher sans modification.
Pour tester le projet, c'est toujours là https://github.com/marsante/MedShakeEHR-docker-compose
|
J'ai testé les secrets files sur ma stack ça fonctionne. J'ai ajouté à la stack Watchtower pour automatiser les mises à jour des images, phpMyAdmin pour ceux qui en auraient besoin, Wireguard si besoin d'un VPN. @MedShake j'ai également testé Orthanc, pour le moment, c'est une installation sans mots de passe sur un réseau à part accessible que par le conteneur MedShakeEHR. Je n'ai pas trouvé comment passer un utilisateur et un mot de passe dans l'interface de MedShakeEHR ? |
Je viens de penser qu'on peut également comme l'image orthanc, passer le fichier config.yml comme un secret. Dans ce cas-là, il faudra générer dans l'image de base un fichier de configuration exemple, pour que l'utilisateur puisse l'importer facilement sur sa machine avant de le modifier et de le passer dans sa stack. Je ne sais pas ce qui est le mieux entre les deux solutions ? |
Question : la v8 semble mure. Que faut il y intégrer pour la dockerisation et ce qui tourne autour y soit présent ? |
Pour la dockerisation, tout roule finalement de mon côté. Comme je respecte les recommandations des mainteneurs de l'image officielle php, j'avais construit avec le module php mysqli au lieu de pdo_mysql. Les images de la v8 en php8.1 et php8.2 sont dispos sur dockerhub pour tester. @bugeaud ne devrait pas avoir ce problème, car il utilise le paquet d'Ubuntu qui empaquète les deux modules. Je n'ai pas testé par contre. Le bug de la page des tâches planifiées commun à toutes les dockeurisations de MedShakeEHR et présente aussi sur les conteneurs LXC est toujours présent, mais non dépendant de la v8. |
Concrètement, faut-il que je merge ce PR et ça sera bon ? |
A priori oui, mais je n'ai pas eu le temps de tester, la mise en place de cette implémentation est assez longue. |
J'ai enfin eu le temps de me poser sur la problématique d'installation, mise à jour des modules dans le container. J'ai fait un script qui utilise les mécanismes déjà existant dans le logiciel. <?php
// Check if the required argument is provided
if ($argc < 2) {
echo "Usage: php msehr.upgrade.php <repo>\n\n base, chiro, gyneco, general, thermal, mpr, osteo\n";
exit(1);
}
// Extract the shorthand repo argument
$repoShorthand = $argv[1];
// Define a mapping of shorthand names to GitHub user/repo
$repoMap = [
'base' => 'MedShake/MedShakeEHR-base',
'chiro' => 'MedShake/MedShakeEHR-modChiro',
'gyneco' => 'MedShake/MedShakeEHR-modGynObs',
'general' => 'MedShake/MedShakeEHR-modMedGe',
'thermal' => 'MedShake/MedShakeEHR-modMedTher',
'mpr' => 'MedShake/MedShakeEHR-modMPR',
'osteo' => 'marsante/MedShakeEHR-modOsteo',
];
// Check if the repo shorthand exists in the map
if (!isset($repoMap[$repoShorthand])) {
echo "Invalid repo shorthand.\n";
exit(1);
}
// Extract the user and repo from the repo map
$repoInfo = explode('/', $repoMap[$repoShorthand]);
$user = $repoInfo[0];
$repo = $repoInfo[1];
try {
// Extract the database credentials from config.yml
$configFile = '/var/www/html/config/config.yml';
$config = yaml_parse_file($configFile);
$sqlServer = $config['sqlServeur'];
$sqlBase = $config['sqlBase'];
$sqlUser = $config['sqlUser'];
$sqlPass = $config['sqlPass'];
// Update the value of the 'state' column in the 'system' table
$dsn = "mysql:host=$sqlServer;dbname=$sqlBase;charset=utf8mb4";
$pdo = new PDO($dsn, $sqlUser, $sqlPass);
// Set PDO error mode to exception
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "UPDATE system SET value = 'maintenance' WHERE name = 'state'";
$pdo->exec($sql);
// Retrieve the latest release tag name using cURL
$apiUrl = "https://api.github.com/repos/$user/$repo/releases/latest";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3');
$response = curl_exec($ch);
curl_close($ch);
$releaseData = json_decode($response, true);
$latestRelease = $releaseData['tag_name'];
// Print the latest release tag name
echo "Dernière version : $latestRelease\n";
// Download and extract the release from GitHub
$version = substr($latestRelease, 1); // Remove the 'v' prefix
$tarFile = "/tmp/$latestRelease.tar.gz";
$downloadUrl = "https://github.com/$user/$repo/archive/$latestRelease.tar.gz";
// Download the release tar.gz file using cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $downloadUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
curl_close($ch);
// Save the downloaded tar.gz file
file_put_contents($tarFile, $response);
// Extract the release contents using tar
$extractDir = "/tmp/$repo-$version";
$extractCommand = "tar -xzf $tarFile -C /tmp";
exec($extractCommand);
// Move the extracted files to the target directory
$moveCommand = "cp -r -f $extractDir/* /var/www/html/";
exec($moveCommand);
// Print a success message
echo "La copie c'est bien déroulée, connectez vous à votre compte administrateur pour appliquer la mise à jour.\n";
} catch (Exception $e) {
// Handle any errors
echo "Erreur: " . $e->getMessage() . "\n";
}
?> Ça copie la dernière version du module concerné et met medshakeehr en mode maintenance. En se déconnectant / connectant en tant qu'admin ça met à jour / installe. Les droits ont l'air d'être ok que ce soit exécuté par root ou un utilisateur arbitraire. J'ai testé sur Linux, Windows et macOS avec succès. Je suis toujours aussi mauvais en PHP il y a probablement moyen de faire plus propre. Pour tester : git clone https://github.com/marsante/MedShakeEHR-docker-compose
cd MedShakeEHR-docker-compose
cp sample.env .env
nano .env
nano docker-compose.yml
docker-compose up -d
ou
docker compose up -d puis rendez-vous sur https://msehr.localhost/install.php pour configurer le premier utilisateur admin ensuite pour mettre à jour / installer : docker exec -ti msehr php /usr/local/bin/msehr.upgrade.php base les arguments disponibles sont : base, chiro, gyneco, general, thermal, mpr, osteo J'avais commencé à nettoyer aussi le projet de bugeaud, mais j'ai peur que ça passe par une phase d'incompatibilité avec le projet existant donc j'ai arrêté. Concernant le script est ce qu'il serait intéressant de le livrer directement dans les scripts du module base ? |
Cette branche effectue une dockerisation.
3 conteneurs sont créés :
Un fichier config.yml par défaut est créé. Ceci court-circuite de de fait certaines phases de l'installation classique.
Le README a été mis à jour pour détailler l'installation via Docker.
Hormis la modification de quelques fichiers de configuration (identifiant base, mot de passe base, hachés et nom d'hôte), la procédure est automatique.
Un problème connu a été identifié : lors du premier "docker-compose up", un répertoire de log pour apache2 n'est pas créé automatiquement. La procédure de contournement est documentée (création du répertoire et relancement du "up").