Pour les environnements Microsoft Dynamics, installez DQE One Standalone sur Azure Container Instance (ACI) avec une base Azure Database for PostgreSQL managée, sans conteneur de base de données dédié.
Remarque : tous les éléments décrits ci-dessous sont des recommandations de DQE, basées sur l'expérience de déploiement auprès de différents clients. Le client est responsable de l'intégration de la solution dans sa propre architecture. Un architecte connaissant le contexte client et l'infrastructure interne doit aligner les recommandations de DQE avec l'infrastructure du client.
1. Architecture
Ce document décrit comment déployer le backend DQE One Standalone sous forme de groupe de conteneurs Azure Container Instance (ACI). Tous les conteneurs du groupe partagent le même espace de noms réseau et communiquent via localhost. Un Application Gateway expose l'application en HTTPS et route le trafic vers l'ACI via un VNET privé.
Architecture recommandée
Internet (HTTPS port 443)
|
Application Gateway (public IP + WAF)
|
Private VNET subnet
|
ACI Container Group (private IP)
|
NGINX sidecar (port 80, internal)
|
DQE One Standalone (port 8000, internal)
|
Redis (internal)
|
Azure Database for PostgreSQL (private VNET)Mesures de sécurité
- Application Gateway : termine le HTTPS et route le trafic vers l'ACI via le VNET privé. Utilisez le WAF pour restreindre les plages d'adresses IP entrantes.
- VNET : isole l'ACI de tout accès direct depuis l'internet public. Tout le trafic provenant de l'Application Gateway transite par un sous-réseau privé.
- Certificat SSL : géré au niveau de l'Application Gateway ou au niveau de NGINX à l'intérieur de l'ACI.
-
Secrets : utilisez
secureValuedans le YAML du groupe de conteneurs pour toutes les valeurs sensibles (mots de passe, clés de licence, clés de chiffrement).
Dimensionnement recommandé
| Conteneur | CPU | Mémoire |
|---|---|---|
| nginx | 0.25 vCPU | 0.5 Go |
| redis | 0.5 vCPU | 1.0 Go |
| dqeone | 1.0 vCPU | 2.0 Go |
| Total | 1.75 vCPU | 3.5 Go |
Les groupes de conteneurs ACI sont limités à 4 vCPU et 16 Go de mémoire par groupe.
PostgreSQL est hébergé sur Azure Database for PostgreSQL (en dehors du groupe de conteneurs ACI). Consultez la section 2.5 pour la configuration.
2. Installation
2.1. Azure CLI
Azure CLI doit être installé sur votre machine locale.
Linux / macOS :
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bashWindows : reportez-vous à la documentation Microsoft.
2.2. Créer un Application Gateway
L'Application Gateway expose l'ACI avec une adresse IP publique et un nom DNS. Elle gère également la terminaison HTTPS et le filtrage IP via le WAF.
Pour tous les détails de configuration, reportez-vous à la documentation Microsoft sur Application Gateway.
Basic Tab
Sélectionnez votre abonnement, votre groupe de ressources et votre région. Choisissez le niveau WAF V2 pour activer le Web Application Firewall.
WAF Policy
Créez une nouvelle stratégie WAF depuis le champ WAF policy. Utilisez le WAF pour définir les plages d'adresses IP entrantes autorisées à appeler l'Application Gateway.
VNET
Créez un nouveau réseau virtuel (VNET) depuis le champ Virtual network. Ce VNET connecte l'Application Gateway à l'ACI.
Frontends
Créez une nouvelle adresse IP publique. Il s'agit de l'adresse IP exposée en externe et utilisée pour router le trafic vers l'ACI.
Backends
Créez un nouveau pool de backend. Laissez-le vide pour l'instant — l'adresse IP privée de l'ACI sera ajoutée une fois l'ACI déployé (section 3.3).
Configuration — Routing Rules
Créez une règle de routage avec :
- Listener : HTTPS sur le port 443, avec votre certificat SSL.
- Backend target : le pool de backend créé ci-dessus.
- Backend setting : HTTP sur le port 80 (le trafic entre l'Application Gateway et l'ACI transite par le VNET privé et ne nécessite pas de HTTPS en interne).
Cliquez sur Review + create pour déployer l'Application Gateway.
2.3. Ajouter un sous-réseau VNET pour l'ACI
Dans le VNET créé à la section 2.2, créez un nouveau sous-réseau dédié à l'ACI. Déléguez ce sous-réseau à Microsoft.ContainerInstance/containerGroups.
az network vnet subnet create \
--resource-group MY_RESOURCE_GROUP \
--vnet-name VNET_NAME \
--name aci-subnet \
--address-prefixes 10.0.1.0/24 \
--delegations Microsoft.ContainerInstance/containerGroupsNotez l'ID de ressource complet du sous-réseau — il sera requis dans le YAML du groupe de conteneurs :
/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.Network/virtualNetworks/VNET_NAME/subnets/SUBNET_NAME2.4. Configurer Azure Storage
Les conteneurs ACI utilisent Azure File Shares pour le stockage persistant. Créez un compte de stockage, puis créez les partages de fichiers suivants :
| Partage de fichiers | Objet |
|---|---|
nginxconf |
Fichiers de configuration NGINX et certificat SSL |
redisdata |
Données persistantes Redis |
Étape 1 — Créer le compte de stockage :
az storage account create \
--name MY_STORAGE_ACCOUNT \
--resource-group MY_RESOURCE_GROUP \
--location MY_LOCATION \
--sku Standard_LRSÉtape 2 — Récupérer la clé du compte de stockage :
az storage account keys list \
--account-name MY_STORAGE_ACCOUNT \
--resource-group MY_RESOURCE_GROUP \
--query "[0].value" -o tsvÉtape 3 — Créer les partages de fichiers :
az storage share create --name nginxconf --account-name MY_STORAGE_ACCOUNT
az storage share create --name redisdata --account-name MY_STORAGE_ACCOUNT2.5. Créer une base Azure Database for PostgreSQL
PostgreSQL est hébergé en tant que service Azure managé, en dehors du groupe de conteneurs ACI. Les Azure File Shares (SMB) ne prennent pas en charge les opérations de système de fichiers POSIX requises par PostgreSQL et provoqueront un CrashLoopBackOff.
Étape 1 — Créer un sous-réseau dédié pour PostgreSQL
Dans le VNET créé à la section 2.2, ajoutez un nouveau sous-réseau (par exemple postgres-subnet). Déléguez-le à Microsoft.DBforPostgreSQL/flexibleServers. Ce sous-réseau ne peut pas être partagé avec le sous-réseau de l'ACI.
az network vnet subnet create \
--resource-group MY_RESOURCE_GROUP \
--vnet-name VNET_NAME \
--name postgres-subnet \
--address-prefixes 10.0.2.0/24 \
--delegations Microsoft.DBforPostgreSQL/flexibleServersÉtape 2 — Créer le serveur
Dans le portail Azure, créez une ressource Azure Database for PostgreSQL :
- Networking : sélectionnez Private access (VNet Integration).
- Virtual network : sélectionnez le même VNet que celui de l'ACI. L'ACI et le serveur doivent partager le même VNet.
- Subnet : sélectionnez le sous-réseau créé à l'étape 1.
-
Admin username / password : définissez les identifiants. Ces valeurs sont utilisées dans
DB_USERetDB_PASSWORDdans le YAML du groupe de conteneurs.
az postgres flexible-server create \
--resource-group MY_RESOURCE_GROUP \
--name SERVERNAME \
--location MY_LOCATION \
--vnet VNET_NAME \
--subnet postgres-subnet \
--admin-user DB_ADMIN_USER \
--admin-password "DB_ADMIN_PASSWORD" \
--sku-name Standard_B1ms \
--tier Burstable \
--version 16Étape 3 — Créer la base de données de l'application
Dans le portail Azure, allez dans la ressource Azure Database for PostgreSQL → Databases → + Add, saisissez dqeone comme nom, puis enregistrez.
az postgres flexible-server db create \
--resource-group MY_RESOURCE_GROUP \
--server-name SERVERNAME \
--database-name dqeone2.6. Créer un espace de travail Log Analytics
Un espace de travail Log Analytics centralise les journaux des conteneurs et permet la supervision via Azure Monitor. Les journaux sont conservés 30 jours par défaut.
Étape 1 — Créer l'espace de travail :
az monitor log-analytics workspace create \
--resource-group MY_RESOURCE_GROUP \
--workspace-name dqe-standalone-logs \
--location MY_LOCATIONÉtape 2 — Récupérer le Workspace ID :
az monitor log-analytics workspace show \
--resource-group MY_RESOURCE_GROUP \
--workspace-name dqe-standalone-logs \
--query customerId -o tsvÉtape 3 — Récupérer la Workspace Primary Key :
az monitor log-analytics workspace get-shared-keys \
--resource-group MY_RESOURCE_GROUP \
--workspace-name dqe-standalone-logs \
--query primarySharedKey -o tsvConservez le Workspace ID et la Primary Key — ils sont requis dans le YAML du groupe de conteneurs (section 2.8).
2.7. Configurer NGINX
NGINX agit comme un reverse proxy à l'intérieur du groupe de conteneurs ACI, en transférant les requêtes entrantes vers le conteneur dqeone sur le port 8000. Comme tous les conteneurs d'un groupe ACI partagent le même espace de noms réseau, la cible du proxy utilise localhost.
Créez un fichier nommé default.conf avec le contenu suivant :
server {
listen 80;
location / {
proxy_pass http://localhost:8000;
proxy_read_timeout 300s;
}
}Si le HTTPS est géré directement au niveau de l'ACI (sans déchargement SSL par l'Application Gateway), ajoutez un second bloc server pour le port 443 et téléversez les fichiers de certificat SSL et de clé vers le partage de fichiers nginxconf, sous un sous-répertoire ssl/.
Téléversez default.conf vers le partage de fichiers nginxconf :
az storage file upload \
--account-name MY_STORAGE_ACCOUNT \
--share-name nginxconf \
--source ./default.conf \
--path default.conf2.8. YAML du groupe de conteneurs
Créez un fichier nommé container-group.yaml. Remplacez tous les placeholders avant le déploiement.
| Placeholder | Description |
|---|---|
MY_LOCATION |
Région Azure, par exemple francecentral
|
DQE_REGISTRY_LOGIN |
Nom d'utilisateur du registre fourni par DQE |
DQE_REGISTRY_PASSWORD |
Mot de passe du registre fourni par DQE |
MY_STORAGE_ACCOUNT |
Nom du compte de stockage créé à la section 2.4 |
MY_STORAGE_ACCOUNT_KEY |
Clé du compte de stockage récupérée à la section 2.4, étape 2 |
LOG_ANALYTICS_WORKSPACE_ID |
Workspace ID récupéré à la section 2.6, étape 2 |
LOG_ANALYTICS_WORKSPACE_KEY |
Primary Key récupérée à la section 2.6, étape 3 |
SUBNET_RESOURCE_ID |
ID de ressource complet du sous-réseau ACI noté à la section 2.3 |
SERVERNAME |
Nom du serveur PostgreSQL créé à la section 2.5 |
DB_ADMIN_USER |
Nom d'utilisateur admin du serveur PostgreSQL |
DB_ADMIN_PASSWORD |
Mot de passe admin du serveur PostgreSQL |
DQE_ADMIN_USER |
Nom d'utilisateur admin de l'application DQE One |
DQE_ADMIN_PASSWORD |
Mot de passe admin de l'application DQE One |
name: dqe-standalone
apiVersion: '2021-10-01'
location: MY_LOCATION
tags: {"docker-compose-application": "docker-compose-application"}
properties:
containers:
- name: nginx
properties:
image: dqeone.azurecr.io/dqe-one-nginx:latest
ports:
- protocol: TCP
port: 80
resources:
requests:
memoryInGB: 0.5
cpu: 0.25
volumeMounts:
- name: nginxconf
mountPath: /etc/nginx/conf.d
- name: redis
properties:
image: dqeone.azurecr.io/dqe-one-redis:v1.0
resources:
requests:
memoryInGB: 1.0
cpu: 0.5
volumeMounts:
- name: redisdata
mountPath: /data
- name: dqeone
properties:
image: dqeone.azurecr.io/standalone:v1.4.0
command:
- "bash"
- "./entrypoint.sh"
ports:
- protocol: TCP
port: 8000
resources:
requests:
memoryInGB: 2.0
cpu: 1.0
environmentVariables:
- name: SFAPIVERSION
value: v65.0
- name: CREATE_SUPERUSER
value: "true"
- name: RUN_COLLECTSTATIC
value: "false"
- name: DQE_ONE_SERVER_ADMIN_USER
value: DQE_ADMIN_USER
- name: DQE_ONE_SERVER_ADMIN_PASSWORD
secureValue: DQE_ADMIN_PASSWORD
- name: DQE_CLIENT_LICENCE
value: CLIENT_LICENCE
- name: WEBSITE_HOSTNAME
value: https://YOUR_DNS_NAME
- name: SECRET_ENCRYPTION_KEY
secureValue: SECRET_ENCRYPTION_KEY_VALUE
- name: WAIT_HOSTS
value: "localhost:6379"
- name: WAIT_HOSTS_TIMEOUT
value: "300"
- name: WAIT_SLEEP_INTERVAL
value: "5"
- name: WAIT_HOST_CONNECT_TIMEOUT
value: "30"
- name: REDIS_URL
value: redis://localhost:6379
- name: PORT
value: "8000"
- name: DEBUG
value: "false"
- name: DB_USER
value: DB_ADMIN_USER
- name: DB_PASSWORD
secureValue: DB_ADMIN_PASSWORD
- name: DB_NAME
value: dqeone
- name: DB_HOST
value: SERVERNAME.postgres.database.azure.com
- name: DB_PORT
value: "5432"
- name: DB_VOLUME_PATH
value: ./db/
- name: DB_MAX_CAPACITY
value: "8000000000"
- name: AUTHORIZED_SFTP_HOSTS
value: AUTHORIZED_SFTP_HOSTS
# Only required if WEBSITE_HOSTNAME does not match the URL used to access the app:
# - name: CSRF_TRUSTED_ORIGINS
# value: https://YOUR_IP_OR_ALTERNATE_URL
imageRegistryCredentials:
- server: dqeone.azurecr.io
username: DQE_REGISTRY_LOGIN
password: DQE_REGISTRY_PASSWORD
diagnostics:
logAnalytics:
workspaceId: LOG_ANALYTICS_WORKSPACE_ID
workspaceKey: LOG_ANALYTICS_WORKSPACE_KEY
restartPolicy: Always
ipAddress:
ports:
- protocol: TCP
port: 80
type: Private
osType: Linux
volumes:
- name: nginxconf
azureFile:
shareName: nginxconf
readOnly: false
storageAccountName: MY_STORAGE_ACCOUNT
storageAccountKey: MY_STORAGE_ACCOUNT_KEY
- name: redisdata
azureFile:
shareName: redisdata
readOnly: false
storageAccountName: MY_STORAGE_ACCOUNT
storageAccountKey: MY_STORAGE_ACCOUNT_KEY
subnetIds:
- id: SUBNET_RESOURCE_IDImportant : utilisez les versions d'images fournies par DQE. Ne les remplacez pas par le tag latest.
Remarque clé sur le réseau ACI : tous les conteneurs du groupe partagent le même espace de noms réseau. La communication inter-conteneurs utilise localhost — c'est pourquoi REDIS_URL vaut redis://localhost:6379. PostgreSQL s'exécute en dehors du groupe de conteneurs en tant que service Azure managé, donc DB_HOST correspond au FQDN d'Azure Database for PostgreSQL.
2.9. Variables d'environnement
| Variable | Exemple de valeur | Description |
|---|---|---|
SFAPIVERSION |
v65.0 |
Version de l'API Salesforce utilisée par l'application. |
CREATE_SUPERUSER |
true |
Crée le compte administrateur initial lors du premier démarrage. |
RUN_COLLECTSTATIC |
false |
Exécute la commande Django collectstatic au démarrage. Laissez sur false sauf nécessité explicite. |
DQE_ONE_SERVER_ADMIN_USER |
— | Nom d'utilisateur du compte administrateur initial. |
DQE_ONE_SERVER_ADMIN_PASSWORD |
— | Mot de passe du compte administrateur initial. Utilisez secureValue. |
DQE_CLIENT_LICENCE |
— | Clé de licence client fournie par DQE. |
WEBSITE_HOSTNAME |
https://myapp.example.com |
URL HTTPS publique. Doit correspondre au nom DNS pointant vers l'Application Gateway. |
SECRET_ENCRYPTION_KEY |
— | Clé de chiffrement pour les données sensibles. À générer une seule fois, ne jamais modifier après le déploiement. Utilisez secureValue. |
WAIT_HOSTS |
localhost:6379 |
Service à attendre avant le démarrage. Utilise localhost dans l'ACI. |
WAIT_HOSTS_TIMEOUT |
300 |
Temps d'attente maximal en secondes pour les services dépendants. |
WAIT_SLEEP_INTERVAL |
5 |
Délai en secondes entre les vérifications de disponibilité. |
WAIT_HOST_CONNECT_TIMEOUT |
30 |
Timeout en secondes pour chaque tentative de connexion. |
REDIS_URL |
redis://localhost:6379 |
URL de connexion Redis. Utilise localhost dans l'ACI. |
PORT |
8000 |
Port d'écoute interne de l'application. |
DEBUG |
false |
Mode debug. Doit être false en production. |
DB_USER |
dqeone |
Nom d'utilisateur admin PostgreSQL défini lors de la création du serveur Postgres. |
DB_PASSWORD |
— | Mot de passe admin PostgreSQL. Utilisez secureValue. |
DB_NAME |
dqeone |
Nom de la base de données PostgreSQL. Obligatoire — l'application ne démarrera pas sans cette valeur. |
DB_HOST |
myserver.postgres.database.azure.com |
FQDN du serveur PostgreSQL. |
DB_PORT |
5432 |
Port PostgreSQL. |
DB_VOLUME_PATH |
./db/ |
Chemin de stockage lié à la base de données. |
DB_MAX_CAPACITY |
8000000000 |
Capacité maximale de la base de données en octets. |
AUTHORIZED_SFTP_HOSTS |
depot-1.dqe-software.net |
Liste des hôtes SFTP autorisés, séparés par des virgules. |
CSRF_TRUSTED_ORIGINS |
https://myapp.example.com |
Origines de confiance pour le CSRF Django. Requis uniquement si l'application est accédée via une URL différente de WEBSITE_HOSTNAME. |
Important : la SECRET_ENCRYPTION_KEY doit être générée une seule fois et conservée pendant toute la durée de vie du déploiement. Pour générer une clé compatible :
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"3. Lancement
3.1. Se connecter à Azure
az login3.2. Déployer le groupe de conteneurs
az container create -g MY_RESOURCE_GROUP -f container-group.yamlUne fois l'opération terminée, récupérez l'adresse IP privée attribuée au groupe de conteneurs :
az container show \
--resource-group MY_RESOURCE_GROUP \
--name dqe-standalone \
--query "ipAddress.ip" -o tsvCette adresse IP privée n'est accessible que depuis l'intérieur du VNET Azure.
3.3. Configurer le backend pool de l'Application Gateway
Une fois l'ACI déployé, allez dans Azure Portal > Application Gateway > Backend pools > votre backend pool > Edit.
Ajoutez l'adresse IP privée de l'ACI récupérée à l'étape 3.2. Cliquez sur Save.
3.4. Configurer le health probe de l'Application Gateway
Le health probe permet à l'Application Gateway de vérifier que l'application fonctionne. Allez dans Azure Portal > Application Gateway > Health probes > Add.
Configurez la sonde pour appeler le chemin racine de l'application en HTTP. Cliquez sur Test. Si le statut affiche Healthy, l'ACI est correctement configuré et l'Application Gateway peut router le trafic vers celui-ci. Cliquez sur Add pour enregistrer le health probe.
3.5. Configurer le DNS
Contactez vos administrateurs DNS pour créer un enregistrement DNS pointant vers l'adresse IP publique de l'Application Gateway :
| Type d'enregistrement | Nom | Valeur |
|---|---|---|
| A | standalone.yourdomain.com |
Adresse IP publique de l'Application Gateway |
3.6. Vérifier l'installation
Vérifiez que tous les conteneurs sont en cours d'exécution :
az container show \
--resource-group MY_RESOURCE_GROUP \
--name dqe-standalone \
--query "containers[].{Name:name, State:instanceView.currentState.state}" \
-o tableRésultat attendu :
Name State
-------- -------
nginx Running
redis Running
dqeone RunningRemarque : l'ACI démarre tous les conteneurs simultanément. Le mécanisme WAIT_HOSTS gère l'ordre de démarrage en réessayant la connexion. Un délai de 1–2 minutes avant que l'application soit pleinement opérationnelle est normal au premier démarrage.
Une fois tous les conteneurs en cours d'exécution et le DNS propagé, accédez à https://standalone.yourdomain.com.
4. Adresses IP à autoriser
Une fois l'application en cours d'exécution, configurez le WAF ou le pare-feu en amont pour autoriser les plages d'adresses IP entrantes suivantes :
- Serveur Office DQE Software : contactez le support DQE Software pour obtenir l'adresse IP à autoriser.
- Service de dédoublonnage DQE : contactez le support DQE Software pour obtenir l'adresse IP à autoriser.
- Service de qualité DQE : contactez le support DQE Software pour obtenir l'adresse IP à autoriser.
Action requise : communiquez à DQE Software l'adresse IP publique sortante utilisée par votre infrastructure Azure (NAT Gateway, Azure Firewall, ou équivalent) afin qu'elle puisse être autorisée sur les services DQE.
5. Dépannage
Consulter les journaux des conteneurs
Les journaux des conteneurs sont disponibles dans Azure Monitor sous la table ContainerInstanceLog_CL. Vous pouvez également les récupérer directement via la CLI :
az container logs \
--resource-group MY_RESOURCE_GROUP \
--name dqe-standalone \
--container-name CONTAINER_NAMENon autorisé lors du téléchargement des images
Vérifiez que :
- la section
imageRegistryCredentialscontient bien le login et le mot de passe fournis par DQE ; - toutes les images référencent bien le registre de production DQE
dqeone.azurecr.io; - les versions des images correspondent bien à celles fournies par DQE.
Configuration de PostgreSQL
Suivez la section 2.5 pour la procédure complète de configuration. Points clés :
- Le serveur doit se trouver dans le même VNet que l'ACI — des VNets différents nécessitent du peering et une configuration de zone DNS.
- Azure Database for PostgreSQL nécessite un sous-réseau dédié délégué à
Microsoft.DBforPostgreSQL/flexibleServers. - Après la création du serveur, créez la base de données
dqeonedepuis le portail Azure : Azure Database for PostgreSQL → Databases → + Add. - Toutes les variables d'environnement
DB_*doivent être définies dans le YAML du groupe de conteneurs avant le premier déploiement — voir section 2.8.
Échec de vérification CSRF (403)
Django vérifie que les requêtes entrantes proviennent d'une origine de confiance correspondant à WEBSITE_HOSTNAME. Une erreur CSRF 403 survient lorsque l'application est accédée via une URL différente du hostname configuré.
Solution permanente : configurez le DNS pour que le hostname défini dans WEBSITE_HOSTNAME résolve vers l'adresse IP publique de l'Application Gateway.
Contournement temporaire (tests sans DNS) : définissez WEBSITE_HOSTNAME avec l'adresse IP et ajoutez CSRF_TRUSTED_ORIGINS :
- name: WEBSITE_HOSTNAME
value: https://YOUR_GATEWAY_IP
- name: CSRF_TRUSTED_ORIGINS
value: https://YOUR_GATEWAY_IPUne fois le DNS configuré, remettez les deux valeurs sur le nom de domaine approprié.
Échec du health probe de l'Application Gateway
Vérifiez que :
- tous les conteneurs ACI affichent l'état
Running; - le backend pool contient bien l'adresse IP privée correcte de l'ACI ;
- le sous-réseau est bien délégué à
Microsoft.ContainerInstance/containerGroups; - le NSG attaché au sous-réseau autorise le trafic entrant sur le port 80 depuis le sous-réseau de l'Application Gateway.