sábado, 21 de abril de 2018

Usando Docker de manera práctica - Parte II

Hola, en esta nueva entrada vamos a seguir realizando ejemplos prácticos con Docker y profundizando en sus características, así como extendiendo los ejemplos que realizamos en la entrada anterior.

En el post anterior de esta serie, creamos un contenedor a partir de una imagen de Apache para tener un servidor web. Al hacerlo comprobamos como nuestro sistema descargaba la imagen de Docker Hub en caso de que no la tuviesemos ya, creaba el contenedor y lo ejecutaba.

También comprobamos que no podíamos acceder a este contenedor desde fuera del host que lo albergaba, pero si desde el propio host y como el contenedor si podía acceder al exterior.

Hoy vamos a continuar con este ejemplo y a explorar dos conceptos fundamentales para la implementación de nuestros servicios, la red y el almacenamiento.

Hasta aquí, lo que tenemos es un servidor web el cual es que no es accesible desde el exterior de nuestro host. Si queremos dar servicio a clientes, ¿que tenemos que hacer para que puedan acceder a la web publicada en nuestro servidor? La solución con docker es increiblemente sencilla ya que, lo único que debemos hacer, es crear nuestro contenedor estableciendo un mapeo de puertos con la opción -p para que los puertos expuestos definidos por la imagen, sean accesibles desde el host que ejecuta el contenedor.

¿Que es eso de los puertos expuestos definidos por la imagen? Como ya he comentado de forma muy resumida, nuestros contenedores hacen uso de imágenes que contienen el software que necesitamos ejecutar. Estas imágenes tienen unas características que podemos consultar con el docker inspect, el cual nos permitirá ver gran cantidad de información sobre cualquier imagen. Si usamos este comando con la imagen httpd que hemos utilizado para crear nuestro contenedor webserver, encontraremos una configuración como la siguiente: 

Comando docker inspect para consultar los puertos expuestos.
En la imagen anterior, justo al final, podemos ver una entrada que se denomina ExposedPorts que indica que cualquier contenedor creado usando esta imagen, expondrá a la red el puerto 80 para que se acceda al servicio. Como es lógico, al tratarse de una imagen que contiene el software de un servidor web, el puerto que expone para acceder al servicio es el puerto 80 y en general, cada servicio que implementemos podrá tener una serie de puertos expuestos, siempre en función del solftware que esté incluido en la imagen.

Por tanto, teniendo esto en cuenta, si ahora creamos un nuevo contenedor especificando que el puerto 80 debe estar mapeado al mismo puerto en nuestro host, tendremos un comando como el siguiente:

Contenedor con el puerto 80 publicado en red.
Ahora, desde cualquier host podremos acceder al servicio web dado por nuestro contenedor:

Acceso al servicio web del contenedor.
En general, cuando necesitemos publicar puertos de red de un contenedor o contenedores, usaremos siempre el comando siguiente a la hora de crearlos:

docker run -p HOSTPORT:CONTAINERPORT [OPCIONES]

De este modo, si por ejemplo ya tenemos otro servidor web escuchando en nuestro host en el puerto 80, podremos crear el contenedor especificando que el puerto 80 expuesto por el contenedor se publique en otro puerto diferente:

Cambiando el puerto publicado de un contenedor.
Si de nuevo probamos a acceder al host donde está corriendo nuestro contenedor, pero en este caso al puerto 8000, veremos de nuevo nuestra web disponible:

Acceso al servicio web del contenedor.

La opción -p permite unas cuantas variaciones que, en función de nuestras necesidades, nos permitirá publicar los puertos del siguiente modo:

  • -p Puerto_Contenedor, al especificarlo así se enlazará el puerto dado del contenedor con un puerto dinámico en todos los interfaces de red del host.
  • -p Puerto_Host:Puerto_Contenedor, este es el ejemplo que hemos utilizado, enlazamos el puerto del contenedor con el puertos especificado del host en todos los interfaces de red del host.
  • -p ip::Puerto_Contenedor, al especificarlo así se enlazará el puerto dado del contenedor con un puerto dinámico en el interfaz con la dirección IP especificada.
  • -p ip:Puerto_Host:Puerto_Contenedor, enlazamos el puerto dado del contenedor con el puerto específico del host en el interfaz con la dirección IP especificada.
Como es lógico podemos usar la opción -p varias veces con todos los puertos que sea necesario exponer desde el contenedor.

Os recomiendo revisar la documentación oficial de Docker, ya que hay más opciones relacionadas con el control y acceso a la red.

Ya sabemos como controlar el acceso a red de nuestros contenedores y continuando nuestro ejemplo, ya que tenemos un servidor web, lo siguiente es publicar nuestro propio contenido pero, ¿cómo podemos hacer esto? La respuesta a esta pregunta es mediante el uso de volúmenes.

La forma más sencilla de entender un volumen es como un punto de montaje en el host al cual nuestro contenedor tendrá acceso. De este modo, para nuestro servidor web, lo único que necesitamos es volver a crear el contenedor especificando el volumen o volúmenes a los que tendrá acceso. 

Por ejemplo, vamos a crear una página web muy simple y vamos a darle acceso de lectura al nuevo contenedor. Para esto solo tenemos que crear nuestro contenedor con la opción -v y la especificación de rutas a utilizar, por ejemplo, para nuestro servidor web sería algo como lo siguiente:

Creación de un contenedor con un volumen.
En este comando hemos expuesto el puerto 80 del contenedor en el puerto 80 del host y además, hemos añadido la opción -v indicándo que la ruta local /home/develop/HTML está disponible y accesible para el contenedor en la ruta /usr/local/apache2/htdocs con lo que, si lo hemos hecho todo bien, al acceder con un navegador web al puerto 80 de nuestro host veremos nuestra página web.

De esta manera tan sencilla los contenedores acceden a contenidos que queremos servir, como por ejmplo el contenido de un servicio web, conseguimos permanencia de los datos generados por clientes de nuestro servicio, como en el caso de un servicio de base de datos, etc...

Al usar volumenes es necesario tener en cuenta lo siguiente:
  • Un volumen puede ser compartido por varios contenedores. Evidentemente es importante tener en cuenta el tipo de acceso que se va a realizar ya que, si se realizan escrituras será necesaria considerar el uso de algún tippo de sistema de archivos de cluster como GFS2.
  • Al montar un volumen en una ruta de un contenedor, el contenido de esa ruta dentro del contenedor se sustituye por lo que tengamos en nuestra ruta.
  • En caso de especificar uan ruta dentro del contenedor que no existe, dicha ruta se creará para permitir el montaje de nuestro volumen.
Con el ejemplo anterior hemos dado acceso a un directorio de nuestro host a un contenedor. Imaginemos que debido a un bug, un intruso es capaz de acceder al contenedor y por tanto, a dicho directorio local en nuestro host. Para limitar el daño que podría hacer podemos especificar que el acceso a dicho volumen, se en modo solo lectura. Para esto solo tenemos que crear el contenedor con la opción -v añadiendo :ro al final, como en el siguiente comando:

Creación de contenedor con volumen de solo lectura.
De este modo tenemos nuestro servidor web accediendo a nuestro contenido, pero ahora solamente en modo lectura.

Vamos a comprobar este último punto y así revisar algunas de las opciones que podemos utilizar en línea de comandos y que, hasta ahora, hemos venido usando.

Hasta ahora, en todos los comandos hemos utilizado la opción -d, la cual le dice a docker que queremos crear o arrancar un cotenendor sin tener acceso a sus salidas estándar stdout, haciendo así que se ejecute en background. Como ejemplo, si creamos un nuevo contenedor como nuestro servidor web, sin usar la opción -d veremos lo siguiente:

Contenedor corriendo en primer plano.
Al ejecutarse así veremos en consola toda la salida que los procesos del contenedor estén enviando a stderr y stdout y nos desconectaremos parando el contenedor, pulsando CTRL+C.

Ahora, para comprobar como hemos dicho, que nuestro volumen está montado en modo solo lectura, vamos a lanzar un comando en nuestro contenedor para intentar crear un fichero en dicha ruta. Para esto solo debemos usar el subcomando exec:

Volumen de solo lectura.
De este modo nos aseguramos de proteger nuestro hoost local y deberíamos tomar como buena práctica que los contenedores solo tengan acceso de escritura a aquellos volúmenes donde realmente necesiten escribir.

Hasta aquí la segunda parte de las prácticas de Docker, en breve la siguiente en la que intentaremos relacionar cotenedores y describir servicios.

lunes, 16 de abril de 2018

Backups con SnapManager para Exchange

Hola de nuevo, hoy voy a explorar las características de Snap Manager para Exchange, el cual acabo de implementar para poder realizar los backups de nuestra infraestructura de Exchange.

Snap Manager para Exchange es una aplicación de NetApp que dentro de su familia de aplicaciones Snap Manager, se integra con sus sistemas de almacenamiento y Microsoft Exchange para poder hacer backups de BBDD de Exchange mediante snapshots del almacenamiento donde residan las BBDD de buzones.

Este software se comunica directamente con Exchange a través de su API consiguiendo realizar backups consistentes de las BBDD de buzones así como de los logs de transacciones de Exchange. Así mismo, gracias a esta integración, Exchange truncará los logs de transacciones ya aplicados y de los que se ha realizado el backup, liberando así espacio en las LUNs de logs de las BBDD de buzones.

¿Que ventajas tengo al usar una aplicación como esta?
  • Velocidad a la hora de realizar backups. Al ser un backup a disco basado en la capacidad de realizar snapshots, el backup es mucho más rápido.
  • Velocidad a la hora de realizar restores. Del mismo modo, cualquier restauración es muchísimo más rápida.
Como es lógico estas son las dos ventajas fundamentales, pero adicionalmente disponemos de las siguientes ventajas derivadas de usar un sistema NetApp:
  • Optimización del uso del almacenamiento. Fundamentalmente tenemos un ahorro de almacenamiento conseguido gracias a la deduplicación del dato. Almacenando varias LUNs en el mismo volumen conseguiremos una reducción del espacio utilizado.
  • Protección de la información. Ya que estamos usando cabinas NetApp y snapshots ¿porque no transferir esos snapshots a otra SVM y mantenerlos con SnapVault? Igualmente, mediante una relación de SnapMirror podremos tener una réplica para nuestra política de DR.
Este último punto, que es el que nos ha costado más hacer funcionar, se integra directamente con ONTAP cluster, de tal manera que configurando el backup con la opción de archivado, lanzará automáticamente la relación de snapmirror o snapvault del almacenamiento primario al secundario.

Por tanto, si necesitas hacer backups rápidos de Exchange e implementar políticas de protección sobre ellos de forma rápida y sencilla, esta es una opción a tener muy en cuenta.

miércoles, 11 de abril de 2018

Cluster ONTAP - Parte II

Hola de nuevo, revisando las entradas sobre cluster ONTAP me he dado cuenta que hace infinito que no escribo nada y hemos hecho muchos cambios en el último año.

En aquel momento acabábamos de empezar la migración de nuestras controladoras, que por aquel entonces estaban en 7-Mode, a la versión 8.3.2 de cluster ONTAP, migración que realizamos satisfactoriamente usando la herramienta 7-Mode Transition Tool de NetApp.

Recientemente hemos realizado el último paso que nos faltaba, la conversión de un cluster switchless a switched, así que voy a explicar un poco las diferencias entre 7-Mode y cluster ONTAP a nivel hardware.

Para empezar, como siempre digo, recomiendo visitar la página web de NetApp en la cual podréis encontrar información más precisa y explicaciones mucho mejores que las mías.

Antes de cluster ONTAP, las controladoras se instalaban en parejas aisladas cuando queríamos disponer de alta disponibilidad. Con ONTAP 7-Mode, las controladoras se instalaban formando parejas. En una pareja, las dos controladoras se interconectaban entre sí para comunicarse enre ellas. Esta conexión podía realizarse internamente, cuando ambas estaban en un mismo chasis, o externamente cuando estaban separadas. Esta interconexión entre controladoras, llamada HA interconnect, nos permite forrmar lo que se denomina una pareja HA.

Cada controladora podía estar conectada a una o más stacks de bandejas de discos de las que era propietaria, asignándose dicha propiedad por software y para asegurar la máxima disponibilidad, también se conectaban a la controladora partner que formaba la pareja. Esta interconexion podemos verla así:
Conexiones básicas pareja HA.

A nivel software, cada controladora disponía de su servidor NFS y CIFS, además de proporcionar servicios FCP e iSCSI. Por tanto cada controladora de una pareja HA podía servir datos simultaneamente y ya dependía de nuestras necesidades, como repartir la carga y los servicios.

Con la nueva versión cluster de ONTAP todo esto ha cambiado sustancialmente. Ahora a nivel hardware, podemos tener varias parejas interconectadas entre sí formando un cluster. El concepto de parejas de controladoras se mantiene y es el bloque fundamental de construcción de los nuevos clusters, los cuales, en función del número de parejas que los formen pueden ser switchless cluster, en los cuales solo tenemos una pareja de controladoras interconectadas entre sí, además de mediante la conexión HA interconnect mediante una red de cluster, o switched cluster, en la cual dos o más parejas se interconectan entre sí mediante una red de cluster dedicada. Ambos casos podemos verlos más o menos del siguiente modo:
Switchless ONTAP cluster.








Switched ONTAP cluster.

Viendo estas imágenes está claro que la idea fundamental de cluster ONTAP es la escalabilidad del servicio de almacenamiento.

Por tanto, desde el punto de vista hardware, podríamos decir que mediante la red de cluster podemos interconectar parejas HA para conseguir más rendimiento y puertos de acceso, escalando horizontalmente nuestro sistema de almacenamiento. Así mismo, al conectar bandejas adicionales a cada pareja HA, añadiremos almacenamiento al sistema y por tanto escaleremos el cluster verticalmente añadiendo más capacidad.

Hasta aquí el resumen de las diferencias hadware. En los próximos posts intentaré explicar un poco las diferencias software y el modo de operación básico.

viernes, 6 de abril de 2018

Usando Docker de manera práctica - Parte I

Hola de nuevo, en los posts anteriores sobre Docker he repasado un poco la teoría de operación de Docker y, de una manera muy básica, he realizado una introducción a ciertas características. Para poder profundizar un poco más en Docker y su funcionamiento vamos a ver unos cuantos casos prácticos.

Para empezar lo fundamental es instalar Docker. Esto podemos hacerlo de una manera muy sencilla con solo descargar el paquete correspondiente para nuestra distribución Linux. Por ejemplo, en sistemas como CentOS:
Instalación del motor de Docker.

con lo que nuestro motor de Docker ya estaría listo y disponible en nuestro sistema para empezar a usarlo.

Una vez instalado, el comando que vamos a utilizar para todo es docker, el cual interactua con el demonio docker que ahora estará arrancado en nuestro sistema.

El primer comando que vamos a utilizar, para comprobar que la instalación se ha realizado correctamente, nos dará la versión de Docker que estamos usando:

Comprobando la versión de Docker,.

Bien, una vez que tenemos nuestro motor de Docker instalado y funcionando correctamente vamos a realizar un ejemplo básico, pero en este caso no vamos a crear un contenedor que nos diga Hola mundo, sino vamos a hacer algo un poco más interesante, como montar con un solo comando un servidor web Apache.

Como ya expliqué, el motor de Docker permite ejecutar aplicaciones dentro de un entorno aislado a partir de una imagen que contendrá todo el software que dicha aplicación necesita. Ahora bien, ¿de donde salen esas imágenes? Al igual que las diferentes distribuciones de Linux tienen repositorios con paquetes de software, Docker dispone de un repositorio público que contiene miles de imágenes que podemos descargar y utilizar para crear nuestros contenedores. Puedes consultar dicho repositorio en la URL https://hub.docker.com/ previo registro, el cual es absolutamente gratuito. Este registro en Docker Hub nos permitirá, más adelante, subir nuestras imágenes y hacerlas públicas si así lo deseamos.

Al igual que nuestro gestor de paquetes favorito nos permite buscar software por su nombre, el comando docker dispone de un subcomando search el cual, salvo que especifiquemos otro repositorio, buscará siempre en Docker Hub. Como para estas operaciones no es necesario que tengamos un usuario registrado, vamos a buscar una imagen para instalar nuestro servidor Apache:

Busqueda de imágenes de Apache en Docker Hub.
Como véis aparecen muchos resultados ya que, al buscar una cadena con el comando docker search, este realizará la búsuqeda tnato el nombre de la imagen como en la descripción de la misma. Como se vé en la salida, las imágenes tienen valoraciones con estrellas y además, en algunas se indica que son oficiales. Más adelante intentaré profundizar un poco más en toda esta información pero, de momento vamos a quedarnos con la imagen docker.io/httpd y vamos a crear nuestro primer contenedor con ella. Para esto solo es necesario ejecutar el comando; docker run -d --name webserver httpd:latest, como podemos ver a continuación:

Creación de un contenedor con un servidor web Apache.
Tras descargarse las capas de sistemas de ficheros necesarias que forman la imagen, podemos comprobar con el comando docker ps -a si hay algún contenedor corriendo:

Lista de contenedores arrancados y parados en el sistema.
La salida del comando muestra que hemos creado un contenedor con la imagen httpd:latest, que el nombre del contenedor es webserver, el estado del contenedor y que está escuchando en el puerto 80. Por tanto, ¿quiere esto decir que con tan solo ese comando hemos levantado un servidor web Apache y que es accesible por el puerto 80? La respuesta es no. Por defecto, un contenedor tendrá acceso al exterior del host donde se está ejecutando pero no podremos acceder a él desde fuera del host, solo desde el propio host. La manera más sencilla de comprobar esto es arrancar nuestro contenedor webserver con una shell, para ello solo tenemos que hacer lo siguiente:

Usando una shell en un contenedor.

Al arrancar así el contenedor, especificando el comando, no se ejecutará el comando por defecto de la imagen y por tanto, no estará corriendo el servidor apache pero podremos interactuar con el contenedor. Desde esta shell, si comprobamos la dirección IP y lanzamos un ping podremos comprobar que el contenedor puede acceder a la red sin problemas:

Acceso a la red desde un contenedor.

Como lo que queremos es comprobar que nuestro contenedor es un servidor web que está funcionando correctamente, arrancamos nuestro contenedor de nuevo sin pasarle ningún comando y a probamos a acceder desde el propio host. Para esto primero necesitamos saber que dirección IP le ha asignado docker a este contenedor, para esto podemos ejecutar el comando ip addr dentro del contenedor del siguiente modo:
Ejecutando un comando dentro de un contenedor.
Esto nos muestra una funcionalidad muy interesante y es que, siempre que el comando exista dentro del contenedor, podremos ejecutarlo y realizar acciones dentro de un contenedor que está corriendo. Con este sencillo comando hemos obtenido la dirección IP que nuestro contenedor webserver tiene con lo que ahora, con nuestro querido comando lynx podemos comprobar si de verdad está sirviendo una página web:

Accediendo con lynx a nuestro servidor web.
Aunque no es muy gráfico, nos permite comprobar que efectivamente, con un solo comando, hemos levantado un servidor web Apache totalmente operativo.

En el próximo post vamos a darle una pequeña vuelta a esto y explicar un poco más los comandos que hemos utilizado en este post, así como cambiar la forma en que creamos nuestro contenedor para que sea accesible desde el exterior.

martes, 3 de abril de 2018

Imágenes de software

Hola de nuevo, en el anterior post realicé una pequeña introducción a Docker. Como ya expliqué, con Docker podremos ejecutar software en entornos aislados de ejecución llamados contenedores. La pregunta obvia es ¿que software es el que se ejecuta dentro del contenedor?

Para poder crear un contenedor usaremos imágenes de software, las cuales contendrán las aplicaciones que necesitamos con todas sus dependencias.

Al hablar de imágenes de software podemos pensar que estas son ficheros únicos, como un paquete RPM o DEB, que descargamos y utilizamos para crear contenedores pero, en realidad, las imágenes de Docker son conjuntos de capas de ficheros.

Cada una de las capas de ficheros que forman una imagen contiene un conjunto de ficheros y directorios y todas esas capas juntas, mediante el uso de un union filesystem, formará el sistema de archivos completo que usará el contenedor.

Visualmente creo que se entiende mucho mejor, así que ahí va un esquema aclaratorio:
Sistema de archivos UFS y su relación con capas de ficheros.
Viendo esta imagen podemos entender como, al unir varias capas de sistemas de ficheros, se formará una imagen que contendrá todos los archivos necesarios para poder ejecutar una determinada aplicación.

Las capas de sistemas de ficheros se relacionarán entre ellas de tal manera que, la capa más baja será la capa padre de la siguiente y así sucesivamente, hasta formar una imagen completa que contenga toda la estructura de directorios y los ficheros necesarios para la ejecución de una determinada aplicación.

Por tanto, al crear un contenedor con una imagen, lo que tendremos serán todas esas capas montadas mediante un union filesystem que para el contenedor será un sistemas de ficheros HFS estándar, aunque realmente los archivos y directorios estén distribuidos entre las diferentes capas.

Cuando los procesos que corren en la aplicación deban realizar operaciones de escritura, lo harán sobre una capa superior que se añadira automáticamente a la imagen en el mismo momento de su creación.

Con esta forma de trabajar está claro que se consigue una reutilización de las capas de software para poder construir diferentes imágenes con solo relacionarlas entre ellas. Por ejemplo imaginemos una imagen que contenga el software de un servidor web como Apache o Nginx, aunque es una aproximación muy burda podemos imaginar que podría estar formada por dos capas de sistemas de ficheros:
  1. La primera capa contendría las bibliotecas necesarias de sistema operativo, así como aplicaciones básicas como una shell bash.
  2. La segunda capa, que sería hija de la anterior, contendría el software del propio servidor web, con sus bibliotecas, binarios y ficheros de configuración.
De este modo, al montar ambas capas juntas, el contenedor tendría acceso a un sistema de archivos donde "vería" ciertas carpetas con bibliotecas y binarios de sistema y, adicionalmente, las carpetas que contendrían el software del servidor web.

Más adelante volveremos sobre las imágenes, ya que lo interesante es ver como usarlas y construirlas, pero creo que para empezar es una buena introducción.

Muy pronto más información.