Categoría: programación

Telegram y el precio de la luz

Telegram y el precio de la luz

Desde hace ya un tiempo, llevo usando Telegram como principal aplicación de mensajería con mis conocidos. En esta, existen los llamados bots, que pueden implementarse por cualquiera a través de un API. Hace algún tiempo, intenté crear una librería para poder tratar con esos bots desde Java de una forma sencilla, pero lo dejé de lado por falta de tiempo, y por los constantes cambios que se van introduciendo por parte de Telegram. Por suerte no fui el único con esa idea, y alguien terminó llevándola a buen puerto, e incluso mejorándola. La librería se integra de una forma sencillísima con Spring Boot, para hacer un bot completamente funcional integrado en el ecosistema de Telegram.

Para crear un bot con esa librería, solo hay que usar el starter que incluye, y arrancarlo como una aplicación más de Spring. Lo necesario también, es obtener el token necesario de Telegram a través del BotFather que tiene, y que sirve para poder hacer las peticiones, que se debe añadir dentro de tu aplicación.

En su día, ya había creado algún bot por mi cuenta con mi propia librería anticuada, pero que también había abandonado, y ya llevaba dando vueltas a la cabeza el hacer uno nuevo, que realmente fuese útil. Y con mi situación actual, no terminó siendo difícil encontrar lo que necesitaba.

Como ya sabéis de mi anterior post, tengo un coche eléctrico, con el que estoy encantado. Para recargarlo, el 99% de las veces lo hago a través de la propia electricidad de mi casa, después de haber instalado un punto de carga en el garaje, y eso nos lleva hasta 2021. El precio de la luz como todos sabemos se disparó de manera desproporcionada, y la factura, incluso no siendo un consumidor excesivo, subió un riñón, y parte del otro. De hecho subió tanto, que ha habido un tiempo que no me compensaba cargar el coche en mi casa, porque me salía más caro, que irme a uno de los cargadores rápidos que hay cerca de mi casa.

Con todo esto, decidí que si iba a cargar el coche en casa, tendría que saber cuando hacerlo, para que mi factura no fuese una autentica aberración. Encontré una página web donde te dice que precio tiene la luz a cada hora del día, pero consultarla cada día, me parecía un poco engorroso. Esa página tira de un api público accesible para todos, que se puede consultar sin ningún problema, y al que le di un par de vueltas para ver como funcionaba.

Con mis ganas de volver a hacer un bot para Telegram, y mi necesidad de saber el precio de la luz cada día de forma rápida y sencilla, estaba claro lo que había que hacer: Un bot que te mandase cada día los precios de la luz de las horas de ese día, de forma automática. Con todo esto en mente, me puse manos a la obra, y en menos de un fin de semana ya lo tenia listo, y desplegado en un servidor propio que tengo desde hace siglos y un poco desaprovechado.

PrecioDeLaLuzBot

El código del bot es muy sencillo en si mismo: Obtiene desde el api público el precio de la luz para el día actual (Y el día siguiente también), y se lo guarda en una base de datos MariaDB. También almacena en la base de datos el ID de Telegram de todos los usuarios que se van uniendo al bot, para poder enviarle el mensaje con los precios de la luz. Una vez hecho esto, con un proceso programado a las 00:00 de cada noche, se crea el mensaje con los precios de ese día, y se le manda el mensaje formateado a todos los usuarios. Por supuesto si un usuario decide parar el bot, se le elimina del listado para que no se le mande más. Todo esto desplegado en un servidor a través de Docker (Como ya sabéis, no despliego ya nada que no se pueda hacer a través de Docker).

Desde que lo desplegué lo consulto todos los días, y en el momento de escribir este post, ya hay 70 personas que lo están usando, cosa que ya es más de lo que esperaba. Podéis acceder al bot vosotros mismos escaneando el QR de abajo, o pulsando directamente sobre el, para abrirlo directamente en Telegram.

Servicios básicos para startups con Ansible y Docker

Por anteriores post, habéis podido ver, que tengo una predilección enorme por Ansible y Docker, y todas sus posibilidades. Tanto es así que en mis servidores, ya no despliego nada que no vaya en contenedores, y si puedo, lo automatizo a través de Ansible.

Mi último descubrimiento fue Nextcloud: Un servicio de nube privada, que a su vez tiene mensajería instantánea, y videoconferencia integrada, que una vez instalado en tu servidor no necesitas depender de servicios de terceros. Si a eso se le añade la compatibilidad para poder editar documentos on-line gracias a Collabora y Onlyoffice, el potencial de este servicio se dispara hasta limites insospechables.

Teniendo un servidor infra utilizado, decidí instalarlo en el, para tener mis archivos sin que ninguno de los gigantes tecnológicos tuviera acceso a mis datos, pero me quedé prendado de la cantidad de posibilidades que presenta, y me di cuenta de algo tan obvio que no podia dejarlo pasar.

Nextcloud es el servicio perfecto para pequeñas empresas o startups que estén empezando, y no necesiten una infraestructura enorme, sin tener que depender de servicios de terceros, con una inversión mínima. Y ese es justo el punto en el que se me encendió la bombilla.

Servicios cloud

¿Por que no crear un instalador de servicios básicos para startups con Nextcloud? ¿Y si lo llevo un paso más allá, y no solo le añado un cloud privado, sino también un servidor propio de e-mail? Dos pájaros de un tiro, y los servicios básicos que toda empresa pequeña pueda necesitar, listos y preparados de forma sencilla. Encontré una solución integral de servidor de e-mail llamado Poste.io gratuito (Aunque con versión de pago con más características) que también se despliega con Docker, y es perfecto para el objetivo que tenía en mente.

Era el pequeño proyecto perfecto para poder usar Ansible y Docker unidos en todo su potencial.

Servicios para desarrollo de software

Una vez puesto al tema, y ver que todo iba viento en popa, la bombilla se volvió a encender, y lleve el instalador un paso más allá para crear el instalador definitivo para startups que se dediquen a desarrollo de software.

Ya tenía experiencia montando Gitlab, Jenkins y Nexus en mi empresa, así que… ¿Por qué no añadirlo al paquete? La combinación de nube privada, y servicios privados para entornos de desarrollo quedaba perfecta.


Manos a la obra…

Os explicaré brevemente los pasos que da el instalador, para tener todo listo simplemente con cambiar 2 variables, ponerle los datos de acceso de la máquina destino, configurar DNS para que apunten a tu máquina, y si no es un servidor que esté directamente en Internet, un mapeo de puertos.

1 – Instalación de dependencias

Para poder lanzar los servicios, se necesita tener instalado en la máquina docker, y docker-compose para un manejo mas simple de los contenedores. Además se le instalan dependencias de Python necesarias para que Ansible ejecute correctamente algunas tareas de Docker.

Se le da permisos al usuario para poder ejecutar contenedores de Docker si no es root, y listo: Máquina preparada para empezar

2 – Comprobación de DNS

Dado que van a ser unos servicios que tengan acceso desde Internet, compruebo mediante unas consultas de DNS si las IPs de los sub-dominios donde se van a desplegar los servicios, concuerdan con la IP pública del servidor.

3 – Instalación de proxy base

Para poder manejar todos los servicios desde una misma máquina, y además con Docker, es necesario ponerle delante un proxy para poder tratar las peticiones, y lo más importante, usar https sin tener que configurarlo en todos y cada uno de los servicios. En este caso he usado Nginx ya que tengo experiencia con el, y siempre me ha funcionado bien.

En este punto cabe destacar, que los certificados https pueden llevar un coste asociado, que no cuadra mucho con la filosofía de este instalador (Aunque al final se pueden añadir manualmente en la instalación si ya los tienes). ¿Solución? Let’s Encrypt: Con esto siempre que tengas configurado tu servidor web de una forma específica, puedes generar certificados https de forma gratuita, y además incluso renovarlos de forma automática para desentenderte de todo.

En este punto, le añado opcionalmente un servidor web con https al dominio raíz, por si en el futuro se quiere desplegar algo aquí.

4 – Instalación de proxy para servicios

Cada servicio lleva asociado un subdominio para su despliegue (Los despliegues en subdirectorios de un dominio, generan muchos dolores de cabeza, e incompatibilidades que no son recomendables), y por supuesto su certificado https, por lo cual, aplicando el mismo procedimiento que en el anterior punto, se genera certificados para los subdominios de Nextcloud, Poste.io, Collabora, Onlyoffice, Gitlab, Jenkins y Nexus, dejándolos preparados para el despliegue de cada uno de ellos

5 – Instalación de todos los servicios

Cada servicio tiene sus configuraciones específicas, redirecciones, restricciones de seguridad, triquiñuelas, etc… , que requieren muchas horas de investigación en base a documentación y prueba y error.

Al final de cada despliegue hecho a base de ficheros docker compose que agrupan todas las dependencias de un posible servicio, se le añade la configuración específica al proxy, para que sea capaz de redirigir las peticiones correctamente mediante https con el certificado generado anteriormente.

Sin duda este es el paso más laborioso, ya que todos los servicios son completamente distintos y requieren de laboriosas configuraciones que lleva su tiempo entender.

5 – Obtención de passwords de admin

Los servicios de Jenkins y Nexus, al arrancar generan una password de administrador, que solo se puede ver a través de la consulta de determinados ficheros generados tras completar la instalación. Yo quería que la instalación fuera lo menos dolorosa posible, así que al finalizar, saco por pantalla las passwords de administrador iniciales de estos servicios, para que puedan usarse de forma inmediata.


Con este proceso te queda un servidor listo para poder acceder a el, y crear usuarios y configuraciones ya especificas para cada servicio, pero sin haberte preocupado de toda su instalación, que ha durado poco más de 10 minutos.

Toda la codificación en scripts de Ansible me ha llevado unas 40 horas, pero me lo he pasado en grande combinando todas estas herramientas para poder tener un instalador muy completo. Algunas personas se divierten viendo la tele, otras haciendo deporte, y los que tenemos alma de programador, haciendo cosas como esta.

ACTUALIZACIÓN: Pues la cuarentena del corona virus, me ha dejado tiempo, y ahora también incluye un servidor de OpenLDAP y su administrador web.

ACTUALIZACIÓN 2: Y para seguir pasando la cuarentena, se incluye un Sonar.

Github

¿Que sentido tiene aprovechar unas herramientas gratuitas, si luego otra gente no puede aprovecharlas de la misma forma? Así que toca compartirlo con todo el mundo, y si alguno se decide a mejorarlo, los pull request son bienvenidos 😉

Ansible Web Tools installer

Ansible: La automatización definitiva para servidores

El término ansible se usa en la literatura de ciencia ficción para describir un dispositivo hipotético de comunicación más rápida que la luz.

Ansible logo

Los creadores de la tecnología llamada Ansible, se basaron en este sistema para darle nombre, y aunque obviamente no hayan conseguido que vaya más rápido que la luz, si que esta tecnología consigue hacer muchísimo más simple la configuración remota de equipos.

Ansible se basa en el más que probado protocolo SSH, con el cual se pueden ejecutar ordenes remotas mediante un terminal introduciendo comandos. Además se han abstraído estos comandos (Llamados tasks en Ansible), para que no tengan que escribirse como tal, y que escribiendo un trozo de código en formato yml, Ansible lo traduzca a comandos Linux. Lo bueno de Ansible, es que no hay que instalar en servidor nada más que un servidor de SSH, y listo, Ansible funcionará perfectamente, ya que en realidad no ejecuta en servidor, sino en la máquina cliente que ataca esos servidores, por eso desde la máquina donde se lance la ejecución, si que debe tener Ansible instalado.

Inventarios

El inventario en Ansible no es mas que un archivo de texto plano, donde se definen los hosts a los que podemos atacar. Un fichero de inventario podría tener el siguiente aspecto

mail.example.com

[webservers]
foo.example.com
bar.example.com

[dbservers]
one.example.com
two.example.com
three.example.com

Se puede ver, que tiene una dirección por defecto como mail.example.com, y ademas mediante corchetes, se pueden crear grupos de máquinas como en este caso [webservers] o [dbservers], por si queremos ejecutar los mismos comandos directamente contra varios servidores de una sola vez.

A su vez, Ansible tiene unos posibles hosts donde ejecutar estos comandos. Estos hosts no son mas que configuraciones de conexión a los servidores donde se tiene que ejecutar los tasks. Se puede tener un solo host, o varios a la vez donde ejecutarse. Por supuesto, se debe tener el acceso correspondiente a cada máquina, ya sea via usuario y contraseña (Nada recomendable), o mediante una clave publica/privada que se haya instalado en el servidor donde se ejecutarán las tareas.

tareas

Un ejemplo básico de una tarea Ansible, en la que se copia un fichero de un directorio local, a uno remoto en el servidor sería este

- name: example copying file with owner and permissions
  copy:
    src: /srv/myfiles/foo.conf
    dest: /etc/foo.conf
    owner: foo
    group: foo
    mode: 0644

Los elementos son los siguientes:

  • name: Nombre de la tarea a ejecutar que la identifica de forma unica
  • copy: etiqueta que identifica el comando de la tarea. En este caso el tipo copy sirve para copiar archivos en servidor.
    • src: Fichero local a subir en nuestro servidor
    • dest: Ruta donde se dejará el fichero a subir. Se puede poner un nombre distinto al original si queremos renombrarlo.
    • owner: Propietario del fichero que se pondrá al subirlo.
    • group: Grupo del fichero que se pondrá al subirlo.
    • mode: Permisos en formato octal, que se le darán al fichero en servidor.

Como podéis ver es un formato yml muy claro, y fácilmente entendible. Por supuesto existen muchos mas tipos de tareas en Ansible que se traducirán a comandos ssh automáticamente cuando se ejecuten. Los ficheros que agrupan estas tareas, se les denomina en Ansible, playbooks, ya que pueden contener varias tareas a ejecutar.

ejecución

Una vez creado nuestro primero playbook, ya podremos ejecutarlo. Una ejemplo de ejecución seria este

ansible-playbook -i hosts.cfg -l webservers myPlaybookFile.yml

Este comando usa un fichero hosts.cfg (El del ejemplo escrito arriba), y un fichero de playbook llamado myPlaybookFile.yml donde se encuentran las tareas a ejecutar. Al ejecutar este comando, subirá a los hosts definidos dentro del grupo webservers (Con el argumento -l nombregrupo se indica que se quiere ejecutar contra un grupo de hosts) del ficheros hosts.cfg, el fichero que se indica en la tarea copy de nuestro fichero myPlaybookFile.yml.

Variables

La gran mayoria de veces las tareas que necesitamos ejecutar deben ser parametrizadas, ya que seguramente cambien con el tiempo. Para eso pueden usarse variables que puedan cogerse desde el mismo fichero de playbook, una fuente externa como un fichero de variables, o como parámetros dentro del propio comando de ejecución.

Para usar variables dentro de una tarea se debe poner el nombre de la variable dentro de dobles llaves {{ nombre_variable }}.

Un ejemplo dentro de una tarea podria ser el siguiente

- name: example copying file with owner and permissions
  copy:
    src: /srv/myfiles/{{ file_name }}
    dest: /etc/{{ file_name }}
    owner: foo
    group: foo
    mode: 0644

Y el comando a ejecutar pasándole la variable file_name

ansible-playbook -i hosts.cfg -l webservers myPlaybookFile.yml --extra-vars "file_name=ficherodeprueba.txt"

Con el parámetro –extra-vars (Aunque también vale con -e) se le pueden pasar variables extras que después se usen dentro de los playbooks.

Módulos

Ansible tienes unas tareas básicas que prácticamente pueden ejecutar en cualquier servidor Linux, sin embargo, estas son ampliables y pueden añadírsele módulos adicionales para poder manejar determinadas partes del host destino, como por ej. docker.

En la página web de Ansible tenéis todos los módulos disponibles que se pueden instalar para poder ampliar su funcionalidad.


Con esto espero haberos dado una idea aproximada de la potencia de Ansible, ya que para mi es imprescindible en estos momento, porque mis backups automatizados de servidores están hechos sobre Ansible, y en un futuro lo usaré para configuración completa de servidores nuevos.

ThyMeLeaf y el método de plantillado del futuro

Uno de los mayores incordios que tenemos los programadores full-stack (O comúnmente llamados «El que hace de todo»), es tener que coger el diseño de una web -que por supuesto no hemos diseñado nosotros, porque nuestra mente es más lógica que estética- y adaptarlo para darle el dinamismo que requiere una web hoy en día. Muchas veces este proceso es muy tedioso, sobre todo cuando se van haciendo pequeños cambios, que requieren una comparación exhaustiva de lo que ya hay adaptado, a los nuevos cambios estéticos que te pasan, y que al ser de contenido estático, puede llegar a ser una tortura encontrarlos.
Hace unos meses, cuando teníamos en mente un esbozo de lo que sería Origin Path, había que ir decidiendo la arquitectura que tocaría usar, y ya que parece que el concepto de SPA no parecía ni llamarnos demasiado la atención, ni de ser una buena opción de primeras, tocaba buscar un motor de plantillas con el que trabajar. Usar JSP me parecía ya desfasado si íbamos a hacer algo actual (Aun con las etiquetas de los distintos frameworks me parece anticuado), y aunque obviamente tuviese el mejor rendimiento, teníamos que buscar en una dirección que nos diese más facilidades a la hora de trabajar. Lo primero que te puede venir a la cabeza de motores de plantillas si vas a trabajar con java, es Velocity y Freemarker, ya que son probablemente los motores con más aceptación ahora mismo. Ya que ninguno de los dos terminaba de convencerme, hice una búsqueda sencilla al señor Google, a ver que me decía, y encontré algo que no conocía, que parecía repetirse bastante.
ThyMeLeafAlgo llamado ThyMeLeaf, por lo visto está empezando a ganar gran visibilidad y haciéndose un hueco, en el mundo de los motores de plantillas para Java. Dado que estábamos en busca y captura de uno nuevo, echarle un vistazo no nos iba a hacer daño, y podíamos encontrar algo interesante. Para lo que no estaba preparado, es para lo que me encontré, y me dejo bastante aturdido, ya que no era ni de lejos lo que me esperaba. En los motores de plantillas siempre sueles encontrar lo mismo, pero de distintas formas: Etiquetas de control de flujo, inclusión de otras plantillas en las propias plantillas, definición de tus propias etiquetas, etc… Y ThyMeLeaf, no es una excepción en esto.
El hecho es que la plantilla en si misma, es compatible con el diseño estático que puede hacer un diseñador, y a la vez con toda la parte dinámica que le damos los programadores, trabajando los dos sobre el mismo fichero. Esto puedo decir con toda sinceridad que no lo había visto NUNCA, y me sorprendió de una manera muy grata. Sin duda hizo que fuera la elección a usar en Origin path, y empezar a trabajar con ello.
Os voy a intentar poner un ejemplo para que veáis a que me refiero, con que es compatible con diseñadores y programadores trabajando sobre el mismo fichero. El ejemplo lo haré con spring MVC por detrás, para que podáis orientaros un poco en lo que voy haciendo.
Lo primero es crear un HTML estático, que tenga algún estilo para poder simular que un diseñador ha hecho una página genial, en vez de un programador sin ningún sentido del gusto.

 <html lang="es" xmlns="http://www.w3.org/1999/xhtml">
 <head>
      <title>Titulo de la aplicacion</title>
      <link rel="stylesheet" type="text/css"
            media="all" href="../../css/propio.css" />
 </head>
 <body>
     <header>
         <h1 class="titulo">Pagina de thymeleaf</h1>
     </header>
     <table>
         <thead>
             <tr>
                 <th>Autores</th>
             </tr>
        </thead>
        <tbody>
            <tr>
                <td>Primero</td>
            </tr>
            <tr>
                <td>Segundo</td>
            </tr>
            <tr>
                <td>Tercero</td>
            </tr>
        </tbody>
     </table>
     <br/>
     <footer> Ejemplo de Thymeleaf </footer>
 </body>
</html>

Hasta aquí nada del otro mundo, un HTML con una tabla, un fichero de estilos situado dos niveles más arriba, y listo. El resultado del HTML al abrirlo en cualquier navegador, sin un servidor de por medio es el siguiente:
Salida1
Como veis nada del otro mundo. Ahora añadámosle unas cuantas etiquetas de ThyMeLeaf (Ya que ThyMeLeaf puede usar HTML a secas) que coge datos directamente desde un controlador implementado con Spring MVC:

<html lang="es" xmlns="http://www.w3.org/1999/xhtml"
       xmlns:th="http://www.thymeleaf.org">
<head>
    <title th:text="${title}">Titulo de la aplicacion</title>
    <link rel="stylesheet" type="text/css"
          media="all" th:href="@{/css/propio.css}" href="../../css/propio.css" />
</head>
<body>
    <header>
        <h1 th:text="${actualPage}" class="titulo">Pagina de thymeleaf</h1>
    </header>
    <table>
       <thead>
           <tr>
              <th>Autores</th>
           </tr>
      </thead>
      <tbody>
          <tr th:each="autor : ${nombres}">
              <td th:text="${autor}">Primero</td>
          </tr>
          <tr th:remove="all">
             <td>Segundo</td>
          </tr>
          <tr th:remove="all">
             <td>Tercero</td>
         </tr>
      </tbody>
   </table>
 <br/>
 <footer> Ejemplo de Thymeleaf </footer>
</body>
</html>

Y al abrirlo directamente como un fichero HTML normal, el resultado sigue siendo el mismo.
Salida2
Como podéis ver, al no ser atributos estándar de HTML, el navegador simple y llanamente los ignora, y el diseñador podría trabajar igualmente con el sin tener ningún problema, únicamente con la condición de no tocar ningún atributo de etiquetas que empiecen por th:. Ahora pasemos esta misma plantilla sin ningún cambio a través de un servidor con Spring MVC y ThyMeLeaf, y la salida es la siguiente:
Salida3
¡¡Magia!! El título de la página, la cabecera, y el listado de nombres, ha cambiado por completo. Simplemente pasando unos cuantos atributos a través del ModelMap de SpringMVC hemos conseguido todo un contenido dinámico.
La etiqueta th:text ha sustituido el texto que contiene la etiqueta en la que se aplica. Con th:each hacemos que la etiqueta donde se aplica, se repita tantas veces como la longitud de la lista de nombres que le pasamos, y dentro del td, volvemos a aplicar un reemplazo del texto. En los siguientes td se usa th:remove=»all» que lo que hace, es eliminar de la salida toda esa etiqueta y su contenido (Si solo quisiéramos eliminar la etiqueta, pero no su contenido podríamos usar th:remove=»tag»), consiguiendo así dinamizar la página en función de los datos que se le pasen. Además con la etiqueta th:ref del link para el css, sustituye la ruta estática al css por una que se pueda entender en servidor.
Ahora mismo, tanto diseñador como programador pueden trabajar sobre el mismo archivo y pudiendo ver los dos, resultados instantáneos sin tener que ir adaptándolo cada vez que haya un cambio estético. Como podeis ver, esto va a evitar un tiempo enorme a la hora de tener que cambiar diseños, haciendo así, mucho más dinámico el desarrollo de la web.
A cada conjunto de etiquetas en ThyMeLeaf, se le llama dialecto, y ya existen muchos para poder hacer cualquier cosa. En el caso de Origin Path, estoy usando el dialecto SpringSecurityDialect para usar Spring security, y LayoutDialect para poder realizar layouts complejos con plantillas más reutilizables. Por supuesto, puedes crearte tus propios dialectos para usarlos como en cualquier otro motor de plantillas, a través de toda la aplicación.
Como podéis ver, es una mejora enorme respecto a los sistemas tradicionales de plantillas, que sin duda ha llegado para quedarse, y en mi caso, para ser el motor principal que voy a usar en proyectos de este tipo. Espero que os haya sido útil, y que hayáis visto, que no solo de JSPs, Velocity y Freemarker vive el programador Java.

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.