ACI — Installation Standalone pour Microsoft Dynamics

Support DQE
Support DQE
  • Mise à jour

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 secureValue dans 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 bash

Windows : 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/containerGroups

Notez 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_NAME

2.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_ACCOUNT

2.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_USER et DB_PASSWORD dans 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 dqeone

2.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 tsv

Conservez 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.conf

2.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_ID

Important : 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 login

3.2. Déployer le groupe de conteneurs

az container create -g MY_RESOURCE_GROUP -f container-group.yaml

Une 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 tsv

Cette 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 table

Résultat attendu :

Name      State
--------  -------
nginx     Running
redis     Running
dqeone    Running

Remarque : 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_NAME

Non autorisé lors du téléchargement des images

Vérifiez que :

  • la section imageRegistryCredentials contient 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 dqeone depuis 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_IP

Une 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.

Cet article vous a-t-il été utile ?

Utilisateurs qui ont trouvé cela utile : 0 sur 0