<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Leonel Gareis</title>
    <description>The latest articles on Forem by Leonel Gareis (@gareisdev).</description>
    <link>https://forem.com/gareisdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F584421%2F57326c4d-6168-4ac4-98f3-cd3adef87aaf.jpg</url>
      <title>Forem: Leonel Gareis</title>
      <link>https://forem.com/gareisdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gareisdev"/>
    <language>en</language>
    <item>
      <title>Docker para Jrs #2: Imágenes y Contenedores 🍰</title>
      <dc:creator>Leonel Gareis</dc:creator>
      <pubDate>Thu, 02 Jan 2025 12:40:00 +0000</pubDate>
      <link>https://forem.com/gareisdev/docker-para-jrs-2-imagenes-y-contenedores-18a3</link>
      <guid>https://forem.com/gareisdev/docker-para-jrs-2-imagenes-y-contenedores-18a3</guid>
      <description>&lt;p&gt;En el primer post te conté lo básico sobre Docker y por qué puede ser tu mejor amigo para contenerizar apps. Ahora vamos a dar un paso más y entender dos conceptos clave: imágenes y contenedores. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Spoiler: si los entendés bien, el resto será pan comido. 😉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué es una Imagen de Docker?
&lt;/h2&gt;

&lt;p&gt;Las imágenes son como una receta: definen qué ingredientes (archivos, dependencias) y pasos (comandos) necesita tu app para correr.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cada imagen es inmutable (una vez creada, no se modifica).&lt;/li&gt;
&lt;li&gt;Se pueden construir usando un archivo llamado Dockerfile.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ejemplo:&lt;br&gt;
Si querés una app basada en Python, tu receta incluiría Python, librerías, y tu código.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Y qué es un Contenedor?
&lt;/h2&gt;

&lt;p&gt;Un contenedor es la app lista y funcionando, creada a partir de una imagen. Es como seguir una receta y tener el plato servido. 🍝&lt;/p&gt;

&lt;p&gt;Los contenedores son efímeros: viven mientras los necesitás.&lt;br&gt;
Podés correr, pausar o eliminar contenedores sin afectar la imagen original.&lt;/p&gt;
&lt;h2&gt;
  
  
  Capas en las Imágenes: el truco de la magia 🎩
&lt;/h2&gt;

&lt;p&gt;Cada imagen se construye en capas. Cada comando en un Dockerfile crea una nueva capa.&lt;br&gt;
Esto hace que las imágenes sean eficientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si actualizás algo, Docker reutiliza las capas que no cambiaron.&lt;/li&gt;
&lt;li&gt;Resultado: builds más rápidos y menos espacio usado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch93z4wv9dyxh1616r37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch93z4wv9dyxh1616r37.png" alt="Image description" width="756" height="988"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Comandos Básicos para Trabajar con Imágenes y Contenedores
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Gestión de Imágenes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker pull &amp;lt;imagen&amp;gt;&lt;/code&gt;: Bajate una imagen del registry (como Docker Hub).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker images&lt;/code&gt;: Listá las imágenes locales.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker rmi &amp;lt;id&amp;gt;&lt;/code&gt;: Eliminá una imagen que no necesitás.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker tag &amp;lt;id_imagen&amp;gt; &amp;lt;nuevo_nombre&amp;gt;&lt;/code&gt;: Renombrá una imagen local.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker save -o &amp;lt;archivo.tar&amp;gt; &amp;lt;imagen&amp;gt;&lt;/code&gt;: Guardá una imagen como archivo.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker load -i &amp;lt;archivo.tar&amp;gt;&lt;/code&gt;: Cargá una imagen desde un archivo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Gestión de Contenedores
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker run &amp;lt;imagen&amp;gt;&lt;/code&gt;: Crea y corre un contenedor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker stop &amp;lt;id&amp;gt;&lt;/code&gt;: Paramos un contenedor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker ps -a&lt;/code&gt;: Lista todos los contenedores (corriendo o no).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker rm &amp;lt;id&amp;gt;&lt;/code&gt;: Eliminá un contenedor parado.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker logs &amp;lt;id&amp;gt;&lt;/code&gt;: Mirá los logs de un contenedor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker exec -it &amp;lt;id&amp;gt; bash&lt;/code&gt;: Ingresá a un contenedor corriendo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Ejemplo práctico:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull nginx
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; mi-nginx &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:80 nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Con esto, ya tenés un servidor web corriendo en &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;. 🚀&lt;/p&gt;
&lt;h2&gt;
  
  
  Bonus: Contenerizá tu Primera App en Go
&lt;/h2&gt;

&lt;p&gt;Creamos una app simple que devuelve "¡Hola, Docker!" cuando accedemos a localhost:8080.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/mi-app
│── Dockerfile
│── main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"¡Hola, Docker!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Imagen base&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; golang:1.20&lt;/span&gt;

&lt;span class="c"&gt;# Configuración del contenedor&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Build de la app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go build &lt;span class="nt"&gt;-o&lt;/span&gt; app .

&lt;span class="c"&gt;# Comando que ejecuta el contenedor&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["./app"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pasos para Correr la App
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Navegá al directorio donde está tu app (mi-app).&lt;/li&gt;
&lt;li&gt;Construí la imagen:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; mi-app &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Corré un contenedor basado en la imagen:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 mi-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Probalo en el navegador o con curl:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl localhost:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Próximos Pasos
&lt;/h2&gt;

&lt;p&gt;¡Ya entendiste cómo funcionan las imágenes y los contenedores en Docker! Ahora podés empezar a experimentar construyendo tus propias imágenes y lanzando aplicaciones contenerizadas. Pero acá no termina el viaje: en el próximo post vamos a hablar de algo igual de importante que los contenedores mismos, los volúmenes.&lt;/p&gt;

&lt;p&gt;Vas a aprender cómo guardar y compartir datos entre tus contenedores, algo fundamental si querés que tus aplicaciones sean más que "efímeras". Desde un servidor web que mantiene sus logs hasta una base de datos que conserva información entre reinicios, los volúmenes son clave para llevar tus contenedores al próximo nivel. 🚀&lt;/p&gt;

&lt;p&gt;Nos vemos en la próxima entrega: "Docker para Jrs #3: Guardá tus Datos con Volúmenes 📂". ¡A seguir aprendiendo! 🙌&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>devops</category>
      <category>docker</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Docker para Jrs #1: Introducción 🔥</title>
      <dc:creator>Leonel Gareis</dc:creator>
      <pubDate>Sun, 04 Aug 2024 21:35:48 +0000</pubDate>
      <link>https://forem.com/gareisdev/docker-para-jrs-1-introduccion-b6p</link>
      <guid>https://forem.com/gareisdev/docker-para-jrs-1-introduccion-b6p</guid>
      <description>&lt;h2&gt;
  
  
  📦 Docker en pocas palabras
&lt;/h2&gt;

&lt;p&gt;Docker es "una" herramienta que permite a los desarrolladores empaquetar sus aplicaciones y todas sus dependencias en un "contenedor". Este contenedor puede ejecutarse en cualquier entorno, garantizando que la aplicación funcione de la misma manera sin importar dónde se ejecute.&lt;/p&gt;

&lt;p&gt;¿Por qué Docker es lo recomendado? &lt;br&gt;
En el mundo del desarrollo, es común escuchar la frase "funciona en mi máquina, pero no en la tuya". Docker resuelve este problema al garantizar que tu aplicación y sus dependencias siempre se ejecuten de la misma manera. ¿Cómo lo hace? Empaquetando todo y ejecutandolo en un contenedor, que incluye:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El código de tu aplicación.&lt;/li&gt;
&lt;li&gt;Las bibliotecas y dependencias necesarias.&lt;/li&gt;
&lt;li&gt;Configuraciones del sistema.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contenedores vs. Máquinas Virtuales 🖥️
&lt;/h2&gt;

&lt;p&gt;Para entender mejor Docker, es útil compararlo con las máquinas virtuales (VMs).&lt;/p&gt;

&lt;h3&gt;
  
  
  Máquinas Virtuales
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simulan hardware completo: Cada VM incluye un sistema operativo completo.&lt;/li&gt;
&lt;li&gt;Recursos: Cada VM necesita su propia cantidad de memoria y CPU asignada. Estos recursos son reservados se usen o no.&lt;/li&gt;
&lt;li&gt;Aislamiento completo: Cada VM opera de manera totalmente independiente, lo que puede ser necesario para ciertos entornos de seguridad o aplicaciones que requieren un nivel alto de aislamiento.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Contenedores
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ligereza: Los contenedores comparten el kernel del sistema operativo anfitrión, lo que los hace mucho más ligeros.&lt;/li&gt;
&lt;li&gt;Arranque rápido: Iniciar un contenedor toma segundos.&lt;/li&gt;
&lt;li&gt;Eficiencia: Pueden ejecutarse múltiples contenedores en la misma máquina sin una sobrecarga significativa.&lt;/li&gt;
&lt;li&gt;Aislamiento: Aunque los contenedores comparten el mismo kernel, siguen proporcionando un buen nivel de aislamiento para la mayoría de las aplicaciones.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Beneficios de Docker ⭐
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Portabilidad: Los contenedores pueden ejecutarse en cualquier entorno que tenga Docker instalado.&lt;/li&gt;
&lt;li&gt;Eficiencia: Al compartir el kernel del sistema operativo, los contenedores utilizan menos recursos que las máquinas virtuales.&lt;/li&gt;
&lt;li&gt;Consistencia: El mismo contenedor se puede ejecutar en desarrollo, pruebas y producción, eliminando problemas de configuración entre entornos.&lt;/li&gt;
&lt;li&gt;Aislamiento: Cada contenedor opera de manera independiente, lo que facilita la gestión de múltiples aplicaciones y sus dependencias.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;¿Esto significa que los contenedores son mejores que las máquinas virtuales? No. Son herramientas desarrolladas con propósitos distintos. Habrá casos en los que las máquinas virtuales, sean una mejor solución que un contenedor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ejemplo práctico
&lt;/h2&gt;

&lt;p&gt;En la documentación oficial de Docker podes encontrar los pasos para instalar la herramienta según el Sistema Operativo que estés usando.&lt;/p&gt;

&lt;p&gt;Dicho esto, para ilustrar lo fácil que es comenzar con Docker, vamos a correr un contenedor simple que muestra un mensaje de "Hola Mundo".&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abris la terminal&lt;/li&gt;
&lt;li&gt;Corres el comando &lt;code&gt;docker run hello-world&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Y así, sin vueltas, tenés tu primer contenedor corriendo con Docker. ¿Viste qué fácil? &lt;br&gt;
Ahora seguramente la pregunta que se te viene es, ¿cómo hizo Docker esto?&lt;/p&gt;

&lt;p&gt;En el medio pasaron algunas cosas que, para no enredarte, decidí graficar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66cjexrne2k7k08f7ox6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66cjexrne2k7k08f7ox6.png" alt="Image description" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;De esta imagen podemos desprender tres conceptos nuevos que me gustaría que te lleves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Docker client: se trata de la interfaz que usamos para comunicarnos con docker. Esta puede ser una interfaz grafica (como Docker Desktop si estas usando Windows/MacOS) o una herramienta de CLI (terminal). Lo importante es que esa herramienta es la encargada de tomar nuestro pedido y enviárselo al "Docker Daemon"&lt;/li&gt;
&lt;li&gt;Docker Daemon: el "demonio" de Docker es el cerebro detrás de todo. Expone una API que le permite recibir instrucciones del cliente. Este proceso se ejecuta en segundo plano y se encarga de cosas como: gestión de contenedores, gestión de imágenes, gestión de volúmenes, etc. &lt;/li&gt;
&lt;li&gt;Registry: en la imagen vemos a Docker Hub como el lugar donde conseguimos las imágenes. Este sitio es un Registry pero no es el único que existe. Lo importante es que se trata de un lugar remoto donde almacenamos las imágenes de contenedores.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión 🎯
&lt;/h2&gt;

&lt;p&gt;En esta primera parte del post, hemos explorado qué es Docker y por qué se ha convertido en una herramienta esencial para el desarrollo moderno. Hemos visto que Docker permite empaquetar aplicaciones en contenedores ligeros y portátiles, resolviendo problemas comunes de consistencia y portabilidad en el desarrollo de software.&lt;/p&gt;

&lt;p&gt;También hemos comparado contenedores con máquinas virtuales, destacando sus diferencias clave en cuanto a ligereza, eficiencia, y uso de recursos. Los contenedores ofrecen una forma más ágil y eficiente de ejecutar aplicaciones, especialmente en entornos de desarrollo y producción donde la consistencia y la rapidez son cruciales.&lt;/p&gt;

&lt;p&gt;Además, hemos desglosado los componentes principales de Docker: el Cliente, el Daemon, y los Registros. Cada uno de estos elementos desempeña un papel fundamental en el ecosistema de Docker, permitiendo a los desarrolladores crear, gestionar y desplegar aplicaciones de manera sencilla y efectiva.&lt;/p&gt;

&lt;p&gt;En la próxima parte, vamos a sumergirnos en los conceptos básicos de Docker, como la creación y ejecución de contenedores, y cómo empezar a trabajar con imágenes de Docker. Prepárate para poner manos a la obra y empezar a contenerizar tus aplicaciones.&lt;/p&gt;

&lt;p&gt;¡Nos vemos en la próxima! 👋&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>devops</category>
      <category>docker</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Despliega un servidor Nginx en AWS con Terraform</title>
      <dc:creator>Leonel Gareis</dc:creator>
      <pubDate>Mon, 27 Nov 2023 18:36:56 +0000</pubDate>
      <link>https://forem.com/gareisdev/despliega-un-servidor-nginx-en-aws-con-terraform-3385</link>
      <guid>https://forem.com/gareisdev/despliega-un-servidor-nginx-en-aws-con-terraform-3385</guid>
      <description>&lt;p&gt;Hoy vamos a aprender como podemos desplegar una instancia EC2 e instalar Nginx de forma rápida y sencilla con Terraform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Desde el inicio: Que es Terraform? 🤔
&lt;/h2&gt;

&lt;p&gt;Terraform es una herramienta que nos permite crear, modificar y versionar la infraestructura de nuestro proyecto  de forma fácil a partir de manifiestos (archivos). A esto se le conoce como IaC (Infrastructure as Code)&lt;/p&gt;

&lt;p&gt;Terraform no es la única herramienta para IaC, pero si me arriesgo a decir que es la más popular.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform vs Manual ❗🟰
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Características&lt;/th&gt;
&lt;th&gt;Terraform&lt;/th&gt;
&lt;th&gt;Configuración Manual&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sintaxis y Lenguaje&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HCL (HashiCorp Configuration Lang.)&lt;/td&gt;
&lt;td&gt;Interfaz gráfica o CLI proveedor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Declarativo vs. Imperativo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Declarativo&lt;/td&gt;
&lt;td&gt;Imperativo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gestión de Estado&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sí (Archivo de Estado)&lt;/td&gt;
&lt;td&gt;No (Depende de documentación)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Escalabilidad&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Escala bien con infraestructuras&lt;/td&gt;
&lt;td&gt;Propenso a complejidad y errores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Control de Versiones&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sí (Archivo de Configuración)&lt;/td&gt;
&lt;td&gt;No (Depende de documentación)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gestión de Cambios&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Planificación antes de aplicar&lt;/td&gt;
&lt;td&gt;Riesgo de cambios no documentados&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reproducibilidad&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Alta&lt;/td&gt;
&lt;td&gt;Variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Curva de Aprendizaje&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderada&lt;/td&gt;
&lt;td&gt;Baja (Interfaz gráfica)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Colaboración&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Facilita la colaboración en equipos&lt;/td&gt;
&lt;td&gt;Dificultad para compartir contextos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibilidad y Abstracción&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Permite abstracciones complejas&lt;/td&gt;
&lt;td&gt;Limitado a la interfaz del proveedor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automatización&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Totalmente automatizable&lt;/td&gt;
&lt;td&gt;Limitado a capacidades de proveedor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Que seria el "versionado"? 🤔
&lt;/h3&gt;

&lt;p&gt;Al declarar toda la infraestructura en archivos, estos pueden estar versionados tranquilamente con Git.&lt;/p&gt;

&lt;h3&gt;
  
  
  Es conveniente hacer todo con Terraform? 🤔
&lt;/h3&gt;

&lt;p&gt;Esto depende mucho de lo que estes haciendo. A veces, para proyectos muy chicos/personales es mas rápido utilizar la consola del proveedor. &lt;/p&gt;




&lt;h2&gt;
  
  
  Instalación 🖥️
&lt;/h2&gt;

&lt;p&gt;Si no tenes Terraform instalado, te sugiero que entres &lt;a href="https://developer.hashicorp.com/terraform/install" rel="noopener noreferrer"&gt;aca&lt;/a&gt; y sigas la guía.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creando nuestra infraestructura ☁️
&lt;/h2&gt;

&lt;p&gt;Empecemos creando nuestro archivo &lt;code&gt;main.tf&lt;/code&gt; con el siguiente contenido (voy a ir explicando para que es cada bloque):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;El archivo &lt;code&gt;main.tf&lt;/code&gt; es el archivo de configuración principal.  Acá vamos a definir todo lo que queremos crear.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El bloque provider le permite saber a Terraform con que proveedor de la nube vamos a trabajar. Existen varios proveedores (podes ver la lista completa en este &lt;a href="https://registry.terraform.io/browse/providers" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Cada proveedor establece que valores deberemos indicar en este bloque. Hay cosas que son obligatorias, y otras que son opcionales.&lt;/p&gt;

&lt;h3&gt;
  
  
  Autenticación 🔐
&lt;/h3&gt;

&lt;p&gt;Si, es necesario que Terraform se identifique con el proveedor para crear los recursos solicitados. Como logramos esto?&lt;/p&gt;

&lt;p&gt;Para el caso de AWS existen 3 formas principales (en la doc hay mas):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Colocar los valores directamente en el bloque del proveedor (no recomiendo esta forma):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;    &lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
        &lt;span class="nx"&gt;access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"clave-de-acceso"&lt;/span&gt;
        &lt;span class="nx"&gt;secret_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"clave-secreta"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Usando variables de entorno (&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; y &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; y opcionalmente &lt;code&gt;AWS_SESSION_TOKEN&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configurando el archivo de credenciales. Podes hacerlo con la herramienta de &lt;code&gt;awscli&lt;/code&gt; y la instrucción &lt;code&gt;aws configure&lt;/code&gt;. Terraform buscara el archivo donde, según la documentación, deberían estar. Pero podemos indicarle nosotros mismos donde buscar con lo siguiente:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;    &lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;shared_config_files&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/tf_user/.aws/conf"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nx"&gt;shared_credentials_files&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/tf_user/.aws/creds"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mi-perfil-para-test"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En mi caso, yo tengo las credenciales como variables de entorno así que no voy a colocar parámetros extras en el bloque del proveedor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creamos una VPC ☁️
&lt;/h3&gt;

&lt;p&gt;Lo primero que vamos a crear es una VPC. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Si estas viendo Terraform, es porque algo de conocimiento tenés sobre AWS y ciertos recursos como VPC, EC2, etc. Si no es el caso, tranquilo/a que repasamos algunos conceptos clave para que entiendas 😃&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Una VPC nos permite crear una red virtual privada para aislar recursos de forma lógica en la nube. Con esto podremos lanzar y gestionar recursos como instancias EC2, bases de datos en RDS, etc.&lt;/p&gt;

&lt;p&gt;Escribamos esto en nuestro &lt;code&gt;main.tf&lt;/code&gt; y analicemos que es:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc"&lt;/span&gt; &lt;span class="s2"&gt;"my-vpc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10.0.0.0/16"&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En Terraform debemos crear un bloque de &lt;code&gt;resource&lt;/code&gt; por cada recurso que deseemos. Se define así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"tipo_de_recurso"&lt;/span&gt; &lt;span class="s2"&gt;"nombre_del_recurso"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;atributo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;valor&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Donde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tipo_de_recurso: indica el tipo de recurso que estamos creando (esto se define en la documentación del proveedor). Por ejemplo: aws_instance, aws_vpc, aws_eks_cluster, etc.&lt;/li&gt;
&lt;li&gt;nombre_del_recurso: nombre que le damos a ese recurso para usarlo en los siguientes bloques en caso de ser necesario (spoiler)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Los Tags
&lt;/h3&gt;

&lt;p&gt;El atributo &lt;code&gt;tags&lt;/code&gt; es algo que se encuentra presente en casi todos los recursos que podemos crear. Yo normalmente agrego estas 3 etiquetas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;El nombre del proyecto para el que estoy creando la infra. Es mejor si es el nombre del repositorio donde estas por almacenar los manifiestos.&lt;/li&gt;
&lt;li&gt;El ambiente para el que esta siendo desplegado (dev, stg, prd).&lt;/li&gt;
&lt;li&gt;El tag de &lt;code&gt;Terraform = true&lt;/code&gt; para saber que ese recurso esta siendo gestionado por esa herramienta y comunicarle así a mi equipo (o a mi yo del futuro) que evite modificarlo manualmente.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creamos un Internet Gateway 🌐
&lt;/h2&gt;

&lt;p&gt;Este recurso es fundamental en la infraestructura de red de AWS, ya que proporciona una conexión entre una red privada en la nube y la red publica de internet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_internet_gateway"&lt;/span&gt; &lt;span class="s2"&gt;"internet-gw"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dev-vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fijate en el siguiente detalle: No estamos escribiendo el id del VPC porque no lo tenemos ya que no existe. Así que le estamos pidiendo a Terraform que lo defina por nosotros cuando cree ese recurso.&lt;br&gt;
Siempre que tengamos que referirnos a un recurso que va a ser creado en el mismo manifiesto, lo vamos a hacer de esta forma: &lt;code&gt;tipo_de_recurso.nombre_del_recurso.atributo&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creamos el Route Table 📄
&lt;/h2&gt;

&lt;p&gt;El Route Table nos permite definir como se dirige el trafico entre las subredes de la VPC y, en particular, como se enruta el trafico desde y hacia internet mediante el Internet Gateway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_route_table"&lt;/span&gt; &lt;span class="s2"&gt;"route-table"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;my-vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;
    &lt;span class="nx"&gt;gateway_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internet-gw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ipv6_cidr_block&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"::/0"&lt;/span&gt;
    &lt;span class="nx"&gt;gateway_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internet-gw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este bloque de configuración está estableciendo reglas para decirle a AWS cómo manejar el tráfico dentro de una VPC, permitiendo que las cosas en esa VPC se comuniquen con el Internet y viceversa. La tabla de rutas es como un mapa que dice a las instancias de la VPC hacia dónde enviar o recibir datos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creamos una subnet en la VPC 🌐
&lt;/h2&gt;

&lt;p&gt;Una subnet es una porción de una red IP mas grande. En AWS, una subnet esta asociada a una VPC y se usa para organizar y segmentar los recursos de red.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet"&lt;/span&gt; &lt;span class="s2"&gt;"subnet-1a"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;my-vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10.0.1.0/24"&lt;/span&gt;
  &lt;span class="nx"&gt;availability_zone&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1a"&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creamos la asociación entre la subnet y la route table 🌐
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_route_table_association"&lt;/span&gt; &lt;span class="s2"&gt;"association-1a"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet-1a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;route_table_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route-table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este bloque nos va a permitir establecer una relación entre la subred que creamos mas arriba y la tabla de enrutamiento también creada con anterioridad. Esto significa, básicamente, que la subred va a usar esas reglas de enrutamiento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creamos un security group 🔓
&lt;/h2&gt;

&lt;p&gt;Los "security group" son como un firewall. Estos permiten definir que conexiones entrantes y salientes se aceptan, y cuales no.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"security-group"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sg-internet"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow ingress and egress connection to the internet"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;my-vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow HTTPS connection"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow HTTP connection"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow SSH connection"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este bloque nos permite definir las reglas necesarias para permitir las conexiones hacia los puertos 80 (HTTP), 443 (HTTPS) y 22 (SSH) desde cualquier IP. Si, se que no es seguro permitir conexiones desde cualquier lado por SSH, pero es solo para el ejemplo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creamos una network interface 🌐
&lt;/h2&gt;

&lt;p&gt;Las "network interfaces" (interfaces de red) son un componente clave para permitir la conexión de instancias EC2 a la red.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_network_interface"&lt;/span&gt; &lt;span class="s2"&gt;"network-interface"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet-1a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;private_ips&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10.0.1.50"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;security-group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este recurso nos permite configurar también la IP privada que asignaremos a la interfaz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creamos una elastic IP 🌐
&lt;/h2&gt;

&lt;p&gt;En AWS, una elastic IP es una dirección IP publica estática que sera asociada a una instancia EC2. Lo que la diferencia de las IPs publicas tradicionales que son asignadas dinámicamente a nuestras instancias EC2, es que las IPs otorgadas por este recurso persisten aun cuando las instancias son reiniciadas o detenidas. Increíble, no?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_eip"&lt;/span&gt; &lt;span class="s2"&gt;"eip"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;domain&lt;/span&gt;                    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vpc"&lt;/span&gt;
  &lt;span class="nx"&gt;network_interface&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_network_interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network-interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;associate_with_private_ip&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10.0.1.50"&lt;/span&gt;

  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internet-gw&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Algo interesante de este bloque es el &lt;code&gt;depends_on&lt;/code&gt; que nos permite decirle a Terraform que debe crear primero de forma explícita. En nuestro caso, este atributo asegura que la Elastic IP se cree después de que el Internet Gateway asociado esté disponible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finalmente: creamos el servidor 🖥️
&lt;/h2&gt;

&lt;p&gt;Las instancias EC2 (Elastic Cloud Computing) son básicamente maquinas virtuales con recursos de computo limitados según el tipo de instancia elegida. Como es una maquina virtual, debemos seleccionar el sistema operativo que correrá en la misma. Es lo que en AWS se conocen como AMI (Amazon Machine Image).&lt;br&gt;
Tenemos AMI's para Windows, Linux y MacOS. &lt;br&gt;
Para este tutoria, voy a usar una imagen de Ubuntu Server 20.04 aunque vos podes usar el que quieras.&lt;/p&gt;

&lt;p&gt;El recurso necesita que le indiquemos el ID de la AMI. Como lo obtenemos? Existen dos formas: buscar en la consola de AWS, o definir un bloque de &lt;code&gt;data&lt;/code&gt; para que haga la búsqueda por nosotros.&lt;/p&gt;

&lt;p&gt;Si vamos por la consola, al darle "Crear instancia" podremos seleccionar el tipo de AMI y copiar el ID. También podes usar esta &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html" rel="noopener noreferrer"&gt;guía&lt;/a&gt; de AWS.&lt;/p&gt;
&lt;h3&gt;
  
  
  El bloque &lt;code&gt;data&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Este bloque se usa para obtener y utilizar información existente antes de la creación o modificación de los recursos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_ami"&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu-ami"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;most_recent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; 
  &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"name"&lt;/span&gt;
    &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"virtualization-type"&lt;/span&gt;
    &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"hvm"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es importante que si vamos a usar esta opción, aceptemos los términos y condiciones de AWS Marketplace. Si no lo hacemos, obtendremos un error como este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;creating EC2 Instance: OptInRequired: In order to use this AWS Marketplace product you need to accept terms and subscribe. To &lt;span class="k"&gt;do &lt;/span&gt;so please visit https://&amp;lt;URL&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por último, creamos la instancia de EC2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"nginx-server"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_ami&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ubuntu-ami&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;

  &lt;span class="nx"&gt;network_interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;device_index&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;network_interface_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_network_interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network-interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si no usaste &lt;code&gt;data&lt;/code&gt;, podes hacerlo de esta forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"nginx-server"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0fc5d935ebf8bc3bc"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;

  &lt;span class="nx"&gt;network_interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;device_index&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;network_interface_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_network_interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network-interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este bloque estamos definiendo: el tipo de instancia, la AMI que debe usar, la interfaz de red (que creamos mas arriba) y los tags de siempre.&lt;/p&gt;

&lt;p&gt;Que nos falta? 🤔&lt;br&gt;
Esto nos creara una instancia con un sistema operativo y nada mas. Que pasa con Nginx? Debemos instalarlo a mano a través de SSH? 🤔&lt;br&gt;
Por suerte no. Si has trabajado con la consola, te acordaras de un input llamado "user data". Este input nos permitía definir un script de bash (en su mayoría) que seria ejecutado cuando la instancia de EC2 sea creada. &lt;br&gt;
Para agregar un &lt;code&gt;user_data&lt;/code&gt; en el bloque, tenemos dos formas:&lt;/p&gt;
&lt;h3&gt;
  
  
  Forma 1️⃣:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;  &lt;span class="err"&gt;...&lt;/span&gt;
  &lt;span class="nx"&gt;user_data&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
#!/bin/bash
sudo apt update
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Forma 2️⃣ (mi favorita)
&lt;/h3&gt;

&lt;p&gt;Creamos un archivo llamado &lt;code&gt;init.sh&lt;/code&gt; (o como prefieras) y definimos el script ahi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start nginx
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora, en el &lt;code&gt;main.tf&lt;/code&gt; definimos el user_data de la siguiente forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;  &lt;span class="err"&gt;...&lt;/span&gt;
  &lt;span class="nx"&gt;user_data&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'init.sh'&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;El archivo de &lt;code&gt;init.sh&lt;/code&gt; debe estar al mismo nivel que el archivo &lt;code&gt;main.tf&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Despliegue 🚀
&lt;/h2&gt;

&lt;p&gt;Ahora que tenemos toda la infraestructura definida, solo nos resta decirle a Terraform que aplique lo solicitado.&lt;/p&gt;

&lt;p&gt;El primer comando que vamos a ejecutar donde se encuentra el &lt;code&gt;main.tf&lt;/code&gt; es: &lt;code&gt;terraform init&lt;/code&gt;. Este comando incializará los archivos de estado y descargara los archivos necesarios para interactuar con el proveedor (AWS en nuestro caso).&lt;/p&gt;

&lt;p&gt;Al ejecutarlo, notaremos que se han creado algunas cosas en el directorio donde estamos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;.terraform.lock.hcl&lt;/code&gt;: este archivo registra la version del proveedor que vamos a usar para el despliegue.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.terraform&lt;/code&gt;: este directorio contiene varios directorios, pero en resumen, acá se guarda el binario del proveedor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Si no estamos seguro de que es lo que va a hacer Terraform, este nos provee de un comando para la visualización del plan de ejecución. Simplemente debemos ejecutar &lt;code&gt;terraform plan&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si estamos seguros, podemos ejecutar &lt;code&gt;terraform apply&lt;/code&gt; para aplicar el plan. Este comando primero nos mostrara todo lo que va a hacer (misma salida que el &lt;code&gt;terraform plan&lt;/code&gt;), y nos pedirá que ingresemos una palabra para confirmar los cambios.&lt;/p&gt;

&lt;p&gt;Mientras el plan se ejecuta, notaremos cambios en nuestro directorio. Se ha creado un archivo llamado &lt;code&gt;terraform.tfstate&lt;/code&gt;. Este es MUY importante para Terraform ya que con el rastrea y gestiona el estado de los recursos que fueron creados por la herramienta.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cuidado! En este &lt;code&gt;terraform.tfstate&lt;/code&gt;, Terraform muestra secretos y cosas sensibles en texto plano. Así que si estas recuperando secretos de Secrets Manager para inyectarlos en los recursos que estes creando/modificando, tené por seguro que van a aparecer ahi sin protección alguna.&lt;/p&gt;

&lt;p&gt;Abordaremos cuestiones de seguridad y buenas practicas en otro post.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Revisamos la consola de AWS
&lt;/h2&gt;

&lt;p&gt;Para saber que todo fue bien, entramos a la consola y nos vamos al apartado de EC2&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3tewj4pkdcyjt8ns2zk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3tewj4pkdcyjt8ns2zk.png" alt="Información de la instancia EC2 creada" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ya tenemos una instancia creada! &lt;br&gt;
Copiemos la IP y vayamos al navegador para corroborar que todo funciona:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvodn8c1slle86v4c2s5r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvodn8c1slle86v4c2s5r.png" alt="Captura del navegador mostrando la respuesta exitosa de Nginx" width="800" height="695"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/vmv47p4zksWDC/giphy-downsized-large.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/vmv47p4zksWDC/giphy-downsized-large.gif" alt="is alive" width="480" height="261"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Destruir lo creado
&lt;/h2&gt;

&lt;p&gt;Para borrar todos los recursos creados y evitar un costo extra en nuestra factura de AWS, apliquemos &lt;code&gt;terraform destroy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3oKIPwoeGErMmaI43S/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3oKIPwoeGErMmaI43S/giphy.gif" alt="Explosiones" width="266" height="200"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Extras (lo que no vimos)
&lt;/h2&gt;

&lt;p&gt;Existen mas cosas de Terraform que no cubrimos en este mini tutorial.&lt;/p&gt;
&lt;h3&gt;
  
  
  Bloque output
&lt;/h3&gt;

&lt;p&gt;Este bloque se utiliza para declarar valores que deben ser mostrados después de que Terraform haya aplicado los cambios. Puede ser información útil, identificadores, direcciones IP, o cualquier otro dato que deseemos exponer después de que la infraestructura ha sido creada o modificada.&lt;/p&gt;

&lt;p&gt;En nuestro caso podriamos agregar el siguiente bloque para obtener la IP pública y evitar acceder a la consola&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"public_ip_nginx_server"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nginx-server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Archivos
&lt;/h3&gt;

&lt;p&gt;Si bien el &lt;code&gt;main.tf&lt;/code&gt; es el mas importante, existen otros archivos que podemos definir para mantener el main lo mas limpio posible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;variables.tf&lt;/code&gt; : acá definimos variables que pueden ser usadas para parametrizar la configuracion de los recursos. Por ejemplo: el environment y el tipo de instancia&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="c1"&gt;# variables.tf&lt;/span&gt;
&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"instance_type"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"environment"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# main.tf&lt;/span&gt;
&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"nginx-server"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0fc5d935ebf8bc3bc"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;-- esto cambió&lt;/span&gt;

  &lt;span class="nx"&gt;network_interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;device_index&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;network_interface_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_network_interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network-interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;user_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"init.sh"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-nginx-server-with-terraform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;-- esto cambió&lt;/span&gt;
    &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;outputs.tf&lt;/code&gt;: Acá definimos todas las salidas que necesitamos&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"public_ip_nginx_server"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nginx-server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;terraform.tfvars&lt;/code&gt;: Este archivo se usa para asignar valores a las variables definidas en &lt;code&gt;variables.tf&lt;/code&gt;. Por ejemplo, podemos darle un valor de la variable aws_region (si la tuvieramos definida)&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;    &lt;span class="nx"&gt;aws_region&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;backend.tf&lt;/code&gt;: Este archivo se usa para definir un backend remoto, es decir, el lugar donde se va a almacenar el &lt;code&gt;terraform.tfstate&lt;/code&gt;, pero esto mejor dejémoslo para otro post.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Hasta acá el post de hoy! Espero realmente que te haya gustado.&lt;br&gt;
Todo comentario o sugerencia es mas que bienvenido.&lt;/p&gt;

&lt;p&gt;Te dejo el link al &lt;a href="https://github.com/gareisdev/aws-nginx-server-with-terraform" rel="noopener noreferrer"&gt;repositorio&lt;/a&gt; por si queres dar un vistazo mas general, forkearlo (spanglish++) o revisar mis otros repositorios.&lt;/p&gt;

&lt;p&gt;No te olvides de seguirme en redes (Twitter: LeoGareis)&lt;/p&gt;

&lt;p&gt;Hasta la próxima coder!&lt;/p&gt;

</description>
      <category>infrastructureascode</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>aws</category>
    </item>
    <item>
      <title>Bases de datos: Vistas</title>
      <dc:creator>Leonel Gareis</dc:creator>
      <pubDate>Mon, 24 May 2021 00:46:42 +0000</pubDate>
      <link>https://forem.com/gareisdev/bases-de-datos-vistas-2eo6</link>
      <guid>https://forem.com/gareisdev/bases-de-datos-vistas-2eo6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Photo by &lt;a href="https://www.pexels.com/@luis-gomes-166706" rel="noopener noreferrer"&gt;luis gomes&lt;/a&gt; from &lt;a href="https://www.pexels.com" rel="noopener noreferrer"&gt;Pexels&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En algun momento de nuestras vidas como desarrolladores, nos hemos topado con SQL.&lt;/p&gt;

&lt;p&gt;Hemos hecho consultas agradables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otras mas complejas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y mas complejas aun&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;departments&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;departments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dep_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y en algun momento te habras preguntado: ¿Hay una forma mas sencilla que estar copiando y ejecutando la misma sentencia SQL una y otra vez?&lt;/p&gt;

&lt;p&gt;Bueno, esto ya esta respondido en el titulo 😁&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduccion a Vistas
&lt;/h2&gt;

&lt;p&gt;Las vistas son tablas virtuales creadas a partir de una consulta almacenada.&lt;br&gt;
Este mecanismo de SQL nos permite definir, una unica vez, una consulta (query) y usarla tantas veces como deseemos.&lt;/p&gt;
&lt;h3&gt;
  
  
  Como crear una vista
&lt;/h3&gt;

&lt;p&gt;Esto depende del motor de bases de datos usado.&lt;br&gt;
Yo uso PostgreSQL, pero vos podes usar el que quieras (solo vas a tener que buscar la sintaxis)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;nombre_de_la_vista&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SENTENCIA_sql&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Como usar una vista
&lt;/h3&gt;

&lt;p&gt;Dado que se crea una tabla virtual, podemos consultarla como tal a traves del select.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;nombre_de_la_vista&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Veamos un ejemplo
&lt;/h3&gt;

&lt;p&gt;Mi tabla &lt;code&gt;users&lt;/code&gt; tiene los siguiente campos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;id&lt;/li&gt;
&lt;li&gt;username&lt;/li&gt;
&lt;li&gt;email&lt;/li&gt;
&lt;li&gt;password&lt;/li&gt;
&lt;li&gt;age&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Necesito obtener el &lt;code&gt;username&lt;/code&gt; y el &lt;code&gt;email&lt;/code&gt; de aquellos usuarios cuya edad sea mayor a 18.&lt;/p&gt;

&lt;p&gt;Antes, hubieramos realizado una consulta SQL normal de toda la vida.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pero ahora que sabemos vistas, las cosas se ponen mas interesantes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;users_legal_age&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; 
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users_legal_age&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lo interesante de las vistas es que, dado que son tablas, podemos seguir lanzando distintas consultas sin necesidad de modificar la query original.&lt;/p&gt;

&lt;p&gt;Si yo quisiera en este momento obtener, ademas de los usuarios mayores de edad, aquellos cuyo username contiene la cadena 'admin', solo tendria que hacer esto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users_legal_age&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%admin%'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y nuestra query original se mantiene intacta.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recomendacion para operaciones con mas tablas
&lt;/h3&gt;

&lt;p&gt;Si tenemos la siguiente vista&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;view_posts_users&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
    &lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Debemos de tener cuidado con los campos que tienen el mismo nombre.&lt;/p&gt;

&lt;p&gt;Si &lt;code&gt;users&lt;/code&gt; y &lt;code&gt;posts&lt;/code&gt; tienen campos cuyos nombres son iguales, debemos de asignarle un alias a esos campos para evitar conflictos.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cuando debo usar vistas?
&lt;/h2&gt;

&lt;p&gt;Lo recomendado es que lo uses cuando tenes una query compleja y que requiere ser usada mas de una vez.&lt;/p&gt;

&lt;p&gt;Aca tiene sentido crear una:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;view_admin_users_legal_age&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_name&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%admin%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aca no:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;view_list_users&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Esto solo fue una introduccion, lo demas, lo dejo a tu imaginacion para que sigas practicando y probando 💪&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
