Universidad Politécnica de Madrid Escuela Técnica Superior de Ingenieros de Telecomunicación DESARROLLO DE ESCENARIOS VIRTUALES PARA PRÁCTICAS DE LABORATORIO SOBRE ARQUITECTURAS DE SERVICIOS EN LA NUBE Autor: Raúl Álvarez Pinilla Tutor: David Fernández Cambronero Miembros del tribunal Presidente: Alejandro Alonso Muñoz Vocal: David Fernández Cambronero Secretario: Joaquín Salvachúa Rodríguez Suplente: Francisco Javier Ruiz Piñar Fecha de lectura y defensa: Calificación: Universidad Politécnica de Madrid Escuela Técnica Superior de Ingenieros de Telecomunicación Grado en Ingeniería de Tecnologías y Servicios de Telecomunicación TRABAJO FIN DE GRADO DESARROLLO DE ESCENARIOS VIRTUALES PARA PRÁCTICAS DE LABORATORIO SOBRE ARQUITECTURAS DE SERVICIOS EN LA NUBE Autor: Raúl Álvarez Pinilla Tutor: David Fernández Cambronero Miembros del tribunal Presidente: Alejandro Alonso Muñoz Vocal: David Fernández Cambronero Secretario: Joaquín Salvachúa Rodríguez Suplente: Francisco Javier Ruiz Piñar Fecha de lectura y defensa: Calificación: Resumen El trabajo consiste en el diseño, desarrollo y prueba de escenarios basados en máquinas virtuales que implementan servicios en la nube, haciendo énfasis en las soluciones actuales para dotar de fiabilidad y escalabilidad a dichos servicios. El escenario virtual en el que se fundamenta el trabajo está compuesto por servidores web, servidores de disco y un cortafuegos, y mediante él se comprobarán diferentes configuraciones a implantar. Se centrará principalmente en la creación de un sistema de ficheros distribuido y en el estudio de las nuevas arquitecturas de red basadas en software para dotar la funcionalidad de balanceo de carga en el escenario proporcionando alta disponibilidad y tolerancia a posibles fallos. Con todo ello se pretende combinar los componentes de una arquitectura de servicios en la nube y profundizar en el funcionamiento de ella, acercando la visión de un centro de datos mediante la virtualización de un escenario. Palabras clave: Computación en la nube, Centro de datos, Virtualización, Sistema de ficheros _distribuido, Balanceador de carga, Redes definidas por software Abstract The project consist of the design, development and testing of scenarios based on virtual machines which implement cloud services, emphasizing current solutions to provide reliability and scalability to such services. The virtual scenario of this project is composed of web servers, disk servers and a firewall, and through him, different configurations will be checked to introduce. It will focus mainly on the creation of a distributed file system and the study of new network architectures based on software to supply the functionality of load balancing providing high availability and fault tolerance. All of this is intended to combine the components of a cloud service architecture and go into detail about its functioning, bringing closer the vision of a data center by virtual network scenarios. Key words: Cloud computing, Data center, Virtualization, Distributed file system, _Load balancer, Software Defined Networking (SDN) INDICE DE CONTENIDOS . 1. INTRODUCCIÓN ....................................................................................................................... 1 1.1. Motivación ................................................................................................................................. 1 1.2. Objetivos .................................................................................................................................... 1 1.3. Estructura de la memoria ........................................................................................................... 2 2. DESARROLLO............................................................................................................................ 3 2.1. Preparación del escenario .......................................................................................................... 4 2.1.1. Instalación de VNX ................................................................................................................ 4 2.1.2. Configuración del escenario .................................................................................................. 5 2.1.2.A. Modificación del sistema de ficheros ............................................................................ 7 2.1.2.B. Conexión del escenario con redes externas ................................................................... 8 2.2. Arranque del escenario............................................................................................................. 13 2.3. Sistema de ficheros .................................................................................................................. 15 2.3.1.Configuración de los servidores de disco ............................................................................. 15 2.3.1.A. Volumen distribuido .................................................................................................... 17 2.3.1.B. Volumen en réplica ...................................................................................................... 17 2.3.1.C. Volumen seccionado .................................................................................................... 18 2.3.2. Montaje desde los servidores web ..................................................................................... 19 2.3.2.A. Montaje mediante el comando mount ........................................................................ 19 2.3.2.B. Montaje mediante el fichero fstab .............................................................................. 20 2.3.2.C. Montaje creando un archivo de configuración del volumen ....................................... 21 2.4. Aplicación web ......................................................................................................................... 22 2.5. Balanceador de carga ............................................................................................................... 24 2.5.A. Controlador Floodlight ........................................................................................................ 25 2.5.B. Controlador POX ................................................................................................................. 27 2.6. Firewall ..................................................................................................................................... 30 2.7. Clientes..................................................................................................................................... 35 3. PRUEBAS Y RESULTADOS ................................................................................................. 37 3.1. Análisis de GlusterFS ................................................................................................................ 37 3.2. Recuperación de un Servidor de Disco ...................................................................................... 39 3.3. Análisis del balanceador de carga ............................................................................................. 41 3.4. Comprobación de las políticas de seguridad ............................................................................. 46 4. CONCLUSIONES ..................................................................................................................... 47 BIBLIOGRAFÍA ...................................................................................................................... 49 INDICE DE FIGURAS DESARROLLO Figura 2-1: Diagrama lógico del escenario de Centro de Datos y Provisión de Servicios ...................................... 3 Figura 2-2: Diagrama lógico del escenario del trabajo ......................................................................................... 3 Figura 2.1-1 - Sistema COW en un servidor web ................................................................................................... 5 Figura 2.1-2 - Switch de red virtual de libvirt ........................................................................................................ 8 Figura 2.1-3 - Servidor DNS y DHCP de libvirt ....................................................................................................... 8 Figura 2.2-1 - Diagrama de estados de las máquinas virtuales en VNX .............................................................. 13 Figura 2.3-1: Volumen distribuido 10.................................................................................................................... 17 Figura 2.3-2: Volumen en réplica 10 ..................................................................................................................... 17 Figura 2.3-3: Volumen seccionado 10 ................................................................................................................... 18 Figura 2.3-4 - Modelo maestro-esclavo en GlusterFS 11 ...................................................................................... 19 Figura 2.4-1: Página de incio de la Aplicación web ............................................................................................. 22 Figura 2.4-2: Función de Subida de ficheros ........................................................................................................ 23 Figura 2.4-3: Función de Descarga de ficheros .................................................................................................... 23 Figura 2.4-4: Función de Borrado de ficheros ...................................................................................................... 23 Figura 2.5-1: Arquitectura SDN ........................................................................................................................... 24 Figura 2.5-2: Petición de servicio desde FW para comprobar balanceador de carga mediante Floodlight ........ 26 Figura 2.5-3: Arranque del Controlador POX ....................................................................................................... 27 Figura 2.5-4: Arranque del Controlador POX en modo DEBUG ........................................................................... 28 Figura 2.5-5: ARPing hacia los servidores web .................................................................................................... 28 Figura 2.5-6: Envío de una petición de servicio desde un cliente......................................................................... 29 Figura 2.5-7: Envío de una respuesta de servicio desde un servidor web ............................................................ 29 Figura 2.6-1: Pantalla de bienvenida de Firewall Builder .................................................................................... 30 Figura 2.6-2: Creación de un firewall (paso 1) ..................................................................................................... 31 Figura 2.6-3 Creación de un firewall (paso 2) ...................................................................................................... 31 Figura 2.6-4: Configuración de la interfaz eth1 del firewall ................................................................................ 32 Figura 2.6-5: Configuración de la interfaz eth2 del firewall ................................................................................ 32 Figura 2.6-6: Configuración de la interfaz de loopback del firewall .................................................................... 32 Figura 2.6-7: Política de reglas aplicadas en el firewall ...................................................................................... 33 Figura 2.6-8: Instalación de políticas de seguridad en el firewall ........................................................................ 34 Figura 2.7-1: Navegador Firefox desde un cliente a través de un túnel ssh ........................................................ 35 Figura 2.7-2: Código fuente desde Firefox de la Aplicación web ......................................................................... 36 PRUEBAS Y RESULTADOS Figura 3.1-1 - Captura del envío de la información del volumen ......................................................................... 37 Figura 3.1-2 - Captura de llamada LOOKUP en GlusterFS ................................................................................... 38 Figura 3.1-3: Captura de la llamada WRITE en GlusterFS ................................................................................... 38 Figura 3.2-1 - Uso del comando ifconfig down .................................................................................................... 39 Figura 3.2-2 - Contenido de los servidores de disco ............................................................................................. 39 Figura 3.2-3 - Uso del comando ifconfig up ......................................................................................................... 40 Figura 3.2-4 - Captura de la recuperación de la información en un servidor de disco caído ............................... 40 Figura 3.3-1: Balanceo mediante iperf desde un cliente ..................................................................................... 42 Figura 3.3-2: Balanceo mediante iperf desde varios clientes .............................................................................. 42 Figura 3.3-3: Uso de curl para comprobar balanceo de carga ............................................................................ 43 Figura 3.3-4: Trazas del controlador que verifican el balanceo de carga ............................................................ 43 Figura 3.3-5: Captura de tráfico de paquetes OpenFlow ..................................................................................... 43 Figura 3.3-6: Tabla de flujos del switch virtual en LAN2 ...................................................................................... 44 Figura 3.3-7: Diagrama físico de LAN2 ................................................................................................................ 45 Figura 3.3-8: Trazas del controlador al realizar una petición de servicio desde un navegador ........................... 45 Figura 3.4-1: Ping desde C1 hacia FW ................................................................................................................. 46 Figura 3.4-2: Captura de tráfico para comprobar la regla 4 del firewall ............................................................. 46 1. Introducción En el día de hoy la computación en la nube sigue en continuo crecimiento y progresivamente ofrece a los usuarios más tipos de servicios. Las aplicaciones telemáticas son de gran complejidad y cada vez demandan mayor cantidad de recursos de computación, red y almacenamiento. Asimismo, los usuarios exigen a los servicios un comportamiento eficiente, fiable y seguro. Por ello surge la necesidad de grandes infraestructuras de redes de comunicaciones y de centros de datos. Otra de las razones de la necesidad de disponer de grandes centros de datos es la creciente tendencia que existe de mover aplicaciones e infraestructuras desde centros de datos corporativos de un tamaño pequeño a otros de mayor tamaño, que son mantenidos por grandes proveedores. Esto permite a pequeños negocios ahorrar elevados costes en inversión económica y pagar únicamente por el consumo efectuado, teniendo un servicio de forma flexible y adaptativa. A parte de las características mencionadas, los centros de datos proporcionan muchas más, como pueden ser, gran escalabilidad, mayor fiabilidad, mejor conectividad con proveedores y facilidad en la gestión. 1.1. Motivación Con el objeto de conocer las tecnologías usadas para proporcionar servicios en la nube en los centros de datos de hoy en día es necesario disponer de escenarios didácticos que permitan entender y practicar dichas tecnologías. A través de la virtualización de un escenario que recrea un centro de datos, se proporcionará a los equipos clientes un servicio de compartición de ficheros escalable que cumplirá los requisitos de un servicio alojado en la nube. 1.2. Objetivos Se partirá de un escenario proporcionado en la práctica final de Centro de Datos y Provisión de Servicios con el propósito de su perfeccionamiento, y así dotarlo de nuevas funcionalidades usadas actualmente en los grandes centros de datos del mundo. Con ello se profundizará en el conocimiento de las tecnologías usadas y se propondrán nuevas funcionalidades. Los puntos en los que se centrará principalmente el trabajo serán el análisis de un sistema de ficheros distribuido para el servicio a través de GlusterFS y el estudio e incorporación de un balanceador de carga utilizando la tecnología SDN (Software Defined Networking). Además, será necesario centrarse en otros aspectos durante el transcurso del trabajo como la virtualización a través de la herramienta VNX, la implementación de una aplicación web, y la creación y configuración de un firewall. 1 Introduccion 1.3. Estructura de la memoria Se ha seguido el siguiente esquema a lo largo de la memoria: En el Capítulo 2: Desarrollo se presentan las diferentes etapas que se han seguido desde la preparación del escenario hasta que un cliente puede acceder al servicio, pasando por los diferentes elementos que son necesarios configurar para cumplir con los requisitos de un servicio en la nube. En el Capítulo 3: Pruebas y resultados se han analizado diferentes puntos del escenario para comprobar el correcto funcionamiento de sus elementos. Las pruebas se han centrado fundamentalmente en el sistema de ficheros y en el balanceador de carga. En el Capítulo 4: Conclusiones se ofrece una visión final sobre el trabajo realizado y posibles líneas de trabajo futuro que se podrían seguir. Se ha utilizado un código de colores en los diferentes cuadros que aparecerán a lo largo de la memoria. Un relleno anaranjado mostrará el contenido total o parcial de un fichero específico, como puede ser un script, y un relleno de color gris claro indicará comandos ejecutados en un terminal. CONTENIDO DE FICHEROS COMANDOS EN UN TERMINAL Todos los comandos que se muestran a lo largo del trabajo se encuentran con privilegios de root, por lo tanto el lector puede anteponer sudo a todos ellos o bien pasar a ser root con el comando sudo su. 2 2. Desarrollo A lo largo de este capítulo se describirán los diferentes pasos que se han seguido para modificar y mejorar el escenario virtual que emula el funcionamiento de un servicio de compartición de ficheros escalable implementado sobre un centro de datos. El escenario de partida del trabajo es el propuesto en la práctica final de la Centro de Datos y Provisión de Servicios, que se encuentra compuesto por tres equipos clientes, tres servidores web, tres servidores de disco y un router que realiza balanceo de carga entre los diferentes servidores web. Su diagrama lógico es el que se muestra a continuación: Figura 2-1: Diagrama lógico del escenario de Centro de Datos y Provisión de Servicios 1 Sobre el anterior escenario se ha decidido realizar los siguientes cambios: La función de balanceador de carga recaerá sobre un controlador SDN que se conectará a un switch de la subred LAN2 de tipo Open vSwitch 2. Se escogerá este tipo de switch virtual ya que es compatible con el controlador SDN. El router LB de acceso al servicio se cambiará por un firewall al que se le aplicarán unas políticas de seguridad. De esta forma, el escenario propuesto en el que se basará este trabajo es el siguiente: Figura 2-2: Diagrama lógico del escenario del trabajo 3 Desarrollo 2.1. Preparación del escenario Se utilizará la herramienta de virtualización VNX (Virtual Networks over linuX) 3, que se encargará de la creación del escenario propuesto sobre el ordenador, incluyendo redes virtuales creadas por switches virtualizados. Para ello será necesario, tras el diseño del escenario, la especificación de un fichero .xml que tendrá el siguiente formato: <?xml version="1.0" <vnx> (definiciones (definiciones (definiciones (definiciones </vnx> encoding="UTF-8"?> globales: <global>) de redes virtuales: <net>) de máquinas virtuales: <vm>) del equipo host: <host>) De esta forma se proporcionará a la herramienta VNX la configuración de cada uno de los elementos que componen el escenario y la interconexión entre ellos. 2.1.1. Instalación de VNX La instalación se encuentra descrita paso a paso en el portal de la herramienta, y tras ella será necesario descargar alguno de los sistemas de ficheros preconfigurados que facilita la herramienta desde su repositorio. En nuestro caso, se utilizará el sistema de ficheros proporcionado por LXC (Linux Containers) 4, que es una tecnología de contenedores que permite crear sistemas Linux contenidos dentro de otro aplicándole algunos límites de CPU, memoria o incluso asignarle interfaces de red, tratándolo como si fuera un equipo independiente. La ventaja de LXC respecto a otras tecnologías de virtualización es su ligereza, ya que utiliza recursos mínimos dando así respuestas mucho más rápidas. Como inconveniente cabe mencionar que no hay interfaz gráfica (GUI) para configuración, por lo que todo se realizará a través del terminal de cada máquina virtual. Se puede descargar el sistema de ficheros directamente desde el repositorio o desde la herramienta vnx_download_rootfs que proporciona VNX. El archivo comprimido necesario a descargar para nuestro escenario se llama “vnx_rootfs_lxc_ubuntu-XX.XXvXXX.tgz”. Si el sistema operativo lo permite también se encuentra disponible una versión de 64 bits. Es importante recordar a lo largo de la práctica que el sistema de ficheros descargado dispone de los usuarios “root” y “vnx”, con contraseña “xxxx” en ambos. 4 Desarrollo 2.1.2. Configuración del escenario Las máquinas virtuales pueden utilizar el sistema de ficheros que se ha descargado de dos formas posibles, en modo directo o en modo cow (copy on write) 5. Cuando una máquina virtual utiliza el sistema de ficheros en modo directo solo podrá ser usado un sistema de ficheros por máquina virtual, por lo que para nuestro escenario sería necesario disponer de numerosas copias de sistemas de ficheros. La opción de copy on write será la que se utilice ya que permite que varias máquinas virtuales puedan utilizar el mismo sistema de ficheros. En el escenario propuesto será útil porque los tres servidores web podrán utilizar un mismo sistema de ficheros, e igual sucede con los servidores de disco y los clientes. El sistema copy on write devuelve punteros a un mismo sistema de ficheros, y en el momento en que un proceso intenta modificar algún fichero del sistema, se crea una copia para prevenir que los cambios producidos por dicho proceso sean visibles por todos los demás. Todo ocurre de forma transparente para los procesos, y de esta forma no se crea ninguna copia adicional del recurso si ningún proceso llega a realizar modificaciones. De esta forma, se dispondrá del sistema de ficheros de sólo lectura que se encontrará disponible el directorio filesystems de VNX (/usr/share/vnx/filesystems), y del directorio (read and write) donde se encontrarán las modificaciones del sistema de ficheros. Además se dispondrá de un directorio en el cual se encuentran punteros del sistema de ficheros completo de la máquina virtual. En el siguiente diagrama se muestra un ejemplo de lo comentado en la máquina virtual WWW1: Figura 2.1-1 - Sistema COW en un servidor web En este punto se puede plantear la práctica de diferentes formas dependiendo que opción se utilice respecto a los sistemas de ficheros: Crear un único sistema de ficheros que compartirán todas las máquinas virtuales reduciendo el espacio utilizado en disco. Crear varios sistemas de ficheros para aislar el software de los diferentes grupos de máquinas virtuales. 5 Desarrollo Si se escoge la opción de tener varios sistemas de ficheros, se tendrá que realizar la copia del sistema de ficheros descargado y modificar dos líneas del fichero config de cada uno de los sistemas de ficheros copiados. En las líneas a modificar se deberá indicar la ruta del directorio rootfs y del fichero fstab del sistema de ficheros correspondiente. El siguiente ejemplo corresponde al sistema de ficheros que se utilizará en los servidores web: lxc.rootfs = /usr/share/vnx/filesystems/vnx_rootfs_lxc_ubuntu-13.10v025-WWW/rootfs lxc.mount = /usr/share/vnx/filesystems/vnx_rootfs_lxc_ubuntu-13.10v025-WWW/fstab Además, en la plantilla .xml del escenario se indicará en cada máquina virtual su correspondiente sistema de ficheros: <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-WWW </filesystem> Para la instalación de los diferentes paquetes necesarios en las máquinas virtuales se puede: a) Modificar directamente el sistema de ficheros descargado cuando el escenario no se encuentre arrancado. En este caso se está modificando el sistema de ficheros de sólo lectura que compartirán las máquinas virtuales. b) Configurar en las máquinas virtuales del escenario una interfaz con conexión a Internet e instalar en cada máquina los paquetes necesarios. Mediante esta opción se crearán copias de los archivos modificados del sistema de ficheros en cada máquina virtual de forma individualizada. Para el desarrollo del trabajo se instalarán los siguientes paquetes: Máquina virtual Identificador Controlador SDN CONTROLLER Servidores de disco NAS Servidores web WWW Firewall FW Clientes C Paquetes Git GlusterFS Apache2 , PHP5 , GlusterFS , Iperf Firewall Builder , Xauth Firefox , Iperf , Curl , Xauth 6 Desarrollo Para la instalación de los paquetes mencionados se ejecutarán las siguientes órdenes en las correspondientes máquinas virtuales: Paquete Comando de instalación Git # apt-get install git GlusterFS # apt-get install glusterfs-server Apache2 # apt-get install apache2 PHP5 # apt-get install php5 Firewall Builder # apt-get install fwbuilder Iperf # apt-get install iperf Curl # apt-get install curl Xauth # apt-get install xauth En los siguientes subapartados se describirán los dos procedimientos comentados para la instalación de los paquetes necesarios en las máquinas virtuales. 2.1.2.A. Modificación del sistema de ficheros Dado un cierto sistema de ficheros rootfs_lxc_ubuntu, que se encuentra en el directorio /usr/share/vnx/filesystems, se explicará cómo modificarlo para añadir los paquetes que se consideren oportunos. De esta forma, al arrancar el escenario las máquinas virtuales que dependan de tal sistema de ficheros tendrán modificado su sistema de ficheros con los cambios que se hayan realizado. Como ventaja de este método cabe nombrar que al estar utilizando copy on write en la virtualización se reduce el espacio de disco utilizado, ya que varias máquinas virtuales están utilizando la misma imagen de disco con los paquetes ya instalados. Para ello se arrancará una máquina virtual que utilice en modo directo y con conectividad a Internet el sistema de ficheros descargado: # lxc-start –n MV –f /usr/share/vnx/filesystems/rootfs_lxc_ubuntu/config Una vez arrancada se activará la red utilizando el comando dhclient a la interfaz eth0: # dhclient eth0 De esta forma, tal interfaz se conectará al switch virtual lxcbr0 que proporcionará acceso a Internet y ya se podrán instalar los paquetes necesarios. Finalizada la instalación se parará la máquina virtual con el comando halt, quedando los cambios realizados visibles desde todas las máquinas virtuales de nuestro escenario que dependan del sistema de ficheros modificado. 7 Desarrollo 2.1.2.B. Conexión del escenario con redes externas La otra opción disponible, para la instalación de los paquetes necesarios en el escenario, es dotar a las diferentes máquinas virtuales de una interfaz de red conectada a un switch virtual con conexión a Internet. En nuestro caso se dispone de dos redes virtuales creadas por defecto con sus correspondientes switches virtuales: virbr0 y lxcbr0. A continuación se explicará el funcionamiento de este tipo de redes y switches virtuales, más en concreto virbr0, que es proporcionado por libvirt 6. Libvirt es una interfaz de programación de aplicaciones (API) que interactúa con varios hipervisores de virtualización y ofrece diferentes funciones, como por ejemplo la creación de redes virtuales. Se utilizará el switch de red virtual virbr0 que está disponible tras la instalación de la herramienta VNX. A este switch se conectarán las diferentes máquinas virtuales de nuestro escenario y en el momento que se precise de conexión con el exterior será posible. 7 Figura 2.1-2 - Switch de red virtual de libvirt 7 Para realizar la conexión es necesario solicitar desde la máquina virtual deseada una petición desde el cliente de DHCP. De esta forma se enviarán peticiones broadcast por la interfaz creada solicitando información de configuración, y así conseguir una dirección IP junto con otros parámetros relevantes para el correcto funcionamiento del sistema en la red, como la máscara de red, el router por defecto y los servidores de DNS. El servidor DHCP otorgará a la máquina virtual una dirección IP del rango 192.168.122.2 – 192.168.122.254 Figura 2.1-3 - Servidor DNS y DHCP de libvirt 7 8 Desarrollo Se puede comprobar que está activo el switch virtual virbr0, que viene preconfigurado por defecto, mediante el comando ifconfig o brctl show en el que se obtendrán los siguientes resultados: # ifconfig virbr0 Link encap:Ethernet direcciónHW fe:35:18:d7:76:81 Direc.inet:192.168.122.1 Difus.:192.168.122.255 Másc:255.255.255.0 ACTIVO DIFUSIÓN FUNCIONANDO MULTICAST MTU:1500 Métrica:1 Paquetes RX:27 errores:0 perdidos:0 overruns:0 frame:0 Paquetes TX:18 errores:0 perdidos:0 overruns:0 carrier:0 colisiones:0 long.colaTX:0 Bytes RX:2884 (2.8 KB) TX bytes:1934 (1.9 KB) # brctl show virbr0 bridge name virbr0 bridge id 8000.000000000000 STP enabled yes interfaces También existen unas funciones disponibles a través del comando virsh mediante el cual se obtiene más información, como por ejemplo: Muestra el listado de redes (en nuestro caso la red que utilizada es default, que deberá venir preconfigurada) # virsh net-list Nombre Estado Inicio automático Persistente ------------------------------------------------------------default activo si si Muestra información general sobre la red solicitada # virsh net-info default Nombre default UUID 70a01cdb-e771-462c-8ec1-8a7f64c57088 Activar: si Persistente: si Autoinicio: si Puente: virbr0 9 Desarrollo Muestra el fichero .xml de la red solicitada # virsh net-dumpxml default <network> <name>default</name> <uuid>70a01cdb-e771-462c-8ec1-8a7f64c57088</uuid> <forward mode='nat'> <nat> <port start='1024' end='65535'/> </nat> </forward> <bridge name='virbr0' stp='on' delay='0' /> <ip address='192.168.122.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.122.2' end='192.168.122.254'/> </dhcp> </ip> </network> Si en algunas de las comprobaciones no se obtiene un resultado verificando el switch virtual o se desea crear una nueva red con su switch virtual correspondiente se puede definir de la siguiente manera: 1 – Creación de un fichero .xml especificando la red a crear en el directorio /etc/libvirt/qemu/network. A continuación se muestra un ejemplo del fichero correspondiente de la red preconfigurada default: <network> <name>default</name> <bridge name="virbr0" /> <forward/> <ip address="192.168.122.1" netmask="255.255.255.0"> <dhcp> <range start="192.168.122.2" end="192.168.122.254" /> </dhcp> </ip> </network> 2 – Definición de la red # virsh net-define /etc/libvirt/qemu/network/default.xml La red default se encuentra definida desde default.xml 3 – Configuración de auto-inicio de la red (opcional) # virsh net-autostart default La red default se ha sido marcada para iniciarse automáticamente 10 Desarrollo 4 – Inicio de la red # virsh net-start default La red default se ha iniciado Si se desea borrar una red existente se puede hacer uso del siguiente comando: # virsh net-destroy default La red default ha sido destruida Para la creación de la interfaz de red de las máquinas virtuales que se conectará al switch virtual que se ha descrito se tendrá que modificar la plantilla .xml del escenario. Se añadirá un nuevo switch virtual con el nombre de virbr0 y la opción managed=”no” que permitirá a la herramienta VNX en el momento del borrado del escenario no eliminar la red correspondiente al switch virtual virbr0: <net name="virbr0" mode="virtual_bridge" managed="no" /> Y en cada una de las máquinas virtuales que se desee tener conexión a Internet se indicará el nuevo interfaz: <if id="99" net="virbr0"/> Una vez arrancado el escenario, como se describe en el apartado 2.1.3. Arranque del escenario, se podrá comprobar que está disponible tal interfaz de red en las máquinas virtuales: # ifconfig eth99 Link encap:Ethernet HWaddr 02:fd:00:00:03:63 inet6 addr: fe80::fd:ff:fe00:363/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:337 errors:0 dropped:0 overruns:0 frame:0 TX packets:10 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:62098 (62.0 KB) TX bytes:1076 (1.0 KB) Para solicitar una dirección IP al servidor DHCP, y tener conectividad al exterior, se utilizará el siguiente comando: # dhclient eth99 11 Desarrollo Se puede comprobar la dirección IP asignada utilizando de nuevo el comando ifconfig: # ifconfig eth99 Link encap:Ethernet HWaddr 02:fd:00:00:03:63 inet addr:192.168.122.153 Bcast:192.168.122.255 Mask:255.255.255.0 inet6 addr: fe80::fd:ff:fe00:363/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:68 errors:0 dropped:0 overruns:0 frame:0 TX packets:14 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:10078 (10.0 KB) TX bytes:1920 (1.9 KB) Y en la tabla de forwarding de las máquinas virtuales se habrá añadido automáticamente como puerta de enlace la dirección IP 192.168.122.1: root@FW:~# route Kernel IP routing table Destination Gateway default 192.168.122.1 10.1.1.0 * 10.1.2.0 * 192.168.122.0 * Genmask 0.0.0.0 255.255.255.0 255.255.255.0 255.255.255.0 Iface eth99 eth1 eth2 eth99 Realizando un ping para comprobar la conectividad a cualquier página web disponible en Internet se comprueba que el resultado es satisfactorio: # ping www.dit.upm.es PING www.dit.upm.es (138.4.2.60) 56(84) bytes of 64 bytes from www.dit.upm.es (138.4.2.60): seq=1 64 bytes from www.dit.upm.es (138.4.2.60): seq=2 64 bytes from www.dit.upm.es (138.4.2.60): seq=3 data. ttl=51 time=53.5 ms ttl=51 time=54.5 ms ttl=51 time=52.8 ms --- www.dit.upm.es ping statistics --3 packets transmitted, 3 received, 0% packet loss, time 2002ms rtt min/avg/max/mdev = 52.814/53.634/54.503/0.715 ms 12 Desarrollo 2.2. Arranque del escenario El último paso para el funcionamiento del escenario es arrancarlo a través de la herramienta VNX, la cual ofrece múltiple funcionalidades. Los comandos a ejecutar tendrán la siguiente estructura: # vnx –f VNX_file --ACTION [options][-M VM_LIST] VNX_FILE es la plantilla .xml creada para el escenario. ACTION es una de las diferentes acciones disponibles de la herramienta. VM_LIST es una de las posibles opciones en el que la acción a ejecutar sólo se producirá en la lista de máquinas virtuales indicadas del escenario. Un ejemplo puede ser -M NAS1,NAS2,NAS3. A continuación se muestra el diagrama de estados en el que pueden estar las diferentes máquinas virtuales de un escenario en concreto a través de la herramienta VNX, y sus diferentes acciones de transición: Figura 2.2-1 - Diagrama de estados de las máquinas virtuales en VNX 13 Desarrollo En nuestro caso, las acciones más utilizadas serán create, destroy, shutdown, start y reboot, siendo sus comandos los siguientes: # vnx –f VNX_file --create # vnx –f VNX_file --destroy # vnx –f VNX_file --shutdown # vnx –f VNX_file --start # vnx –f VNX_file --reboot Cabe mencionar la opción –n al utilizar el comando create o start que permite ocultar las consolas de las distintas máquinas virtuales arrancadas. También existen otros comandos de interés de la herramienta VNX a utilizar en el desarrollo de la práctica como por ejemplo los que se nombran a continuación: Ejecuta los comandos indicados con una cierta etiqueta de la plantilla. Este tipo de comando es útil porque se puede especificar en la plantilla que se ejecuten ciertos comandos en las máquinas virtuales que se requieran en el momento de arranque de la propia máquina virtual o cuando se utiliza este comando. # vnx –f VNX_file --execute TAG [-M VM_LIST] En la plantilla .xml se configurará de la siguiente forma: <exec seq="TAG" type="verbatim" ostype="system"> COMANDO_A_EJECUTAR </exec> Muestra las consolas del conjunto de máquinas virtuales del escenario. Aplicando la opción -M permite mostrar las consolas de aquellas máquinas virtuales indicadas. # vnx –f VNX_file --console [-M VM_LIST] Muestra el estado en el que se encuentran las máquinas virtuales # vnx –f VNX_file --show-status [-M VM_LIST] Muestra un diagrama con las conexiones de red construidas en el escenario. # vnx –f VNX_file --show-map 14 Desarrollo 2.3. Sistema de ficheros A continuación se detalla la configuración del sistema de ficheros GlusterFS 8 en el escenario propuesto con el objetivo de evaluar diferentes propuestas y características de un centro de datos como pueden ser: escalabilidad, redundancia, tolerancia de fallos, etc. El proceso se dividirá en dos pasos ya que es necesario configurar tanto los servidores de disco como los servidores web. El primer paso consistirá en la creación del volumen en los servidores de disco, donde se podrá disponer de diferentes tipos de volúmenes según las necesidades requeridas. En el segundo paso se describirán diferentes métodos para realizar el montaje desde los servidores web, ya que aunque tengan el mismo propósito no son todos iguales de fiables. 2.3.1. Configuración de los servidores de disco Para la correcta configuración de los servidores de disco se necesita que cada uno de ellos disponga de identificadores (UUID) distintos. En nuestro caso, al generar todas las máquinas virtuales a partir de la misma imagen tienen configurado el mismo identificador. Por ello, es necesario generar nuevos identificadores. Una posible solución es generar identificadores nuevos con el comando uuidgen en cada uno de los servidores de disco NAS2 y NAS3, y sobrescribir el fichero /etc/glusterd/glusterd.info con el nuevo identificador generado en cada uno de ellos respectivamente. Por ejemplo: Comandos a ejecutar en el servidor de disco NAS2: root@NAS2:~# uuidgen 361fbfb4-fa61-49d1-9096-1b8a481476b6 root@NAS2:~# echo UUID=361fbfb4-fa61-49d1-9096-1b8a481476b6> /etc/glusterd/glusterd.info Comandos a ejecutar en el servidor de disco NAS3: root@NAS3:~# uuidgen 6763582b-7fc7-4767-a7d7-e289709c0ba7 root@NAS3:~# echo UUID=6763582b-7fc7-4767-a7d7-e289709c0ba7> /etc/glusterd/glusterd.info Tras la ejecución de estos comandos se debe rearrancar el servicio, en cada uno de los NAS, para que los cambios tengan efecto mediante la siguiente orden: # service glusterfs-server restart glusterfs-server stop/waiting glusterfs-server start/running 15 Desarrollo El siguiente paso será la creación del clúster de servidores de disco 9. Para ello se necesitará acceder a uno de los servidores de disco, por ejemplo NAS1, y agregar los servidores al repositorio ejecutando el comando gluster peer probe seguido de la dirección IP de los demás servidores: root@NAS1:~# gluster peer probe 10.1.3.22 Probe successful root@NAS1:~# gluster peer probe 10.1.3.23 Probe successful Se puede verificar que se han añadido correctamente desde cualquiera de los servidores NAS de la siguiente manera: root@NAS1:~# gluster peer status Number of Peers: 2 Hostname: 10.1.3.22 Uuid: 361fbfb4-fa61-49d1-9096-1b8a481476b6 State: Peer in Cluster (Connected) Hostname: 10.1.3.23 Uuid: 6763582b-7fc7-4767-a7d7-e289709c0ba7 State: Peer in Cluster (Connected) Si se necesita descartar algún servidor añadido al cluster se puede hacer uso del siguiente comando: root@NAS1:~# gluster peer detach IPADDRESS Detach successful Una vez añadidos los servidores de disco se procederá a crear el volumen con la configuración que se considere más apropiada. Se deberá seguir el siguiente formato en el comando de creación: # gluster volume create VOLNAME [stripe COUNT | replica COUNT] NEW-BRICK1 NEW-BRICK2 NEW-BRICK3... Los distintos modelos de configuración se tratarán en los siguientes subapartados: - Volumen distribuido - Volumen en replica - Volumen seccionado Existen otras posibilidades que se pueden aplicar en GlusterFS que son combinaciones entre las configuraciones anteriores. 16 Desarrollo 2.3.1.A. Volumen distribuido Se distribuyen los archivos de forma aleatoria entre los bloques del volumen. En este modo de configuración hay que tener en cuenta que la avería de algún servidor de disco puede resultar una grave pérdida de datos, ya que el contenido del servidor caído se perderá del volumen. Como ventaja en esta configuración cabe destacar la eficiencia en la escritura de datos.10 Figura 2.3-1: Volumen distribuido 10 El comando de creación en esta configuración debe seguir el siguiente formato: # gluster volume create NEW-VOLNAME NEW-BRICK... Siendo en nuestro escenario el siguiente: # gluster volume create nas 10.1.3.21:/nas 10.1.3.22:/nas 10.1.3.23:/nas 2.3.1.B. Volumen en réplica Se copian los archivos a través de los bloques del volumen. Esta configuración proporciona una mayor fiabilidad ya que se tendrá redundancia en la información almacenada y garantizará mayor disponibilidad del servicio. El inconveniente en este tipo de volumen es la cantidad de tráfico generado, ya que los cambios se distribuyen al mismo tiempo a todos los bloques del volumen. Figura 2.3-2: Volumen en réplica 10 El comando de creación en esta configuración debe seguir el siguiente formato: # gluster volume create NEW-VOLNAME [replica COUNT] NEW-BRICK.. Siendo en nuestro escenario el siguiente: # gluster volume create nas replica 3 10.1.3.21:/nas 10.1.3.22:/nas 10.1.3.23:/nas 17 Desarrollo 2.3.1.C. Volumen seccionado En esta configuración los archivos son fragmentos en diferentes porciones que se reparten entre los diferentes bloques que componen el volumen. Es generalmente utilizado para almacenar archivos de gran tamaño en entornos de alta concurrencia. Figura 2.3-3: Volumen seccionado 10 El comando de creación en esta configuración debe seguir el siguiente formato: # gluster volume create NEW-VOLNAME [stripe COUNT] NEW-BRICK.. Siendo en nuestro escenario el siguiente: # gluster volume create nas stripe 3 10.1.3.21:/nas 10.1.3.22:/nas 10.1.3.23:/nas Una vez creado el volumen se puede comprobar la información del volumen: # gluster volume info Volume Name: nas Type: XXX Status: Created Number of Bricks: 3 Transport-type: tcp Bricks: ... Tras la creación del volumen será necesario su inicialización mediante el comando: # gluster volume start nas Starting volume nas has been successful Si en algún determinado momento es necesario eliminar el volumen creado se debe seguir el siguiente procedimiento: # gluster volume stop nas Stopping volume will make its data inaccessible. Do you want to continue? (y/n) y Stopping volume nas has been successful # gluster volume delete nas Deleting volume will erase all information about the volume. Do you want to continue? (y/n) y Deleting volume nas has been successful 18 Desarrollo 2.3.2. Montaje desde los servidores web El último paso para finalizar la configuración del sistema de ficheros es realizar el montaje desde los servidores web, ya que necesitan conocer el volumen creado, así como su configuración y bloques que lo componen. En el momento del montaje se especificará desde cada servidor web uno de los tres servidores de disco del escenario, los cuales poseen la información del volumen creado en el directorio/etc/glusterd/vols/nas. Una vez realizado el montaje, los servidores web conocerán cada uno de los servidores de disco que componen el volumen para mantener el sistema de ficheros. El sistema de ficheros GlusterFS funciona basándose en un modelo maestro-esclavo, siendo en nuestro caso el maestro los servidores web, y el esclavo los servidores de disco del escenario.11 Figura 2.3-4 - Modelo maestro-esclavo en GlusterFS 11 Para las diferentes formas de montaje es necesario tener en el sistema un módulo cargable de núcleo conocido como FUSE (Filesystem in Userspace) 12. Para su creación basta con ejecutar el siguiente comando mknod 13 creando el correspondiente archivo de dispositivo: # mknod -m 666 /dev/fuse c 10 229 A continuación se describirán diferentes métodos de montaje que se diferenciarán entre sí porque proporcionarán distintos grados de automatización y fiabilidad en el montaje. 2.3.2.A. Montaje mediante el comando mount Para acceder al sistema de ficheros exportado por los servidores de disco se puede utilizar directamente el comando mount, ya que es una de las opciones más rápidas de montaje. Solamente será necesaria la creación de un directorio y ejecutar mount indicando el punto de montaje en el directorio creado del servidor web. Un posible ejemplo es el siguiente: # mkdir /mnt/nas root@NAS1:~# mount -t glusterfs 10.1.3.21:/nas /mnt/nas root@NAS2:~# mount -t glusterfs 10.1.3.22:/nas /mnt/nas root@NAS3:~# mount -t glusterfs 10.1.3.23:/nas /mnt/nas En este caso, si falla el servidor de disco que se indica en el momento del montaje se perderá el sistema de ficheros en el servidor web correspondiente. 19 Desarrollo 2.3.2.B. Montaje mediante el fichero fstab El fichero /etc/fstab (File System Table) 14 forma parte de la configuración del sistema y es el encargado de reflejar cómo se montan los discos en el sistema de ficheros. Lo que está escrito en tal fichero sirve para tener acceso a los discos una vez que se inicia el sistema operativo. Este procedimiento se puede considerar una versión avanzada del montaje visto anteriormente ya que se modificará el fichero fstab para que el sistema monte automáticamente el sistema de ficheros proporcionado por los servidores de disco. Para ello, será necesario añadir la siguiente línea al fichero fstab: IPADDRESS:/VOLNAME MOUNTDIR glusterfs defaults,_netdev 0 0 En nuestro caso, el fichero fstab quedará con el siguiente contenido: # UNCONFIGURED FSTAB FOR BASE SYSTEM 10.1.3.21:/nas /mnt/nas glusterfs defaults,_netdev 0 0 Para proceder al montaje una vez modificado el fichero fstab se puede reiniciar la máquina virtual mediante el comando reboot, o directamente utilizar el comando mount –a. Si al arrancar de nuevo alguna de las máquinas no se cargara automáticamente el sistema de ficheros será necesario modificar el fichero /etc/rc.local dejándolo con el siguiente contenido: #!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. mount -a exit 0 Sin embargo, se tiene el mismo problema que en el montaje mediante el comando mount, donde si no se encuentra disponible el servidor de disco indicado en el momento del montaje no se cargará el sistema de ficheros en el servidor web correspondiente. 20 Desarrollo 2.3.2.C. Montaje creando un archivo de configuración del volumen En este modo de montaje se pretende crear un archivo de configuración del volumen indicando diferentes puntos de montaje. Dado el escenario se indicarán tres puntos de montaje del volumen, uno por cada servidor de disco del escenario. Este tipo de montaje se garantiza que se comprobarán todos los puntos de montaje indicados, evitando el problema que se mencionaba en los otros dos métodos anteriores. Para ello, se debe modificar el fichero /etc/fstab indicando donde se encuentra el archivo de configuración del volumen: # UNCONFIGURED FSTAB FOR BASE SYSTEM /etc/glusterfs/datastore.vol /mnt/nas glusterfs rw,allow_other,default_permissions,max_read=131072 0 0 Se creará un archivo de configuración llamado datastore.vol en el directorio /etc/glusterfs. Su contenido es el siguiente: volume remote1 type protocol/client option transport-type tcp option remote-host 10.1.3.21 option remote-subvolume /nas end-volume volume remote2 type protocol/client option transport-type tcp option remote-host 10.1.3.22 option remote-subvolume /nas end-volume volume remote3 type protocol/client option transport-type tcp option remote-host 10.1.3.23 option remote-subvolume /nas end-volume volume replicate type cluster/replicate subvolumes remote1 remote2 remote3 end-volume volume writebehind type performance/write-behind option window-size 1MB subvolumes replicate end-volume 21 Desarrollo volume cache type performance/io-cache option cache-size 512MB subvolumes writebehind end-volume Para realizar el montaje sin reiniciar el sistema es posible utilizar el comando mount -a. Se puede comprobar el estado del montaje de la siguiente forma: root@WWW1:/# df -h S.ficheros /etc/glusterfs/datastore.vol Montado en /mnt/nas Así, aunque en el momento del montaje no se encuentre accesible el servidor de disco NAS1, se intentará con NAS2, y en caso de fallo se intentará con NAS3, siendo esta opción la más fiable de las mencionadas. 2.4. Aplicación web Se ha desarrollado para el escenario una aplicación web que permite a los diferentes usuarios subir, descargar y borrar ficheros que se alojan en los servidores de disco. Para ello las tecnologías utilizadas han sido HTML y PHP5. Se pretende proporcionar una interfaz sencilla para el usuario donde en todo momento pueda seleccionar una de las opciones que se han comentado. Por ello se ha utilizado una estructura de marcos con cuatro frames, donde uno de ellos se encargará de permitir al usuario realizar la acción que seleccione a partir de un menú. De esta forma, la página principal es la siguiente: Figura 2.4-1: Página de incio de la Aplicación web 22 Desarrollo SUBIDA DE FICHEROS: Se puede realizar una subida múltiple seleccionando varios archivos en la ventana emergente que se muestra. Para el correcto funcionamiento es necesario que los directorios /tmp y /mnt/nas dispongan de permisos de lectura y escritura para todos los usuarios. Figura 2.4-2: Función de Subida de ficheros DESCARGA DE FICHEROS: Se mostrará una lista con todos los archivos que se encuentran disponibles para descargar. Figura 2.4-3: Función de Descarga de ficheros BORRADO DE FICHEROS: Se mostrará una lista con los archivos alojados en los servidores. Se notificará mediante una ventana emergente cuando se haya eliminado el archivo deseado correctamente. Figura 2.4-4: Función de Borrado de ficheros 23 Desarrollo 2.5. Balanceador de carga Según el escenario propuesto se pretende balancear la carga entre los diferentes servidores web que se disponen y así se podrán repartir las peticiones de servicio que se reciban. En este caso, se ha decidido realizar esta funcionalidad a través de la tecnología SDN (Software Defined Networking) 15, ya que proporciona una nueva visión sobre las configuraciones y funciones de la red mediante el control y centralización gestionado por software. La aplicación software que se encarga de la red se denomina controlador, y en el escenario se situará en la máquina virtual denominada CONTROLLER. De esta forma, en el controlador se encontrará la Capa de Control y en los dispositivos de red la Capa de Infraestructura. Para la comunicación entre ambas capas será necesario la utilización de un protocolo. Actualmente, existe un proyecto en el que trabajan varias empresas del mundo, que forman parte de la Open Networking Fundation (ONF) 16, con el objetivo del desarrollo de un protocolo de código abierto llamado OpenFlow, siendo el más ampliamente aceptado en SDN, pero cabe mencionar que existen otras iniciativas para la comunicación entre las capas mencionadas. En cada uno de los dispositivos de la red se encuentra una parte denominada Tabla de Flujos, que recoge todas las acciones que debe realizar un switch a medida que se recibe un nuevo flujo por alguno de sus puertos. El controlador es el encargado de añadir entradas en la tabla de flujos de cada switch. Existe una tercera capa, la Capa de Aplicación, que es la de más alto nivel y aporta la capacidad de crear aplicaciones a través de una API (application programming interface). De esta forma, la estructura SDN es la siguiente: Figura 2.5-1: Arquitectura SDN 24 Desarrollo Dependiendo de la API utilizada existen múltiples controladores que se diferenciaran fundamentalmente en cuanto al lenguaje de programación y la plataforma. Algunas de las alternativas de controladores SDN OpenFlow son: Python: POX, Ryu Java: Floodlight, Beacon Ruby: Trema El estudio se ha centrado en los controladores Floodlight y POX, ya que son dos controladores que vienen con la funcionalidad de balanceo de carga implementada en cierta medida, y por sus características se han considerado apropiados para el escenario. En un primer momento se trabajó con el controlador Floodlight en el escenario propuesto, pero no se alcanzó el balanceo de carga correctamente ya que solo se produce en peticiones que se realizan desde la misma subred. Por ello se decidió examinar nuevas alternativas y se realizó el estudio con el controlador POX, con el cual se han alcanzado los objetivos satisfactoriamente y se balancea el tráfico en el escenario en su totalidad. A continuación se detalla más información sobre cada uno de ellos para dotar de la función de balanceo de carga al escenario. 2.5.A. Controlador Floodlight Es un controlador que está basado en Java, y para su correcto funcionamiento debe estar ejecutándose en el propio host o en una máquina virtual donde el sistema de ficheros sea en modo directo. Si se decide instalar el controlador en el host se deberá indicar en la plantilla .xml del escenario que en la red LAN2 el controlador se encontrará en 127.0.0.1:6633. Si se escoge la otra opción, y se decide utilizar una máquina virtual en modo directo es necesario modificar la plantilla .xml del escenario con la siguiente línea: <filesystem type="direct"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-CONTROLLER </filesystem> El proceso de instalación e inicialización se encuentra descrito en la documentación del proyecto Floodlight 17, donde también se especifica el funcionamiento del módulo balanceador de carga. Para trasmitir los parámetros del balanceador al controlador, será necesario crear un script y mediante la conexión de curl será suficiente. En el escenario propuesto se utilizará el siguiente script: 25 Desarrollo #!/bin/sh curl -X POST -d '{"id":"1","name":"vip1","protocol":"tcp","address":"10.1.2.10","port":"8"}' http://localhost:8080/quantum/v1.0/vips/ curl -X POST -d '{"id":"1","name":"pool1","protocol":"tcp","vip_id":"1"}' http://localhost:8080/quantum/v1.0/pools/ curl -X POST -d '{"id":"1","address":"10.1.2.11","port":"8","pool_id":"1"}' http://localhost:8080/quantum/v1.0/members/ curl -X POST -d '{"id":"2","address":"10.1.2.12","port":"8","pool_id":"1"}' http://localhost:8080/quantum/v1.0/members/ curl -X POST -d '{"id":"3","address":"10.1.2.13","port":"8","pool_id":"1"}' http://localhost:8080/quantum/v1.0/members/ Con todo esto se tendrá el controlador Floodlight funcionando, pero como se ha comentado anteriormente, solo balanceará peticiones de la misma subred donde se encuentran los servidores web. Para ello se puede comprobar realizando una petición de servicio desde la máquina FW: Figura 2.5-2: Petición de servicio desde FW para comprobar balanceador de carga mediante Floodlight Una de las ventajas que se ha encontrado que tiene Floodlight es que incorpora un portal web en el que se recoge información sobre el controlador. Para acceder basta con conectarse desde el navegador a la dirección localhost:8080/ui/index.html. Sin embargo, se han encontrado varios inconvenientes en el escenario: No se ha alcanzado el balanceo de carga en su totalidad, ya que los clientes deben encontrarse en la misma subred que los servidores web. El controlador debe estar ejecutándose en el propio host o en una máquina virtual donde el sistema de ficheros sea en modo directo, no tipo cow como se estaba utilizando hasta ahora. Requiere importante espacio libre en disco, ya que se precisa la instalación de diferentes paquetes Por las anteriores razones, se decidió estudiar y probar el controlador POX con el objetivo de dotar al escenario con la funcionalidad de balanceo de carga a las diferentes peticiones de servicio que se envíen desde los equipos clientes. 26 Desarrollo 2.5.B. Controlador POX Es un controlador que tiene una interfaz OpenFlow y puede estar ejecutándose en cualquier plataforma: Linux, Windows, Mac OS, etc. Se constituye por diversos componentes que pueden ser reutilizados para la adaptación según considere el usuario. En nuestro caso se modificará el componente de balanceo de carga para adaptarlo al escenario propuesto. Para su instalación solo es necesario disponer en la máquina de Git y ejecutar el siguiente comando para obtener una copia del repositorio del proyecto: # git clone http://github.com/noxrepo/pox # cd pox El componente encargado del balanceo de carga se encuentra implementado, dentro del proyecto, en el fichero pox/misc/ip_loadbalancer.py. Es necesario realizar diferentes modificaciones en el fichero para personalizarlo en el escenario propuesto. Para poner en marcha el controlador se utiliza el componente de inicio pox.py. De esta forma, para arrancar cualquier modulo se sigue la siguiente orden: root@CONTROLLER:/pox# ./pox.py NOMBRE_COMPONENTE [OPCIONES] En nuestro caso, para arrancar el balanceador de carga: root@CONTROLLER:/pox# ./pox.py misc.ip_loadbalancer --ip=10.1.2.10 --servers=10.1.2.11,10.1.2.12,10.1.2.13 Figura 2.5-3: Arranque del Controlador POX 27 Desarrollo También es posible arrancarlo en un modo de depuración donde es posible obtener más información al respecto de los eventos que suceden en el controlador. Para ello hay que añadir la opción log.level --DEBUG, como se muestra en la siguiente captura: Figura 2.5-4: Arranque del Controlador POX en modo DEBUG Como se muestra en la captura anterior, el controlador envía periódicamente mensajes ARP a los diferentes servidores, que se le han proporcionado en su arranque, para comprobar que se encuentran activos y así enviar las posibles peticiones de servicio hacia ellos. Si pasado un cierto tiempo del envío del mensaje ARP Request no se recibe ninguna respuesta por parte de algún servidor, mediante un mensaje ARP Reply, se considerará que el servidor está caído y no se enviarán peticiones hacia él. Figura 2.5-5: ARPing hacia los servidores web 28 Desarrollo Al recibir una petición de servicio el switch verificará si en su tabla de flujos tiene algún flujo asociado. En caso de no tenerlo se lo comunicará al controlador que examinará cuál de los servidores de encuentra activo y según el algoritmo implementado informará a la tabla de flujos del switch para redirigir la petición hacia al servidor web seleccionado. En nuestro caso, se encuentra implementado un algoritmo round robin 18 entre los servidores web para balancear las diferentes conexiones abiertas en los clientes. En la siguiente imagen se muestra este proceso: Figura 2.5-6: Envío de una petición de servicio desde un cliente Una vez que el servidor web seleccionado recibe la petición, devuelve una respuesta al cliente, y en el momento que la trama pasa por el switch se cambia la dirección IP origen del servidor web a la dirección IP virtual del servicio. Este proceso se puede ver en la siguiente imagen: Figura 2.5-7: Envío de una respuesta de servicio desde un servidor web Se puede comprobar el estudio de pruebas realizado del balanceador de carga mediante el controlador POX en el capítulo 3.3. Análisis del balanceador de carga. 29 Desarrollo 2.6. Firewall En el escenario se ha elegido utilizar Firewall Builder 19 como sistema cortafuegos ya que proporciona una interfaz gráfica y profesional al usuario para la configuración de políticas de seguridad. Sin embargo, es posible utilizar cualquier otro software de seguridad como por ejemplo, Uncomplicated Firewall 20, que es más ligero y utiliza un pequeño número de comandos simples para su configuración. Para el acceso a la interfaz de Firewall Builder es necesario acceder a la máquina FW desde el host a través de la red, y ejecutar las acciones pertinentes en la máquina remota. Por ello, ha sido necesario la instalación del paquete xauth que permitirá mostrar la interfaz gráfica del software en el equipo host de manera remota. Para crear un túnel ssh a la máquina FW, y así poder conectarse a ella, se ejecutará el siguiente comando: # slogin -X [email protected] [email protected]’s password: xxxx root@FW:~# Una vez dentro de la máquina virtual FW se accederá a la interfaz de Firewall Builder: root@FW:~# fwbuilder Firewall Builder GUI 5.1.0.3599 La primera vez que se accede se mostrará la siguiente pantalla de bienvenida: Figura 2.6-1: Pantalla de bienvenida de Firewall Builder 30 Desarrollo En ella se pulsará la opción Create new firewall, situada en el botón izquierdo de la parte central. Tras ello se abrirá una nueva ventana solicitando información sobre el firewall a crear. Aquí se indicará que se utilizará como software iptables 21, como se indica a continuación: Figura 2.6-2: Creación de un firewall (paso 1) Tras seleccionar el botón Next, se permite realizar el descubrimiento automáticamente de las interfaces de red del firewall mediante SNMP 22 o realizar una configuración manual. En nuestro caso se realizará una configuración manual de las mismas. Figura 2.6-3 Creación de un firewall (paso 2) Para ello será necesario configurar las tres interfaces que tiene el firewall de nuestro escenario: eth1 (10.1.1.1), eth2 (10.1.2.1) y lo (127.0.0.1). 31 Desarrollo Figura 2.6-4: Configuración de la interfaz eth1 del firewall Figura 2.6-5: Configuración de la interfaz eth2 del firewall Figura 2.6-6: Configuración de la interfaz de loopback del firewall Tras finalizar el proceso de creación del firewall ya se está en condiciones de crear, según las necesidades, las reglas de filtrado de paquetes. En la parte izquierda de la pantalla principal se encuentran disponibles dos librerías, Standard y User, que muestran un árbol de objetos y servicios que se podrán añadir en las reglas mediante la técnica conocida como arrastrar y soltar (drag and drop), por lo que será muy fácil el rellenado de las reglas con el contenido que se desee aplicar. Es posible crear nuevos objetos en la librería User según las necesidades del usuario. En nuestro caso se han realizado las siguientes creaciones: 32 Desarrollo NOMBRE DEL OBJETO TIPO DETALLES Addresses Address: 10.1.1.10 Networks Address: 10.1.2.0 Netmask: 255.255.255.0 También se ha agregado un servicio que debe permitir el firewall en nuestro escenario, el puerto 5001 que utiliza la herramienta iperf por defecto. NOMBRE DEL SERVICIO TIPO TCP DETALLES Destination Port: 5001 Una vez creados todos los objetos necesarios para la política de seguridad, en la pestaña Policy del firewall es posible definir un conjunto de reglas a aplicar en nuestro escenario, como pueden ser las siguientes: Figura 2.6-7: Política de reglas aplicadas en el firewall En este momento, antes de la instalación de las reglas, se debe salvar un fichero de configuración, con la extensión .fwb, que permite guardar no solo los nombres y definiciones de los objetos, servicios, etc. que utilizan las reglas de filtrado, sino también las propias reglas de filtrado. Tras ello es posible realizar la instalación de las reglas mediante la compilación del fichero de configuración, generando un fichero, con extensión .fw, que es realmente un archivo tipo Shell-Script que permitirá poner en marcha las reglas especificadas en el fichero de configuración. Este proceso hay que llevarlo a cabo usando las funciones Compile e Install que se muestran en la parte superior de la pantalla. En el momento de instalación aparecerá una pantalla solicitando algunos datos sobre el firewall, que se deben rellenar como se muestra en la siguiente figura: 33 Desarrollo Figura 2.6-8: Instalación de políticas de seguridad en el firewall Al pulsar el botón Install, se procederá a la instalación de todas las reglas configuradas y mediante el mensaje Firewall policy successfully installed se concluye que ha sido un éxito la instalación. La próxima vez que sea necesario configurar nuevas reglas en el firewall será posible cargar el fichero de configuración mediante la opción Open, y así evitar de nuevo la creación del firewall desde cero. Para finalizar la sesión ssh a la máquina FW es necesario ejecutar el comando exit: root@FW:~# exit logout Connection to 10.1.1.1 closed. 34 Desarrollo 2.7. Clientes Se han configurado en el escenario dos clientes, C1 y C2, además del propio host para comprobar el correcto acceso a la aplicación web desde diferentes equipos. El sistema operativo que tienen los clientes también carece de interfaz gráfica, como el resto de las máquinas virtuales. Por lo que para acceder al navegador Firefox instalado en los clientes se procederá a crear una sesión ssh, igual que en el caso del firewall. Para crear la sesión remota a C1, por ejemplo, se introducirá el siguiente comando: # slogin -X [email protected] [email protected]’s password: xxxx root@C1:~# Una vez dentro de la máquina virtual del cliente es posible abrir el navegador: root@C1:~# firefox Figura 2.7-1: Navegador Firefox desde un cliente a través de un túnel ssh De esta forma es posible visualizar la aplicación web que se ha creado desde los diferentes clientes. Además, desde el propio navegador se puede comprobar que se está efectuando correctamente el balanceo de carga configurado en el Controlador. Para ello, es posible mostrar el código fuente de la página mediante el atajo de teclado Ctrl+U. 35 Desarrollo Figura 2.7-2: Código fuente desde Firefox de la Aplicación web En la figura anterior se muestra que la página ha sido obtenida del servidor web WWW1, ya que en la aplicación web se configuró en el fichero index.html un comentario, que se indica dentro del rectángulo rojo, aportando información del servidor en el que se encuentra alojada la aplicación. Se recuerda que es posible tener conectividad al exterior desde el cliente al cual se está accediendo. Para ello solo será necesario utilizar el comando dhclient y abrir de nuevo el navegador. root@C1:~# dhclient eth99 root@C1:~# firefox Para finalizar la sesión ssh abierta con el cliente es necesario ejecutar el comando exit: root@C1:~# exit logout Connection to 10.1.1.11 closed. 36 3. Pruebas y resultados Tras el completo desarrollo del escenario se ha decidido realizar una serie de pruebas de algunas partes en concreto para comprobar el funcionamiento de diversos aspectos. Las dos primeras pruebas se han centrado en el sistema de ficheros. La primera de ellas ofrece un análisis del funcionamiento del protocolo GlusterFS, y la segunda muestra como un servidor caído es capaz de recuperar la información tras su reanudación. La tercera prueba se centra en el balanceador de carga, e intenta examinar el funcionamiento del controlador SDN cuando recibe diferentes peticiones de servicio. La cuarta prueba es una breve comprobación de la política de seguridad que se ha aplicado en el firewall. 3.1. Análisis de GlusterFS En esta prueba se pretende analizar fases destacables en el funcionamiento del protocolo GlusterFS cuando ya se tiene un volumen creado en los servidores de disco. Se utilizará el analizador de tráfico Wireshark para mostrar capturas de la información relevante en los diferentes procesos. Una vez creado el volumen como se ha descrito en 2.3.1. Configuración de los servidores de disco, es necesario el montaje desde los servidores web. El montaje es un proceso en el cual un servidor de disco indicado envía al servidor web correspondiente toda la información referente al volumen creado. En este caso se utilizará un volumen en réplica y se analizará el tráfico cuando el montaje es realizado desde el servidor web WWW1. En la siguiente captura se muestra la trama enviada por el servidor de disco NAS1 (10.1.3.21) que recibe el servidor web WWW1 (10.1.3.11) con toda la información del volumen creado a través del protocolo GlusterFS Handshake. Esta información enviada la poseen todos los servidores de disco en el directorio /etc/glusterd/vols/nas. Figura 3.1-1 - Captura del envío de la información del volumen 37 Pruebas y resultados Una vez montado el sistema de ficheros en los servidores web se procede a la creación de un archivo, y analizando el tráfico se puede comprobar en qué determinado momento se envía el archivo creado en el servidor web a los diferentes servidores de disco. En esta acción cabe destacar dos procesos que realiza el protocolo GlusterFS. El primero de ellos consiste en el envío de información general del archivo creado desde el servidor web a los diferentes servidores de disco. Lo realiza a través de una llamada denominada LOOKUP como se puede apreciar en la siguiente captura: Figura 3.1-2 - Captura de llamada LOOKUP en GlusterFS Tras la llamada LOOKUP enviada a los diferentes servidores de disco se produce una llamada WRITE en la que envía el contenido del archivo creado. La siguiente captura muestra este proceso: Figura 3.1-3: Captura de la llamada WRITE en GlusterFS En las tramas 200 y 201 se envía el contenido del archivo desde el servidor web hacia el servidor de disco NAS1. La trama 202 es el acuse de recibo que envía el servidor de disco NAS2 tras la recepción de la información, junto con la trama 204 que es la contestación a la llamada WRITE producida. Lo mismo ocurre en los demás servidores de disco, como se puede apreciar en las otras tramas capturadas. 38 Pruebas y resultados 3.2. Recuperación de un Servidor de Disco En esta prueba se pretende deshabilitar un servidor de disco mientras un usuario se encuentra añadiendo archivos al servidor web. Tras unos segundos se habilitará el servidor de disco caído y se analizará el proceso de recuperación de la información perdida. Para la prueba se configurará un volumen en réplica, ya que en este caso todos los servidores de disco deberán contener la misma información. Para simular la caída del servidor de disco se empleará una de las opciones del comando ifconfig que permite desactivar una interfaz dada. Figura 3.2-1 - Uso del comando ifconfig down De esta forma solamente figurará como interfaz de red la de loopback, dejando así el servidor de disco aislado de la red. En este momento, si un usuario agrega cualquier archivo a los servidores web no se encontrará disponible la información en el servidor de disco caído, como se puede apreciar en la siguiente captura: Figura 3.2-2 - Contenido de los servidores de disco 39 Pruebas y resultados Para habilitar de nuevo la interfaz de red del servidor de disco caído se utilizará de nuevo el comando ifconfig: Figura 3.2-3 - Uso del comando ifconfig up De esta forma el servidor de disco caído se encuentra de nuevo habilitado en la red, y al interaccionar con alguno de los servidores web enviará la información que desconocía. El envío de la información se realiza de igual forma que el explicado en el apartado 3.1. Análisis del protocolo GlusterFS. La siguiente captura muestra tal envío de recuperación de la información que se produce desde el servidor web, en este caso desde WWW1 (10.1.3.11), hacia el servidor de disco caído NAS1 (10.1.3.21) Figura 3.2-4 - Captura de la recuperación de la información en un servidor de disco caído 40 Pruebas y resultados 3.3. Análisis del balanceador de carga Una vez que se tiene el controlador POX funcionando, se pueden realizar diferentes pruebas para verificar el balanceo de tráfico de las peticiones que se hacen del servicio. En el momento de iniciar el controlador se muestra en una línea la siguiente información: INFO:openflow.of_01:[fa-f5-8d-5d-a8-45 1] connected En ella se muestra que se ha reconocido un switch del tipo Open vSwitch e indica un identificador del mismo. Es posible obtener más información sobre el switch creado mediante los siguientes comandos: # ovs-vsctl list bridge LAN2 _uuid : 5d8df5fb-4a9b-45a8-b73f-a50538a410ab controller : [5cfbd10a-2de9-444d-934b-9d38826e4d62] datapath_id : "0000faf58d5da845" datapath_type : "" external_ids : {} fail_mode : [] flood_vlans : [] flow_tables : {} ipfix : [] mirrors : [] name : "LAN2" netflow : [] other_config : {} ports : [119c5e01-30e7-431b-bb25-26d8ef48158f, 5e040e2d-8c24-48e9-8340-2e129e61af75, f8ff6d46-73a0-431a9ab5-3738c6fbdd15, fc9a6f99-a9c0-4a29-accc-166d5fe7e1e9, fd9266ea-2a50-4496-954e-a79aeb533a07] protocols : [] sflow : [] status : {} stp_enable : false # ovs-vsctl show 1b0d0349-6984-40cb-bbb1-100a50bcbf1d Bridge "LAN2" Controller "tcp:10.1.4.2:6633" is_connected: true Port "WWW3-e1" Interface "WWW3-e1" Port "WWW1-e1" Interface "WWW1-e1" Port "LAN2" Interface "LAN2" type: internal Port "WWW2-e1" Interface "WWW2-e1" Port "FW-e2" Interface "FW-e2" ovs_version: "2.0.1"ports 41 Pruebas y resultados Mediante la herramienta iperf ejecutándola desde alguno de los clientes se puede comprobar el balanceo entre los diferentes servidores web. A continuación se muestra una captura de la prueba: Figura 3.3-1: Balanceo mediante iperf desde un cliente De la misma forma, también es posible realizar la prueba con más clientes, y comprobar que se sigue balanceando sin ningún problema: Figura 3.3-2: Balanceo mediante iperf desde varios clientes En las capturas anteriores se comprueba que a medida que se inicia una nueva conexión con la dirección 10.1.2.10 se va balanceando el tráfico entre los tres servidores web, a pesar que se estén realizando peticiones simultáneamente entre diferentes clientes. 42 Pruebas y resultados Otra prueba se podría realizar con la herramienta curl, y así obtener el contenido de una página web en modo texto. Como en el index.html de la aplicación web se ha añadido un comentario indicando la procedencia del servidor, será de utilidad para comprobar el balanceador de carga. En la siguiente captura se muestra tal comando: Figura 3.3-3: Uso de curl para comprobar balanceo de carga A la vista del resultado se puede asegurar que el servidor web seleccionado para obtener el fichero index.html ha sido WWW1. Además, si se comprueba la ventana del controlador se mostrará una traza indicando el redireccionamiento: Figura 3.3-4: Trazas del controlador que verifican el balanceo de carga También es posible analizar el tráfico en la interfaz del CONTROLLER y comprobar que se está enviando información hacia la tabla de flujos del switch para la nueva petición del servicio realizada. Figura 3.3-5: Captura de tráfico de paquetes OpenFlow 43 Pruebas y resultados En la captura de tráfico se aprecia que desde el controlador se está creando un nuevo flujo como respuesta al nuevo paquete que se ha recibido desde el cliente hacia la IP virtual de servicio. Y comprobando la tabla de flujos se verifican los flujos creados: Figura 3.3-6: Tabla de flujos del switch virtual en LAN2 Resumiendo la información más relevante de la captura anterior de la tabla de flujos queda de la siguiente forma: in_port dl_src nw_src tp_src FLUJO 1 1 output 02:fd:00:00:02:02 dl_dst 10.1.1.11 nw_dst 42449 tp_dst mod_dl_dst mod_nw_dst FLUJO 2 2 output 02:fd:00:00:04:01 dl_dst 10.1.2.11 nw_dst 80 tp_dst mod_dl_src 00:00:00:11:22:33 10.1.2.10 mod_nw_src in_port dl_src nw_src tp_src 2 00:00:00:11:22:33 10.1.2.10 80 02:fd:00:00:04:01 10.1.2.11 1 02:fd:00:00:02:02 10.1.1.11 42449 Observando las tablas cabe mencionar que igual que existe una dirección IP virtual de servicio, también existe una dirección MAC virtual, 00:00:00:11:22:33. De esta forma, todas las peticiones del servicio se dirigen hacia la IP virtual y en el último salto se proporciona la dirección MAC virtual. Así, en las peticiones que se reciben desde el cliente se modifica la dirección física de destino (mod_dl_dst) y la dirección lógica de destino (mod_nw_dst). Y en las respuestas que se proporcionan desde el servidor web se modifica la dirección física de origen (mod_dl_src) y la dirección lógica de origen (mod_nw_src). 44 Pruebas y resultados En nuestro escenario el mapa físico en la red LAN2 es el siguiente: Figura 3.3-7: Diagrama físico de LAN2 Si se realiza la misma prueba desde el navegador de alguno de los clientes y se examina el controlador, se comprobará que se han añadido diferentes flujos para una única petición de servicio. Esto es así porque la aplicación web está creada con marcos y se compone de cinco ficheros .html. El navegador se encarga de abrir diferentes puertos para los ficheros que necesita obtener y con ello el controlador balancea todas las peticiones. En la siguiente captura se muestra lo obtenido en las trazas del controlador: Figura 3.3-8: Trazas del controlador al realizar una petición de servicio desde un navegador 45 Pruebas y resultados 3.4. Comprobación de las políticas de seguridad Tras la instalación de las políticas de seguridad del firewall descritas en el apartado 2.6. Firewall, es posible realizar aquellas acciones configuradas con denegar y rechazar para comprobar su correcto funcionamiento. La regla 2 no permite ningún tipo de tráfico con destino el propio firewall, a excepción si proviene desde el host mediante el servicio ssh. Por lo que se puede comprobar que deniega ese tipo de tráfico realizando un ping desde alguno de los clientes disponibles del escenario. En la siguiente figura se muestra el resultado: Figura 3.4-1: Ping desde C1 hacia FW La regla 4 no permite ningún tráfico saliente desde las máquinas situadas en LAN2 distinto de ICMP. Para comprobar el funcionamiento de ella es posible utilizar la herramienta iperf desde uno de los servidores web, e indicar la dirección de alguno de los clientes como dirección del servidor. Así, ejecutando el comando se indica que la red es inalcanzable: root@WWW1:~# iperf –c 10.1.1.11 connect failed: Network is unreachable Si se analiza el tráfico que se encuentra en la interfaz eth1 (10.1.2.11) del servidor web WWW1 se aprecia que desde el firewall se indica que el acceso a la red está prohibido, tal y como se indicó en la regla mediante la acción Reject: ICMP net prohibited. Figura 3.4-2: Captura de tráfico para comprobar la regla 4 del firewall 46 4. Conclusiones El trabajo se ha finalizado cumpliendo las expectativas iniciales, dejando un escenario didáctico que representa el concepto de centro de datos y computación en la nube. A lo largo de su desarrollo se han encontrado diferentes problemas relacionados fundamentalmente con la virtualización y la configuración de un controlador capaz de realizar la función de balanceador de carga satisfactoriamente en el escenario propuesto. Sin embargo, todo ello ha ayudado en el aprendizaje de diferentes conceptos, como el de las SDN. Durante la utilización de la herramienta VNX para la gestión del escenario virtual, se han notificado diferentes fallos y se han propuesto nuevas extensiones, como la conexión a Internet de las máquinas virtuales de un escenario, ayudando con ello al perfeccionamiento de la misma. A través de este trabajo, que se ha centrado en cuestiones prácticas partiendo del desarrollo de ideas, he aprendido que una primera propuesta a un problema no es siempre la correcta, y por ello es necesario buscar nuevas soluciones a todos los problemas que van surgiendo hasta encontrar una válida. En cuanto al apartado de Pruebas y resultados se han especificado algunas de las posibles pruebas que se pueden realizar en un escenario como el descrito con el objetivo de comprobar y asimilar conceptos a través de los resultados, pero se pueden efectuar muchas otras. Las líneas futuras de desarrollo que pueden partir de este trabajo son varias, ya que un escenario como el utilizado permite profundizar en diferentes aspectos de un centro de datos. A continuación se nombran algunas: La importancia que actualmente están teniendo las redes definidas por software en los grandes centros de datos es una línea de desarrollo para seguir investigando. De la misma forma que se ha implementado un balanceador de carga en un controlador SDN, es posible hacerlo con otras funciones, como puede ser un firewall. Además, en este trabajo solo se han estudiado dos tipos de controlador, por lo que ampliar el análisis podría añadir nuevas funcionalidades al escenario. La evaluación de alternativas a GlusterFS para sistemas de archivos distribuidos en un entorno de red de área local puede optimizar de la red y el uso de los servidores de disco. Una opción puede ser Ceph. La creación de una base de datos alojada en una nueva máquina virtual en el escenario puede permitir a la aplicación un control centralizado de los usuarios al almacenamiento de ficheros. Finalmente, mencionar que mediante la realización de este trabajo se han aplicado diferentes conocimientos adquiridos a lo largo de la carrera que permiten ser relacionados entre ellos y puestos en práctica en un escenario tan completo como el utilizado. 47 Bibliografía 1 Práctica final de Centro de Datos y Provisión de Servicios - E.T.S.I. Telecomunicación 2 Open vSwitch - Wikipedia (http://en.wikipedia.org/wiki/Open_vSwitch) 3 Portal de Virtual Networks over linuX (http://web.dit.upm.es/vnxwiki) 4 Información sobre LinuX Containers - Ubuntu Documentation (https://help.ubuntu.com/lts/serverguide/lxc.html) 5 Copy on write – Wikipedia (http://en.wikipedia.org/wiki/Copy-on-write) 6 Libvirt (http://libvirt.org/index.html) 7 Virtual Networking – WikiLibvirt (http://wiki.libvirt.org/page/VirtualNetworking) 8 GlusterFS – Gluster Community (http://www.gluster.org/about/) 9 Filesystem Administration Guide – Gluster Community (http://gluster.org/community/documentation/index.php/Gluster_3.2_Filesystem_Admi nistration_Guide) Setting up Storage Volumes – Red Hat Storage (Administration Guide) (https://access.redhat.com/site/documentation/enUS/Red_Hat_Storage/2.0/html/Administration_Guide/index.html) 10 11 Resumen sobre GlusterFS - Escuela Latinoamericana de Redes (http://www.eslared.org.ve/walc2012/material/track5/GlusterFS.pdf) 12 Sistema de archivos en el espacio de usuario (SAEU / FUSE) - Wikipedia (http://es.wikipedia.org/wiki/Sistema_de_archivos_en_el_espacio_de_usuario) 13 Comando mknod - Ubuntu Manuals (http://manpages.ubuntu.com/manpages/karmic/es/man1/mknod.1.html) 14 Fichero fstab - Wikipedia (http://es.wikipedia.org/wiki/Fstab) 15 Sotware Defined Networking - Wikipedia (http://en.wikipedia.org/wiki/Software-defined_networking) 49 16 Open Networking Foundation (https://www.opennetworking.org/about/onf-overview) 17 Floodlight Documentation (http://www.openflowhub.org/display/floodlightcontroller/Floodlight+Documentation) 18 Algoritmo Round Robin - Wikipedia (http://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin) 19 Firewall Builder (http://www.fwbuilder.org) 20 Uncomplicated Firewall - Ubuntu Wiki (https://wiki.ubuntu.com/UncomplicatedFirewall?action=show&redirect=UbuntuFire wall) 21 IPTables - Wikipedia (http://es.wikipedia.org/wiki/Netfilter/iptables) 22 Simple Network Management Protocol - Wikipedia (http://en.wikipedia.org/wiki/Simple_Network_Management_Protocol) 50 Apéndice A: Plantilla del escenario 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <?xml version="1.0" encoding="UTF-8"?> <!-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESARROLLO DE ESCENARIOS VIRTUALES PARA PRÁCTICAS DE LABORATORIO SOBRE ARQUITECTURAS DE SERVICIOS EN LA NUBE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Autor: Raúl Álvarez Pinilla Tutor: David Fernández Cambronero Departamento de Ingeniería de Sistemas Telemáticos (DIT) Universidad Politécnica de Madrid SPAIN --> <vnx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="/usr/share/xml/vnx/vnx-2.00.xsd"> <global> <version>2.0</version> <scenario_name>TFG:Arquitecturas_de_servicios_en_la_nube </scenario_name> <automac/> <vm_mgmt type="none" /> <vm_defaults> <console id="0" display="no"/> <console id="1" display="yes"/> <forwarding type="ip" /> </vm_defaults> </global> <net <net <net <net <net name="LAN1" mode="virtual_bridge" /> name="LAN2" mode="openvswitch" controller="tcp:10.1.4.2:6633" /> name="LAN3" mode="virtual_bridge" /> name="virbr0" mode="virtual_bridge" managed="no"/> name="MNG" mode="virtual_bridge" /> <vm name="C1" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-CLIENT </filesystem> <if id="1" net="LAN1"> <ipv4>10.1.1.11/24</ipv4> </if> <if id="99" net="virbr0"/> <route type="ipv4" gw="10.1.1.1">10.1.2.0/24</route> </vm> <vm name="C2" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-CLIENT </filesystem> <if id="1" net="LAN1"> <ipv4>10.1.1.12/24</ipv4> </if> <if id="99" net="virbr0"/> <route type="ipv4" gw="10.1.1.1">10.1.2.0/24</route> </vm> 51 Apéndicé A: Plantilla dél éscénario 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 <vm name="FW" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-FW </filesystem> <if id="1" net="LAN1"> <ipv4>10.1.1.1/24</ipv4> </if> <if id="2" net="LAN2"> <ipv4>10.1.2.1/24</ipv4> </if> <if id="99" net="virbr0"/> </vm> <vm name="CONTROLLER" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-CONTROLLER </filesystem> <if id="1" net="MNG"> <ipv4>10.1.4.2/24</ipv4> </if> <if id="99" net="virbr0"/> </vm> <vm name="WWW1" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-WWW </filesystem> <if id="1" net="LAN2"> <ipv4>10.1.2.11/24</ipv4> </if> <if id="2" net="LAN3"> <ipv4>10.1.3.11/24</ipv4> </if> <if id="99" net="virbr0"/> <route type="ipv4" gw="10.1.2.1">10.1.1.0/24</route> <exec seq="on_boot" type="verbatim" ostype="system">/etc/init.d/apache2 start</exec> </vm> <vm name="WWW2" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-WWW </filesystem> <if id="1" net="LAN2"> <ipv4>10.1.2.12/24</ipv4> </if> <if id="2" net="LAN3"> <ipv4>10.1.3.12/24</ipv4> </if> <if id="99" net="virbr0"/> <route type="ipv4" gw="10.1.2.1">10.1.1.0/24</route> <exec seq="on_boot" type="verbatim" ostype="system">/etc/init.d/apache2 start</exec> </vm> 52 Apéndicé A: Plantilla dél éscénario 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 <vm name="WWW3" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-WWW </filesystem> <if id="1" net="LAN2"> <ipv4>10.1.2.13/24</ipv4> </if> <if id="2" net="LAN3"> <ipv4>10.1.3.13/24</ipv4> </if> <if id="99" net="virbr0"/> <route type="ipv4" gw="10.1.2.1">10.1.1.0/24</route> <exec seq="on_boot" type="verbatim" ostype="system">/etc/init.d/apache2 start</exec> </vm> <vm name="NAS1" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-NAS </filesystem> <if id="1" net="LAN3"> <ipv4>10.1.3.21/24</ipv4> </if> <if id="99" net="virbr0"/> </vm> <vm name="NAS2" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-NAS </filesystem> <if id="1" net="LAN3"> <ipv4>10.1.3.22/24</ipv4> </if> <if id="99" net="virbr0"/> </vm> <vm name="NAS3" type="lxc"> <filesystem type="cow"> /usr/share/vnx/filesystems/rootfs_lxc_ubuntu-NAS </filesystem> <if id="1" net="LAN3"> <ipv4>10.1.3.23/24</ipv4> </if> <if id="99" net="virbr0"/> </vm> <host> <hostif net="LAN1"> <ipv4>10.1.1.10/24</ipv4> </hostif> <hostif net="MNG"> <ipv4>10.1.4.1/24</ipv4> </hostif> <route type="ipv4" gw="10.1.1.1">10.1.0.0/16</route> </host> </vnx> 53 Apéndice B: Scripts del sistema de ficheros Mediante los siguientes scripts se pretende aclarar el proceso de configuración del sistema de ficheros, y de esta forma proporcionar una guía a seguir. B.1. Script para la creación del sistema de ficheros El siguiente script pretende automatizar el proceso de configuración en los servidores de disco para la creación de un cierto volumen. Se permitirá al usuario elegir entre un volumen distribuido, en réplica, o seccionado. Además, se dará la opción de eliminar un volumen ya creado. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #!/bin/bash # Definición de funciones function anadirServidores(){ lxc-attach -n NAS2 -- bash -c "echo UUID=361fbfb4-fa61-49d1-90961b8a481476b6 > /etc/glusterd/glusterd.info" lxc-attach -n NAS3 -- bash -c "echo UUID=6763582b-7fc7-4767a7d7e289709c0ba7 > /etc/glusterd/glusterd.info" lxc-attach -n NAS2 -- service glusterfs-server restart lxc-attach -n NAS3 -- service glusterfs-server restart sleep 2 lxc-attach -n NAS1 -- gluster peer probe 10.1.3.22 lxc-attach -n NAS1 -- gluster peer probe 10.1.3.23 echo lxc-attach -n NAS1 -- gluster peer status echo } function compruebaVolumen(){ com=$( lxc-attach -n NAS1 -- gluster volume info | grep "No volumes present" ) if [ "$com" ] then echo "No hay ningún volumen creado" else echo "Hay algún volumen creado" echo "Elimínelo e inténtelo de nuevo" exit 0 fi } function iniciarVolumen(){ lxc-attach -n NAS1 -- gluster volume start nas lxc-attach -n NAS1 -- gluster volume info } function eliminarVolumen(){ lxc-attach -n NAS1 -- bash -c "gluster volume stop nas" lxc-attach -n NAS1 -- bash -c "gluster volume delete nas" } 55 Apéndicé B: Scripts dél sistéma dé fichéros 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #Programa principal clear echo "CONFIGURACIÓN DE LOS SERVIDORES DE DISCO" echo "Seleccione la opción a realizar:" echo "1 - Crear volumen" echo "2 - Eliminar volumen" echo -n "Opción seleccionada: " read opcion clear case $opcion in "1") echo "CREACION DEL VOLUMEN" compruebaVolumen echo "Seleccione el tipo de volumen deseado:" echo "1 - Volumen distribuido" echo "2 - Volumen en réplica" echo "3 - Volumen seccionado" echo -n "Opción seleccionada: " read tipo clear case $tipo in "1") echo "CREACION DE VOLUMEN DISTRIBUIDO" anadirServidores lxc-attach -n NAS1 -- gluster volume create nas 10.1.3.21:/nas 10.1.3.22:/nas 10.1.3.23:/nas iniciarVolumen ;; "2") echo "CREACION DE VOLUMEN EN REPLICA" anadirServidores lxc-attach -n NAS1 -- gluster volume create nas replica 3 10.1.3.21:/nas 10.1.3.22:/nas 10.1.3.23:/nas iniciarVolumen ;; "3") echo "CREACION DE VOLUMEN SECCIONADO" anadirServidores lxc-attach -n NAS1 -- gluster volume create nas stripe 3 10.1.3.21:/nas 10.1.3.22:/nas 10.1.3.23:/nas iniciarVolumen ;; esac ;; 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 "2") echo "ELIMINACION DEL VOLUMEN" eliminarVolumen ;; esac 56 Apéndicé B: Scripts dél sistéma dé fichéros B.2. Script para el montaje del sistema de ficheros Con la ejecución de este script se pretende automatizar el proceso de montaje del sistema de ficheros que hay que realizar desde los servidores web. Se permitirá al usuario la opción de montar el sistema de ficheros como de desmontarlo. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #!/bin/bash # Definición de funciones function creaFstab(){ echo -e "# UNCONFIGURED FSTAB FOR BASE SYSTEM /etc/glusterfs/datastore.vol /mnt/nas glusterfs rw,allow_other,default_permissions,max_read=131072 0 0" > /tmp/fstab } function creaDatastore(){ echo "volume remote1 type protocol/client option transport-type tcp option remote-host 10.1.3.21 option remote-subvolume /nas end-volume volume remote2 type protocol/client option transport-type tcp option remote-host 10.1.3.22 option remote-subvolume /nas end-volume volume remote3 type protocol/client option transport-type tcp option remote-host 10.1.3.23 option remote-subvolume /nas end-volume volume replicate type cluster/replicate subvolumes remote1 remote2 remote3 end-volume volume writebehind type performance/write-behind option window-size 1MB subvolumes replicate end-volume volume cache type performance/io-cache option cache-size 512MB subvolumes writebehind end-volume" > /tmp/datastore.vol } 57 Apéndicé B: Scripts dél sistéma dé fichéros 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 function copiaFstab(){ cp /tmp/fstab /var/lib/lxc/WWW1/rootfs/etc cp /tmp/fstab /var/lib/lxc/WWW2/rootfs/etc cp /tmp/fstab /var/lib/lxc/WWW3/rootfs/etc } function copiaDatastore(){ cp /tmp/datastore.vol /var/lib/lxc/WWW1/rootfs/etc/glusterfs cp /tmp/datastore.vol /var/lib/lxc/WWW2/rootfs/etc/glusterfs cp /tmp/datastore.vol /var/lib/lxc/WWW3/rootfs/etc/glusterfs } function compruebaNAS(){ com=$( lxc-attach -n NAS1 -- gluster volume info | grep "No volumes present" ) if [ "$com" ] then echo "No hay ningún volumen creado" echo "Cree un nuevo volumen e inténtelo de nuevo" exit 0 fi } function compruebaMontaje(){ com=$( lxc-attach -n WWW1 -- df -h | grep "datastore.vol" ) if [ "$com" ] then echo "Ya se encuentra el sistema de ficheros montado" exit 0 fi } function creaDirectorios(){ carpeta1=/var/lib/lxc/WWW1/rootfs/mnt/nas carpeta2=/var/lib/lxc/WWW2/rootfs/mnt/nas carpeta3=/var/lib/lxc/WWW3/rootfs/mnt/nas if [ ! -d $carpeta1 ] then mkdir $carpeta1 fi if [ ! -d $carpeta2 ] then mkdir $carpeta2 fi if [ ! -d $carpeta3 ] then mkdir $carpeta3 fi } function compruebaFUSE(){ com1=$( lxc-attach -n WWW1 -- ls /dev | grep "fuse" ) if [ "$com1" ] then echo "Módulo FUSE ya instalado en WWW1" else echo "Instalando módulo FUSE en WWW1..." lxc-attach -n WWW1 -- mknod -m 666 /dev/fuse c 10 229 fi 58 Apéndicé B: Scripts dél sistéma dé fichéros 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 com2=$( lxc-attach -n WWW2 -- ls /dev | grep "fuse" ) if [ "$com2" ] then echo "Módulo FUSE ya instalado en WWW2" else echo "Instalando módulo FUSE en WWW2..." lxc-attach -n WWW2 -- mknod -m 666 /dev/fuse c 10 229 fi com3=$( lxc-attach -n WWW3 -- ls /dev | grep "fuse" ) if [ "$com3" ] then echo "Módulo FUSE ya instalado en WWW3" else echo "Instalando módulo FUSE en WWW3..." lxc-attach -n WWW3 -- mknod -m 666 /dev/fuse c 10 229 fi } function asignaPermisos(){ lxc-attach -n WWW1 -- chmod lxc-attach -n WWW2 -- chmod lxc-attach -n WWW3 -- chmod lxc-attach -n WWW1 -- chmod lxc-attach -n WWW2 -- chmod lxc-attach -n WWW3 -- chmod 777 777 777 777 777 777 /mnt/nas /mnt/nas /mnt/nas /tmp /tmp /tmp } #Programa principal clear echo "MONTAR/DESMONTAR EL SISTEMA DE FICHEROS" echo "Seleccione la opción a realizar:" echo "1 - Montar sistema de ficheros" echo "2 - Desmontar sistema de ficheros" echo -n "Opción seleccionada: " read opcion clear case $opcion in "1") echo "MONTAJE DEL SISTEMA DE FICHEROS" compruebaNAS compruebaMontaje creaFstab creaDatastore copiaFstab copiaDatastore creaDirectorios compruebaFUSE lxc-attach -n WWW1 -- mount -a lxc-attach -n WWW2 -- mount -a lxc-attach -n WWW3 -- mount -a echo "Sistema de ficheros montado correctamente" ;; 59 Apéndicé B: Scripts dél sistéma dé fichéros 165 166 167 168 169 170 171 172 "2") echo "DESMONTAJE DEL SISTEMA DE FICHEROS" lxc-attach -n WWW1 -- umount -l /mnt/nas lxc-attach -n WWW2 -- umount -l /mnt/nas lxc-attach -n WWW3 -- umount -l /mnt/nas echo "Sistema de ficheros desmontado correctamente" ;; esac 60 Apéndice C: Código de la Aplicación Web A continuación se muestran los diferentes archivos que han sido creados para la Aplicación Web del centro de datos. index.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~ Servidor Web X (10.1.2.1X) ~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> <html> <head> <title>Almacenamiento de ficheros</title> </head> <frameset rows="86,*,45z" frameborder="0" border="0" framespacing="0"> <frame name="topNav" src="webTop_nav.html"> <frameset cols="200,*" frameborder="0" border="0" framespacing="0"> <frame name="menu" src="webMenu.html" marginheight="0" marginwidth="0" scrolling="auto" noresize> <frame name="content" src="webContent.html" marginheight="0" marginwidth="0" scrolling="auto" noresize> </frameset> <frame name="footer" src="webFooter.html"> </frameset> </html> webTop_nav.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <html> <head> <meta charset="utf-8"> <title>Top Nav</title> <style type="text/css"> body { font-family:verdana,arial,sans-serif; font-size:14.2pt; margin:30px; background-color:#a08029;} </style> </head> <body> <h3>Desarrollo de Escenarios Virtuales para Prácticas de Laboratorio sobre Arquitecturas de Servicios en la Nube</h3> </body> </html> 61 Apéndicé C: Codigo dé la Aplicacion Wéb webMenu..html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <html> <head> <title>Menu</title> <style type="text/css"> body { font-family:verdana,arial,sans-serif; font-size:10pt; margin:15px; background-color:#ff9900;} </style> </head> <body> <p><a href="webContent.html" target="content">INICIO</a></p> <p><a href="pagSubida.php" target="content">Subida de ficheros</a></p> <p><a href="pagDescarga.php" target="content">Descarga de ficheros</a></p> <p><a href="pagBorrado.php" target="content">Borrado de ficheros</a></p> </body> </html> webContent.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <html> <head> <meta charset="utf-8"> <title>Content</title> <style type="text/css"> body { font-family:verdana,arial,sans-serif; font-size:10pt; margin:30px; background-color:#ffcc00;} </style> </head> <body> <h1>Bienvenido</h1> <h2>Desde esta página web podrá realizar el almacenamiento de ficheros</h2> <ul> <li><a href="pagSubida.php" target="content">Subida de ficheros</a></li><p/> <li><a href="pagDescarga.php" target="content">Descarga de ficheros</a></li><p/> <li><a href="pagBorrado.php" target="content">Borrado de ficheros</a></li> </ul> </body> </html> 62 Apéndicé C: Codigo dé la Aplicacion Wéb webFooter.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <html> <head> <meta charset="utf-8"> <title>Footer</title> <style type="text/css"> body { font-family:verdana,arial,sans-serif; font-size:10pt; margin:10px; text-align: right; background-color:black; color:white;} </style> </head> <body> <table width="100%"> <tr> <td align="left"><strong>Raúl Álvarez Pinilla</strong></td> <td align="right"><strong>Escuela Técnica Superior de Ingenieros de Telecomunicación (UPM)</strong></td> </tr> </table> </body> </html> 63 Apéndicé C: Codigo dé la Aplicacion Wéb pagSubida.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <html> <head> <title>Subida</title> <style type="text/css"> body { font-family:verdana,arial,sans-serif; font-size:10pt; margin:30px; background-color:#a1f861;} </style> <script type="text/javascript" src="funciones.js"></script> </head> <body> <h1>Subida de ficheros</h1> <ol> <li value="1"> <span><input id="archivos" type="file" name="archivos[]" multiple="multiple"/></span><p/> </li> <li> <button onclick="subido();"/>Subir</button> </li> </ol> </body> </html> scriptSubir.php 1 2 3 4 5 6 7 8 9 10 11 12 <?php $ruta="/mnt/nas/"; foreach($_FILES as $key) { if($key["error"]==UPLOAD_ERR_OK){ move_uploaded_file($key["tmp_name"],$ruta.$key["name"]); echo "Subida realizada correctamente\n"; }else{ echo $key["Error en la subida"]; } } ?> 64 Apéndicé C: Codigo dé la Aplicacion Wéb pagDescarga.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <html> <head> <title>Descarga</title> <style type="text/css"> body { font-family:verdana,arial,sans-serif; font-size:10pt; margin:30px; background-color:#58FAD0;} </style> <script type="text/javascript" src="funciones.js"></script> </head> <body> <h1>Descarga de ficheros</h1> <?php $ruta="/mnt/nas/"; $archivos=scandir($ruta); $lista=""; foreach($archivos as $value){ if($value!="."&&$value!=".."){ $lista.= '<form action="javascript:getFile(\''.$value.'\');"> <input type="submit" value="Descargar archivo =>"><a>'.$value.'</a> </form><p/>'; } } echo $lista; ?> </body> </html> scriptBajar.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php $ruta="/mnt/nas/"; $name=$_GET["file"]; $archivo=$ruta.$name; if(file_exists($archivo)){ header("Content-Description: File transfer"); header("Content-Type: application/octect-stream"); header("Content-Disposition: attachment; filename=".basename($archivo)); header("Content-Transfer-Encoding: binary"); header("Expires: 0"); header("Cache-Control: must-revalidate"); header("Pragma: public"); ob_clean(); flush(); readfile($archivo); exit; } ?> 65 Apéndicé C: Codigo dé la Aplicacion Wéb pagBorrado.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <html> <head> <title>Borrado</title> <style type="text/css"> body { font-family:verdana,arial,sans-serif; font-size:10pt; margin:30px; background-color:#F5A9A9;} </style> <script type="text/javascript" src="funciones.js"></script> </head> <body> <h1>Borrado de ficheros</h1> <?php $ruta="/mnt/nas/"; $archivos=scandir($ruta); $lista=""; foreach($archivos as $value){ if($value!="."&&$value!=".."){ $lista.= '<form action="javascript:deleteFile(\''.$value.'\');"> <input type="submit" value="Borrar archivo =>"><a>'.$value.'</a> </form><p/>'; } } echo $lista; ?> </body> </html> scriptBorrar.php 1 2 3 4 5 <?php $ruta="/mnt/nas/"; unlink($ruta.$_POST["file"]); echo $_POST["file"]." ha sido borrado"; ?> 66 Apéndicé C: Codigo dé la Aplicacion Wéb funciones.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 //SUBIDA DE FICHEROS function subido(){ var archivo =document.getElementById("archivos").files; if(archivo.length==0){ alert("No se ha subido ningún fichero"); return; } createFile(archivo); } function createFile(archivo){ var xhr=new XMLHttpRequest(); var data=new FormData(); for (var i=0; i<archivo.length; i++){ data.append("archivo"+i,archivo[i]); } xhr.open("POST", "scriptSubir.php", true); xhr.onreadystatechange= function(){ if(xhr.readyState!=4){ return; } if(xhr.status==200){ alert(xhr.responseText); location.href="pagDescarga.php"; } }; xhr.send(data); } //DESCARGA DE FICHEROS function getFile(file){ location.href="scriptBajar.php?file="+file; } //BORRADO DE FICHEROS function deleteFile(file){ var xhr=new XMLHttpRequest(); var data=new FormData(); data.append("file",file); xhr.open("POST", "scriptBorrar.php", true); xhr.onreadystatechange= function(){ if(xhr.readyState!=4){ return; } if(xhr.status==200){ alert(xhr.responseText); location.href="pagBorrado.php"; } } xhr.send(data); } 67 68 Apéndice D: Balanceador de carga (Controlador POX) El fichero pox/misc/ip_loadbalancer.py es el encargado de la función de balanceador de carga del escenario. Viene por defecto tras la instalación del controlador pero es necesario realizar diversos cambios para el correcto funcionamiento en el escenario. A continuación se muestra su contenido: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 # # # # # # # # # # # # # Copyright 2013 James McCauley Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ A very sloppy IP load balancer. Run it with --ip=<Service IP> --servers=IP1,IP2,... Please submit improvements. :) """ from pox.core import core import pox log = core.getLogger("iplb") from from from from from pox.lib.packet.ethernet import ethernet, ETHER_BROADCAST pox.lib.packet.ipv4 import ipv4 pox.lib.packet.arp import arp pox.lib.addresses import IPAddr, EthAddr pox.lib.util import str_to_bool, dpid_to_str import pox.openflow.libopenflow_01 as of import time import random FLOW_IDLE_TIMEOUT = 5 FLOW_MEMORY_TIMEOUT = 60 * 5 selected_server=0 class MemoryEntry (object): """ Record for flows we are balancing 69 Apéndicé D: Balancéador dé carga (Controlador POX) 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 Table entries in the switch "remember" flows for a period of time, but rather than set their expirations to some long value (potentially leading to lots of rules for dead connections), we let them expire from the switch relatively quickly and remember them here in the controller for longer. Another tactic would be to increase the timeouts on the switch and use the Nicira extension which can match packets with FIN set to remove them when the connection closes. """ def __init__ (self, server, first_packet, client_port): self.server = server self.first_packet = first_packet self.client_port = client_port self.refresh() def refresh (self): self.timeout = time.time() + FLOW_MEMORY_TIMEOUT @property def is_expired (self): return time.time() > self.timeout @property def key1 (self): ethp = self.first_packet ipp = ethp.find('ipv4') tcpp = ethp.find('tcp') return ipp.srcip,ipp.dstip,tcpp.srcport,tcpp.dstport @property def key2 (self): ethp = self.first_packet ipp = ethp.find('ipv4') tcpp = ethp.find('tcp') return self.server,ipp.srcip,tcpp.dstport,tcpp.srcport class iplb (object): """ A simple IP load balancer Give it a service_ip and a list of server IP addresses. New TCP flows to service_ip will be randomly redirected to one of the servers. We probe the servers to see if they're alive by sending them ARPs. """ def __init__ (self, connection, service_ip, servers = []): self.service_ip = IPAddr(service_ip) self.servers = [IPAddr(a) for a in servers] self.con = connection #self.mac = self.con.eth_addr self.mac = EthAddr("00:00:00:11:22:33") self.live_servers = {} # IP -> MAC,port 70 Apéndicé D: Balancéador dé carga (Controlador POX) 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 try: self.log = log.getChild(dpid_to_str(self.con.dpid)) except: # Be nice to Python 2.6 (ugh) self.log = log self.outstanding_probes = {} # IP -> expire_time # How quickly do we probe? self.probe_cycle_time = 5 # How long do we wait for an ARP reply before we consider a server dead? self.arp_timeout = 3 # We remember where we directed flows so that if they start up again, # we can send them to the same server if it's still up. Alternate # approach: hashing. self.memory = {} # (srcip,dstip,srcport,dstport) -> MemoryEntry self._do_probe() # Kick off the probing # As part of a gross hack, we now do this from elsewhere #self.con.addListeners(self) def _do_expire (self): """ Expire probes and "memorized" flows Each of these should only have a limited lifetime. """ t = time.time() # Expire probes for ip,expire_at in self.outstanding_probes.items(): if t > expire_at: self.outstanding_probes.pop(ip, None) if ip in self.live_servers: self.log.warn("Server %s down", ip) del self.live_servers[ip] # Expire old flows c = len(self.memory) self.memory = {k:v for k,v in self.memory.items() if not v.is_expired} if len(self.memory) != c: self.log.debug("Expired %i flows", c-len(self.memory)) def _do_probe (self): """ Send an ARP to a server to see if it's still up """ self._do_expire() server = self.servers.pop(0) self.servers.append(server) 71 Apéndicé D: Balancéador dé carga (Controlador POX) 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 r = arp() r.hwtype = r.HW_TYPE_ETHERNET r.prototype = r.PROTO_TYPE_IP r.opcode = r.REQUEST r.hwdst = ETHER_BROADCAST r.protodst = server r.hwsrc = self.mac r.protosrc = self.service_ip e = ethernet(type=ethernet.ARP_TYPE, src=self.mac, dst=ETHER_BROADCAST) e.set_payload(r) self.log.debug("ARPing for %s", server) msg = of.ofp_packet_out() msg.data = e.pack() msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD)) msg.in_port = of.OFPP_NONE self.con.send(msg) self.outstanding_probes[server] = time.time() + self.arp_timeout core.callDelayed(self._probe_wait_time, self._do_probe) @property def _probe_wait_time (self): """ Time to wait between probes """ r = self.probe_cycle_time / float(len(self.servers)) r = max(.25, r) # Cap it at four per second return r def _pick_server (self, key, inport): """ Pick a server for a (hopefully) new connection, round robin based """ global selected_server a=self.live_servers.keys() if selected_server<=-(len(self.live_servers)): selected_server=0 #print selected_server, len(self.live_servers) b=a[selected_server] selected_server-=1 return b #return random.choice(self.live_servers.keys()) def _handle_PacketIn (self, event): inport = event.port packet = event.parsed def drop (): if event.ofp.buffer_id is not None: # Kill the buffer msg = of.ofp_packet_out(data = event.ofp) self.con.send(msg) return None tcpp = packet.find('tcp') 72 Apéndicé D: Balancéador dé carga (Controlador POX) 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 if not tcpp: arpp = packet.find('arp') if arpp: # Handle replies to our server-liveness probes if arpp.opcode == arpp.REPLY: if arpp.protosrc in self.outstanding_probes: # A server is (still?) up; cool. del self.outstanding_probes[arpp.protosrc] if (self.live_servers.get(arpp.protosrc, (None,None)) == (arpp.hwsrc,inport)): # Ah, nothing new here. pass else: # Ooh, new server. self.live_servers[arpp.protosrc] = arpp.hwsrc,inport self.log.info("Server %s up", arpp.protosrc) return # Not TCP and not ARP. return drop() Don't know what to do with this. Drop it. # It's TCP. ipp = packet.find('ipv4') if ipp.srcip in self.servers: # It's FROM one of our balanced servers. # Rewrite it BACK to the client key = ipp.srcip,ipp.dstip,tcpp.srcport,tcpp.dstport entry = self.memory.get(key) if entry is None: # We either didn't install it, or we forgot about it. self.log.debug("No client for %s", key) return drop() # Refresh time timeout and reinstall. entry.refresh() #self.log.debug("Install reverse flow for %s", key) # Install reverse table entry mac,port = self.live_servers[entry.server] actions = [] actions.append(of.ofp_action_dl_addr.set_src(self.mac)) actions.append(of.ofp_action_nw_addr.set_src(self.service_ip)) actions.append(of.ofp_action_output(port = entry.client_port)) match = of.ofp_match.from_packet(packet, inport) msg = of.ofp_flow_mod(command=of.OFPFC_ADD, idle_timeout=FLOW_IDLE_TIMEOUT, hard_timeout=of.OFP_FLOW_PERMANENT, data=event.ofp, actions=actions, match=match) self.con.send(msg) 73 Apéndicé D: Balancéador dé carga (Controlador POX) 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 elif ipp.dstip == self.service_ip: # Ah, it's for our service IP and needs to be load balanced # Do we already know this flow? key = ipp.srcip,ipp.dstip,tcpp.srcport,tcpp.dstport entry = self.memory.get(key) if entry is None or entry.server not in self.live_servers: # Don't know it (hopefully it's new!) if len(self.live_servers) == 0: self.log.warn("No servers!") return drop() # Pick a server for this flow server = self._pick_server(key, inport) self.log.info("Directing from %s (%s) to %s (%s)", ipp.srcip,tcpp.srcport,server,tcpp.dstport) entry = MemoryEntry(server, packet, inport) self.memory[entry.key1] = entry self.memory[entry.key2] = entry # Update timestamp entry.refresh() # Set up table entry towards selected server mac,port = self.live_servers[entry.server] actions = [] actions.append(of.ofp_action_dl_addr.set_dst(mac)) actions.append(of.ofp_action_nw_addr.set_dst(entry.server)) actions.append(of.ofp_action_output(port = port)) match = of.ofp_match.from_packet(packet, inport) msg = of.ofp_flow_mod(command=of.OFPFC_ADD, idle_timeout=FLOW_IDLE_TIMEOUT, hard_timeout=of.OFP_FLOW_PERMANENT, data=event.ofp, actions=actions, match=match) self.con.send(msg) # Remember which DPID we're operating on (first one to connect) _dpid = None def launch (ip, servers): servers = servers.replace(","," ").split() servers = [IPAddr(x) for x in servers] ip = IPAddr(ip) # Boot up ARP Responder from proto.arp_responder import launch as arp_launch arp_launch(eat_packets=False,**{str(ip):True}) import logging logging.getLogger("proto.arp_responder").setLevel(logging.WARN) def _handle_ConnectionUp (event): global _dpid 74 Apéndicé D: Balancéador dé carga (Controlador POX) 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 if _dpid is None: log.info("IP Load Balancer Ready.") core.registerNew(iplb, event.connection, IPAddr(ip), servers) _dpid = event.dpid if _dpid != event.dpid: log.warn("Ignoring switch %s", event.connection) else: log.info("Load Balancing on %s", event.connection) # Gross hack core.iplb.con = event.connection event.connection.addListeners(core.iplb) core.openflow.addListenerByName("ConnectionUp", _handle_ConnectionUp) 75
© Copyright 2024