Archivo de la categoría: Azure

Presentación Windows Azure VPN Workshop #windowsazure

Aquí esta la presentación que hicimos hoy junto a Alejandro Pachecho en Microsoft Chile sobre Windows Azure VPN.

Links relacionados

Presentación: Using windows azure to develop secure and deploy cloud applications Santiago Chile

vs2013_a

En el contexto del lanzamiento de Visual Studio 2013 presenté las siguientes laminas. En la exposición se muestran los conceptos básicos de Windows Azure y las herramientas que VS2013 trae para facilitar el desarrollo de aplicaciones en la Nube.

En las siguientes ligas se pueden hacer tutoriales parecidos a las demostraciones  que vimos en la presentación.

  1. Escenario de DEV/TES de Sharepoint en Azure VM
  2. Creación de Web Sites en Azure
  3. Debugging remoto con Visual Studio 2013
  4. Crear una aplicación Windows Phone 8 con BackEnd en Azure Mobile Services
  5. Publicar servicios internos en Azure Service Bus Relay

Windows Azure Queues and Windows Azure Service Bus Queues

Aquí publico una pequeña comparación de las opciones de mensajería de Windows Azure, con foco en Services bus Queues y ejemplos transaccionales que compilé la semana pasada para un proyecto en México.

Lo que necesita el proyecto es poder habilitar mensajería transaccional entre servidores en sus instalaciones y servicios corriendo en la Nube. Aquí se incluye un ejemplo de cómo enviar mensajes desde una cola MSMQ a una Cola del Service Bus en Azure de manera transaccional.

Links relacionados

  1. Colección de EBooks GRATIS de tecnologías Microsoft, incluida Windows AZURE
  2. Mejores Prácticas para el Diseño de la arquitectura en CLoud
  3. Presentación: Introducción SOA

 

Windows Azure Session Affinity en Java/Tomcat con HTTPS/SSL #windowsazure

Introducción

Muchos desarrolladores de JAVA que desarrollan en eclipse están utilizando Windows Azure para hacer despliegue de sus aplicaciones en la Nube. Optan por Azure en el modelo de plataforma como servicio (PaaS) que les brinda muchas ventajas como por ejemplo elasticidad horizontal para responder a demanda variable, control automático de la plataforma basado en monitoreo de las aplicaciones, altoa disponibilidad de 99,95% asegurada,  etc.

Las aplicaciones desarrolladas para correr en PaaS siguen ciertas directivas de diseño para aprovechar al máximo las capacidades de la plataforma. Una de esas directivas es no utilizar estado en memoria, porque eso genera dependencia del cliente (Browser en una aplicación Web) con la instancia del servicio que lo está atendiendo. La razón por la cual se busca que esta dependencia no exista es para permitir escalar horizontalmente sin problema a las aplicaciones, dando la potencialidad de convertirse en aplicaciones que no tendrán problemas de desempeño si se ven enfrentados a picos de utilización.

Históricamente los desarrolladores Web han utilizado variables de sesión almacenadas en memoria para conservar estados.  Con eso se les simplificaba el trabajo ya que podía almacenar cualquier información que considerara parte de la sesión del usuario en memoria y acceder a ella. Esto generaba un problema cuando las aplicaciones web son desplegadas en una granja de servidores constituida por más de una instancia del servidor Web y un balanceador de carga.

Para Ilustrar el problema veamos el siguiente escenario. Una aplicación web con estado en memoria que es desplegada en dos instancias coordinadas por un balanceador de carga (NLB) como se muestra en el diagrama 1. La idea es que el usuario ingresa su nombre de usuario / contraseña para inicia una sesión (Mensaje 1), esa petición es enviada a la instancia cero del servicio web y esa instancia crea la sesión en memoria de ese servidor. Lugo, el cliente vuelve ha hacer un requerimiento donde le pregunta al servidor web los datos de su sesión (Mensaje 2), esa petición es enviada a la instancia uno servicio web quien la busca en memoria y por supuesto no la encuentra ya que esa sesión fue creada en la instancia cero lo que produce un error!

1

Una solución simple para este problema es configurar el balanceador para que genere afinidad entre el cliente y la instancia de servicio que lo está atendiendo, comúnmente esto se llama Sticky Session. Esta configuración lo que hace es que la primera vez que un cliente se conecta lo envía a una instancia de servicio y almacena esa información (cliente/instancia) en memoria del balanceador. Entonces cuando el balanceador recibe la siguiente llamada de un cliente ya conocido lo envía siempre a la misma instancia, como se muestra en el diagrama 2.

2

Esta solución, muy simple de configurar, tiene la desventaja de que si la instancia cero de nuestro ejemplo cae, entonces todos los clientes que tienen afinidad con esa instancia caen también con ella aunque el servicio tenga otras instancias funcionando.

La solución más correcta en aplicaciones que corren en PaaS es que esa sesión sea almacenada en memoria compartida por todas las instancias del servicio web ya que así no se produce este error ya que todas las instancias tienen acceso a los mismos datos. En Windows Azure para esto se implementa memcache. Para más detalles de esto en JAVA, pueden ver el tutorial How to Use Caching.

Ahora, muchas aplicaciones JAVA ya fueron construidas con sesiones en memoria y vienen de despliegues tradicionales en Datacenters en los cuales los balanceadores de carga fueron configurados con Sticky session. Para hacer mas simple la migración de esas aplicaciones a Windows Azure, en el Plugin de Eclipse se incorporó la opción de configurar Session Affinity para evitar tener que modificar el código de las aplicaciones para que usen memoria compartida. La figura 3 muestra la pantalla de configuración de Session Affinity en Eclipse.

3

Escenario

El escenario que vamos a utilizar es una página Web desarrollada en JSP que es hospedada en el servidor web Tomcat. Un escenario muy común en el mundo JAVA. Esta aplicación será desplegada en Windows Azure utilizando Worker Role, con la opción de Session Affinity sobre HTTPS. La figura 4 muestra el escenario de este artículo.

4

Una sorpresa común para los desarrolladores de JAVA que usan Eclipse y el plugin de Azure es que en el despliegue de su solución se utiliza Internet Information Services (IIS) con Application Request Routing (ARR). ARR es el responsable de mantener la afinidad de la sesión, sin intervención alguna de Tomcat. Este elemento es quien identifica a los clientes y crea la afinidad entre cada cliente y una de las instancias de Tomcat. Esto permite que cada vez que llega un requerimiento desde el cliente ARR lo envía siempre a la misma instancia de Tomcat permitiendo así que las variables de sesión en memoria funcionen correctamente.

La página JSP de nuestra aplicación web nos permitirá identificar que instancia de Tomcat nos está respondiendo, que instancia de ARR nos esta rutenado e ver los identificadores de sesión de Tomcat y el identificador de ruteo de ARR como se muestra en la figura 5.

5

Implementación paso a paso

  1. Crear un proyecto tipo Dynamic Web Project en Eclipse

Utilizando Eclipse creamos un nuevo proyecto web dinámico con el nombre de HolaMundov2 como se muestra en la figura 6.

6

2. Crear una página JSP en la carpeta WebContent

Ahora, debemos crear la página JSP que utilizaremos en nuestra aplicación la cual llamaremos index.jsp como se muestra en la figura 7.

7

3. Modificar la página JSP

Reemplazamos el código que viene por defecto en la página por el siguiente código.

<%@page import="java.net.InetAddress"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Hola Mundo V2 JSP</title>
</head>
<body>
	<%
	java.net.InetAddress ip = java.net.InetAddress.getLocalHost();
	ip = InetAddress.getLocalHost();
	System.out.println("Current Server IP address : " + ip.getHostAddress());
	String hostName=request.getServerName();
	String x=(String)session.getId();
	if ( x  == null ) {
			x="";
		}
    Integer count = (Integer)session.getAttribute("COUNT");
	// If COUNT is not found, create it and add it to the session
    if ( count == null ) {
      count = new Integer(1);
      session.setAttribute("COUNT", count);
    }
    else {
      count = new Integer(count.intValue() + 1);
      session.setAttribute("COUNT", count);
    }
	%>
	<br>IP TOMCAT Server: <b><%=ip.getHostAddress() %></b><br>
	Cloud Services: <b><%=hostName%></b>
	<br>
	Session ID: <B><%=x  %></B>
	<br>Session Counter: <b><%=count%></B> times.

	<script language="JavaScript">
		var req = new XMLHttpRequest();
		req.open('GET', document.location + 'lala.jps', false);
		req.send(null);
		var headers = req.getAllResponseHeaders().toLowerCase();
		document.write('<p><b>HTTP Headers</b>: '  + headers);
	</script>

	<%
	   Cookie cookie = null;
	   Cookie[] cookies = null;
	   // Get an array of Cookies associated with this domain
	   cookies = request.getCookies();
	   if( cookies != null ){
	      out.println("<h2> Found Cookies Name and Value</h2>");
	      for (int i = 0; i < cookies.length; i++){
	         cookie = cookies[i];
	         out.print("Name : " + cookie.getName( ) + ",  ");
	         out.print("Value: " + cookie.getValue( )+" <br/>");
	      }
	  }else{
	      out.println("<h2>No cookies founds</h2>");
	  }
%>
</body>
</html>

4. Ejecutar en el ambiente local
Para poder ejecutar localmente la página JSP debemos definir un nuevo servidor Tomcat 7 como se muestra en la figura 8. Como segundo paso del asistente, agregamos nuestra aplicación.

8

Una vez creado el servidor podemos ejecutar localmente el proyecto obteniendo como respuesta la página mostrada en la figura 9 en el mismo ambiente de Eclipse. En este momento estamos listos para hacer el despliegue en Windows Azure.

9

5. Crear un proyecto tipo Windows Azure Deployment Project
Ya tenemos funcionando nuestra aplicación de prueba en el ambiente local, por lo que ahora debemos hacer el proyecto de despliegue. Este proyecto lo que hace es crear un paquete de instalación y un archivo de configuración de Azure.  Dentro del paquete van utilitarios que instalaran y configuraran los diferentes componentes necesarios para que esta aplicación funcione correctamente, como por ejemplo Java Runtime Environment (JRE), el servidio de Tomcat, etc.

Al crear el proyecto, seguimos el asistente como se muestra en las siguientes imágenes.

Primero le asignamos un nombre al proyecto de despliegue.

10

Segundo, incluimos el JDK en el proyecto.

11

Tercero, incluimos el servidor Tomcat.

12

Cuarto, Incluimos nuestra aplicación (WAR)

13

Por último, debemos seleccionar la opción de Session Affinity para que se configure la afinidad entre clientes y una de las instancias de Tomcat.

14

6. Cambio de configuración de Puertos para soportar SSL

Una vez terminado el asistente Eclipse crea un proyecto de despliegue que tiene dos EndPoints  definidos como se muestra en la imagen 15. EL llamado “http” tiene el puerto publico 80 y privado 31221 mientras el llamado “http_SESSION_AFFINITY” solo el privado 8080. La idea de esta configuración es que las llamadas http:80 son recibidas por el balanceador del Cloud Services y enviados al puerto 31221 donde IIS ARR lo recibe y lo redirige a alguna de las instancias de Tomcat que está escuchando en el puerto 8080.

15

Ahora como nosotros queremos que esto funcione sobre HTTP:443 debemos modificar la configuración por defecto de los EndPoints como se muestra en la imagen 16.

16

7. Instalar el Certificado a utilizar en el Cloud Services

Para poder utilizar HTTPS necesitamos un certificado que será utilizado para cifrar la comunicación entre el navegador y el servidor Web. Para esto debemos subir el certificado a nuestro Cloud Services, como se muestra en la imagen 17.

17

En este ejemplo yo estoy utilizando un certificado autogenerado para hacer las pruebas, el cual tiene el Thumbprint 09D7DF2A1779D027CB52DE223FA30C579182109B como se muestra en la siguiente imagen.

18

8. Incluir la referencia al certificado en ServiceDefinition.csdef

LA definición de los servicios de un Cloud Services se hace en el archivo XML llamado ServiceDefinition.csdef. Este archivo describe cada Rol y sus características. Aquí vamos a agregar la referencia al certificado que usaremos, en este caso lo he llamado “web.ssl”. Para esto debemos agregar los siguientes tag como miembro del tag WorkerRole.

<Certificates>
      <Certificate name="web.ssl" storeLocation="LocalMachine" storeName="My"/>
</Certificates>

9. Incluir la referencia al certificado en ServiceConfiguration.cscfg
La configuración del servicio que brinda un Cloud Services se hace en el archivo XML llamado ServiceConfiguration.cscfg, Aquí vamos a agregar la referencia al certificado y su Thumbprint.

<Certificates>
<Certificate name="web.ssl" thumbprint="09D7DF2A1779D027CB52DE223FA30C579182109B" thumbprintAlgorithm="sha1"/>
</Certificates>

10.Definir el número de instancias del servicio
En este mismo archivo vamos a aumentar las instancias del servicio de 1 a 2, para poder generar el escenario mostrado en la figura 4. Para eso modificamos el siguiente TAG en el archivo ServiceConfiguration.cscfg

<Instances count="2"/>

11. Script de configuración Automática de IIS ARR

Dado que el Plugin de Eclipse para Windows Azure, al configurar Session Affinity lo hace sobre HTTP y no sobre HTTPS, nosotros debemos modificar la configuración para que así si funcione el servicio sobre HTTPS. Para lograr este cambio de configuración vamos a utilizar un script llamado stratup.cmd que permite ejecutar comandos destinados a configuraciones especiales antes que el servicio inicie.

Lo que necesitamos hacer en este script sobre IIS es:

  • Borrar el Binding HTTP que tiene el sitio web por defecto
  • Crear el Binding HTTPS para el sitio web por defecto en el puerto 31221
  • Agregar el certificado al puerto 31221
  • Agregar un HTTP Header para poder identificar que instancia de ARR nos esta direccionando (opcional)
  • Reiniciar el servicio IIS para que todas las configuraciones se apliquen

Todo esto debe hacerse de manera automática cada vez que una instancia de se crea, por eso lo incluimos en el script stratup.cmd.  Reemplazamos el contenido original de dicho archivo con el siguiente código.

echo Hello World!
:: Script Variables
set vcerthash=09D7DF2A1779D027CB52DE223FA30C579182109B

:: get ipv4
ipconfig | findstr IPv4 > ipadd.txt
for /F "tokens=14" %%i in (ipadd.txt) do (
	@echo %%i
	set varip=%%i
)
del ipadd.txt /Q
set varip=%varip: =%
:: Move to directory
cd d:\windows\System32\inetsrv > logArrSetup.txt
d:
: Delete HTTP Binding
appcmd set site /site.name: "Default Web Site"  /-bindings.[protocol='http',bindingInformation='%varip%:31221:'] >> logArrSetup.txt
:Create HTTPS Binding
appcmd set site /site.name: "Default Web Site"  /+bindings.[protocol='https',bindingInformation='%varip%:31221:'] >> logArrSetup.txt
:Add Certificate to HTTPS Binding port
netsh http add sslcert ipport=0.0.0.0:31221 certhash=%vcerthash% appid={4dc3e181-e14b-4a21-b022-59fc669b0914} >> logArrSetup.txt
:Add HTTP Header response to track who instance of ARR is reciving the request
appcmd set config /section:httpProtocol /+customHeaders.[name='X-JPG-ARR',value='%varip%']  >> logArrSetup.txt
:Reset IIS Services to update de configuration Changes
iisreset >> logArrSetup.txt

Para efectos de análisis, todos los comandos tienen como salida el archivo logArrSetup.txt. En este archivo vamos a poder ver el resultado de las configuraciones aplicadas en cada instancia de servicio.

12. Publicación en Azure

En este momento ya estamos listos para realizar el despliegue de nuestra aplicación de pruebas. Para eso utilizamos la opción de publicación que nos brinda el Plugin de Eclipse, que inicia el dialogo que se muestra en la siguiente imagen.

Es importante completar la información de Remote Access para que en pasos posteriores podamos conectarnos a las instancias y revisar la configuración.

Una vez terminado de hacer el deploy, obtenemos el esperado mensaje “Running” como se muestra en la siguiente imagen.

20

Prueba de Afinidad de sesión

Ahora, debemos hacer la prueba de afinidad de sesión. Para ello, vamos a ejecutar el siguiente comando

iexplore -private https://tomcatssl.cloudapp.net/HolaMundov2/

Esto lo que hace es abrir un browser en modo privado y carga mi página JSP usando HTTPS como queremos. Al ejecutarlo recibo el mensaje advertencia que el certificado no está emitido por una entidad certificadora reconocida y que la dirección del certificado no corresponde. Esto está bien ya que yo generé ese certificado.

21

Selecciono la opción Continue to this website (not recommended) y me muestra la respuesta de mi página. Recargo la página unas 3 veces y obtengo lo que se muestra en la siguiente pantalla.

22

Primero, podemos ver que la dirección de la instancia de Tomcat con la que se generó afinidad es 10.146.226.34 y la cookie de identificación de sesión es DE9EF2B35416C64B4CB0165F4A6A9C4E. Estos dos datos no deben cambiar nunca ya que todas las futuras peticiones que haga al servidor con este browser van a ser redireccionadas a esa instancia de Tomcat.

Este requerimiento, el balanceador de carga lo envío al IIS ARR  x-jpg-arr: 10.146.226.34 cómo podemos ver en el encabezado de HTTP.

Ahora, recargo la página y obtengo lo siguiente.

23

Se puede ver que la instancia de Tomcat sigue siendo la misma 10.146.226.34, el identificador de sesión también se mantiene  DE9EF2B35416C64B4CB0165F4A6A9C4E pero la instancia de IIS ARR cambío ya que ahora es la x-jpg-arr: 10.175.104.24. Esto quiere decir que el balanceador de carga envío mi nuevo requerimiento a la otra instancia del servicio que tiene la dirección 10.175.104.24 y aquella reconoció que yo ya tengo afinidad con la instancia de Tomcat  10.146.226.34 por lo que redirigió mi llamada a esa instancia.

¿Cómo supo IIS ARR que ya tengo afinidad con un Tomcat?

Bueno, muy simple. IIS ARR creó en la primera llamada una cookie llamada ARRWAP4EJ la cual contiene la información de afinidad de sesión para este navegador. EL valor de esa cookie tampoco cambia en las diferentes llamadas, en mi caso el valor es  5855a053ea34b597db38b95ce14626517935371c9408359ab695f0f1b114977f.  Con esa cookie ARR puede saber dónde enviar este y los próximos requerimientos.

EL comportamiento de las dos llamadas se muestra en el siguiente diagrama de secuencia.

24

Es importante notar que la comunicación entre el ARR y Tomcat es HTTP no HTTPS por lo que el certificado digital sólo debe ser instalado en IIS.

Código fuente

El código fuente se puede descargar desde Github

https://github.com/liarjo/TomcatSSL/tree/master/TomcatSSLSessionAffinity

Conclusiones

Es perfectamente posible configurar de manera automática Session Affinity sobre HTTPS cuando se desarrolla en Java con Eclipse. Solo se debe entender cómo funciona  IIS ARR, el balanceador de Carga y la configuración de IIS a través de comandos como lo hicimos en este ejemplo.

Links Relacionados

Windows Azure Virtual Machine: múltiples sitios en una VM #windowsazure

Dos clientes diferentes, uno en Santiago y otro en Bogotá me han preguntado cómo pueden hospedar distintos sitios web en una máquina virtual de Windows Azure, cada una con su propio dominio. En este artículo se muestra como hospedar 3 sitios web en misma máquina virtual cada uno con su propio DNS. Los sitios de prueba son los siguientes:

  1. xxx.jpgarcia.cl
  2. yyy.jpgarcia.cl
  3. zzz.agrotrade.cl

Los tres sitios anteriores se encuentran en la misma máquina virtual, la que pertenece al  Cloud Services multisitio.cloudapp.net. La idea es que cuando un usuario cargue en su navegador una de esas URL, el DNS server lo envía a al cloud service. Este mediante la configuración de EndPoint de la máquina virtual (VM), envía el requerimiento al puerto 80 de la VM. En este momento es cuando el ARR intercepta la llamada y utilizando las reglas de ruteo envía el requerimiento al sitio web que corresponda, el cual está hospedado en la misma máquina virtual pero en diferente puerto. Todo esto es trasparente para el usuario final, quien no sabe que todo esto está ocurriendo tras bambalinas. La figura 1, muestra el ejemplo de lo que ocurre cuando se llama al sitio http://xxx.jpgarcia.cl. El requerimiento es ruteado por ARR al sitio xxx hospedado en el puerto 8080.

0

Ahora vamos a revisar cómo configurar el escenario de ejemplo paso a paso, lo que dará como resultado que hospedaremos 3 sitios en la misma VM, cada uno con su propio DNS.

Paso 1: Dar de alta una máquina virtual con IIS 7

Primero creamos una máquina virtual en Windows Azure desde la galería con la imagen de Windows Server 2012 Datacenter. Los datos para la creación son los siguientes:

  • Virtual machine name: vmMultiSitio
  • Size: Large
  • New user name: jpg
  • Password: xxxxxx
  • DNS name: multisitio

Se termina el asistente y comienza el aprovisionamiento de la VM.

1

Una vez aprovisionada la VM nos conectamos utilizando terminal server. La instalación  de Internet Information Server (IIS) se hace agregando el rol Web Server (IIS) desde la consola de Server Manager, siguiendo el asistente con todas las opciones por defecto.

2

Una vez terminada la agregación del Rol obtenemos esta confirmación.

Paso 2: Crear los 3 sitios Web en la VM

Ahora,  nos movemos a la consola Internet Information Server (IIS) Manager para crear los 3 sitios Web que se hospedaran en este servidor. Por defecto tenemos un sitio Web llamado Default Web Site que está configurado en el puerto 80. Ahora creamos el sitio Web llamado XXX, como se muestra en la siguiente imagen.

4

Ahora, en el sitio xxx, creamos la página HMTL llamada iisstart.html con el siguiente código.

<!DOCTYPE HTML>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>Microsoft Internet Information Services 8</title>
	</head>
	<body>
		Hola Soy el Servido XXX del puerto 8080
	</body>
</html>

Para el segundo sitio ocupamos la siguiente configuración cuando creamos el sitio Web.

5

Volvemos a crear una página HTML llamada iisstart.html con el siguiente código pero en el directorio del sitio yyy.

<!DOCTYPE HTML>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>Microsoft Internet Information Services 8</title>

	</head>
	<body>
		Hola Soy el Servido YYY del puerto 8081
	</body>
</html>

Por último, creamos el tercer sitio llamado zzz para el sitio xxx.agrotrade.cl con la siguiente configuración.

6

Volvemos a crear una página HTML llamada iisstart.html con el siguiente código pero en el directorio del sitio zzz.

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>Microsoft Internet Information Services 8</title>
	</head>
	<body>
		Hola Soy el Servido ZZZ del puerto 8082
	</body>
</html>

Al terminar estos 3 sitios, tenemos la siguiente vista de sitios en nuestro servidor.

7

Paso 4: Instalar Application Request Routing (ARR)

Ya tenemos nuestra máquina virtual con II8 Instalado y los sitios Web creados. Ahora, vamos a instalar ARR utilizando la herramienta Get New Web Platform Components, desde el menú de acciones al nivel de servidor, como se muestra en la siguiente imagen.

8

Esta acción nos lleva a un sitio web donde tenemos el botón de instalación. No podemos descargar nada hasta cambiar la configuración IE Enhanced Security Configuration, lo configuramos como Off para administradores.

9

Volvemos a IE, lo reiniciamos, bajamos el software  y lo ejecutamos inmediatamente. Cuando esté listo, nos presenta la pantalla de Web Platform Installer 4.5. Aquí buscamos ARR, seleccionamos Application Request Routing 2.5 y luego hacemos click en instalar.

10

Finalizado el proceso de instalación, obtenemos la siguiente confirmación.

11

Cerramos IIS Manager.

Antes de configurar el DNS, agregamos un EndPoint en la VM llamado www, no balanceado como muestra la siguiente figura. La idea es que todos los requerimientos lleguen al puerto 80 de balanceador de carga del Cloud Services y de ahí se lo envíe al puerto 80 de nuestra máquina virtual.

11a

Paso 5: Configurar DNS de los 3 sitios Web

Ya tenemos VM con IIS 8,  los 3 sitios Web creados y ARR instalado. Ahora necesitamos ir a nuestro servidor de DNS y configurar que las URL xxx.jpgarcia.cl, yyy.jpgarcia.cl y zzz.agrotrade.cl para que utilizando el registro CNAME sean direccionados al Cloud Services multisitio.cloudapp.net.

En este punto depende de que herramienta de DNS que se utilice, yo uso WordPress.com. En la siguiente imagen podemos ver los registros CNAME destacados en amarillo.

12

Ahora, para la URL zzz.agrotrade.cl tenemos el siguiente registro.

13

Ahora hacemos las pruebas de configuración de DNS.

1. Cargamos http://multisitio.cloudapp.net/  y vemos la página por defecto de IIS 8, que se sirve desde el Web Server llamado Default.

14

2. Cargamos http://xxx.jpgarcia.cl/ y vemos la página por defecto de IIS 8, que se sirve desde el Web Server llamado Default.

15

3. Cargamos http://yyy.jpgarcia.cl/ y vemos la página por defecto de IIS 8, que se sirve desde el Web Server llamado Default.

16

4. si cargamos http://zzz.agrotrade.cl/ y vemos la página por defecto de IIS 8, que se sirve desde el Web Server llamado Default al igual que los 3 casos anteriores.

Paso 6: Configurar las reglas de ruteo

Llegamos ahora a la parte más importante del artículo, es aquí donde vamos a configurar las reglas de ruteo basados en el la variable HTTP_HOST. Volvemos a IIS Manager y en el nivel de servidor seleccionamos el icono URL Rewrite. Entonces, en acciones seleccionamos Add Rule(s), y en el primer dialogo utilizamos Blank rule con los siguientes valores para el sitio xxx.

17

18

19

Para crear la regla aplicamos el cambio en el panel de acciones.

Con esta regla de ruteo le decimos a IIS que al momento de recibir una petición para el sitio xxx.jpgarcia.cl sobre escriba la dirección de la petición hacia el sitio localhost en el puerto 80, donde está el sitio XXX en nuestra máquina virtual. Como utilicé la opción Rewrite y no Redirect, necesitamos configurar el proxy de ARR para que así el cliente no sea enviado al otro sitio, sino que el proxy llame al sitio XXX le envié la respuesta el cliente sin que el browser haga nada para esto. Esta es la forma de lograr la trasparencia para el usuario final del sitio XXX.

El proxi se active en el icono Application Request Routing Cache, acción Server Proxy Settings como se muestra en la siguiente imagen.

20

Para activar el proxy, después de seleccionar el Checkbox hacemos click en aplicar del panel de acciones.

Para completar la confiugracion creamos dos reglas más, una para el sitio YYY y otra para ZZZ. Para hacerlo seguimos el mismo procedimiento que usamos para el sitio XXX, con lo cual quedamos con las siguientes tres reglas.

21

Paso 7: Probar

Luego de toda la configuración podemos probar si las reglas están funcionando correctamente. Para eso, simplemente cargamos las 3 URL y obtenemos como resultado que cada requerimiento es respondido de manera trasparente por cada correspondiente sitio de nuestra máquina virtual. Además, podemos probar el sitio Default que sigue funcionando, lo que quiere decir que tenemos 4 Web Sites en la misma máquina virtual, funcionando con sus propios nombres de DNS.

22

Comentarios al cierre

Este es un ejemplo para ilustrar el uso de ARR en este escenario, en producción se puede usar pero hay que utilizarlo en esquema de alta disponibilidad. ARR tiene por diseño la capacidad de trabajar en HA.  Lo mismo pasa con los sitios Web, no es buena práctica tener una sola instancia de un sitio, siempre dos o más!

Links Relacionados

Windows Azure Live smooth Streaming (Paas) #windowsazure

Introducción

La semana pasada estuve con un diario local que quiere hacer live streaming si hacer una gran inversión inicial porque no saben cómo van a rentabilizar ese nuevo canal que están desarrollando. Este requerimiento de inversión baja para partir calza perfecto con el comportamiento de costos de las soluciones de Nube. En una solución tradicional, en el Datacenter del cliente, tienen que comprar los servidores que van a necesitar desde el día cero, mientras que en la nube pagaran solo por lo que usan.

En Windows Azure, solución de Nube de Microsoft, existe un servicio llamado Windows Azure Media Services, el cual permite hacer On Demand Streming pero al día de hoy no está disponible para clientes la funcionalidad de Live Streming.

Como Azure es una plataforma, y no un producto, las empresas pueden armar soluciones utilizando las piezas base de la plataforma como si fuera un Lego. En este sentido, podemos armar un servicio de Live Streaming.

Como Azure es una plataforma, y no un producto, las empresas pueden armar soluciones utilizando las piezas base de la plataforma como si fuera un Lego. En este sentido, podemos armar un servicio de Live Streaming.

Existe un proyecto en codeplex llamado Windows Azure Live Smooth Streaming de  DmitriMartynov que implementa el servicio de IIS Media Services 4 de manera automática en un Web Role utilizando las posibilidades de automatización de tareas en el inicio del role. Es un excelente proyecto!

El proyecto soporta dos modos de despliegue, todo en un solo rol o multi instancias. En la primera opción, el servidor de origen (el que recibe el video desde la fuente) y el servidor de distribución son el mismo. La segunda opción, de una implementación distribuida, el servidor de origen y el de distribución son diferentes y además se podría tener varias instancias de distribución.

En mi opinión, la implementación todo en uno, funciona bien para pequeñas implementaciones. Ahora, el modelo que se propone para multiroles, tiene un detalle que afecta el desempeño y que puede ser mejorado. La arquitectura propuesta por  DmitriMartynov es siguiente.

Las observaciones que tengo de la solución son básicamente dos. Primero, una oportunidad de mejora que tiene que ver con el comportamiento de Windows Azure. La comunicación entre el rol que llaman en el diagrama upstream con el dwonstream se hace a través del endpoint público. Esto trae como consecuencia que  la comunicación “sale” de la red internar y pasa por el balanceador de carca de cada Cloud Services donde se hospeda cada servicio. Yo utilizaría una red virtual entre los dos Cloud Services para tener comunicación directa entre los diferentes servicios. La utilización de una red virtual tiene múltiples ventajas de performance ya que por ejemplo, todos los recursos están en el mismo Affinity Groups, la comunicación es interna sin pasar por los balanceadores y la VIP, etc.

Segundo, esta es una observación de IIS Media Service, en vez de hacer PULL desde los servidores de distribución al origen se puede hacer que el origen haga push a los servidores de distribución, y así dejar a los servidores de distribución con la única responsabilidad de entender clientes finales. El siguiente diagrama muestra mis propuestas.

d1
Ahora, vamos a ver como configurar el escenario propuesto en este post.

Configuración de la red virtual en Windows Azure

La creación de una red virtual se puede realizar siguiendo el asistente del sitio de administración de Azure. Para este caso, vamos a utilizar el asistente de una creación personalizada. En el primer paso nos pide el nombre de la red virtual y el grupo de afinidad. El grupo de afinidad es clave ya que le indica al datacenter que todos los recursos que están afiliados a ese grupo trabajan juntos por lo cual deben ser desplegados lo más cerca posible para disminuir la latencia de comunicaciones entre ellos.

d2

En el paso dos, nos preguntan sobre si usaremos un DNS propio, si tendremos VPN site to site y point to site. En este caso, no necesitamos nada de esto por lo que avanzamos al paso 3.

d3

En el tercer paso, tenemos la definición del direccionamiento y las sub redes. Este es el paso principal de configuración para nuestra solución. Aquí definimos básicamente dos segmentos, uno para el servidor de origen (UpStream) es decir el servidor que recibe el video desde la fuente y otro para los servidores de distribución (DownStream).

d4

Proyecto Cloud

Ahora que tenemos la red Virtual lista en Azure, pasamos a desarrollar el cloud en Visual Studio. La idea es crear 2 Cloud services, Upream y DownStream. El primero solo tendrá una instancia de un Web Role que tendrá el punto de publicación PUSH para recibir el viedo desde la fuente codificada.  Este Web Role tiene la siguiente definición  de servicio, la cual se refleja en el archivo ServiceDefinition.csdef. En este xml podemos ver que tiene 1 instancia y en EndPoint público llamado “push” en el puerto 8080.

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="waUpStream" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
  <WebRole name="upStream" vmsize="Medium">
    <Sites>
      <Site name="Web">
        <Bindings>
          <Binding name="Endpoint1" endpointName="push" />
        </Bindings>
      </Site>
    </Sites>
    <Endpoints>
      <InputEndpoint name="push" protocol="http" port="8080" />
    </Endpoints>
    <Imports>
      <Import moduleName="Diagnostics" />
      <Import moduleName="RemoteAccess" />
      <Import moduleName="RemoteForwarder" />
    </Imports>
    <Startup>
      <Task commandLine="startup.cmd" executionContext="elevated">
      </Task>
    </Startup>
  </WebRole>
</ServiceDefinition>

Junto a lo anterior, aquí se define la tarea de configuración de IIS Media Services. La idea es que cuando este rol se inicie, se instale IIS Media Services de manera automática como buena aplicación PaaaS. Para ellos, se ejecuta la línea de comando llamada “startup.cmd”con privilegios elevados porque realizará instalaciones den el servidor. El archivo cmd es el siguiente y realiza la instalación por línea de comando.

set msiexec=%systemroot%\system32\msiexec.exe
set appcmd=%systemroot%\system32\inetsrv\appcmd.exe
%msiexec% /i "%~dp0\IISMedia64.msi" /qn ADDLOCAL=ALL /Le startup_media.txt

Junto a lo anterior, aquí se define la tarea de configuración de IIS Media Services. La idea es que cuando este rol se inicie, se instale IIS Media Services de manera automática como buena aplicación PaaaS. Para ellos, se ejecuta la línea de comando llamada “startup.cmd”con privilegios elevados porque realizará instalaciones den el servidor. El archivo cmd es el siguiente y realiza la instalación por línea de comando.

Después de la definición del servicio, debemos hacer la configuración del servicio la que se ve reflejada en el archivo ServiceConfiguration.Cloud.cscfg. En este archivo podemos ver que el rol solo tendrá una instancia lo que es lógico. Ahora, aquí es donde podemos definir que este Cloud Service utilizará la red virtual creada en el paso anterior. Esto se configura en el nodo llamado NetworkConfiguration, donde le indicamos la subnet en que el rol será desplegado.

<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="waUpStream" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="3" osVersion="*" schemaVersion="2013-03.2.0">
  <Role name="upStream">
    <Instances count="1" />
    <ConfigurationSettings>
    </ConfigurationSettings>
    <Certificates>
      <Certificate name="Microsoft.WindowsAzure.Plugins.RemoteAccess.PasswordEncryption" thumbprint="0DA151D90DD3C3B707595B898EAB5F53ED5609EF" thumbprintAlgorithm="sha1" />
    </Certificates>
  </Role>
  <NetworkConfiguration>
    <VirtualNetworkSite name="vnFrontBack" />
    <AddressAssignments>
      <InstanceAddress roleName="upStream">
        <Subnets>
          <Subnet name="BackEnd" />
        </Subnets>
      </InstanceAddress>
    </AddressAssignments>
  </NetworkConfiguration>
</ServiceConfiguration>

Creación del punto de publicación PUSH de UpStream

Una vez creado y configurado el Cloud Services, debemos crear en el Web Role un punto de publicación del tipo push. Para eso creamos un archivo XML llamado push.isml y agregamos en el mismo los servidores de distribución en el TAG body/par. De esta forma el contenido que el servidor de recibe desde el origine, lo publica en los servidores de distribución.

<?xml version="1.0" encoding="utf-8"?>
<smil xmlns="http://www.w3.org/2001/SMIL20/Language">
  <head>
    <meta name="title" content="Punto de Push para Live Streaming" />
    <meta name="module" content="liveSmoothStreaming" />
    <meta name="sourceType" content="Push" />
    <meta name="publishing" content="Fragments;Streams;Archives" />
    <meta name="estimatedTime" content="0" />
    <meta name="lookaheadChunks" content="2" />
    <meta name="manifestWindowLength" content="0" />
    <meta name="startOnFirstRequest" content="True" />
    <meta name="archiveSegmentLength" content="0" />
    <meta name="formats" content="m3u8-aapl" />
    <meta name="m3u8-aapl-segmentlength" content="10" />
    <meta name="m3u8-aapl-maxbitrate" content="3000000" />
    <meta name="m3u8-aapl-allowcaching" content="False" />
    <meta name="m3u8-aapl-backwardcompatible" content="False" />
    <meta name="m3u8-aapl-enableencryption" content="False" />
    <meta name="filters" content="" />
    <meta name="restartOnEncoderReconnect" content="true" />
  </head>
  <body>
    <par>
      <ref src="http://10.0.0.4/push.isml" />
      <ref src="http://10.0.0.5/push.isml" />
      <ref src="http://10.0.0.6/push.isml" />
    </par>
  </body>
</smil>

Ya que estamos usando redes virtuales podemos conocer de antemano las direcciones IP que  utilizarán los servidores de distribución, basados en el direccionamiento del segmento en el cual son desplegados. En mi caso estoy usando este direccionamiento y los servidores de distribución estarán en la subred llamada BackEnd. El direccionamiento para máquinas de ese segmento comienza en 10.0.0.4 y termina en 10.0.0.6

d5
Con esto tenemos completo nuestro servicio upStream para que el orignen haga push del contenido desde la estación de codificación a la Nube.

Los elementos del proyecto Upstream los podemos ver en la siguiente figura. Tenemos el proyecto Web llamado upStream y el proyecto Cloud Services llamado waUpStream. El primero tiene el instalador de IIS Media Services, el punto de publicación Push.isml y el script inicial de configuración startup.cmd.

d6

Configuración de downStream

Ahora vamos a revisar la definición de servicio de del Cloud Services waDownStream que se encuentra en el archivo ServiceDefinition.csdef. El objetivo de este Cloud Service es recibir la copia push desde el servidor de origen y ponerla a disposición de los clientes finales mediante una granja de servidores, como aparece en la imagen 2 Arquitectura propuesta. En la definición se crea en EndPoint llamado www en el puerto 80, para el acceso de clientes. Además, al igual que en Cloud Service upStream, se crea una tarea de inicio que ejecuta con privilegios elevados el script startup.cmd. Además podemos ver que la instancia en que corre el rol es de tamaño pequeño, ya que aquí apostamos por escalar de manera horizontal, como lo hacen comúnmente los servicios PaaS.

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="waDownStream" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
  <WebRole name="downStream" vmsize="Small">
    <Sites>
      <Site name="Web">
        <Bindings>
          <Binding name="Endpoint1" endpointName="www" />
        </Bindings>
      </Site>
    </Sites>
    <Endpoints>
      <InputEndpoint name="www" protocol="http" port="80" />
    </Endpoints>
    <Imports>
      <Import moduleName="RemoteAccess" />
      <Import moduleName="RemoteForwarder" />
    </Imports>
    <Startup>
      <Task commandLine="startup.cmd" executionContext="elevated">
      </Task>
    </Startup>
  </WebRole>
</ServiceDefinition>

Una vez definido el servicio hay que configurarlo. El archivo ServiceConfiguration.Cloud.cscfg nos muestra que este servicio corre en 3 instancias y que el Cloud Service se conecta a la red Virtual vnFrontBack en la sub red FrontEnd.

<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="waDownStream" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="3" osVersion="*" schemaVersion="2013-03.2.0">
  <Role name="downStream">
    <Instances count="3" />
    <ConfigurationSettings>
    </ConfigurationSettings>
    <Certificates>
      <Certificate name="Microsoft.WindowsAzure.Plugins.RemoteAccess.PasswordEncryption" thumbprint="878C2E5211A054E97146A4FBDEBB61C0FD8F34E4" thumbprintAlgorithm="sha1" />
    </Certificates>
  </Role>
  <NetworkConfiguration>
    <VirtualNetworkSite name="vnFrontBack" />
    <AddressAssignments>
      <InstanceAddress roleName="downStream">
        <Subnets>
          <Subnet name="FrontEnd" />
        </Subnets>
      </InstanceAddress>
    </AddressAssignments>
  </NetworkConfiguration>
</ServiceConfiguration>

El proyecto web de este Cloud Service se llama downStream. Este proyecto contiene un punto de publicación llamado push.isml, que a diferencia del punto de publicación de upStream, este no distribuye el contenido a otros servidores.

<?xml version="1.0" encoding="utf-8"?>
<smil xmlns="http://www.w3.org/2001/SMIL20/Language">
  <head>
    <meta name="title" content="Look Point" />
    <meta name="module" content="liveSmoothStreaming" />
    <meta name="sourceType" content="Push" />
    <meta name="publishing" content="Fragments;Streams;Archives" />
    <meta name="estimatedTime" content="0" />
    <meta name="lookaheadChunks" content="2" />
    <meta name="manifestWindowLength" content="0" />
    <meta name="startOnFirstRequest" content="True" />
    <meta name="archiveSegmentLength" content="0" />
    <meta name="formats" content="m3u8-aapl" />
    <meta name="m3u8-aapl-segmentlength" content="10" />
    <meta name="m3u8-aapl-maxbitrate" content="3000000" />
    <meta name="m3u8-aapl-allowcaching" content="False" />
    <meta name="m3u8-aapl-backwardcompatible" content="False" />
    <meta name="m3u8-aapl-enableencryption" content="False" />
    <meta name="filters" content="" />
    <meta name="restartOnEncoderReconnect" content="true" />
  </head>
  <body>
  </body>
</smil>

Ahora, debemos publicar una página web donde instalar nuestro control de Silverligth SmoothStreamingPlayer.xap para que la gente vea el Streaming. La página se llama default.aspx. El siguiente código muestra el objeto incrustado en el HTML.

d16

Junto con el video, en esta página se muestra el nombre de la instancia de servidor a la cual nos conectamos, recordar que esto corre en una granja de servidores, y se muestra la lista de instancias del rol. Para conocer las instancias del role utilizamos el siguiente código.

foreach (var roleInstance in Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.Roles["downStream"].Instances)
{
    blServers.Items.Add(roleInstance.Id);
}

Podemos ver el contenido de los proyectos en Solution Explorer como se muestra en la siguiente imagen.

d7

Publicación de los servicios

La publicación de los dos servicios lo realizamos con Visual Studio.

d8

d9

d9.1

Captura, codificación y publicación del video en vivo

Una vez completado el despliegue podemos comenzar con la captura del video y su publicación en el servidor de originen. Para ellos vamos a utilizar el programa Microsoft Expression Encoder.  Al iniciar el programa seleccionamos la opción de proyecto Live Broadcasting.

d10

Ahora, configuramos el tipo de Encode de video para una salida del tipo IIS Smooth Streaming con video H.264 Baseline.

d11

Luego, agregamos la fuente de video con la opción Add Live Source, y seleccionamos la cámara que utilizaremos en la opción Video Device. En mi caso voy a utilizar la WebCam de mi escritorio.

d12

Teniendo definido el tipo de codificación y la fuente de video, debemos definir la salida. Nosotros queremos publicar Live Streaming en un servidor en Windows Azure. Para ellos seleccionamos en la pestaña de configuración Output el checkbox streaming y el radio button Publishing point con el valor de http://jpggupstream.cloudapp.net:8080/push.isml en Location. Por último, para conectarse con el punto de publicación apretar el botón Connect, luego de unos segundos debería ponerse verde y decir Connected.

d13

Para habilitar el botón Start, debes activar la cámara haciendo click en Cue Source. Estamos listos para comenzar a trasmitir! Se inicia la transmisión utilizando el botón Strat y podemos ver los cuadros que estamos codificando.

d14

Ahora, utilizando el browser vamos al sitio Web http://jpggdownstream.cloudapp.net/ y podemos ver el video en vivo.

d15

Con esto completamos el sencillo procedimiento necesario para montar en la nube un servicio de Live Streaming, con separación de roles de servidor de origen y granja de distribución con comunicación por la red interna entre los Cloud Services.

Links Relacionados

Windows Azure Tech Series: Media Services #windowsazure

Esta es la presentación y contenido del evento Windows Azure Tech Series: media Services que se realizó ayer en las oficinas de MS Chile.

Alguno de los comentarios que recibidos de los asistentes y mis respuestas a los mismos 😉

  1. Publicar los ejemplos

Respuesta: los ejemplos pueden encontrarlos en los siguientes links

2. Excelente

Respuesta: como dicen en Colombia “Con Gusto”

3. Hubiese gustado algo impreso (tarjado)

Respuesta: No damos material impreso, somos ecológicos 😉

4. “En el área de TI no me ha tocado ver información acerca de Streaming. Si bien el curso es bueno, se nota que fue planeado para diseñadores”

Respuesta: más que para diseñadores lo había pensado para programadores de ISV que quisieran hacer un portal de Videos en vivo (Live Streaming) o en demanda (On demmand streaming)

5.  “Mucho mejor este exponente, explica bien los contenidos y de forma interactiva. Felicitaciones.”

Respuesta: Cuando el tema es interesante, es fácil apasionarse con la presentación. Windows Azure, como plataforma es en mi opinión el futuro 110% para nuestros socios.

Links Relacionados

Invitación a Windows Azure Tech Series

Esta es la invitación a la presentación técnica de hoy, Manejo de multimedia optimizado en la nube con Windows Azure Media Services. En rigor voy a cubrir mas que Media Services, ya que Live Streaming es un requerimiento muy común además de On Demand Streaming.

——————————————————————————————————————————-Estimado,

Queremos invitarte a participar de Windows Azure Tech Series, diversas sesiones diseñadas para nuestra comunidad de IT Pros, donde entregaremos conocimientos en profundidad de distintos escenarios con Windows Azure, así como una oportunidad para que puedas compartir tus experiencias y conocimientos.

Fecha Hora Tema Speaker Registro

20 de Junio

18:30 a 20:30

Manejo de multimedia optimizado en   la nube con Windows Azure Media Services Juan Pablo García

Link

25 de Junio

18:30 a 20:30

Plataformas de desarrollo Open   Source en Windows Azure Hans Nemarich

Link

Para más detalles revisa el calendario aquí.

Te esperamos en las oficinas de Microsoft ubicadas en Mariano Sánchez Fontecilla 310, piso 6, Las Condes.

Parte II: Cómo usar Custom Load Balance y Affinity en Windows Azure #windowsazure

Introducción

En esta segunda parte del artículo vamos a completar el escenario propuesto anteriormente. La primera parte pueden encontrarla aquí.

El escenario consta de dos máquinas virtuales (ARR1 y ARR2) que actuarán como balanceadores de carga de 3 instancias de la aplicación Web WebAppStateFull. Los Aplication Request Routing (ARR) están expuestos a internet, es decir los clientes hacen sus llamadas HTTTP al puerto 80 del Cloud Services llamado demoarrblog, y estos redirigen las llamadas a los servidores Web que se encuentran en el Cloud Service jpggArrInterno. La gracia es que esas llamadas son a través de la red virtual VirtualNetworkArr que une los dos Cloud Services con direccionamiento privado. Esto quiere decir que los ARR llaman directamente a las direcciones privadas de los Web Servers sin necesidad que estos últimos expongan un EndPoint público, lo que tiene como segunda derivada, mayor seguridad.

0

Este escenario tiene sentido cuando las aplicaciones Web son StateFul y no tenemos opción de cambiarlas a StateLess. Como siempre, debemos notar que staless permite escalar más fácil a las aplicaciones PaaS por lo que es la primera opción al momento de diseñar una aplicación. La aplicación del ejemplo es StateFul, por lo cual cuando es instalada en una granja de servidores como en este caso, es necesario que los balanceadores tenga la característica de afinidad para que no se produzcan errores al usar la aplicación porque el usuario es enviado a otro servidor de la granja en el cual su sesión no existe.

Estas dos cosas vamos a probar en este artículo, balanceo de carga y afinidad en
Windows Azure. Es pre requisito para seguir el paso a paso haber realizado la
configuración de la primera parte del artículo, la cual se encuentra aquí.

Primer paso: crear Proyecto Web staful

Utilizando Visual Studio, creamos un proyecto ASP.NET 4.5 vacio como se muestra en la siguiente pantalla. Esta será nuestra aplicación de Web StateFul la cual llamaremos WebAppStateFul.

1

A este proyecto Web vacío le agregamos una página llamada default.aspx, en la cual agregamos los controlesque aparecen a continuación.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="WebAppStateFul._default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        Nombre Servidor:
        <asp:Label ID="lbNombreServer" runat="server"></asp:Label>
        <br />
        ¿Es una nueva sessión?
        <asp:Label ID="lbNuevaSession" runat="server" Text="Label"></asp:Label>
        <br />
        LLave de sessión:
        <asp:Label ID="lbSessionLLave" runat="server"></asp:Label>
        <br />
        Contador de request por sessión:
        <asp:Label ID="lbNRequest" runat="server"></asp:Label>
    
        <br />
        <br />
        <strong>Lista de Variables de Session</strong><br />
        <asp:GridView ID="gvListaGalletas" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None" Width="681px">
            <AlternatingRowStyle BackColor="White" />
            <EditRowStyle BackColor="#2461BF" />
            <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
            <RowStyle BackColor="#EFF3FB" />
            <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
            <SortedAscendingCellStyle BackColor="#F5F7FB" />
            <SortedAscendingHeaderStyle BackColor="#6D95E1" />
            <SortedDescendingCellStyle BackColor="#E9EBEF" />
            <SortedDescendingHeaderStyle BackColor="#4870BE" />
        </asp:GridView>
    
        <br />
        <strong>Lista de cookies</strong><br />
        <asp:GridView ID="gvListaCookies" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None">
            <AlternatingRowStyle BackColor="White" />
            <EditRowStyle BackColor="#7C6F57" />
            <FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
            <HeaderStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
            <PagerStyle BackColor="#666666" ForeColor="White" HorizontalAlign="Center" />
            <RowStyle BackColor="#E3EAEB" />
            <SelectedRowStyle BackColor="#C5BBAF" Font-Bold="True" ForeColor="#333333" />
            <SortedAscendingCellStyle BackColor="#F8FAFA" />
            <SortedAscendingHeaderStyle BackColor="#246B61" />
            <SortedDescendingCellStyle BackColor="#D4DFE1" />
            <SortedDescendingHeaderStyle BackColor="#15524A" />
        </asp:GridView>
        <br />
        <strong>HTTP Header</strong><br />
        <asp:GridView ID="gvHttpHeader" runat="server" BackColor="#CCCCCC" BorderColor="#999999" BorderStyle="Solid" BorderWidth="3px" CellPadding="4" CellSpacing="2" ForeColor="Black">
            <FooterStyle BackColor="#CCCCCC" />
            <HeaderStyle BackColor="Black" Font-Bold="True" ForeColor="White" />
            <PagerStyle BackColor="#CCCCCC" ForeColor="Black" HorizontalAlign="Left" />
            <RowStyle BackColor="White" />
            <SelectedRowStyle BackColor="#000099" Font-Bold="True" ForeColor="White" />
            <SortedAscendingCellStyle BackColor="#F1F1F1" />
            <SortedAscendingHeaderStyle BackColor="#808080" />
            <SortedDescendingCellStyle BackColor="#CAC9C9" />
            <SortedDescendingHeaderStyle BackColor="#383838" />
        </asp:GridView>
    
    </div>
    </form>
</body>
</html>

Luego agregamos el código C# que tiene la lógica de la aplicación.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;

namespace WebAppStateFul
{
    public partial class _default : System.Web.UI.Page
    {
        

        protected void Page_Load(object sender, EventArgs e)
        {
            lbNombreServer.Text = System.Environment.MachineName;
            if (Session["llave"] == null)
            {
                //Nueva session
                lbNuevaSession.Text = "Si";
                Session["llave"]= string.Format("{0}_{1}_{2}", System.Environment.MachineName, DateTime.Now.ToShortTimeString(), Request.Browser.Browser.ToString());
                Session["nRequest"] = 0;
            }
            else 
            {
                lbNuevaSession.Text = "NO";
                
                Session["nRequest"] = (int)Session["nRequest"] + 1;
            }
            lbSessionLLave.Text = (string)Session["llave"];
            lbNRequest.Text = ((int)Session["nRequest"]).ToString();
            
            ArrayList listaVarSession = new ArrayList();
            for (int i = 0; i < Session.Count; i++)
            {
                listaVarSession.Add(Session[i]);
            }
            gvListaGalletas.DataSource = listaVarSession;
            gvListaGalletas.DataBind();

            //gvListaCookies
            ArrayList colCookies = new ArrayList();
            for (int i = 0; i < Request.Cookies.Count; i++)
            {
                colCookies.Add(Request.Cookies[i]);
            }
            gvListaCookies.DataSource = colCookies;
            gvListaCookies.DataBind();
            //http header
            ArrayList httpLista = new ArrayList();
            for (int i = 0; i < Request.Headers.Count; i++)
            {
                httpLista.Add(Request.Headers.GetKey(i) +"="+ Request.Headers[i]);
            }
            gvHttpHeader.DataSource = httpLista;
            gvHttpHeader.DataBind();
        }
    }
}

Esta aplicación captura el nombre físico de la instancia de la aplicación Web donde se está ejecutando el requerimiento dentro de la Server Farm. Lugo, si es el primer llamado de ese cliente a ese servidor crear una variable de sesión llamada llave para identificar si el servidor reconoce o no al cliente. Por último, en otra variable de sesión lleva la cuenta de los requerimientos que cada cliente lleva en ese servidor. Esto es una aplicación StateFul porque si el cliente es enviado a otro servidor se pierde la cuenta.

La siguiente imagen muestra lo que la página produce después de cargarla un par de veces.

1y1

Segundo paso: Proyecto Cloud

Ya tenemos una aplicación Web lista, la que usaremos como ejemplo nuestro Web Site Stateful. Ahora, para poder publicar la aplicación en Azure. Para esto, tenemos que agregar un nuevo proyecto del tipo Cloud vacío, como se muestra en el siguiente diálogo.

3

Para incluir el proyecto Web existente a la solución Cloud, debemos agregar un Web Role de una solución existente como se muestra a continuación.

4

En este punto ya tenemos un proyecto Cloud y podemos probarlo utilizando el emulador local. Para esto, configuramos el proyecto CloudServiceWeb como Set As Startup Prjoject y luego utilizando F5 ejecutamos la aplicación.

Podemos ver en Windows Azure Compute Emulator que la aplicación se ejecuta en una instancia y en el Browser los datos del servidor donde se ejecuta y variables de sesión.

5

Para el escenario que vamos a montar en Azure, vamos a utilizar 3 instancias, lo que nos va a ayudar  a ver claramente cómo el servicio ARR realiza el balanceo de Carga. Para configura la cantidad de instancias, vamos a la configuración del rol y cambiamos la cantidad de instancias de 1 a 3.

6

El Segundo cambio que debemos hacer es configurar el EndPoint externo en el puerto 80, así podrán los clientes acceder al servicio una vez publicado en la Nube.

6y1

La ultima configuración que hacemos es la red virtual (virtualNetwordArr) y sub red (servidoresWe) donde las instancias de servicio Web se van a desplegar. Esto se configura manualmente en el archivo XML ServiceConfiguration.Cloud.cscfg

<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="cloudServiceWeb" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="3" osVersion="*" schemaVersion="2013-03.2.0">
  <Role name="WebAppStateFul">
    <Instances count="3" />
    <ConfigurationSettings>
      <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
    </ConfigurationSettings>
  </Role>
  <NetworkConfiguration>
    <VirtualNetworkSite name="virtualNetwordArr" />
    <AddressAssignments>
      <InstanceAddress roleName="WebAppStateFul">
        <Subnets>
          <Subnet name="servidoresWe" />
        </Subnets>
      </InstanceAddress>
    </AddressAssignments>
  </NetworkConfiguration>
</ServiceConfiguration>

Por último, podemos hacer el despliegue en la nube siguiendo el asistente de publicación del proyecto Cloud.

7

Una vez terminado el despliegue de la solución podemos revisar en el portal de administración de Azure los recursos que la red virtual virtualnetwordarr tiene desplegados. En la lista de recursos vemos las 3 instancias de nuestra aplicación junto con la máquina virtual que tiene el servicio de ARR.

8

Tercer paso: Pruebas del proyecto Cloud

Para probar el servicio, utilizamos un par de navegadores diferentes y vamos a la url http://demoarrblog.cloudapp.net/ del Cloud Service donde hicimos el deploy de la aplicación Web. Como configuramos un EndPoint externo en el puerto 80, accedemos directamente como muestra la siguiente imagen. Podemos ver que cada cliente es enviado a diferentes instancias de nuestra aplicación. Este balanceo es el que hace Windows Azure de manera automática, del cual no tenemos control por ahora.

9

Cuarto paso: Configuración ARR

Una vez probada la aplicación Web y entendido el comportamiento del balanceador de carga por defecto, vamos a configurar el servicio Aplication Request Routing ARR en la máquina virtual para tomar control de la forma como balanceamos la carga de usuarios y la afinidad de los mismos con la primera instancia con la que se conectaron. El escenario se muestra en la siguiente figura.

La idea es que el cliente llama al servicio a la URL del  Cloud Service del ARR en la URL http://demoarrblog.cloudapp.net/ y ahí el ARR toma control del requerimiento y lo redirige hacia una de las instancias del servicio Web.

9y1

Las instancias del servicio web WebAppStateFul sólo tienen que recibir requerimientos desde el servicio de ARR por lo cual no es necesario que exponga un EndPoint público. El ARR llamará directamente al servicio utilizando el direccionamiento privado 10.0.0.x de la sub red servidoreswe En este caso, vamos a publicar un EndPoint interno porque los clientes finales no van a acceder directamente a este servicio sino que lo harán a través de los servidores ARR. Para que sea más claro, vamos a utilizar el puerto 90 y no el 80 para publicar el servicio.

Volvemos a hacer deploy del servicio con la nueva configuración.

10

Una vez actualizada la configuración del Cloud Servicies, tenemos que configurar el ARR para que diriga los requerimientos que recibe hace los servicios Web. Nos conectamos a la maquina vitual utilizando RDP y podemos comprobar que tenemos conectividad con las instancias de la aplicación web utilizando direccionamiento privado. Para validar podemos hacer ping al 10.0.0.12 y usando el navegador podemos cargar http://10.0.0.12:90

11

La configuración del servicio ARR se hace en Internet information Server Manager. Al igual como lo hicimos en la primera parte del artículo, vamos a configurar una granja de servidores. En la misma granja antes creada, borramos los servidores que contiene y agregamos las tres instancias de la aplicación Web:

  • 10.0.0.12 puerto 90
  • 10.0.0.13 puerto 90
  • 10.0.0.14 puerto 90

12

Para la primera prueba no utilizaremos Server Affinity para así observar cómo funciona al balanceador. Para esto, desmarcamos la opción Client Affinity de la granja de servidores. Esto significa que vamos dejar que los clientes fluyan entre todos los servidores de la granja.

13

ARR permite diferentes criterios de balanceo, nosotros utilizaremos Weighted Round Robin con una distribución de carga custom, que dejaremos en 33.33% para que todos los servidores reciban la misma cantidad de requerimientos de clientes.

14

Quinto paso: Pruebas de balanceo sin afinidad

Una vez realizada la configuración del ARR podemos probar utilizando un solo cliente. Utilizando el browser cargarnos la URL del Cloud Services de la máquina virtual con ARR y obtenemos el siguiente resultado en la primera llamada. Nos responde el servidor RD00155D53D6C8 y reconoce que la sesi[on es nueva, es decir es el primer llamado.

15

Ahora, realizamos llamados sucesivos y obtenemos las respuestas que se muestran en la siguiente tabla. El comportamiento es exactamente el esperado, el cliente es dirigido a cada uno de los 3 servidores que forman la Web Farm de manera secuencial lo que crea 3 sesiones diferentes para el cliente, una en cada instancia de la aplicación. Esto es el problema para las aplicaciones StateFul ya que el cliente en rigor es solo uno por lo que debería tener solo una sesión independiente de la cantidad de instancias de la granja.

# Request Nombre Servidor ¿Es una nueva sesión? Llave de sesión Contador de request por sesión

1

RD00155D53D6C8

RD00155D53D6C8_9:02 PM_Firefox

0

2

RD00155D53D115

RD00155D53D115_9:03 PM_Firefox

0

3

RD00155D53C1CB

RD00155D53C1CB_9:03 PM_Firefox

0

4

RD00155D53D6C8

No

RD00155D53D6C8_9:02 PM_Firefox

1

5

RD00155D53D115

No

RD00155D53D115_9:03 PM_Firefox

1

6

RD00155D53C1CB

No

RD00155D53C1CB_9:03 PM_Firefox

1

7

RD00155D53D6C8

No

RD00155D53D6C8_9:02 PM_Firefox

2

Para solucionar el problema de las múltiples sesiones debido a múltiples instancias en una granja de servidores tenemos dos opciones. Primero, y la más recomendada,  modificar la aplicación para que sea StateLess. Si esto no se puede hacer, tenemos la segunda opción que es crear afinidad entre el cliente y la instancia del servidor que lo atiende primero.

ARR nos permite crear afinidad de una manera muy simple. Configuramos en Server Affinitty la opción de Client Affinity y con esto ARR agrega una cookie en el cliente que mamamos en este caso  ARRAffinity. Esta cookie almacena la instancia que ese cliente está utilizando, lo que le permite al ARR desde el segundo Request en adelante seguir retueando al cliente con la primera instancia que sirvió a ese cliente. De esa forma la sesión del cliente se mantiene con ese servidor y no tenemos problema con la aplicación StateFul.

La configuración la realizamos a nivel de Server Farm, en la opción de Server Afinnity como muestra la siguiente figura.

16

Sexto paso: Pruebas de balanceo con afinidad

Una vez configurado ARR con afinidad podemos probar el comportamiento de la aplicación. Para esto abrimos dos nuevas instancias del navegador y hacemos el primer request. Luego comenzamos a recargar la aplicación y las respuestas se muestran en las siguientes capturas de pantalla.

Primer request de ambos navegadores.17

Segundo request de ambos navegadores.18

Tercer request de ambos navegadores.

19

Las respuestas que obsérvanos nos muestran que el primer cliente (Internet Explorer) fue ruteado por el ARR la instancia RD00155D53D6C8 en el primer llamado. El segundo cliente (FireFox) a su vez fue enviado a la instancia RD00155D53D6C8. Todas las siguientes peticiones de cada cliente, se mantienen en la misma instancia! Esto es afinidad funcionando.

Pueden ver también que la tabla donde aparecen las cookies, aparece la cookie llamada ARRAfinnity, llave con al cual ARR logra la afinidad con el servidor.

Séptimo paso: Agregar Segundo ARR

Todo sistema que busca tener alta disponibilidad requiere como base no tener puntos únicos de falla, en el ejemplo hasta ahora desarrollado la aplicación Web tiene 3 instancias por lo cual no debemos preocuparnos por la falla en una de ellas. Si hay una falla en una instancia, los clientes que tienen afinidad establecida con esa instancia van a experimentar un error de conexión (la instancia esta caída) y el ARR los enviará a conectarse a otra instancia donde crearan una nueva sesión.

El punto único de falla, hasta ahora, en el ejemplo es el ARR ya que sólo tenemos una instancia. Queremos llegar a la siguiente configuración.0

Para completar este escenario, debemos crear un segundo Windows Server 2012 y configurar el servicio de ARR en esa nueva máquina virtual. Para hacer esto, seguimos los mismos pasos explicados en detalle en la primera parte del artículo, específicamente en los pasos Crear un servidor Windows Server 2012 , Configuración de IIS en Windows Server e Instalación de Instalación de Aplication Request Routing (ARR). Esto se encuentra en este link.

Las consideraciones que debemos tener para crear esta segunda máquina virtual son el nombre (ARR2) y ubicarla en el mismo Cloud Service que la primera, como se muestra en la siguiente captura de pantalla.

20

Una vez Instalado ARR, se configura la granja de servidores con las 3 instancias de la aplicación Web de la misma manera como se hizo con el primer ARR. Esto incluye configurar Server Affinity además de los 3 servidores de la granja y el criterio de balanceo de carga.

22

Por último, debemos configurar el Endpoint público de la máquina virtual en el
puerto 80. Como en el Cloud Service el servicio Web se va a balancear entre las
dos máquinas virtuales, se crea un EndPoint del tipo Load-Balance como se
muestra a continuación.

23

El puerto a balancear es el 80 (externo) y el puerto de la máquina virtual (interno) también es el 80.

24

Una vez creado el EndPoint podemos ver en la configuración de la máquina virtual que el puerto ha quedado configurado y balanceado. Con esto eliminamos el punto único de falla de la arquitectura de ejemplo.

25

Octavo paso: Probar la configuración

Nuevamente utilizamos 3 clientes para realizar las pruebas. Los 3 clientes se conectan a dos servidores, lo cual podría pensarse que es un error pero no lo es ya que cada ARR tiene su propio registro de balanceo, por lo cual, ARR1 puede haber enviado el primer request que recibió a RD00155D53C1D5 y ARR2 al recibir su primer request puede hace lo mismo. Por eso ese servidor aparece dos veces. Ahora, si se fijan el tercer cliente va a otro servidor. Si recargamos las páginas de los 3 clientes observamos que mantienen afinidad con el servidor que los atendió primero, por lo que hemos comprobado que tenemos listo la configuración de nuestro ejemplo.

28

Conclusiones

En estos dos artículos hemos desarrollado un escenario donde podemos tomar control del método con que se balancea la carga entre las múltiples instancias de una aplicación Web.

Además, para las aplicaciones StateFul que no podemos modificar, aprendimos a configurar la característica de Server Afinnity de ARR que permite asegurar que el cliente se mantendrá conectado a la instancia de la aplicación que lo atendió en el primer llamado que es en la cual creo su sesión.

Como corolario al ejercicio, tuvimos la necesidad de conectar un Cloud Service IaaS, donde están contenidas las máquinas virtuales de ARR, con un Cloud Services de PaaS. En este último se desplegaron las instancias de la aplicación Web. Esto lo logramos utilizando redes virtuales, que son la vía de comunicación interna/ directa entre  Cloud Services independiente si son PaaS o IaaS. Esto es una de las grandes ventajas de la plataforma Azure que permite construir sistemas hibridos combinando la potencia de PaaS con la flexibilidad de IaaS en nuestros sistemas.

Links relacionados