La utilización de contenedores Docker nos ha facilitado la vida en muchos ámbitos de desarrollo y devops en entornos de desarrollo, de testing y de producción también. Ahora también nos puede facilitar las cosas a la hora de pasar nuestras aplicaciones a la nube.

Tenemos herramientas que nos proporcionan un chequeo más o menos efectivo de nuestras aplicaciones para darnos una vista preliminar e incluso realizarnos la migración a Azure, como por ejemplo el App Service Migration Assistant, que escanea nuestra configuración en el Internet Information Server y nos verifica si la configuración que tenemos para una aplicación en el IIS es válida para ser llevada tal cual a una Web App en Azure.

La versión actual chequea 13 puntos de la configuración de IIS, pero, aunque obtengamos 13 OK esto no garantiza que nuestra aplicación vaya a funcionar tal y como la tenemos en on-premise como WebApp. Además de usar esta aplicación de migración, debemos repasar otros puntos y funcionalidades de la aplicación y comprobar que cumplan con los requisitos que una Web App en Azure supone.

Una de estas restricciones, es la de hacer un uso de aplicaciones instalables de terceros. Es decir, si nuestra aplicación para ejecutar una parte del código requiere instalaciones a nivel de sistema operativo, bien sean .msi, funcionalidades del SO, ejecutables, instalación de paquetes concretos de Linux, etc.
Si tenemos esto, habrá que revisar esas dependencias y ver si son ejecutables como WebApp o no, ya que no podremos instalar nada en el App Service donde tengamos alojada nuestra web app.

Para el ejemplo, supongamos que tenemos una aplicación web de reporting que hace uso del Crystal Reports de SAP en nuestro servidor IIS on-prem.

Al ejecutar el Migration Assistant tool en un servidor donde tengamos desplegada la aplicación web, nos da el siguiente resultado:

Por lo que nos dice que nuestra aplicación es migrable a una WebApp. Después de completar el asistente y especificarle la subscripción, grupo de recurso, App Service y nombre de la WebApp, el asistente crea los recursos necesarios y nos dice que nuestra web ha sido migrada correctamente.

Para el ejemplo que vamos a ver ahora, obviamos la parte de migración de SQL Server, que podemos o bien migrarla también a Azure, o activar el Hybrid Connection para acceder a nuestros datos on-prem desde la WebApp en Azure. Vamos a centrarnos en la correcta ejecución de Crystal Report.

Al intentar acceder a la URL de la webapp que hemos migrado, nos aparece un error de ejecución, que si profundizamos en él es una falta de dependencias al no tener instalado el runtime del CrystalReport y sus dependencias.

Tenemos dos posibles alternativas para llevar esta aplicación a Azure:

  • Modelo PaaS: Desplegar un contenedor Docker
  • Modelo IaaS: Desplegar la aplicación en una MV

Las ventajas de un modelo PaaS en cuanto a mantenimiento, costes, escalabilidad y disponibilidad frente a un modelo IaaS son evidentes, pero para una solución de este estilo hasta hace relativamente poco no teníamos otra opción que ir a morir a un modelo IaaS.

Ahora pudiendo desplegar una instancia de contenedor Docker con Azure Container Instance (ACI) o una web app que corra un contenedor Docker, tenemos más opciones.
¿Por qué una WebApp en vez de un ACI? Al desplegarse como WebApp nos permite gestionarlo como el resto de aplicaciones web que tengamos en nuestro entorno además de poder usar las funcionalidades que nos da para una webapp “estándar”.

Nos permite balancear la carga entre regiones, hacer uso de API Management, seguridad a nivel de webapp, despliegue en slots y configuración de slots, gestión de logs, monitorización de recursos etc…
Si estamos acostumbrados a trabajar con WebApp o vamos a lanzarnos a migrar nuestras aplicaciones web a Azure, podremos hacer una migración más homogénea al migrar nuestras aplicaciones en IIS a WebApps sin más conceptos nuevos.

Ahora bien, ¿cómo hacemos esto?

Vamos a ver como hacer esto de manera local paso a paso.

Visual Studio 2019 ya trae una opción para publicar una aplicación web como webapp basada en contenedor, pero vamos a ver cómo hacerlo paso a paso para comprender el proceso y poder automatizarlo e incluirlo en nuestro flujo de CI/CD.

Estos mismos pasos se podrían reproducir desde un pipeline y una release desde Azure DevOps con ligeras modificaciones a la hora de publicar los contenedores y los recursos. No sería necesario hacer un login interactivo si tenemos el grupo de recursos o la subscripción como Servicio conectado dentro de nuestra organización/proyecto.

 

1. Compilar la aplicación web para publicación.

Para la compilación usaremos un perfil de publicación al sistema de ficheros local generado desde Visual Studio

Esto en Azure DevOps lo haremos con una tarea de MSBuild.

 

2. Generar el Dockerfile

Para construir un contenedor personalizado se utiliza un Dockerfile, donde se define con una serie de instrucciones las acciones y capas que va a tener nuestro contenedor. Asi cuando se ejecute, nuestra aplicación funcionará correctamente. Siempre se parte de un contenedor base y puede ser Windows o Linux.

En nuestro ejemplo, nos basaremos en el contenedor Microsoft/iis ya que tenemos una aplicación web hecha en .Net Framework y usa el runtime de Crystal Report que está disponible para windows.
Los pasos a seguir serán los siguientes:

  • Obtener dlls necesarias de otra imagen de Windows que en nuestro caso son necesarias para la correcta ejecución de los informes de Crystal Report
  • Activar las features de Windows server para IIS
  • Instalación del runtime de Crystal Report
  • Publicación del código de la aplicación en el IIS del contenedor.

El contenido del Dockerfile final será el siguiente:

Para construir la imagen del contenedor que desplegaremos usamos la siguiente instrucción desde la carpeta raíz del proyecto. Para poder generar esta imagen tenemos que usar la versión de Windows de Docker y asegurarnos de tenerlo corriendo en modo Windows Containers o tendremos un error a la hora de descargar y usar las imágenes de Windows e IIS.

$ docker build . -t creportdemo

El punto de la orden anterior indica la ruta que le vamos a pasar al motor de Docker como contexto de la build, todas las rutas que usemos dentro del dockerfile de manera parcial tienen su origen en este path.
La salida de este comando será algo similar a esto:

Con esto ya tenemos una imagen de contenedor formada en local con el nombre creportdemo.

 

3. Crear un Azure Container Registry

Azure Container Registry (ACR) es un servicio que nos proporciona un repositorio de imágenes Docker privado. Podemos usar otros repositorios de imágenes como Docker Hub, pero están más enfocados a imágenes de contenedores públicas o privadas bajo el pago de una licencia Enterprise.

Si las imágenes las vamos a desplegar en Azure, ya sea con Kubernetes, con ACI o con web apps, la integración con el Azure Container Registry viene casi ya hecha, pero podemos utilizar otro registro.

Si ya tenemos un ACR podemos usarlo y crear una imagen nueva en el repositorio.
Si no lo tenemos, podemos crearlo o bien desde el portal o bien haciendo uso del Azure CLI

La URL de nuestro ACR será siempre <nombre-acr>.azurecr.io

Con este fragmento de código, podemos comprobar si ya existe un ACR con el nombre especificado en el grupo de recursos y si no existe crearlo y hacer el Docker login necesario para poder subir la imagen.

Esto mismo, podemos usarlo en los flujos de CI/CD tal cual lo estamos haciendo en local, pero lo ideal sería usar un template ARM para generar el recurso y asignarle permisos a nuestro pipeline para poder hacer push de imágenes.

 

4. Subir imagen del contenedor al ACR

Para poder desplegar la imagen que hemos formado a nuestro ACR, tendremos que hacer login a través de Docker. Esto se hace usando el comando Docker login tal y como se muestra en la última línea de fragmento de código del punto anterior.

Para poder subirlo, tenemos que nombrar la imagen que hemos compilado “creportdemo” con el nombre completo de nuestro ACR, nombre de la imagen y etiqueta.
La etiqueta nos vale para marcar la versión de la imagen, por si actualizamos la versión de software, algún componente instalado o correcciones. La etiqueta por defecto en todos los registros de contenedores es latest, cuando nosotros usamos Microsoft/iis, es como si usáramos Microsoft/iis:latest.

Es buena práctica que además de generar la versión latest que al subirla sustituirá a la actual, generar una etiqueta que identifique la versión, por ejemplo, si la compilación de la imagen es del 28 de octubre de 2020 podemos usar: 10.28.2020
Si queremos mantener versiones por entorno: prod, qa, dev… podemos usar estas etiquetas o generar “rutas” para una sola imagen. O dividir por carpetas si queremos mantener un solo ACR un poco más ordenado con las imágenes de varios proyectos.
Un ejemplo con todos estos atributos podría ser: 

gperezacr.azurecr.io/release/demos/docker/webapp/creportdemo:10.28.2020

Para hacer esto, desde la terminal usamos los siguientes comandos:

$ docker tag creportdemo gperezacr.azurecr.io/release/demos/docker/webapp/creportdemo:10.28.2020
$ docker push gperezacr.azurecr.io/release/demos/docker/webapp/creportdemo:10.28.2020


$ docker tag creportdemo gperezacr.azurecr.io/release/demos/docker/webapp/creportdemo:latest
$ docker push gperezacr.azurecr.io/release/demos/docker/webapp/creportdemo:latest

Para el ejemplo usaremos este:
$ docker tag creportdemo gperezacr.azurecr.io/release/demos/docker/webapp/creportdemo:latest
$ docker push gperezacr.azurecr.io/release/demos/docker/webapp/creportdemo:latest

Desde el portal se vería así:

 

 

 

 

 

 

 

La manera de verlo en el portal no ayuda demasiado a la organización, pero esta organización por URLs nos puede ayudar en la automatización de publicaciones además de saber exactamente con que imagen y entorno estamos usando.

 

5. Desplegar web app con ARM

Por último, nos falta crear la webapp vinculada a la imagen que hemos subido al ACR.
Las webapps que corren contenedores Docker funcionan sobre Application Service Plan al igual que una webapp en la que publicamos el código directamente.

Para poder ejecutar contenedores Windows requiere que el Service Plan sea de tier Premium y V3 con la opción de hyper-v activa. Esta opción desde el portal no podemos especificarla al crear un App Service Plan (de momento), debemos hacerlo con una plantilla ARM o bien con el Az CLI con el siguiente comando:

$ az appservice plan create --name $aspName --sku $aspSku --location $resourceGroupLocation --resource-group $resourceGroupName --hyper-v

Si no cumple estas condiciones, no podremos desplegar el contenedor. Para contenedores Linux, necesitamos un Service Plan Linux y en casi cualquier tier permite desplegar webapps sobre contenedores Docker.
La funcionalidad de ejecutar contenedores Docker basados en Windows como webapp, a dia de hoy (Octubre 2020) está en preview, de hecho si intentamos hacer el despliegue desde el portal accediendo al ACR e intentando desplegar una imagen como WebApp Windows tiene errores y no detecta correctamente los service plan. Sin embargo, si se hace desde dar de alta una nueva webapp si que permite hacerlo.

Algo similar pasa con la línea de comandos de Azure CLI ya que solo permite desplegar WebApps basadas en contenedores Linux dando errores si lo intentamos para imágenes basadas en Windows con un Service Plan Windows.
Haciendo uso del Azure CLI tampoco permite realizar un despliegue ARM donde se despliegue una webapp ejecutando un contenedor Windows.
Podemos automatizar el despliegue haciendo uso de las funciones Az de Powershell para desplegar un ARM con el siguiente recurso (el fichero completo aquí):
{
    "apiVersion": "2018-11-01",
    "name": "[parameters('name')]",
    "type": "Microsoft.Web/sites",
    "location": "[parameters('location')]",
    "tags": null,
    "dependsOn": [],
    «properties»: {
        «name»: «[parameters(‘name’)]»,
        «siteConfig»: {
            «appSettings»: [
                {
                    «name»: «DOCKER_REGISTRY_SERVER_URL»,
                    «value»: «[parameters(‘dockerRegistryUrl’)]»
                },
                {
                    «name»: «DOCKER_REGISTRY_SERVER_USERNAME»,
                    «value»: «[parameters(‘dockerRegistryUsername’)]»
                },
                {
                    «name»: «DOCKER_REGISTRY_SERVER_PASSWORD»,
                    «value»: «[parameters(‘dockerRegistryPassword’)]»
                },
                {
                    «name»: «WEBSITES_ENABLE_APP_SERVICE_STORAGE»,
                    «value»: «false»
                }
            ],
            «windowsFxVersion»: «[parameters(‘windowsFxVersion’)]»,
            «appCommandLine»: «[parameters(‘dockerRegistryStartupCommand’)]»,
            «alwaysOn»: «[parameters(‘alwaysOn’)]»
        },
        «serverFarmId»: «[concat(‘/subscriptions/’, parameters(‘subscriptionId’),’/resourcegroups/’, parameters(‘serverFarmResourceGroup’), ‘/providers/Microsoft.Web/serverfarms/’, parameters(‘hostingPlanName’))]»,
        «clientAffinityEnabled»: false
    }
}

Usando el siguiente bloque de código de powershell podemos hacer el despliegue de nuestra webapp con un contenedor Docker basado en Windows:

La salida de este comando debe ser la siguiente:

Y después de esto, ya tenemos nuestra webapp corriendo el contenedor Docker sobre Windows con el runtime de CrystalReport y sirviendo reports.

 

Conclusiones

Con esta nueva funcionalidad, conseguimos ser capaces de migrar aplicaciones on-prem a un modelo PaaS de WebApp que de otra manera tendríamos que llevar a un modo IaaS.
Además, podemos integrar aplicaciones legacy o con dependencias de nuestro entorno en una plataforma cloud que nos permitirá crecer tanto vertical como horizontalmente. De este modo, también estaremos preparados para ejecutar nuestras aplicaciones legacy en nuevas arquitecturas como Kubernetes con el servicio de Azure Kubernetes Service (AKS).
Ya tenemos cada vez menos stoppers para dar el salto a la nube sin tener que rehacer nuestras aplicaciones.

Código del artículo

En la siguiente URL https://github.com/SolidQES/AzureWebAppDockerContainerDemo encontrarás el proyecto de aplicación web, el Dockerfile para generar la imagen Docker y dos scripts powershell. createParameters.ps1 para introducir los datos de tu subscripción y establecer todos los datos para el despliegue y CreateAndDeployWebAppContainer.ps1 para crear desde el grupo de recursos hasta la webapp vinculado al conector ACR.

El instalador del runtime de Crystal Report requiere descargarlo con una cuenta gratuita. Lo puedes hacer aquí.
Descárgalo y cópialo en la carpeta de Resources para poder ejecutar todos los pasos del artículo.

 

Enlaces:

 

X Edición Executive Máster en BI & Advanced Analytics con Tecnologías Microsoft. Conviértete en un año en un experto en BI con un seguimiento personalizado de los mentores y MVPs de SolidQ y con el nuevo temario del máster en BI & Advanced Analytics , introduciendo Modern Data Warehouse, analítica y visualización avanzada.

¡Empezamos el 18 de febrero! Inscríbete ahora y aprovecha el descuento de 50% en la matrícula y 25% en el precio total que hay disponible hasta finales de diciembre. (Válido para las 10 primeras inscripciones desde en inicio de la oferta) Toda la información aquí.