Microsoft ACI - Backend server installation

Support DQE
Support DQE
  • Updated

1. Installation

This section describes the deployment of DQE Unify Server on Azure Container Instances (ACI). The application stack — Redis, RabbitMQ, Nginx, Unify Server, and Queue Worker — runs as a single Azure Container Group. All containers share the same network namespace and communicate via localhost.

1.1 Prerequisites

1.1.1 Resource Requirements

Container CPU (vCores) Memory
redis 0.5 0.5 GB
rabbitmq 0.5 1 GB
nginx 0.5 0.5 GB
unify-server 0.5 1 GB
queue-worker 1.0 5 GB
Total 3.0 8 GB

Note: Estimates are based on 1 million records. Depending on data volume, you may need to increase the memory allocation of the queue-worker container.

1.1.2 Software Requirements

Software Version / Notes
Azure CLI Latest stable — az command available in terminal
Azure Subscription Active subscription with permissions to create Container Instances and Storage Accounts
Internet access Required to pull images from DQE Container Registry

1.2 Authenticate to DQE Container Registry

All images (DQE Unify, Redis, RabbitMQ, Nginx) are hosted on a private Azure Container Registry. Use the credentials provided by DQE Software to log in from your local terminal:

az login
docker login <registry-url> --username <Username provided by DQE> --password <Password provided by DQE>

A successful login displays: Login Succeeded.

Note: The registry credentials are also required in the Container Group YAML file (section 1.6) so that ACI can pull the images at deploy time.

1.3 Configure Azure Storage

Azure Container Instances do not support local bind mounts. Persistent data for Redis and RabbitMQ must be stored in Azure File Shares. The Nginx configuration file is also uploaded to a file share so the container can mount it at runtime.

  1. Step 1 — Create a Storage Account:

    az storage account create \
      --name dqeunifystorage \
      --resource-group <resource-group> \
      --location <location> \
      --sku Standard_LRS
  2. Step 2 — Retrieve the storage account key:

    az storage account keys list \
      --account-name dqeunifystorage \
      --resource-group <resource-group> \
      --query "[0].value" -o tsv
  3. Step 3 — Create the file shares:

    az storage share create --name redisvol   --account-name dqeunifystorage
    az storage share create --name rabbitvol  --account-name dqeunifystorage
    az storage share create --name nginxconf  --account-name dqeunifystorage

1.4 Configure Nginx

Nginx acts as a reverse proxy, forwarding incoming HTTP/HTTPS requests to the Unify Server. In ACI, all containers share the same network namespace, so the proxy target is http://localhost:8000 and not a service name.

Create the file default.conf locally, then upload it to the Azure File Share.

The file default.conf must contain:

server {
    listen 80;

    location / {
        proxy_pass         http://localhost:8000;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_read_timeout 300s;
    }
}

Upload to the Azure File Share:

az storage file upload \
  --account-name dqeunifystorage \
  --share-name nginxconf \
  --source ./default.conf \
  --path default.conf

HTTPS

Add a second server block and upload your SSL certificate and private key to the nginxconf file share. Update the Container Group YAML to expose port 443.

server {
    listen 443 ssl;

    ssl_certificate      /etc/nginx/ssl/cert.crt;
    ssl_certificate_key  /etc/nginx/ssl/cert.key;

    location / {
        proxy_pass         http://localhost:8000;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_read_timeout 300s;
    }
}

Note: Upload certificate files to the nginxconf file share under an ssl/ subdirectory, and mount the share at /etc/nginx/ssl in the Nginx container configuration.

1.5 Configure Log Analytics Workspace

A Log Analytics workspace centralizes container logs and enables monitoring through Azure Monitor. The workspace ID and key are referenced in the Container Group YAML (section 1.6).

  1. Step 1 — Create a Log Analytics workspace:

    az monitor log-analytics workspace create \
      --resource-group <resource-group> \
      --workspace-name dqe-unify-logs \
      --location <location>
  2. Step 2 — Retrieve the Workspace ID:

    az monitor log-analytics workspace show \
      --resource-group <resource-group> \
      --workspace-name dqe-unify-logs \
      --query customerId -o tsv
  3. Step 3 — Retrieve the Workspace Primary Key:

    az monitor log-analytics workspace get-shared-keys \
      --resource-group <resource-group> \
      --workspace-name dqe-unify-logs \
      --query primarySharedKey -o tsv

Note: Keep the Workspace ID and Primary Key at hand — they are used as placeholders <workspace-id> and <workspace-key> in the Container Group YAML (section 1.6).

1.6 Container Group Configuration File

Create the file container-group.yaml with the content below. Replace all placeholders in angle brackets before deploying.

Placeholder Description
<resource-group> Azure Resource Group name
<location> Azure region, for example westeurope
<registry-url> DQE Container Registry URL
<Username provided by DQE> Registry username given by DQE Software
<Password provided by DQE> Registry password given by DQE Software
<storage-account-key> Key retrieved in section 1.3 Step 2
<workspace-id> Log Analytics Workspace ID (retrieved in section 1.5 Step 2)
<workspace-key> Log Analytics Workspace Primary Key (retrieved in section 1.5 Step 3)
name: dqe-unify-aci
apiVersion: '2021-10-01'
location: <azure-region>

tags:
  docker-compose-application: docker-compose-application

properties:
  containers:
    - name: redis
      properties:
        image: <registry-url>/dqe-unify-redis:latest
        resources:
          requests:
            memoryInGB: 1
            cpu: 0.5
        volumeMounts:
          - name: redisvol
            mountPath: /data

    - name: rabbitmq
      properties:
        image: <registry-url>/dqe-unify-rabbitmq:latest
        ports:
          - protocol: TCP
            port: 5672
        resources:
          requests:
            memoryInGB: 1
            cpu: 1
        volumeMounts:
          - name: rabbitvol
            mountPath: /bitnami
            readOnly: false

    - name: nginx
      properties:
        image: <registry-url>/dqe-unify-nginx:latest
        ports:
          - protocol: TCP
            port: 80
        resources:
          requests:
            memoryInGB: 1
            cpu: 0.25
        volumeMounts:
          - name: nginxconf
            mountPath: /etc/nginx/conf.d

    - name: unify-server
      properties:
        image: <registry-url>/unify-server-web-ms-dynamics:<version>
        command: ["python", "-u", "app.pyc"]
        ports:
          - protocol: TCP
            port: 8000
        environmentVariables:
          - name: REDIS_URL
            value: redis://127.0.0.1:6379
          - name: CLOUDAMQP_URL
            value: amqp://guest:guest@127.0.0.1:5672/
          - name: PORT
            value: 8000
        resources:
          requests:
            memoryInGB: 1
            cpu: 0.25

    - name: queue-worker
      properties:
        image: <registry-url>/unify-server-web-ms-dynamics:<version>
        command: ["python", "-u", "queue_worker.pyc"]
        environmentVariables:
          - name: REDIS_URL
            value: redis://127.0.0.1:6379
          - name: CLOUDAMQP_URL
            value: amqp://guest:guest@127.0.0.1:5672/
        resources:
          requests:
            memoryInGB: 5
            cpu: 1

  imageRegistryCredentials:
    - server: <registry-url>
      username: <registry-username>
      password: <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: rabbitvol
      azureFile:
        shareName: rabbitvol
        readOnly: false
        storageAccountName: <storage-account-name>
        storageAccountKey: <storage-account-key>

    - name: nginxconf
      azureFile:
        shareName: nginxconf
        readOnly: false
        storageAccountName: <storage-account-name>
        storageAccountKey: <storage-account-key>

    - name: redisvol
      azureFile:
        shareName: redisvol
        readOnly: false
        storageAccountName: <storage-account-name>
        storageAccountKey: <storage-account-key>

  subnetIds:
    - id: /subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Network/virtualNetworks/<vnet-name>/subnets/<subnet-name>

Key configuration notes:

  • All containers in an ACI Container Group share the same network namespace — services communicate via localhost, not via service names.
  • The REDIS_URL and CLOUDAMQP_URL use localhost instead of redis and rabbitmq.
  • The image unify-server-web-ms-dynamics:v3.0 contains compiled Python bytecode — the entry point is app.pyc, not app.py.
  • RabbitMQ uses the official image with credentials set via environment variables. The virtual host is / by default.
  • The diagnostics.logAnalytics block routes all container stdout/stderr to the Log Analytics workspace. Logs appear in Azure Monitor under the ContainerInstanceLog_CL table within a few minutes of deployment.

1.7 Deploy the Application

  1. Step 1 — Deploy the Container Group:

    az container create \
      --resource-group <resource-group> \
      --file container-group.yaml
  2. Step 2 — Check the deployment status:

    az container show \
      --resource-group <resource-group> \
      --name dqe-unify \
      --query "instanceView.state" -o tsv

    Expected output: Running.

  3. Step 3 — Retrieve the private IP address assigned to the Container Group:

    az container show \
      --resource-group <resource-group> \
      --name dqe-unify \
      --query "ipAddress.ip" -o tsv

     The returned IP address is reachable only from the Azure Virtual Network or from connected networks.

  4. Step 4 — Verify all containers are running:

    az container show \
      --resource-group <resource-group> \
      --name dqe-unify \
      --query "containers[].{Name:name, State:instanceView.currentState.state}" \
      -o table

    Expected output: all containers should show state Running:

    Name            State
    -----------     -------
    redis           Running
    rabbitmq        Running
    nginx           Running
    unify-server    Running
    queue-worker    Running

Important: If any container shows state Terminated or Waiting, check its logs immediately: az container logs --resource-group <rg> --name dqe-unify --container-name <service-name>.

Note: ACI starts all containers simultaneously. RabbitMQ and Redis may take a few seconds to be ready. The Unify Server will automatically retry the connection on startup.

1.8 Configure Network Security Group (NSG)

If the Container Instance is deployed in an Azure Virtual Network, configure the associated NSG to allow inbound traffic on the required ports.

  1. Go to Azure Portal → Network Security Groups → [Your NSG] → Inbound security rules.
  2. Click Add.
  3. Set Destination port ranges : 80. If HTTPS is enabled through an external reverse proxy or Application Gateway, additional rules may be required.
  4. Set Protocol to TCP and Action to Allow.
  5. Click Add.

Note: Port 8000 (Unify Server) and port 5672 (RabbitMQ) are internal to the Container Group and do not need to be exposed externally.

Dynamics 365 — Authorize Inbound IP Ranges

The DQE Unify Server receives requests from Microsoft Dynamics 365, which runs on Azure infrastructure. You must authorize the corresponding Azure IP ranges in the NSG.

The full and up-to-date list of Microsoft Azure IP ranges is available for download at:
Microsoft Azure IP Ranges and Service Tags

Download the JSON file, identify the Dynamics365 and AzureCloud service tags relevant to your region, and add the corresponding IP ranges as inbound allow rules on the port exposed by the reverse proxy or Application Gateway (typically port 80 or 443 depending on the infrastructure configuration). Alternatively, set Source to Service Tag and select Dynamics365 directly in the NSG rule.

1.9 Set Up DNS

Contact your network or DNS administrators to create an internal DNS record pointing to the private IP address of the Container Group or to the hostname exposed by the reverse proxy/Application Gateway.

Record Type Name Value
A unify.yourdomain.com Private IP of the ACI Container Group

Alternatively, you can assign a DNS name label directly to the Container Instance in Azure Portal: Azure Portal → Container Instances → [dqe-unify] → Overview → DNS name label. This gives a hostname of the form dqe-unify.<location>.azurecontainer.io.

1.10 Verify the Deployment

Once DNS propagates, open a browser and navigate to:

http://unify.yourdomain.com

You can also test directly using the public IP:

curl http://<private-ip>

Expected response from the Unify Server:

{"status": "available"}

If the application responds, the deployment is complete and the server is properly configured.

2. Application Set Up

Once the application is running, the NSG and any upstream firewall or proxy must be configured to allow the IP ranges listed below.

2.1 IP Addresses to Authorize

DQE Software Office Server

Contact DQE Software support to obtain the IP address to authorize.

DQE – Deduplication Service

Contact DQE Software support to obtain the IP address to authorize.

DQE – Quality Service

Contact DQE Software support to obtain the IP address to authorize.

Action required: Provide DQE Software with the outbound public IP address used by your Azure infrastructure (NAT Gateway, Azure Firewall or equivalent) so that it can be authorized on DQE services.

Azure IP Ranges — Dynamics 365 and Azure Services

The full and up-to-date list of Microsoft Azure IP ranges (IPv4 and IPv6) is available for download at:

Microsoft Azure IP Ranges and Service Tags

Download the JSON file and identify the service tags relevant to your region (Dynamics365, AzureCloud). Add the corresponding IP ranges to your NSG inbound rules.

Related to

Was this article helpful?

0 out of 0 found this helpful