Solo hay una forma de hacer café en arkhotech

(Español) #Agiles2017, un mes después…

Sorry, this entry is only available in European Spanish. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Ya han pasado 4 semanas desde que asistí a #Agiles2017, 3 días de motivación, 3 días intenso, y 3 días para aprender.

Lo primero que hice fue hacer un “Estoy aquí” en Facebook, y a los minutos veo el mensaje de una gran amiga @msolisf – y dije listo, no estaré solo para conversar – por lo menos en el primer día (aun soy un poco tímido).

Busque mi credencial, mi polera y agua mineral que estaban regalando, y listo ya estábamos inmersos en el patio de la universidad Federico Santa Maria donde fue este magno evento.

Estábamos todos sentados esperando la bienvenida, y de repente veo que se está armando la pista de baile, sí, una pista de baile donde empezaron a tocar varios pies de cueca (nuestro hermoso baile nacional) fue el inicio donde fibras sensibles activaron el “pelometro”, vestidos de cueca china, porteña, y listo. Toco la oportunidad de salir a bailar y claro que lo hice.

Luego toco la bienvenida, explicar lo del openspace (para los que no conocíamos el formato) y el Marketplace donde muchas personas participaron para exponer los temas que dominaban, desde grandes gurus hasta los que se están iniciando en esto de querer ser rockstar. Se dio origen a #Agiles2017, donde más de 850 personas se reunirían, pertenecientes a 20 países y con más de 300 sesiones para nutrirse de conocimiento.

En la retina quedaron varios temas y grandes presentaciones de expositores, uno de ellos fue las 10 practicas no negociables del desarrollo ágil (con Veronica Rodriguez – Slin Castro) , dentro de este marco, se reforzaron varios temas de interés y que debemos estar constantemente recordando.

 

Con el pasar del tiempo toco el turno de ir donde una persona que conocí y que sin duda expone desde su experiencia y como lo lleva al día a día. Si es @jgarza una persona que a simple vista… es uno más, y que sin duda puedes verte reflejado por su trayectoria.

El tema que expuso @jgarzas te hace ver lo fácil que es caer en el lado oscuro de la agilidad, de recordarlo (por qué ya lo sabes) pero que se olvida fácil con el día a día en tu trabajo.

(@jgarzas quiso sacarse una foto con @tamoslistos) (aquí puedes ver su presentación aquí)

Otro tema que quedo en la retina fue la conversación de historias de usuario con @luchoSalazar en donde empezó con pequeño grupo de personas para luego termino con muchas personas alrededor, solo tenían 45 min por sesión, pero con Lucho teníamos para hablar todo el día con experiencias propias y de los integrantes que participaron.

Mi percepción del día 1 al día 3 es que este openspace fue mejorando cada día, consideraron mucho y se retroalimentaron de la opinión de todos.

Ya como termino del día 3, hicieron un carnaval, una batucada se presentó y para motivarse en la finalización una guerra épica de bombitas de agua en los jardines de la universidad.

#Agiles2017 ya termino, pero dejó una experiencia enriquecedora, donde sin duda aprendí, reforcé, y donde te deja con la sensación de… ¿porque no expuse un tema? Bueno el desafío ya está, y este 2018 es en Ciudad de México #Agilchingon #Agiles2018 y si se da la oportunidad de exponer, lo haré.

Agrega

trello-domo

Sorry, this entry is only available in European Spanish. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Desde hace ya bastante tiempo, y en nuestra estrategia de agilidad, hemos probado diferentes herramientas para mantener visibilidad de nuestro trabajo día a día. Sin hablar mucho de las otras herramientas, considero Trello nos ha traído grandes beneficios por su simpleza y facilidad de uso; no hay que explicar mucho a alguien que nunca lo ha visto o no tiene mucha experiencia, y eso, es más que valioso.

En mi perspectiva, si hay algo que no tienes en tu lista de pendientes, entonces no existe; y esto es lo que para mi gusto, Trello resuelve muy bien, todo lo que se te ocurra es muy sencillo de apilar… Ahora bien, si solo sumas a tu bandeja de entrada tareas y tareas que nunca se mueven, ese es otro problema; recuerden movimiento es muy diferente a progreso.

La manera versátil de organizar tareas en listas que propone trello hace mucho sentido en los tableros que queremos potenciar, tanto personales como grupales, pero en estos últimos es donde más encontramos valor, y los usamos para todo! … Aquí algunos ejemplos:

  • Metas semanales → Mensuales → Anuales. ¿Scrum de scrums? Esta es la fuente, también hay una pizarra física, pero cuando hay gente remota lo físico pierde valor.
  • Clientes (Mini-CRM). Cuántos clientes están activos? Cuántos han dejado de tener movimiento? Prospectos? Perdidos? Bueno, acá están todos…
  • Vacaciones:  Sí, hasta las peticiones de fechas se hacen por Trello! Chao correos o herramientas de RRHH que nadie entiende. Cuatro columnas son suficientes: Solicitadas, Aprobadas, Actuales y Tomadas. Además, se calculan automáticamente los días que te debe la compañía.
  • Colaboradores: Personas, Alianzas, Partners, Asociados y hasta la gente que se ha ido en un solo lugar… Algun teléfono? bueno ahi está su VCF, Foto, Ficha y hasta su foto por si no tenemos ni idea quién es.
  • Proyectos: actuales, exitosos, fracasos, servicios. Una cuenta total? Fácil, mediante la API de Trello. Fuente genial para estadísticas de compañía.
  • Asignaciones (staffing): Quién está en qué y con qué asignación. Muy útil, pero hay que actualizarla! OjO.
  • Ventas (Revenue)Tres columnas hacen magia: Facturas pendientes (proyección), emitidas y pagadas. Cada una con su monto, en un formato estándar. Tip, usar story points para el monto funciona perfecto.
  • Tareas Administrativas y Caja Chica. Bastante más claro que un excel en muchas oportunidades. Además, la secretaria siempre tendrá una visibilidad tremenda, lo que hace y deja de hacer.
  • Operaciones. Bueno, por último para algunos proyectos, donde la gestión es suficiente  con un simple Kanban… pero para proyectos que requieren muchas más métricas no es muy recomendable. Ejm, Tiempos consumidos (work-log).

Todo esto suena bien. Sin embargo, hizo falta algo, ¿cómo interpretar la gran cantidad de datos que se suben a los tableros día a día? Bueno para ello, primero hicimos varias cosas:

  1. Lo que está en la parte de más arriba es lo que tiene más prioridad.
  2. Las tareas deben tener etiquetas que permitan clasificar más adelante. Ojalá esta clasificación sea muy acotada, no vale la pena tener 100 etiquetas diferentes.
  3. Idealmente una persona por tarjeta. Responsabilidad compartida, no es de nadie.
  4. Agregar fechas de venciento es tan importante como agregar la tarea, da un marco de acción.
  5. Integrar Trello con alguna herramienta de chat, en nuestro caso Slack. La notificación del movimiento de una tarea es muy importante para la inercia de equipo. Muchos no lo perciben o le prestan atención, pero que haya uno entre diez, es suficiente.
  6. Finalizado (Done) es finalizado, no es casi finalizado, o falta poco, o de seguro mañana se cierra y me adelanto a cerrarlo. La definición de Finalizado, es una discusión muy importante, el consenso de equipo es lo que la hace poderoso.
  7. Limpiar los boards de manera recurrente, lo que está en Terminado pasa a ser archivado cada semana.
  8. Un reporte diario 8am (vía Mail), para empezar el día y ver donde estoy como deudor. Aquí es donde empieza a aparecer nuestra nueva herramienta.

Con todo esto, de nuevo parece que falta algo… la información es poco visible cuando el equipo crece y las tareas abundan; para esto, buscamos alguna herramienta que permita generar estadísticas y métricas de acuerdo a nuestros tableros, y … nuestra elección fue DOMO, una herramienta BI que permite interpretar datos de múltiples fuentes, procesarlos y desplegarlos en múltiples formatos, para ayudar a la toma de decisiones de negocio. Es bastante potente, se pueden combinar múltiples fuentes de datos, esta alojada en la nube y la modalidad gratis es suficiente para lo que buscamos.

Que hacemos con Domo entonces? Primero, conectamos Trello como fuente de datos, el permiso es por 30 días, así que cada mes toca renovar las credenciales para no perder acceso. El usuario que hace la integración, debe pertenecer a todos los tableros que se quieran leer, para ello usamos un usuario genérico para evitar depender de alguien en particular. Una vez con la integración lista, programamos una tarea en modalidad segundo plano todos los días a las 7am para traer lo último de las tarjetas y tenerlas como fuente de datos de Domo.

Una vez la data esta disponible, se crean páginas que agrupan tarjetas (no de trello), que corresponden básicamente a un gráfico o métrica. Aquí algunos ejemplos de lo que se puede lograr.

 

Esta es una muestra de lo que ha sido valioso para el equipo, algunas se han ofuscado por obvias razones; acá se muestran como modelo de inspiración o crítica, lo importante es que las métricas elegidas sean útiles a toda la organización.

Cada tarjeta tiene su detalle, por ejemplo, cuando se da click sobre una particular, se muestra el detalle asociado. Ejemplo, para clientes:

Bien, todos estas tarjetas (gráficos) se generan mediante una especie de tabla dinámica de excel, en un modo llamado “Analyzer”, donde se establecen las dimensiones de información y se puede jugar con datos calculados y formulas dinámicas (Beast mode) que la herramienta provee. Los tipos de gráfico disponibles son bastante completos y ricos visualmente, desde “funnel” de conversión, tablas,  “data science”, mapas y muchos más. Aún queda mucho por explorar, pero algo bien interesante es que las tarjetas ahora pueden ser embebidas dentro de contenido html en cualquier lugar o publicarse en redes sociales como Twitter, Facebook y LinkedIn.

¿Qué es lo más complicado? Bien, la exportación de Trello aún tiene muchos detalles por mejorar, y uno de las más complicadas es que las listas no son exportadas con el nombre, sino con el identificador único, por tanto, hay que hacer un mapeo/traducción para saber a que columna pertenece; lo bueno de esto, es que se hace una vez y de ahi se comparte a todas las tarjetas (como campo calculado). Un ejemplo de ello, es una función no tan limpia como:

CASE when `idList` = '58c36bb5f7781a57df6dba6c' then 'Inbox' 
     when `idList` = '56bf30f9e7857bb868a04b25' then 'Inbox' 
     when `idList` = '577d0f282076b7a67c595355' then 'Inbox'
     when `idList` = '58c43cbc823286e6fa47d13e' then 'In Progress' 
     when `idList` = '5952afda7d036e870a9c33f8' then 'In Progress' 
     when `idList` = '596e4ef1ea1b31b1fbf6d1f7' then 'In Progress'    
     when `idList` = '58c43cbe3774edac9afe567a' then 'DONE'
     when `idList` = '58e79a3918388b9ff9ef5516' then 'DONE' 
     else 'Other' End

Algo también que puede ser complicado, es que cuando una tarjeta en trello pertenece a dos personas, la exportación la toma como dos registros independientes y no un solo registro.

¿Qué queda faltando? Algo que se extraña de manera simple, es el poder comparar el día anterior con el actual, en ocasiones es útil poder determinar tendencias y contar con algo que permita validar si hubo un cambio o no con relación a la instancia inmediatamente anterior. De seguro se puede realizar, pero la implementación a primera vista no sería tan sencilla. En todo caso, Domo es una herramienta bastante versátil y va más allá del uso que le estamos dando acá.

Finalmente, siempre considerar que el valor más importante no está en las herramientas, sino en lo que podemos crear explorando y explotando las funcionalidades que nos brindan las elecciones tecnológicas que hacemos. Sin duda, tanto Trello como Domo, tienen muchos más usos de los acá planteados, pero la invitación es a probarlos, ajustarlos a las necesidades particulares y compartir los resultados.

(Español) ELK Stack

Sorry, this entry is only available in European Spanish. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

El stack ELK es una solución para la recolección, la centralización y la explotación de logs.
Estos últimos años, se ha vuelto la solución recomendada para los sistemas complejos y distribuidos que generan muchos logs.

Lleva al menos esos tres componentes:
E para ElasticSearch
L para Logstash
K para Kibana

ElasticSearch

Es una base de datos orientada a documentos (JSON) con schema opcional, tiene tres casos de uso principales :

  • Motor de búsqueda de texto
  • Análisis de logs
  • Business Intelligence

ElasticSearch es muy bueno para almacenar grandes volúmenes de documentos, indexarlos, y buscar textos en ellos, lo que le hace una herramienta muy adaptada para analizar las cantidades de archivos logs que generan las aplicaciones hoy en día.

Logstash

Es un procesador de datos, que funciona como un pipeline en tres partes :

  • Input
  • Filter
  • Output

Logstash viene con varios plugins de entrada y salida, lo que le permite colectar datos de varios fuentes y mandarlos a varias partes, los plugins de filtro, permiten tratar estos datos dándole sentido, como por ejemplo, convirtiendo una IP en una zona geográfica.

Kibana

Es un visualizador de datos, especialmente desarrollado para ElasticSearch.
Permite explorar los datos recolectados en ElasticSearch, construir varios tipos de gráficos, incluyendo mapas, y componer dashboards a partir de esos gráficos.

Elastic

Esos tres componentes son obras de la compañía Elastic (https://www.elastic.co/) y son Open Source :
– ElasticSearch (Java) https://github.com/elastic/elasticsearch
– Kibana (Javascript) https://github.com/elastic/kibana
– Logstash (Ruby) https://github.com/elastic/logstash

¿Como funcionan juntos?

La configuración de ElasticSearch y Kibana es bastante fácil, solo hay que indicarle a Kibana la URL de ElasticSearch, por ejemplo en una configuración docker-compose :

elastic:
  image: docker.elastic.co/elasticsearch/elasticsearch:5.6.3
  volumes:
  - logs:/usr/share/elasticsearch/data
  ports:
  - 9200:9200
kibana:
  image: docker.elastic.co/kibana/kibana:5.6.3
  environment:
  - ELASTICSEARCH_URL=http://elastic:9200
  ports:
  - 5601:5601
  depends_on:
  - elastic

Eso aplica también para el output de Logstash, solo hay que ocupar el plugin de salida para ElasticSearch y indicarle la URL:

output {
  elasticsearch {
    hosts => "elastic:9200"
  }
}

Lo más complicado es la recolección de los logs, ya que no hay dos aplicaciones que ocupen el mismo formato.

Modelo 1
Logstash puede colectar los logs directamente desde el filesystem, pero en este caso, se necesitará una instancia de logstash en cada nodo. Es el modelo 1, que se representa a continuación :

ELK1

Modelo 2
Un modelo más evolucionado consiste en ocupar Filebeat, es un agente liviano especialmente escrito para ese caso de uso, es capaz de comunicarse con Logstash de forma inteligente. También es de Elastic y es Open Source (escrito en Go), hace parte de una familia más grande llamada “Beats” que conlleva otros productos relacionados.
En este modelo, se puede tener una instancia única de Logstash con un agente Filebeat en cada nodo :

ELK2

Modelo 3
Finalmente, se pueden configurar los componentes en un tercer modelo, agregándole un message queue broker, lo que permite desacoplar la recolección y el tratamiento de los logs :

ELK3

De esa forma, se puede detener el ElasticSearch, por mantención por ejemplo, sin pérdida de logs, ya que se acumulan en la cola. También permite que no se colapse el sistema cuando llegan muchos logs al mismo tiempo; la cola hará un papel de amortiguador de carga, en ese caso. Como Message Broker, entre otros, se puede ocupar Redis.
Existen plugins de entrada y de salida para Logstash.

Salida:

output {
  redis {
    host => "redis"
    data_type => "list"
    key => "logstash"
  }
}

Entrada:

input {
  redis {
    host => "redis"
    data_type => "list"
    key => "logstash"
  }
}

Ejemplos de configuración de Filebeat

Este ejemplo es una configuración (filebeat.yml) que mueve los logs de un servidor HTTP Nginx a una instancia Logstash:

filebeat.prospectors:
- input_type: log
  paths:
  - /var/log/nginx/access.log
name: "nginx"
output.logstash:
  hosts: ["logstash-collector:5044"]

Este segundo ejemplo colecta los logs de una aplicación corriendo en JBoss:

filebeat.prospectors:
- input_type: log
  paths:
  - /opt/jboss/jboss-eap-6.4/standalone/log/server.log
  multiline:
    pattern: '^[0-9]{2}/[0-9]{2}/[0-9]{4}'
    negate: true
    match: after
- input_type: log
  paths:
  - /opt/jboss/jboss-eap-6.4/standalone/log/app/*.log     
  multiline:
    pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
    negate: true
    match: after
name: "hub"
output.logstash:
  hosts: ["logstash-collector:5044"]

Acá se puede ver que Filebeat es capaz de leer desde diferentes archivos, y también, gracias al multiline pattern, de unir varias líneas del archivo en una sola entrada de log (lo que típicamente ocurre con los logs que producen las aplicaciones Java).

Ejemplos de configuración de Logstash

Este es un ejemplo de archivo de configuración en el modelo 3.
Corresponde a la primera instancia de Logstash que colecta los logs de los diferentes agentes Filebeat y los manda en Redis, sin tratamiento inmediato.

Archivo logstash.conf :

input {
  beats {
    port => 5044
  }
}

output {
  redis {
    host => "redis"
    data_type => "list"
    key => "logstash"
  }
}

Este segundo ejemplo, corresponde a la segunda instancia de Logstash, la que recupera los logs desde la cola Redis, los transforma en algo con sentido y los indexa en ElasticSearch :

input {
  redis {
    host => "redis"
    data_type => "list"
    key => "logstash"
  }
}

filter {
  if [beat][name] == "meta" {
    if  =~ "meta-search\.log$" {
      grok {
        match => {
          "message" => "(\e?\[\d+m)+\[%{DATESTAMP:datetime}\] \[%{DATA:user}\] \[%{LOGLEVEL:level}] \[th:%{DATA:thread}\] \[%{GREEDYDATA:category}\]:%{INT:line} - %{GREEDYDATA:message}"
        }
        overwrite => [ "message" ]
      }
    } else {
      grok {
        match => {
          "message" => "\[%{DATESTAMP:datetime}\] \[%{DATA:user}\] \[%{LOGLEVEL:level}] \[%{GREEDYDATA:category}\]:%{INT:line} - %{GREEDYDATA:message}"
        }
        overwrite => [ "message" ]
      }
    }
    date {
      match => [ "datetime", "dd/MM/yyyy HH:mm:ss,SSS" ]
      timezone => "America/Santiago"
      remove_field => [ "datetime" ]
    }
  } else if [beat][name] == "hub" {
    if  =~ "server\.log$" {
      grok {
        match => {
          "message" => "%{DATESTAMP:datetime} %{LOGLEVEL:level} +\[%{GREEDYDATA:category}\] \(%{DATA:thread}\) %{GREEDYDATA:message}"
        }
        overwrite => [ "message" ]
      }
      date {
        match => [ "datetime", "dd/MM/yyyy HH:mm:ss,SSS" ]
        timezone => "America/Santiago"
        remove_field => [ "datetime" ]
      }
    } else {
      grok {
        match => {
          "message" => "%{TIMESTAMP_ISO8601:datetime} %{LOGLEVEL:level} %{GREEDYDATA:category}:%{INT:line} - %{GREEDYDATA:message}"
        }
        overwrite => [ "message" ]
      }
      date {
        match => [ "datetime", "yyyy-MM-dd HH:mm:ss" ]
        timezone => "America/Santiago"
        remove_field => [ "datetime" ]
      }
    }
  } else if [beat][name] == "hazelcast" {
    grok {
      match => {
        "message" => "%{MONTH:month} %{MONTHDAY:day}, %{YEAR:year} %{TIME:time} (?<ampm>[AP]M) %{GREEDYDATA:category}\n%{LOGLEVEL:level}: \[%{GREEDYDATA:ip}\]:?(?<port>[0-9]{0,5}) \[%{GREEDYDATA:groupname}\] \[%{GREEDYDATA:version}\] ?%{GREEDYDATA:message}"
      }
      overwrite => [ "message" ]
    }
    mutate {
      add_field => {
        "datetime" => "%{year} %{month} %{day} %{time} %{ampm}"
        }
    }
    date {
      match => [ "datetime", "yyyy MMM dd h:mm:ss a" ]
      timezone => "America/Santiago"
      remove_field => [ "year", "month", "day", "time", "ampm", "datetime" ]
    }
  } else if [beat][name] == "elasticsearch" {
    grok {
      match => {
        "message" => "\[%{TIMESTAMP_ISO8601:datetime}\]\[%{LOGLEVEL:level} ?\]\[%{NOTSPACE:category} *\] \[%{WORD:nodename}\] %{GREEDYDATA:message}"
      }
      overwrite => [ "message" ]
    }
    date {
      match => [ "datetime", "ISO8601" ]
      timezone => "America/Santiago"
      remove_field => [ "datetime" ]
    }
  } else if [beat][name] == "nginx" {
    grok {
      match => {
        "message" => "\[%{HTTPDATE:time_local}\]\[%{IPORHOST:remote_addr}\]\[%{GREEDYDATA:request}\]\[%{INT:status}\]\[%{INT:body_bytes_sent}\]\[%{GREEDYDATA:http_user_agent}\]"
      }
    }
    date {
      match => [ "time_local", "dd/MMM/YYYY:HH:mm:ss Z" ]
      remove_field => [ "time_local" ]
    }
    geoip {
      source => "remote_addr"
    }
    useragent {
      source => "http_user_agent"
    }
  }
}

output {
  elasticsearch {
    hosts => "elastic:9200"
  }
}

Por supuesto, es acá donde ocurre toda la magia, por ejemplo el filtro geoip permite sacar informaciones geográficas de las IP que aparecen en los logs de Nginx, el filtro useragent sirve para formatear el http header user-agent en el tipo de navegador que ocupan los clientes.

El filtro grok, sin duda el más importante, permite separar los diferentes campos que lleva cada mensaje del log, gracias a expresiones regulares, que ocupan un formato bien particular.

Resultó muy útil ocupar este tester online: http://grokconstructor.appspot.com/do/match, que permite probar la sintaxis del pattern grok con extractos de su archivo log. Kibana en sus últimas versiones, también incluye un debugger de grok patterns.

El filtro date también es muy importante ya que permite asignar a cada entrada del log la fecha real en la cual sucedió el evento, sin eso, por defecto se le asignaría la fecha de entrada en Logstash que no es necesariamente pertinente.

En un próximo post, introduciremos el stack EFK, que es más adecuada para recolectar y centralizar los logs en un entorno basado en contenedores Docker.

(Español) Emular secuencias en MySQL

Sorry, this entry is only available in European Spanish. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Ayer, debido a una necesidad para un proyecto en que estoy trabajando, me encontré nuevamente con la falta de sequences en MySQL. Generalmente este problema se resuelve utilizando campos con la característica autoincrement, pero aún así hay ocaciones en que eso no resuelve la problemática. Como me ocurrió a mi.

Buscando un poco en google me encontré con un enlace muy interesante en donde resuelven el problema de forma más que convincente. La probé y me funcionó a la perfección. En enlace en cuestión es :

https://www.convert-in.com/mysql-sequence.htm

La solución, muy distinta a lo acostumbrado que es tener un tabla con un único campo al que se le obtiene el Max Value y luego se incremente en “1”, consiste en (como el título de este post lo indica) emular una secuencia tal cual funciona en Oracle o en PostgreSQL.

Primero que todo, se debe crear una tabla para guardar todas nuestras sequences, de forma similar a como lo hace Oracle o Postgres (tras bambalinas).


CREATE TABLE `sequence` (
    `name` varchar(100) NOT NULL,
    `increment` int(11) NOT NULL DEFAULT 1,
    `min_value` int(11) NOT NULL DEFAULT 1,
    `max_value` bigint(20) NOT NULL DEFAULT 9223372036854775807,
    `cur_value` bigint(20) DEFAULT 1,
    `cycle` boolean NOT NULL DEFAULT FALSE,
    PRIMARY KEY (`name`)
) ENGINE=MyISAM;

Puedes cambiar el ENGINE a InnoDB dependiendo de la versión de MySQL o MariaDB que estés utilizando.

Cada campo representa lo siguiente:

  • name: Nombre de la sequence que se está configurando.
  • increment: Valor incremental que se utilizará cada vez que use nuestra sequence.
  • min_value: Valor mínimo de la sequence.
  • max_value: Máximo valor que puede tomar la sequence.
  • cur_value: Valor inicial con que se configura la secuencia (start value ¿les suena?).
  • cycle: Permite determinar si llegado al max_value, la sequence comieza en su min_value nuevamente o no.

Luego se procede a crear nuestra primera sequence, que para este ejemplo será ejemplo_seq.


INSERT INTO sequence
    ( name, increment, min_value, max_value, cur_value) 
VALUES 
    ('ejemplo_seq', 1, 1, 100, 1);

Ahora toca generar la función nextval. Sí, nextval. Dijimos que emularíamos
una secuencia y esa es la forma correcta de trabajar con ellas.

Para ello se crea una function en MySQL que se encargará de consultar el valor a utilizar y de actualizar el valor. Tal cual funcionan las sequences.

DELIMITER $$
CREATE FUNCTION `nextval` (`seq_name` varchar(100))
RETURNS bigint NOT DETERMINISTIC
BEGIN
    DECLARE cur_val bigint;
 
    SELECT
        cur_value INTO cur_val
    FROM
        sequence
    WHERE
        name = seq_name;
 
    IF cur_val IS NOT NULL THEN
        UPDATE
            sequence
        SET
            cur_value = IF (
                (cur_value + increment) > max_value OR (cur_value + increment) < min_value, IF ( cycle = TRUE, IF ( (cur_value + increment) > max_value,
                        min_value, 
                        max_value 
                    ),
                    NULL
                ),
                cur_value + increment
            )
        WHERE
            name = seq_name;
    END IF; 
    RETURN cur_val;
END;
$$

En este paso ya tenemos nuestra sequence creada y lista para funcionar por medio de la función nextval. Sólo queda probarla. Para esto, tal cual lo haríamos en un motor de base de datos que cuenta con esta característica, utilizaremos simplemente:

select nextval(‘ejemplo_seq’);

Espero les sirva y lo encuentren tan útil como yo.

Saludos!

(Español) ¿Máquina Virtual o Docker?

Sorry, this entry is only available in European Spanish. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Introducción

Ha transcurrido ya un buen tiempo, desde que empezamos a experimentar el desarrollo con Docker en nuestros proyectos, ya sea como plataforma de desarrollo o en la automatización de procesos.  Poco a poco, hemos ido comprendiendo la diferencia entre virtualización y “contenerización”, un ejemplo claro que aplica, es cuando intentamos levantar un ambiente de desarrollo con múltiples dependencias en un nuestras estaciones de trabajo, mientras que la virtualización conlleva a crear múltiples instancias (de acuerdo a necesidades), éstas generalmente exigen una cantidad importante de recursos que se traducen finalmente en un detrimento considerable en la experiencia del usuario y el desempeño de la máquina. Por su parte, la “contenerización” (docker) busca optimizar bastante bien los recursos limitados de nuestras máquinas, permitiendo que virtualmente se transformen en pequeños data center (guardando las proporciones) y se compartan recursos comunes entre servicios independientes (contenedores).

Pero ¿qué es Docker y en qué se diferencia de la virtualización?

Existen diferencias importantes: Una máquina virtual hace uso de un hypervisor para acceder al hardware físico del huésped, con el objeto de ejecutarse como si fuese una máquina física independiente; los recursos utilizados están previamente definidos en su configuración y son utilizados en su totalidad durante su ejecución, es decir, si se configuro la máquina con 4GB de RAM, ésta reservará la totalidad de memoria de la máquina huésped para su ejecución. Como consecuencia de ello, y una vea esté definida la configuración de la máquina virtual, solo queda administrar de buena manera las aplicaciones que se ejecutan dentro de ellas, y que éstas saquen el mejor provecho de los recursos asignados; si una aplicación toma menos recursos, éstos estarán disponibles en la máquina virtual pero no para la máquina huésped.

Hasta este punto, podemos deducir que las máquinas virtuales están mas orientadas a plataforma que hacia aplicación en si.

Docker por su parte, usa una forma muy diferente de interactuar con la maquina huésped.  Al igual que el software de virtualización posee una especie de hypervisor, que sirve de interfaz con el hardware subyacente, pero trabaja de forma muy distinta; lo que hace Docker es generar un wrapper, sobre el cual se ejecuta un único proceso, de ahí viene el nombre de contenedor, ya que éste “contiene” un micro ambiente de ejecución para una aplicación. Éste ambiente de ejecución, provee acceso a librerías de Sistema Operativo, a filesystem, a archivos de configuración y variables de ambiente. Cada contenedor se ejecuta sobre alguna distribución de SO Linux o Windows (ahora último), esta distribución es llamada imagen, y contiene toda la configuración necesaria para que una aplicación se ejecute tal como si la aplicación estuviera corriendo sobre una maquina virtual.

Contenedor

Un contenedor es una especie de wrapper que aísla el proceso a ejecutar de la máquina huésped. Este contenedor, encapsula una imagen de sistema operativo, posee acceso a filesystem y a recursos de hardware de la máquina huésped como si se tratara de un recurso independiente, pero que en ningún caso tiene acceso o conocimiento directo sobre el huésped.

La ventaja del contenedor es que éste solo ocupa los recursos que necesita la aplicación para ejecutarse, y a pesar de estar corriendo sobre una imagen del Sistema Operativo, no inicia otros procesos ajenos a la aplicación.

Docker provee acceso a la aplicación en ejecución, a las liberarías que éste pudiera necesitar, a montar ciertos volúmenes para realizar actividades de lectura y escritura (R/W) e incluso montar volúmenes desde el huésped para persistencia de datos.  En pocas palabras, Docker provee un ambiente de sistema operativo de solo lectura, para ejecutar un solo proceso que sin cargar nada mas que lo necesario, utiliza los recursos de Hardware que necesita dicho proceso.

¿No queda clara la diferencia?

Bueno, hasta acá probablemente sea un poco confuso, pero planteémonos el siguiente caso: Existe un programa que su ejecución toma hipotéticamente el 10% de CPU y 250M de Memoria. Por un lado, tenemos una máquina virtual con Linux Ubuntu con 4GB de Memoria y le dimos el 50% de nuestra CPU para su ejecución.  Si ejecutamos este programa sobre esta máquina virtual el proceso tomará el 10% de la CPU y 250MB de la memoria asignada para esta, pero para la maquina huésped no habrá ninguna diferencia por que ya hay 4GB y el 50% de la CPU reservado para esta maquina virtual.

Ahora bien, si ejecutamos a través de Docker, este proceso tomará 250MB del total de la memoria de la maquina huésped (quizá un poco mas por alguna que otra librería que necesite cargar para su ejecución) y el 10% de la memoria del huésped (también un poco más sumando la memoria que necesita Docker para correr).

Otras Diferencias

Como lema, Docker propone “Build, Ship and Run”, Construir, exportar ejecutar. Esto es sin duda, una de las ventajas mas considerables, ya que la habilidad de desarrollar una aplicación que se pueda exportar con todo su ambiente configurado e independiente, ahorra un montón de dolores de cabeza, sobre todo en ambientes donde conviven muchas aplicaciones, y cada una de ellas no debe afectar a las demás.

El lector seguramente podría pensar… Pero esto también se puede hacer con una maquina virtual!. Si, efectivamente se puede hacer, pero acá llegamos a otra ventaja importante, ya que el transporte de una máquina virtual es más complicado debido a su gran tamaño; Se necesita bastante tiempo y espacio para copiar una máquina en otro ambiente.  Docker, simplifica esto a nivel de archivo, es decir a partir de un archivo la máquina se construye bajando las imágenes de Sistema Operativo desde repositorios (Docker HUB) en Internet, por lo que solo basta este archivo plano para generar todo el ambiente.

Conclusión

Podemos concluir que la diferencia entre la tecnología de contenedores y la de virtualización es que la primera esta orientada a aplicación, mientras la segunda hacia la plataforma y por tanto, se puede ejecutar Docker container dentro de una maquina virtual perfectamente.

Docker provee un wrapper para hacer creer a la aplicación está sobre un ambiente específico, donde provee sistema operativo, recursos de Hardware y acceso a librerías. En cambio, la virtualización provee una ambiente completo, no solo de aplicación, sino también de los servicios que el sistema operativo tiene montados como entidades independientes.

Al momento de elegir, es importante considerar que ambas tecnologías tienen enfoques distintos, pero que también pueden ser complementarias, y que muchas veces las combinación de las dos es adecuada para los escenarios complejos a los que nos enfrentamos día a día.

Monitor your containers with Portainer

Portainer is an open-source web application, which allows to handle easily your Docker containers.
In a nutshell, it let you do all the same than the Docker client, but with a nice and intuitive web interface.

Install Portainer

docker pull portainer/portainer

There is a Windows version too (portainer/portainer:windows)

Run Portainer

docker run --name portainer -d \
    -p 9000:9000 \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v portainer_data:/data \
    portainer/portainer

The port mapping is used to make the web interface accesible at port 9000.
The first volume mapping is used to give access Portainer on the socket for the docker engine (this won’t work on Windows).
The second volume mapping is used to keep Portainer internal data.

Access Portainer

Go to http://localhost:9000 in your favorite browser.

At start, Portainer will ask you for the admin password:

Then it will ask you this password to init the session:

Afterwards comes this screen:

Select “Manage the Docker instance where Portainer is running”:

This means that Portainer will monitor the containers of the host machine where he is running.
The other option allows connect on a remote Docker host.
Warning: This will not work on Windows host, because Windows use named pipe instead of unix socket to expose its Rest API and Portainer does not support it right now.

Click on “Connect” and the Dashboard of Portainer shows up:

We will check the images first: click on Images:

That´s what we could see in a terminal with the command:

docker image ls

or

docker images

But there are some advantages:
– You can sort images by size or tag, when in the terminal they always display sorted by date.
– An image with two tags would display two lines in the terminal, here two tags show up in the same line.
– This screen make it easy to delete images, using those checkboxes and the “Remove” button.
– Be able to filter images by part of their tag is really useful when you have a bunch.

Clicking on the ID of an image gives more details on it:

Here you can see useful data like ports and volumes that the image exposes.
You can add and delete tags for the image too.

Now we will see the containers, clicking on Containers of the lateral menu:

Here you can stop, remove, restart, pause kill container and run new ones.
As with images, this list view with filter and sort abilities is very convenient.
Y like for images you can see the details of a container clicking on its name:

On this screen you can:
– See informations of the container (docker inspect)
– Save the container into a new image (docker commit)
– See the logs of the container (docker logs)
– See the statistics of the contenedor (docker stats)
– Log in the contenedor (docker exec), but with bash or sh only.
– Disconnect the container out of a network (docker network disconnect)
– Y all commons operations like stop, pause, unpause, kill, remove the container

The screens “Volumes” and “Networks” allow to list, delete or add volumes and networks:

The “App Templates” screen make it easy to create containers, it purposes some templates to quickly config Redis, MongoDB, Postgres, Nginx, ElasticSearch, among others.


As an example, we will click on the “WordPress” logo, yeah, a little form shows up, but that form has a “MySql Database host” field asking to select a container, and I don’t have one, so we will first setup a MySql clicking on the “MySql” logo, here it justs asks for a name and the root password, that, I can handle:


Click on “Create” to finalize, Portainer redirects to the containers list and here is MySql !
Now I can go back to the WordPress template and give it the “MySql Database host” and the MySql password:


Click on “Create” to finalize, and you’ll be redirected to the containers list:

I got my WordPress running, and I can access it clicking on the port number which is in the “Published Ports” column where it says 32769:80 in my screenshot:

That was so easy ! 🙂

Conclusion

Portainer is a nice tool that allows to handle Docker containers really intuitively, on Windows included and on remote servers.
It is ideal for those who are not comfortable with the terminal command line and it allows to do almost all the things you do with the docker-cli.
I recommend you try it

More information on http://portainer.io/overview.html

(Español) Soapui mocks sobre https con apache y centOS 7 desde cero

apache-soap-letsencrypt-centos

Sorry, this entry is only available in European Spanish. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Continuando con la serie de servicios mocks con soap-ui, nuestro próximo paso es agregar conexiones seguras https con un certificado gratis emitido por letsencrypt.

Partimos nuestro procedimiento desde un CentOS 6.8, pero a pesar que seguimos un procedimiento similar al que se va a describir, el certificado siempre quedaba inválido, indicando que “Common name” no correspondía al nombre del host (Lo cual era cierto, hablando del archivo /etc/hosts, pero finalmente el certificado que se deseaba emitir correspondía a un subdominio con un registro DNS tipo A, apuntando a la IP de la máquina), considerando ésto, y sumado a las vulnerabildiades con esa distribución al POODLE attack, migramos a CentOS 7.1.1503 (Core).

Bueno, manos a la obra. Como lo indica el post, es desde cero, así que vamos a suponer que tenemos nuestro SO recién instalado con cuenta root. Lo primero será entonces crear una cuenta de usuario con permisos de sudo.

Sistema Operativo

# Instalar sudo para agregar el usuario a los sudoers de la máquina
$ yum install sudo
# Crear el usuario y asignarle un password, así mismo, agregarlo al grupo wheel, 
# que en CentOS por defecto tiene privilegios de sudo
$ adduser username
$ passwd username
$ usermod -aG wheel username
# Instalar crontab para ejecutar la renovación programada del certificado
$sudo yum -y install cronie
# Subir el demonio de crontab:
$ sudo service crond start

De ahora en adelante, conectarse (ssh) con ese usuario, y ejecutar los comandos que requieren privilegios con sudo

Apache

Para la instalación y configuración de apache, se siguió el siguiente procedimiento:

# Instalación de apache
$ sudo yum install httpd
# Instalación de mod_proxy_html para el proxy reverso que va a ir desde apache a soapui
$ sudo yum install mod_proxy_html
# Instalación de mod_ssl que servirá para levantar apache en modo seguro (puerto 443)
$ sudo yum -y install mod_ssl
# Habilitar apache como servicio cada vez que suba
$ sudo systemctl enable httpd.service

Es importante activar mod_ssl, en caso contrario, un error común obtenido con el certbot de letsencrypt será:

Failed authorization procedure. subdomain.domain (tls-sni-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: Failed to connect to XXX.YYY.ZZZ.OOO:443 for TLS-SNI-01 challenge

Activar el módulo proxy

# Hacer una copia de la configuración por defecto
$ cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.bk
$ sudo vi /etc/httpd/conf/httpd.conf

Buscar por la posición adecuada para agregar las directivas LoadModule y adicionar:

LoadModule proxy_html_module modules/mod_proxy_html.so

Agregar un nuevo archivo de virtual host

$ vi /etc/httpd/conf.d/vhost.conf 

Si hay un firewall activo, permitir el tráfico a apache por el 443 así:

firewall-cmd --add-service=https --permanent
firewall-cmd --reload

En este punto, se asume que la instalación de soap-ui está completa y se ha logrado subir el mockservicerunner de manera exitosa, como recomendación repasar este post y dependiendo en que puerto y contexto esté corriendo la instancia de soapui, agregar:

<VirtualHost *:80>
     ServerName subdomain.domain.com
     ProxyPass /context-path http://0.0.0.0:9090/context-path
     ProxyPassReverse /context-path http://0.0.0.0:9090/context-path
     ErrorLog /var/www/html/my-folder/logs/error.log
     CustomLog /var/www/html/my-folder/logs/access.log combined
</VirtualHost>
# Crear la carpeta de logs referida anteriormente
$ sudo mkdir -p /var/www/html/my-folder/logs    
# Reiniciar apache
$ sudo service httpd restart
# O también, así:
$ sudo systemctl restart httpd.service

Probar que la configuración tenga efecto, para ello se recomienda hacer un llamado a uno de los servicios que se tenga en los mock services, ya no usando el puerto del mock, sino el 80, donde apache haría la magia del proxy reverso enviando la petición. Un ejemplo de llamada exitosa con postman sería:

Certificado

Nuestro último paso es la instalación del certificado usando el servicio gratis de letsencrypt (Usando la configuración Apache + CentOS 7). Recordar que la emisión de este tipo de certificados se hace hasta por 3 meses y luego expirará, por lo que es necesario ir renovándolo.

Lo primero es habilitar el repositorio EPEL (Extra Packages for Enterprise Linux) que para usuarios de centOS se hace con:

$ sudo yum install epel-release

Luego instalar el Certbot de apache de letsencrypt

$ sudo yum install python-certbot-apache

Ahora, permitiendo que bot haga los cambios de forma autónoma (el otro modo es usando el modificador certonly)

$ certbot --apache

Se ejecutará un asistente que guía el proceso de creación:

  1. Los logs serán almacenados en una ruta como /var/log/letsencrypt/letsencrypt.log,
  2. Se confirma los nombres para emitir el certificado (datos extraídos de vhost.conf)
  3. Se obtiene el certificado y se hace la validación del mismo (tls-sni-01).
  4. Se genera la clave de tamaño 2048 bits, y se almacena en una ruta similar a /etc/letsencrypt/keys/0000_key-certbot.pem
  5. Se genera el CSR (Certificate Signing request) y se almacena en /etc/letsencrypt/csr/0000_csr-certbot.pem
  6. Se habilita apache para operar en el puerto 443 agregando un nuevo virtual host SSL en la carpeta
    /etc/httpd/conf.d/vhost-ssl.conf (Se agrega el sufijo -ssl al archivo original)
  7. Se consulta si HTTPS será opcional, Easy permitirá accesso HTTP como HTTPS, mientras que Secure no permitirá HTTP
  8. Felicidades! El certificado fue almacenado en /etc/letsencrypt/live/subdomain.domain.com/fullchain.pem

Revisemos el archivo generado en la configuración de apache, donde se puede validar en donde quedan finalmente los certificados, la cadena y la llave privada.

<IfModule mod_ssl.c>
<VirtualHost *:443>
     ServerName subdomain.domain.com
     ProxyPass /context-path http://0.0.0.0:9090/context-path
     ProxyPassReverse /context-path http://0.0.0.0:9090/context-path
     ErrorLog /var/www/html/sodexo/logs/error.log
     CustomLog /var/www/html/my-folder/logs/access.log combined
SSLCertificateFile /etc/letsencrypt/live/subdomain.domain.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/subdomain.domain.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateChainFile /etc/letsencrypt/live/subdomain.domain.com/chain.pem
</VirtualHost>
</IfModule>

Siempre se recomienda validar la validez del certificado usando un servicio que provee Qualys SSL Labs, usando la siguiente URL. Si todo está ok, y el rating del certificado es trusted, y ojalá con rating A, estamos listos para que el certificado sea aceptado por browsers y otros clientes.

Reiniciar apache de nuevo y validar que los servicios respondan ahora correctamente (con postman):

$ sudo service httpd restart


Respuesta esperada: 200 OK

Por último, programar la entrada de renovación del certificado para evitar que se invalide luego de los 3 meses, para ello:

# Validar que el demonio este arriba 
$ pgrep cron 
# La salida anterior no debería ser blanca, sino el PID del demonio cron<<</span
$ sudo crontab -e

Agregar la siguiente línea, que se ejecutará todos los lunes a las 2:30 am y si el certificado está por expirar, lo renovará automáticamente.

30 2 * * 1 certbot renew >> /var/log/le-renew.log

Cuando el certificado aún tiene la suficiente vigencia, en el log sale algo como:

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/vhost.conf
-------------------------------------------------------------------------------
The following certs are not due for renewal yet:
  /etc/letsencrypt/live/subdomain.domain.com/fullchain.pem (skipped)
No renewals were attempted.

Referencias

twitterFacebooklinkedin

(Español) Docker on Windows

Sorry, this entry is only available in European Spanish. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Es importante hacer la diferencia entre Docker for Windows y Docker on Windows.

  • Docker for Windows permite usar contenedores Linux en una máquina Windows 10.
  • Docker on Windows permite usar contenedores Windows en una máquina Windows Server 2016.

En este post, voy a describir cómo se puede usar Docker on Windows

Instalar Docker

Los contenedores Windows funcionan únicamente en Windows Server 2016, para hacer pruebas se puede conseguir una versión de evaluación de 180 días en la web de Microsoft.

Antes de activar el servicio docker, se necesita descargar las últimas actualizaciones de Windows
2016, luego en PowerShell (y siendo administrador), entrar los comandos siguientes :

Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module -Name DockerMsftProvider -Force
Install-Package -Name docker -ProviderName DockerMsftProvider -Force
Restart-Computer -Force

(Windows también tiene su package manager ahora)

Como el último comando lo deja suponer, se necesitará reiniciar la máquina.

Esto instala el servicio docker (docker daemon) y el cliente docker.

Descargar las imágenes de base

Microsoft provee dos imágenes que se puedan usar como base para un contenedor Windows:

  • microsoft/windowsservercore
  • microsoft/nanoserver

La primera lleva un servidor Windows con todas sus funcionalidades, la segunda es una versión mucho más liviana, y lógicamente con menos funcionalidades.

La versión completa ocupa casi 10 Gb, así que dura bastante la descarga.

docker pull microsoft/windowsservercore

La versión NanoServer ocupa casi 1 Gb, lo que la hace mucho más conveniente para trasladarla o para un uso en el cloud por ejemplo, así que cuando se puede se debería preferir esa.

docker pull microsoft/nanoserver

(Acá se puede ver que docker se puede levantar/bajar usando net start/stop como cualquier servicio, y que el cliente docker se puede usar como en Linux)

Construir una imagen con una máquina virtual Java

Para construir una primera imagen vamos a descargar una JDK y agregarla en una imagen de base NanoServer.

En una carpeta dedicada, se copia la JDK y se crea un archivo Dockerfile (sin extensión), con el contenido siguiente:

FROM microsoft/nanoserver

MAINTAINER Guillaume Mayer <gmayer@arkho.tech>

SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]

COPY jdk1.8.0_112 c:/jdk1.8.0_112

ENV JAVA_HOME c:\\jdk1.8.0_112

RUN $newPath = ('{0};{1}\bin' -f $env:PATH, $env:JAVA_HOME); \
 Write-Host ('Updating PATH: {0}' -f $newPath); \
 setx /M PATH $newPath;

  • Esa imagen ocupa la de Microsoft NanoServer como base
  • Se define PowerShell como shell por defecto
  • Se copia la JDK en la raíz (C:)
  • Se define la variable de entorno JAVA_HOME
  • Se agrega JAVA_HOME\bin al PATH

Hay que ser cuidadoso con las rutas con anti-slash (\) porque también es el carácter de escape de los dockerfiles, por eso se deben doblar.

Para construir esta imagen, se puede llamar el comando siguiente (parado en la carpeta que lleva el Dockerfile):

docker build -t java:8-nanoserver .

La option -t permite dar un nombre (tag) a la imagen.

Se puede probar la imagen con el comando siguiente:

docker run -it --rm java:8-nanoserver

(Las opciones -it permiten simular un terminal interactivo, la opción –rm le dice a docker de borrar el contenedor cuando
no se usa mas)

(Se puede ver que la carpeta del JDK fue copiada en la raiz de C: , que la variable de entorno apunta correctamente y que java funciona)

 Construir una imagen con una aplicación

Ahora que tenemos una imagen con Java funcionando, vamos crear otra que haga algo, un hello world en Spring Boot por ejemplo.

En este caso, es una aplicación que funciona con Jetty en modo standalone, y que responde “Hello, world!” cuando se llama al URL http://localhost:8080/hello/world

src/main/java/hello/HelloController.java :

package hello;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.PathVariable;

@RestController
public class HelloController {

  @RequestMapping("/hello/{name}")
  String hello(@PathVariable String name) {
  return "Hello, " + name + "!";
  }
}

src/main/java/hello/Application.java :

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(applicationClass, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(applicationClass);
    }

    private static Class applicationClass = Application.class;
}

Archivo pom.xml :

<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>hello-world</artifactId>
<version>0.1.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<version>1.4.3.RELEASE</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

En otra carpeta dedicada, copiamos el jar y creemos otro Dockerfile con este contenido:


FROM java:8-nanoserver

MAINTAINER Guillaume Mayer <gmayer@arkho.tech>

COPY hello-world-0.1.0.jar c:/hello-world-0.1.0.jar

EXPOSE 8080

ENTRYPOINT java -jar hello-world-0.1.0.jar
  • Esa imagen ocupa la imagen con Java 8 previamente construida
  • Se copia el archivo JAR
  • Se expone el puerto 8080 (donde corre la app Spring Boot por defecto)
  • Se define el comando que se ejecutara al arrancar el contenedor (levantar la app Spring Boot)

Para construir la imagen :

docker build -t hello .

Para arrancar el contenedor :

docker run --name hello -d -p 8080:8080 hello

Acceder al contenedor

En Windows, los contenedores corren por defecto en un network de tipo “nat”.

Cada uno tiene su IP y no se puede acceder al contenedor directamente usando localhost como en Linux.

Para averiguar la dirección IP del contenedor se debe usar el comando docker inspect:

docker inspect hello

o

docker inspect -f {{.NetworkSettings.Networks.nat.IPAddress}} hello

Y se puede comprobar que la aplicación funciona :

 
twitterFacebooklinkedin
 

(Español) El Café extraterrestre

Sorry, this entry is only available in European Spanish. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

 

Nuestro compañía siempre, pero siempre esta buscando la forma de buscar nuevos y más eficientes métodos para hacer mejor las cosas y el café no escapa a este afán de mejora.  Es por eso que voy a comentarles acerca de nuestro nuevo método de hacer café nivel extraterrestre, que gracias a nuestro compañero Aldemar, tenemos un nuevo descubrimiento para compartir.

Este nuevo método se llama “Café al vacío” que si bien puede no sea realmente nuevo, lo fue para nosotros, tanto que nos llevó a rebautizarlo como “extraterrestre”. Aunque diría que por los utensilios, esto ser vería mas parecido a un laboratorio de la serie “Breaking Bad”.

Bueno, en que consiste el método: Normalmente el café es realizado al vapor, filtración, presión (café italiano)… Pero este utiliza las leyes de la física para su realización.

El utensilio es muy parecido a la tetera italiana donde el agua va bajo el recipiente con el café, separado por un filtro. Hasta este punto parecen ser similares. Sin embargo, la tetera italiana contiene un tubo de seguridad que impide que el café vuelva.

Una vez montado todo se calienta el agua con un mechero o cocinilla de butano en la parte inferior. Esta al calentarse genera presión de vapor la que hace subir el agua caliente al recipiente del café, mezclándose ambos por el tiempo que dura en pasar toda el agua hacia el recipiente superior (aproximadamente 5 minutos).

1.- Etapa de Presión

Una vez que toda el agua queda en el recipiente superior comienza el trabajo inverso, al condensarse el vapor residual, éste se convierte en vacío dentro del recipiente de agua. Este vacío hace que el agua caliente que esta mezclada con el café en la parte superior sea succionada a través del filtro nuevamente al recipiente inferior. El resultado es: un delicioso café muy bien filtrado, mezclado con un sabor extraterrestre.

2. Etapa de Vacío

 

 

(Español) Metodologías GIT – Centralized Workflow

Sorry, this entry is only available in European Spanish. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Este es el primero de una serie de artículos que haré sobre las distintas metodologías que al momento de redactar estas líneas son ampliamente conocidas y discutidas en el mundo T.I para el trabajo con el también conocido control de versiones GIT.

Si bien ni este documento ni los siguientes pretenden ser un tutorial de GIT, de igual forma se abarcarán algunos tópicos y comandos básicos (o avanzados dependiendo de lo que se requiera mostrar)  como complemento de la metodología tratada.

 

Centralized Workflow

Se trata del workflow o estrategia de trabajo más simple que veremos en esta serie. Desde mi punto de vista, es el paso lógico de adaptación/transición si es que vienes de un sistema de control de versiones como SVN y pretendes comenzar a utilizar GIT.

Esta metodología consiste en mantener un único repositorio y una única rama sobre la cual los desarrolladores van subiendo sus cambios.

Pese a ser tan simple y tener ciertas similitudes, esta metodología aún nos permite visualizar algunas ventajas sobre SVN, por ejemplo, cada desarrollador puede trabajar y hacer commits en su copia local sin afectar el trabajo de los demás hasta el momento de hacer push sobre el branch remoto.

 

Workflow-centralized-image

 

Operación

Tal como mencioné anteriormente, esta metodología trabaja con un único branch Master, similar al trunk si hacemos la analogía con SVN. La primera gran diferencia, es que cada desarrollador puede generar cuantos commits estime necesarios en su rama local hasta llegar a una funcionalidad completa, para sólo entonces hacer un “push” al repositorio. Todo esto sin afectar el trabajo de los demás, ya que todos los cambios pequeños se hicieron localmente.

En general, los pasos para trabajar con esta metodología (o workflow) son los siguientes:

  1. Cada desarrollador realiza un clone de la única rama del proyecto, en este caso Master,  en su working copy para trabajar de forma local.
  2. Un desarrollador crea, modifica o elimina código con la finalidad de completar una historia de usuario, suponiendo que estamos trabajando con Scrum. Para esto puede generar tantos commits en su branch local como estime conveniente, como ya se dijo, sin afectar el trabajo de los demás miembros del equipo.
  3. Una vez que el desarrollador tiene código listo para liberar, hace un último commit sobre su rama local y posteriormente realiza el push a la rama Master remota, quedando de esta forma el código sincronizado y listo para que los demás miembros del team puedan actualizar su código fuente también.

 

Ejemplo

Con el fin de aterrizar un poco más esta estrategia de trabajo, veremos un ejemplo con un proyecto Libros  en el que está trabajando un equipo de tres desarrolladores: Marcelo, Javier y Jimmy.

Para tales efectos, tenemos entonces un repositorio único cuya rama principal Master será la que cada miembro del equipo debe clonar para tener una copia en su equipo.


$ git clone https://gitlab.com/company/mi-proyecto-prueba

Una vez que tenemos el código en nuestro equipo local, cada desarrollador del equipo comienza a trabajar.

Jimmy será el primer miembro del equipo que haga un push sobre el repositorio remoto. No encontrará mayores problemas ya que dicho repositorio se encontrará exactamente igual al momento de hacer el clone. Por esto, será un push absolutamente limpio.


$git commit -m "últimas modificaciones antes de hacer push"

$git push master origin

Cuando el segundo miembro del equipo, que esta vez será Marcelo, llegue a la fase de hacer push de SU código al repositorio, podría encontrarse con el primer problema. Jimmy en su trabajo de implementación de la funcionalidad “búsqueda de libros” ha debido agregar métodos a la clase Libro.

Marcelo por su parte ha debido crear también métodos y atributos que permiten hacer una reserva, para lo cual realizó cambios también en la clase Libro.


$git commit -m "Reserva de libros finalizada"

$git push origin master

Si tanto Jimmy como Marcelo tuvieron la fortuna de no modificar el mismo código dentro de la clase Libro, el push de Marcelo se llevará a cabo sin mayores problemas. Pero si la suerte no nos acompaña, y esto comenzará a suceder en la medida que los proyectos vayan avanzando y aumentando su complejidad  y el número de miembros del equipo vaya en aumento, Marcelo deberá realizar el proceso de merge del código de ambos desarrolladores para poder llevar a cabo, finalmente, el push del código ya sincronizado a la rama Master.

Ahora es el turno de Javier. Debe actualizar el código que recién acaba de terminar y, deberá hacer el mismo proceso que Marcelo para poder dejar el código del proyecto totalmente sincronizado para todos los miembros de equipo.

Resolución de conflictos

En esta metodología el problema más común que se encontrarán es la constante desactualización de código en las ramas locales, más aún cuando los equipos que modifican código de forma transversal en el proyecto. Esto debido a que la única rama remota está sufriendo constantes updates con cada push que se haga sobre ella.

Será necesario entonces contar con una buena herramienta de resolución de conflictos, como el p4merge u otra que sea de su agrado.


$git commit -m "Reserva de libros finalizada"

$git push origin master
CONFLICT (modify/delete): README.md deleted in HEAD and modified in branch-b. Version branch-b of README.md left in tree.
Automatic merge failed; fix conflicts and then commit the result.
$git merge tool

Para resolver el conflicto, hacer el commit y hacer nuevamente el push del código al repositorio remoto.

 

Ventajas

Esta metodología es especialmente útil para equipos que están cambiando de un sistema de control de versiones como SVN a Git, ya que su línea de trabajo es muy similar. No obstante las diferencias que ya se han mencionado, la utilización de esta metodología permite comprender en la marcha de un proyecto, la filosofía de Git y los comandos utilizados para la operación diaria.

 

Desventajas

La principal desventaja de esta metodología es que, como se está trabajando con un branch local que hace tracking del branch remoto, cada uno de los commits locales que un desarrollador hace pasan a formar parte también del branch remoto, dejando una rama principal (y única) muy sucia y muy compleja de analizar su historia.

 

Recomendación Experta

Como ya he mencionado en más de una oportunidad en este artículo, esta metodología me parece un excelente primer paso para migrarse a GIT ya que se está orientada a comprender el uso básico de este control de versiones. Creo importante que el proyecto que se utilice como proceso de adaptación no corresponda a un desarrollo pequeño, sino más bien un proyecto de envergadura media, de esta forma el equipo se verá enfrentado a problemas de baja dificultad como resolución de conflictos, creación de stashes, utilización de Tags, etc, que le permitan en un siguiente proyecto abordar otras metodologías con características más avanzadas de GIT.

Como último consejo, sería conveniente sobre todo al principio del proyecto, que cada desarrollador tome líneas lo más independientes posibles dentro del desarrollo, para de estar forma comprender primero los comandos a utilizar y luego, comenzar a trabajar con situaciones más complejas como los merges y rebases.