Aller au contenu principal

OpenEMR sur GKE Autopilot

OpenEMR sur GKE Autopilot

OpenEMR est le système open source de dossiers médicaux électroniques (DME) et de gestion de cabinet le plus largement adopté au monde, utilisé par plus de 100 000 professionnels de santé dans plus de 100 pays. Ce module déploie OpenEMR sur GKE Autopilot au-dessus du socle App_GKE, qui provisionne et gère l'infrastructure Google Cloud et Kubernetes partagée.

Ce guide se concentre sur les services cloud qu'utilise OpenEMR et sur la manière de les explorer et de les exploiter depuis la console Google Cloud et la ligne de commande. Pour les mécanismes communs à toutes les applications GKE — Workload Identity, ingress, autoscaling, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC Service Controls, sauvegardes et cycle de vie du déploiement — reportez-vous au guide du socle App_GKE plutôt que de les répéter ici.


1. Vue d'ensemble​

OpenEMR s'exécute comme une charge de travail Apache/PHP 8.3 FPM sur Alpine 3.20. Le déploiement assemble un ensemble ciblé de services Google Cloud :

FonctionnalitéService Google CloudRemarques
CalculGKE AutopilotPods Apache/PHP, 2 vCPU / 4 GiB par défaut, autoscaling horizontal
Base de donnéesCloud SQL for MySQL 8.0Obligatoire — OpenEMR ne prend pas en charge PostgreSQL
Documents des patientsFilestore (NFS)Répertoire sites/ contenant les documents des patients, le cache de sessions et l'état de l'application, partagé entre tous les réplicas
Stockage d'objetsCloud StorageUn bucket de données à usage général
Stockage des sessionsRedisActivé par défaut ; se rabat sur l'adresse IP du serveur NFS lorsqu'aucun hôte Redis n'est indiqué
SecretsSecret ManagerMot de passe administrateur (OE_PASS) et mot de passe de la base de données (MYSQL_PASS) générés automatiquement
IngressCloud Load BalancingLoadBalancer externe, domaine personnalisé et certificat géré en option

Valeurs par défaut judicieuses à connaître d'emblée :

  • MySQL 8.0 est obligatoire. Le moteur de base de données est imposé ; sélectionner PostgreSQL ou NONE empêche le démarrage.
  • Le NFS est obligatoire. Le répertoire sites/ d'OpenEMR — qui contient sqlconf.php, les documents des patients, les caches Twig/Smarty et les fichiers téléversés — doit se trouver sur un volume NFS partagé. L'application ne peut pas fonctionner sans lui.
  • Redis est activé par défaut. Lorsque max_instance_count > 1, un stockage de sessions partagé est nécessaire pour éviter la perte des sessions PHP entre les pods.
  • L'affinité de session est ClientIP. OpenEMR s'appuie sur les sessions PHP ; les requêtes d'un navigateur sont donc rattachées à un seul pod.
  • L'installation au premier démarrage est automatisée et lente. Lors du premier déploiement, trois jobs d'initialisation s'exécutent successivement : nfs-init (préparation du répertoire NFS), db-init (création de l'utilisateur et de la base de données MySQL) et openemr-install (installation du schéma via auto_configure.php). La sonde de démarrage laisse jusqu'à 120 secondes à l'application pour devenir prête une fois les jobs terminés.
  • Le mot de passe administrateur d'OpenEMR est généré automatiquement et stocké dans Secret Manager ; vous ne le définissez jamais en clair.
  • min_instance_count vaut 1 par défaut. La réduction à zéro n'est pas recommandée pour les systèmes de DME cliniques — les démarrages à froid ajoutent 20 à 40 secondes de latence que les cliniciens pourraient interpréter comme une panne du système.

2. Services Google Cloud et comment les explorer​

Toutes les commandes supposent que vous avez exécuté gcloud container clusters get-credentials <cluster> --region <region> --project <project> et que PROJECT, REGION et NAMESPACE sont définis. L'espace de noms et les autres identifiants sont indiqués dans les sorties du déploiement.

A. GKE Autopilot — la charge de travail OpenEMR​

Les pods OpenEMR sont planifiés sur Autopilot, qui facture le CPU et la mémoire que les pods demandent réellement. Le Horizontal Pod Autoscaling dimensionne le déploiement entre le nombre minimal et le nombre maximal de réplicas.

  • Console : Kubernetes Engine → Workloads → sélectionnez la charge de travail OpenEMR pour voir les pods, les événements et l'état des sondes. Kubernetes Engine → Services & Ingress affiche l'adresse IP externe.
  • CLI :
    kubectl get pods,svc,hpa -n "$NAMESPACE"
    kubectl logs -n "$NAMESPACE" deploy/<service-name> --tail=100
    kubectl describe hpa -n "$NAMESPACE" # current vs target utilisation

Consultez App_GKE pour savoir comment sont gérés Autopilot, le dimensionnement et le type de charge de travail (Deployment ou StatefulSet).

B. Cloud SQL for MySQL 8.0​

OpenEMR stocke toutes les données cliniques (dossiers des patients, planification, facturation) dans une instance gérée Cloud SQL for MySQL 8.0. Les pods y accèdent de manière privée via le sidecar Cloud SQL Auth Proxy par un socket Unix, si bien qu'aucune adresse IP publique n'est exposée. Lors du premier déploiement, le job db-init crée la base de données et l'utilisateur de l'application avant que le job openemr-install n'exécute l'installateur du schéma d'OpenEMR.

  • Console : SQL → sélectionnez l'instance pour les connexions, les sauvegardes, les flags et les métriques.
  • CLI :
    gcloud sql instances list --project "$PROJECT"
    gcloud sql instances describe <instance-name> --project "$PROJECT"
    # Open an interactive shell to inspect schema/data:
    gcloud sql connect <instance-name> --user=<db-user> --project "$PROJECT"

Le nom de l'instance, le nom de la base de données, l'utilisateur et le secret Secret Manager contenant le mot de passe sont tous indiqués dans les sorties. Pour le modèle de connexion, les sauvegardes automatisées et la rotation des mots de passe, consultez App_GKE.

C. Filestore (NFS) et Cloud Storage​

Le répertoire sites/ d'OpenEMR est écrit sur un partage Filestore (NFS) monté dans chaque pod sur /var/www/localhost/htdocs/openemr/sites. Ce répertoire contient sqlconf.php (qui signale la fin de l'installation), les documents téléversés pour les patients, les caches de modèles Twig/Smarty et les données de session. Tous les réplicas doivent partager le même montage NFS. Un bucket Cloud Storage à usage général est également provisionné.

  • Console : Filestore → Instances pour le partage NFS ; Cloud Storage → Buckets pour le bucket de données.
  • CLI :
    gcloud filestore instances list --project "$PROJECT"
    gcloud storage buckets list --project "$PROJECT"
    # Confirm the NFS share is mounted and sites directory exists:
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- \
    ls /var/www/localhost/htdocs/openemr/sites/default/

Consultez App_GKE pour le provisionnement NFS, GCS Fuse et les options CMEK.

D. Magasin de sessions Redis​

Redis sert de stockage aux sessions PHP d'OpenEMR. Lorsque redis_host est laissé vide et que le NFS est activé, l'instance Redis colocalisée sur le serveur NFS est utilisée automatiquement. Dans les déploiements à plusieurs réplicas, un stockage de sessions partagé est nécessaire pour éviter la perte des sessions.

  • Console : Memorystore → Redis (si vous utilisez une instance Memorystore gérée).
  • CLI :
    redis-cli -h <redis-host> ping        # from a host with network access
    redis-cli -h <redis-host> info keyspace
    # Confirm REDIS_SERVER is set inside the pod:
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- env | grep REDIS

E. Secret Manager​

Le mot de passe administrateur d'OpenEMR (OE_PASS) et le mot de passe de la base de données MySQL (MYSQL_PASS) sont stockés en tant que secrets Secret Manager et injectés dans les pods à l'exécution via le pilote Secret Store CSI. Le texte en clair n'apparaît jamais dans la configuration.

  • Console : Security → Secret Manager.
  • CLI :
    gcloud secrets list --project "$PROJECT"
    # Retrieve the admin password to log in for the first time:
    gcloud secrets versions access latest \
    --secret=<admin-password-secret-id> --project "$PROJECT"

L'ID du secret du mot de passe administrateur est exposé dans la sortie admin_password_secret_id. Le nom du secret du mot de passe de la base de données figure dans database_password_secret. Consultez App_GKE pour l'intégration Secret Store CSI et la rotation.

F. Réseau et entrée​

Par défaut, la charge de travail est exposée via une adresse IP externe Cloud Load Balancing. Un domaine personnalisé avec un certificat géré par Google peut être activé, et une adresse IP statique peut être réservée afin que l'adresse survive aux redéploiements.

  • Console : Network services → Load balancing ; VPC network → IP addresses.
  • CLI :
    kubectl get ingress,svc -n "$NAMESPACE"
    gcloud compute addresses list --project "$PROJECT"
    # Test the login page from within the cluster:
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- \
    curl -s -o /dev/null -w "%{http_code}" http://localhost/interface/login/login.php

Consultez App_GKE pour les domaines personnalisés, Cloud CDN et les détails sur les adresses IP statiques.

G. Cloud Logging et Monitoring​

Les flux stdout/stderr des pods sont envoyés vers Cloud Logging ; les métriques de GKE et de Cloud SQL sont envoyées vers Cloud Monitoring. Des tests de disponibilité et des règles d'alerte sont disponibles en option.

  • Console : Logging → Logs Explorer ; Monitoring → Dashboards / Alerting.
  • CLI :
    gcloud logging read \
    'resource.type="k8s_container" AND resource.labels.namespace_name="'"$NAMESPACE"'"' \
    --project "$PROJECT" --limit 50

3. Comportement de l'application OpenEMR​

  • Initialisation en trois étapes au premier déploiement. Les Jobs Kubernetes suivants s'exécutent successivement à chaque apply :

    JobRôleDépend de
    nfs-initPrépare l'arborescence du répertoire NFS sites/, attribue la propriété à l'UID 1000 (Apache) et restaure éventuellement une sauvegarde—
    db-initCrée la base de données MySQL et l'utilisateur de l'application—
    openemr-installExécute auto_configure.php en mode K8S=admin pour installer le schéma de la base de données et créer le compte administrateur ; écrit $config=1 dans sqlconf.php sur le NFSnfs-init, db-init

    Le pod principal de l'application ne démarre qu'une fois openemr-install terminé et $config=1 présent dans sqlconf.php — il ignore alors l'installateur et commence à servir les requêtes. Inspectez les jobs :

    kubectl get jobs -n "$NAMESPACE"
    kubectl logs -n "$NAMESPACE" job/nfs-init
    kubectl logs -n "$NAMESPACE" job/openemr-install
  • Le premier démarrage peut prendre 5 à 20 minutes. Le job openemr-install exécute l'installateur complet du schéma en PHP, qui est lent. La sonde de démarrage (TCP sur le port 80, seuil de 12 échecs) laisse 120 secondes au pod pour devenir prêt une fois les jobs terminés. Pour une installation entièrement neuve, envisagez d'augmenter failure_threshold dans la sonde de démarrage.

  • Mises à niveau tenant compte des versions. Lors des déploiements suivants, le script de démarrage compare la version de l'image à la version stockée sur le NFS et exécute automatiquement les scripts de mise à niveau appropriés (fsupgrade-N.sh).

  • Serveur temporaire de sonde de santé. Pendant la phase d'installation, openemr.sh démarre un serveur web PHP intégré sur le port 80 qui renvoie HTTP 200 sur le chemin de la sonde de santé, ce qui évite que le pod soit tué pendant l'exécution de l'installateur.

  • Connexion administrateur. Le nom d'utilisateur initial de l'administrateur est admin. Le mot de passe est généré automatiquement et stocké dans Secret Manager — récupérez-le avec :

    gcloud secrets versions access latest \
    --secret=<admin_password_secret_id> --project "$PROJECT"

    Si le compte administrateur est verrouillé après des tentatives de connexion échouées, utilisez l'utilitaire /root/unlock_admin.sh <new_password> dans le conteneur.

  • Variable d'environnement K8S=yes. L'application reçoit K8S=yes à l'exécution, ce qui indique à openemr.sh d'utiliser le chemin de démarrage adapté à Kubernetes (en évitant les opérations chown récursives et lentes qui provoqueraient des échecs par dépassement de délai).


4. Variables de configuration​

Les variables sont regroupées exactement comme elles apparaissent sur la plateforme de déploiement. Seuls les paramètres propres à OpenEMR ou notables pour lui sont listés ; toutes les autres entrées sont héritées d'App_GKE avec leur comportement et leurs valeurs par défaut standard.

Groupe 0 — Métadonnées du module​

VariableValeur par défautDescription
module_description / module_documentation / module_dependency / module_services(définie)Métadonnées du catalogue de la plateforme.
credit_cost300Crédits de la plateforme consommés par déploiement.
require_credit_purchasesfalseLorsque true, les frais de module ne peuvent être payés qu'avec des crédits achetés (abonnement ou recharge), et non avec des crédits offerts gratuits ou des crédits d'événement.
enable_purgetrueAutorise la suppression complète des ressources lors de la destruction.
public_accesstrueRend le module visible dans le catalogue public.
require_services_gcp_moduletrueÉchoue au moment du plan si aucun VPC géré par Services_GCP n'est détecté dans le projet.
shared_users / technical_support_users[]Utilisateurs auxquels l'accès est accordé / vers lesquels les demandes de support sont acheminées, quel que soit public_access.
resource_creator_identityrad-module-creator@YOUR_PLATFORM_PROJECT.iam.gserviceaccount.comCompte de service utilisé par Terraform pour créer les ressources.
impersonation_service_account""Compte de service dont l'identité est empruntée pour les scripts shell (découverte, mise en miroir des images, configuration NFS). Laissez vide pour utiliser les identifiants de l'exécuteur.
job_execution_wait_timeout900Nombre maximal de secondes pendant lesquelles un déploiement attend le job db-init avant d'interrompre l'apply.
explicit_secret_values / scripts_dir{} / ""Repris du socle, non référencés par ce module.
requires_services(create_postgres=true, create_mysql=false, create_redis=false, create_network_filesystem=true, create_google_kubernetes_engine=true, autres à false)Indique à la plateforme quelles ressources Services_GCP provisionner automatiquement pour ce module.

Groupe 1 — Projet et identité​

VariableValeur par défautDescription
project_id(obligatoire)Projet Google Cloud cible.
regionus-central1Région de la charge de travail et des ressources régionales.

Groupe 2 — Environnement de déploiement​

VariableValeur par défautDescription
tenant_iddemoSuffixe court qui rend les noms de ressources uniques par environnement.
support_users[]Adresses e-mail auxquelles sont accordés l'accès au projet et les alertes de surveillance.
resource_labels{}Libellés appliqués à toutes les ressources pour le suivi des coûts et de la propriété.

Groupe 3 — Identité de l'application​

VariableValeur par défautDescription
application_nameopenemrNom de base des ressources. Ne le modifiez pas après le premier déploiement.
application_display_name / application_description(valeurs par défaut du socle)Champs repris du socle. Non référencés — utilisez plutôt display_name / description.
application_version7.0.4Tag de version de l'image OpenEMR ; incrémentez-le pour déployer une nouvelle version.
display_nameOpenEMRNom convivial affiché dans la console et les tableaux de bord.
description(définie)Annotation de description de la charge de travail.

Groupe 4 — Exécution et mise à l'échelle​

VariableValeur par défautDescription
deploy_applicationtrueDéfinissez false pour ne provisionner que l'infrastructure.
container_image_source / container_image / container_build_config(valeurs par défaut du socle)Approvisionnement de l'image repris du socle. Non référencés — OpenEMR_Common construit toujours une image personnalisée.
enable_image_mirroringtrueMet en miroir l'image OpenEMR dans Artifact Registry pour éviter les limites de débit de Docker Hub.
container_port8080Port du conteneur repris du socle. Non référencé — main.tf impose le port 80 en dur.
container_protocolhttp1Protocole HTTP repris du socle. Non référencé.
container_resources(valeurs par défaut du socle)Objet CPU/mémoire repris du socle. Non référencé — utilisez plutôt cpu_limit/memory_limit/ephemeral_storage_limit.
cpu_limit2000mCPU par pod ; 2 vCPU recommandés pour des charges de travail cliniques concurrentes.
memory_limit4GiMémoire par pod ; 4 GiB au minimum en production.
ephemeral_storage_limit8GiStockage éphémère pour l'opcache PHP, les journaux Apache et les fichiers temporaires. GKE Autopilot plafonne le stockage éphémère total d'un pod à 10 GiB ; le sidecar Auth Proxy en utilise environ 1 GiB, ce qui laisse un maximum de 9 GiB.
min_instance_count1Nombre minimal de réplicas. Conservez une valeur ≥ 1 pour éviter les délais de démarrage à froid pour les utilisateurs cliniques.
max_instance_count1N'augmentez cette valeur qu'après avoir confirmé que le partage des sessions via Redis est opérationnel.
enable_cloudsql_volumetrueActivation du sidecar Cloud SQL Auth Proxy reprise du socle. Non référencé — openemr.tf force toujours cette valeur à true en interne.
cloud_sql_proxy_version2-alpineTag de l'image du sidecar Cloud SQL Auth Proxy.
cloudsql_volume_mount_path/cloudsqlChemin du socket de l'Auth Proxy repris du socle. Non référencé.
service_annotations / service_labels{}Annotations/libellés personnalisés du Service Kubernetes.
enable_vertical_pod_autoscalingfalseLaisse Autopilot ajuster automatiquement les demandes de ressources.
timeout_seconds300Durée maximale d'une requête en secondes (0–3600).
deployment_timeout1800Nombre de secondes pendant lesquelles Terraform attend le déploiement progressif. Allongé en raison de la longue installation d'OpenEMR au premier démarrage.

Groupe 5 — Variables d'environnement et secrets​

VariableValeur par défautDescription
environment_variables{}Paramètres supplémentaires en clair. Les valeurs de base MYSQL_* et OE_* sont définies automatiquement. Ajouts courants : PHP_MEMORY_LIMIT, SMTP_HOST, SMTP_PORT.
secret_environment_variables{}Correspondance variable d'environnement → nom de secret Secret Manager. À utiliser pour les valeurs sensibles comme les identifiants SMTP.
secret_rotation_period2592000sFréquence des notifications de rotation de Secret Manager.
secret_propagation_delay30Nombre de secondes d'attente après la création d'un secret avant de poursuivre.

Groupe 6 — Backend GKE et cluster​

VariableValeur par défautDescription
gke_cluster_name""Nom du cluster cible. Laissez vide pour la découverte automatique.
gke_cluster_selection_modeprimaryStratégie de sélection du cluster reprise du socle. Non référencé.
namespace_name""Espace de noms Kubernetes. Laissez vide pour le générer automatiquement.
prereq_gke_subnet_cidr / prereq_subnet_cidr_override / prereq_gke_pod_cidr_override / prereq_gke_service_cidr_override(dérivées automatiquement)Remplacements de CIDR pour un VPC/cluster GKE intégré lorsque Services_GCP n'existe pas encore. Sur les déploiements existants, renseignez les valeurs déjà appliquées pour éviter un remplacement.
service_typeLoadBalancerMode d'exposition du Service.
session_affinityClientIPRoutage persistant requis pour les sessions PHP d'OpenEMR.
enable_multi_cluster_servicefalseActivation de Multi-Cluster Services reprise du socle. Non référencé.
extra_service_ports[]Ports de Service supplémentaires pour les charges de travail multiprotocoles, repris du socle. Non référencé — déclaré uniquement pour la parité des conventions.
configure_service_meshfalseActive l'injection du sidecar Istio pour l'espace de noms.
enable_network_segmentationfalseCrée des ressources NetworkPolicy Kubernetes.
termination_grace_period_seconds30Nombre de secondes pendant lesquelles Kubernetes attend après SIGTERM avant SIGKILL.
workload_typenullSe résout automatiquement en StatefulSet lorsque le stockage par pod est activé.
network_tags['nfsserver']Requis pour la connectivité NFS via les règles de pare-feu VPC. Ne le supprimez pas.

Groupe 7 — StatefulSet​

VariableValeur par défautDescription
stateful_pvc_enablednullActive les modèles de PVC. OpenEMR utilise le NFS, pas des PVC — laissez non défini.
stateful_pvc_size / stateful_pvc_mount_path / stateful_pvc_storage_class10Gi / /data / standard-rwoOptions de PVC lorsque le mode StatefulSet est explicitement nécessaire.
stateful_headless_servicenullCrée un Service headless pour des identités réseau stables.
stateful_pod_management_policynullOrdre de création des pods : OrderedReady ou Parallel. OrderedReady par défaut.
stateful_update_strategynullRollingUpdate ou OnDelete. RollingUpdate par défaut.
stateful_fs_group0GID fsGroup défini dans le contexte de sécurité du pod ; 0 laisse fsGroup non défini.

Groupe 8 — Quota de ressources​

VariableValeur par défautDescription
enable_resource_quotafalsePlafonne le CPU, la mémoire et le nombre d'objets de l'espace de noms.
quota_cpu_requests / quota_cpu_limits""Total des demandes/limites de CPU autorisées pour l'ensemble des pods de l'espace de noms.
quota_memory_requests / quota_memory_limits""Doivent utiliser des unités binaires (4Gi, 8192Mi) — les entiers sans unité sont interprétés comme des octets et bloquent la planification.
quota_max_pods / quota_max_services / quota_max_pvcs""Nombre maximal de pods / Services / PVC dans l'espace de noms.

Groupe 9 — Règles de fiabilité​

VariableValeur par défautDescription
enable_pod_disruption_budgetfalseDésactivé par défaut car max_instance_count = 1 — un PDB avec min_available = 1 bloque le drainage des nœuds sur un pod unique. Ne l'activez qu'avec 2 réplicas ou plus.
pdb_min_available1Portez min_instance_count au-dessus de 1 si vous avez besoin d'une marge pour les évictions.
enable_topology_spreadfalseRépartit les pods entre les zones.
topology_spread_strictfalseLorsque true, rejette les pods (DoNotSchedule) si la contrainte de répartition entre zones ne peut pas être satisfaite, au lieu de ScheduleAnyway.

Groupe 10 — Observabilité et santé​

VariableValeur par défautDescription
startup_probe_config / health_check_config(valeurs par défaut du socle)Objets de sonde repris du socle. Non référencés — utilisez plutôt startup_probe / liveness_probe.
startup_probeTCP sur le port 80, 12 échecs × 10sSonde TCP ; laisse jusqu'à 120 secondes pour le démarrage. Augmentez failure_threshold pour les premiers déploiements avec des bases de données volumineuses.
liveness_probeHTTP GET /interface/login/login.php, 10 échecs × 30sLa page de connexion ne renvoie HTTP 200 que lorsque Apache, PHP-FPM et la connexion à la base de données sont tous opérationnels.
uptime_check_configdésactivéTest de disponibilité Cloud Monitoring facultatif.
alert_policies[]Règles d'alerte facultatives sur les métriques.

Groupe 11 — Automatisation des charges de travail​

VariableValeur par défautDescription
initialization_jobs[]Laissez vide pour utiliser la séquence intégrée nfs-init / db-init / openemr-install.
cron_jobs[]CronJobs planifiés (par exemple sauvegarde, génération de rapports).
additional_services[]Services GKE sidecar ou auxiliaires déployés aux côtés d'OpenEMR.

Groupe 12 — CI/CD et intégration GitHub​

Intégration Cloud Build / Cloud Deploy standard d'App_GKE — voir App_GKE. Entrées principales : enable_cicd_trigger, github_repository_url, github_token, github_app_installation_id, cicd_trigger_config, enable_cloud_deploy, cloud_deploy_stages, enable_binary_authorization, binauthz_evaluation_mode (mode d'application — ALWAYS_ALLOW, REQUIRE_ATTESTATION ou ALWAYS_DENY — utilisé uniquement lorsque enable_binary_authorization = true et que Services_GCP n'a pas préconfiguré la règle).

Groupe 13 — Système de fichiers (NFS)​

VariableValeur par défautDescription
enable_nfstrueDoit rester à true. OpenEMR a besoin du NFS pour le répertoire sites/.
nfs_mount_path/var/www/localhost/htdocs/openemr/sitesChemin de montage dans le conteneur. Doit correspondre au chemin du répertoire sites d'OpenEMR.
nfs_volume_namenfs-data-volumeNom du volume Kubernetes pour le montage NFS.
nfs_instance_name""VM GCE NFS existante à cibler directement. Laissez vide pour la découverte automatique.
nfs_instance_base_nameapp-nfsNom de base d'une VM GCE NFS intégrée lorsqu'il n'en existe aucune.

Groupe 14 — Cloud Storage et Artifact Registry​

VariableValeur par défautDescription
create_cloud_storagetrueProvisionne le bucket de données.
storage_buckets[{name_suffix="data"}]Buckets supplémentaires.
gcs_volumes[]Buckets GCS montés via le pilote CSI GCS Fuse.
manage_storage_kms_iam / enable_artifact_registry_cmekfalseOptions CMEK.
max_images_to_retain7Nombre maximal d'images récentes à conserver dans Artifact Registry.
delete_untagged_imagestrueSupprime automatiquement les images sans tag.
image_retention_days30Nombre de jours après lesquels les images deviennent éligibles à la suppression.

Groupe 15 — Magasin de sessions Redis​

VariableValeur par défautDescription
enable_redistrueUtilise Redis pour le stockage des sessions PHP.
redis_host""Laissez vide pour utiliser l'adresse IP du serveur NFS ; définissez-le explicitement pour une instance Memorystore dédiée.
redis_port6379Port Redis.
redis_auth""Mot de passe d'authentification Redis facultatif (sensible).

Groupe 16 — Backend de base de données​

VariableValeur par défautDescription
database_typePOSTGRESSélecteur du moteur de base de données repris du socle. Non référencé — OpenEMR_Common définit toujours MYSQL_8_0.
sql_instance_name / sql_instance_base_name"" / app-sqlCiblage de l'instance Cloud SQL repris du socle. Non référencés.
application_database_name / application_database_usergkeappdb / gkeappuserNom/utilisateur de base de données repris du socle. Non référencés — utilisez plutôt db_name / db_user.
db_nameopenemrNom de la base de données MySQL. Immuable après le premier déploiement.
db_useropenemrUtilisateur de l'application. Immuable après le premier déploiement.
database_password_length32Longueur du mot de passe généré (16–64).
enable_postgres_extensions / postgres_extensionsfalse / []Installateur d'extensions PostgreSQL repris du socle. Non référencés — OpenEMR utilise MySQL.
enable_mysql_plugins / mysql_pluginsfalse / []Installateur de plugins MySQL repris du socle. Non référencés par ce module.
enable_auto_password_rotationfalseRotation du mot de passe de la base de données sans interruption. Nécessite un redémarrage des pods pour prendre en compte le nouveau secret.
rotation_propagation_delay_sec90Nombre de secondes d'attente après la rotation avant de redémarrer les pods.
db_password_env_var_name""Variable d'environnement supplémentaire pour le mot de passe, reprise du socle. Non référencé — main.tf impose MYSQL_PASS en dur.
db_host_env_var_name / db_user_env_var_name / db_name_env_var_name / db_port_env_var_name""Noms de variables d'environnement de base de données supplémentaires repris du socle. Non référencés par ce module.

Groupe 17 — Sauvegarde et maintenance​

VariableValeur par défautDescription
backup_schedule0 2 * * *Planification cron des sauvegardes automatisées (UTC). Ne la désactivez pas pour les déploiements soumis à HIPAA.
backup_retention_days7Rétention ; portez-la à 30–90 pour la production/la conformité.
enable_backup_importfalseRestaure à partir d'une sauvegarde lors du déploiement.
backup_sourcegcsSource de l'import : gcs ou gdrive.
backup_filebackup.sqlNom du fichier de sauvegarde repris du socle. Non référencé — utilisez plutôt backup_uri.
backup_uri""URI GCS (gs://bucket/path) ou ID de fichier Google Drive. Lorsqu'il est défini, il est injecté dans nfs-init sous la forme BACKUP_FILEID.
backup_formatsqlFormat du fichier de sauvegarde : sql, tar, gz, tgz, tar.gz ou zip.

Groupe 18 — Scripts SQL personnalisés​

enable_custom_sql_scripts, custom_sql_scripts_bucket, custom_sql_scripts_path, custom_sql_scripts_use_root — exécutent du SQL depuis un bucket GCS après le provisionnement. Voir App_GKE.

Groupe 19 — Domaine personnalisé, IP statique et réseau​

VariableValeur par défautDescription
enable_custom_domaintrueProvisionne une Kubernetes Gateway pour les noms d'hôte personnalisés et un certificat géré (une Gateway avec une adresse IP statique est provisionnée automatiquement).
application_domains[]Noms d'hôte à servir. S'il est vide, un domaine nip.io basé sur l'adresse IP statique générée automatiquement est utilisé.
gateway_backend_stagedevÉtape Cloud Deploy dont le Service est ciblé par la HTTPRoute de la Gateway. Ignoré lorsque enable_cloud_deploy vaut false.
reserve_static_iptrueAdresse IP externe stable d'un redéploiement à l'autre.
static_ip_name""Nom de l'adresse IP statique réservée. Laissez vide pour le générer automatiquement.
network_name""Nom explicite du réseau VPC. Laissez vide pour découvrir automatiquement le réseau géré par Services_GCP. Non référencé par ce module.

Groupe 20 — Identity-Aware Proxy (IAP)​

VariableValeur par défautDescription
enable_iapfalseExige une connexion Google devant OpenEMR. Recommandé pour restreindre l'accès au personnel clinique.
iap_authorized_users / iap_authorized_groups[]Personnes autorisées à accéder.
iap_oauth_client_id / iap_oauth_client_secret""Obligatoires lorsque IAP est activé (sensibles).
iap_support_email""Affiché sur l'écran de consentement OAuth.

Groupe 21 — Cloud Armor​

VariableValeur par défautDescription
enable_cloud_armorfalseAssocie une règle Cloud Armor (WAF) au backend de l'Ingress.
admin_ip_ranges[]CIDR autorisés pour l'accès privilégié.
cloud_armor_policy_namedefault-waf-policyNom de la règle.
enable_cdnfalseActive Cloud CDN via GCPBackendPolicy sur le backend de l'Ingress GKE.

Groupe 22 — VPC Service Controls et journalisation d'audit​

VariableValeur par défautDescription
enable_vpc_scfalseImpose un périmètre VPC-SC. Nécessite que organization_id soit défini explicitement. Recommandé pour les environnements HIPAA.
vpc_cidr_ranges / vpc_sc_dry_run(définies)CIDR du niveau d'accès / mode simulation (dry-run).
enable_audit_loggingfalseJournaux Cloud Audit Logs détaillés (DATA_READ, DATA_WRITE). Recommandé pour la conformité HIPAA.

5. Sorties​

Ces valeurs sont renvoyées à l'issue d'un déploiement réussi et constituent le moyen le plus rapide de localiser et d'explorer les ressources en cours d'exécution.

SortieDescription
service_nameNom du Service Kubernetes.
namespaceEspace de noms dans lequel s'exécute la charge de travail.
service_cluster_ipClusterIP interne au cluster.
stage_service_cluster_ipsCorrespondance des ClusterIP des services propres à chaque étape (Cloud Deploy).
service_external_ipAdresse IP externe du LoadBalancer (lorsqu'une adresse IP statique est réservée).
service_urlURL permettant d'accéder à OpenEMR.
admin_password_secret_idID du secret Secret Manager contenant le mot de passe administrateur d'OpenEMR (OE_PASS).
database_instance_nameNom de l'instance Cloud SQL.
database_nameNom de la base de données de l'application.
database_userUtilisateur de la base de données de l'application.
database_password_secretSecret Secret Manager contenant le mot de passe de la base de données (MYSQL_PASS).
database_host / database_portPoint de terminaison de la base de données (127.0.0.1 via l'Auth Proxy) / port.
nfs_server_ipAdresse IP interne du serveur NFS (sensible).
nfs_mount_pathChemin de montage NFS dans le conteneur.
nfs_share_pathChemin du partage NFS sur le serveur.
nfs_setup_jobNom du job de configuration NFS.
storage_bucketsBuckets Cloud Storage créés.
network_name / network_exists / regionsRéseau VPC, présence, régions disponibles.
container_image / container_registryImage déployée et dépôt Artifact Registry.
monitoring_enabled / monitoring_notification_channelsÉtat de la surveillance et canaux.
initialization_jobs / db_import_jobNoms des jobs de configuration et d'import (facultatif).
deployment_id / tenant_id / resource_prefixIdentifiants de nommage.
project_id / project_numberIdentifiants du projet.
cicd_enabled / cicd_configurationÉtat et détails du CI/CD (dépôt, déclencheur, registre).
github_repository_url / github_repository_owner / github_repository_nameDétails du dépôt GitHub.
artifact_registry_repository / cloudbuild_trigger_name / cloudbuild_trigger_idRegistre et déclencheur de build.
kubernetes_readyIndique si le cluster/la charge de travail est prêt.
vpc_sc_enabled / vpc_sc_perimeter_name / vpc_sc_dry_run_modeÉtat de VPC-SC.
audit_logging_enabled / artifact_registry_cmek_enabledÉtat de la journalisation d'audit et de CMEK.

6. Pièges de configuration et valeurs par défaut judicieuses​

Risque : Critique (perte de données / panne / sécurité) — Élevé (> service dégradé) — Moyen (coût ou dégradation partielle) — Faible (> mineur).

ParamètreValeur judicieuseRisqueConséquence en cas d'erreur
enable_nfstrueCritiqueOpenEMR ne peut pas fonctionner sans NFS. Le répertoire sites/, sqlconf.php et les documents des patients résident tous sur le NFS. Le désactiver provoque un échec immédiat au démarrage.
nfs_mount_path/var/www/localhost/htdocs/openemr/sitesCritiqueDoit correspondre au chemin du répertoire sites d'OpenEMR. En cas de non-concordance, openemr-install écrit sqlconf.php à un emplacement que le pod principal ne vérifie jamais — le pod attend indéfiniment la fin de la configuration.
database_type (via OpenEMR_Common)MYSQL_8_0CritiqueOpenEMR nécessite MySQL ; PostgreSQL ou NONE casse l'installateur et tous les appels PHP à la base de données.
db_name / db_userdéfini une foisCritiqueImmuables après le premier déploiement ; les renommer recrée la base de données/l'utilisateur et détruit toutes les données des patients.
enable_backup_importfalse sauf en cas de restaurationCritiqueL'activer sans backup_uri valide fait échouer le job d'import et peut corrompre le répertoire sites sur le NFS.
quota_memory_requests / _limitsunités binaires (4Gi)CritiqueLes entiers sans unité sont des octets et bloquent toute planification des pods.
backup_schedule0 2 * * *CritiqueDésactiver les sauvegardes d'un DME contenant des PHI constitue une violation de la conformité HIPAA.
ephemeral_storage_limit8GiCritiqueOpenEMR écrit l'opcache PHP, les journaux Apache et les fichiers temporaires dans la couche du conteneur. La valeur par défaut de 1 GiB de GKE Autopilot est insuffisante — le pod est évincé pendant le démarrage.
enable_redistrueÉlevéAvec plus d'un réplica, des sessions PHP isolées par pod provoquent des échecs de connexion et des pertes de session.
redis_host"" (NFS) ou expliciteÉlevéUn hôte Redis inaccessible provoque des échecs de session PHP et empêche toute connexion.
memory_limit4GiÉlevéLa génération de PDF et les rapports de facturation d'OpenEMR sont gourmands en mémoire. Moins de 2 GiB provoque des arrêts OOM en cours de requête.
session_affinityClientIPÉlevéSans persistance, les déploiements à plusieurs réplicas perdent l'état des sessions entre les requêtes.
min_instance_count1ÉlevéLa réduction à zéro entraîne des délais de démarrage à froid de 20 à 40 secondes — inacceptables pour l'accès clinique.
enable_pod_disruption_budgetà activer lorsque min_instance_count > 1ÉlevéDésactivé par défaut car max_instance_count = 1 — un PDB bloquerait définitivement le drainage des nœuds sur un déploiement à pod unique. Activez-le lorsque vous dépassez un réplica.
backup_retention_days7 (à augmenter en production)MoyenLes environnements soumis à HIPAA doivent conserver au moins 90 jours.
enable_iap / enable_cloud_armorà activer dans le secteur de la santéMoyenL'interface d'administration d'OpenEMR est accessible publiquement sans ces contrôles.
enable_audit_loggingtrue pour HIPAAMoyenHIPAA exige la journalisation d'audit des accès aux PHI.
enable_vpc_scdéfinir organization_id explicitementMoyenSans ID d'organisation explicite, VPC-SC ignore silencieusement la création du périmètre — ce qui donne un faux sentiment de sécurité.
container_image_source / container_port / container_resources / database_type / application_database_name / db_password_env_var_name (Groupe 4/16/10)laisser la valeur par défautFaibleCes variables reprises du socle ne sont déclarées que pour la parité avec check_conventions.py et ne sont pas transmises par main.tf — les modifier n'a aucun effet. Utilisez plutôt cpu_limit/memory_limit/ephemeral_storage_limit, db_name/db_user et startup_probe/liveness_probe.

Pour le comportement du socle mentionné tout au long de ce guide — IAM et Workload Identity, autoscaling, ingress et certificats, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC-SC, sauvegardes et mise en miroir des images — consultez App_GKE. La configuration applicative propre à OpenEMR partagée avec la variante Cloud Run est décrite dans OpenEMR_Common.

Need RAD to do something it does not do yet? Request it on the roadmap, or vote on what is already there.