<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>aprenderDevOps</title>
	<atom:link href="https://aprenderdevops.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://aprenderdevops.com/</link>
	<description>Para profesionales TI interesados en DevOps</description>
	<lastBuildDate>Thu, 15 Aug 2024 03:04:44 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.5</generator>

<image>
	<url>https://aprenderdevops.com/wp-content/uploads/2017/10/cropped-favicon_aprenderDevOps-32x32.png</url>
	<title>aprenderDevOps</title>
	<link>https://aprenderdevops.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Despliegue de una aplicación web Python en Docker con construcción multi-etapa</title>
		<link>https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-construccion-multi-etapa/</link>
					<comments>https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-construccion-multi-etapa/#respond</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Sat, 08 Apr 2023 11:30:00 +0000</pubDate>
				<category><![CDATA[Contenedores]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[flask]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[uwsgi]]></category>
		<guid isPermaLink="false">https://aprenderdevops.com/?p=909</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker.png" class="webfeedsFeaturedVisual wp-post-image" alt="Despliegue de una aplicación web Python en Docker con construcción multi-etapa" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" fetchpriority="high" srcset="https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker.png 700w, https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker-300x129.png 300w" sizes="(max-width: 700px) 100vw, 700px" /><p>En una entrada anterior vimos cómo desplegar una aplicación web Python en Docker y posteriormente añadimos NGINX como proxy inverso y balanceador de carga. En esta ocasión vamos a mejorar la construcción de la imagen Docker que utilizamos para desplegar la aplicación web Python, y lo haremos utilizando construcción multi-etapa o multi-stage build. Construcción multi-etapa [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-construccion-multi-etapa/">Despliegue de una aplicación web Python en Docker con construcción multi-etapa</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker.png" class="webfeedsFeaturedVisual wp-post-image" alt="Despliegue de una aplicación web Python en Docker con construcción multi-etapa" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" srcset="https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker.png 700w, https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker-300x129.png 300w" sizes="(max-width: 700px) 100vw, 700px" />
<p>En una entrada anterior vimos <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker/">cómo desplegar una aplicación web Python en Docker</a> y posteriormente añadimos <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-nginx-como-proxy-inverso-y-balanceador-de-carga/">NGINX como proxy inverso y balanceador de carga</a>.</p>



<p>En esta ocasión vamos a mejorar la construcción de la imagen Docker que utilizamos para desplegar la aplicación web Python, y lo haremos utilizando <strong>construcción multi-etapa o multi-stage build.</strong></p>



<span id="more-909"></span>



<h2 class="wp-block-heading">Construcción multi-etapa de imágenes o multi-stage build</h2>



<p>La construcción de imágenes en múltiples etapas o construcción multi-stage fue introducida por primera vez en la versión 17.05 de Docker, que se lanzó en mayo de 2017.</p>



<p>La construcción multi-stage consiste en utilizar múltiples etapas en la construcción de una imagen de contenedor. En cada etapa se puede utilizar una imagen base diferente, y se construye una imagen intermedia que contiene un conjunto específico de dependencias o configuraciones. Se pueden copiar selectivamente artefactos de una etapa a otra, dejando atrás todo lo que no se quiera incluir en la imagen final.</p>



<p>El resultado final de la construcción multi-stage es una imagen de contenedor que contiene sólo los componentes necesarios para que la aplicación se ejecute correctamente y no contiene los componentes innecesarios que se utilizaron durante el proceso de construcción.</p>



<h3 class="wp-block-heading">Beneficios de la construcción multi-etapa de imágenes o multi-stage build</h3>



<p>Algunos de los beneficios de la construcción multi-etapa son:</p>



<ul class="wp-block-list">
<li>Tamaño reducido de la imagen: la construcción multi-stage permite reducir el tamaño final de la imagen de contenedor eliminando los componentes innecesarios utilizados durante el proceso de construcción. Esto puede ser especialmente importante en entornos de producción donde el tamaño de la imagen puede afectar a la velocidad de despliegue de la aplicación.</li>



<li>Mayor seguridad: al utilizar múltiples etapas para construir una imagen de contenedor, se pueden aplicar diferentes medidas de seguridad en cada etapa, como la eliminación de credenciales de construcción o la reducción de la superficie de ataque.</li>



<li>Mayor eficiencia: la construcción multi-stage permite la reutilización de capas de imágenes previamente construidas, lo que acelera significativamente el proceso de construcción.</li>



<li>Mayor flexibilidad: la construcción multi-stage permite la creación de imágenes de contenedor que pueden ser fácilmente personalizadas para diferentes entornos y casos de uso.</li>
</ul>



<h2 class="wp-block-heading">¿Qué necesitáis para hacer este laboratorio?</h2>



<p>Para hacer este laboratorio, sólo se requiere un equipo con Docker instalado. En caso de no tener Docker instalado, se pueden seguir las&nbsp;<a href="https://docs.docker.com/install/">instrucciones de instalación</a>&nbsp;correspondientes a vuestro sistema en la web oficial de Docker.</p>



<p>También podéis hacer este laboratorio en&nbsp;<a href="https://killercoda.com/aprenderdevops/scenario/docker-uwsgi-multi-stage">Killercoda</a>.</p>



<h2 class="wp-block-heading">Construcción multi-etapa de nuestra imagen</h2>



<p>Como ya vimos en la entrada <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker/">Despliegue de una aplicación web Python en Docker</a>, para poder ejecutar nuestra aplicación necesitaremos un servidor de aplicaciones WSGI como uWSGI. Por lo tanto, construiremos una imagen Docker que contenga dicho servidor y nuestra aplicación web Python.</p>



<h3 class="wp-block-heading">Dockerfile multi-stage</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; gutter: false; title: ; notranslate">
# Version de Python (solo mayor y menor)
ARG _PYTHON_VERSION=3.11

# Etapa build
FROM python:${_PYTHON_VERSION} AS build
LABEL maintainer=&quot;Jose Arturo Fernandez &lt;jarfernandez@aprenderdevops.com&gt;&quot;

# Se instala uWSGI y todas las librerias que necesita la aplicacion
COPY WebApp/requirements.txt requirements.txt
RUN pip install uwsgi &amp;&amp; pip install -r requirements.txt
 
# Etapa run
FROM python:${_PYTHON_VERSION}-slim AS run

# Es necesario volver a incluir en esta etapa esta variable
ARG _PYTHON_VERSION

# Puerto HTTP por defecto para uWSGI
ARG UWSGI_HTTP_PORT=8000
ENV UWSGI_HTTP_PORT=$UWSGI_HTTP_PORT

# Aplicacion por defecto para uWSGI
ARG UWSGI_APP=webapp
ENV UWSGI_APP=$UWSGI_APP

# Se instalan dependencias
RUN apt-get update &amp;&amp; apt-get install -y libxml2

# Se crea un usuario para arrancar uWSGI
RUN useradd -ms /bin/bash admin
USER admin

# Se copia el contenido de la imagen builder
COPY --from=build /usr/local/lib/python${_PYTHON_VERSION}/site-packages /usr/local/lib/python${_PYTHON_VERSION}/site-packages
COPY --from=build /usr/local/bin/uwsgi /usr/local/bin/uwsgi

# Se copia el contenido de la aplicacion
COPY WebApp /WebApp

# Se copia el fichero con la configuración de uWSGI
COPY uwsgi.ini uwsgi.ini

# Se establece el directorio de trabajo
WORKDIR /WebApp

# Se crea un volumen con el contenido de la aplicacion
VOLUME /WebApp

# Se inicia uWSGI
ENTRYPOINT &#x5B;&quot;uwsgi&quot;, &quot;--ini&quot;, &quot;/uwsgi.ini&quot;]
</pre></div>


<h3 class="wp-block-heading">Instrucciones</h3>



<p>Para construir la imagen ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker build -t aprenderdevops/uwsgi .
</pre></div>


<p>Para arrancar el contenedor ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker run -d -p 8080:8000 --restart unless-stopped -v $(pwd)/WebApp:/WebApp aprenderdevops/uwsgi
</pre></div>


<p>Una vez arrancado el contenedor, abrimos un navegador web y accedemos a http://localhost:8080. Nos mostrará una página web con el texto “Hello, World!”.</p>



<p>También podéis ver la ejecución de estas instrucciones en el siguiente vídeo:</p>



<script async id="asciicast-Rrdgcey2rxoWg5bajYqnXHRC5" src="https://asciinema.org/a/Rrdgcey2rxoWg5bajYqnXHRC5.js"></script>



<h2 class="wp-block-heading">Código fuente del laboratorio</h2>



<p>Podéis encontrar en GitHub el código fuente de este laboratorio en&nbsp;<a href="https://github.com/aprenderdevops/docker-uwsgi">https://github.com/aprenderdevops/docker-uwsgi</a>. <strong>Los cambios del Dockerfile para que sea multi-stage están en la rama multi-stage, no en la master.</strong></p>
<p>La entrada <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-construccion-multi-etapa/">Despliegue de una aplicación web Python en Docker con construcción multi-etapa</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-construccion-multi-etapa/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Despliegue de una aplicación web Python en Docker con NGINX como proxy inverso y balanceador de carga</title>
		<link>https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-nginx-como-proxy-inverso-y-balanceador-de-carga/</link>
					<comments>https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-nginx-como-proxy-inverso-y-balanceador-de-carga/#respond</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Mon, 06 Mar 2023 00:15:18 +0000</pubDate>
				<category><![CDATA[Contenedores]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[flask]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[uwsgi]]></category>
		<guid isPermaLink="false">https://aprenderdevops.com/?p=816</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-1.png" class="webfeedsFeaturedVisual wp-post-image" alt="Despliegue de una aplicación web Python en Docker con NGINX como proxy inverso y balanceador de carga" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" srcset="https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-1.png 700w, https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-1-300x129.png 300w" sizes="(max-width: 700px) 100vw, 700px" /><p>En una entrada anterior vimos cómo desplegar una aplicación web Python en Docker. En esta ocasión vamos a desplegar la misma aplicación, con una modificación mínima, pero por delante levantaremos un contenedor con NGINX que hará de proxy inverso y balanceador de carga. Un proxy inverso es un servidor que actúa como intermediario entre los [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-nginx-como-proxy-inverso-y-balanceador-de-carga/">Despliegue de una aplicación web Python en Docker con NGINX como proxy inverso y balanceador de carga</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-1.png" class="webfeedsFeaturedVisual wp-post-image" alt="Despliegue de una aplicación web Python en Docker con NGINX como proxy inverso y balanceador de carga" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-1.png 700w, https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-1-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" />
<p>En una entrada anterior vimos cómo <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker/">desplegar una aplicación web Python en Docker</a>. En esta ocasión vamos a desplegar la misma aplicación, con una modificación mínima, pero por delante levantaremos un contenedor con <a href="https://www.nginx.com/">NGINX</a> que hará de proxy inverso y balanceador de carga.</p>



<span id="more-816"></span>



<p>Un proxy inverso es un servidor que actúa como intermediario entre los clientes y los servidores web, y que se utiliza para proteger y optimizar el acceso a los servidores.</p>



<p>Cuando un cliente se conecta a un servidor a través de un proxy inverso, la petición del cliente se enruta primero al proxy inverso, que la reenvía al servidor de destino correspondiente. De esta manera, el proxy inverso puede realizar funciones de filtrado, balanceo de carga, caché, encriptación y autenticación de manera transparente para el cliente y el servidor.</p>



<p>Un balanceador de carga es un componente que distribuye el tráfico entrante entre varios servidores con el objetivo de mejorar el rendimiento, la disponibilidad y la escalabilidad de los sistemas y las aplicaciones.</p>



<p>En lugar de tener un solo servidor que maneje todas las peticiones, un balanceador de carga reparte la carga de trabajo entre varios servidores, de modo que cada uno de ellos procesa una parte del tráfico y se evita la sobrecarga de un solo servidor. Además, si uno de los servidores falla, el balanceador de carga puede redirigir las peticiones a otro servidor disponible, lo que aumenta la disponibilidad y la tolerancia a fallos del sistema.</p>



<p>En este laboratorio levantaremos un contenedor con la <a href="https://hub.docker.com/_/nginx">imagen oficial de NGINX</a> que balanceará el tráfico entre dos contenedores <a href="https://uwsgi-docs.readthedocs.io/en/latest/">uWSGI</a>.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="844" height="524" src="https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-2.png" alt="" class="wp-image-886" srcset="https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-2.png 844w, https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-2-300x186.png 300w, https://aprenderdevops.com/wp-content/uploads/2023/03/python-docker-nginx-2-768x477.png 768w" sizes="auto, (max-width: 844px) 100vw, 844px" /></figure>



<p></p>



<h2 class="wp-block-heading">Aplicación web Python “Hola mundo”</h2>



<p>Vamos a utilizar la misma aplicación web Python desarrollada con&nbsp;<a href="http://flask.pocoo.org/">Flask</a> que utilizamos en la primera entrada, pero con una pequeña modificación que muestra desde que servidor uWSGI se está dando respuesta a la petición realizada desde el cliente.</p>



<h3 class="wp-block-heading">webapp.py</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: python; auto-links: false; gutter: false; title: ; notranslate">
from flask import Flask
import socket

app = Flask(__name__)


@app.route(&quot;/&quot;)
def hello():
    return f&quot;&quot;&quot;
    &lt;!DOCTYPE html&gt;
    &lt;html&gt;
    &lt;head&gt;
      &lt;title&gt;Hello, World!&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;h1&gt;Hello, World! This is {socket.gethostname()}.&lt;/h1&gt;
    &lt;/body&gt;
    &lt;/html&gt;
    &quot;&quot;&quot;


if __name__ == &quot;__main__&quot;:
    app.run()
</pre></div>


<h2 class="wp-block-heading">¿Qué necesitáis para hacer este laboratorio?</h2>



<p>Para hacer este laboratorio únicamente necesitáis tener un equipo con Docker instalado. Si no tenéis Docker instalado, podéis seguir las&nbsp;<a href="https://docs.docker.com/install/">instrucciones de instalación</a>&nbsp;para vuestro sistema operativo en la web oficial de Docker.</p>



<p>También podéis hacer este laboratorio en <a href="https://killercoda.com/aprenderdevops/scenario/docker-uwsgi-nginx">Killercoda</a>.</p>



<h2 class="wp-block-heading">Construcción de nuestra imagen con uWSGI</h2>



<p>Al igual que en la primera entrada, para poder ejecutar nuestra aplicación web Python necesitaremos un servidor de aplicaciones WSGI como uWSGI. Construiremos una imagen Docker que contendrá el servidor uWSGI y nuestra aplicación web Python.</p>



<h3 class="wp-block-heading">Dockerfile</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; gutter: false; title: ; notranslate">
FROM python:3.11.2
LABEL maintainer=&quot;Jose Arturo Fernandez &lt;jarfernandez@aprenderdevops.com&gt;&quot;

# Se instala uWSGI y todas las librerias que necesita la aplicacion
COPY WebApp/requirements.txt requirements.txt
RUN pip install uwsgi &amp;&amp; pip install -r requirements.txt

# Puerto HTTP por defecto para uWSGI
ARG UWSGI_HTTP_PORT=8000
ENV UWSGI_HTTP_PORT=$UWSGI_HTTP_PORT

# Aplicacion por defecto para uWSGI
ARG UWSGI_APP=webapp
ENV UWSGI_APP=$UWSGI_APP

# Se crea un usuario para arrancar uWSGI
RUN useradd -ms /bin/bash admin
USER admin

# Se copia el contenido de la aplicacion
COPY WebApp /WebApp

# Se copia el fichero con la configuración de uWSGI
COPY uwsgi.ini uwsgi.ini

# Se establece el directorio de trabajo
WORKDIR /WebApp

# Se crea un volumen con el contenido de la aplicacion
VOLUME /WebApp

# Se inicia uWSGI
ENTRYPOINT &#x5B;&quot;uwsgi&quot;, &quot;--ini&quot;, &quot;/uwsgi.ini&quot;]
</pre></div>


<h3 class="wp-block-heading">requirements.txt</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; auto-links: false; gutter: false; title: ; notranslate">
Click==8.1.3
Flask==2.2.3
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.2
Werkzeug==2.2.3
</pre></div>


<p>El fichero requirements.txt contiene las librerías Python necesarias para ejecutar la aplicación. Este fichero se obtiene con el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ pip freeze &gt; requirements.txt
</pre></div>


<h3 class="wp-block-heading">uwsgi.ini</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; auto-links: false; gutter: false; title: ; notranslate">
&#x5B;uwsgi]
http = 0.0.0.0:$(UWSGI_HTTP_PORT)
module = $(UWSGI_APP):app
</pre></div>


<p>El fichero uwsgi.ini contiene la configuración del servidor uWSGI.</p>



<h2 class="wp-block-heading">Utilización de Docker Compose</h2>



<p>Para facilitar la construcción de la imagen con el servidor uWSGI que contiene nuestra aplicación, y para crear, arrancar, parar y eliminar los contenedores que vamos a utilizar en el despliegue de la misma, utilizaremos Docker Compose.</p>



<h3 class="wp-block-heading">docker-compose.yml</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; auto-links: false; title: ; notranslate">
version: &#039;3.8&#039;

services:
  nginx:
    image: nginx:latest
    container_name: nginx
    hostname: nginx
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    ports:
      - 80:80
    restart: unless-stopped

  uwsgi-1:
    build: .
    image: aprenderdevops/uwsgi:latest
    container_name: uwsgi-1
    hostname: uwsgi-1
    volumes:
      - ./WebApp:/WebApp
    restart: unless-stopped

  uwsgi-2:
    image: aprenderdevops/uwsgi:latest
    container_name: uwsgi-2
    hostname: uwsgi-2
    volumes:
      - ./WebApp:/WebApp
    restart: unless-stopped
</pre></div>


<p>A continuación, paso a explicar el código de este fichero docker-compose.yml:</p>



<ul class="wp-block-list">
<li>De las líneas 4 a la 12 se describe el servicio nginx.</li>



<li>En la línea 5 se indica el repositorio y el tag de la imagen de NGINX que se va a utilizar.</li>



<li>En las líneas 6 y 7 indicamos el nombre y el hostname del contenedor NGINX. En ambos casos es nginx.</li>



<li>En la línea 9 se mapea el volumen que contendrá el fichero de configuración de NGINX (nginx.conf).</li>



<li>En la línea 11 se mapea el puerto 80, que es el puerto en el que escuchará NGINX.</li>



<li>En la línea 12 indicamos que el contenedor se reiniciará siempre, salvo que lo paremos.</li>



<li>De las líneas 14 a la 21 se describe el servicio del primer servidor uWSGI.</li>



<li>En la línea 15 se indica que el Dockerfile que define como se construirá la imagen del servidor uWSGI se encuentra en el directorio actual, es decir, en el mismo directorio en el que se encuentra el fichero docker-compose.yml.</li>



<li>En la línea 16 se indica el repositorio y el tag de la imagen del servidor uWSGI.</li>



<li>En las líneas 17 y 18 indicamos el nombre del contenedor y el hostname del primer servidor uWSGI. En ambos casos es uwsgi-1.</li>



<li>En la línea 20 se mapea el volumen que contendrá nuestra aplicación web Python.</li>



<li>En la línea 21 indicamos que el contenedor se reiniciará siempre, salvo que lo paremos.</li>



<li>De las líneas 23 a la 29 se describe el servicio del segundo servidor uWSGI. La configuración es idéntica a la del primero a excepción del nombre del contenedor y del hostname, que en este caso es uwsgi-2. Tampoco hay configuración para la construcción de la imagen, ya que es la misma para ambos servidores uWSGI, por lo que sólo es necesario construirla una vez.</li>
</ul>



<h2 class="wp-block-heading">Configuración de NGINX</h2>



<p>Para que nuestro contenedor NGINX funcione como proxy inverso y balanceador de carga necesitamos pasarle el fichero de configuración nginx.conf.</p>



<h3 class="wp-block-heading">nginx.conf</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; title: ; notranslate">
user nginx;
worker_processes 1;

error_log /var/log/nginx/error.log warn;
pid       /var/run/nginx.pid;

events {
  worker_connections 1024;
}

http {
  sendfile    on;
  tcp_nopush  on;
  tcp_nodelay on;

  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Host $server_name;

  upstream uwsgi {
    server uwsgi-1:8000;
    server uwsgi-2:8000;
  }

  server {
    listen 80;

    location / {
      proxy_pass     http://uwsgi;
      proxy_redirect off;
    }
  }
}
</pre></div>


<p>A continuación, explico en detalle esta configuración:</p>



<ul class="wp-block-list">
<li>En la línea 1 se especifica el usuario bajo el cual se ejecutará el proceso de NGINX.</li>



<li>En la línea 2 se especifica el número de procesos que se utilizarán para manejar las peticiones. En este caso, se utiliza sólo un proceso.</li>



<li>En la línea 4 se establece la ubicación del fichero de log de errores de NGINX y el nivel de registro de errores que se registrarán en el fichero.</li>



<li>En la línea 5 se especifica la ubicación del fichero de identificación de proceso (PID) de NGINX.</li>



<li>De las líneas 7 a la 9 se definen las opciones de eventos de NGINX. En este caso, se establece el número máximo de conexiones que un worker puede manejar al mismo tiempo.</li>



<li>De las líneas 12 a la 14 se incluyen las opciones de envío de ficheros (sendfile) para enviar ficheros estáticos, la desactivación de la agrupación de TCP (tcp_nopush) y la desactivación de la demora de TCP (tcp_nodelay) para mejorar la velocidad de transferencia de ficheros.</li>



<li>De las líneas 16 a la 19 se establecen las cabeceras HTTP que se enviarán al servidor proxy. Estas cabeceras incluyen la dirección IP real del cliente (X-Real-IP), la dirección IP del cliente detrás del proxy (X-Forwarded-For), el nombre del servidor proxy (X-Forwarded-Host) y el nombre del host original (Host).</li>



<li>De las líneas 21 a la 24 se define el grupo de servidores que se utilizarán como destino de las peticiones entrantes. En este caso, se especifican los dos contenedores uWSGI uwsgi-1 y uwsgi-2 en el puerto 8000.</li>



<li>De las líneas 26 a la 33 se define el servidor virtual y la ubicación de las peticiones entrantes. En este caso, todas las peticiones entrantes se manejarán mediante el servidor virtual que escucha en el puerto 80. La ubicación de la petición se establece en la raíz (/), lo que significa que cualquier petición entrante se pasará al grupo de servidores definido en la sección upstream utilizando la directiva proxy_pass. La directiva proxy_redirect off desactiva la redirección automática de URLs en las respuestas del servidor proxy.</li>
</ul>



<h2 class="wp-block-heading">Instrucciones</h2>



<p>Para construir la imagen del servidor uWSGI, ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker-compose build
</pre></div>


<p>Una vez construida la imagen del servidor uWSGI, ya podemos arrancar ambos servidores uWSGI y el servidor NGINX mediante el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker-compose up -d
</pre></div>


<p>Para verificar que todos los contenedores están arrancados, ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker-compose ps
NAME                IMAGE                         COMMAND                  SERVICE             CREATED             STATUS              PORTS
nginx               nginx:latest                  &quot;/docker-entrypoint.…&quot;   nginx               2 minutes ago       Up 2 minutes        0.0.0.0:80-&gt;80/tcp
uwsgi-1             aprenderdevops/uwsgi:latest   &quot;uwsgi --ini /uwsgi.…&quot;   uwsgi-1             2 minutes ago       Up 2 minutes
uwsgi-2             aprenderdevops/uwsgi:latest   &quot;uwsgi --ini /uwsgi.…&quot;   uwsgi-2             2 minutes ago       Up 2 minutes
</pre></div>


<p>Para ver los logs, utilizamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker-compose logs -f
</pre></div>


<p>Por último, vamos a comprobar que todo está funcionando correctamente. Para ello, abrimos un navegador y accedemos a http://localhost. Esto nos deberá mostrar el mensaje «Hello, World! This is uwsgi-1.» o «Hello, World! This is uwsgi-2.».</p>



<p>Si refrescamos la petición en el navegador nos devolverá el mismo mensaje, pero si en la petición anterior la respuesta nos la había proporcionado el servidor uwsgi-1 en esta ocasión la respuesta nos la dará uwsgi-2, y viceversa. Esto verificará que el contenedor NGINX está balanceando correctamente las peticiones entre ambos contenedores uWSGI.</p>



<p>Podéis ver la ejecución de estas instrucciones en el siguiente vídeo:</p>



<script async="" id="asciicast-zAT3BEouW0ZgSX285CmNPLUkp" src="https://asciinema.org/a/zAT3BEouW0ZgSX285CmNPLUkp.js"></script>



<h2 class="wp-block-heading">Código fuente del laboratorio</h2>



<p>Tenéis el código fuente de este laboratorio en&nbsp;<a href="https://github.com/aprenderdevops/docker-uwsgi-nginx">https://github.com/aprenderdevops/docker-uwsgi-nginx</a>.</p>
<p>La entrada <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-nginx-como-proxy-inverso-y-balanceador-de-carga/">Despliegue de una aplicación web Python en Docker con NGINX como proxy inverso y balanceador de carga</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker-con-nginx-como-proxy-inverso-y-balanceador-de-carga/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Instalación del stack Elastic con Docker</title>
		<link>https://aprenderdevops.com/instalacion-del-stack-elastic-con-docker/</link>
					<comments>https://aprenderdevops.com/instalacion-del-stack-elastic-con-docker/#respond</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Sun, 14 Nov 2021 23:25:00 +0000</pubDate>
				<category><![CDATA[Contenedores]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[elastic]]></category>
		<guid isPermaLink="false">https://aprenderdevops.com/?p=574</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-1.png" class="webfeedsFeaturedVisual wp-post-image" alt="Instalación del stack Elastic con Docker" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-1.png 700w, https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-1-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /><p>En esta entrada vamos a ver cómo instalar el stack Elastic utilizando contenedores Docker. Para ello, vamos a preparar un fichero Docker compose que cree y arranque los contenedores necesarios para el funcionamiento del stack. Es importante destacar que en un entorno de producción no se instala todo el stack en un único host. Además, [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/instalacion-del-stack-elastic-con-docker/">Instalación del stack Elastic con Docker</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-1.png" class="webfeedsFeaturedVisual wp-post-image" alt="Instalación del stack Elastic con Docker" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-1.png 700w, https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-1-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" />
<p>En esta entrada vamos a ver cómo instalar el <a href="https://www.elastic.co/es/elastic-stack/">stack Elastic</a> utilizando contenedores Docker. Para ello, vamos a preparar un fichero Docker compose que cree y arranque los contenedores necesarios para el funcionamiento del stack.</p>



<span id="more-574"></span>



<p>Es importante destacar que en un entorno de producción no se instala todo el stack en un único host. Además, se suelen instalar varios nodos de Logstash, y en cuanto a Elasticsearch, este se suele instalar como un cluster con al menos tres nodos.</p>



<p>Antes de empezar a instalar el stack vamos a ver primero qué es Elastic, qué componentes tiene y para que se suele utilizar.</p>



<h2 class="wp-block-heading">¿Qué es el stack Elastic?</h2>



<p>El stack Elastic es el nuevo nombre de lo que anteriormente se conocía como stack ELK, y que está formado por los proyectos open source Elasticsearch, Logstash y Kibana.</p>



<p>En 2015 se añadieron al stack los Beats, que son un conjunto de agentes ligeros que se instalan en los distintos sistemas y envían datos a Elasticsearch, ya sea directamente o a través de Logstash.</p>



<p>El stack Elastic recolecta logs y eventos de los sistemas y aplicaciones, los formatea y almacena en forma de datos que pueden ser buscados y leídos en tiempo real por otras aplicaciones, y los representa de forma visual en cuadros de mando.</p>



<h2 class="wp-block-heading">Componentes del stack Elastic</h2>



<p>A continuación, vamos a conocer un poco más de cada uno de los componentes del stack:</p>



<ul class="wp-block-list">
<li>Elasticsearch es donde se almacenan los datos. Además, es un motor de búsqueda open source, distribuido, RESTful basado en JSON, fácil de usar, escalable y flexible.</li>



<li>Logstash es un pipeline de procesamiento de datos del lado del servidor que ingesta datos de una multitud de fuentes simultáneamente, los transforma y luego los envía a Elasticsearch.</li>



<li>Kibana permite visualizar los datos en cuadros de mando.</li>
</ul>



<h2 class="wp-block-heading">Casos de uso</h2>



<p>Ya sabemos que es, que hace y cuales son los componentes del stack Elastic, pero realmente ¿para qué se utiliza?</p>



<p>Los casos de uso del stack Elastic son la búsqueda de datos en tiempo real, la observabilidad de sistemas y aplicaciones mediante la analítica de logs y métricas, o el análisis de seguridad mediante el módulo de SIEM integrado en Kibana.</p>



<h2 class="wp-block-heading">¿Qué necesitáis para hacer este laboratorio?</h2>



<p>Para hacer este laboratorio únicamente necesitáis tener un equipo con Docker instalado. Si no tenéis Docker instalado, podéis seguir las <a href="https://docs.docker.com/install/">instrucciones de instalación</a> en la web oficial de Docker para vuestro sistema operativo.</p>



<p>Vamos a ver los pasos necesarios para instalar el stack Elastic utilizando contenedores Docker.</p>



<h2 class="wp-block-heading">¿Qué imágenes Docker elegir?</h2>



<p>El registro Docker de Elastic (<a href="https://www.docker.elastic.co/">https://www.docker.elastic.co/</a>) contiene las imágenes de todos los productos del stack.</p>



<h2 class="wp-block-heading">Instalación del stack Elastic utilizando docker-compose</h2>



<p>Para la instalación del stack Elastic, vamos a utilizar docker-compose. A continuación, podemos ver el fichero docker-compose.yml que utilizaremos.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; auto-links: false; title: ; notranslate">
version: &#039;3.8&#039;

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.15.2
    container_name: elasticsearch
    ports:
      - 9200:9200
      - 9300:9300
    environment:
      cluster.name: elasticsearch-cluster
      node.name: elasticsearch
      bootstrap.memory_lock: true
      ES_JAVA_OPTS: &quot;-Xms512m -Xmx512m&quot;
      discovery.type: single-node
    volumes:
      - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
      - ./elasticsearch/data:/usr/share/elasticsearch/data
    ulimits:
      memlock:
        soft: -1
        hard: -1

  logstash:
    image: docker.elastic.co/logstash/logstash:7.15.2
    container_name: logstash
    ports:
      - 5044:5044
      - 5000:5000
      - 9600:9600
    environment:
      LS_JAVA_OPTS: &quot;-Xmx256m -Xms256m&quot;
    volumes:
      - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
      - ./logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    depends_on:
      - elasticsearch

  kibana:
    image: docker.elastic.co/kibana/kibana:7.15.2
    container_name: kibana
    ports:
      - 5601:5601
    volumes:
      - ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
    depends_on:
      - elasticsearch
</pre></div>


<p>A continuación, paso a explicar el código de este fichero docker-compose:</p>



<ul class="wp-block-list">
<li>De las líneas 4 a la 22 se describe el servicio elasticsearch.</li>



<li>En la línea 5 se indica el repositorio y el tag de la imagen de Elasticsearch que se va a utilizar. Como se puede ver, vamos a obtener las imágenes del registro Docker de Elastic.</li>



<li>En la línea 6 indicamos que nombre va a tener el contenedor de Elasticsearch. En este caso elasticsearch.</li>



<li>De las líneas 7 a la 9 mapeamos los puertos que utiliza Elasticsearch. Concretamente los puertos 9200 y 9300.</li>



<li>De las líneas 10 a la 15 se establecen las variables de entorno que tendrá el contenedor del servicio elasticsearch, como el nombre del cluster, el nombre del nodo o la memoria heap con la que se levantará el proceso Java con el que se ejecuta Elasticsearch.</li>



<li>En la línea 13 se habilita el bloqueo del espacio de direcciones del proceso en la RAM para evitar que la memoria heap de Elasticsearch pase a la memoria swap. Esto se hace para mejorar la estabilidad y el rendimiento del nodo.</li>



<li>En la línea 15 se indica que el cluster tendrá un único nodo.</li>



<li>De las líneas 16 a la 18 se mapean los volúmenes del contenedor eleasticsearch.</li>



<li>En la línea 17 se mapea el volumen que contendrá el fichero de configuración de Elasticsearch (elasticsearch.yml).</li>



<li>En la línea 18 se mapea el volumen que contendrá los datos de Elasticsearch, de tal forma que, si se reinicia el contenedor, los datos persistirán en el volumen y volverán a ser accesibles a través de una nueva instancia del contenedor.</li>



<li>De las líneas 19 a la 22 se utiliza ulimit para deshabilitar la memoria swap. Ulimit permite controla la cantidad máxima de recursos del sistema que se pueden asignar a los procesos en ejecución.</li>



<li>De las líneas 24 a la 37 se describe el servicio logstash.</li>



<li>En la línea 25 se indica el repositorio y el tag de la imagen de Logstash que se va a utilizar.</li>



<li>En la línea 26 se indica qué nombre va a tener el contenedor de Logstash.</li>



<li>De las líneas 27 a la 30 mapeamos los puertos que utiliza Logstash.</li>



<li>En la línea 32 se establece la variable de entorno en la que se indica con cuanta memoria heap se levantará el proceso Java con el que se ejecuta Logstash.</li>



<li>De las líneas 33 a la 35 se mapean los volúmenes del contenedor logstash.</li>



<li>En la línea 34 se mapea el volumen que contendrá el fichero de configuración de Logstash (logstash.yml).</li>



<li>En la línea 35 se mapea el volumen que contendrá la configuración del pipeline de procesamiento de datos que va a llevar a cabo Logstash (logstash.conf).</li>



<li>En las líneas 36 y 37 se establece una dependencia del servicio logstash respecto al servicio elasticsearch, de forma que se arranque el servicio elasticsearch antes que el servicio logstash. Esto tiene que ser así porque Logstash necesita conectarse a Elasticsearch para empezar a reenviarle los eventos que procesa, por lo que ha de estar iniciado Elasticsearch para que se pueda establecer esta conexión.</li>



<li>De las líneas 39 a la 47 se describe el servicio kibana.</li>



<li>En la línea 40 se indica el repositorio y el tag de la imagen de Kibana que se va a utilizar.</li>



<li>En la línea 41 se indica qué nombre va a tener el contenedor de Kibana.</li>



<li>En las líneas 42 y 43 mapeamos los puertos que utiliza Kibana. En este caso únicamente el puerto 5601.</li>



<li>En las líneas 44 y 45 se mapea el volumen que contendrá el fichero de configuración de Kibana (kibana.yml).</li>



<li>En las líneas 46 y 47 se establece una dependencia del servicio kibana respecto al servicio elasticsearch, de forma que se arranque el servicio elasticsearch antes que el servicio kibana. Esto es así porque Kibana se conecta a Elasticsearch para poder mostrar los datos almacenados en Elasticsearch, por lo que, al igual que pasaba con Logstash, ha de estar iniciado Elasticsearch para que se pueda establecer la conexión.</li>
</ul>



<p>En el caso de la configuración de Kibana, cabe destacar que se pueden utilizar tanto variables de entorno como pares clave valor en el fichero de configuración kibana.yml. En el caso de que se utilicen variables de entorno, los nombres de estas variables son los mismos que los de las propiedades del fichero kibana.yml a las que sustituyen, pero con mayúsculas y caracteres punto (.) en lugar de subrayados (_).</p>



<p>Podéis consultar esto con más detalle en el siguiente enlace de la documentación de Elastic: <a href="https://www.elastic.co/guide/en/kibana/current/docker.html#environment-variable-config">https://www.elastic.co/guide/en/kibana/current/docker.html#environment-variable-config</a></p>



<h3 class="wp-block-heading">Instrucciones</h3>



<p>Para arrancar los contenedores del stack Elastic, ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker-compose up -d
</pre></div>


<p>Para verificar que los tres contenedores se están ejecutando correctamente, ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker-compose ps
NAME                COMMAND                  SERVICE             STATUS              PORTS
elasticsearch       &quot;/bin/tini -- /usr/l…&quot;   elasticsearch       running             0.0.0.0:9200-&gt;9200/tcp, 0.0.0.0:9300-&gt;9300/tcp
kibana              &quot;/bin/tini -- /usr/l…&quot;   kibana              running             0.0.0.0:5601-&gt;5601/tcp
logstash            &quot;/usr/local/bin/dock…&quot;   logstash            running             0.0.0.0:5000-&gt;5000/tcp, 0.0.0.0:5044-&gt;5044/tcp, 0.0.0.0:9600-&gt;9600/tcp
</pre></div>


<p>Para visualizar los logs, ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker-compose logs -f
</pre></div>


<h2 class="wp-block-heading">Comprobación del funcionamiento del stack Elastic</h2>



<p>Una vez arrancados los tres contenedores del stack Elastic, para comprobar si el stack está funcionando correctamente, podemos seguir las instrucciones que se detallan a continuación.</p>



<h3 class="wp-block-heading">Elasticsearch</h3>



<p>Abrimos un navegador y accedemos a http://localhost:9200. Deberíamos ver una salida similar a la mostrada en la siguiente captura de pantalla.</p>



<figure class="wp-block-image size-full"><a href="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-2.png"><img loading="lazy" decoding="async" width="982" height="372" src="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-2.png" alt="Instalación del stack Elastic con Docker" class="wp-image-675" srcset="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-2.png 982w, https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-2-300x114.png 300w, https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-2-768x291.png 768w" sizes="auto, (max-width: 982px) 100vw, 982px" /></a></figure>



<p></p>



<h3 class="wp-block-heading">Logstash</h3>



<p>A continuación, se muestra el fichero <meta charset="utf-8"><a href="https://github.com/aprenderdevops/docker-elastic/blob/main/logstash/pipeline/logstash.conf">logstash/pipeline/logstash.conf</a>, que contiene la <meta charset="utf-8">configuración del pipeline que <meta charset="utf-8">nos va a permitir comprobar el funcionamiento <meta charset="utf-8">de Logstash.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; auto-links: false; gutter: false; title: ; notranslate">
input {
  heartbeat {
    message =&gt; &quot;ok&quot;
    interval =&gt; 5
    type =&gt; &quot;heartbeat&quot;
  }
}

output {
  if &#x5B;type] == &quot;heartbeat&quot; {
    elasticsearch {
      hosts =&gt; &quot;elasticsearch:9200&quot;
      index =&gt; &quot;heartbeat&quot;
    }
  }
  stdout {
    codec =&gt; &quot;rubydebug&quot;
  }
}
</pre></div>


<p>Con esta configuración se genera cada 5 segundos un evento mediante el <a href="https://www.elastic.co/guide/en/logstash/current/plugins-inputs-heartbeat.html">plugin heartbeat</a>.</p>



<p>En este ejemplo no hemos incluido ningún <a href="https://www.elastic.co/guide/en/logstash/current/filter-plugins.html">filter</a>, por lo que, con los eventos generados no se va a realizar ningún tipo de procesamiento o transformación.</p>



<p>En la sección output se configura la salida de los eventos para su envío al índice <meta charset="utf-8">heartbeat de Elasticsearch cuando estos hayan sido generados por el plugin heartbeat. También se envían todos los eventos por la salida estándar mediante el <a href="https://www.elastic.co/guide/en/logstash/current/plugins-outputs-stdout.html">plugin stdout</a> utilizando el formato definido por el <a href="https://www.elastic.co/guide/en/logstash/current/plugins-codecs-rubydebug.html">códec rubydebug</a>.</p>



<p>Para comprobar que los eventos de tipo heartbeat se están generando cada 5 segundos y se están enviando a la salida estándar, se puede ejecutar el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker logs logstash -n21 -f
{
          &quot;host&quot; =&gt; &quot;18ff4068ddbb&quot;,
      &quot;@version&quot; =&gt; &quot;1&quot;,
    &quot;@timestamp&quot; =&gt; 2021-11-11T00:10:11.934Z,
          &quot;type&quot; =&gt; &quot;heartbeat&quot;,
       &quot;message&quot; =&gt; &quot;ok&quot;
}
{
          &quot;host&quot; =&gt; &quot;18ff4068ddbb&quot;,
      &quot;@version&quot; =&gt; &quot;1&quot;,
    &quot;@timestamp&quot; =&gt; 2021-11-11T00:10:16.935Z,
          &quot;type&quot; =&gt; &quot;heartbeat&quot;,
       &quot;message&quot; =&gt; &quot;ok&quot;
}
{
          &quot;host&quot; =&gt; &quot;18ff4068ddbb&quot;,
      &quot;@version&quot; =&gt; &quot;1&quot;,
    &quot;@timestamp&quot; =&gt; 2021-11-11T00:10:21.935Z,
          &quot;type&quot; =&gt; &quot;heartbeat&quot;,
       &quot;message&quot; =&gt; &quot;ok&quot;
}
</pre></div>


<p>La salida de este comando deberá mostrar cada 5 segundos un nuevo evento de tipo heartbeat.</p>



<p>Para comprobar que los eventos también se están enviado a Elasticsearch, se puede ejecutar el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ curl -XGET &quot;http://localhost:9200/heartbeat/_search?pretty=true&quot; -H &#039;Content-Type: application/json&#039; -d&#039;{&quot;size&quot;: 1}&#039;
{
  &quot;took&quot; : 693,
  &quot;timed_out&quot; : false,
  &quot;_shards&quot; : {
    &quot;total&quot; : 1,
    &quot;successful&quot; : 1,
    &quot;skipped&quot; : 0,
    &quot;failed&quot; : 0
  },
  &quot;hits&quot; : {
    &quot;total&quot; : {
      &quot;value&quot; : 148,
      &quot;relation&quot; : &quot;eq&quot;
    },
    &quot;max_score&quot; : 1.0,
    &quot;hits&quot; : &#x5B;
      {
        &quot;_index&quot; : &quot;heartbeat&quot;,
        &quot;_type&quot; : &quot;_doc&quot;,
        &quot;_id&quot; : &quot;3NEq_HwB8PSqowAaUkI_&quot;,
        &quot;_score&quot; : 1.0,
        &quot;_source&quot; : {
          &quot;type&quot; : &quot;heartbeat&quot;,
          &quot;message&quot; : &quot;ok&quot;,
          &quot;host&quot; : &quot;e66d07ee3402&quot;,
          &quot;@timestamp&quot; : &quot;2021-11-07T20:50:04.374Z&quot;,
          &quot;@version&quot; : &quot;1&quot;
        }
      }
    ]
  }
}
</pre></div>


<p>La salida de este comando deberá mostrar el primer evento de tipo heartbeat generado.</p>



<h3 class="wp-block-heading">Kibana</h3>



<p>Para comprobar el correcto funcionamiento de Kibana, abrimos un navegador y accedemos a http://localhost:5601. Esto debería abrir la consola de Kibana, tal y como se muestra en la siguiente captura de pantalla.</p>



<figure class="wp-block-image size-large"><a href="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-3.png"><img loading="lazy" decoding="async" width="1024" height="788" src="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-3-1024x788.png" alt="Instalación del stack Elastic con Docker" class="wp-image-761" srcset="https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-3-1024x788.png 1024w, https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-3-300x231.png 300w, https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-3-768x591.png 768w, https://aprenderdevops.com/wp-content/uploads/2021/11/elastic-docker-3.png 1169w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p></p>



<h2 class="wp-block-heading">Código fuente del laboratorio</h2>



<p>Podéis descargar o clonar el código fuente completo de este laboratorio de GitHub de <a href="https://github.com/aprenderdevops/docker-elastic">https://github.com/aprenderdevops/docker-elastic</a>.</p>
<p>La entrada <a href="https://aprenderdevops.com/instalacion-del-stack-elastic-con-docker/">Instalación del stack Elastic con Docker</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/instalacion-del-stack-elastic-con-docker/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Despliegue de una aplicación web Python en Docker</title>
		<link>https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker/</link>
					<comments>https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker/#comments</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Fri, 10 May 2019 22:30:23 +0000</pubDate>
				<category><![CDATA[Contenedores]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[flask]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[uwsgi]]></category>
		<guid isPermaLink="false">http://aprenderdevops.com/?p=419</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker.png" class="webfeedsFeaturedVisual wp-post-image" alt="Despliegue de una aplicación web Python en Docker con construcción multi-etapa" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker.png 700w, https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /><p>En esta entrada vamos a ver cómo desplegar una aplicación web desarrollada en Python, en este caso usando el framework Flask, dentro de un contenedor Docker con un servidor uWSGI. Aplicación web Python “Hola mundo” La aplicación web Python que vamos a utilizar es extremadamente sencilla. Se trata de la típica aplicación “Hola mundo” que [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker/">Despliegue de una aplicación web Python en Docker</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker.png" class="webfeedsFeaturedVisual wp-post-image" alt="Despliegue de una aplicación web Python en Docker con construcción multi-etapa" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker.png 700w, https://aprenderdevops.com/wp-content/uploads/2019/04/python-docker-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" />
<p>En esta entrada vamos a ver cómo desplegar una aplicación web desarrollada en Python, en este caso usando el framework Flask, dentro de un contenedor Docker con un servidor uWSGI.</p>



<span id="more-419"></span>



<h2 class="wp-block-heading">Aplicación web Python “Hola mundo”</h2>



<p>La aplicación web Python que vamos a utilizar es extremadamente sencilla. Se trata de la típica aplicación “Hola mundo” que en este caso está desarrollada con <a href="http://flask.pocoo.org/">Flask</a>.</p>



<p>El funcionamiento sería exactamente el mismo si la aplicación fuera más compleja o en lugar de Flask se hubiera utilizado otro framework, como <a href="https://www.djangoproject.com/">Django</a>, para su desarrollo.</p>



<h3 class="wp-block-heading">webapp.py</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: python; auto-links: false; gutter: false; title: ; notranslate">
from flask import Flask

app = Flask(__name__)


@app.route(&quot;/&quot;)
def hello():
    return &quot;Hello World!&quot;


if __name__ == &quot;__main___&quot;:
    app.run()
</pre></div>


<h2 class="wp-block-heading">¿Qué es WSGI?</h2>



<p>WSGI
(Web Server Gateway Interface) es un protocolo para que los servidores web como
Nginx, lighttpd o Cherokee envíen peticiones a aplicaciones web desarrolladas
en Python. </p>



<p>Para poder ejecutar una aplicación WSGI lo primero que se necesita es un servidor WSGI. WSGI es tanto un protocolo como un servidor de aplicaciones. El servidor de aplicaciones puede servir a los protocolos WSGI, FastCGI y HTTP.</p>



<h2 class="wp-block-heading">El servidor uWSGI</h2>



<p>Existen varios <a href="http://flask.pocoo.org/docs/1.0/deploying/wsgi-standalone/#deploying-wsgi-standalone﻿">servidores WSGI</a> como Gunicorn, <a href="https://uwsgi-docs.readthedocs.io/en/latest/">uWSGI</a>, Gevento o Twisted Web. Para este laboratorio he optado por uWSGI.</p>



<p>uWSGI es un servidor de aplicaciones escrito en C, rápido y muy configurable.</p>



<h2 class="wp-block-heading">¿Qué necesitáis para hacer este laboratorio?</h2>



<p>Para hacer este laboratorio únicamente necesitáis tener un equipo con Docker instalado. Si no tenéis Docker instalado, podéis seguir las&nbsp;<a href="https://docs.docker.com/install/">instrucciones de instalación</a>&nbsp;para vuestro sistema operativo en la web oficial de Docker.</p>



<h2 class="wp-block-heading">Construcción de nuestra imagen con uWSGI</h2>



<p>Como ya hemos comentado, para poder ejecutar nuestra aplicación web Python necesitaremos un servidor de aplicaciones WSGI como uWSGI. Por lo tanto, lo que vamos a hacer es construir una imagen Docker que contenga el servidor uWSGI y ejecutar nuestra aplicación web Python en él. </p>



<h3 class="wp-block-heading">Dockerfile</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
FROM python:3.7.3
LABEL maintainer=&quot;Jose Arturo Fernandez &lt;jarfernandez@aprenderdevops.com&gt;&quot;

# Se instala uWSGI y todas las librerias que necesita la aplicacion
COPY WebApp/requirements.txt requirements.txt
RUN pip install uwsgi &amp;&amp; pip install -r requirements.txt

# Puerto HTTP por defecto para uWSGI
ARG UWSGI_HTTP_PORT=8000
ENV UWSGI_HTTP_PORT=$UWSGI_HTTP_PORT

# Aplicacion por defecto para uWSGI
ARG UWSGI_APP=webapp
ENV UWSGI_APP=$UWSGI_APP

# Se crea un usuario para arrancar uWSGI
RUN useradd -ms /bin/bash admin
USER admin

# Se copia el contenido de la aplicacion
COPY WebApp /WebApp

# Se copia el fichero con la configuración de uWSGI
COPY uwsgi.ini uwsgi.ini

# Se establece el directorio de trabajo
WORKDIR /WebApp

# Se crea un volume con el contenido de la aplicacion
VOLUME /WebApp

# Se inicia uWSGI
ENTRYPOINT &#x5B;&quot;uwsgi&quot;, &quot;--ini&quot;, &quot;/uwsgi.ini&quot;]
</pre></div>


<p>A
continuación, explico las distintas líneas del Dockerfile:</p>



<ul class="wp-block-list">
<li>En la línea 1 se indica la imagen base de la que se parte para construir la nueva imagen. En este caso partimos de la imagen oficial de Python en su versión 3.7.3.</li>



<li>En la línea 5 se copia el fichero requirements.txt que contiene las librerías Python necesarias para ejecutar la aplicación.</li>



<li>En la línea 6 se instala el servidor uWSGI y las librerías incluidas en el fichero requirements.txt. Para la instalación se utiliza pip. pip&nbsp;es un&nbsp;sistema de gestión de paquetes&nbsp;utilizado para instalar y administrar paquetes software escritos en&nbsp;Python.</li>



<li>En la línea 9 se define la variable UWSGI_HTTP_PORT. Esta variable puede ser modificada al hacer docker build con el flag &#8211;build-arg. Esta variable contendrá el puerto HTTP por defecto en el que escucha el servidor uWSGI.</li>



<li>En la línea 10 se define la variable de entorno UWSGI_HTTP_PORT que será igual al valor de la variable definida en la línea 9.</li>



<li>En las líneas 13 y 14 hacemos lo mismo que en las líneas 9 y 10, pero en este caso para la variable de entornos UWSGI_APP. Esta variable contendrá el nombre del fichero Python en el que se declara la aplicación que ejecutará el servidor uWSGI.</li>



<li>En la línea 17 se crea el usuario admin.</li>



<li>En la línea 18 se cambia la ejecución del proceso uwsgi al usuario admin, ya que puede ejecutarse sin privilegios, lo que proporciona mayor seguridad.</li>



<li>En la línea 21 se copia el contenido de la aplicación.</li>



<li>En la línea 24 se copia el fichero de configuración del servidor uWSGI.</li>



<li>En la línea 27 se establece el directorio de trabajo que será el directorio en el que se encuentra la aplicación (/WebApp).</li>



<li>En la línea 30 se crea un volumen para compartir el contenido de la aplicación desde el host al contenedor. De esta forma, si se modifica el código fuente de la aplicación en el host, los cambios se harán efectivos también dentro del directorio WebApp del contenedor. Para que el servidor uWSGI los refleje será necesario reiniciar el contenedor con docker restart.</li>



<li>En la línea 33 se inicia el servidor uWSGI. Se pasa como parámetro el fichero con la configuración que previamente se ha copiado en la línea 24.</li>
</ul>



<h3 class="wp-block-heading">requirements.txt</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; auto-links: false; gutter: false; title: ; notranslate">
Click==7.0
Flask==1.1.1
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
Werkzeug==0.15.5
</pre></div>


<p>El fichero requirements.txt contiene las librerías Python necesarias para ejecutar la aplicación. Este fichero se obtiene con el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; gutter: false; title: ; notranslate">
$ pip freeze &gt; requirements.txt
</pre></div>


<h3 class="wp-block-heading">uwsgi.ini</h3>


<div class="wp-block-syntaxhighlighter-code nums:true"><pre class="brush: plain; auto-links: false; gutter: false; title: ; notranslate">
&#x5B;uwsgi]
http = 0.0.0.0:$(UWSGI_HTTP_PORT)
module = $(UWSGI_APP):app
</pre></div>


<p>El fichero uwsgi.ini contiene la configuración del servidor uWSGI.</p>



<p>En la línea 2 se indica la dirección IP y el puerto en el que el servidor uWSGI escuchará peticiones HTTP. La dirección establecida a 0.0.0.0 hará que se escuche por todas las interfaces de red.</p>



<p>En el caso del puerto, se especifica que se obtenga el valor de la variable de entorno UWSGI_HTTP_PORT. Si esta variable no se establece en la ejecución del contenedor con el flag &#8211;env o -e se le asignará el valor por defecto (8000).</p>



<p>El valor por defecto del puerto se puede cambiar al construir la imagen con docker build especificando otro valor. Por ejemplo, si queremos que el valor por defecto del puerto para la imagen sea el 9000, ejecutaremos el siguiente comando para construir la imagen:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker build --build-arg UWSGI_HTTP_PORT=9000 -t aprenderdevops/uwsgi .
</pre></div>


<p>Esta configuración se define en las líneas 9 y 10 del Dockerfile.</p>



<p>En la línea 3 se especifica el módulo a ejecutar por el servidor uWSGI. Se especifica que se obtenga el valor de la variable de entorno UWSGI_APP. Si esta variable no se establece en la ejecución del contenedor con el flag –env o -e se le asignará el valor por defecto (webapp).</p>



<p>Al igual que en el caso del puerto, el valor por defecto del módulo se puede cambiar al construir la imagen con docker build especificando otro valor mediante el flag &#8211;build-arg. Esta configuración se define en las líneas 13 y 14 del Dockerfile.</p>



<p>La utilización de variables de entorno que se pasan al fichero de configuración del servidor uWSGI nos proporciona mucha flexibilidad a la hora de utilizar el contenedor, ya que se puede iniciar el servidor uWSGI en el puerto que deseemos, siempre que no esté ya ocupado, y lo que es más importante, se puede cambiar el nombre del fichero Python en el que se declara la aplicación que ejecutará el servidor uWSGI.</p>



<h3 class="wp-block-heading">Instrucciones</h3>



<p>Para construir la imagen ejecutamos el
siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker build -t aprenderdevops/uwsgi .
</pre></div>


<p>Para arrancar el contenedor ejecutamos el
siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker run -d -p 8080:8000 --restart unless-stopped -v $(pwd)/WebApp:/WebApp aprenderdevops/uwsgi
</pre></div>


<p>Con el flag -p indicamos que se rediriga el puerto 8000 del contenedor (puerto por defecto en el que escucha el servidor uWSGI) al puerto 8080 de nuestra máquina. Si el puerto 8080 estuviera ocupado por otro proceso habría que cambiarlo por otro.</p>



<p>Una vez arrancado el contenedor, abrimos un navegador web y accedemos a http://localhost:8080. Nos debería abrir una página web con el texto “Hello World!”.</p>



<h2 class="wp-block-heading">Código fuente del laboratorio</h2>



<p>Podéis descargar o clonar de GitHub el código fuente de este
laboratorio de&nbsp;<a href="https://github.com/aprenderdevops/docker-uwsgi">https://github.com/aprenderdevops/docker-uwsgi</a>.</p>
<p>La entrada <a href="https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker/">Despliegue de una aplicación web Python en Docker</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/despliegue-de-una-aplicacion-web-python-en-docker/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Arquitectura de Kubernetes</title>
		<link>https://aprenderdevops.com/arquitectura-de-kubernetes/</link>
					<comments>https://aprenderdevops.com/arquitectura-de-kubernetes/#comments</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Sat, 22 Dec 2018 00:45:31 +0000</pubDate>
				<category><![CDATA[Contenedores]]></category>
		<category><![CDATA[kubernetes]]></category>
		<guid isPermaLink="false">http://aprenderdevops.com/?p=382</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes.png" class="webfeedsFeaturedVisual wp-post-image" alt="Introducción a Kubernetes" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /><p>Tras la entrada Introducción a Kubernetes, en la que conocimos este orquestador de contenedores y vimos algunos conceptos clave, vamos a ver su arquitectura, identificando los distintos componentes en los que está organizado y su relación entre ellos. Nodos Los nodos en Kubernetes son las máquinas que componen el clúster Kubernetes. Estas máquinas pueden ser [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/arquitectura-de-kubernetes/">Arquitectura de Kubernetes</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes.png" class="webfeedsFeaturedVisual wp-post-image" alt="Introducción a Kubernetes" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" />
<p>Tras la entrada <a href="https://aprenderdevops.com/introduccion-a-kubernetes/">Introducción a Kubernetes</a>, en la que conocimos este orquestador de contenedores y vimos algunos conceptos clave, vamos a ver su arquitectura, identificando los distintos componentes en los que está organizado y su relación entre ellos.</p>



<span id="more-382"></span>



<h2 class="wp-block-heading">Nodos</h2>


<div class="wp-block-image">
<figure class="aligncenter"><a href="http://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-1.png"><img loading="lazy" decoding="async" width="843" height="654" src="http://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-1.png" alt="Arquitectura de Kubernetes" class="wp-image-386" srcset="https://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-1.png 843w, https://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-1-300x233.png 300w, https://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-1-768x596.png 768w" sizes="auto, (max-width: 843px) 100vw, 843px" /></a></figure></div>


<p>Los nodos en Kubernetes son las máquinas que componen el clúster Kubernetes. Estas máquinas pueden ser físicas o virtuales, y estar desplegadas on premise o en la nube. A su vez los nodos pueden ser nodos master o nodos worker.</p>



<h3 class="wp-block-heading">Nodos master</h3>



<p>Los nodos master son los responsables de gestionar el clúster Kubernetes. Estos nodos toman decisiones globales sobre el clúster, como el reparto de trabajo entre los nodos worker, y detectan y dan respuesta a distintos eventos del clúster, como puede ser el inicio de nuevos pods cuando el número de replicas es inferior al configurado para un controlador de replicación.</p>



<p>En un clúster Kubernetes puede haber un único nodo master o varios si queremos tener redundancia para asegurar una mayor disponibilidad del clúster. Si hay varios nodos master, el número de nodos master tiene que ser siempre impar para que sea posible establecer quórum. Esto es así porque en cada nodo master se ejecuta un nodo de la base de datos distribuida etcd y todos los componentes master de Kubernetes restantes (API, administrador del controlador/controller y scheduler). Un clúster etcd necesita alcanzar una mayoría de nodos, un quórum, para acordar las actualizaciones del estado del clúster, y esto sólo se puede asegurar si el número de nodos es impar.</p>



<h3 class="wp-block-heading">Nodos worker</h3>



<p>Los nodos worker, también denominados simplemente nodos, son los responsables de ejecutar las aplicaciones en pods. Como ya vimos en la entrada <a href="https://aprenderdevops.com/introduccion-a-kubernetes/">Introducción a Kubernetes</a>, un pod es una colección lógica de contenedores y recursos compartidos por esos contenedores que pertenecen a una aplicación.</p>



<p>Como curiosidad, indicar que en la documentación de las primeras versiones de Kubernetes los nodos worker se denominaban minions.</p>



<p>Cada nodo worker puede ejecutar múltiples pods. Es muy recomendable tener varios nodos worker si queremos asegurar la disponibilidad de las aplicaciones desplegadas en el clúster Kubernetes.</p>



<h2 class="wp-block-heading">Componentes de un nodo master</h2>


<div class="wp-block-image">
<figure class="aligncenter"><a href="http://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-2.png"><img loading="lazy" decoding="async" width="859" height="570" src="http://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-2.png" alt="Arquitectura de Kubernetes" class="wp-image-406" srcset="https://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-2.png 859w, https://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-2-300x199.png 300w, https://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-2-768x510.png 768w" sizes="auto, (max-width: 859px) 100vw, 859px" /></a></figure></div>


<p>Los distintos componentes de un nodo master se pueden ejecutar en cualquier máquina del clúster, sin embargo, por simplicidad, las secuencias de comandos de configuración inician normalmente todos los componentes del nodo master en la misma máquina. Además, en esa máquina no se ejecutan contenedores de usuario.Estos componentes de un nodo master se detallan a continuación.</p>



<h3 class="wp-block-heading">API server</h3>



<p>Es el componente que expone la API de Kubernetes. Es, por lo tanto, el punto de entrada para todos los comandos REST utilizados para controlar el clúster. Procesa las solicitudes REST, las valida y ejecuta.</p>



<h3 class="wp-block-heading">Scheduler</h3>



<p>Este componente observa los pods recién creados que no tienen un nodo asignado y selecciona un nodo para que se ejecuten. El scheduler tiene en cuenta los recursos disponibles en cada nodo del clúster, así como los recursos necesarios para que se ejecute un determinado servicio. Con esta información decide dónde desplegar cada pod dentro del clúster.</p>



<h3 class="wp-block-heading">Controller-manager</h3>



<p>Este componente ejecuta los controladores. Un controlador usa el API server para observar el estado compartido del clúster y realiza cambios correctivos en el estado actual para cambiarlo al estado deseado.</p>



<p>Un ejemplo de controlador es el controlador de replicación, que se ocupa de mantener la cantidad correcta de pods en el clúster. El usuario configura el factor de replicación, y es responsabilidad del controlador de replicación volver a crear un pod caído o eliminar uno que se haya programado de más.</p>



<p>Desde un punto de vista lógico, cada controlador es un proceso separado, pero para reducir la complejidad, todos los controladores se compilan en un único binario y se ejecutan en un solo proceso.</p>



<p>Estos son los controladores incluidos:</p>



<ul class="wp-block-list">
<li>Controlador de nodo: responsable de monitorizar el estado de los nodos y responder cuando uno se cae desplegando los pods afectados en los nodos restantes disponibles.</li>



<li>Controlador de replicación: responsable de mantener el número correcto de pods.</li>



<li>Controlador de endpoints: responsable de asegurar la conexión entre servicios y pods.</li>



<li>Controladores service acount y token: crean cuentas predeterminadas y tokens de acceso a la API para nuevos espacios de nombres.</li>
</ul>



<h3 class="wp-block-heading">etcd</h3>



<p><a href="https://coreos.com/etcd/">etcd</a> es un almacén de datos clave valor simple, distribuido y consistente. Se utiliza para almacenar la configuración compartida del clúster y para el descubrimiento de servicios. Permite de una forma confiable notificar al resto de nodos del clúster los cambios de configuración en un nodo determinado.</p>



<p>Algunos ejemplos de datos almacenados por Kubernetes en etcd son los trabajos que se programan, crean y despliegan, estado y detalles de los pods, espacios de nombre o información de replicación.</p>



<h2 class="wp-block-heading">Componentes de un nodo worker</h2>


<div class="wp-block-image">
<figure class="aligncenter"><a href="http://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-3.png"><img loading="lazy" decoding="async" width="951" height="650" src="http://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-3.png" alt="Arquitectura de Kubernetes" class="wp-image-412" srcset="https://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-3.png 951w, https://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-3-300x205.png 300w, https://aprenderdevops.com/wp-content/uploads/2018/12/arquitectura-kubernetes-3-768x525.png 768w" sizes="auto, (max-width: 951px) 100vw, 951px" /></a></figure></div>


<p>Cada nodo worker ejecuta los siguientes componentes que se detallan a continuación.</p>



<h3 class="wp-block-heading">kubelet</h3>



<p>kubelet es el servicio, dentro de cada nodo worker, responsable de comunicarse con el nodo master. Obtiene la configuración de los pods del API server y garantiza que los contenedores descritos en dicha configuración estén arriba y funcionando correctamente. También se comunica con etcd para obtener información de los servicios y registrar los detalles de los nuevos servicios creados.</p>



<h3 class="wp-block-heading">kube-proxy</h3>



<p>kube-proxy actúa como proxy de red y balanceador de carga enrutando el tráfico hacia el contenedor correcto en función de la dirección IP y el número de puerto indicados en cada petición.</p>



<h3 class="wp-block-heading">Runtime de contenedores</h3>



<p>El runtime de contenedores es el software responsable de ejecutar los contenedores de los pods. Para ello, se encarga de descargar las imágenes necesarias y de arrancar los contenedores.</p>



<p>Kubernetes admite varios runtimes de contenedores: <a href="https://www.docker.com/">Docker</a>, <a href="https://coreos.com/rkt/">rkt</a>, <a href="https://github.com/opencontainers/runc">runc</a> y cualquier implementación de la especificación de runtime <a href="https://www.opencontainers.org/">OCI (Open Container Initiative)</a>.</p>



<h3 class="wp-block-heading">Pods</h3>



<p>Como ya comentamos, las aplicaciones se ejecutan mediante pods. Un pod es una colección lógica de contenedores más los recursos compartidos por esos contenedores.</p>



<p>En próximas entradas veremos cómo instalar Kubernetes y algunos ejemplos de configuración de aplicaciones en este orquestador de contenedores.</p>
<p>La entrada <a href="https://aprenderdevops.com/arquitectura-de-kubernetes/">Arquitectura de Kubernetes</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/arquitectura-de-kubernetes/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Tipos de pruebas en un pipeline de entrega continua</title>
		<link>https://aprenderdevops.com/tipos-de-pruebas-entrega-continua/</link>
					<comments>https://aprenderdevops.com/tipos-de-pruebas-entrega-continua/#respond</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Tue, 31 Jul 2018 06:00:54 +0000</pubDate>
				<category><![CDATA[Aseguramiento de la calidad]]></category>
		<category><![CDATA[Integración y entrega continua]]></category>
		<category><![CDATA[pruebas]]></category>
		<guid isPermaLink="false">http://aprenderdevops.com/?p=331</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/07/tipos-de-pruebas-entrega-continua.png" class="webfeedsFeaturedVisual wp-post-image" alt="Tipos de pruebas en un pipeline de entrega continua" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/07/tipos-de-pruebas-entrega-continua.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/07/tipos-de-pruebas-entrega-continua-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /><p>El aseguramiento de la calidad del software debe ser una de las prácticas esenciales dentro de las organizaciones TI de alto rendimiento que adoptan un enfoque DevOps. En esta entrada vamos a ver los distintos tipos de pruebas que se deben incluir en un pipeline de entrega continua. Objetivos de las pruebas El objetivo principal [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/tipos-de-pruebas-entrega-continua/">Tipos de pruebas en un pipeline de entrega continua</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/07/tipos-de-pruebas-entrega-continua.png" class="webfeedsFeaturedVisual wp-post-image" alt="Tipos de pruebas en un pipeline de entrega continua" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/07/tipos-de-pruebas-entrega-continua.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/07/tipos-de-pruebas-entrega-continua-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" />
<p>El aseguramiento de la calidad del software debe ser una de las prácticas esenciales dentro de las organizaciones TI de alto rendimiento que <a href="https://aprenderdevops.com/razones-para-adoptar-devops/">adoptan un enfoque DevOps</a>. En esta entrada vamos a ver los distintos tipos de pruebas que se deben incluir en un pipeline de entrega continua.</p>



<span id="more-331"></span>



<h2 class="wp-block-heading">Objetivos de las pruebas</h2>



<p>El objetivo principal de las pruebas es asegurar y mejorar la calidad del software que se desarrolla y entrega.</p>



<p>Además de este objetivo principal, dentro del pipeline de entrega continua, el objetivo de las pruebas debe ser <strong>identificar builds problemáticos lo antes posible</strong> para mantener ciclos de entrega rápidos,&nbsp;evitar tener que repetir trabajo y obtener feedback lo antes posible. De esta forma se consigue <strong>entregar software de calidad con más frecuencia.</strong></p>



<h2 class="wp-block-heading">Pruebas automáticas</h2>



<p>En un pipeline de entrega continua se pueden incluir etapas de pruebas manuales que serán llevadas a cabo por el equipo de QA (aseguramiento de la calidad) o pruebas de aceptación de usuario. Sin embargo, la automatización de las pruebas es la característica clave que permite acelerar los ciclos de entrega y mejorar la calidad. Por lo tanto, se debe automatizar la mayor cantidad posible de pruebas.</p>



<p>Invertir en la automatización de pruebas es costoso al principio, pero una vez que se ha desarrollado una batería de pruebas automáticas la inversión de tiempo y esfuerzo merece la pena, ya que es algo que ayudará a asegurar y mejorar la calidad del software de una manera eficiente a lo largo de la vida útil de ese software.</p>



<h2 class="wp-block-heading">Tipos de pruebas</h2>



<p>A continuación, vamos a ver los distintos tipos de pruebas que existen y para que sirve cada uno de ellos.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><td><strong>Tipo de prueba</strong></td><td><strong>Para confirmar que</strong></td></tr><tr><td>Pruebas unitarias</td><td>Las funciones y clases funcionan como se espera bajo una variedad de entradas.</td></tr><tr><td>Pruebas de integración</td><td>Los módulos integrados funcionan en conjunto y junto con la infraestructura, como colas de mensajes y bases de datos. En entornos de microservicios las pruebas de integración de todos los componentes desplegados son cada vez más importantes para asegurar el correcto funcionamiento del software en su conjunto.</td></tr><tr><td>Prueba de aceptación</td><td>Los flujos de usuario clave en la interfaz de usuario funcionan como se espera.</td></tr><tr><td>Pruebas de carga</td><td>La aplicación funciona bien bajo carga de usuario simulada.</td></tr><tr><td>Pruebas de rendimiento</td><td>La aplicación cumple con los requisitos de rendimiento y tiempos de respuesta en escenarios de carga similares a la carga real esperada.</td></tr><tr><td>Pruebas de simulación</td><td>La aplicación funciona en entornos de simulación de dispositivos. Esto es especialmente importante en aplicaciones móviles donde es necesario probar el software en distintos dispositivos móviles emulados.</td></tr><tr><td>Pruebas de humo</td><td>El estado y la integridad de un entorno recién provisionado son válidos.</td></tr><tr><td>Pruebas de calidad</td><td>El código de la aplicación es de alta calidad. Esto se lleva a cabo mediante técnicas como el análisis estático de código que permiten validar el cumplimiento de guías de estilo o la cobertura del código.</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Buenas practicas</h2>



<p>Estas son algunas buenas prácticas que se deben tener en cuenta a la hora de mantener una batería de pruebas:</p>



<ul class="wp-block-list">
<li>Automatizar tantas pruebas como sea posible.</li>



<li>Proporcionar una buena cobertura de pruebas, tanto contra los artefactos de código como contra el sistema desplegado.</li>



<li>Distribuir diferentes tipos de pruebas a lo largo del pipeline de entrega continua. Se recomienda dejar las pruebas más lentas y costosas, como pueden ser las pruebas manuales, para su ejecución en las últimas etapas del pipeline, en entornos cada vez más similares a los de producción.</li>
</ul>
<p>La entrada <a href="https://aprenderdevops.com/tipos-de-pruebas-entrega-continua/">Tipos de pruebas en un pipeline de entrega continua</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/tipos-de-pruebas-entrega-continua/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Introducción a Kubernetes</title>
		<link>https://aprenderdevops.com/introduccion-a-kubernetes/</link>
					<comments>https://aprenderdevops.com/introduccion-a-kubernetes/#respond</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Tue, 03 Jul 2018 21:15:39 +0000</pubDate>
				<category><![CDATA[Contenedores]]></category>
		<category><![CDATA[kubernetes]]></category>
		<guid isPermaLink="false">http://aprenderdevops.com/?p=292</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes.png" class="webfeedsFeaturedVisual wp-post-image" alt="Introducción a Kubernetes" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /><p>Kubernetes se ha convertido en el orquestador de contenedores de facto. En esta entrada vamos a ver algunos conceptos clave de este orquestador. ¿Qué es Kubernetes? Kubernetes, abreviado como k8s, es un orquestador de contenedores de código abierto desarrollado originalmente por Google y donado a la Cloud Native Computing Foundation (parte de la&#160;Linux Foundation) que [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/introduccion-a-kubernetes/">Introducción a Kubernetes</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes.png" class="webfeedsFeaturedVisual wp-post-image" alt="Introducción a Kubernetes" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/07/kubernetes-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" />
<p>Kubernetes se ha convertido en el orquestador de <a href="https://aprenderdevops.com/category/contenedores/">contenedores</a> de facto. En esta entrada vamos a ver algunos conceptos clave de este orquestador.</p>



<span id="more-292"></span>



<h2 class="wp-block-heading">¿Qué es Kubernetes?</h2>



<p>Kubernetes, abreviado como k8s, es un orquestador de contenedores de código abierto desarrollado originalmente por Google y donado a la <a href="https://www.cncf.io/">Cloud Native Computing Foundation</a> (parte de la&nbsp;<a href="https://www.linuxfoundation.org/">Linux Foundation</a>) que permite automatizar la implementación, el escalado y la administración de aplicaciones en contenedores.</p>



<h2 class="wp-block-heading">Conceptos clave de Kubernetes</h2>



<p>Para empezar a conocer Kubernetes es necesario tener claros algunos conceptos clave.</p>



<h3 class="wp-block-heading">Pods</h3>



<p>Un pod es una colección lógica de contenedores y recursos compartidos por esos contenedores que pertenecen a una aplicación. Un pod contiene uno o varios contenedores.</p>



<h3 class="wp-block-heading">Labels y selectors</h3>



<p>Las etiquetas o labels son pares clave/valor que se asignan a los objetos, por ejemplo, pods, y que se utilizan para especificar atributos de identificación de objetos que sean significativos y relevantes para los usuarios. Cada objeto puede tener un conjunto de etiquetas clave/valor definidas.</p>



<p>Los label selectors permiten identificar y seleccionar subconjuntos de objetos a partir de etiquetas.</p>



<p>Existen dos formas de seleccionar objetos mediante selectors:</p>



<ul class="wp-block-list">
<li>Requisito basado en la igualdad. Filtran claves por igualdad o desigualdad de valores, pudiendo usarse más de una etiqueta. Por ejemplo:<br><pre class="lang:default decode:true">entorno = produccion, capa != frontend</pre><p>Identifica los objetos en el entorno de producción que no estén en la capa de frontend. El separador coma actúa como operador AND.</p></li>



<li>Requisito basado en conjunto. Filtran claves según un conjunto de valores. Por ejemplo:<br><pre class="lang:default highlight:0 decode:true">environment in (production, qa)<br>tier notin (frontend, backend)<br>partition<br>!partition</pre><p>El primer ejemplo selecciona todos los recursos con clave igual a entorno y valor igual a producción o qa. El segundo ejemplo selecciona todos los recursos con clave igual a tier y valores distintos de frontend y backend, y todos los recursos sin etiquetas con la clave tier. El tercer ejemplo selecciona todos los recursos que tengan una etiqueta con clave partition El cuarto ejemplo selecciona todos los recursos que no tengan una etiqueta con clave partition. De manera similar al requisito basado en igualdad, el separador de coma actúa como operador AND.</p></li>
</ul>



<h3 class="wp-block-heading">Replica sets y controladores de replicación</h3>



<p>Tanto los replica sets como los controladores de replicación garantizan que se ejecute un número específico de réplicas de pod en cada momento. Una réplica es una copia exacta de un pod. Los replica sets y controladores de replicación levantan nuevos pods en caso de caídas de los pods en funcionamiento.</p>



<p>El controlador de replicación es el mecanismo original de replicación en Kubernetes, pero está siendo reemplazado por los replica sets. La única diferencia entre un replica set y un controlador de replicación es que el primero admite requisitos de selector basados en conjuntos.</p>



<h3 class="wp-block-heading">Servicios</h3>



<p>Los servicios son end-points que definen como acceder a las aplicaciones.</p>



<h3 class="wp-block-heading">Volúmenes</h3>



<p>Un volumen de Kubernetes es esencialmente un directorio accesible por todos los contenedores que se ejecutan en un pod. A diferencia del sistema de ficheros local de los contenedores, los datos en volúmenes se preservan, aunque se reinicie el contenedor. Existen varios tipos de volúmenes dependiendo del tipo de almacenamiento, su contenido y su propósito:</p>



<ul class="wp-block-list">
<li>Locales, es decir, en la misma máquina en la que se ejecutan los contenedores, como <strong>emptyDir</strong> o <strong>hostPath</strong>.</li>



<li><strong>nfs</strong> si se montan sobre un sistema de ficheros compartido de tipo NFS (Network File System).</li>



<li>Específicos según el proveedor de cloud como <strong>awsElasticBlockStore</strong>, <strong>azureDisk</strong>, o <strong>gcePersistentDisk</strong>.</li>



<li>En sistemas de fichero distribuidos como por ejemplo <strong>glusterfs</strong> o <strong>cephfs</strong>.</li>



<li>Para propósitos específicos como <strong>secret</strong> o <strong>gitRepo</strong>.</li>
</ul>



<h3 class="wp-block-heading">Deployments</h3>



<p>Un deployment define una aplicación como una colección de recursos y referencias. Los deployments contienen pods.</p>



<h3 class="wp-block-heading">kubectl</h3>



<p>kubectl es la utilidad de línea de comandos que nos permite interactuar con un cluster de Kubernetes y gestionar todos los recursos que hemos estado viendo en esta entrada.</p>



<p>En próximas entradas veremos la arquitectura de Kubernetes y cómo instalarlo.</p>
<p>La entrada <a href="https://aprenderdevops.com/introduccion-a-kubernetes/">Introducción a Kubernetes</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/introduccion-a-kubernetes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Beneficios de la Infraestructura como Código</title>
		<link>https://aprenderdevops.com/beneficios-de-la-infraestructura-como-codigo/</link>
					<comments>https://aprenderdevops.com/beneficios-de-la-infraestructura-como-codigo/#respond</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Fri, 30 Mar 2018 11:30:49 +0000</pubDate>
				<category><![CDATA[Infraestructura como código]]></category>
		<category><![CDATA[automatización]]></category>
		<guid isPermaLink="false">http://aprenderdevops.com/?p=280</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/03/beneficios-infraestructura-como-codigo.png" class="webfeedsFeaturedVisual wp-post-image" alt="Beneficios de la Infraestructura como Código" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/03/beneficios-infraestructura-como-codigo.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/03/beneficios-infraestructura-como-codigo-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /><p>En esta entrada vamos a ver qué beneficios reporta la Infraestructura como Código. ¿Qué es Infraestructura como Código? Infraestructura como Código consiste en automatizar mediante la ejecución de código fuente las tareas de instalación y configuración de componentes de infraestructura TI. Este código fuente define el estado en el que estos componentes de infraestructura queremos [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/beneficios-de-la-infraestructura-como-codigo/">Beneficios de la Infraestructura como Código</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/03/beneficios-infraestructura-como-codigo.png" class="webfeedsFeaturedVisual wp-post-image" alt="Beneficios de la Infraestructura como Código" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/03/beneficios-infraestructura-como-codigo.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/03/beneficios-infraestructura-como-codigo-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /><p>En esta entrada vamos a ver qué beneficios reporta la Infraestructura como Código.</p>
<p><span id="more-280"></span></p>
<h2>¿Qué es Infraestructura como Código?</h2>
<p>Infraestructura como Código consiste en automatizar mediante la ejecución de código fuente las tareas de instalación y configuración de componentes de infraestructura TI. Este código fuente define el estado en el que estos componentes de infraestructura queremos que se encuentren.</p>
<p>Por lo tanto, con la Infraestructura como Código ya no instalamos ni configuramos la infraestructura de forma manual, sino que programamos cómo queremos que esta infraestructura se instale y configure.</p>
<h2>¿Por qué surge la necesidad de la Infraestructura como Código?</h2>
<p>Todas las compañías, independientemente del sector económico en el que se enmarquen, intentan lanzar sus productos y servicios al mercado lo antes posible porque reducir el Time to Market les proporciona una ventaja competitiva indiscutible. Ser el primero o de los primeros marca la diferencia.</p>
<p>Dentro de esta carrera, la provisión ágil de la infraestructura TI sobre la que se ejecutan estos productos y servicios digitales es esencial. De nada sirve ser ágiles en el desarrollo de las aplicaciones si luego tenemos que esperar a que se provisione la infraestructura para poner estas aplicaciones en producción, disponibles para los clientes.</p>
<p>Esto es además especialmente crítico cuando hablamos de productos o servicios que debido al nivel de aceptación que pueden llegar a tener en el mercado requieren de una infraestructura con cientos o incluso miles de máquinas para asegurar un buen rendimiento.</p>
<p>La Infraestructura como Código lo que consigue es reducir radicalmente el tiempo de provisión de la infraestructura al automatizar tareas que de forma manual pueden llevar días y ahora pasan a realizarse en minutos.</p>
<h2>¿Qué beneficios aporta la Infraestructura como Código?</h2>
<p>Además de la reducción de los tiempos de provisión de infraestructura que acabamos de comentar, y todo lo que esto conlleva en términos de reducción del Time to Market, la Infraestructura como Código mejora la estabilidad de los productos y servicios digitales, ya que se evitan los fallos debidos a la realización de actividades manuales.</p>
<p>Otro beneficio muy importante es la reducción de costes que se consigue con la reducción del tiempo y el esfuerzo necesarios para provisionar la infraestructura.</p>
<p>Por otra parte, una infraestructura más estable implica siempre menos coste en actividades de soporte y mantenimiento, y una mayor satisfacción de los clientes.</p>
<p>La entrada <a href="https://aprenderdevops.com/beneficios-de-la-infraestructura-como-codigo/">Beneficios de la Infraestructura como Código</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/beneficios-de-la-infraestructura-como-codigo/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Instalación de SonarQube con Docker</title>
		<link>https://aprenderdevops.com/instalacion-de-sonarqube-con-docker/</link>
					<comments>https://aprenderdevops.com/instalacion-de-sonarqube-con-docker/#comments</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Sun, 25 Feb 2018 16:35:34 +0000</pubDate>
				<category><![CDATA[Aseguramiento de la calidad]]></category>
		<category><![CDATA[Contenedores]]></category>
		<category><![CDATA[Infraestructura como código]]></category>
		<category><![CDATA[análisis estático de código]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[sonarqube]]></category>
		<guid isPermaLink="false">http://aprenderdevops.com/?p=262</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/02/sonarqube-docker.png" class="webfeedsFeaturedVisual wp-post-image" alt="Instalación de SonarQube con Docker" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/02/sonarqube-docker.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/02/sonarqube-docker-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /><p>Vamos a ver cómo instalar SonarQube utilizando contenedores Docker. En esta ocasión nos centraremos únicamente en la instalación de SonarQube. En posteriores entradas veremos cómo integrar SonarQube con otras herramientas DevOps y cómo utilizarlo para analizar la calidad de los desarrollos. ¿Qué es SonarQube? SonarQube (conocido anteriormente como Sonar) es una herramienta open source para [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/instalacion-de-sonarqube-con-docker/">Instalación de SonarQube con Docker</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2018/02/sonarqube-docker.png" class="webfeedsFeaturedVisual wp-post-image" alt="Instalación de SonarQube con Docker" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2018/02/sonarqube-docker.png 700w, https://aprenderdevops.com/wp-content/uploads/2018/02/sonarqube-docker-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" />
<p>Vamos a ver cómo instalar SonarQube utilizando contenedores Docker.</p>



<span id="more-262"></span>



<p>En esta ocasión nos centraremos únicamente en la instalación de SonarQube. En posteriores entradas veremos cómo integrar SonarQube con otras herramientas DevOps y cómo utilizarlo para analizar la calidad de los desarrollos.</p>



<h2 class="wp-block-heading">¿Qué es SonarQube?</h2>



<p><a href="https://www.sonarqube.org/">SonarQube</a> (conocido anteriormente como Sonar) es una herramienta open source para evaluar la calidad del código fuente. Utiliza herramientas de análisis estático de código fuente para obtener métricas de calidad del código.</p>



<p>Estas son algunas de las características de SonarQube que hacen que sea una de las soluciones de evaluación de calidad del software más utilizadas:</p>



<ul class="wp-block-list">
<li>Es open source aunque también se puede optar por ediciones comerciales que incluyen soporte dedicado.</li>



<li>Analizadores de más de 20 lenguajes de programación entre los que se incluyen Java, JavaScript, Python, PHP, C/C++, C# o VB.NET.</li>



<li>Es fácil de integrar dentro de la cadena de herramientas de DevOps. Esto incluye los sistemas de compilación como <a href="https://maven.apache.org/">Maven</a>, <a href="https://gradle.org/">Gradle</a> o <a href="http://ant.apache.org/">Ant</a>&nbsp;y los motores de integración continua como <a href="https://jenkins.io/">Jenkins</a>, <a href="https://es.atlassian.com/software/bamboo">Bamboo</a>, <a href="https://travis-ci.org/">Travis CI</a> o <a href="https://www.visualstudio.com/es/tfs/">Visual Studio Team Foundation Server</a>.</li>
</ul>



<h2 class="wp-block-heading">Requisitos de instalación de SonarQube</h2>



<p>Los requisitos necesarios para poder instalar SonarQube se detallan en el siguiente enlace a la documentación de SonarQube: <a href="https://docs.sonarqube.org/latest/requirements/requirements/">https://docs.sonarqube.org/latest/requirements/requirements/</a></p>



<p>De entre todos los requisitos detallados en la documentación cabe destacar lo siguiente:</p>



<ul class="wp-block-list">
<li>Es necesario tener instalado Java 11 (Oracle JRE 11 u OpenJDK 11).</li>



<li>Se necesitan al menos 3 Gb de memoria.</li>



<li>El espacio en disco necesario depende de la cantidad de código fuente a analizar.</li>



<li>El almacenamiento debe tener un excelente rendimiento de lectura/escritura.</li>



<li>Se necesita una base de datos para almacenar la configuración de SonarQube, así como otra información necesaria para el correcto funcionamiento de la solución. Las bases de datos soportadas son PostgreSQL, Microsoft SQL Server, Oracle y MySQL. En nuestro caso vamos a utilizar una base de datos PostgreSQL.</li>
</ul>



<h2 class="wp-block-heading">¿Qué necesitáis para hacer este laboratorio?</h2>



<p>La utilización de contenedores Docker simplifica mucho la instalación de SonarQube. Únicamente se necesita contar con un equipo que tenga Docker instalado. Si no tenéis Docker instalado, podéis seguir las <a href="https://docs.docker.com/install/">instrucciones de instalación</a> para vuestro sistema operativo en la web oficial de Docker.</p>



<p>A continuación, vamos a ver cómo instalar SonarQube utilizando contenedores Docker.</p>



<h2 class="wp-block-heading">¿Qué imágenes Docker elegir?</h2>



<p>Vamos a necesitar dos imágenes Docker: una para el servidor SonarQube y otra para la base de datos, en este caso PostgreSQL. Concretamente, las imágenes que vamos a utilizar son la imagen oficial de SonarQube (<a href="https://hub.docker.com/_/sonarqube/">sonarqube</a>) y la imagen oficial de PostgreSQL (<a href="https://hub.docker.com/_/postgres/">postgres</a>).</p>



<h2 class="wp-block-heading">Instalación de SonarQube utilizando docker-compose</h2>



<p>Para facilitar la instalación de SonarQube en contenedores Docker vamos a utilizar el comando docker-compose.</p>



<p>A continuación, podéis ver el fichero docker-compose.yml que describe cómo se van a ejecutar los contenedores.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; auto-links: false; gutter: false; title: ; notranslate">
version: &#039;2&#039;

services:
  sonarqube:
    image: sonarqube
    ports:
      - &quot;9000:9000&quot;
    networks:
      - sonarnet
    environment:
      - SONARQUBE_JDBC_URL=jdbc:postgresql://db:5432/sonar
      - SONARQUBE_JDBC_USERNAME=sonar
      - SONARQUBE_JDBC_PASSWORD=sonar
    volumes:
      - sonarqube_conf:/opt/sonarqube/conf
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_bundled-plugins:/opt/sonarqube/lib/bundled-plugins
      
  db:
    image: postgres
    networks:
      - sonarnet
    environment:
      - POSTGRES_USER=sonar
      - POSTGRES_PASSWORD=sonar
    volumes:
      - postgresql:/var/lib/postgresql
      - postgresql_data:/var/lib/postgresql/data
      
networks:
  sonarnet:
    driver: bridge

volumes:
  sonarqube_conf:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_bundled-plugins:
  postgresql:
  postgresql_data:
</pre></div>


<p>Para arrancar los contenedores ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker-compose up -d
</pre></div>


<h2 class="wp-block-heading">Acceso a la consola de SonarQube</h2>



<p>Una vez arrancados los contenedores, abrimos un navegador web y accedemos a http://localhost:9000 para acceder a la consola de SonarQube.</p>



<p>El usuario y la contraseña predeterminados son admin y admin respectivamente. La primera ver que accedamos nos pedirá que cambiemos la contraseña.</p>



<figure class="wp-block-image size-large"><a href="https://aprenderdevops.com/wp-content/uploads/2021/10/consola-sonarqube.png"><img loading="lazy" decoding="async" width="1024" height="585" src="https://aprenderdevops.com/wp-content/uploads/2021/10/consola-sonarqube-1024x585.png" alt="Instalación de SonarQube con Docker" class="wp-image-565" srcset="https://aprenderdevops.com/wp-content/uploads/2021/10/consola-sonarqube-1024x585.png 1024w, https://aprenderdevops.com/wp-content/uploads/2021/10/consola-sonarqube-300x171.png 300w, https://aprenderdevops.com/wp-content/uploads/2021/10/consola-sonarqube-768x438.png 768w, https://aprenderdevops.com/wp-content/uploads/2021/10/consola-sonarqube.png 1235w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p></p>



<h2 class="wp-block-heading">Código fuente del laboratorio</h2>



<p>Podéis descargar o clonar el código fuente completo de este laboratorio de GitHub de <a href="https://github.com/aprenderdevops/docker-sonarqube">https://github.com/aprenderdevops/docker-sonarqube</a>.</p>
<p>La entrada <a href="https://aprenderdevops.com/instalacion-de-sonarqube-con-docker/">Instalación de SonarQube con Docker</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/instalacion-de-sonarqube-con-docker/feed/</wfw:commentRss>
			<slash:comments>13</slash:comments>
		
		
			</item>
		<item>
		<title>Configuración de builds automatizados en Docker Hub utilizando tags de Git</title>
		<link>https://aprenderdevops.com/builds-automatizados-en-docker-hub-utilizando-tags-de-git/</link>
					<comments>https://aprenderdevops.com/builds-automatizados-en-docker-hub-utilizando-tags-de-git/#respond</comments>
		
		<dc:creator><![CDATA[Arturo]]></dc:creator>
		<pubDate>Wed, 14 Feb 2018 06:30:58 +0000</pubDate>
				<category><![CDATA[Contenedores]]></category>
		<category><![CDATA[Integración y entrega continua]]></category>
		<category><![CDATA[builds automatizados]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[docker hub]]></category>
		<category><![CDATA[git tag]]></category>
		<category><![CDATA[github]]></category>
		<guid isPermaLink="false">http://aprenderdevops.com/?p=228</guid>

					<description><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2017/12/builds-dockerhub.png" class="webfeedsFeaturedVisual wp-post-image" alt="Configuración de builds automatizados en Docker Hub" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2017/12/builds-dockerhub.png 700w, https://aprenderdevops.com/wp-content/uploads/2017/12/builds-dockerhub-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /><p>En esta entrada vamos a ver cómo configurar builds automatizados en Docker Hub para que estos se desencadenen a partir del etiquetado de un commit en GitHub. En la entrada Configuración de builds automatizados en Docker Hub vimos cómo configurar un repositorio Docker Hub (aprenderdevops/jenkins)&#160;para enlazarlo con un repositorio de código&#160;GitHub (aprenderdevops/docker-jenkins), de forma que [&#8230;]</p>
<p>La entrada <a href="https://aprenderdevops.com/builds-automatizados-en-docker-hub-utilizando-tags-de-git/">Configuración de builds automatizados en Docker Hub utilizando tags de Git</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="300" src="https://aprenderdevops.com/wp-content/uploads/2017/12/builds-dockerhub.png" class="webfeedsFeaturedVisual wp-post-image" alt="Configuración de builds automatizados en Docker Hub" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://aprenderdevops.com/wp-content/uploads/2017/12/builds-dockerhub.png 700w, https://aprenderdevops.com/wp-content/uploads/2017/12/builds-dockerhub-300x129.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" />
<p>En esta entrada vamos a ver cómo configurar builds automatizados en Docker Hub para que estos se desencadenen a partir del etiquetado de un commit en GitHub.</p>



<span id="more-228"></span>



<p>En la entrada <a href="http://aprenderdevops.com/configuracion-de-builds-automatizados-en-docker-hub/">Configuración de builds automatizados en Docker Hub</a> vimos cómo configurar un repositorio <a href="https://hub.docker.com/">Docker Hub</a> (<a href="https://hub.docker.com/r/aprenderdevops/jenkins/">aprenderdevops/jenkins</a>)&nbsp;para enlazarlo con un repositorio de código&nbsp;<a href="https://github.com/">GitHub</a> (<a href="https://github.com/aprenderdevops/docker-jenkins">aprenderdevops/docker-jenkins</a>), de forma que cualquier actualización del código fuente en el repositorio GitHub desencadene automáticamente en Docker Hub la construcción de una nueva versión de la imagen Docker.</p>



<p>Con esta configuración, cualquier actualización de código en la rama master del repositorio GitHub desencadenará la construcción de una nueva imagen Docker etiquetada con el tag latest.</p>



<p>Además, cualquier actualización en otra rama del repositorio GitHub distinta de la rama master desencadenará la construcción de una nueva imagen Docker etiquetada con el nombre de la rama de GitHub.</p>



<p>Esta última configuración es útil si tenemos una o más líneas de desarrollo paralelas a la línea principal (rama master) y queremos que se construyan imágenes Docker etiquetadas con el nombre de cada rama, de forma que sea muy sencillo identificar a que código fuente corresponde cada imagen en función de su etiqueta asignada. Las modificaciones en GitHub en cualquiera de las ramas desencadenarán la construcción de la imagen correspondiente, de forma que se puede ir evolucionando la funcionalidad de cualquiera de las ramas en paralelo al resto de ramas y de la rama principal.</p>



<h2 class="wp-block-heading">Utilidad de los tags de Git</h2>



<p>El problema de las ramas de Git es que no sirven para identificar una versión concreta y estática del código. Para conseguir esto, lo mejor es utilizar tags (o etiquetas) de Git.</p>



<p>Un tag es una cadena arbitraria que apunta a un commit específico de un repositorio Git. Se trata, por lo tanto, de algo estático, ya que el código puede seguir evolucionando, pero el tag siempre apuntará a un determinado punto de la historia del código. La principal utilidad de los tags es identificar las distintas versiones o releases del código.</p>



<p>Podéis encontrar información sobre el uso de tags en Git en el siguiente enlace: <a href="https://git-scm.com/book/es/v2/Fundamentos-de-Git-Etiquetado">https://git-scm.com/book/es/v2/Fundamentos-de-Git-Etiquetado</a></p>



<p>Cuando tenemos builds automatizados en Docker Hub, la utilización de tags Git resulta de gran utilidad para identificar las distintas versiones de las imágenes Docker que se van construyendo.</p>



<p>Vamos a ver cómo configurar en Docker Hub esta característica.</p>



<h2 class="wp-block-heading">Configuración de builds automatizados en Docker Hub utilizando tags de Git</h2>



<p>Lo primero que tenemos que hacer es logarnos en Docker Hub y acceder a la configuración de los builds (opción Build Settings) del repositorio en el que queremos configurar builds automatizados utilizando tags de Git.</p>



<p>Una vez en la pantalla Build Settings nos aparecerá una configuración similar a la de la siguiente pantalla.</p>


<div class="wp-block-image">
<figure class="aligncenter"><a href="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-1.png"><img loading="lazy" decoding="async" width="1024" height="639" src="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-1-1024x639.png" alt="Configuración de builds automatizados en Docker Hub utilizando tags de Git" class="wp-image-233" srcset="https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-1-1024x639.png 1024w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-1-300x187.png 300w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-1-768x479.png 768w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-1.png 1269w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<p></p>



<p>En esta configuración, si previamente ya habíamos configurado los builds automatizados, tendremos una línea para la rama master y otra línea para cualquier rama distinta de la rama master. Lo que tenemos que hacer ahora es pulsar en el símbolo más de color verde y añadir una línea de tipo Tag. Para esta nueva línea podemos dejar los valores por defecto. De esta forma, cualquier tag creado en el repositorio GitHub desencadenará un build cuya imagen Docker resultante será etiquetada con el mismo tag que se ha creado en GitHub.</p>


<div class="wp-block-image">
<figure class="aligncenter"><a href="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-2.png"><img loading="lazy" decoding="async" width="1024" height="699" src="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-2-1024x699.png" alt="Configuración de builds automatizados en Docker Hub utilizando tags de Git" class="wp-image-234" srcset="https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-2-1024x699.png 1024w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-2-300x205.png 300w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-2-768x524.png 768w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-2.png 1271w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<p></p>



<h2 class="wp-block-heading">Actualización del código en GitHub y etiquetado con un tag</h2>



<p>Para probar que esta nueva configuración de builds automatizados funciona correctamente, vamos a hacer una modificación en la rama master del código de nuestro proyecto de <a href="http://aprenderdevops.com/instalacion-de-jenkins-con-docker/">instalación de Jenkins con Docker</a>.&nbsp;También vamos a etiquetar ese código con el comando git tag. Por último, lo vamos a subir al repositorio GitHub (<a href="https://github.com/aprenderdevops/docker-jenkins">aprenderdevops/docker-jenkins</a>) mediante el comando git push.</p>



<p>Todo esto, debería desencadenar la construcción de dos imágenes Docker, una correspondiente a la rama master y que se etiquetará con el tag latest, y otra correspondiente al tag de Git que hayamos subido a GitHub y que se etiquetará con ese mismo tag. Ambas imágenes serán totalmente idénticas, cambiando únicamente la etiqueta que tienen asignada.</p>



<p>Vamos a ver en detalle los pasos de esta modificación en el código del proyecto de <a href="http://aprenderdevops.com/instalacion-de-jenkins-con-docker/">instalación de Jenkins con Docker</a>.</p>



<h3 class="wp-block-heading">Instalación de un plugin adicional en Jenkins</h3>



<p>La modificación que vamos a hacer es muy sencilla. Consistirá en añadir un nuevo plugin Jenkins a nuestra imagen Docker. El plugin que he elegido es <a href="https://jenkins.io/projects/blueocean/">Blue Ocean</a> (identificado como <a href="https://plugins.jenkins.io/blueocean">blueocean</a>). Este plugin realiza un completo rediseño del interfaz de usuario de Jenkins.</p>



<p>Para añadir un nuevo plugin Jenkins a la imagen Docker únicamente tenemos que incluir el identificador del plugin, en este caso blueocean, en el fichero plugins.txt. Os recuerdo que este fichero contiene todos los plugins de Jenkins que queremos incluir en nuestra imagen Docker. Se trata de un fichero en formato texto que incluye un identificador de plugin por línea. Añadiendo el identificador blueocean en el fichero plugins.txt se instalará el plugin Blue Ocean y todos los plugins de los que éste dependa para su correcto funcionamiento.</p>



<h3 class="wp-block-heading">Asignación de un tag para versionar la imagen Docker</h3>



<p>Una vez realizada la modificación en el código de nuestro proyecto, hacemos un commit de los cambios de nuestro código y le asignamos un tag. Esto lo hacemos ejecutando los comandos que detallo a continuación:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ git add plugins.txt
$ git commit -m &quot;Se añade el plugin blueocean en plugins.txt&quot;
&#x5B;master c38387a] Se añade el plugin blueocean en plugins.txt
1 file changed, 2 insertions(+), 1 deletion(-)
$ git tag 1.5 -m &quot;Versión 1.5. Se añade el plugin Blue Ocean.&quot;
</pre></div>


<p>En mi caso he etiquetado esta versión como la 1.5.</p>



<p>Podemos obtener información sobre un determinado tag ejecutando un comando git show como el siguiente:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; gutter: false; title: ; notranslate">
$ git show 1.5
tag 1.5
Tagger: aprenderdevops &lt;jarfernandez@aprenderdevops.com&gt;
Date:   Sun Feb 11 14:44:19 2018 +0100

Versión 1.5. Se añade el plugin Blue Ocean.

commit 14287aafa95734a3e6fc4d8f5bceb1f73c33340d (HEAD -&gt; master, tag: 1.5, origin/master, origin/HEAD)
Author: aprenderdevops &lt;jarfernandez@aprenderdevops.com&gt;
Date:   Sun Feb 11 14:43:51 2018 +0100

    Se añade el plugin blueocean en plugins.txt

diff --git a/plugins.txt b/plugins.txt
index 30ac56c..1b3b57c 100644
--- a/plugins.txt
+++ b/plugins.txt
@@ -5,6 +5,7 @@ antisamy-markup-formatter
 apache-httpcomponents-client-4-api
 authentication-tokens
 branch-api
+blueocean
 build-monitor-plugin
 build-pipeline-plugin
 checkstyle
@@ -69,4 +70,4 @@ workflow-job
 workflow-multibranch
 workflow-scm-step
 workflow-step-api
-workflow-support
\ No newline at end of file
+workflow-support
</pre></div>


<p>Por último, para actualizar estos cambios en GitHub ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ git push origin master --tag
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 489 bytes | 489.00 KiB/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/aprenderdevops/docker-jenkins.git
   c6c882b..14287aa  master -&gt; master
 * &#x5B;new tag]         1.5 -&gt; 1.5

</pre></div>


<p>En el repositorio de GitHub tendremos una nueva release etiquetada con el tag 1.5.</p>


<div class="wp-block-image">
<figure class="aligncenter"><a href="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-3.png"><img loading="lazy" decoding="async" width="1024" height="456" src="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-3-1024x456.png" alt="Configuración de builds automatizados en Docker Hub utilizando tags de Git" class="wp-image-235" srcset="https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-3-1024x456.png 1024w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-3-300x134.png 300w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-3-768x342.png 768w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-3.png 1271w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<p></p>



<p>Estos cambios en GitHub desencadenarán dos builds en Docker Hub, uno etiquetado como latest y otro como 1.5.</p>


<div class="wp-block-image">
<figure class="aligncenter"><a href="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-4.png"><img loading="lazy" decoding="async" width="1024" height="590" src="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-4-1024x590.png" alt="Configuración de builds automatizados en Docker Hub utilizando tags de Git" class="wp-image-236" srcset="https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-4-1024x590.png 1024w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-4-300x173.png 300w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-4-768x443.png 768w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-4.png 1273w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<p></p>



<p>Pasados unos minutos ambas imágenes estarán disponibles en Docker Hub y podremos usarlas para ejecutar Jenkins con el plugin Blue Ocean.</p>


<div class="wp-block-image">
<figure class="aligncenter"><a href="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-5.png"><img loading="lazy" decoding="async" width="1024" height="390" src="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-5-1024x390.png" alt="Configuración de builds automatizados en Docker Hub utilizando tags de Git" class="wp-image-237" srcset="https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-5-1024x390.png 1024w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-5-300x114.png 300w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-5-768x293.png 768w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-5.png 1270w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<p></p>



<h3 class="wp-block-heading">Arranque del contenedor con la nueva imagen Docker</h3>



<p>Para comprobar que todo ha ido bien, descargamos a local la nueva imagen Docker construida. Para ello, ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker pull aprenderdevops/jenkins
</pre></div>


<p>Una vez descargada la nueva imagen Docker, arrancamos el contenedor ejecutando el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker-compose up -d
Creating volume &quot;dockerjenkins_jenkins_home&quot; with default driver
Creating dockerjenkins_master_1 ... done
</pre></div>


<p>Una vez arrancado el contenedor, abrimos un navegador y accedemos a http://localhost:8080 para entrar en la consola de administración de Jenkins.</p>



<p>Para obtener la contraseña del usuario admin de Jenkins ejecutamos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; auto-links: false; gutter: false; title: ; notranslate">
$ docker exec -it dockerjenkins_master_1 cat /var/jenkins_home/secrets/initialAdminPassword
</pre></div>


<p>Si todo ha ido bien, en la parte izquierda de la consola de Jenkins se mostrará el icono de acceso a la interfaz Blue Ocean.</p>


<div class="wp-block-image">
<figure class="aligncenter"><a href="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-6.png"><img loading="lazy" decoding="async" width="1024" height="625" src="http://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-6-1024x625.png" alt="Configuración de builds automatizados en Docker Hub utilizando tags de Git" class="wp-image-238" srcset="https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-6-1024x625.png 1024w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-6-300x183.png 300w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-6-768x469.png 768w, https://aprenderdevops.com/wp-content/uploads/2018/02/builds-dockerhub-tags-6.png 1182w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<p></p>



<h2 class="wp-block-heading">Código fuente del laboratorio</h2>



<p>Podéis descargar o clonar de GitHub el código fuente completo de este laboratorio de&nbsp;<a href="https://github.com/aprenderdevops/docker-jenkins">https://github.com/aprenderdevops/docker-jenkins</a>.</p>
<p>La entrada <a href="https://aprenderdevops.com/builds-automatizados-en-docker-hub-utilizando-tags-de-git/">Configuración de builds automatizados en Docker Hub utilizando tags de Git</a> se publicó primero en <a href="https://aprenderdevops.com">aprenderDevOps</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://aprenderdevops.com/builds-automatizados-en-docker-hub-utilizando-tags-de-git/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
