Desplegar la infraestructura de Bitmovin en tu suscripción de Azure con Cloud Connect

Si ya has trabajado con Bitmovin en el pasado sabrás que ellos se encargan de gestionar la infraestructura para los diferentes servicios que ofrecen. Sin embargo, también es posible hacer que esta esté en la nube del cliente por diferentes motivos (costes, seguridad, etcétera). En este artículo te cuento cómo configurarlo con Microsoft Azure.

Prerrequisitos

Lo primero que necesitas, si todavía no lo has hecho es pedir a Bitmovin a través del apartado Infrastructure que te habiliten esta opción, para poder hacer uso de esta opción.

Bitmovin – Encoding – Infrastructure

Configurar recursos en tu suscripción de Azure

Tal y como cuentan en su artículo, lo primero que necesitas es dar permiso a la aplicación bitmovin-azure-connect en tu tenant. Para ello debes utilizar esta URL añadiendo tu tenant ID: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/authorize?client_id=ad59b58a-9910-409a-909e-cf98258bb566&response_type=code&redirect_uri=https%3A%2F%2Fbitmovin.com%2F

Lo siguiente que debes hacer es crear dos recursos en un grupo de recursos: un Network Security Group y una red virtual, a la que asignaremos a este primero. También debes añadir como Contributor a la aplicación bitmovin-azure-connect para que pueda crear los recursos. Para que sea más cómodo su despliegue y mantenible he utilizado Terraform para generarlo:

### Backend ###
# terraform {
#   backend "azurerm" {}
# }

### Providers ###
provider "azurerm" {
  features {}
}

## Data: recover bitmovin-azure-connect
data "azuread_service_principal" "bitmovin_azure_connect" {
  application_id = "ad59b58a-9910-409a-909e-cf98258bb566" 
}

### Resources ###

# Resource group
resource "azurerm_resource_group" "rg" {
  name     = "bitmovin-on-azure"
  location = var.location
}

# Azure Network Security Group
resource "azurerm_network_security_group" "nsg" {
  name                = "bitmovin-nsg"
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name



  #Allow Encoder Service Inbound
  security_rule {
    name                       = "AllowEncoderServiceInbound"
    description                = "For communication with the service that manages the encoding"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "TCP"
    source_port_range          = "*"
    destination_port_range     = "9999"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  #Allow Session Manager Inbound
  security_rule {
    name                       = "AllowSessionManagerInbound"
    description                = "For communication with the service that manages the encoding instances"
    priority                   = 200
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "TCP"
    source_port_range          = "*"
    destination_port_range     = "9090"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  #Allow SSH
  security_rule {
    name                       = "AllowSSH"
    description                = "For incoming commands (i.e. pulling and starting docker containers)"
    priority                   = 1000
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "TCP"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  #Inbound security rules that are necessary to run RTMP live streams

  #RTMP Listener
  security_rule {
    name                       = "rtmp-listener"
    description                = "For RTMP live streams"
    priority                   = 300
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "TCP"
    source_port_range          = "*"
    destination_port_range     = "1935"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  #Inbound security rules that are necessary to run SRT live streams

  #For SRT live streams
  security_rule {
    name                       = "srt-listener-TCP"
    description                = "For SRT live streams"
    priority                   = 400
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "TCP"
    source_port_range          = "*"
    destination_port_range     = "2088"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  #For SRT live streams
  security_rule {
    name                       = "srt-listener-udp-2088"
    description                = "For SRT live streams"
    priority                   = 500
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "UDP"
    source_port_range          = "*"
    destination_port_range     = "2088"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  #For SRT live streams
  security_rule {
    name                       = "srt-listener-udp-2090"
    description                = "For SRT live streams"
    priority                   = 700
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "UDP"
    source_port_range          = "*"
    destination_port_range     = "2090"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  #For SRT live streams
  security_rule {
    name                       = "srt-listener-udp-2091"
    description                = "For SRT live streams"
    priority                   = 800
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "UDP"
    source_port_range          = "*"
    destination_port_range     = "2091"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  #Inbound security rules that are necessary to run Zixi live streams
  #For SRT live streams
  security_rule {
    name                       = "zixi-listener"
    description                = "For Zixi live streams"
    priority                   = 900
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "TCP"
    source_port_range          = "*"
    destination_port_range     = "4444"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

}

# Azure Virtual Network
resource "azurerm_virtual_network" "vnet" {
  name                = "bitmovin-vnet"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  address_space       = ["10.0.0.0/16"]

  subnet {
    name           = "encoders-subnet"
    address_prefix = "10.0.0.0/16"
    security_group = azurerm_network_security_group.nsg.id
  }
}

# Give the bitmovin-azure-connect Application rights to run virtual machines on your subscription
resource "azurerm_role_assignment" "assignment" {
  scope                = azurerm_resource_group.rg.id
  role_definition_name = "Contributor"
  principal_id         = data.azuread_service_principal.bitmovin_azure_connect.object_id
}

Lo que he hecho ha sido recopilar todos los pasos relatados en este artículo y plasmarlos en esta configuración para que su creación y gestión sea lo más sencilla posible.

Dar de alta la infrastructura en Bitmovin

Ahora que ya tienes la infra mínima creada en tu suscripción, debes hacerle saber a Bitmovin qué grupo de recursos, red y subnet has elegido para hacer el despliegue de los encoders cuando haya trabajos que hacer. En el apartado Encoding > Infrastructure deberás dar de alta una nueva infraestructura y añadir los siguientes valores, tal y como se detalla en su artículo:

  • Name: un nombre representativo que quieras dar a esta configuración
  • Subscription ID: el id de la suscripción de Microsoft Azure
  • Resource Group ID: aunque ponga que es el id del grupo de recursos, lo que hay que indicar es el nombre del grupo de recursos, en mi ejemplo bitmovin-on-azure.
  • Tenant ID: el id del tenant asociado a la suscripción.

Además de esto, necesitas dar de alta una región donde quieras desplegar tus recursos. Para ello debes hacer clic en Show details de tu nueva configuración y dar de alta la nueva región, indicando el nombre de la red privada virtual y la subnet creadas anteriormente.

Ahora que ya tienes creado los recursos y conectados con Bitmovin ya puedes comenzar a usar tus encoders.

Ejemplo de encoding

Para hacer una prueba con un encoding, puedes seguir el artículo anterior donde adapté el artículo de Bitmovin para que hiciera uso de Azure Storage para los inputs y outputs. Si además quisieras usar tu propia infrastructura con Cloud Connect, lo único que debes modificar es el apartado donde se crea el encoding:

//Step 6: Create Encoding
// console.log(`Create encoding in Azure West Europe`);
// const encoding = await bitmovinApi.encoding.encodings.create(
//     new Encoding({
//         name: `Encoding for ${process.env.INPUT_FILE} in ${CloudRegion.AZURE_EUROPE_WEST}`,
//         cloudRegion: CloudRegion.AZURE_EUROPE_WEST
//     })
// );

//Cloud Connect with Azure
console.log(`Create encoding using Cloud Connect`);
const encoding = await bitmovinApi.encoding.encodings.create(
      new Encoding({
          name: `Encoding for ${process.env.INPUT_FILE} using Cloud Connect and Azure`,
          cloudRegion: CloudRegion.EXTERNAL,
          infrastructure: new InfrastructureSettings({
             infrastructureId: process.env.INFRASTRUCTURE_ID,
             cloudRegion: CloudRegion.AZURE_EUROPE_WEST
      })
   })
);

Como ves, en este caso ya no utilizas como valor de cloudRegion como CloudRegion.AZURE_EUROPE_WEST, que sería el encoder manejado por Bitmovin, sino que lo marco como CloudRegion.EXTERNAL y añado la propiedad infrastructure, con un objecto InfrastructureSettings, donde especifico además el ID de la infra que quiero utilizar, además de la región que he dado de alta.

Al hacer esto, verás que al ejecutar el código la generación del encoding aparecerá con un icono diferente a cuando es manejada y en la región será la elegida, dentro de tu suscripción:

Encoding con Cloud Connect

Por otro lado en tu grupo de recursos en Azure verás un nuevo recurso de tipo Virtual machine scale set donde estarán las máquinas virtuales que harán los trabajos que has pedido a través de la API de Bitmovin.

Virtual Machine scale set para el encoding

Otra de las ventajas de utilizar este modo es la capacidad de definir pools precalentados (todavía en BETA) para que los encoders estén listos cuando hagan falta y evitar así el tiempo de espera hasta que todo esté listo.

//BETA: Pre-warmed Encoder Pools (https://bitmovin.com/docs/encoding/tutorials/pre-warmed-encoder-pools)
console.log(`Create pre-warmed pool`);
let poolToCreate = new PrewarmedEncoderPool({
      name: "Fast-track encodings",
      description: "Use for encodings that have to be done immediately",
      encoderVersion: "2.77.2",
      infrastructureId: process.env.INFRASTRUCTURE_ID,
      cloudRegion: CloudRegion.AZURE_EUROPE_WEST,
      diskSize: PrewarmedEncoderDiskSize.GB_500,
      targetPoolSize: 1
});

let createdPool = await bitmovinApi.encoding.infrastructure.prewarmedEncoderPools.create(poolToCreate);
console.log(`Pre-warmed pool created with id ${createdPool.id}`);
console.log(`Starting the pool ${createdPool.id}`);
await bitmovinApi.encoding.infrastructure.prewarmedEncoderPools.start(createdPool.id);

let listOfPools = await bitmovinApi.encoding.infrastructure.prewarmedEncoderPools.list();
console.dir(listOfPools);

Para esta característica también es necesario solicitar el acceso al equipo de Bitmovin.

He actualizado el repo de GitHub con este ejemplo.

¡Saludos!