Azure Container Instance (ACI) — Instalación de DQE One Standalone

Support DQE
Support DQE
  • Actualización

Implemente DQE One Standalone en Azure Container Instance (ACI) para entornos de Microsoft Dynamics, utilizando una instancia administrada de Azure Database for PostgreSQL en lugar de un contenedor de base de datos.

Nota: todos los elementos descritos a continuación son recomendaciones de DQE, basadas en la experiencia de implementación con distintos clientes. El cliente es responsable de integrar la solución en su propia arquitectura. Un arquitecto familiarizado con el contexto del cliente y la infraestructura interna debe alinear las recomendaciones de DQE con la infraestructura del cliente.

1. Arquitectura

Este documento describe cómo implementar el backend de DQE One Standalone como un grupo de contenedores de Azure Container Instance (ACI). Todos los contenedores del grupo comparten el mismo espacio de nombres de red y se comunican a través de localhost. Un Application Gateway expone la aplicación mediante HTTPS y enruta el tráfico hacia el ACI a través de una VNET privada.

Arquitectura recomendada

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)

Medidas de seguridad

  • Application Gateway: finaliza el HTTPS y enruta el tráfico hacia el ACI a través de la VNET privada. Utilice el WAF para restringir los rangos de IP entrantes.
  • VNET: aísla el ACI del acceso público directo a internet. Todo el tráfico procedente del Application Gateway pasa por una subred privada.
  • Certificado SSL: se gestiona a nivel del Application Gateway o a nivel de NGINX dentro del ACI.
  • Secretos: utilice secureValue en el YAML del grupo de contenedores para todos los valores sensibles (contraseñas, claves de licencia, claves de cifrado).

Dimensionamiento recomendado

Contenedor CPU Memoria
nginx 0.25 vCPU 0.5 GB
redis 0.5 vCPU 1.0 GB
dqeone 1.0 vCPU 2.0 GB
Total 1.75 vCPU 3.5 GB

Los grupos de contenedores de ACI están limitados a 4 vCPU y 16 GB de memoria por grupo.

PostgreSQL se aloja en Azure Database for PostgreSQL (fuera del grupo de contenedores de ACI). Consulte la sección 2.5 para la configuración.

2. Instalación

2.1. Azure CLI

Azure CLI debe estar instalado en su máquina local.

Linux / macOS:

curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

Windows: Consulte la documentación de Microsoft.

2.2. Crear un Application Gateway

El Application Gateway expone el ACI con una dirección IP pública y un nombre DNS. También gestiona la finalización de HTTPS y el filtrado de IP mediante el WAF.

Para obtener información completa sobre la configuración, consulte la documentación de Microsoft Application Gateway.

Pestaña Basic
Seleccione su suscripción, grupo de recursos y región. Elija el nivel WAF V2 para habilitar el Web Application Firewall.

WAF Policy
Cree una nueva política WAF en el campo WAF policy. Utilice el WAF para definir los rangos de IP entrantes autorizados a llamar al Application Gateway.

VNET
Cree una nueva red virtual (VNET) en el campo Virtual network. Esta VNET conecta el Application Gateway con el ACI.

Frontends
Cree una nueva dirección IP pública. Es la dirección IP expuesta externamente y utilizada para enrutar el tráfico hacia el ACI.

Backends
Cree un nuevo pool de backend. Déjelo vacío por ahora: la dirección IP privada del ACI se añade después de implementar el ACI (sección 3.3).

Configuration — Reglas de enrutamiento
Cree una regla de enrutamiento con:

  • Listener: HTTPS en el puerto 443, con su certificado SSL.
  • Backend target: el pool de backend creado anteriormente.
  • Backend setting: HTTP en el puerto 80 (el tráfico entre el Application Gateway y el ACI viaja a través de la VNET privada y no requiere HTTPS internamente).

Haga clic en Review + create para implementar el Application Gateway.

2.3. Añadir una subred de VNET para el ACI

En la VNET creada en la sección 2.2, cree una nueva subred dedicada al ACI. Delegue esta subred a 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

Anote el ID de recurso completo de la subred: es necesario en el YAML del grupo de contenedores:

/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.Network/virtualNetworks/VNET_NAME/subnets/SUBNET_NAME

2.4. Configurar Azure Storage

Los contenedores de ACI utilizan Azure File Shares para el almacenamiento persistente. Cree una cuenta de almacenamiento y, a continuación, cree los siguientes recursos compartidos de archivos:

Recurso compartido Finalidad
nginxconf Configuración de NGINX y archivos de certificado SSL
redisdata Datos persistentes de Redis

Paso 1 — Crear la cuenta de almacenamiento:

az storage account create \
  --name MY_STORAGE_ACCOUNT \
  --resource-group MY_RESOURCE_GROUP \
  --location MY_LOCATION \
  --sku Standard_LRS

Paso 2 — Recuperar la clave de la cuenta de almacenamiento:

az storage account keys list \
  --account-name MY_STORAGE_ACCOUNT \
  --resource-group MY_RESOURCE_GROUP \
  --query "[0].value" -o tsv

Paso 3 — Crear los recursos compartidos de archivos:

az storage share create --name nginxconf --account-name MY_STORAGE_ACCOUNT
az storage share create --name redisdata --account-name MY_STORAGE_ACCOUNT

2.5. Crear Azure Database for PostgreSQL

PostgreSQL se aloja como servicio administrado de Azure fuera del grupo de contenedores de ACI. Azure File Shares (SMB) no admite las operaciones de sistema de archivos POSIX que requiere PostgreSQL y provocará un CrashLoopBackOff.

Paso 1 — Crear una subred dedicada para PostgreSQL

En la VNET creada en la sección 2.2, añada una nueva subred (por ejemplo, postgres-subnet). Delegúela a Microsoft.DBforPostgreSQL/flexibleServers. Esta subred no puede compartirse con la subred del 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

Paso 2 — Crear el servidor

En Azure Portal, cree un recurso de Azure Database for PostgreSQL:

  • Networking: seleccione Private access (VNet Integration).
  • Virtual network: seleccione la misma VNet que el ACI. El ACI y el servidor deben compartir la misma VNet.
  • Subnet: seleccione la subred creada en el paso 1.
  • Admin username / password: establezca las credenciales. Estos valores se utilizan en DB_USER y DB_PASSWORD en el YAML del grupo de contenedores.
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

Paso 3 — Crear la base de datos de la aplicación

En Azure Portal, vaya al recurso de Azure Database for PostgreSQL → Databases+ Add, introduzca dqeone como nombre y guarde.

az postgres flexible-server db create \
  --resource-group MY_RESOURCE_GROUP \
  --server-name SERVERNAME \
  --database-name dqeone

2.6. Crear un Log Analytics Workspace

Un Log Analytics workspace centraliza los registros de los contenedores y permite la supervisión a través de Azure Monitor. De forma predeterminada, los registros se conservan durante 30 días.

Paso 1 — Crear el workspace:

az monitor log-analytics workspace create \
  --resource-group MY_RESOURCE_GROUP \
  --workspace-name dqe-standalone-logs \
  --location MY_LOCATION

Paso 2 — Recuperar el Workspace ID:

az monitor log-analytics workspace show \
  --resource-group MY_RESOURCE_GROUP \
  --workspace-name dqe-standalone-logs \
  --query customerId -o tsv

Paso 3 — Recuperar 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

Conserve el Workspace ID y la Primary Key: son necesarios en el YAML del grupo de contenedores (sección 2.8).

2.7. Configurar NGINX

NGINX actúa como proxy inverso dentro del grupo de contenedores de ACI, reenviando las solicitudes entrantes al contenedor dqeone en el puerto 8000. Dado que todos los contenedores de un grupo de ACI comparten el mismo espacio de nombres de red, el destino del proxy utiliza localhost.

Cree un archivo llamado default.conf con el siguiente contenido:

server {
    listen 80;

    location / {
        proxy_pass         http://localhost:8000;
        proxy_read_timeout 300s;
    }
}

Si el HTTPS se gestiona directamente a nivel del ACI (sin descarga SSL en el Application Gateway), añada un segundo bloque server para el puerto 443 y cargue los archivos de certificado y clave SSL en el recurso compartido de archivos nginxconf, en un subdirectorio ssl/.

Cargue default.conf en el recurso compartido de archivos nginxconf:

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

2.8. YAML del grupo de contenedores

Cree un archivo llamado container-group.yaml. Sustituya todos los marcadores de posición antes de implementar.

Marcador de posición Descripción
MY_LOCATION Región de Azure, por ejemplo francecentral
DQE_REGISTRY_LOGIN Nombre de usuario del registro proporcionado por DQE
DQE_REGISTRY_PASSWORD Contraseña del registro proporcionada por DQE
MY_STORAGE_ACCOUNT Nombre de la cuenta de almacenamiento creada en la sección 2.4
MY_STORAGE_ACCOUNT_KEY Clave de la cuenta de almacenamiento obtenida en el paso 2 de la sección 2.4
LOG_ANALYTICS_WORKSPACE_ID Workspace ID obtenido en el paso 2 de la sección 2.6
LOG_ANALYTICS_WORKSPACE_KEY Primary Key obtenida en el paso 3 de la sección 2.6
SUBNET_RESOURCE_ID ID de recurso completo de la subred del ACI anotado en la sección 2.3
SERVERNAME Nombre del servidor de PostgreSQL creado en la sección 2.5
DB_ADMIN_USER Nombre de usuario administrador del servidor PostgreSQL
DB_ADMIN_PASSWORD Contraseña de administrador del servidor PostgreSQL
DQE_ADMIN_USER Nombre de usuario administrador de la aplicación DQE One
DQE_ADMIN_PASSWORD Contraseña de administrador de la aplicación 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

Importante: utilice las versiones de imagen proporcionadas por DQE. No las sustituya por la etiqueta latest.

Nota clave sobre la red de ACI: todos los contenedores del grupo comparten el mismo espacio de nombres de red. La comunicación entre contenedores utiliza localhost; por eso REDIS_URL es redis://localhost:6379. PostgreSQL se ejecuta fuera del grupo de contenedores como servicio administrado de Azure, por lo que DB_HOST es el FQDN de Azure Database for PostgreSQL.

2.9. Variables de entorno

Variable Valor de ejemplo Descripción
SFAPIVERSION v65.0 Versión de la API de Salesforce utilizada por la aplicación.
CREATE_SUPERUSER true Crea la cuenta de administrador inicial durante el primer arranque.
RUN_COLLECTSTATIC false Ejecuta el comando collectstatic de Django durante el arranque. Déjelo en false salvo que sea explícitamente necesario.
DQE_ONE_SERVER_ADMIN_USER Nombre de usuario de la cuenta de administrador inicial.
DQE_ONE_SERVER_ADMIN_PASSWORD Contraseña de la cuenta de administrador inicial. Utilice secureValue.
DQE_CLIENT_LICENCE Clave de licencia del cliente proporcionada por DQE.
WEBSITE_HOSTNAME https://myapp.example.com URL pública HTTPS. Debe coincidir con el nombre DNS que apunta al Application Gateway.
SECRET_ENCRYPTION_KEY Clave de cifrado para datos sensibles. Genérela una sola vez y no la cambie tras la implementación. Utilice secureValue.
WAIT_HOSTS localhost:6379 Servicio que se debe esperar antes de arrancar. Utiliza localhost en ACI.
WAIT_HOSTS_TIMEOUT 300 Tiempo máximo de espera en segundos para los servicios dependientes.
WAIT_SLEEP_INTERVAL 5 Retardo en segundos entre comprobaciones de disponibilidad.
WAIT_HOST_CONNECT_TIMEOUT 30 Tiempo de espera en segundos para cada intento de conexión.
REDIS_URL redis://localhost:6379 URL de conexión a Redis. Utiliza localhost en ACI.
PORT 8000 Puerto interno de escucha de la aplicación.
DEBUG false Modo de depuración. Debe ser false en producción.
DB_USER dqeone Nombre de usuario administrador de PostgreSQL definido al crear el Postgres Server.
DB_PASSWORD Contraseña de administrador de PostgreSQL. Utilice secureValue.
DB_NAME dqeone Nombre de la base de datos PostgreSQL. Obligatorio: la aplicación no se iniciará sin este valor.
DB_HOST myserver.postgres.database.azure.com FQDN del servidor PostgreSQL.
DB_PORT 5432 Puerto de PostgreSQL.
DB_VOLUME_PATH ./db/ Ruta para el almacenamiento relacionado con la base de datos.
DB_MAX_CAPACITY 8000000000 Capacidad máxima de la base de datos en bytes.
AUTHORIZED_SFTP_HOSTS depot-1.dqe-software.net Lista de hosts SFTP autorizados, separados por comas.
CSRF_TRUSTED_ORIGINS https://myapp.example.com Orígenes de confianza para el CSRF de Django. Solo es necesario si se accede a la aplicación mediante una URL distinta de WEBSITE_HOSTNAME.

Importante: el SECRET_ENCRYPTION_KEY debe generarse una sola vez y conservarse durante toda la vida útil de la implementación. Para generar una clave compatible:

python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

3. Launcher

3.1. Iniciar sesión en Azure

az login

3.2. Implementar el grupo de contenedores

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

Una vez finalizada la operación, recupere la dirección IP privada asignada al grupo de contenedores:

az container show \
  --resource-group MY_RESOURCE_GROUP \
  --name dqe-standalone \
  --query "ipAddress.ip" -o tsv

Esta dirección IP privada solo es accesible desde dentro de la VNET de Azure.

3.3. Configurar el Backend Pool del Application Gateway

Una vez implementado el ACI, vaya a Azure Portal > Application Gateway > Backend pools > su pool de backend > Edit.

Añada la dirección IP privada del ACI obtenida en el paso 3.2. Haga clic en Save.

3.4. Configurar el Health Probe del Application Gateway

El health probe permite al Application Gateway verificar que la aplicación está en funcionamiento. Vaya a Azure Portal > Application Gateway > Health probes > Add.

Configure el probe para que llame a la ruta raíz de la aplicación mediante HTTP. Haga clic en Test. Si el estado muestra Healthy, el ACI está correctamente configurado y el Application Gateway puede enrutar tráfico hacia él. Haga clic en Add para guardar el health probe.

3.5. Configurar el DNS

Contacte con sus administradores de DNS para crear un registro DNS que apunte a la dirección IP pública del Application Gateway:

Tipo de registro Nombre Valor
A standalone.yourdomain.com IP pública del Application Gateway

3.6. Verificar la instalación

Compruebe que todos los contenedores estén en ejecución:

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

Salida esperada:

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

Nota: ACI inicia todos los contenedores simultáneamente. El mecanismo WAIT_HOSTS gestiona el orden de arranque reintentando la conexión. Es normal que se produzca un retardo de 1 a 2 minutos antes de que la aplicación esté completamente operativa en el primer arranque.

Una vez que todos los contenedores estén en ejecución y el DNS se haya propagado, acceda a https://standalone.yourdomain.com.

4. Direcciones IP que autorizar

Una vez que la aplicación esté en funcionamiento, configure el WAF o el firewall situado aguas arriba para autorizar los siguientes rangos de IP entrantes:

  • DQE Software Office Server: contacte con el soporte de DQE Software para obtener la dirección IP que debe autorizarse.
  • DQE Deduplication Service: contacte con el soporte de DQE Software para obtener la dirección IP que debe autorizarse.
  • DQE Quality Service: contacte con el soporte de DQE Software para obtener la dirección IP que debe autorizarse.

Acción requerida: proporcione a DQE Software la dirección IP pública de salida utilizada por su infraestructura de Azure (NAT Gateway, Azure Firewall o equivalente) para que pueda autorizarse en los servicios de DQE.

5. Solución de problemas

Ver registros de contenedores

Los registros de los contenedores están disponibles en Azure Monitor, en la tabla ContainerInstanceLog_CL. También puede obtenerlos directamente mediante la CLI:

az container logs \
  --resource-group MY_RESOURCE_GROUP \
  --name dqe-standalone \
  --container-name CONTAINER_NAME

Unauthorised al descargar imágenes

Verifique que:

  • la sección imageRegistryCredentials contiene el login y la contraseña correctos proporcionados por DQE;
  • todas las imágenes hacen referencia al registro de producción de DQE dqeone.azurecr.io;
  • las versiones de imagen coinciden con las proporcionadas por DQE.

Configuración de PostgreSQL

Siga la sección 2.5 para el procedimiento de configuración completo. Puntos clave:

  • El servidor debe estar en la misma VNet que el ACI: VNets distintas requieren peering y configuración de zona DNS.
  • Azure Database for PostgreSQL requiere una subred dedicada delegada a Microsoft.DBforPostgreSQL/flexibleServers.
  • Tras crear el servidor, cree la base de datos dqeone desde Azure Portal: Azure Database for PostgreSQL → Databases → + Add.
  • Todas las variables de entorno DB_* deben establecerse en el YAML del grupo de contenedores antes de la primera implementación; consulte la sección 2.8.

CSRF Verification Failed (403)

Django valida que las solicitudes entrantes procedan de un origen de confianza que coincida con WEBSITE_HOSTNAME. Se produce un error 403 CSRF al acceder a la aplicación mediante una URL distinta del hostname configurado.

Solución permanente: configure el DNS para que el hostname definido en WEBSITE_HOSTNAME resuelva a la IP pública del Application Gateway.

Solución temporal (pruebas sin DNS): establezca WEBSITE_HOSTNAME en la dirección IP y añada CSRF_TRUSTED_ORIGINS:

- name: WEBSITE_HOSTNAME
  value: https://YOUR_GATEWAY_IP
- name: CSRF_TRUSTED_ORIGINS
  value: https://YOUR_GATEWAY_IP

Una vez configurado el DNS, revierta ambos valores al nombre de dominio adecuado.

El Health Probe del Application Gateway falla

Verifique que:

  • todos los contenedores del ACI muestran el estado Running;
  • el pool de backend contiene la dirección IP privada correcta del ACI;
  • la subred está correctamente delegada a Microsoft.ContainerInstance/containerGroups;
  • el NSG asociado a la subred permite el tráfico entrante en el puerto 80 desde la subred del Application Gateway.

¿Fue útil este artículo?

Usuarios a los que les pareció útil: 0 de 0