Mes: mayo 2016

El vicio de Docker

¿Alguna vez os habéis encontrado una tecnología/gadget tan versátil que os gustaría que estuviera todo ahí? Algo así como el smartphone actual, donde si pudieras, pedirías que con pulsar una sola tecla en la pantalla, que te preparase el café, te leyese las noticias, te pusiera en la cama la ropa que te vas a poner ese día, y que además te teletransportase al trabajo. Pues eso mismo me pasó a mi con Docker.
Docker
En una entrevista de trabajo que tuve, me hablaron de Docker por primera vez, como una forma de virtualizar aplicaciones, pero que no requería un OS completo de por medio. Para mi eso era toda una novedad, ya que me habría venido muy bien para virtualizar los servidores que uso para CoResponde en vez de tener que configurármelos uno a uno con todos los pequeños detalles. Solo crear una imagen de Docker especifica con todas las configuraciones, y lanzar contenedores de esa imagen en otros servidores. Más fácil imposible.
Desde el momento que empecé a enredar más a fondo con ello, vi que si pudiera, Dockerizaria hasta las sartenes de la cocina. Su potencia me sorprendió, y el rendimiento era extremadamente bueno.
Debo deciros antes de nada, que Docker está pensado para ejecutar en máquinas Linux, por lo cual si queréis hacerlo desde Windows o Mac, debereis usar una máquina virtual intermedia para poder funcionar. Pero por supuesto, esto no tiene ningún sentido, ya que si vamos a usar Docker, es porque no queremos hacer una virtualización tradicional. Así que si quieres usar Docker, ya estás tardando en pasarte a Linux.
Ahora entramos en la chicha de Docker. Esto es como funcionaría una máquina virtual tradicional, con su sistema operativo completo corriendo por encima de un sistema de virtualización o hypervisor elegido.

stackvm

Solo con el sistema operativo completo, el rendimiento se reduce dramáticamente. Sin embargo, este es el stack de Docker.

stackdocker

Con esto nos quitamos de en medio todo el sistema operativo de la máquina virtual, y el motor de Docker usará los recursos nativos de la máquina, junto con los binarios y librerías estrictamente necesarios para poder correr las aplicaciones que se requiera.
El funcionamiento de Docker es relativamente sencillo: Se basa en imágenes que contienen todo lo necesario para ejecutar una, o varias aplicaciones, y lanzar contenedores (Instancias) de estas imagenes. Contruir una imagen propia es tan sencillo como crear un fichero de texto plano llamado Dockerfile en el cual, se configura la aplicación que quieras correr.
Ej. de fichero Dockerfile

FROM buildpack-deps:jessie-scm
# A few problems with compiling Java from source:
# 1. Oracle. Licensing prevents us from redistributing the official JDK.
# 2. Compiling OpenJDK also requires the JDK to be installed, and it gets
# really hairy.
RUN apt-get update && apt-get install -y --no-install-recommends \
 bzip2 \
 unzip \
 xz-utils \
 && rm -rf /var/lib/apt/lists/*
RUN echo 'deb http://httpredir.debian.org/debian jessie-backports main' > /etc/apt/sources.list.d/jessie-backports.list
# Default to UTF-8 file.encoding
ENV LANG C.UTF-8
# add a simple script that can auto-detect the appropriate JAVA_HOME value
# based on whether the JDK or only the JRE is installed
RUN { \
 echo '#!/bin/sh'; \
 echo 'set -e'; \
 echo; \
 echo 'dirname "$(dirname "$(readlink -f "$(which javac || which java)")")"'; \
 } > /usr/local/bin/docker-java-home \
 && chmod +x /usr/local/bin/docker-java-home
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64
ENV JAVA_VERSION 8u72
ENV JAVA_DEBIAN_VERSION 8u72-b15-1~bpo8+1
# see https://bugs.debian.org/775775
# and https://github.com/docker-library/java/issues/19#issuecomment-70546872
ENV CA_CERTIFICATES_JAVA_VERSION 20140324
RUN set -x \
 && apt-get update \
 && apt-get install -y \
 openjdk-8-jdk="$JAVA_DEBIAN_VERSION" \
 ca-certificates-java="$CA_CERTIFICATES_JAVA_VERSION" \
 && rm -rf /var/lib/apt/lists/* \
 && [ "$JAVA_HOME" = "$(docker-java-home)" ]
# see CA_CERTIFICATES_JAVA_VERSION notes above
RUN /var/lib/dpkg/info/ca-certificates-java.postinst configure
ENTRYPOINT /usr/lib/jvm/java-8-openjdk-amd64/bin/java -version 

Este es el código del Dockerfile para tener un contenedor con java 8 instalado.
Lo primero que se puede observar es el siguiente texto :

FROM buildpack-deps:jessie-scm

Esto indica que estás heredando de la imagen con nombre buildpack-deps y la versión jessie-scm. Casi la totalidad de las imágenes de docker, heredan de una más básica (Existen imágenes de Ubuntu o Debian básicas muy útiles de las cuales partir), y van añadiendo funciones extra.
Todo lo demás son intrucciones de que debe tener instalado nuestra imagen, excepto la orden final, que debe ser un ENTRYPOINT o CMD que es la orden que se ejecuta cuando se inicia una instancia de esta imagen. En el ejemplo anterior simplemente se ejecuta un java -version que mostraría simplemente la versión de java. Este parámetro de entrada, puede ser sustituido por nuestro propio punto de entrada para una imagen propia.
Para convertir este archivo Dockerfile en una imagen lista para ejecutar, simplemente con ejecutar este comando desde el propio directorio donde se encuentra el Dockerfile, crearemos una imagen:

docker build -t imagen-java .

En este caso, estamos construyendo una imagen con nombre imagen-java, diciéndole que nuestro fichero Dockerfile, se encuentra en el directorio actual. Dependiendo de todo lo que hayamos definido en el fichero, tardará más o menos tiempo, y al final si ejecutamos

docker images

veremos que ya tenemos nuestra imagen lista.
A partir de aquí ya tenemos lo básico para empezar a trabajar con ella. Lo siguiente es lanzar un contenedor de docker. Un contenedor no es más que una instancia de esta imagen base, y que será equivalente a nuestra máquina virtual tradicional para poder entenderlo bien. Para lanzar un nuevo contenedor solo necesitamos el siguiente comando:

docker run --name container-java imagen-java

Y listo, ya tenemos nuestro primer contenedor creado, y veremos como por pantalla nos sale la versión de java que configuramos en nuestra imagen base.
Los contenedores de Docker se paran, en cuanto no tienen una aplicación en primer plano ejecutándose. Esto significa que si lanzas un proceso que empieza y termina, como por ej. el contenedor lanzado antes con java -version, en cuanto se acabe de ejecutar, el contenedor se para, y tendrías que volver a ejecutarlo con

docker start container-java

ya que no habría que crear otro, solamente re-arrancar el ya creado.
Por supuesto esto es algo demasiado básico que no nos sirve para nada, ya que no tenemos ninguna aplicación real corriendo.
Llegados a este punto, toca explicar que es Docker Hub. Docker Hub es una plataforma, donde almacenar y poner disponibles imágenes de Docker pre-compiladas, para poder ejecutar desde cualquier sitio. Resumiendo: Si ejecutamos

docker run tomcat:8.0

primero se comprobará que no tenemos disponible en local una imagen con ese nombre, irá a docker hub, comprobará que existe una imagen con ese nombre y versión, se la bajará a tu equipo, y después lanzará un contenedor que se quedará ejecutando un servidor tomcat versión 8. Como podéis ver la simplicidad de esto es infinita, y nos permite lanzar contenedores extremadamente rápido.
Hay que tener en cuenta, que estos contenedores son como máquina virtuales, y los puertos que usan las aplicaciones dentro, están aislados, por lo cual si queremos que estén accesibles en la máquina, debemos mapearlos. La sintaxis es la siguiente:

docker run <nombreimagen> -p <puerto externo>:<puerto del contenedor>

Un ejemplo de esto con un contenedor de tomcat sería

docker run tomcat:8.0 -p 80:8080

Con esto mapeamos el puerto por defecto del tomcat del contenedor, a nuestro puerto 80 de la máquina, por lo que con acceder a http://localhost/  estariamos ejecutando ya todo lo que contenga nuestro tomcat.
Se pueden tener múltiples contenedor de la misma imagen, por lo que tener dos servidores a la vez sería tan fácil como

docker run tomcat:8.0 -p 81:8080

y ya tendríamos otro tomcat corriendo en la misma máquina. Por supuesto, tiene que ser en un puerto distinto, ya que nuestro puerto 80 estaría ocupado por el contenedor anterior, y crearía un conflicto.

Espero que os haya servidor de ayuda, y a pesar de que no es un tutorial completo, hayáis echado un vistazo a una de las tecnologías que más me ha impresionado en los últimos tiempos.

Concepto de orientación a objetos

Probablemente el concepto que más me costó comprender cuando empecé a programar fue la orientación a objetos. El primer día de programación, van y me sueltan tan tranquilamente la definición estándar: Un objeto es una instancia de una clase. Ajam… si… muy bien… No se vosotros pero yo me quedé exactamente igual que estaba. Para mi en ese momento, una clase no era más que un archivo con cierto formato, donde yo ponía ordenes, y al compilarlas se ejecutaban una detrás de otra. Pero claro, eso se queda muy lejos de lo que es realmente programar.

Tardé bastante tiempo en entender claramente el significado de que era un objeto, y cómo usarlo. Y estoy seguro de que no he sido el único que ha estado tan perdido en este sentido. Pero un día, no se muy bien cómo, me di cuenta de que era, y cómo funcionaba. Fue un flash instantáneo que me vino a la mente, y de repente todo cobró sentido. Era un concepto tan simple que no sabía como había podido no entenderlo. Bueno, si lo se: Me estaban metiendo tantas cosas nuevas en la cabeza, que comprender en profundidad todo, era casi imposible. Pero a partir de ese momento todo fue viento en popa.

Por eso hoy, os voy a intentar enseñar cómo comprendí la orientación a objetos, y que siempre uso de ejemplo cada vez que intento explicarle a un alumno mío, que no tiene ni idea de que es un objeto.

Voy a dar por hecho que sabéis los conceptos de clase (Al menos con saber, burdamente explicado, que es un fichero donde se mete código y se ejecuta, suficiente), el de función o método (Definición simple: Una forma de agrupar instrucciones para hacer más legible el código), y la de variables (Esta lo siento, pero si no sabes lo que es una variable es que estás en el día 0 de aprender a programar xD), para explicaros la forma de entender la orientación a objetos

Esto es una clase

Clase coche
A partir de ahora, para vosotros esta clase es intocable, el código que escribáis en ella, NO PODÉIS EJECUTARLO. Hay formas de hacerlo obviamente (El concepto de static me costó comprenderlo bastante más, y no voy a meterme ahora con ello), pero por ahora para tener las cosas claras, ese código es intocable.
La cosa es que necesitamos ejecutar código de esa clase, y acceder a la variable que hay en ella para cambiarla, o ver que valor tiene. Aquí es cuando entra el concepto de objeto. Mi propia definición de objeto: Un objeto, es una copia usable de una clase. Dicho así, suena casi tan raro como la definición original de objeto, así que vamos a desarrollarlo un poco.
Para poder usar ese código hacemos una copia de nuestra clase:
Clase cocheClase coche
 
 
 
 
 
 
 
Hasta aquí todo bien, ya tenemos nuestra copia usable. La cosa es que, en esta copia, para vosotros, no es visible su código realmente, solo podrás hacer cosas con el, pero no ver las instrucciones que ejecuta. Por lo cual podría resumirse en que ahora mismo tienes esto:

CLASE   –   OBJECTO

Clase coche

 
 
 
 
 
 
 
Esta es la mejor imagen para definir un objeto, porque literalmente ES un objeto: Una cosa con la que podemos hacer algo.
Ahora a ese objeto le podemos decir que haga cosas. En nuestro caso, tenemos un objeto de la clase coche por lo cual podemos llamar a los métodos que tiene:

LLAMADA AL MéTODO/función ARRANCAR DEL OBJETO

Por supuesto, podemos crear tanto objetos como queramos. Podemos tener un array de esos objetos por ej:

Objecto cocheObjecto cocheObjecto coche

Y podemos decirle al segundo solamente que arranque.

Objecto cochearrancarObjecto cocheObjecto coche

Así es como lo veo yo, y al menos a mi me sirvió para captar de forma crucial el concepto de objeto, y por ahora, parece que mis alumnos también consiguen captarlo y entenderlo, por lo cual, algo de bueno tiene que tener verlo así.

Espero que a vosotros también os sirva para entenderlo si estáis empezando. Y si tenéis que enseñarle a alguien este concepto, tener una idea de cómo simplificar el proceso para que lo aprendan.

Starting the Force

Por fin me he decidido a arrancar mi propio blog. Era algo que tenía en mente desde hace muchísimo tiempo, pero a lo que no había dedicado el tiempo necesario hasta ahora mismo. Y por casualidades de la vida es un 4 de Mayo cuando arranca (Para los que no lo sepáis, el día de Star Wars. May the fourth be with you).
Necesitaba un lugar donde poder hablar de todo lo que voy aprendiendo sobre tecnología, sin que se pierda en la memoria y pueda compartirlo con toda la gente.
Cada día estoy aprendiendo algo nuevo, y guardarme todo ese conocimiento para mi, me ha terminado por resultar egoísta, así que es hora de que podáis ver lo que me interesa, aunque no siempre será de tecnología, sino de de una variedad de cosas que podría sorprenderos de alguien a quien se le considera un geek con todas las letras.
En unos días iré escribiendo unos post que tengo pendientes desde tiempos inmemoriales, y que espero que sea de interés general.
May the Force be with you