Quantcast
Channel: Planeta Código
Viewing all 2699 articles
Browse latest View live

Bitácora de Javier Gutiérrez Chamorro (Guti): El misterio con Borland Turbo BASIC 2.1


Picando Código: Documental – Two Cartoon Foxes: Remembering Why The Lucky Stiff

$
0
0

El 19 de agosto de 2009, Why the Lucky Stiff desapareció de la comunidad Ruby. Hoy se celebra el Whyday, donde la comunidad Ruby recuerda las contribuciones de _why al ecosistema y la cultura que la identifica.

Para más información pueden visitar el sitio Whyday.org o la cuenta en Twitter @celebratewhyday o seguir el hashtag #whyday.

El post Documental – Two Cartoon Foxes: Remembering Why The Lucky Stiff fue publicado originalmente en Picando Código.

Blog Bitix: El patrón de estrangulación para reemplazar aplicaciones heredadas

$
0
0

Reescribir partiendo desde cero una aplicación grande que tiene sus defectos pero que ha sido desarrollada durante mucho tiempo y su funcionalidad más importante opera mayormente bien no es una estrategia que esté exenta de riesgo ni garantiza que el el nuevo sistema tenga defectos parecidos, más graves o incluso la reescritura fracase. Si la reescritura tiene riesgos pero existe la necesidad de sustituir la aplicación heredada para solventar algunos de sus problemas es necesaria otra estrategia diferente a partir de cero. Una estrategia que se utiliza en estos casos es aplicar el patrón de estrangulación que reemplaza el sistema antiguo de forma incremental cada una de sus piezas.

Algunas aplicaciones tienen un tiempo de vida de uso muy prolongado que ofrecen una funcionalidad esencial en una empresa u organización, muchas son mantenidas durante todo este tiempo de vida añadiendo funcionalidades, modificando las existentes, corrigiendo errores, fallos de seguridad o modestas modernizaciones. Otras aplicaciones finalmente dejan de mantenerse completamente salvo errores graves. Pasado un lustro o una década con una cantidad importante de líneas de código implementadas por un equipo grande de personas probablemente las aplicaciones pueden considerarse heredadas presentando problemas en su base de código o tecnologías ya consideradas obsoletas.

Quizá llegue un momento que surge el interés de sustituir la aplicación, una opción es reescribir completamente la aplicación heredada con sus propios inconvenientes y riesgos otra opción es reemplazarla de forma incremental, en este último caso se suele utilizar el patrón de estrangulación. Los proyectos que se empiezan desde un inicio son los menos, lo habitual es tener que mantener sistemas existentes y cuando es necesario migrarlos a nuevos.

Contenido del artículo

El problema de las aplIcaciones heredadas

Algunos de los motivos para desear sustituir una aplicación son los siguientes.

  • Código heredado complicado.
  • Reglas de negocio en varias ubicaciones del código.
  • Diseño monolítico no adecuado para las necesidades actuales de rendimiento, fiabilidad u organización de equipos de desarrollo.
  • Dificultad para hacer pruebas.
  • Acumulación de deuda técnica.
  • Proceso de despliegue complicado con varios pasos manuales.

Cuando los problemas son demasiado grandes las consecuencias son que al hacer un cambio en el código existente no haya confianza de que vaya a funcionar correctamente o requiera demasiado tiempo incrementando los tiempos desde que se acepta un cambio hasta que este es aplicado en producción. Más tiempo entre despliegues agrava los problemas, el resultado es que se crea una espiral de decadencia que realimenta si no se toman medidas para evitarlo.

Reescribir o reemplazar

Entre las dos opciones al sustituir una aplicación se puede optar por reescribir la aplicación completamente desde cero o sustituir sus funcionalidades de forma incremental. La reescritura completa de una aplicación grande no está exenta de problemas y riesgos. Probablemente no sea posible dejar de dar servicio a la aplicación existente corrigiendo errores o modificaciones mientras la nueva aplicación se está desarrollando. Sustituir un sistema de un tiempo de vida de más de un lustro de vida en poco tiempo no es fácil conseguirlo en unos pocos meses ya que posiblemente tenga una base de código grande con lógica de negocio complicada embebida, la realidad es que pasado unos pocos meses después de empezada la tarea el nuevo sistema únicamente tiene un porcentaje bajo de todas las funcionalidades de la antigua, también se acumule la deuda técnica con la presión de realizar una entrega y la nueva aplicación contenga varios de los mismos problemas que la aplicación que pretende sustituir.

Como alternativa a la reescritura está el reemplazo de forma incremental de partes del sistema mientras continúa ofreciendo su servicio. La razón más importante de optar por el reemplazo es reducir el riesgo de la reescritura completa. Realizar el reemplazo de forma incremental permite realizar entregas más frecuentemente y monitorizar el progreso con más cuidado. A veces esta opción no es tomada en cuenta ya que se considera que costosa más, sin embargo, el poder realizar ciclos de entrega más cortos permite aplicar el conocimiento adquirido en cada ciclo a los siguientes y obtener valor de forma más temprana que con la reescritura completa. Para el reemplazo de forma incremental se utiliza el patrón de estrangulación.

Teniendo en cuenta que una aplicación pasado un tiempo se considerará heredada y obsoleta, las aplicaciones deberían diseñarse y estructurarse de tal forma que faciliten su sustitución en un futuro.

El patrón de estrangulación

El patrón de estrangulación permite sustituir una aplicación heredada reemplazando de forma gradual piezas específicas de funcionalidad por nuevas aplicaciones y servicios. A medida que las funcionalidades de la aplicación heredada son sustituidas, el nuevo sistema eventualmente reemplaza todas las funcionalidades del sistema heredado que es estrangulado hasta que nada de él queda ya por sustituir, lo que queda si no es necesario es posible eliminarlo.

El objetivo es reducir lentamente la dependencia del sistema heredado, el reemplazo llevará bastante tiempo pero planeado correctamente el patrón de estrangulación minimiza el riesgo y tiene menos impacto que una reescritura completa.

El patrón no es la única estrategia que ayuda a reemplazar un sistema existente otras ténicas que ayudan son utilizar un servidor mock para imitar las peticiones y respuestas mientras se desarrolla o en las pruebas unitarias y realizar pruebas de contrato para validar de forma unitaria el cliente y el servidor de un servicio.

El patrón extrangulación

El patrón extrangulación

El patrón extrangulación

Funcionamiento

El funcionamiento del patrón de estrangulación es bastante simple. El primer paso consiste en establecer un intermediario entre el código o aplicación heredado a sustituir y el cliente o usuario de este código. En el inicio de proceso de estrangulación, el intermediario simplemente delega cada petición que recibe en el código o aplicación heredado. Una vez que el intermediario está ubicado puede redirigir las peticiones a otra aplicación o componente una vez completado su desarrollo.

Por ejemplo, suponiendo que se desea reemplazar la funcionalidad de autenticación y autorización, se desarrollan los nuevos servicios de autenticación y autorización de forma completamente separada de la aplicación heredada. Para empezar usar el nuevo código, el intermediario intercepta todos los intentos de inicio de sesión y en vez de delegarlos en la aplicación heredada los delega en el nuevo servicio. Este proceso se repite para cada nueva funcionalidad, en cada reemplazo se redirigen más peticiones fuera de la aplicación heredada.

Los usuarios del servicio no deberían notar los cambios, al menos no ninguno que no sea una mejora en el servicio o que el reemplazo proporcione una nueva funcionalidad a medida que su código aumenta. Algunos servicios reemplazados dependen de nuevos repositorios de datos, es posible que haya la necesidad de coordinar ciertos datos entre los repositorios de datos de lo que queda de la aplicación heredada y el repositorio de datos de un nuevo servicio. Esta coordinación de datos es un aspecto a tener en cuenta para tratar de minimizar la redundancia de datos que facilite la transición.

En el caso de una aplicación monolítica es posible optar por una opción también monolítica pero más modular que resuelva algunos de los problemas en el código de la aplicación heredada o ya que se realiza la tarea del reemplazo aprovechar para utilizar una arquitectura de microservicios si estos se adaptan a las necesidades de la aplicación y de desarrollo en diferentes equipos independientes para que puedan trabajar de forma simultánea e independiente.

El intermediario en una aplicación monolítica es una clase fachada que delega en el código heredado, en el nuevo módulo o en un microservicio que extrae de la aplicación heredada la funcionalidad a estragular. En el caso de una aplicación heredada que funciona mediante llamadas de red como HTTP el intermediario es un proxy inverso que redirige las peticiones a la aplicación heredada o al nuevo servicio sin que los clientes sean conscientes del cambio.

Ventajas e inconvenientes

Las ventajas del patrón de estrangulación son:

  • Proporciona una forma de transformar un sistema con menos riesgo que una reescritura desde cero.
  • Los nuevos servicios se desarrollan de forma incremental.
  • Se mantienen los servicios antiguos mientras se desarrollan los nuevos.

Los inconvenientes son:

  • Requiere cuidado en el enrutado de peticiones hacia los diferentes sistemas. Cada nuevo servicio requiere adaptar la lógica del intermediario para redirigir las peticiones de la funcionalidad del viejo servicio al nuevo, cuando una aplicación está compuesta de gran cantidad de servicios es un trabajo significativo.
  • Requiere un plan de vuelta hacia para cada funcionalidad reemplazada en caso de que las casas vayan mal. Aún así esto es más sencillo y está más acotado que en el caso de la reescritura.

Que seleccionar primero para estrangular

Otra cuestión que funcionalidades de la aplicación heredada reemplazar primero. Es posible utilizar varios criterios pudiendo ser su facilidad de reemplazo, importancia, tamaño o dependencias que tenga.

Bitácora de Javier Gutiérrez Chamorro (Guti): Modula-2 (Fitted y TopSpeed)

Blog Bitix: The three ways y The five ideals de los libros The DevOps Handbook, The Phoenix Project y The Unicorn Project

$
0
0

En la trilogía de los libros The DevOps Handbook, The Phoenix Project y The Unicorn Project se explican más detalladamente varios principios para conseguir que la cadena de valor en un producto de software funcione de forma correcta y evitar en gran medida muchos problemas comunes, son los principios denominados como The three ways y The five ideals.

Una fábrica que manufactura objetos físicos en una cadena de montaje en varios pasos, pueden ser coches o mesas de escritorio, puede parecer que no tiene mucho que ver con el desarrollo de software ya que en este último no se fabrican objetos físicos sino software que es algo intangible que no tiene una representación física.

Sin embargo, en realidad una cadena de montaje de objetos físicos tiene muchos puntos en común al desarrollo de software, en ambos casos se siguen una secuencia de pasos o cadena de valor desde que llega una orden hasta que ésta es entregada al cliente. En el caso de una fábrica de coches se producen coches y en un desarrollo de software se producen funcionalidades en una aplicación.

Los mismos principios que se aplican en una cadena de valor en una cadena de montaje de una fábrica también se pueden aplicar al desarrollo de software para producir software, esos principios y metodologías permiten fabricar de forma eficiente y evitar problemas en la cadena de valor. Estos principios y metodologías identificados en varias organizaciones que tienen un gran rendimiento en su cadena de valor se resumen en The three ways y The five ideals.

Contenido del artículo

The three ways

The three ways son tres principios que se centran en el aspecto productivo, estos principios son explicados en el libro The DevOps Handbook de una forma teórica, detallada y extensa y en el libro The Phoenix Project que son el argumento subyacente de una historia de ficción sobre una empresa con problemas en sus proyectos de software, algunos son reconocibles a los que uno pueda tener en su organización.

El libro empieza con los personajes de una empresa con multitud de problemas en el desarrollo que hacen peligrar la viabilidad de la empresa en una época en la que la tecnología está transformando su negocio, a lo largo del libro y con la guía de un cierto personaje misterioso van aplicando varias mejoras de forma paulatina que les permite recuperar el control.

Parte de la base de The three ways se fundamenta o es similar los principios definidos en el libro Lean Enterprise, el movimiento ágil y el movimiento de entrega continua.

En mi experiencia profesional de típica consultoría informática no hice prácticamente ninguna de las prácticas de los libros ni siquiera lo más básico como pruebas pruebas unitarias. Sin embargo, en otra experiencia profesional de una empresa de producto quizá no todos pero muchas de las prácticas de estos principios si que los veo identificados.

Son libros muy recomendables de leer en los que se mencionan muchos otros bastante populares como Release it!, The Mythical Man Month, Continuous Delivery, The Pragmatic Programmer, Extreme Programming Explained.

The first way: The technical practices of flow

El primer principio trata sobre la efectividad del flujo de trabajo, para medirlo toma como métrica principal el tiempo entre que entra una petición y esta es entregada que se denomina como el lead time. En el caso de desarrollo de software desde se crea una petición hasta que ésta es desplegada en producción, su finalización engloba el despliegue no solo su desarrollo. Las prácticas de este principio tratan de mejorar y evitar problemas en esta métrica.

Hay que tener en cuenta que dos partes de la cadena de valor tiene objetivos diferentes, el área de desarrollo requiere de realizar despliegues de forma continua que potencialmente introducen errores, por otro lado el área de operaciones requiere que los entornos sean estables y que los servicios no tengan errores por un cambio ni caídas de servicio. Reducir la frecuencia de los despliegues para no introducir errores no resuelve los errores sino que  lo agrava al ser despliegues más grandes. La opción es automatizar en la mayor medida posible las pruebas y el procesos de los despliegues, de modo que el conjunto de cambios esté probado por las pruebas y sea más pequeño para fácil identificar la causa de un error más fácilmente y no requiera intervenciones manuales que evite esperas.

El software al ser algo intangible es más difícil de conocer su estado e identificar dónde hay algún problema en la cadena de valor. Para visualizar el estado del trabajo se emplean los paneles kanban que agrupan en columnas según el estado las peticiones, de esta forma es posible visualizar rápidamente qué peticiones han sido desplegadas, que peticiones están el la cola de despliegue, que peticiones están siendo probadas, que peticiones están en desarrollo y cuales están a la espera de ser desarrolladas. Este panel permite ver si en una determinada columna se están acumulando muchas peticiones. El panel kanban permite ver el trabajo en progreso o work in progress  en la columna de peticiones en desarrollo o ver el tamaño del lote o batch size en la columna de peticiones a la espera de ser desplegadas.

Otra forma de visibilizar el trabajo es hacer reuniones diarias que sirven para compartir información en la que cada miembro del equipo comenta en que estuvo trabajando el día anterior, en que trabajará durante el día y si existe algún bloqueo. El resto de los miembros del equipo quizá puedan ayudar a eliminar ese bloqueo o proporcionar alguna ayuda.

Conociendo el dato del trabajo en progreso y del tamaño del lote permite limitarlos, ya que si son grandes es posible que causen problemas en la cadena de valor. Por ejemplo, un trabajo en progreso muy grande ocasiona que se esté haciendo mucho trabajo pero que poco esté siendo terminado o generando problemas de cambio de contexto entre diferentes peticiones, un tamaño de lote grande es un problema ya que si hay algún problema en un despliegue será más difícil identificar cuál de las peticiones es la causante.

Para evitar entregar defectos en el siguiente paso de la cadena de valor una práctica es implementar teses unitarios del código. Otro de los problemas en la cadena de valor es el cambio de manos del trabajo o handoffs entre diferentes personas, por ejemplo de una persona de desarrollo a una de operaciones ya que se requiere coordinación y comunicación. Para evitar los problemas de los handoffs conviene automatizar en la medida de lo posible cosas como la creación de entornos de prueba o el despliegue de forma que las personas sean autosuficientes.

Para evitar riesgos en la publicación de funcionalidades éstas se pueden desplegar de forma progresiva obteniendo información de forma más temprana que en el caso de publicarla en un momento determinado de forma completa. Para ello se utilizan los feature flags que permiten activar una funcionalidad a voluntad. Publicar la funcionalidad de forma progresiva y activarla con un feature flag permite reducir el tamaño del lote y obtener feedback de forma más temprana.

También conviene eliminar trabajo desperdiciado como un exceso de peticiones realizadas pero no desplegadas, realizar peticiones que no aportan valor, realizar más de lo necesario, evitar handoffs, evitar esperas y defectos.

The first way

The first way

The second way: The technical practices of feedback

Una vez el flujo es correcto para mejorar la cadena de valor es necesario obtener información lo antes posible. Para ello se utilizan prácticas como integración continua en la que cada commit al repositorio de código fuente ejecuta los teses unitarios y de integración con el objetivo de comprobar que los cambios no introducen errores en las partes probadas del código ni errores de regresión.

Otras forma de feedback es obtener información de los sistemas mediante telemetría para comprobar el estado de los sistemas, conocer su estado normal e identificar algún tipo de problema cuando algo se está comportando de forma anómala respecto a su estado normal. También es posible utilizar pruebas A/B para comprobar si realmente una funcionalidad aporta valor o cual de varias posibilidades es la que más aporta. Por ejemplo es posible realizar una prueba A/B que permita conocer cuál de dos diseños de una página de compra genera más compras.

Otras prácticas de feedback son realizar programación en parejas o pair programming que permite evaluar otro punto de vista en el mismo momento de estar programando, revisiones de código o peer review para obtener una segunda opinión antes de aplicar los cambios en la rama principal de desarrollo o desplegar en producción. Herramientas como GitHub o GitLab facilitan estos peer review a través de los pull request.

The second way

The second way

The third way: The technical practices of continual learning

El tercer principio propone prácticas que permitan mejorar de forma continua y adquirir nuevo conocimiento. Unas de estas prácticas son crear post mortems cuando ocurra un error con un impacto en el servicio. Los post mortem permiten averiguar la causa que generó el problema y establecer acciones para evitar que ocurra en el futuro, aplicando las acciones  de los post mortem según sucedan los problemas a lo largo del tiempo deberían evitarse que sucedan los mismo problemas de forma recurrente. Los post mortem no deben ser utilizados para castigar o identificar personas culpables sino para evitar que los mismo problemas sucedan en el futuro, deben ser blameless. Y en sistemas complejos como son muchos productos de software con muchas dependencias en los que una única persona no posee el conocimiento completo problemas se producirán sin ninguna duda.

Otra opción de aprendizaje es introducir problemas de forma intencionada para comprobar se un sistema continúa funcionando aún con los errores y para aprender cómo se comporta el sistema ante esos errores, estas técnicas se denominan chaos monkey.

Para compartir información en vez de crear documentos que quedarán desactualizados es preferible crear documentación ejecutable como pruebas unitarias con ejemplo del uso de la API. En vez de utilizar correos electrónicos como forma de comunicación privadas utilizar herramientas más instantáneas y públicas como Slack o Teams e incluso utilizar bots desde estas herramientas que lancen acciones como despliegues. Al quedar los registros de las comunicaciones públicas es fácil compartir la información.

The third way

The third way

The five ideals

De los mismos autores que los libros anteriores es el libro The Unicorn Project, es una novela de una historia ficticia simultánea a la historia del de libro The Phoenix Project ambientada en la misma organización, la historia es similar con un comienzo en el que hay varios problemas, en este caso un grupo de personas forma «la rebelión aplicando también mejoras de forma paulatina que les permite retomar el control, el mismo personaje misterioso aparece en este libro.

El libro The Unicorn Project explica The five ideals con varios principios que en global The three ways añadiendo el objetivo del éxito desde el punto vista de negocio y de la organización.

The first ideal: locality and simplicity

Uno de los problemas que afecta al lead time es que en una determinada tarea sea necesario que intervengan varias personas y roles diferentes, sobre todo cuando cada una tiene sus propias tareas y prioridades. Estos cambios de manos generan tiempos de espera por cambios de contexto, comunicación y coordinación que retrasan la entrega.

Este ideal propone que la persona encargada de hacer los cambios de una tarea tenga la mayor capacidad posible para completarla con la menor ayuda de otros equipos. Hay que evitar procesos y burocracia innecesaria.

Una medida para implementar este ideal es las personas tenga a su disposición servicios en forma de autoservicio, por ejemplo si un desarrollador necesita un nuevo entorno de pruebas o desplegar en producción sea este el que pueda crearlo con alguna herramienta de forma automatizada o tenber la capacidad de hacer despliegues. A evitar sería el requerir de una persona con el rol de operaciones de forma manual cree el entorno o haga el despliegue. En este caso el rol de operaciones es proporcionar a desarrollo las herramientas necesarias para realizar las tareas de forma automatizada.

The second ideal: focus, flow, and joy

El segundo ideal indica que el trabajo no debería ser desagradable. Para que no lo sea hay que evitar esperas a que otras personas hagan cosas, estar trabajando en pequeñas cosas sin conocer su objetivo, evitar estar constantemente apagando fuegos, evitar identificar responsables cuando algo no funciona y evitar el agotamiento.

En vez de eso hay que tener visibilidad de los resultados del trabajo y tener una visión global de su impacto que sirvan de motivación, trabajar en pequeños lotes de trabajo que fluyan rápido en la cadena de valor y obtener realimentación del trabajo. Estas condiciones permiten un desempeño correcto, ser un reto, aprender y crecer como profesionales, dominar el dominio de negocio e incluso disfrutar de ello.

The third ideal: Improvement of daily work

El tercer ideal indica que mejorar el trabajo diario es al menos tan importante como el propio trabajo. Cuando se crea deuda técnica el eliminarla es tratada como una prioridad, la arquitectura es mejorada y modernizada de forma constante de modo que siga siendo posible entregar trabajo con fluidez y más valor antes, de forma segura sin miedos a hacer cambios por riesgos de generar errores y de forma agradable.

The fourth ideal: psychological safety

En el cuarto ideal es necesario que haya seguridad psicológica de tal forma que los miembros del equipo se sientan seguros al hablar de problemas, de esta forma no solo se pueden resolver sino también prevenir. Resolver problemas requiere honestidad y la honestidad requiere ausencia de miedo a ser castigado.

Los post mortem han de ser blameless de lo contrario las personas tenderán a ocultar información o no visibilizar los problemas para tratar de evitar los castigos.

The fifth ideal: customer focus

El quinto ideal trata sobre cual es el objetivo de la organización y que parte de la misma es la esencial y cuál es contextual. La esencial del negocio es la diferenciadora y por la que están dispuestos a pagar los clientes, la contextual aunque importante no es relevante para el cliente. Los esfuerzos e iniciativas más importantes de una organización deben estar dirigidos a aportar valor al cliente.

Header Files: Ajuste dinámico de imágenes en QLabels

$
0
0

El control para mostrar etiquetas de texto en Qt se llama QLabel. Además de texto, puede mostrar una imagen mediante el método QLabel::setPixmap, aunque de una forma bastante limitada. Me explico: la imagen se mostrará con una relación 1:1, por lo que estará recortada si es mayor que el widget, mostrándose más o menos dependiendo del tamaño del mismo.

QLabel cuenta con una propiedad para paliar el problema descrito arriba (aunque yo creo que lo que logra es confundir más aún): scaledContents. Al usar QLabel::setScaledContents(true) el pixmap se redimensiona dinámicamente al tamaño de la etiqueta, pero sin respetar la relación de aspecto (adquiere la relación de aspecto del widget).

Si por el contrario lo que queremos es que la imagen se escale dinámicamente respetando la relación de aspecto, entonces este artículo es para ti. La técnica consiste básicamente en crear una segunda versión escalada y centrada de la imagen original cada vez que el widget cambie de tamaño.

Escalado y posicionamiento

La parte del escalado es sencilla, ya que Qt la incorpora en QPixmap::scale. En este caso, usaremos aspectMode = Qt::KeepAspectRatio para que la imagen quede dentro de la nueva área. Si por el contrario quisiésemos que la imagen cubriese todo usaríamos Qt::KeepAspectRatioByExpanding. Además, usaremos el modo Qt::SmoothTransformation para obtener el mejor resultado posible. Es importante recordar que siempre debemos hacer el escalo sobre una copia de la imagen original para evitar degradaciones en la calidad de la misma.

Ahora toca centrar la imagen, ya que el escalado únicamente nos ajusta el tamaño, el posicionamiento es un asunto del renderizado. Para ello crearemos una imagen secundaria con el tamaño de la etiqueta, sobre la que pintaremos centrada la imagen escalada en el paso anterior:

autoimage=QImage{label->size(),QImage::Format_ARGB32_Premultiplied};// transparency required to prevent 'black' strips to appearimage.fill(Qt::transparent);// cannot use QPainter::eraseGeometry when working with a QImage as painting device// Scale imageconstautoscaled_pixmap=original_pixmap.scaled(label->size(),aspect_mode,Qt::SmoothTransformation);// Center image by computing the new originconstautosize_diff=label->size()-scaled_pixmap.size();constautotop_left=QPoint{size_diff.width()/2,size_diff.height()/2};// Render the new imageQPainterpainter{&image};painter.drawPixmap(top_left,scaled_pixmap);painter.end();

Ajuste dinámico

Por último sólo nos toca cambiar el pixmap cada vez que la etiqueta cambie de tamaño. Si bien la herencia es una opción, la forma más sencilla de realizar este procedimiento es mediante un filtro de eventos que capture el evento de cambio de tamaño (QEvent::Resize). Una sencilla clase nos puede dar esta funcionalidad:

classQLabelPixmapScaler:publicQObject{public:explicitQLabelPixmapScaler(QLabel*label,Qt::AspectRatioModeaspect_mode):QObject{label},m_pixmap{*label->pixmap()},m_aspect_mode{aspect_mode}{label->installEventFilter(this);}booleventFilter(QObject*obj,QEvent*event)override{if(obj==parent()&&event->type()==QEvent::Resize){autolabel=(QLabel*)parent();// Scale original pixmap and save on 'image'label->setPixmap(QPixmap::fromImage(image));}returnfalse;}private:constQPixmapm_pixmap;constQt::AspectRatioModem_aspect_mode;};

Ahora únicamente nos queda instalar el escalador al QLabel. Nótese que el escalador se asocia a la jerarquía de objetos de la etiqueta, por lo que no es necesario preocuparse de eliminarlo; se hará cuando se borre la etiqueta.

newQLabelPixmapScaler{label,Qt::KeepAspectRatio};

Retoques finales

La solución anterior es válida si la etiqueta siempre tiene la misma imagen, pero si ha de cambiar entonces podemos vernos en el caso de tener múltiples escaladores instalados. Para solucionarlo bastaría con borrar los anteriores cada vez que se cree uno nuevo:

setObjectName("QLabelPixmapScaler");for(autoprev_scaler:label->findChildren<QLabelPixmapScaler*>(objectName())){label->removeEventFilter(prev_scaler);}

Un ejemplo de cambio de imagen sería algo así como

newQLabelPixmapScaler{label,Qt::KeepAspectRatio};// ...label->setPixmap(/* ... */);newQLabelPixmapScaler{label,Qt::KeepAspectRatio};

Ejemplo

En este ejemplo (disponible en GitHub) se comparan los cuatro modos de escalado mencionados: sin escala, usando scaledContents, escalado dinámico por dentro, y escalado dinámico por fuera.

resize_image_qlabel

Blog Bitix: Análisis, guía y consejos del juego roguelike Darkest Dungeon

$
0
0

Si hay un juego en el que no hay una decisión perfecta o en el que hay que hacer sacrificios ese es Darkest Dungeon. Seguir avanzando en una mazmorra supone un riesgo, tocar un objeto sin la provisión adecuada puede tener efectos muy negativos, a veces para completar una misión hay que sacrificar un héroe, equiparse con un abalorio aparte de los efectos positivos la mayoría tiene efectos negativos. Darkest Dungeon es un juego difícil en el que en gran medida para completarlo hace falta conocerlo muy bien, sin una guía y consejos es muy difícil llegar al su final o requeriría mucho tiempo para aprender todos sus trucos, con algunos de ellos el éxito no está asegurado pero hay mayor probabilidad de conseguirlo. Está guía es introductoria no es exhaustiva para completarla incluye varios enlaces con mucha información para profundizar más.

Darkest Dungeon desarrollado por Red Hook Studios es uno de los mejores juegos en su categoría de rol y roguelike, destacando principalmente por sus mecánicas de juego que ofrecen gran cantidad de combinaciones y posibilidades. Es un juego difícil en el que los progresos se guardan de forma automática, de modo que las acciones realizadas no se pueden deshacer y si un héroe muere permanecerá muerto. En este juego el nivel de dificultad normal se puede considerar difícil, a lo largo del juego siempre se va al filo del desastre y en ocasiones hay tomar la decisión de que personaje es mejor que muera si es inevitable que uno lo haga, la mayoría de objetos que se encuentran y muchos curio tienen cosas negativas, aún con sus beneficios. Hay que exterminar el mal y es el precio a pagar.

Aún con su dificultad a medida que se juega se van aprendiendo sus mecánicas y funcionamiento que hace del juego más sencillo y con menos riesgos dentro de su constante dificultad que roza el estar siempre al al borde del desastre, a veces se sufren derrotas aunque hace la victoria es más satisfactoria. Su gráficos no son en tres dimensiones pero destacan por su arte y son suficientes para el juego, la música tétrica ambiental al juego en su mundo decadente y peligroso. El juego está traducido al español pero no está doblado, es posible colocar subtítulos para entender los diálogos.

Posee varias expansiones, The Crimson Court, The Colour of Madness y The Butcher’s Circus que añaden algunos héroes adicionales, nuevas localizaciones y algunas mecánicas de juego nuevas.

Está disponible tanto en PC como para consultas y en las principales tiendas digitales de juegos, en la tienda de la Epic Store estuvo gratis. Aunque es posible jugarlo en consolas, con ratón es mucho más sencillo jugarlo, con el mando el manejo de la interfaz se hace complicado por la limitación de botones y la falta de puntero.

Aún no me he pasado el juego y no he llegado al final pero ya he escrito este artículo porque este juego exige conocerlo para poder completarlo, al igual que en otros juegos de autoguardado las acciones son definitivas junto que además un error se penaliza llegando en el peor de los casos a suponer sin mucha dificultad la muerte de uno o varios héroes incluso de nivel alto. Parte de la dificultad del juego se basa en obtener conocimiento del él ya sea por experiencia, información leída o por consejos recibidos. Yo no me hubiese pasado el juego sin haber leído una guía, es muy difícil completarlo sin saber que se va a encontrar uno, sabiéndolo permite prepararse adecuadamente con los abalorios, equipo, personajes y habilidades adecuados y aún así se corre riesgo.

Un juego similar a Darkest Dungeon es el juego de rol For the King con algunas mecánicas similares de combates y exploración de mazmorras, sin embargo, Darkest Dungeon es mucho más complejo y difícil. A alguien que le guste uno de los dos juegos seguramente le guste el otro.

Pantalla inicialMenú

Pantalla inicial y menú del juego Darkest Dungeon

Anticipación del juego

Este artículo contiene información de estrategias para completar más fácilmente el juego, parte de la diversión de un juego es descubrir y superar los retos que se plantean por uno mismo. Sin embargo, algunos juegos son difíciles sin una pequeña ayuda que obliga a tener que dedicarles mucho más tiempo o a recomenzarlos.

En algunos juegos el argumento es una de las partes más importantes. El texto del artículo no contiene información acerca del argumento del juego, de la mitad o del final, ni hace ningún spoiler por lo que lo puedes leer sin riesgo de conocer alguna parte del argumento de forma anticipada. Sin embargo, algunos enlaces del artículo a otras páginas y vídeos sí pueden contener información del argumento de modo que recomiendo consultar solo las partes del juego una vez superadas.

Contenido del artículo

Héroes

Las misiones para explorar mazmorras se realizan en grupos de cuatro que hay que elegir en la preparación. Hay 16 clases de héroe distintas que reclutar entre los disponibles en los disponibles en la diligencia, cada clase de héroe tiene sus propias habilidades de combate y acampada y estadísticas base únicas entre las que se encuentran los puntos de vida los rasgos positivos y negativos, sus estadísticas de resistencias a varios efectos como aturdimiento y finalmente están las enfermedades que ha adquirido el héroe.

Algunos tienen  por su clase ciertos beneficios como la anticuaria que incluirla en un grupo permite aumentar acumular montones de dinero de 2500 en vez de 1750 y con beneficios a la obtención de objetos en las exploraciones, las anticuarias son especialmente buenas para obtener botín. Por otro lado el cruzado y la vestal tienen beneficios contra enemigos de tipo impío.

Las clases de los héroes son abominación, anticuaria, arbalestera, caza recompensas, cruzado, asaltatumbas, diabla, bandolero, maestro canino, bufón, leproso, hombre de armas, ocultista, doctor de plaga y vestal. En las expansiones del juego se añaden rompescudos, mosqueteros y flagelantes. Todos estos tipos de clases son únicos aunque algunos comparten habilidades con efectos comunes como el aturdir, causar hemorragia o infección, curar o habilidades de potenciación.

Independientemente de la clase de los héroes al embarcar en una misión hay que elegir un grupo de héroes equilibrado que cumplan los roles de tanque que será el que absorba daño, provocador de daño que será el que haga daño en grandes cantidades a los enemigos, curador que mantenga en buena salud al resto de héroes y soporte que proporcione potenciadores. Esta es la regla general algunos héroes tienen habilidades que permiten hacer la función de otro, en un grupo puede haber un héroe especializado en curar pero otro tener también alguna habilidad de curación para apoyar o un héroe proporcionar potenciadores pero también ser capaz de hacer un daño moderado.

A medida que los héroes realizan misiones ganan experiencia y suben de nivel, lo que mejora sus estadísticas y les permite equiparse con mejores armaduras y armas y un nivel mayor de habilidad. El nivel que tienen los clasifica en aprendiz, veterano y campeón, por otro lado las misiones también se clasifican en aprendiz, veterano y campeón. Los héroes se niegan a participar en misiones de menor nivel al que tienen. Los niveles 0, 1, 2 son de aprendiz, 3 y 4 es un veterano y 5 y 6 es un campeón. Pasar del nivel 5 al 6 no mejora las estadísticas base pero si las resistencias.

Cada héroe puede tener hasta 5 rasgos positivos que se ganan al subir de nivel  y 5 negativos que se adquieren también al subir de nivel o en algunos curio. Si un héroe ya tiene 5 rasgos y adquiere otro uno anterior es reemplazado, para no perder uno especialmente bueno es posible fijarlos en el sanatorio. Aunque los héroes tienen hasta 7 habilidades entre las que elegir en un mismo momento solo pueden estar activas 4 igual que las de acampada, estas hay que elegirlas por ser las mejores del héroe o por ser las más adecuadas según el grupo de héroes en una misión. Se pueden cambiar en el poblado y también entre los combates pero no en medio de un combate. Los héroes de la diligencia que se incorporan a los barracones con un nivel mayor que 0 las poseen todas a su mayor nivel a diferencia de los héroes que se incorporan de nivel 0 que no poseen todas.

AbominaciónAnticuariaArbalestera

Caza recompensasCruzadoAsaltatumbas

DiablaBandoleroMaestro canino

BufónLeprosoHombre de armas

OcultistaDoctor de plagaVestal

Héroes de Darkest Dungeon

Clases, habilidades más destacadas y funciones

Entre todos las diferentes clases de héroes en un grupo hay que elegir una combinación de ellos en el que sus habilidades se complementen o refuercen. Las funciones de los héroes son las siguientes:

  • Tanque: esta función de héroe es desempeñada por uno con una gran cantidad de puntos de vida y protección capaz de absorber mucho daño sin correr excesivo peligro. Aparte de absorber daño también puede tener la función de hacer daño y otras funciones de apoyo con algunas de sus habilidades como curar o proporcionar potenciadores. Las estadísticas principales de este héroes serán los puntos de vida y protección y en menor medida daño y evasión. Aunque un tanque también podría serlo por tener un alto valor de evasión.
  • Provocador de daño: esta función es la de causar gran cantidad de daño a los enemigos para eliminarlos de un solo golpe o quitar gran cantidades de vida a enemigos con gran cantidad de vida. Las estadísticas principales de los héroes para esta función son la de daño y probabilidad de crítico.
  • Curador: los enemigos también van a tener muchas oportunidades de realizar ataques y causar daño  los héroes, es imprescindible que haya un héroe que cuando sea necesario cure al resto para mantener los puntos de vida del resto en unos niveles que no les haga correr el riesgo de entrar a las puertas de la muerte en el que puedan morir. En el grupo de héroes es aconsejable que haya uno que cure puntos de vida y algún otro con la habilidad de bajar los puntos de estrés.
  • Potenciadores y mermas: otra función que puede desarrollar un héroe es la de soporte para proporcionar potenciadores al resto de héroes del grupo como un aumento de daño, esquiva o velocidad.

Todos las clases de héroe tienen tres habilidades de acampada comunes y cuatro únicas, que proporcionan potenciadores durante los cuatro siguientes combates o que curan esfuerzo, algunas habilidades tienen efectos negativos. Al realizar una acción con resultado de crítico los héroes obtienen un potenciador.

Cada tipo de héroe destaca y se diferencia en algunos aspectos del resto:

  • Abominación, ficha: es un héroe flexible ya que todas sus habilidades están a disposición con la transformación. Se puede curar la vida y esfuerzo.
  • Anticuaria: es el héroe con habilidades de ataque más débiles, su mayor utilidad es su capacidad de encontrar objetos de botín adicionales y permitir formar montones de monedas monedas más grandes. En un combate su función es la de soporte.
  • Arbalestera, ficha: su posición es la 3 o 4, puede hacer grandes cantidades de daño a las últimas posiciones potenciado con los enemigos marcados y hacer las funciones de curación de soporte cuando no hay más enemigos a los que pueda atacar, su curación de batalla no cura mucho pero hace más efectivas las siguientes curaciones.
  • Caza recompensas, ficha: su posición es la 2 pero también puede estar en la 3, tiene la capacidad de mover y causa daño adicional a héroes marcados o aturdidos. No hace la función de tanque ya que no se potencia con protección.
  • Cruzado, ficha: su posición es la 1 o 2, hace la función de tanque potenciado su protección significativamente que dura toda la batalla. A los enemigos impíos les hace daño adicional. Tiene la capacidad de curar puntos de vida y esfuerzo dando soporte al curador principal.
  • Asaltatumbas, ficha: tiene habilidades que le dan movilidad pero no es adecuado junto a héroes que no la tengan, su evasión le permite usarse como tanque a base de evasión.
  • Diabla, ficha: su posición es la 1 o 2. Su habilidad Hachazo perverso le permite atacar a las dos primeras posiciones y con Cisne de hierro puede atacar a enemigos en la posición 4 donde suelen estar los más peligrosos, puede atacar casi a cualquier posición del enemigo haciendo grandes cantidades de daño. Otra de sus habilidades destacadas es la de poder aturdir a las dos primeras posiciones de los enemigos.
  • Bandolero, ficha: puede estar en cualquier posición causando grandes cantidades de daño con su notable probabilidad de crítico y aumento de daño, precisión y crítico con Disparo de seguimiento que dura durante todo el combate útil en los combates largos como los jefes. Además con su habilidad de riposte causa daño a los enemigos cuando le atacan pudiendo hacer daño o acabar con enemigos en sus propios turnos de acción.
  • Maestro canino, ficha: su posición es la 3 o 4 pudiendo llegar a todos los enemigos. Es especialmente adecuado para enemigos vulnerables a sangrado como las bestias pero inefectivo para no muertos que lo resisten. La habilidad Silvido quita mucha protección. Está equipado con dos piezas de galleta de premio que proporciona potenciadores al daño durante tres turnos.
  • Bufón, ficha: su posición ideal es la 3 donde puede usar Tonada inspiradora y usar sus ataques. El potenciador Balada de batalla que proporciona velocidad, precisión y crítico aplica a todo el grupo. Con la habilidad Apoteosis puede causar gran cantidad de daño para acabar con el último enemigo. Es más adecuado para misiones largas por su Tonada inspiradora que cura esfuerzo y potencia la resistencia al esfuerzo.
  • Leproso, ficha: puede ser considerado el mejor tanque del juego, tiene la capacidad de curarse puntos de vida significativamente y esfuerzo que lo hace autosuficiente. Solo es útil en las dos primeras posiciones, su otro defecto es que no tiene mucha precisión lo que hay que corregirlo con algún abalorio o potenciador.
  • Hombre de armas, ficha: su posición es la 1 o 2 donde puede usar todas sus habilidades, también es posible usarlo en la posición 4 donde potencia a los aliados en grupo mejorando precisión, velocidad y evasión, también puede reducir la evasión y velocidad los enemigos. Puede hacer de tanque absorbiendo daño.
  • Ocultista, ficha: su posición ideal es la 3, tiene habilidades para reducir la protección o evasión además de marcar a los enemigos. Tiene una poderosa habilidad de curación pero no tan fiable como la la Vestal. Puede mover a enemigos a posiciones adelantadas donde no puedan usar sus habilidades más peligrosas o donde los compañeros de ataques cuerpo a cuerpo los eliminen.
  • Doctor de plaga, ficha: su posición es la 3, aunque sus habilidades tiene un daño base bajo causan efectos negativos al enemigo. Tiene una de las habilidades de movimiento más poderosas y la capacidad de aturdir a dos enemigos en la retaguardia. Tiene una habilidad de curación básica pero que elimina infecciones y sangrado.
  • Vestal, ficha: si posición ideal es la 3. Tiene dos poderosas habilidades de curación, una para un único objetivo y otra que cura menos pero afecta a todo el grupo. Con la habilidad Juicio puede atacar y curarse. Tiene habilidades que restauran el nivel de luz para conservar antorchas en misiones largas.

Por tipo

Las clases de los héroes que tienen como función principal en el grupo son:

  • Tanque: Cruzado, Leproso, Hombre de armas, Asaltatumbas (por evasión).
  • Provocador de daño: Caza recompensas, Asaltatumbas, Diabla, Bandolero, Abominación, Hombre de armas, Maestro canino, Arbalestera.
  • Curador (Puntos de vida, Esfuerzo): Ocultista (PV), Vestal (PV), Cruzado (PV, E), Bufón (E), Arbalestera (PV), Doctor de plaga (PV), Maestro canino(E).
  • Soporte, potenciadores y mermas: Bufón, Oultista, Doctor de plaga, Vestal, Hombre de armas, Maestro canino.

Otro aspecto en el que se pueden clasificar los héroes son por aquellos que tienen la capacidad de hacer daño a medida que pasa el tiempo ya sea por hemorragia o infección. O que tiene la capacidad de mover a enemigos de su posición a otra en la que no puedan utilizar su habilidad más poderosa o de moverse en caso de que los cambien de posición, también si pueden aturdir. La capacidad de hacer daño a enemigos en posiciones 3 y 4, también es importante pues en estas se suelen ubicar los enemigos más peligrosos.

  • Daño por tiempo (Infección, Hemorragia): Asaltatumbas (I), Diabla (H), Bufón (H), Doctor de plaga (H, I), Maestro canino (H), Anticuaria (I).
  • Capacidad de marcar: Caza recompensas, Ocultista, Maestro canino, Arbalestera.
  • Capacidad de aturdir: Doctor de plaga, Vestal, Abominación, Hombre de armas, Diabla.
  • Capacidad de moverse con ataque: Asaltatumbas, Cruzado, Diabla, Bandolero, Bufón, Abominación.
  • Capacidad de mover: Caza recompensas, Ocultista, Doctor de plaga, Abominación, Hombre de armas, Bandolero, Leproso.
  • Capacidad de hacer daño a enemigos en posiciones 3 y 4: Caza recompensas, Asaltatumbas, Diabla, Bufón, Ocultista, Vestal, Abominación, Hombre de armas, Maestro canino, Arbalestera.
  • Capacidad de curarse: Leproso, Abominación, Maestro canino.
  • Capacidad de mermar (Evasión, Daño, Protección, Crítico, Precisión, Velocidad): Ocultista (E, D, Pro), Arbalestera (Pre, C, E), Caza recompensas (Pro, D, V), Hombre de armas (E, V), Maestro canino (Pro), Leproso (D, V, Stealth).
  • Daño adicional (Marcado, Hemorragia, Infección, Aturdido): Arbalestera (M), Asaltatumbas (M, H, I), Caza recompensas (M, Humano), Cruzado (Impío), Diabla (H), Bandolero (M), Maestro canino (M, Bestia), Ocultista (Eldrich), Vestal (Impío).
  • Héroes religiosos: Leproso, Cruzado, Vestal.

La posición de los héroes también es importante, las habilidades y ataques tienen restricciones de posición.

  • Posición 1-2: Abominación (2), Cruzado (1), Diabla, Leproso (1), Hombre de armas.
  • Posición 2-3: Asaltatumbas, Bandolero, Caza recompensas (2).
  • Posición 3-4: Anticuaria, Arbalestera (4), Maestro canino, Hombre de armas, Vestal, Bufón (3), Ocultista (3), Doctor de plaga (3).

Poblado, edificios y recursos

El juego se desarrolla en dos zonas distintas, el poblado donde se prepara la siguiente misión con la exploración de mazmorras y combates.

En el poblado hay una serie de edificios que atienden a varias necesidades de los héroes como el reclutamiento con la caravana, la reducción de esfuerzo con la taberna y la abadía, el sanatorio para quitar rasgos y enfermedades, la armería y el gremio para mejorar habilidades de los héroes según alcanzan mayores niveles y la mejora de armaduras y arma, otras localizaciones son el cementerio donde ver los héroes caídos en combate, el carro nómada donde comprar nuevos abalorios y el superviviente donde adquirir nuevas habilidades de acampada.

Los edificios se pueden mejorar con reliquias que se obtienen durante las misiones como emblemas, bustos, cuadros y manuscritos. Estas mejoras permiten reducir los costes de usar los edificios, proporcionan acceso a entrenar habilidades, armas y armaduras de mayor nivel o más celdas en las salas de los edificios para tratar a los héroes.

Al finalizar una exploración de mazmorra los héroes habrán ganado esfuerzo, quizá alguna infección y si suben de nivel algún rasgo especialmente negativo. Al salir del combate es necesario tratar las afecciones especialmente negativas ganadas por héroes en la taberna, abadía y sanatorio de modo que no tengan penalizaciones en la siguiente misión.

FeudoCuidador

Feudo y cuidador

Mecánicas del juego

El juego no explica en gran detalle la mayor parte de sus mecánicas sino que estas se van aprendiendo al experimentarlas, esto provoca cometer errores, provocar la muerte de héroes y alargar el tiempo que se tarda en completar el juego. Algunas de las cosas que no se explican son las siguientes.

Durante una misión hay un nivel de luz que se va reduciendo a medida se recorre la mazmorra, las antorchas y algunas habilidades permiten aumentar el nivel de luz que afecta a mecánicas como el esfuerzo, probabilidad de ser sorprendidos y sorprender y patrulla. Es recomendable mantener siempre el nivel de luz en un nivel radiante superior a 75. El nivel de luz también afecta al botín obtenido siendo cuanto menos bajo mejor.

Las hemorragias e infecciones que causan daño al inicio de cada turno del héroe o enemigo se pueden acumular en caso de sufrir varias, el daño que causan que aparentemente no parece peligros con varias de estas acumuladas causan un daño significativo. También hay otros efectos de estado que son temporales y que afectan las estadísticas.

Los potenciadores y mermas tanto para héroes como enemigos también se acumulan e igual que las hemorragias e infecciones duran las rondas que indiquen.

En misiones medianas y largas existe la posibilidad de acampar después de la cual los héroes pueden ser sorprendidos por un grupo de enemigos.

Los héroes tienen un nivel y las misiones también tiene un nivel, los héroes de mayor nivel que la misión se niegan a participar en misiones de nivel bajo.

Los héroes pueden morir de dos formas, cuando están con cero puntos de vida en el estado de puertas a la muerte en este estado cada vez que sufran daño deberán superar un golpe mortal según su estadística de golpe mortal que por defecto es de un 67%. La otra forma de morir de un héroe es acumulando 200 puntos de esfuerzo momento en el cual es seguro que sufre un ataque al corazón y muere, si llega a 100 puntos adquiere un rasgo negativo que lastra al resto de héroes pudiendo causarles puntos de esfuerzo, realizando acciones aleatorias o efectos algunos leves pero otros muy nocivos.

El porcentaje de patrulla es de utilidad para evitar peligros al explorar mazmorras, descubrir trampas, sorprender a los enemigos que da la ventaja de tener el turno inicial adicional o evitar que el grupo de héroes sea sorprendido que da el turno adicional a los enemigos. También permite descubrir salas secretas con tesoros.

Localizaciones

En el juego sin expansiones hay 4 localizaciones, 5 contando la mazmorra oscura, en las expansiones se añaden una más. A medida que se completan misiones en las localizaciones estas suben de nivel  lo que causa que puedan aparecer enemigos más peligrosos y da acceso a que aparezca la misión de acabar con los jefes. El nivel de las localizaciones llega hasta al 7.

Cada localización tiene diferentes tipos enemigos. En las ruinas serán principalmente no muertos, nigromantes y cultistas de tipo impío con resistencia al sangrado pero con pocos puntos de vida pero vulnerables a la infección y menos peligrosos que los de otras localizaciones, en esta localización es posible encontrar gran cantidad de tesoros. En la foresta abundan los bandidos de tipo humano y otros seres que causan infecciones. En el laberinto es el lugar de las bestias y hombres cerdo vulnerables a la hemorragia. La cala es habitada por criaturas del mar y no muertos, abundan los enemigos con gran protección que causan infecciones y enfermedades y muchos curio proporcionan potenciadores o mermas o manipulan los rasgos.

La localización del Darkest Dungeon es el objetivo del juego, tiene algunos aspectos diferentes en el que no se genera de forma aleatoria ni se encuentra botín .

Localizaciones

Localizaciones

Estadísticas

Cada clase de héroe tiene sus propias habilidades de combate y acampada y estadísticas únicas entre las que se encuentran, puntos de vida, evasión, protección, velocidad, modificador de precisión, probabilidad de crítico y el rango de daño que realiza por ataque. También tienen varios rasgos positivos y negativos que afectan a las estadísticas de diferentes formas. Otro aspecto único de cada clase son las estadísticas de resistencias a varios efectos como aturdimiento, infección, enfermedad, golpe mortal, movimiento, hemorragia, merma y desarmado de trampas. Finalmente, están las enfermedades que ha adquirido el héroe si no ha superado una resistencia de enfermedad.

Las estadísticas bases y sus efectos son los siguientes:

  • Puntos de vida: son los puntos de vida del héroe. Al  iniciar una misión los héroes siempre empiezan con su nivel máximos de puntos de vida y se recuperan de forma completa al finalizar o abandonar la misión, al contrario que los puntos de esfuerzo que perduran y para reducirlos hay que utilizar la taberna o la abadía.
  • Evasión: es la esquiva del héroe, al medir el éxito de un ataque se tiene en cuenta junto con el porcentaje base de precisión y el modificador de precisión.
  • Protección: es un porcentaje que reduce el daño que sufre el héroe o enemigo al sufrir daño y calcula los puntos de vida que se pierde.
  • Velocidad: determina el momento en el que actúa el héroe teniendo en cuenta el resto de puntos de velocidad de otros héroes y enemigos. La línea de tiempo en la que actúan los héroes no aparece en pantalla lo que dificulta un poco en alguna ocasión utilizar alguna habilidad.
  • Modificador de precisión: es un modificador que se añade a la precisión base del héroe según su nivel de habilidad.
  • Probabilidad de crítico: es un porcentaje realizar ataque crítico que causa un mayor daño o cura un mayor puntos de vida de lo normal.

Las estadísticas de resistencias y sus efectos son las siguientes:

  • Aturdimiento: el aturdimiento causa la pérdida de la acción durante una ronda. La resistencia el porcentaje para resistirse a ser aturdido.
  • Infección: es un ataque que causa daño por tiempo al igual que la hemorragia. La resistencia es el porcentaje para resistirse a ser infectado.
  • Enfermedad: es el nivel de resistencia al sufrir una enfermedad que tiene la capacidad de modificar las estadísticas de los héroes. Las enfermedades se curan en el sanatorio.
  • Golpe mortal: es la resistencia a acabar muerto del héroe al sufrir un nuevo daño cuando está en las puertas de la muerte con cero puntos de vida. La estadística base es de un 67% de resistencia.
  • Movimiento: es la resistencia a ser cambiado de posición cuando sufre un ataque de movimiento.
  • Hemorragia: la hemorragia es otro ataque que causa daño por tiempo. La resistencia es el porcentaje para resistirse a sufrir hemorragia en un ataque que lo provoque.
  • Merma: la resistencia a evitar ataques que causen efectos de merma.
  • Desarmado de trampas: es el porcentaje de éxito al intentar desarmar una trampa.

El nivel de arma afecta al daño base, porcentaje de crítico base y velocidad base. El nivel de armadura afecta a los puntos de esquiva y puntos de vida. El nivel de habilidad afecta con porcentaje modificador al daño base, la precisión base y porcentaje de crítico base. Algunos abalorios modifican estas estadísticas, algunos aumentan unas estadísticas de forma positiva pero también pueden tener efectos negativos al mismo tiempo.

Una estadística que no aparece en la ficha del héroe es la virtud. Cuando un héroe alcanza los 100 puntos de esfuerzo tienen un porcentaje de en vez de obtener un rasgo negativo entrar en un estado virtuoso positivo y reducir su esfuerzo a 45. La probabilidad base de virtud es 25% que se puede modificar por rasgos y abalorios. Hay varios estados de virtud diferentes algunos permiten hacer más daño, curar esfuerzo a los compañeros, tener más protección y otros potenciadores a las estadísticas.

Ficha de héroe

Ficha de héroe

Rasgos y enfermedades

Los héroes al subir de nivel con la experiencia ganada después de completar una misión tienen la posibilidad de ganar rasgos, tanto positivos como negativos. También es posible que ganen algún rasgo al activar algún curio, en la mayoría de ocasiones serán negativos y algunas pocas positivos. Por otro lado, algunos enemigos con sus ataques provocan enfermedades si el héroe no supera la tirada de resistencia a la enfermedad.

Los rasgos positivos especialmente adecuados para el héroe es posible fijarlos en el sanatorio, los rasgos negativos es posible eliminarlos y las enfermedades es posible curarlas. Es posible fijar un rasgo positivo y eliminar un rasgo negativo al mismo tiempo.

Algunos rasgos negativos no son especialmente graves pero hay otros que hay que quitarlos si es posible porque afecta de forma muy negativa a las estadísticas del héroe o a una estadística importante. También hay rasgos positivos buenos, fijarlos evitar perderlos si en algún momento el héroe ya tiene 5 rasgos positivos y gana otro lo que provoca que alguno no fijado sea reemplazado.

Estos son los rasgos positivos más destacados junto con sus efectos e interesantes que los héroes poseen. Si son especialmente adecuados según su clase de héroe interesa fijarlos para que no sean reemplazados por otros.

  • Natural Eye: +5 a la precisión en ataques a distancia.
  • Natural Swing: +5 a la precisión en ataques a cuerpo a cuerpo.
  • Slugger: +10% de daño en ataques cuerpo a cuerpo.
  • Unerring: +10% de daño en ataques a distancia.
  • Eagle Eye: +3% a la posibilidad de crítico para ataques a distancia.
  • Precision Striker: +3% a la posibilidad de crítico para ataques cuerpo a cuerpo.
  • Deadly: +1% a la posibilidad de crítico.
  • Tough: +10% de vida máxima.
  • Evasive: +5 a evasión.
  • Quick Reflexes: +2 a la velocidad.
  • Hard Skinned: +10% a la protección.
  • Steady: +10% de resistencia esfuerzo.
  • Quickdraw: +4 a la velocidad durante la primera ronda de combate.
  • On Guard: +4 a la velocidad y +5 a evasión durante la primera ronda de combate.
  • Unyielding: +10% de resistencia a golpes mortales.

Según la función del héroe estos son los rasgos positivos más beneficiosos que tengan:

  • Un héroe de ataques a distancia: Eagle Eye, Deadly, Evasive. Estos héroes están maximizados para hacer daño con un poco de mayor velocidad.
  • Un héroe de ataques cuerpo a cuerpo: Slugger, Precision Striker, Hard Skinned. Un buen incremento en el daño y protección adicional.
  • Un héroe con la función de tanque: Slugger, Tough, Hard Skinned. Más protección, vida y algo más de daño en ataques cuerpo a cuerpo.
  • Un héroe para actuar primero especialmente en la primera ronda: Quick Reflexes, Quickdraw, On Guard. Esto proporciona puntos de velocidad en la primera ronda.
  • Un héroe con la función de curar: Tough, Quick Reflexes, Hard Skinned. Algo más de vida, de protección y algo de velocidad.

Los rasgos a evitar son los siguientes:

  • Los que reducen la velocidad: Nocturnal, Off Guard, Slowdraw, Slow Reflexes.
  • Los que reducen el daño: Light Sensitive, Scattering, Calm, Tuckered Out.
  • Los que fuerzan a los héroes a realizar acciones: Ablutomania, Bloodthirsty, Compulsive, Curious, Dacnomania, Dark Temptation, Demonomania, Dipsomania, Egomania, Guilty Conscience, Hagiomania, Hylomania, Kleptomaniac, Necromania, Paranormania, Plutomania, Sitiomania.
  • Los que causan robo de botín: Kleptomania.

Guía de rasgos.

Abalorios

Los abalorios son objetos que los héroes equipan, como máximo dos, que proporciona mejoras en algunas estadísticas sin embargo muchos de ellos al mismo tiempo también tiene un efecto negativo en alguna otra estadística. Son un elemento fundamental equipar a los personajes para potenciar sus virtudes o suplir sus defectos, tambié teniendo en cuenta el resto de personajes con los que va acompañado. Los abalorios se consiguen principalmente como una recompensa en el éxito en las misiones, los jefes también entregan abalorios importantes, también se pueden comprar en el carro nómada.

Estos son abalorios destacados para las funciones de algunos héroes, la mayoría aquellos que dan velocidad, evasión, los de daño, precisión y crítico para los que hacen daño, los de protección y resistencias para los tanques y algunos para suplir sus carencias como precisión para el leproso o potenciar su función como curaciones para los curadores.

HéroeAbaloriosEfecto
12
AbominaciónAncestor's PenFeather Crystalmás velocidad, evasión, crítico y daño
Berserk CharmRestraining Padlockmás velocidad, daño, menos estrés causado en la transición a bestia
ArbalesteraAncestor's Musket BallWrathful Bandanamás daño y crítico en ataques a distancia
Bull's Eye BandanaWrathful Bandanamás precisión, critico y daño
Caza recompensasAncestor's PenHunter's Talonmás crítico, precisión y daño en ataques de cuerpo a cuerpo
Hunter's TalonWounding Helmetmás crítico, precisión y daño cuerpo a cuerpo
CruzadoBerserk CharmLegendary Bracermás velocidad y daño
Tough RingBerserk Charmmás protección, vida y daño
Asalta tumbasRaider's TalismanLucky Talismanmás crítico, desarmado de trampas, patrulla, evasión y precisión
Feather CrystalRaider's Talismanmás crítico, desarmado de trampas, patrulla, evasión y velocidad
DiablaAncestor's PenBerserk Charmmás daño, critico y velocidad
Ancestor's PenLegendary Bracermás daño y crítico
BandoleroGunslinger's BuckleBerserk Charm Charmmás daño, precisión en ataques a distancia y daño
Gunslinger's BuckleAncestor's Musket Ballmás daño y precisión en ataques a distancia
Maestro caninoFeather CrystalCamouflage Cloakmás velocidad y evasión
Spiked ColarFeather Crystalmás velocidad, evasión, daño y probabilidad de causar hemorragia
BufonFeather CrystalCamouflage Cloakmás velocidad y evasión
Feather CrystalAncestor's Coatmás velocidad y evasión
LeprosoFocus Ring / Fortunate ArmletTough Ringmás precisión y crítico
Focus RingLegendary Bracermás precisión, crítico y daño
Hombre de armasCamouflage CloakFeather Crystalmás velocidad y evasión
Guardian's ShieldFeather Crystalmás velocidad y evasión, en la posición 4 más protección, evasión y curaciones recibidas
OcultistaFeater CrystalCleansing Crystalmás velocidad, evasión y resistencias, menos probabilidad de causar hemorragia al curar
Camouflage CloakCleansing Crystalmás velocidad, evasión y resistencias, menos probabilidad de causar hemorragia al curar
Doctor de plagaBlasphemous VialPoisoned Herbmás precisión y aturdir e infectar al enemigo
Blasphemous VialFeater Crystalmás precisión y probabilidad de aturdir e infectar al enemigo, evasión y velocidad
VestalSacred ScrollTome of Holy Healingmás precisión y aturdir e infectar al enemigo
Tough RingHaste Chalicemás vida máxima, protección y velocidad

Abalorios

Abalorios

Botines y curios

Los curio son objetos que se encuentran en los pasillos y en las salas de las mazmorras, dependiendo del curio activarlos permite conseguir una recompensa en reliquias o monedas pero algunos también tienen efectos negativos como ganar un rasgo negativo o una enfermedad. Los curio se pueden activar utilizando un objeto del equipo para evitar su probabilidad de efecto negativo y obtener siempre una recompensa positiva ya sea en reliquias, monedas, potenciadores o rasgo positivo. Cada curio tiene siempre los mismos efectos y probabilidad de resultado pero muchos de ellos tienen efectos negativos con lo que siempre hay que consultar antes el objeto adecuado con el que activarlo para evitar el riesgo de obtener un efecto negativo.

Las reliquias de la  familia son bustos, pinturas, hojas de diario y emblemas. Son los recursos con los que se mejoran los edificios. Es posible hacer conversiones entre cada uno de estos recursos.

BotínCurio

Botín y curio

Misiones y combates

Las misiones consisten en la exploración de una mazmorra, según la localización los enemigos serán unos u otros. Las misiones tienen un nivel (aprendiz, veterano, campeón), una duración (corta, mediana y larga), en función de los rasgos de los héroes un porcentaje de patrulla y un objetivo.

Los diferentes objetivos de las misiones son los siguientes:

  • Limpieza: ganar todos las batallas de la mazmorra.
  • Explorar: explorar el 90% de las salas.
  • Matar: acabar con un  jefe.
  • Activación: activar tres altares.
  • Recolectar: recolectar 3 reliquias.

Los héroes de un nivel se niegan a participar en misiones de un nivel inferior, los héroes con nivel inferior pueden participar en misiones de mayor nivel sin embargo es arriesgado ya que son débiles ante los enemigos de mayor nivel.

Los mapas de las mazmorras se generan de forma aleatoria siendo de mayor tamaño para las de mayor duración. En los pasillos y salas de las mazmorras es posible encontrar curio y trampas. Cuando se llega a una sala está vacía o está ocupada y después de eliminar a los enemigos se puede producir el efecto de patrulla que permite ver cómo es la mazmorra en las ubicaciones cercanas, con la patrulla también es posible encontrar salas ocultas, evitar ataques sorpresa de los enemigos y realizar ataques sorpresa con más facilidad al inicio de los combates a los enemigos.

Las misiones cortas no permiten acampada, las misiones medianas permiten acampar una vez y las largas dos veces para lo cual se añade un objeto en el inventario de leña, las acampadas se realizan en una sala de la mazmorra. Al acampar se emplean las habilidades de acampada, se proporcionan 12 puntos de acción a repartir entre las habilidades que se quieran utilizar, estas habilidades permiten curar puntos de vida, puntos de esfuerzo y proporcionar potenciadores que duran hasta 4 combates. Es recomendable acapar en la sala anterior antes de llegar a un jefe final para tener potenciadores que las habilidades causen mayor daño o llegar con unos niveles de esfuerzo y vida buenos. Después de acampar es posible que el grupo sea sorprendido por los enemigos y haya que realizar un combate.

Antes de empezar una misión está la fase de aprovisionamiento en la que se compran los objetos a llevar en el inventario, entre estos objetos están principalmente las antorchas y la comida y algunos otros objetos de utilidad como las vendas para curar hemorragias o antiveneno para curar infecciones, las palas para quitar obstáculos que si no se tiene causan gran daño y esfuerzo sin ellas, el agua bendita para proporcionar resistencias. Varios de estos objetos se pueden emplear para activar curio y obtener botín sin riesgos de efectos negativos. En función de la duración de la misión se equipan más objetos o menos, intentando que sean los mínimos imprescindibles pero siempre con un margen suficiente para completar la misión. Llevar muchos objetos en el inventario permite completar la misión con menos riesgo pero si se quiere recoger botín obliga a tirar objetos que no hubiera sido necesario aprovisionarse.

Después de los combates y con los curio se recoge un botín que ocupa lugar en el inventario, a veces hay que deshacerse de objetos para conseguir espacio para los objetos que se desean recoger. Al final de una misión hay que tratar de conseguir el mayor botín posible tanto en reliquias como en monedas para poder mejorar edificios, adquirir habilidades para los héroes o sanar a los héroes.

Los combates se desarrollan por turnos, cada héroe y enemigo tiene una acción, algunos enemigos dos. El orden de acción se determina por la estadística de velocidad, Un héroe realiza la acción usando una habilidad que se desee entre las equipadas. Para calcular el éxito del uso de una habilidad se utiliza la estadística de precisión y la estadística de evasión del objetivo. El daño se calcula con la estadística de daño y de protección del objetivo. Al realizar un ataque existe la posibilidad de realizar un crítico con el que se hace un daño o curación superior al normal, para ello se utiliza la estadística de probabilidad de crítico. Algunos ataques causan daño por tiempo mediante hemorragia o infección al inicio de la acción del héroe o enemigo, cuando un enemigo muere a causa de estos no deja su cadáver y los enemigos posteriores se desplazan a las primeras posiciones.

Las habilidades tiene unos requerimientos de posición en la que hay que estar para usarla y un requerimiento de posición del objetivo, por ejemplo algunas habilidades sólo son utilizables en la posición 3 y 4 contra objetivos en la posición 1 y 2.

Las provisiones recomendadas en función de la duración de la misión y la localización son las siguientes, las básicas son la comida y las antorchas el resto son de utilidad por el tipo de enemigos y el tipos de curio que se encuentran y son empleables entre ellos. Las provisiones son consumibles que tiene diferentes efectos, se pueden usar para conseguir sus efectos o al activar los curio para conseguir botín sin riesgo.

  • Comida: permite recuperar puntos de vida, al acampar los héroes consumen comida recuperando puntos de vida y en caso de consumir muchas raciones también esfuerzo.
  • Antorchas: aumenta el nivel de luz que desciende a medida que se exploran las mazmorras.
  • Palas: permite quitar obstáculos en los pasillos, si no se dispone de una pala para quitar un obstáculo los héroes sufren grandes cantidades de daño.
  • Vendas: cura las hemorragias.
  • Antiveneno: cura las infecciones.
  • Hierbas medicinales: quitas las mermas que posea un héroe.
  • Llaves esqueleto: para activar curio y recoger botín sin riesgo.
  • Agua bendita: aumenta las resistencias.
  • Láudano: quita el efecto de horror.

AprovisionamientoAprovisionamientoAcampada

Misión, aprovisionamiento y acampada

Combate

Combate

Por muy tranquila que vaya una misión no hay que confiarse, la falta de una pala, falta de comida o un enemigo que realiza un crítico en un ataque da lugar a una situación de riesgo para alguno de los héroes sobre todo en las misiones de nivel campeón.

Remind yourself that overconfidence is a slow and insidious killer.

Jefes

Entre las misiones y objetivos de juego está unas misiones especiales que implican  matar a un jefe. Son enemigos especiales más resistentes, poderosos y cada uno con sus propios comportamientos. Cada jefe es distinto, requiere de su propia estrategia y grupo de héroes para acabar con él sin que mate a ningún héroe.

Los jefes aparecen varias veces a medida que se progresa en el nivel de las localizaciones. Al matarlos estos entregan abalorios especiales algunos de los cuales son poderosos y útiles para conseguirlos antes de entrar en la mazmorra oscura.

Los jefes y sus estrategias de batallas son las siguientes:

Estos son algunos jefes que hay que aniquiar para completar el juego.

BrujaCañonNigromante

Bruja, Cañon y Nigromante

ProfetaSirena

Profeta y Sirena

Estrategia para completar el juego

Este juego para completarlo requiere conocer en profundidad muchos de sus aspectos. Es difícil y a poco error que se cometa o mala suerte que se tenga un héroe puede morir incluso haciendo todo adecuadamente. Para completarlo más fácilmente los siguiente consejos de estrategia son de mucha ayuda, que héroes son los más adecuados para cada localización, qué edificios mejorar primero, que cantidades de provisiones llevar para cada misión y localización, estrategias para enfrentarse a los jefes y a la mazmorra oscura.

Auqí solo doy unos pocos consejos generales, en intenet hay guías mucho más completas y detalladas.

Aviso de la dificultad del juego

Aviso de la dificultad del juego

Estrategia de grupos de héroes

De enviar a una misión un grupo de héroes equilibrado para la ubicación dependen en gran medida el éxito de la misión, junto con las habilidades adecuadas y las provisiones necesarias. Un buen grupo de héroes es aquel que tiene miembros para desempeñar las funciones principales de un grupo, tanque, realizador de daño, curador y soporte. Este esquema admite algunas variaciones dependiendo el objetivo. Enviar a una misión a un grupo de héroes inadecuado o desequilibrado supone sin dificultad la muerte de alguno de ellos.

En las ruinas hay abundancia de enemigos impíos inmunes a la hemorragia, una buena cantidad de PV y ataques de daño y esfuerzo. Una opción es aturdir a los de las primeras posiciones y dañar a los de la trasera junto con infecciones, también es posible poner a los enemigos en la posición trasera en la delantera para atacarlos con ataques de cuerpo a cuerpo. El Cruzado y la Vestal tienen bonificadores de daño impíos. La Anticuaria puede incluirse si el objetivo es conseguir botín.

  • Héroes recomendados para las ruinas: Cruzado, Hombre de armas, Leproso, Doctor de plaga, Vestal, Abominación, Asaltatumbas, Bufón, Anticuaria, Caza recompensas.

La foresta es el área más compleja. Algunos enemigos son rápidos, otros fuertes, a veces se prioriza la línea delantera y a veces la línea trasera, no hay un solo tipo de enemigos como impíos en las ruinas y eldrich en la cueva. El daño recibido proviene de infecciones, hemorragia o críticos de esfuerzo, también de movimiento. Los enemigos son vulnerables a la hemorragia mientras que la infección es inefectiva, tiene la habilidad de marcar que hace la habilidad de proteger o quitar la marca útil.

  • Héroes recomendados para la foresta: Ocultista, Bufón, Abominación, Hombre de armas, Bandolero, Leproso, Maestro canino, Caza recompensas, Diabla, Arbalestera.

Los enemigos del laberinto son humanos y bestias, rápidos con buena evasión, con una combinación de los tres tipos de daño, físico, por hemorragia e infección y resistencias a infecciones. A diferencia de otras áreas el esfuerzo es más manejable. El aturdimiento para las posiciones traseras y las hemorragias funcionan muy bien. Las hierbas medicinales sirven para eliminar las mermas que infligen y activar curio.

  • Héroes recomendados para el laberinto: Hombre de armas, Diabla, Caza recompensas, Maestro canino, Bandolero, Asaltatumbas, Ocultista, Doctor de plaga.

Algunos enemigos de la cala causan daño, otros esfuerzo, otros apilan daño de hemorragia rápidamente y en grandes cantidades, también tiene protección con habilidades de proteger. Los enemigos son vulnerables al aturdimiento e infecciones. Se necesita velocidad, aturdimiento, daño y cura, si se añade daño contra eldritch e impíos las misiones se pueden completar sin recivir grandes cantidades de daño.

  • Héroes recomendados para la cala: Cruzado, Hombre de armas, Doctor de plaga, Vestal, Ocultista, Abominación, Diabla, Asaltatumbas.

Más análisis y consejos de grupos:

Estrategia en misiones

Al organizar una misión es necesario fijarse en cuál es el objetivo de la misión, en qué localización de desarrollar para elegir los héroes más efectivos, su duración para equipar el número de objetos en el inventario adecuados, el nivel de la misión, el porcentaje de patrulla del grupo y si algún personaje tiene fobia a esa localización o por el contrario está especiaizado en ella con ventajas.

El primer paso de una misión es construir el grupo de héroes tratando de que haya uno que realice la función de tanque, provocador de daño, curador y soporte. Algunos héroes pueden hacer la función de otro en caso de necesidad aunque no sea su función principal. Después de una misión es recomendable hacer descansar a los héroes en caso de que hayan regresado con mucho esfuerzo y curarles los rasgos negativos y enfermedades para que en siguientes misiones no tengan penalizaciones. Un héroe con mucho esfuerzo no debería participar en un nueva misión ya que corre el riesgo de ganar un rasgo negativo si llega a 100 de esfuerzo o de morir si llega a 200 en una mala sucesión de ataques. Alguno de los héroes debería tener al menos más de 80% en la desactivación de trampas, al desactivarlas correctamente permite evitar su efecto negativo y al mismo tiempo curar un poco de esfuerzo en el héroe que la desactiva.

El segundo paso es hacer que el resto de héroes que no participan en la misión aprovechen para que recuperen esfuerzo en la taberna o abadía, o curarles rasgos negativos y enfermedades en caso de que tengan. Los héroes de nivel bajo que tengan muchas taras no merece la pena invertir monedas en ellos, es mejor contratar un nuevo héroe que esté menos mermado.

El tercer paso es organizar el aprovisionamiento en función de la localización, nivel y duración de la misión. Con estas recomendaciones generales en función de la duración. La comida, antorchas y palas son los objetos básicos imprescindibles comunes a todas las misioens que conviente que no falten en ningún caso, no tenerlos cuando se necesitan ocasiona en los héroes pérdida de puntos de vida y aumento en el nivel de estrés.

LocalizaciónRuinasForestaLaberintoCala
LocalizaciónCMLCMLCMLCML
Comida1216-1818-24
Antorchas8-914-1616-18
Palas1-222-334-55-722-3412-33
Vendas122-322-341-222-32-33-45-6
Antiveneno00022-34-500-11000
Hierbas medicinales12211-22-32-345-611-22-3
Llaves esqueleto123-412222-33-4123-4
Agua bendita234122-3233-400-11-2

Guías de localizaciones.

Al finalizar una misión hay que conseguir el mayor botín posible, si no hay más hueco en el inventario y se está cerca de finalizar la misión es posible deshacerse de objetos de menor valor y que ya es seguro no son necesarios o se puede completar la misión sin ellos como llaves, vendas, agua bendita, palas e incluso comida y antorchas.

Al finalizar la misión conviene curar los rasgos negativos que hayan conseguido por subir de nivel y las enfermedades para que en la siguiente misión en la que participen no tengan penalizaciones.

Estrategia en los combates

Los enemigos más peligrosos suelen estar en las posiciones 3 y 4 con lo que es recomendable eliminar estos primero o anularlos con aturdimiento o movimiento para cambiarles de posición de modo que no puedan utilizar sus habilidades más peligrosas. Para ello es necesario que en el grupo haya algún héroe capaz de hacer daño en las posiciones 3 y 4. Una vez eliminados los enemigos más peligrosos se acaba con el resto. Cuando queden un solo enemigo es posible aprovechar para utilizar habilidades de curación de puntos de vida o esfuerzo para afrontar el siguiente combate con buenos niveles, si el enemigo causa menos daño del que los héroes se curan se puede pasar algún turno sin matarlo empleándolo para curar, siempre teniendo en cuenta que no es posible pasar de esta forma muchos turnos ya que existe la posibilidad de que el enemigo llame a refuerzos.

En el caso de las misiones que involucran jefes hay que conocer que estos están siempre en la sala más profunda de la mazmorra, con que que si se desea ir directamente a por su ubicación aunque oculta es conocida. Si es una misión mediana conviene aprovechar a descansar en la sala anterior para aplicar potenciadores a los héroes y realizar curas. Hay que tratar que los combates contra los jefes duren el menor número de turnos, a la larga ellos tiene la de vencer por las grandes cantidades de daño que hacen.

Estrategia en edificios

Al inicio de la partida el edificio más importante y el primero a realizar las primeras mejoras es la diligencia y el barracón para tener disponibles más héroes entre los que elegir y en un futuro tener la posibilidad de incorporar héroes de mayor nivel al cero. Los héroes incorporados con un nivel mayor que cero tiene la ventaja de que vienen con todas las habilidades adquiridas a su mayor nivel según el nivel del héroe. Mejorando los barracones es posible tener un grupo de hasta 28 héroes entre los que elegir y mejorando la diligencia permite en ocasiones tener disponibles héroes de hasta nivel 3.

Los siguiente edificios a mejorar son la armería y gremio que permite mejorar los niveles de las habilidades de los héroes y el arma y armadura, algunas de las mejoras hacen que cuesten menos monedas las mejoras de los héroes .

El siguiente edificio es el sanatorio para quitar rasgos negativos y enfermedades. Los siguientes serán la taberna y la abadía cuando los héroes vuelvan con cantidades importantes de esfuerzo. Los últimos edificios del poblado a mejorar son la superviviente que únicamente reduce el coste de adquirir las habilidades de acampada y el carromato nómada que permite tener disponibles más abalorios para comprar cada semana y comprar algún abalorio especialmente interesante.

El orden de preferencia de mejora de los edificios es el siguiente: Diligencia, Gremio, Herrería, Sanitario, Superviviente, Abadía, Taberna. Los retratos es el recurso más raro de las reliquias, es preferible guardar estos que otros en caso de tener que desechar el botín.

Los edificios se van desarrollando de forma progresiva una opción es aumentar la diligencia a 4 héroes por semana y 16 de capacidad en los barracones. El gremio y la herrería a nivel 2 es suficiente para llegar subir a nivel 3 a los héroes para hacer asequibles las mazmorras. Luego reclutas experimentados a nivel 1, es una buena mejora ya que proporciona héroes ya con las habilidades mejoradas y todas adquiridas, con una anticuaria se tarda menos en alcanzar las mejoras por sus beneficios en el botín. Barracones a 24. Gremio y herrería a nivel 3 permite reclutar héroes con nivel 2. El Sanatorio sabiendo que curios son peligrosos y cómo obtener su botín usando la provisión adecuada no es necesario, salvo alguna de los rasgos negativos a evitar no es necesario quitarlos hasta a partir del nivel 4. Para las mazmorras de nivel campeón es necesario el Gremio y la Herrería a nivel 5.

Estrategia para el Darkest Dungeon

Entrar al Darkest Dungeon para acabar con el mal es uno de los objetivos principales del juego, estas mazmorras son especialmente difíciles y hay que entrar con los héroes de nivel 6 con el máximo de provisiones. A diferencia de las mazmorras de otras localizaciones no son aleatorias con lo que conocer el mapa evita encuentros inecesarios, no hay obstáculos ni cofres que abrir con llaves, no hay probabilidad de recibir un ataque sorpresa después de descansar ni hay botín que recoger. Hay cuatro mazmorras a completar en esta localización. Los enemigos causan gran cantidad de esfuerzo por lo que no es aconsejable llevar los abalorios más poderosas que tiene penalizaciones al esfuerzo.

Muchos de los enemigos de la mazmorra oscura son de tipo eldrich con lo que si a lo largo de ganar determinación algún personaje de los que su misión principal es hacer daño consigue la habilidad que hace más daño, crítico o reduce el esfuerzo contra este tipo de enemigos conviene fijar la habilidad para que no la pierdan.

Conociendo el mapa de la mazmorrra oscura y formando un grupo con los personajes adecuados y abalorios las misiones de la mazmorra oscura son más fáciles que algunos encuentros de las misiones de nivel campeón. En las siguientes guías se incluyen una descripción detallada de los enemigos y sus mecánicas asi como consejos de que héroes son los más adecuados y los mapas. En estas misiones conviene llevar el máximo de antorchas, vendas, antiveneno y agua bendita disponibles en el aprovisionamiento.

Los héroes que completan una mazmorra oscura no pueden participar en una nueva misión de mazmorra oscura, sin embargo ya no ocupan espacio en los barracones además de que cuando participan en alguna misión en alguna localización proporcionan al resto de personajes el doble de experiencia de determinación, esto permite subir de nivel a los personajes más rápidamente.

Mazmorra oscuraMazmorra oscuraMazmorra oscura

Mazmorra oscuraMazmorra oscura

Mazmorra oscura

Más información y wiki

Darkest Dungeon aún con sus mecánicas aparentemente sencillas es un juego bastante complejo y con muchas combinaciones posibles con una dificultad elevada. El juego no explica muchos de sus conceptos con lo que aprender cómo funcionan requiere experiencia, en este aprendizaje a veces se comenten errores que en el peor de los casos cuesta la vida a alguno o varios de los héroes.

Ha varias enciclopedias que recogen mucha información del juego desde las localizaciones, héroes y sus estadísticas, armas, armaduras, habilidades, abalorios, rasgos y enfermedades, enemigos y curio. Dos de estas enciclopedias más completas son la siguientes:

Otras fuentes de información son ver jugar a otros jugadores en Twitch o algún video de YouTube en el que se aprende y explican algunas buenas combinaciones para facilitar el completar el juego. En Reddit también se encuentran hilos sobre temas específicos.

Banda sonora original

La banda sonora ambienta el juego de forma tétrica y decadente.

Blog Bitix: Los diagramas UML para documentar y una aplicación para crearlos

$
0
0

Todo el conocimiento está en el código fuente pero este no tiene una forma de fácil y rápida comprensión a alto nivel, para comprender un sistema es necesario una forma de documentación que muestre los detalles importantes de los que se compone el sistema. El lenguaje unificado de desarrollo o UML permite describir un sistema utilizando diferentes diagramas específicos para mostrar diferentes aspectos del sistema. Gaphor es una aplicación de software libre disponible para diferentes sistemas operativos que permite crear y exportar a imágenes los diferentes diagramas.

Gaphor

El trabajo de desarrollo de software en mayor media es un trabajo colaborativo entre un grupo de personas, por ello la comunicación y transmisión de información es fundamental. Por otro lado, los sistemas informáticos de cierto tamaño son complejos de los cuales ninguna persona tiene el conocimiento completo y detallado de todas las partes que lo forman. Esto hace que la documentación y la transferencia de conocimiento sea importante en un grado similar al desarrollo de nuevas funcionalidades.

El problema de la documentación es que se quede obsoleta ni refleje el estado actual del sistema por los continuos cambios realizados en el código, para evitarlo la documentación ha de ser a alto nivel que describan los conceptos fundamentales del sistema que no serán propensos a cambiar. Otra forma de evitar esta obsolescencia en algunos casos es generar la documentación a partir de la información embebida en el código fuente como la documentación Javadoc de las clases y API de Java o la documentación de una API REST con Swagger. Sin embargo, no toda la documentación que aporta valor es posible generarla de forma automatizada.

El código fuente de una aplicación contiene el conocimiento más detallado y fiel de una aplicación , sin embargo, tratar de comprender un sistema complejo compuesto por unas cuantas decenas de miles de líneas de código aún usando un lenguaje de alto nivel ya sea Java , Python o C# es una tarea complicada o al menos que requiere mucho tiempo de investigación y esfuerzo de comprensión. Una breve descripción en prosa y un esquema del sistema permite obtener la misma información que analizando el código de forma mucho más rápida.

Si en una organización cuando una persona la abandona deja un vacío importante de conocimiento en las reglas de negocio implementadas o en la incorporación de una nueva persona a un equipo toma demasiado tiempo y dedicación adquirir el mismo conocimiento que el resto de miembros del equipo un problema de la organización quizá sea la falta de documentación. Con el paso del tiempo a medida que una aplicación es más compleja y dado que las personas en una organización se van con el conocimiento que posean y otras vienen pero necesitan adquirir conocimiento, la documentación es una forma de transferencia de conocimiento que está disponible de forma permanente y en forma de autoservicio.

Una buena documentación ha de se concisa y transmitir su información de forma rápida, una forma es utilizar diagramas que esquematizan el sujeto que se trata de describir complementados descripciones en texto. El lenguaje unificado de modelado o UML describe una notación estándar para los diagramas y varios tipos de diagramas.

Contenido del artículo

El lenguaje unificado de modelado o UML

El lenguaje unificado de desarrollo o UML estandariza las convenciones y elementos utilizados en los diagramas además de identificar y describir varios tipos de diagramas para describir un sistema desde varios puntos de vista. Cada uno de estos diagramas describen un sistema a alto nivel de forma esquematizada los conceptos fundamentales.

Los diagramas UML son de dos tipos estructurales que describen la parte estática del sistema y de comportamiento que describen la parte dinámica.

Diagramas UML estructurales:

  • Diagrama de clases: en un lenguaje de programación orientado a objetos muestra las clases e interfaces por las que está compuesto el sistema y sus relaciones de herencia, composición e implementación con diferentes tipos de flechas. También muestra los atributos y métodos que poseen las clases.
  • Diagrama de paquetes: los paquetes son agrupaciones lógicas de varias clases, en este diagrama se muestran los paquetes fundamentales asi como su relación y dependencia con otros.
  • Diagrama de objetos: utilizan la misma notación que los diagramas de clases, se diferencian de los diagramas de clases en que muestran las instancias en un momento determinado del sistema.
  • Diagrama de componentes: muestran los componentes fundamentales en los que se divide un sistema complejo y sus relaciones.
  • Diagrama de estructura compuesta: muestra la estructura interna de una clase.
  • Diagrama de despliegue: muestra en que elementos de computación se despliega el software asi como sus relaciones. Son especialmente útiles en los sistemas distribuidos o basados en microservicios.

Diagramas UML de comportamiento:

  • Diagrama de flujo o actividad: muestra la secuencia de acciones y decisiones implementadas en un algoritmo o proceso.
  • Diagrama de secuencia: muestran las interacciones de los objetos entre si y el orden en el que se producen esas interacciones. El orden de las acciones se muestran de forma vertical y las interacciones como flechas.
  • Diagrama de caso de uso: proporciona una visión general de los actores involucrados en un sistema, las diferentes funciones que usa esos actores y cómo interactúan estas diferentes funciones. Proporciona un descripción global del sistema inicial.
  • Diagrama de estado: algunos objetos o el sistema se comportan de forma diferente en función del estado, estos diagramas muestran los diferentes estados de los que se compone y cual es su comportamiento en función del estado y condiciones.
  • Diagrama de comunicación
  • Diagrama de interacción: muestra un proceso al igual que un diagrama de actividad pero empleando una colección de diagramas de secuencia con su misma notación.
  • Diagrama de tiempos

Esquema de diagramas UML

Diagramas UMLDiagramas UML

Diagramas UMLDiagramas UMLDiagramas UML

Esquema y ejemplos de diagramas UML

Aplicación para crear diagramas de UML

Para crear los diagramas de UML es necesario utilizar una aplicación, una orientada y especifica para crear diagramas UML es Gaphor. Está disponible a través de aplicación Flatpak como forma de empaquetar una aplicación para cualquier distribución GNU/Linux, para Windows y macOS además de ser una aplicación de software libre. Gaphor es una aplicación sencilla con un aspecto cuidado que forma parte del círculo de aplicaciones de GNOME y sigue la guía de estilos para las aplicaciones de este escritorio.

Aplicación para crear diagramas UML

En el panel izquierdo se encuentran los elementos gráficos con los que crear los diferentes diagramas. Los elementos gráficos están categorizados para crear diagramas de clases, paquetes y componentes, también para diagramas de actividad, secuencia, estado y casos de uso, los otros diagramas se pueden crear con los elementos disponibles.

Crear diagramas UML con GaphorCrear diagramas UML con GaphorCrear diagramas UML con Gaphor

Crear diagramas UML con Gaphor

Gaphor permite guardar en un mismo archivo múltiples diagramas que describan los diferentes aspectos del sistema asi como exportar los diagramas a diferentes formatos de archivo como PDF y forma to de imagen como  PNG y SVG. Otras de sus funciones son poder personalizar los estilos de los elementos con reglas de CSS. Finalmente, UML es simplemente una de los estándares para crear diagramas, Gaphor soporta otro tipos de estándares como el modelo C4, RAAML y SysML.


Arragonán: Un año ayudando a equipos

$
0
0

Hace poco más de un año hice público que empezaba a dar servicios de consultoría para ayudar equipos, sin mucha más pretensión que por un lado ordenar mis ideas sobre los servicios que quería empezar a dar y por otro que la gente que conozco supiera de ello.

Al publicar el post tuvo muy buena acogida, infinitamente mejor de lo que hubiera imaginado nunca. Me surgieron bastantes leads de ahí, incluso un par de tentadoras ofertas para incorporarme a startups muy prometedoras que preferí declinar en ese momento.

Como es normal, de esos leads muchos no se concretaron. Ya fuera por mi parte, por la de las compañías interesadas o por ambas; no terminamos de encontrar encaje. Pero ese post sirvió perfectamente para el propósito de que gran parte de la gente que conozco me tuviera en mente.

Tipos de clientes

Durante este año he podido trabajar con algo más de una decena de empresas de distintos tamaños, que podrían agruparse en estos sectores:

  • Impresión industrial
  • Logística
  • Consultoría tecnológica
  • Alquiler de vehículos
  • Moda
  • Certificación de autenticidad
  • Medios digitales

Con contextos de lo más variopintos, desde fundadores de startups a la búsqueda de su market fit aún sin equipo técnico, hasta equipos dentro de multinacionales involucrados en grandes cambios tecnológicos y organizativos.

Formatos de las colaboraciones

En este año en algunas ocasiones aunque a veces pudiera haber buen feeling inicial sobre posibles colaboraciones, no encontraba un formato de colaboración más allá de incrustarme en los equipos unos meses. Cosa que no podía hacer tras incorporarme en Sigma Rail actuando como tech lead la mayor parte de mi tiempo.

Descartada la opción de incrustarme en equipos, tenía pensados dos formatos: Mentorías y formaciones a equipos, son dos tipos de colaboraciones que ya había hecho en el pasado varias ocasiones y con las que me sentía cómodo. A ese tipo de colaboraciones se le unió pronto el hacer asesorías, que a diferencia de las mentorías los objetivos tienden a tener un impacto más cercano al nivel organizacional, normalmente para apoyar a roles con respondabilidades de gestión.

Las formaciones no tienen mucho misterio. Procuro que sean de no más de 2 o 3 días y que no duren mucho más de media jornada, la gente tiene otras cosas que hacer aparte de estar en tus sesiones. También lo que hago es adaptar cada formación a la realidad de cada cliente, incluso las diseño de cero si es necesario. Si es para un equipo que trabaja conjuntamente procuro que buena parte del trabajo sea sobre su propio código, para facilitar llevar a su día a día lo que hayamos estado tratando.

En cuanto a las mentorías normalmente tendemos a cerrar una bolsa de sesiones inicial que puede ir renovándose si estamos todos a gusto con ello. Combinamos hacer revisiones de arquitectura y de código con programar en pair/mob. Las primeras sesiones suelen ser muy de aterrizaje por mi parte, tienden a ser revisiones de arquitectura de alguna aplicación sobre la que vayamos a trabajar en las que busco detectar de dónde vienen los principales dolores del equipo. En esas sesiones bombardeo a preguntas para conocer qué componentes tiene y cómo interactúan entre ellos, suelo hacer mucho foco en conocer los porqués de las decisiones que se tomaron en el pasado, ya que me ayuda a entender mucho mejor la situación actual. Lo malo es que a veces ya no queda nadie en el equipo que formó parte de esas decisiones y toca tirar de hipótesis.

Respecto a las asesorías técnicas, más allá de también resevar bolsas de sesiones o de horas bastante más reducidas, no tengo un formato establecido. Cada colaboración me ha resultado una situación totalmente diferente a la otra. Las que he hecho es a gente que ha llegado a mi porque ya me conocen o alguien que se fía de mi les ha pasado mi contacto, así que empezamos con un escenario de cierta confianza inicial.

Temáticas de las colaboraciones

En las formaciones, adaptando contenidos a las necesidades de cada cliente, los temas centrales a trabajar han sido en esencia tres: Testing automático, diseño de software y DevOps, pero también me pidieron una específica de Python usando buenas prácticas. En otras de esas formaciones utilizamos Java y C#, ya que el lenguaje es parte de la adaptación.

Las formaciones relacionadas con DevOps no era algo que tuviera en mente, pero llegaron un par de peticiones de empresas interesadas, así que le propuse a Néstor hacerlo conjuntamente porque creo que lo complementamos muy bien. De ahí diseñamos una formación de tres días sobre Principios y Prácticas Devops, donde nos focalizamos en los fundamentos entrando en algunas herramientas para ilustrar algunas de las prácticas, bastante cañera en mi humilde opinión ;).

De momento se me ha quedado fuera el hacer formaciones de Specification by Example (aka BDD) y de Clean Architecture, que eran temas que me apetecían pero de momento no ha surgido la posibilidad de hacerlo. En cambio, aunque fuera sólo en formato charla, sí tuve oportuniad de hablar sobre las partes exploratoria y estratégica de Domain-Driven Design.

En cuanto a mentorías básicamente hice tres. Acompañé a un equipo en el desarrollo de una aplicación móvil desde cero, colaboré en pequeñas evoluciones de un MVP aún en la búsqueda de su market fit y ayudé en poner al día componentes que a nivel técnico se habían quedado algo estancados en un ecosistema de microservicios; en esto último aún seguimos colaborando. En estos casos fui intentando aportar en temas de testing, arquitectura, pipelines de integración y entrega continua… vamos, temas habituales. Respecto a lenguajes Kotlin (que no había tenido oportunidad de usar medianamente en serio y me ha despertado aún más curiosidad), Javascript/Node y Java respectivamente.

Dentro del cajón de las asesorías como decía he hecho cosas bastante variadas, e incluso inesperadas para mi. Algunas cosas más o menos normales; como apoyar en temas de product owning, hacer auditorías o dar feedback sobre código/arquitectura de software. Pero no esperaba hacer cosas como evaluar para contratar (o no) proveedores y servicios o hacer poco más que de patito de goma para ayudar a tomar decisiones, son cosas que no me hubiera contratado nadie sin un escenario confianza previo.

¿Y ahora qué?

Cuando arranqué el año pasado no tenía muy claro qué tal iba a funcionar, tenía dudas de si iba a encontrar un interés suficiente en el tipo de servicios que quería ofrecer para hacerlo sostenible. Pero a los meses me vi en un momento en el que tuve que pisar un poco el freno y quitarme algo de trabajo para equilibrar.

De momento hay un par de clientes con los que vengo trabajando desde hace unos meses con los que vamos a seguir haciéndolo, uno en formato mentoría y otro en asesoría.

Cuento con que prácticamente hasta el último trimestre del año no voy a arrancar ninguna nueva colaboración. Hay alguna posibilidad de colaboración a modo de asesoría que quedó pendiente de concretar tras las vacaciones de verano que debería confirmarse (o no) en cosa de un par de semanas. Y sin haber nada cerrado, quizá de cara a final del año hagamos alguna formación. Más allá de eso, una incógnita.

En fin, que como es de suponer, por mi encantado de explorar posibles nuevas colaboraciones. Así que sea para eso o para cualquier duda o tipo de cuestión vía mi email estoy disponible :). Que aunque luego no cuajen siempre me resulta muy interesante conocer equipos y contextos nuevos.

Una sinfonía en C#: Ejecutar Wordpress + MySQL en Kubernetes paso a paso

$
0
0

En las siguientes semanas voy a publicar una serie de post sobre cómo ejecutar Wordpress en Kubernetes paso a paso, mayormente para comprender los principales elementos de Kubernetes y cómo interactúan.

En esta primera publicación vamos a hacer una aproximación bien simple. Tomaremos un docker-compose como base y convertirlo a menos en los diferentes yaml para que funcione en Kubernetes.

En mi caso voy a usar Docker Desktop sobre Windows.

Convertir Wordpress desde docker-compose a Kubernetes

A modo de ejercicio y para asentar conocimientos la idea es, a partir de un docker-compose, generar los yaml para desplegar Wordpress en Kubernetes. Lo iremos haciendo paso a paso, desde el enfoque más simple y llegar a un buen nivel de complejidad para cubrir gran parte de los conceptos de Kubernetes.

docker-compose actual

Este docker-compose es el que aparece en Docker hub de Wordpress y lo usaremos como base.

version:'3.1'services:wordpress:image:wordpressrestart:alwaysports:-8080:80environment:WORDPRESS_DB_HOST:dbWORDPRESS_DB_USER:exampleuserWORDPRESS_DB_PASSWORD:examplepassWORDPRESS_DB_NAME:exampledbvolumes:-wordpress:/var/www/htmldb:image:mysql:5.7restart:alwaysenvironment:MYSQL_DATABASE:exampledbMYSQL_USER:exampleuserMYSQL_PASSWORD:examplepassMYSQL_RANDOM_ROOT_PASSWORD:'1'volumes:-db:/var/lib/mysqlvolumes:wordpress:db:

Tiene dos servicios, Wordpress y MySQL, un par de volúmenes, uno para la base de datos y otro para los html de Wordpress, unas variables de entorno y algunos secrets (passwords)

Primer approach

Vamos a crear la versión más simple, para ello vamos a necesitar lo mínimo para que esto funcione en Kubernetes:

  • Dos deployments:
    • Worpress: for wordpress app
    • MySQL: for mysql app
  • Dos service:
    • CluterIP: para exponer MySQL dentro del cluster y que Wordpress lo puede alcanzar
    • Loadbalancer: para exponer Wordpress al mundo exterior y poder usarlo.

De momento no vamos a poner storage externo, ni configuraciones ni nada.

Deployment de wordpress

Lo único particular es que le pasamos las variables de entorno y el host de MySQL es mysql y el label app=my-wordpress

apiVersion:apps/v1kind:Deploymentmetadata:name:my-wordpresslabels:app:my-wordpressspec:replicas:1selector:matchLabels:app:my-wordpresstemplate:metadata:labels:app:my-wordpressspec:containers:-name:my-wordpressimage:wordpress:latestports:-containerPort:80env:-name:WORDPRESS_DB_PASSWORDvalue:"my-secret-pw"-name:WORDPRESS_DB_USERvalue:"my-user"-name:WORDPRESS_DB_NAMEvalue:"my-db"-name:WORDPRESS_DB_HOSTvalue:"mysql"

Deployment MySQL

Similar a Wordpress, un deployment, le pasamos las variables de entorno y en este caso el label app=my-db

apiVersion:apps/v1kind:Deploymentmetadata:name:my-dblabels:app:my-dbspec:replicas:1selector:matchLabels:app:my-dbtemplate:metadata:labels:app:my-dbspec:containers:-name:my-dbimage:mysql:5.7ports:-containerPort:80env:-name:MYSQL_ROOT_PASSWORDvalue:"my-secret-pw"-name:MYSQL_DATABASEvalue:"my-db"-name:MYSQL_USERvalue:"my-user"-name:MYSQL_PASSWORDvalue:"my-secret-pw"

Servicios

Tenemos Wordpress y MySQL funcionando, pero necesitamos crear dos servicios como ya dijimos Uno para que Wordpress puede alcanzar a MySQL (un ClusterIP porque sería un ciente interno del cluster) Y otro para acceder a Wordpress desde el exterior, un LoadBalancer.

apiVersion:v1kind:Servicemetadata:name:mysql## DNS name (cluster internal)labels:app:my-dbspec:type:ClusterIPselector:app:my-db# busca el deployment que tenga esa labelports:# puertos que va a escuchar-name:httpport:3306targetPort:3306-name:mysqlport:33060targetPort:33060

Con este ClusterIP ya podemos utilizar un port-forward para probar Wordpress

kubectlport-forwarddeployment/my-wordpress8080:80

Con portforward funciona, vamos a crear el LoadBalancer

apiVersion:v1kind:Servicemetadata:name:wordpress-loadbalancerspec:type:LoadBalancerselector:app:my-wordpress# Busca a partir del laberl app: my-wordpresports:-name:"80"port:8080targetPort:80

Y listo, con esto tenemos Wordpress en el puerto 8080 conectado a MySQL

Nos leemos la próxima para mejorar la persistencia

Fixed Buffer: Generando y publicando imágenes Docker con GitHub Actions

$
0
0
Tiempo de lectura:5minutos

¡Después de muchos meses sin escribir, por fin volvemos a la carga! Han pasado muchas cosas durante estos meses (de las que supongo que hablaré en la entrada de los 3 años), pero entre ellas hay una que ha empujado el tema de esta entrada:
Docker está moviendo ficha en lo referente a sus políticas de precios.

Lo que nos lleva a una pregunta obvia, ¿en qué me afecta eso a mí? Pues seguramente en nada, pero tal vez seas una de esas personas que estaban utilizando utilidades como las «builds automáticas» de DockerHub.

Esta es precisamente la parte que más me ha impactado a mí, tengo algunas imágenes Docker que hasta hace poco generaba directamente usando DockerHub, pero ese tiempo se acabó, y ha tocado buscarse otra solución. Esta solución, en la mayoría de los casos va a pasar por utilizar los propios sistemas de CI/CD que ofrecen muchos proveedores, y ya que estamos en GitHub, ¿por qué no usar GitHub Actions para construir la imagen Docker?

Generando una imagen Docker con GitHub

No es la primera entrada en este blog sobre qué son y cómo utilizar GitHub Actions, así que podemos ir al turrón y centrarnos en como generar nuestras imágenes Docker. Esto en sí mismo ya es algo muy útil que podemos utilizar como parte de nuestro proceso de integración continua, para validar que no se está rompiendo nada con un cambio.

Para este pequeño ejemplo que estamos haciendo, vamos a utilizar un Dockerfile muy sencillo, ya que solo queremos ver como generar la imagen Docker con Github Actions, no recrearnos en Docker 🙂 Algo como esto por ejemplo:

FROM alpine
ENTRYPOINT ["echo", "Hello World!"]

Simplemente usando una imagen ‘alpine’, imprimimos por consola ‘Hello World!’.

El primer paso, como toda GitHub Action, es crear el yam correspondiente dentro de la carpata ‘.github/workflows’, en este caso, algo tan simple como esto:

name: Docker GitHub

on: [push, pull_request,workflow_dispatch]

jobs:
  build-and-push-images:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

Sobre esta Action que de momento no hace nada, vamos a añadir el paso que generará la imagen. Para ello vamos a utilizar la acción build-push-action, que es su modo más simple, basta con añadir el paso a nuestro ‘yaml’:

      - name: Build and push Docker image
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: .  //Contexto para el comando Docker
          push: false //Indicamos si queremos hacer push de la imagen

Con esto ya tenemos todo listo, nuestra GitHub Action va a generar una imagen Docker automáticamente.

Publicando una imagen Docker en DockerHub con GitHub

Muy bien, tenemos lista nuestra Action y ya genera la imagen Docker, pero esto aún no resuelve el problema inicial, de que no tengo las auto builds de DockerHub para mantener las imágenes actualizadas. Precisamente por eso, hay que ir un paso más allá y subir la imagen al registro.

Lo primero que vamos a hacer, es añadir una nueva GitHub Action más a nuestro ‘yaml’ (antes de hacer el build & push, obviamente), con la que haremos un login en DockerHub:

      - name: Login to DockerHub
        if: github.ref == 'refs/heads/master'
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

Ten en cuenta que es necesario crear un token en DockerHub y añadirlo junto al usuario como secreto para el repositorio.

Una vez hecho esto, basta con un par de cositas más, editar el paso donde hacemos el build, para indicarle que queremos también hacer un push por un lado, y por otro lado, darle un tag a la imagen:

      - name: Build and push Docker image
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: .
          push: true
          tags: 'fixedbuffer/hello'

Con esto, ya tenemos lista nuestra imagen Docker, y subida a DockerHub. Pero… ¿Y si quiero más de un tag? Es muy habitual que cuando creamos una nueva imagen, le demos un tag especifico y además ‘latest’.

Gestionando múltiples nombres y etiquetas

Vale, ya tenemos el proceso listo, pero como hemos comentado con el tema de los tags, es mejorable para simplificarnos la vida. Es por eso que mi propuesta es utilizar otra GitHub Action que nos va a generar diferentes tags según la configuremos. Esta Action es metadata-action.

Simplemente vamos a tener que configurar la Action y editar un poco la Action con la que generamos la imagen Docker, de modo que utilice como entrada la salida de esta. Lo primero será configurar los metadatos, para lo que añadimos esto a nuestro ‘yaml’:

      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v3
        with:
          images: |
            fixedbuffer/hello
          tags: |
            latest
            type=sha

Como resultado de esta Action, se van a generar las etiquetas ‘fixedbuffer/hello:latest’ y ‘fixedbuffer/hello:sha-COMMIT-SHA’. Esta solo es una configuración muy simple para poder probar que funciona, pero realmente ofrece una gran cantidad de opciones, que puedes consultar en el mismo repositorio.

Ahora, vamos a usar esas etiquetas. La Action que genera y publica la imagen se verá así:

      - name: Build and push Docker image
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Listo, ya tenemos solucionado el problema y se va a generar y subir la imagen con ambos tags.

¿Y si quiero usar otro regristry? (El de GitHub por ejemplo)

Buena pregunta, y la verdad es que tal cual hemos planteado nuestro ‘yaml’, es algo muy muy sencillo. Bastaría con hacer login en el regritry que queramos usar (ghcr, acr, ecs…) y añadir el nombre. Por ejemplo, con DockerHub Y el registry de GitHub nos quedaría una cosa así:

name: Github Registry

on: [push, pull_request, workflow_dispatch]

env:
  IMAGE_NAME: fixedbuffer/hello

jobs:
  build-and-push-images:
    runs-on: ubuntu-latest
    # Asignamos los permisos sobre los recursos de GitHub
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v3
        with:
          images: |
            ${{ env.IMAGE_NAME}}
            ghcr.io/${{ env.IMAGE_NAME}}
          tags: |
            latest
            type=sha

      - name: Login to DockerHub
        if: github.ref == 'refs/heads/master' # Solo master
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Login to GHCR
        if: github.ref == 'refs/heads/master' # Solo master
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push Docker image
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: .
          push: github.ref == 'refs/heads/master' # Solo master
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Conclusión

La verdad es que en mi caso concreto, perder las auto builds de DockerHub fue un problema, ya que tuve que hacer un trabajo extra para añadir la generación de imágenes directamente desde GitHub.

De todos modos, como puedes comprobar es muy muy sencillo utilizar GitHub Actions para generar imágenes Docker. En este artículo hemos hecho una pequeña review de alto nivel, pero usando las dos Actions principales (docker/build-push-action y docker/metadata-action) podemos configurar incluso las plataformas de destino, usar buildx, …

Puedes verlo en marcha en este repo de GitHub (obviamente xD)

**La entrada Generando y publicando imágenes Docker con GitHub Actions se publicó primero en Fixed Buffer.**

Blog Bitix: Aplicaciones adicionales diseñadas para el entorno de escritorio GNOME

$
0
0

Los entornos de escritorio proporcionan la interfaz gráfica de las computadoras, el aspecto de las ventanas, los estilos de los componentes junto con unas guías de interfaz de usuario que especifican como han de ser las aplicaciones en ese entorno de escritorio. El entorno de escritorio y las guías permiten que todas las aplicaciones tengan uniformidad visual y en su experiencia  que facilite al usuario el uso de las aplicaciones sin tener que aprender unas convenciones únicas para cada aplicación. La mayoría de entornos de escritorio integran unas pocas aplicaciones esenciales como explorador de archivos, visor de documentos e imágenes, editor de texto, terminal, reproductor de vídeo, navegador web y comunicación y gestor de software. El resto de aplicaciones necesarias son proporcionadas por desarrolladores ajenos al entorno de escritorio que no tienen por que seguir las mismas guías de estilos, sin embargo, algunas aplicaciones aún siendo de terceros si siguen las mismas guías de estilos del entorno de escritorio que proporcionan algunas funcionalidades adicionales a las de las aplicaciones esenciales.

GNOME

Distribuciones de GNU/Linux hay muchas que se diferencian principalmente en si están patrocinadas por una empresa como Fedora con Red Hat, Ubuntu con Canonical o si están desarrolladas por una comunidad de usuarios como Debian o Arch Linux, su modelo de publicación de versiones puede seguir un calendario como Ubuntu o estar en continua actualización como Arch Linux, otras diferencias son su popularidad medido por el número de usuarios que la utilizan o el entorno de escritorio o gestor de arranque instalado por defecto.

Sin embargo, en el uso habitual de cualquier distribución GNU/Linux las diferencias no son tantas, al final una distribución de GNU/Linux es simplemente una recopilación de programas y librerías de software libre. Los programas en cada una de las distribuciones son exactamente los mismos tanto de línea de comandos con los programas de GNU, el entorno de escritorio con sus aplicaciones integradas o las aplicaciones de terceros preinstaladas. Cada distribución suele tener su propia aplicación gestor de paquetes para instalar y desinstalar programas junto a sus dependencias de sus repositorios oficiales pero en esencia tanto el gestor de paquetes de Debian como de Arch Linux realizan la misma función incluso las distribuciones derivadas utilizan el mismo programa gestor de paquetes.

En realidad la distribución GNU/Linux que se utilice no es lo más relevante, lo importante son las aplicaciones usadas para realizan las tareas. Aplicaciones hay muchas con diferentes propósitos que se pueden clasificar en las siguientes categorías:

  • Ofimática, documentos y escritorio (editor de documentos ofimáticos, editor de textos avanzado, libros electrónicos y cómics, capturador de pantalla, copias de seguridad).
  • Internet y comunicaciones (navegador, correo electrónico, lector de feeds, descargar archivos torrent y descargas directas, mensajería instantánea, videoconferencia, nube privada).
  • Fotos y gráficos (retoque fotográfico).
  • Multimedia, vídeo y audio (reproductor de vídeo, audio, películas y música, editor de vídeo, conversor de vídeo y audio).
  • Juegos.
  • Programación y desarrollo (compiladores, entorno integrado de desarrollo, bases de datos y software de servidor, virtualización).
  • Seguridad y privacidad.

En estos artículos he escrito sobre las aplicaciones más conocidas para cada una de las categorías anteriores:

Estas son las aplicaciones de línea de comandos de GNU/Linux de los cuales son instalados en la mayoría de distribuciones como parte del sistema base.

El propio entorno de escritorio que proporciona la interfaz gráfica también incluye una serie de aplicaciones esenciales básicas que hacen el sistema gráfico usable e incluso sin necesitar aplicaciones de terceros adicionales para los mismos propósitos, sólo son necesarias aplicaciones adicionales de terceros en el caso de requerir funcionalidades más avanzadas o necesidades no cubiertas.

Aplicaciones adicionales del círculo de GNOME

Las aplicaciones del entorno de escritorio de GNOME son aplicaciones sencillas que cubren las necesidades más básicas, para propósitos adicionales específicos es necesario instalar aplicaciones desarrolladas por terceros fuera del entorno de escritorio.

El problema de las aplicaciones de terceros, si es que es un problema, es que no tienen por qué seguir las directrices de diseño de la interfaz del usuario de ningún entorno de escritorio. Esta libertad que tienen las aplicaciones de terceros hacen que las aplicaciones no estén integradas con el escritorio al emplear un diseño totalmente diferente. La guía de estilos de las aplicaciones de GNOME contiene recomendaciones y normas que las aplicaciones deben seguir para este entorno de escritorio, estas guías permiten uniformidad en las aplicaciones y contienen una colección de buenas prácticas en el diseño de aplicaciones para hacerlas más fáciles de usar e intuitivas para los usuarios.

Aplicaciones del círculo de GNOME

Aplicaciones del círculo de GNOMEAplicaciones del círculo de GNOMEAplicaciones del círculo de GNOME

Aplicaciones del círculo de GNOME

Algunas aplicaciones aunque desarrolladas por terceros siguen las guías de estilos de diseño de interfaces del escritorio de GNOME dando la sensación que están perfectamente integradas con el entorno de escritorio. Muchas son aplicaciones distribuidas como paquetes en formato Flatpak que las hace fácil de instalar en cualquier distribución GNU/Linux sin depender de los paquetes oficiales de la distribución.

Las siguientes son aplicaciones sencillas desarrolladas por terceros que siguen las guías de estilos de diseño de interfaces del escritorio de GNOME y que están recomendadas por GNOME, cada una cubre una necesidad específica que si es necesaria permite hacerlo mediante una aplicación con interfaz gráfica en vez de tener que recurrir a otras aplicaciones o la línea de comandos, en conjunto cubren funcionalidades muy diversas, desde un editor de texto en formato markdown hasta un lector de la Wikipedia.

Aplicaciones del círculo de GNOMEAplicaciones del círculo de GNOMEAplicaciones del círculo de GNOME

Aplicaciones del círculo de GNOMEAplicaciones del círculo de GNOME

Algunas aplicaciones del círculo de GNOME

En la descripción de cada aplicación y en su página del repositorio en Flathub están los detalles para instalar la aplicación con Flatpak. Se puede instalar con la aplicación software de GNOME o desde la línea de comandos. Una vez instalada la aplicación Flatpak la mantiene actualizada automáticamente en cada nueva publicación de versión.

Aplicación gestión de software de GNOME

Aplicación para instalar y desinstalar software de GNOME

Comandos para instalar y ejecutar la aplicación con Flatpak.

1
2
$ flatpak install flathub org.gnome.gitlab.somas.Apostrophe

flatpak-install.sh
1
2
$ flatpak run org.gnome.gitlab.somas.Apostrophe

flatpak-run.sh
  • Apostrophe: Un editor Markdown elegante y libre de distracciones
  • Authenticador: Generar códigos de autenticación de doble factor
  • Blanket: Escuche diferentes sonidos
  • Copia de respaldo Pika: Respaldos sencillos basados en borg
  • Copias de seguridad Déjà Dup: Mantenga sus documentos importantes a salvo de cualquier peligro
  • Cozy: Un moderno reproductor de audiolibros
  • Curtail: Comprima sus imágenes
  • Decodificador: Escanear y generar códigos QR
  • Depósito seguro de contraseñas: Gestionar sus contraseñas
  • Descargador de tipografías: Instalar tipografías de fuentes en línea
  • Dialect: Traduce entre idiomas
  • Dibujo: Una aplicación de dibujo para el escritorio GNOME
  • Fragmentos: Un cliente de BitTorrent
  • Gaphor: Herramienta de modelado UML y SysML
  • Hashbrown: Comrprueba las huellas digitales de sus archivos
  • Health: Una aplicación para la monitorización de la salud para el escritorio GNOME
  • Identity: Comparar imágenes y vídeos
  • Khronos: Medir el tiempo de cada tarea de una forma simple sin obstrucciones
  • Kooha: Graba tu pantalla elegantemente
  • Limpiador de metadatos: Ver y limpiar los metadatos en los archivos
  • Mercados: Un rastreador de acciones, divisas y criptodivisas
  • NewsFlash: Siga sus blogs y sitios de noticias favoritos.
  • Ofuscador: Censor de información privada
  • Plots: Dibujado de gráficas simple
  • Podcasts: Aplicación de podcast para GNOME
  • Recortador de vídeo: Recortar vídeos rápidamente
  • Shortwave: Escuchar la radio por internet
  • Solanum: Equilibrio entre tiempo de trabajo y de descanso
  • Tangram: Ejecutar aplicaciones web en su escritorio
  • Tootle: Cliente rápido para Mastodon
  • Webfont Kit Generator: Cree fácilmente los kits@font*face
  • Wike: Lector de Wikipedia

Fixed Buffer: ¡¡FixedBuffer ha cumplido su tercer año!!

$
0
0
Tiempo de lectura:2minutos

Otro año más llega la vuelta de vacaciones y con ello FixedBuffer cumple un año más. Tres años hace desde que empece esta andadura donde voy publicando mis notas sobre nuevas tecnologías y sobre cosas que en general me parecen interesantes.

Es cierto que este último año he estado sin escribir desde febrero, la muerte de mi padre, el COVID, cambios de trabajo y demás cosas me han alejado de escribir en el blog (principalmente por no tener ganas o simplemente no creer que tenía nada interesante para contar). La parte buena es que aunque no he escrito activamente si he seguido participando activamente en la comunidad así que al menos si alguien ha querido saber de mí (no alcanzo a imaginar por qué… xD), no se ha quedado sin la oportunidad.

También voy a aclarar que no todo ha sido malo, y que he cumplido con otras metas personales: he comprado mi casita, sigo siendo MVP y mi mujer todavía no se ha cansado de mí y de todo el tiempo que dedico a estas cosas (toda una santa he de añadir).

Dicho esto, ¿qué va a ser de FixedBuffer de aquí en adelante? Pues la verdad no tengo una idea clara… Me gustaría y voy a intentar escribir una entrada nueva cada 2-3 semanas, el verano me ha servido para recuperar fuerzas y llevo lo suficiente en mi nuevo trabajo como para haber descubierto varias tecnologías muy interesantes de las que escribir, o de cosas que si bien son básicas, no todo el mundo las conoce. Veremos en que se traduce y si no acabaré solo con las charlas (‘traccionando’ que diría alguno 😉 )

Y ya como despedida, solo 2 cosas más. La primera es agradecer a la gente que seguís aquí pese a que no haya escrito demasiado últimamente, la verdad es que ver que el contenido sigue siendo útil es una de las principales razones para seguir tirando líneas 🙂
La segunda, como ya empieza a ser tradición, es el top 5 de las entradas del último año:

  1. Haciendo fácil el acceso a datos con Entity Framework Core (Parte 2)
  2. Inyección de Dependencias en .Net Framework
  3. Worker Service: Cómo crear un servicio .Net Core 3 multiplataforma
  4. Cómo medir tiempos en C# y .Net con precisión
  5. Generación de ficheros «Excel» (xlsx) con ClosedXML

**La entrada ¡¡FixedBuffer ha cumplido su tercer año!! se publicó primero en Fixed Buffer.**

Blog Bitix: Añadir un mapa cartográfico con JavaScript, Leaflet y OpenStreetMap a una página web

$
0
0

Google Maps es un servicio de mapas cartográficos de Google que permite consultar mapas directamente desde la página de Google pero también insertarlo en páginas de terceros. En el caso de insertar mapas en una página de terceros como muchos de otros de sus servicios ofrece con una capa gratuita que cubre un pequeño número de peticiones. Aunque OpenStreetMaps no ofrece el mismo nivel de detalle y calidad de la información que Google Maps permite su uso sin coste incluso con fines comerciales suficiente en muchos casos.

HTML

Un mapa cartográfico permite mostrar una ubicación real a escala en una vista aérea y con diferentes niveles de acercamiento, mostrando calles, zonas verdes, ciudades y comercios de hostelería, comerciales, farmacias, elementos de equipamiento y de otros tipos.

Para mostrar ubicaciones reales de un localización, calle o ciudad Google con su servicio de mapas de Google Maps permite insertar sus mapas en una página web. Google Maps además permite ver a nivel de calle una ubicación.

Sin embargo, Google Maps tiene límites de uso a partir de los cuales hay que pagar por usar el servicio y algunas funcionalidades solo están disponibles en el servicio de pago. Como alternativa están los mapas de OpenStreetMap que tiene una licencia de acceso libre siempre que se otorgue reconocimiento.

Mapas con Leaflet y OpenStreetMap

La librería Leaflet de JavaScript permite insertar un iframe en cualquier página web usando los mapas cartográficos de OpenStreetMap. Soporta marcadores, ventanas emergentes con información, capas vectoriales, navegadores de escritorio y móvil, interacciones para hacer zoom, navegación el teclado, eventos de JavaScript entre otras.

Insertar el mapa requiere importar el JavaScript y el CSS de Leaflet en la página, crear una etiqueta HTML que actúe como contenedor del mapa con el tamaño deseado e iniciar el JavaScript de Leaflet para que inserte las imágenes del mapa al que habrá que proporcionar las coordenadas. Leaflet ofrece la posibilidad de incluir marcadores, figura geométricas y otros tipos de información para enriquecer los mapas cartográficos.

Mapas de OpenStreetMaps en vista callejero con Leaflet

Mapas de OpenStreetMap en vista callejero con Leaflet
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html><html><head>    <title>Leaflet and OpenStreetMaps example</title>    <linkrel="stylesheet"href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="crossorigin=""/>    <scriptsrc="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="crossorigin=""></script>    <styletype="text/css">        #map{            height:800px;        }    </style></head><body>    <divid="map"></div>    <scripttype="text/javascript">        varmap=L.map('map').setView([43.26271,-2.92528],15);        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{            attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'        }).addTo(map);        varpopup=L.popup()            .setLatLng([43.26271,-2.92528])            .setContent('<a href="https://www.youtube.com/watch?v=YcAW-VbTYnY" target="_blank">La capital del mundo</a>');        varmarker=L.marker([43.26271,-2.92528]).bindPopup(popup).openPopup().addTo(map);    </script></body></html>
leaflet-openstreetmap.html

Mapas con Leaflet e imágenes de Google Maps

No he visto que OpenStreetMap ofrezca una vista aérea en modo satélite de las ubicaciones, sin embargo, cambiando el origen de las imágenes Leaflet es capaz de cargar las capas de otros servicios incluído el de Google. Este es el mismo mapa con la vista de callejero y satélite de la misma ubicación utilizando como fuente de las imágenes el servicio de Google.

Mapas de Google en vista callejeroMapas de Google en vista satélite

Mapas de Google en vista callejero y satélite
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html><html><head>    <title>Leaflet and Google Maps example</title>    <linkrel="stylesheet"href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="crossorigin=""/>    <scriptsrc="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="crossorigin=""></script>    <styletype="text/css">        #map{            height:800px;        }    </style></head><body>    <divid="map"></div>    <scripttype="text/javascript">        varmap=L.map('map').setView([43.26271,-2.92528],15);        L.tileLayer('https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',{           maxZoom:20,            subdomains:['mt0','mt1','mt2','mt3']        }).addTo(map);        varpopup=L.popup()            .setLatLng([43.26271,-2.92528])            .setContent('<a href="https://www.youtube.com/watch?v=YcAW-VbTYnY" target="_blank">La capital del mundo</a>');        varmarker=L.marker([43.26271,-2.92528]).bindPopup(popup).openPopup().addTo(map);    </script></body></html>
leaflet-google-maps.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html><html><head>    <title>Lesflet and Google Maps example</title>    <linkrel="stylesheet"href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="crossorigin=""/>    <scriptsrc="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="crossorigin=""></script>    <styletype="text/css">        #map{            height:800px;        }    </style></head><body>    <divid="map"></div>    <scripttype="text/javascript">        varmap=L.map('map').setView([43.26271,-2.92528],15);        L.tileLayer('https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}',{            maxZoom:20,            subdomains:['mt0','mt1','mt2','mt3']        }).addTo(map);        varpopup=L.popup()            .setLatLng([43.26271,-2.92528])            .setContent('<a href="https://www.youtube.com/watch?v=YcAW-VbTYnY" target="_blank">La capital del mundo</a>');        varmarker=L.marker([43.26271,-2.92528]).bindPopup(popup).openPopup().addTo(map);    </script></body></html>
leaflet-google-maps-hybrid.html

Las URLs de Google dependiendo de la capa de imágenes son las siguientes en las que varía los valores del parámetro lyrs.

  • Streets
  • Hybrid
  • Satellite
  • Terrain
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Streets
googleStreets=L.tileLayer('http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',{    maxZoom:20,    subdomains:['mt0','mt1','mt2','mt3']});// Hybrid
googleHybrid=L.tileLayer('http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}',{    maxZoom:20,    subdomains:['mt0','mt1','mt2','mt3']});// Satellite
googleSat=L.tileLayer('http://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}',{    maxZoom:20,    subdomains:['mt0','mt1','mt2','mt3']});// Terrain
googleTerrain=L.tileLayer('http://{s}.google.com/vt/lyrs=p&x={x}&y={y}&z={z}',{    maxZoom:20,    subdomains:['mt0','mt1','mt2','mt3']});
google-maps-urls.js

Una sinfonía en C#: Ejecutar Wordpress + MySQL en Kubernetes paso a paso 2, agregando persistencia

$
0
0

En el post anterior vimos cómo ejecutar Wordpress (Wordpress + MySQL) en Kubernetes, del modo más básico, solo con dos Pods separados. En este post vamos a poner la persistencia en elementos externos (volúmenes) para que los datos tengan un ciclo de vida separado de los Pods.

Mejorando la persistencia

Evidentemente la persistencia se hace dentro de los containers y esto no es ideal. Vamos a agregar algo de storage. Primero creamos el Persisten volumen, como yo estoy en Docker en Windows será del tipo local-storage En este caso este tipo no permite Dynamic Provisioning, así que no hace falta StorageClass Entonces creamos dos PV

kind:PersistentVolumemetadata:name:wp-pvspec:capacity:storage:1GivolumeMode:FilesystemaccessModes:-ReadWriteOncestorageClassName:local-storagelocal:path:/run/desktop/mnt/host/c/k8svolume/wp#windows pathnodeAffinity:required:nodeSelectorTerms:-matchExpressions:-key:kubernetes.io/hostnameoperator:Invalues:-docker-desktop
apiVersion:v1kind:PersistentVolumemetadata:name:mysql-pvspec:capacity:storage:1GivolumeMode:FilesystemaccessModes:-ReadWriteOncestorageClassName:local-storagelocal:path:/run/desktop/mnt/host/c/k8svolume/mysqlnodeAffinity:required:nodeSelectorTerms:-matchExpressions:-key:kubernetes.io/hostnameoperator:Invalues:-docker-desktop

Creamos un persisten volume claim para cada deployment

apiVersion:v1kind:PersistentVolumeClaimmetadata:name:mysql-pvcspec:accessModes:-ReadWriteOncestorageClassName:local-storageresources:requests:storage:1Gi
apiVersion:v1kind:PersistentVolumeClaimmetadata:name:mywordpress-pvcspec:accessModes:-ReadWriteOncestorageClassName:local-storageresources:requests:storage:1Gi

Y por último modificamos los deployments de Wordpress y MySQL para declarar y montar el los claims

apiVersion:apps/v1kind:Deploymentmetadata:name:my-dblabels:app:my-dbspec:replicas:1selector:matchLabels:app:my-dbtemplate:metadata:labels:app:my-dbspec:containers:-name:my-dbimage:mysql:5.7ports:-containerPort:80volumeMounts:-mountPath:/var/lib/mysqlname:my-db-pvenv:-name:MYSQL_ROOT_PASSWORDvalue:"my-secret-pw"-name:MYSQL_DATABASEvalue:"my-db"-name:MYSQL_USERvalue:"my-user"-name:MYSQL_PASSWORDvalue:"my-secret-pw"volumes:-name:my-db-pvpersistentVolumeClaim:claimName:mysql-pvc
apiVersion:apps/v1kind:Deploymentmetadata:name:my-wordpresslabels:app:my-wordpressspec:replicas:1selector:matchLabels:app:my-wordpresstemplate:metadata:labels:app:my-wordpressspec:containers:-name:my-wordpressimage:wordpress:latestvolumeMounts:-name:my-wp-pvmountPath:/var/www/htmlports:-containerPort:80env:-name:WORDPRESS_DB_PASSWORDvalue:"my-secret-pw"-name:WORDPRESS_DB_USERvalue:"my-user"-name:WORDPRESS_DB_NAMEvalue:"my-db"-name:WORDPRESS_DB_HOSTvalue:"mysql"volumes:-name:my-wp-pvpersistentVolumeClaim:claimName:mywordpress-pvc

Y ya está, en el siguiente post mejoraremos la configuración. Nos leemos en la próxima


Variable not found: ¡Feliz día del programador! Y para celebrarlo, volvemos con unos interesantísimos enlaces (edición 453)

$
0
0
Enlaces interesantes

El timeout que dejé programado semanas atrás ya ha finalizado, por lo que hay que ponerse de nuevo las pilas. Y sin duda, ningún día mejor para hacerlo que el Día Internacional del Programador, celebrado de forma más o menos consensuada el día 13 de septiembre (12 si el año es bisiesto), al ser el día 256º de cada año :)

Así que, para iniciar la temporada con buen pie, ahí va una colección de enlaces, que espero os resulten interesantes :-)

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

    Web / HTML / CSS / Javascript

    Visual Studio / Complementos / Herramientas

    Xamarin

    Otros

    Publicado en Variable not found.

    Blog Bitix: Novedades y nuevas características de Java 17

    $
    0
    0

    La versión Java 17 sucede a Java 11 como versión LTS, por ello es una versión más importante que las no LTS anteriores. Incorpora todas las mejoras incluidas en todas las no LTS previas más otras adicionales dede Java 16 publicada seis meses antes. Como versión LTS ofrece un soporte de correcciones de errores, fallos y alertas de seguridad por un periodo de cinco años hasta septiembre de 2026 más un periodo adicional de tres años hasta 2029. La versión 6 del framework de Spring y Spring Boot 3 se tendrán como requisito mínimo Java 17 y Jakarta 9.

    Java

    El ciclo de publicación de una nueva versión de Java cada seis meses está siendo un éxito en la evolución del lenguaje, algunas características no tienen un gran impacto en la plataforma o el lenguaje pero otras sí suponen un gran mejora como las lambdas de Java 8, los módulos de Java 9, inferencia de tipos de Java 10, Java 11 como primera versión LTS con soporte a largo plazo, expresiones switch de Java 12 en vista previa, bloques de texto de Java 13 en vista previa, excepciones NullPointerException más útiles y Records de Java 14, Sealed Classes de Java 15 y encapsulación más fuerte de clases internas del JDK en Java 16 por mencionar simplemente una característica destacada de cada una de ellas.

    Java 17 al ser una versión LTS es más importante que las versiones no LTS anteriores. Las versiones LTS son más atractivas para ciertas organizaciones por sus periodos de soporte extendidos.

    Contenido del artículo

    Introducción

    Java 17 sucede a como versión LTS en septiembre de 2021 a Java 11 que fué publicada hace tres años en septiembre de 2018. Java 17 según la hoja de ruta de Java tiene un soporte de cinco años hasta septiembre de 2026 y tres años más hasta septiembre de 2029 en el periodo de soporte extendido para los clientes que paguen ese soporte.

    Este calendario de soporte claro y simple permite planificar la estrategia de actualización de forma anticipada de las aplicaciones que usen versiones que han dejado de estar soportadas. Las actualizaciones incluyen correcciones de errores, fallos y alertas de seguridad, actualizaciones legales, regulación y de impuestos asi como certificación con otros productos. El software empresarial por ciclo de vida prefiere usar versiones LTS por su soporte extendido, con la publicación de Java 17 está es la versión recomendada.

    En el caso de pasar de la versión 11, anterior LTS, o previas, la versión 17 incluye las numerosas novedades de las versiones no LTS y previa LTS a esta, de la 12 a la 16.

    Spring ha anunciado que la versión 6 de este framework junto a Spring Boot 3 ampliamente usados se basarán en Java 17 y Jakarta EE 9. Estas versiones serán la base mínima requerida de la siguiente generación de aplicaciones Java.

    Spring 6 y Spring Boot 3 se publicará a finales del 2022 cuando Java 17 incluso ya tenga un par de versiones sucesoras. Los entornos integrados de desarrollo como IntelliJ IDEA han sido actualizados para proporcionar soporte desde el primer momento a las nuevas características de Java 17.

    Las mejoras incluidas en esta versión son:

    Nuevas características

    Restaurar la semántica estricta de coma flotante

    El estándar IEEE 754 especifica cómo realizar operaciones de coma flotante y cómo almacenar valores de coma flotante en varios formatos incluyendo en precisión simple (en 32 bits usado en el float de Java) y precisión doble (en 64 bits usado en el double de Java).

    Algunos dispositivos hardware como CPU proporcionan precisiones extendidas con mayor precisión o mayor rango del exponente. En esas arquitecturas con precisiones extendidas puede ser más eficiente usarlas para los resultados intermedios evitando operaciones de redondeo o desbordamientos que de otra manera ocurrirían. Esto hace las operaciones más eficientes pero puede ocasionar resultados diferentes en esas arquitecturas. La precisión extendida en las máquinas x86 con la arquitectura x87 por sus peculiaridades era necesaria ser usada para evitar penalizaciones de rendimiento.

    Antes de las versiones a la JVM 1.2 los cálculos de coma flotante requerían ser estrictas empleando la misma precisión tal como define el estándar IEEE 754 para todos los cálculos intermedios. La semántica estricta de coma flotante era costosa en el hardware x87 por ello en la versión de la JVM 1.2 se cambió la semántica estricta por defecto por para permitir precisiones extendidas produciendo resultados posiblemente más precisos pero a riesgo de resultados menos repetibles entre diferentes arquitecturas.

    Dado que los cálculos de coma flotante mediante x87 ya no son necesarios ni tienen penalización de rendimiento en los procesadores x86 que soportan el conjunto de instrucciones SSE2 introducidas en el Pentium 4 y están al mismo tiempo presentes en los procesadores de AMD y sucesores de Intel, Java 17 de nuevo hace que todas operaciones de coma flotante sean estrictas recuperando de forma efectiva el comportamiento de las versiones anteriores a Java 1.2.

    Generadores de números pseudo-aleatorios mejorado

    En la API de Java hay varias clases que permiten la obtención de números pseudo-aleatorios, estas clases contienen diferentes métodos con código repetido en varias de las implementaciones.

    Se proporciona una nueva interfaz RandomGenerator que proporciona una API uniforme para los generadores de números aleatorios existentes. RandomGenerator proporciona métodos para ints, longs, y doubles con sus variaciones de parámetros. También se proporciona la factoría RandomGeneratorFactory para localizar y construir instancias que implementan la interfaz RandomGenerator usando la API de ServiceLoader.Provider para registrar las implementaciones.

    1
    2
    3
    
    importjava.util.random.RandomGeneratorFactory;RandomGeneratorFactory.of("Random").create().nextInt(0,11)
    RandomGeneratorFactory.java

    Nuevo pipeline de renderizado para macOS

    Se implementa un pipeline de renderizado interno de Java 2D para macOS usando Apple Metal como alternativa al pipeline existente que usa el obsoleto Apple OpenGL API estando preparado para cuando Apple lo elimine.

    Las funcionalidades proporcionadas en el pipeline usando Apple Metal API son equivalentes a las existentes en OpenGL con un rendimiento tan bueno o mejor. Ambos pipelines coexistirán hasta que el pipeline OpenGL se considere obsoleto.

    Portado a macOS/AArch64

    En Java 16 se implementó el portado a AArch64 para Windows, ahora se hace lo equivalente para macOS. Dado que ARM es una plataforma que será más común con el tiempo junto con el anuncio de Apple de su plan a largo plazo de transición de la arquitectura x64 a AArch64 se espera una demanda amplia para el portado de macOS/AArch64 del JDK.

    Marcado como obsoleto para eliminación la Applet API

    Se marca como obsoleta para eliminación la de los Applet. A día de hoy es irrelevante dado que todos los vendedores de navegadores web han eliminado el soporte para los complementos de Java o han anunciado planes para hacerlo.

    Anteriormente en Java 9 con la Applet API fué marcada como deprecada aunque no para eliminación.

    La alternativa similar a los Applets es utilizar Java Web Start, que permitía descargar y lanzar aplicaciones Java como aplicaciones de escritorio sin utilizar el navegador como entorno de ejecución. En Java 9 Java Web Start fué marcado como obsoleto y en Java 11 el su soporte fué eliminado. La alternativa equivalente a los Applets y Java Web Start es OpenWebStart.

    Encapsulación fuerte de las clases internas del JDK

    Se encapsula de forma fuerte impidiendo su uso de todos los elementos internos del JDK de los paquetes java.*, sun.*, com.sun.*, jdk.* y org.* , exceptuando ciertas APIs críticas como sun.misc.Unsafe. En el JDK 16 se cambió el comportamiento por defecto de permitido a fuerte aún siguiendo siendo posible utilizar la opción para relajar la encapsulación. Ya no será posible relajar la encapsulación de los elementos internos mediante la opción de línea de comandos –illegal-access=permit como era posible en el JDK 9 hasta el JDK 16.

    La encapsulación fuerte permite mejorar la seguridad y el mantenimiento del JDK que era uno de los objetivos primarios del proyecto Jigsaw con la incorporación de los módulos. Se aconseja a los desarrolladores migrar del uso de elementos internos a APIs estándar de modo que tanto los desarrolladores de librerías como sus usuarios puedan actualizar sin complicaciones a futuras versiones de Java.

    Eliminación de RMI Activation

    Se elimina el mecanismo de activación de RMI mientras se conserva el resto de RMI. El mecanismo de llamada a procedimiento remoto RMI de Java es una tecnología obsoleta prefiriéndose REST para la integración de sistemas distribuidos, RMI también ha sido superado y mejorado por gRPC.

    Clases sealed

    Las clases sealed fueron propuestas en Java 15 en modo vista previa, en Java 16 fueron propuestas de nuevo con algunos cambios. Las clases sealed son incorporadas de forma final sin cambios respecto a Java 16. Las clases sealed permite limitar que que clases tienen permitido heredar de una clase definida como sealed.

    1
    2
    3
    4
    5
    
    publicabstractsealedclassShapepermitsCircle,Rectangle,Square{...}publicclassCircleextendsShape{...}publicclassRectangleextendsShape{...}publicclassSquareextendsShape{...}
    sealed-classes.java

    Eliminar el compilador experimental AOT y JIT

    Se elimina el soporte experimental de compilación ahead-of-time o AOT y el compilador just-in-time o JIT implementados en Java. Este compilador ha sido usado poco desde su introducción suponiendo un esfuerzo de mantenimiento significativo. Se mantiene la interfaz experimental de compilador JVM basado en Java o JVMCI para que los desarrolladores continúen construyendo externamente versiones del compilador para la compilación JIT.

    La herramienta jaotc fue incorporada en el JDK 9 de forma experimental, usa el compilador Graal que está escrito a su vez en Java. El compilador Graal fue incorporado como compilador JIT experimental en el JDK 10. Los desarrolladores que deseen usar el compilador Graal para realizar compilación AOT o JIT pueden usar GraalVM.

    Marcado como obsoleto para eliminación el Security Manager

    El Security Manager está presente desde la versión de Java 1.0. No ha sido la forma de añadir seguridad en el código Java en el lado cliente desde hace muchos años y ha sido raramente usado para añadir seguridad en el código de lado del servidor. Se marca como obsoleto el Security Manager en consonancia con la Applet API heredada.

    El control de acceso se basa en el principio de menor privilegio que era viable en la reducida librería de clases de Java 1.0 pero con el rápido crecimiento de los paquetes java.* y javax.* ha originado docenas de permisos y cientos de comprobaciones de permisos en todo el JDK. Esto supone un área grande a mantener seguro.

    Ahora se considera que la seguridad es mejor implementarla proporcionando integridad a bajo nivel en la plataforma Java, por ejemplo fortaleciendo los límites de los módulos para prevenir acceso a detalles del JDK, y aislando el entorno de ejecución de Java completo de recursos sensibles mediante mecanismos ajenos al proceso o out-of-process como los contenedores y virtualización.

    Se marca como obsoleto el Security Manager y eliminan algunas de sus capacidades a lo largo de varias versiones y simultáneamente se crean APIs alternativas para ciertas tareas como bloquear la llamada a System::exit u otros casos de uso considerados suficientemente importantes para tener reemplazos.

    En la JEP 411 hay una descripción detallada de las motivaciones de esta eliminación además de su poco uso se proporciona varias deficiencias como un modelo de permisos frágil, un modelo de programación complicado que desincentiva su uso y bajo rendimiento. Tampoco es eficaz para evitar la mayoría de problemas de seguridad más importantes identificados en 2020.

    Filtros de deserialización específicos para cada contexto

    Esto permite a las aplicaciones configurar un filtro de deserialización específico según el contexto y seleccionado dinámicamente mediante una factoría de filtros de la JVM para cada operación de deserialización.

    Nuevas características en vista previa

    Además de las características anteriores se incorporan otras en modo experimental que también se pueden usar pero que podrían cambiar en el futuro.

    Pattern Matching para los switch

    Se mejoran las sentencias y expresiones switch de dos formas:

    • Se extienden las etiquetas case para incluir patrones adicionalmente a constantes.
    • Se añaden dos nuevos tipos de patrones: patrones de protección o guarded patterns y patrones con paréntesis o parenthesized patterns.

    Este es un ejemplo de sentencia if-else de varios niveles con expresiones booleanas usando el operador instanceof, gracias a que el operador instanceof soporta pattern matching se evita los cast de Object al tipo del instanceof, sin embargo, el código de la sentencia if-else sigue siendo de difícil lectura.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    Objecto=123L;Stringformatted=null;if(oinstanceofIntegeri){    formatted=String.format("int %d",i);}elseif(oinstanceofLongl){    formatted=String.format("long %d",l);}elseif(oinstanceofDoubled){    formatted=String.format("double %f",d);}elseif(oinstanceofStrings){    formatted=String.format("String %s",s);}else{    formatted=o.toString();}
    switch-pattern-matching-1.java

    Este es un ejemplo de expresión switch que usa pattern matching para las etiquetas case que sustituye una expresión if-else anterior.

    1
    2
    3
    4
    5
    6
    7
    8
    
    Objecto=123L;Stringformatted=switch(o){    caseIntegeri->String.format("int %d",i);    caseLongl->String.format("long %d",l);    caseDoubled->String.format("double %f",d);    caseStrings->String.format("String %s",s);    default->o.toString();};
    switch-pattern-matching-2.java

    La etiqueta case también soporta la comprobación del valor null que ha de ser especificado explícitamente, para mantener la compatibilidad hacia atrás el defaultcase no cumple con el valor null.

    1
    2
    3
    4
    5
    6
    7
    
    staticvoidtest(Objecto){    switch(o){        casenull->System.out.println("null!");        caseStrings->System.out.println("String");        default->System.out.println("Something else");    }}
    switch-pattern-matching-3.java

    En el primer caso de esta expresión switch se hace uso de una patrón de protección y de un patrón con paréntesis.

    1
    2
    3
    4
    5
    6
    7
    
    staticvoidtest(Objecto){    switch(o){        caseStrings&&(s.length()==1)->...        caseStrings->...        ...    }}
    switch-pattern-matching-4.java

    Un patrón de protección tiene la forma p && (e) donde p es un patrón y e es una expresión booleana, este patrón incluye la unión de todas las variables definidas en el patrón p y la expresión e. Una valor cumple con un patrón de protección si primero cumple el patrón p y segundo la expresión e se evalúa como verdadero, si el valor no cumple p no se evalúa la expresión e.

    Una patrón con paréntesis tiene la forma (p), donde p es un patrón. Una patrón con paréntesis introduce las variables de patrón que son introducidas por el subatrón p. Un valor cumple el patrón parametrizado (p) su cumple el patrón p.

    Foreign Function& Memory API

    La Foreign Function & Memory API o FFM API permite que los programas Java puedan interoperar con código y datos fuera del entorno de ejecución de Java, invocar eficientemente funciones externas (fuera de la JVM) y acceder de forma segura memoria externa (no gestionada por la JVM).

    La FFM API permite a los programa Java llamar a librerías nativas y procesar datos nativos sin la fragilidad y peligro de JNI. Esta es una revisión introducida inicialmente en Java 14 y revisada en Java 15 y 16.

    La API en el módulo jdk.incubator.foreign define varias clases e interfaces para que el código cliente en librerías puedan:

    • Solicitar memoria externa.
    • Manipular y acceder a estructuras de memoria externas.
    • Gestionar el ciclo de vida de los recursos externos.
    • Invocar funciones externas.

    Vector API

    Se añade la Vector API para expresar computaciones vectoriales que son compiladas en tiempo de ejecución en las instrucciones vectoriales de las arquitecturas de CPU soportadas, esto permite conseguir un rendimiento superior al equivalente con las computaciones escalares.

    La Vector API fue integrada en Java 16 en forma de incubación, en esta nueva revisión se incorporan mejoras en respuesta a los comentarios así como a mejoras de rendimiento y otras mejoras significativas en la implementación.

    Adelante más rápido

    Como última nota se está proponiendo lanzar una versión LTS cada dos años en vez de cada tres lo que permitirá a aquellos usuarios que prefieren el soporte extendido tener disponible una versión LTS cada menos tiempo proporcionando más oportunidades de actualización. Por otro lado, hace más atractivas las versiones no-LTS pudiendo los desarrolladores comenzar con una versión no LTS sabiendo que en dos años habrá una versión LTS que poder utilizar en producción.

    Blog Bitix: El proxy inverso Traefik, características y funcionalidades que ofrece

    $
    0
    0

    Un proxy inverso oculta la complejidad de los servicios para los que hace de intermediario. Al situarse como intermediario el proxy inverso es capaz de proporcionar funcionalidades adicionales como balanceo de carga, limitar el número de peticiones por unidad de tiempo, duplicar peticiones o realizar la autenticación entre otras funciones. Traefik es un proxy inverso diseñado para los entornos cloud dinámicos soportando adicionalmente a las anteriores autoconfigurarción a partir de varios proveedores de registro y descubrimiento de servicios como Consul o Docker, también se integra con herramientas para la observabilidad como Prometheus para métricas y Zipkin y Elastic para trazabilidad y registro de log.

    Traefik

    La tendencia de desarrollo es utilizar microservicios, contenedores y computación en la nube. Una característica de este tipo de aplicaciones es que se componen de múltiples elementos muy dinámicos que se crean, eliminan o cambia el número de instancias. La configuración de las herramientas nativas para la nube ha de ser dinámica en vez de estática.

    Una herramienta específica para hacer de proxy inverso adaptada a la nube es Traefik.

    Contenido del artículo

    El proxy inverso Traefik

    Traefik es un proxy inverso y balanceador de carga adaptado a la computación en la nube mediante microservicios. Traefik se integra con los principales componentes de infraestructura configurándose a sí mismo automáticamente y de forma dinámica. Traefik es simple de operar pero capaz de manejar sistemas complejos y grandes en entornos diversos y diferentes capas de la pila de red como HTTP, TCP o UDP. Proporciona funcionalidades de intermediario que aumenta sus capacidades para realizar balanceo de carga o servir como gateway API.

    Como proxy inverso intercepta las peticiones entrantes y las redirige a los servicios adecuados. A diferencia de proxys inversos configurados de forma estática, Traefik usa descubrimiento de servicios para configurarse a sí mismo según los servicios en ejecución. Puede hacer de proxy en diferentes capas de la pila de red proporcionando funcionalidades como balanceo de carga, limitación de peticiones, circuit breaker, duplicación o mirroring, autenticación y más. También soporta terminación de SSL y puede usar un proveedor ACME como Let’s Encrypt para la generación automática de certificados.

    El proxy inverso Traefik

    El proxy inverso Traefik

    El ecosistema de Traefik permite integrarse con otras herramientas destacadas soportando de forma nativa observabilidad con trazabilidad distribuida y con varios proveedores de métricas.

    Traefik posee dos versiones una open source gratuita con varias de las funcionalidades básicas, para los casos de uso empresariales proporciona funcionalidades adicionales como autenticación OAuth2 o integración con Vault, en la tabla que compara ambas versiones se especifica cuales están incluídas en cada una.

    Al iniciar Traefik se integra un panel de información o dashboard en el que observar las rutas, servicios y middelwares configurados, dado el entorno dinámico de la computación en la nube y microservicios permite ver el estado del sistema.

    El panel de información o dashboard integrado de Traefik

    El panel de información o dashboard integrado de TraefikEl panel de información o dashboard integrado de TraefikEl panel de información o dashboard integrado de Traefik

    El panel de información o dashboard integrado de Traefik

    Casos de uso y características

    Los principales casos de uso deTraefik son:

    • Balanceador de carga: permite distribuir la carga de peticiones con un enrutamiento flexible en la capa 4 (TCP y UDP) y 7 (HTTP, aplicación) junto con un conjunto amplio de midleware que permite escalado dinámico, despliegues blue-green y canary sin caídas, duplicación de peticiones y más.
    • API gateway: usar Traefik como proxy inverso delante de los servicios permite delegar a Traefik aspectos funcionales transversales incluyendo autenticación, limitación de peticiones y terminación de SSL. Estas capacidades son expandibles mediante complementos o plugins.
    • Kubernetes Ingress: Traefik se puede usar como controlador Kubernetes Ingress para añadir la flexibilidad y facilidad de uso a los despliegues de Kubernetes asi como al resto de su infraestructura de red.
    • Gestión de certificados: Traefik soporta de forma nativa gestión de certificados de proveedores ACME como Let’s Encrypt así como certificados actualizables de forma dinámica definidos por el usuario.

    Sus características son:

    • Enrutado y balanceo de carga: capa de enrutado flexible en la capa 4 y 7, soporta los protocolos HTTP, HTTP/2, TCP, UDP, Websockets, gRPC, despliegues blue-green y canary, fijación de sesión o session stickness y comprobaciones de salud.
    • Seguridad: automatización de HTTP, soporte para Let’s Encrypt, certificados personalizados y autenticación.
    • Configuración dinámica: a través de descubrimiento de servicios (Kubernetes, Docker Swarm, Red Hat OpenShift, Rancher, Amazon ECS, key-value stores) y funcionales de intermediario o middelware (circuit breakers, reintentos, buffering, copresión de la respuesta, cabeceras o limitación de peticiones).
    • Observabilidad: posee un panel informativo de forma nativa, trazabilidad distribuida (Jaeger, Open Tracing, Zipkin) y métricas en tiempo real (Datadog, Grafana, InfluxDB, Prometheus, StatsD).

    Estas funcionalidades son extensibles mediante plugins.

    Conceptos

    Como proxy inverso la funcionalidad de Traefik es redirigir las peticiones entrantes a los servicios de backend para los que hace de proxy. Traefik emplea los siguientes conceptos fundamentales para su configuración:

    • Proveedores: permiten descubrir los servicios disponibles proporcionando su ubicación y salud y al mismo tiempo realizar la configuración de Traefik de forma dinámica.
    • Entrypoints: son los puertos por los que entra el tráfico de red y el protocolo usado HTTP, TCP o UDP.
    • Enrutadores: analizan las peticiones entrantes en base a unas reglas que utilizan el nombre de dominio, ruta o cabecera, definen que las funcionalidades de middelware que se aplican y a que servicios se redirigen.
    • Servicios: son los destinos de las peticiones entrantes pudiendo aplicar funcionalidad de balanceo de carga entre las diferentes instancias de los servicios de backend para los que se hace de proxy.
    • Middlewares: pueden actualizar la petición como añadir cabeceras HTTP, actualizar la ruta o realizar acciones de intermediario como autenticación o limitación de peticiones.

    Ejemplos de funcionalidades

    En este ejemplo se utiliza Traefik como proxy inverso para dos instancias de servidor web Nginx. La configuración de los entry points de Traefik es estática que en el ejemplo se define un un archivo de configuración estático.

    La configuración de los enrutadores, servicios y middlewares es dinámica pudiendo actualizarse sin necesidad de reiniciar Traefik. La configuración dinámica la obtiene de los proveedores como Consul o Docker donde los servicios al iniciarse incluyen metainformación que Traefik obtiene se autoconfigura como se muestra en el artículo Microservicios con Spring Cloud, Consul, Nomad y Traefik. En el caso de este ejemplo por sencillez la configuración dinámica se proporciona a Traefik en un archivo de texto, aún siendo manual escribir esta configuración Traefik la puede recargar y aplicar sin necesidad de reiniciar el servidor.

    La configuración de Traefik del ejemplo se divide en tres secciones que son: enrutadores, middlewares y servicios. En la configuración se definen varios enrutadores que aplican reglas en función del host de la petición, los enrutadores definen que middlewares se aplican y a que servicios se redirigen las peticiones coincidentes.

    Esta es la configuración estática de Traefik.

    1
    2
    3
    4
    5
    6
    7
    
    providers:file:watch:truefilename:/etc/traefik/traefik-dynamic.ymlapi:insecure:truedashboard:true
    traefik.yml

    El archivo de Docker Compose que inicia Traefik y los servidores de Nginx de backend.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    version:'3.7'services:traefik:    image:traefik:latest    ports:      - "8090:80"      - "8091:8080"    volumes:      - ./:/etc/traefik/nginx-1:    image:nginx:latest    volumes:      - ./nginx-1:/usr/share/nginx/html:ro    ports:      - "8080:80"nginx-2:    image:nginx:latest    volumes:      - ./nginx-2:/usr/share/nginx/html:ro    ports:      - "8081:80"
    docker-compose.yml

    Y los archivos HTML de los servidores web.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    <!DOCTYPE html><html><head>    <title>Nginx 1</title>    <linkrel="icon"href="data:,"></head><body>    Nginx 1
    </body></html>
    index-1.html
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    <!DOCTYPE html><html><head>    <title>Nginx 2</title>    <linkrel="icon"href="data:,"></head><body>    Nginx 2
    </body></html>
    index-2.html

    Balanceador de carga

    Un balanceador de carga permite distribuir la carga entre las diferentes instancias del servicio de backend. Por defecto, se aplican una estrategia round-robin para distribuir la carga de forma equitativa entre las diferentes instancias.

    Con esta configuración al realizar peticiones se distribuyen entre la instancia nginx-1 y nginx-2 de forma alternativa. La primera petición a la instancia nginx-1, la segunda a la instancia nginx-2 y la tercera de nuevo a la instancia nginx-1.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    http:routers:    ...    nginx:      rule:"Host(`nginx.127.0.0.1.sslip.io`)"      middlewares:        - nginx-ratelimit      service:"nginx"    ...middlewares:    ...services:    ...    nginx:      loadBalancer:        servers:          - url:http://nginx-1:80/          - url:http://nginx-2:80/        passHostHeader:true    ...
    traefik-dynamic-load-balancer.yml
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    $ curl http://nginx.127.0.0.1.sslip.io:8090/
    <!DOCTYPE html>
    <html>
    <head>
        <title>Nginx 1</title>
        <link rel="icon"href="data:,">
    </head>
    <body>
        Nginx 1</body>
    </html>
    $ curl http://nginx.127.0.0.1.sslip.io:8090/
    <!DOCTYPE html>
    <html>
    <head>
        <title>Nginx 2</title>
        <link rel="icon"href="data:,">
    </head>
    <body>
        Nginx 2</body>
    </html>
    $ curl http://nginx.127.0.0.1.sslip.io:8090/
    <!DOCTYPE html>
    <html>
    <head>
        <title>Nginx 1</title>
        <link rel="icon"href="data:,">
    </head>
    <body>
        Nginx 1</body>
    </html>
    curl-load-balancer.sh

    Balanceador de carga con peso

    A veces interesa no distribuir la carga de forma uniforme entre las diferentes instancias de los servicios de backend, sino realizar un balanceo de carga con peso.

    En este caso el balanceo de carga se configura para que la instancia de nginx-1 tenga un peso de 3 y la instancia de nginx-2 tenga un peso de 1, según estos pesos la instancia nginx-1 de cada 4 peticiones recibe 3 mientras que la instancia nginx-2 de cada 4 peticiones recibe 1.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    http:routers:    ...    nginx-weighted:      rule:"Host(`nginx-weighted.127.0.0.1.sslip.io`)"      middlewares:        - nginx-ratelimit      service:"nginx-weighted"    ...middlewares:    ...services:    ...    nginx-weighted:      weighted:        services:          - name:nginx-1            weight:3          - name:nginx-2            weight:1    ...
    traefik-dynamic-load-balancer-weighted.yml
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    
    $ curl http://nginx-weighted.127.0.0.1.sslip.io:8090/
    <!DOCTYPE html>
    <html>
    <head>
        <title>Nginx 1</title>
        <link rel="icon"href="data:,">
    </head>
    <body>
        Nginx 1</body>
    </html>
    $ curl http://nginx-weighted.127.0.0.1.sslip.io:8090/
    <!DOCTYPE html>
    <html>
    <head>
        <title>Nginx 1</title>
        <link rel="icon"href="data:,">
    </head>
    <body>
        Nginx 1</body>
    </html>
    $ curl http://nginx-weighted.127.0.0.1.sslip.io:8090/
    <!DOCTYPE html>
    <html>
    <head>
        <title>Nginx 1</title>
        <link rel="icon"href="data:,">
    </head>
    <body>
        Nginx 1</body>
    </html>
    $ curl http://nginx-weighted.127.0.0.1.sslip.io:8090/
    <!DOCTYPE html>
    <html>
    <head>
        <title>Nginx 2</title>
        <link rel="icon"href="data:,">
    </head>
    <body>
        Nginx 2</body>
    </html>
    $ curl http://nginx-weighted.127.0.0.1.sslip.io:8090/
    <!DOCTYPE html>
    <html>
    <head>
        <title>Nginx 1</title>
        <link rel="icon"href="data:,">
    </head>
    <body>
        Nginx 1</body>
    </html>
    curl-load-balancer-weighted.sh

    Limitar número de peticiones

    Para evitar que un servicio reciba más peticiones de las que es capaz de procesar según su nivel de servicio, con el objetivo de evitar que se sature y falle o evitar denegación de servicio por una carga excesiva es posible establecer un límite en el número de peticiones que se envían a los servicios de backend. El límite se puede establecer de forma global para todas las peticiones o agruparse según la dirección IP origen o el valor de una cabecera.

    En esta configuración se establece que el servicio de backend no reciba más de una petición por segundo, en caso de que se realicen más peticiones por unidad de tiempo que este límite Traefik devuelve un error 429 Too Many Requests.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    http:routers:    ...    nginx:      rule:"Host(`nginx.127.0.0.1.sslip.io`)"      middlewares:        - nginx-ratelimit      service:"nginx"    ...middlewares:    nginx-ratelimit:      rateLimit:        average:1services:    ...
    traefik-dynamic-rate-limit.yml
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    $ curl -v http://nginx.127.0.0.1.sslip.io:8090/
    *   Trying 127.0.0.1:8090...
    * Connected to nginx.127.0.0.1.sslip.io (127.0.0.1) port 8090(#0)> GET / HTTP/1.1
    > Host: nginx.127.0.0.1.sslip.io:8090
    > User-Agent: curl/7.78.0
    > Accept: */*
    > 
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 429 Too Many Requests
    < Retry-After: 1< X-Retry-In: 565.087221ms
    < Date: Sun, 19 Sep 2021 12:32:41 GMT
    < Content-Length: 17< Content-Type: text/plain;charset=utf-8
    < 
    * Connection #0 to host nginx.127.0.0.1.sslip.io left intact
    curl-rate-limit.sh

    Duplicar peticiones o mirroring

    Este middleware permite duplicar la petición que se envía a un servicio a otros servicios descartando el resultado devuelto por esos otros servicios.

    Esto puede ser útil en el caso de aplicar el patrón de estrangulación ya que permite probar las peticiones sin riesgos. El servicio heredado continúa recibiendo y procesando las peticiones a la vez que el nuevo servicio recibe las mismas peticiones, una vez que el nuevo servicio se comporta de la forma esperada las peticiones del servicio heredado se redirigen al nuevo servicio completando la estrangulación.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    http:routers:    ...    nginx-mirroring:      rule:"Host(`nginx-mirroring.127.0.0.1.sslip.io`)"      service:        - nginx-mirroringmiddlewares:    ...services:    ...    nginx-mirroring:      mirroring:        service:nginx-1        mirrors:          - name:nginx-2            percent:50
    traefik-dynamic-mirroring.yml

    Al hacer la petición el resultado que se devuelve es el nginx-1.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    $ curl http://nginx-mirroring.127.0.0.1.sslip.io:8090/
    <!DOCTYPE html>
    <html>
    <head>
        <title>Nginx 1</title>
        <link rel="icon"href="data:,">
    </head>
    <body>
        Nginx 1</body>
    </html>
    curl-mirroring.sh

    Traefik al mismo tiempo que realiza la petición a nginx-1 se realiza a nginx-2 como se observa en las trazas de los servidores Nginx.

    1
    2
    
    nginx-1_1  | 172.20.0.2 - - [19/Sep/2021:12:34:39 +0000] "GET / HTTP/1.1" 200 136 "-""Mozilla/5.0 (X11; Linux x86_64; rv:92.0) Gecko/20100101 Firefox/92.0""172.20.0.1"
    nginx-2_1  | 172.20.0.2 - - [19/Sep/2021:12:34:39 +0000] "GET / HTTP/1.1" 200 136 "-""Mozilla/5.0 (X11; Linux x86_64; rv:92.0) Gecko/20100101 Firefox/92.0""172.20.0.1"
    curl-mirroring-nginx.out

    Otras funcionalidades

    Hay otros middlewares que se pueden aplicar como el de retry para reintentar las peticiones en caso de fallo, aplicar el patrón circuit breaker para aplicar resiliencia evitando enviar peticiones a un servicio que está fallando, autenticación, reescribir el path de las peticiones o quitar un prefijo del path y añadir o eliminar cabeceras.

    Al aplicar el patrón de estrangulación para reemplazar aplicaciones heredadas la solución es añadir un intermediario como Traefik que permita redirigir las peticiones a la aplicación heredada o a su reemplazo cuando esté esté implementado. Este intermediario permite ir reemplazando de forma incremental la aplicación heredada.

    Traefik también permite delegar la autenticación en Keycloak u otros servicios con los middlewaresForward Auth, Digest Auth y Basic Auth.

    Terminal

    El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:
    docker-compose up

    Variable not found: Enlaces interesantes 454

    $
    0
    0
    Enlaces interesantes

    Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

    Por si te lo perdiste...

    .NET Core / .NET

    ASP.NET Core / ASP.NET / Blazor

    Azure / Cloud

    Conceptos / Patrones / Buenas prácticas

    Data

      Web / HTML / CSS / Javascript

      Visual Studio / Complementos / Herramientas

      Xamarin / Maui

      Otros

      Publicado en Variable not found.

      Una sinfonía en C#: Ejecutar Wordpress + MySQL en Kubernetes paso a paso 3, configuración

      $
      0
      0

      En el post anterior Agregamos Persisten Volumens y Persisten Volume Claims para tener un persistencia más allá del ciclo de vida de los Pods, en este Post vamos a mover la configuración a ConfigMaps y Secrets.

      Crear config maps

      El siguiente paso es pasar las environment variables a configuración, de modo de poder modificarlas y que sea escalable. De momento no vamos a crear secrets, solo pasar los valores a un configmap

      Primero creamos el configmap, de momento con los secrets y el mismo para ambas aplicaciones

      apiVersion:v1kind:ConfigMapmetadata:labels:app:my-wordpressname:mywordpress-configdata:MYSQL_RANDOM_ROOT_PASSWORD:'1'MYSQL_DATABASE:passwordMYSQL_USER:readWriteMYSQL_PASSWORD:passwordMYSQL_HOST:mysql

      Y modificamos los deployment para cargar sus valores en las variables de entorno

      apiVersion:apps/v1kind:Deploymentmetadata:name:my-dblabels:app:my-dbspec:replicas:1selector:matchLabels:app:my-dbtemplate:metadata:labels:app:my-dbspec:containers:-name:my-dbimage:mysql:5.7ports:-containerPort:80volumeMounts:-mountPath:/var/lib/mysqlname:my-db-pvenv:-name:MYSQL_RANDOM_ROOT_PASSWORDvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_RANDOM_ROOT_PASSWORD-name:MYSQL_DATABASEvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_DATABASE-name:MYSQL_USERvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_USER-name:MYSQL_PASSWORDvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_PASSWORDvolumes:-name:my-db-pvpersistentVolumeClaim:claimName:mysql-pvc
      apiVersion:apps/v1kind:Deploymentmetadata:name:my-wordpresslabels:app:my-wordpressspec:replicas:1selector:matchLabels:app:my-wordpresstemplate:metadata:labels:app:my-wordpressspec:containers:-name:my-wordpressimage:wordpress:latestvolumeMounts:-name:my-wp-pvmountPath:/var/www/htmlports:-containerPort:80env:-name:WORDPRESS_DB_PASSWORDvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_PASSWORD-name:WORDPRESS_DB_USERvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_USER-name:WORDPRESS_DB_NAMEvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_DATABASE-name:WORDPRESS_DB_HOSTvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_HOSTvolumes:-name:my-wp-pvpersistentVolumeClaim:claimName:mywordpress-pvc

      Proteger secrets

      Los secrets o passwords de la base de datos en el yaml del config map no son una buena idea, podemos hacer dos cosas:

      • Crear dos objetos secret en yaml
      • Crear los secrets por línea de comandos

      Cada uno tiene sus ventajas y desventajas.

      Crear dos objectos secret Ya que los secrets se guardan en base64 primero hay que encodearlos

      apiVersion:v1kind:Secretmetadata:name:mysecretstype:Opaquedata:MYSQL_PASSWORD:bXlwYXNzd29yZA==

      Modificamos el configmap para quitar el password y modificamos los deployments para leer el secret

      apiVersion:v1kind:ConfigMapmetadata:labels:app:my-wordpressname:mywordpress-configdata:MYSQL_DATABASE:passwordMYSQL_USER:readWriteMYSQL_HOST:mysqlMYSQL_RANDOM_ROOT_PASSWORD:'1'
      apiVersion:apps/v1kind:Deploymentmetadata:name:my-dblabels:app:my-dbspec:replicas:1selector:matchLabels:app:my-dbtemplate:metadata:labels:app:my-dbspec:containers:-name:my-dbimage:mysql:5.7ports:-containerPort:80volumeMounts:-mountPath:/var/lib/mysqlname:my-db-pvenv:-name:MYSQL_RANDOM_ROOT_PASSWORDvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_RANDOM_ROOT_PASSWORD-name:MYSQL_DATABASEvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_DATABASE-name:MYSQL_USERvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_USER-name:MYSQL_PASSWORDvalueFrom:secretKeyRef:name:mysecretskey:MYSQL_PASSWORDvolumes:-name:my-db-pvpersistentVolumeClaim:claimName:mysql-pvc-name:my-db-configconfigMap:name:mywordpress-config
      apiVersion:apps/v1kind:Deploymentmetadata:name:my-wordpresslabels:app:my-wordpressspec:replicas:1selector:matchLabels:app:my-wordpresstemplate:metadata:labels:app:my-wordpressspec:containers:-name:my-wordpressimage:wordpress:latestvolumeMounts:-name:my-wp-pvmountPath:/var/www/htmlports:-containerPort:80env:-name:WORDPRESS_DB_PASSWORDvalueFrom:secretKeyRef:name:mysecretskey:MYSQL_PASSWORD-name:WORDPRESS_DB_USERvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_USER-name:WORDPRESS_DB_NAMEvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_DATABASE-name:WORDPRESS_DB_HOSTvalueFrom:configMapKeyRef:name:mywordpress-configkey:MYSQL_HOSTvolumes:-name:my-wp-pvpersistentVolumeClaim:claimName:mywordpress-pvc

      Genial, el último paso sería para no tener el secret en un archivo (aunque se puede restringir su acceso) es crearlo por línea de comandos Borramos el existente y lo creamos por línea de comandos

      kubectldeletesecretmysecretskubectlcreatesecretgenericmysecrets--from-literal=MYSQL_PASSWORD='bXlwYXNzd29yZA=='kubectlgetsecretmysecrets-oyaml

      Alternativamente podemos crearlo por línea de comandos a partir de un file (por ejemplo si es un texto largo o un certificado, etc.)

      kubectlcreatesecretgenericdb-user-pass--from-file=username=./username.txt--from-file=password=./password.txt

      Nos leemos.

      Viewing all 2699 articles
      Browse latest View live