├── terraform-labs ├── aws-dynamodb-items │ ├── main.tf │ ├── outputs.tf │ ├── provider.tf │ └── variables.tf ├── localstack-s3-ecommerce │ ├── main.tf │ ├── outputs.tf │ ├── provider.tf │ └── variables.tf ├── docker-terraform-helloworld │ ├── main.tf │ ├── outputs.tf │ └── variables.tf └── .DS_Store ├── ejemplos ├── 03-aws-s3-localstack │ ├── terraform.tfvars │ ├── output.tf │ ├── main.tf │ ├── variables.tf │ └── provider.tf ├── 04-docker-nginx-html │ ├── output.tf │ ├── main.tf │ └── index.html ├── 02-local-condicionales │ └── main.tf └── 01-local-simple │ └── main.tf └── README.md /terraform-labs/aws-dynamodb-items/main.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/aws-dynamodb-items/outputs.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/aws-dynamodb-items/provider.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/aws-dynamodb-items/variables.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/localstack-s3-ecommerce/main.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/docker-terraform-helloworld/main.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/localstack-s3-ecommerce/outputs.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/localstack-s3-ecommerce/provider.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/localstack-s3-ecommerce/variables.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/docker-terraform-helloworld/outputs.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /terraform-labs/docker-terraform-helloworld/variables.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /ejemplos/03-aws-s3-localstack/terraform.tfvars: -------------------------------------------------------------------------------- 1 | bucket_name = "demo.s3.workshop" 2 | environment = "dev" -------------------------------------------------------------------------------- /ejemplos/03-aws-s3-localstack/output.tf: -------------------------------------------------------------------------------- 1 | output "idbucket" { 2 | value = aws_s3_bucket.example.arn 3 | } -------------------------------------------------------------------------------- /terraform-labs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roxsross/workshop-tfroxs/HEAD/terraform-labs/.DS_Store -------------------------------------------------------------------------------- /ejemplos/04-docker-nginx-html/output.tf: -------------------------------------------------------------------------------- 1 | output "nginx_access_url" { 2 | value = "http://localhost:8080" 3 | description = "URL para acceder al servidor Nginx" 4 | } -------------------------------------------------------------------------------- /ejemplos/03-aws-s3-localstack/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "example" { 2 | bucket = var.bucket_name 3 | 4 | tags = { 5 | Name = var.bucket_name 6 | Environment = var.environment 7 | } 8 | } -------------------------------------------------------------------------------- /ejemplos/03-aws-s3-localstack/variables.tf: -------------------------------------------------------------------------------- 1 | variable "bucket_name" { 2 | description = "The name of the S3 bucket" 3 | type = string 4 | } 5 | 6 | variable "environment" { 7 | description = "The environment for the S3 bucket" 8 | type = string 9 | } 10 | 11 | variable "environment" { 12 | description = "The environment for the S3 bucket" 13 | type = string 14 | } -------------------------------------------------------------------------------- /ejemplos/03-aws-s3-localstack/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "5.97.0" 6 | } 7 | } 8 | } 9 | 10 | provider "aws" { 11 | region = "us-east-1" 12 | access_key = "fake" 13 | secret_key = "fake" 14 | ######solo para localstack 15 | s3_use_path_style = true 16 | skip_credentials_validation = true 17 | skip_metadata_api_check = true 18 | skip_requesting_account_id = true 19 | 20 | endpoints { 21 | s3 = "http://localhost:4566" 22 | } 23 | } -------------------------------------------------------------------------------- /ejemplos/02-local-condicionales/main.tf: -------------------------------------------------------------------------------- 1 | provider "local" { 2 | # Configuration options 3 | } 4 | 5 | variable "files" { 6 | type = map(object({ 7 | content = string 8 | create = bool 9 | })) 10 | default = { 11 | "config1" = { 12 | content = "contenido 1" 13 | create = true 14 | } 15 | "config2" = { 16 | content = "contenido 2" 17 | create = true 18 | } 19 | "config3" = { 20 | content = "contenido 3" 21 | create = true 22 | } 23 | } 24 | } 25 | 26 | resource "local_file" "configs" { 27 | for_each = { 28 | for name, file in var.files : 29 | name => file 30 | if file.create == true 31 | } 32 | 33 | content = each.value.content 34 | filename = "${each.key}.txt" 35 | } -------------------------------------------------------------------------------- /ejemplos/04-docker-nginx-html/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | docker = { 4 | source = "kreuzwerker/docker" 5 | version = "~> 3.0.2" 6 | } 7 | local = { 8 | source = "hashicorp/local" 9 | version = "~> 2.4.0" 10 | } 11 | } 12 | required_version = ">= 1.0.0" 13 | } 14 | 15 | provider "docker" {} 16 | provider "local" {} 17 | 18 | data "local_file" "index_html" { 19 | filename = "${path.module}/index.html" 20 | } 21 | 22 | resource "docker_container" "nginx" { 23 | name = "nginx-terraform" 24 | image = "nginx:alpine" 25 | 26 | ports { 27 | internal = 80 28 | external = 8080 29 | } 30 | 31 | upload { 32 | file = "/usr/share/nginx/html/index.html" 33 | content = data.local_file.index_html.content 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /ejemplos/01-local-simple/main.tf: -------------------------------------------------------------------------------- 1 | provider "local" { 2 | # Configuración del proveedor local 3 | } 4 | 5 | provider "random" { 6 | # Configuración del proveedor random 7 | } 8 | 9 | variable "contenido" { 10 | type = string 11 | default = "Hola Mundo2" 12 | } 13 | 14 | resource "random_string" "random" { 15 | length = 4 16 | special = false 17 | numeric = true 18 | upper = false 19 | } 20 | 21 | resource "local_file" "demo1" { 22 | content = var.contenido 23 | filename = "product-${random_string.random.id}.txt" 24 | } 25 | 26 | resource "local_file" "demo2" { 27 | content = var.contenido 28 | filename = "product2-${random_string.random.id}.txt" 29 | } 30 | 31 | output "nombre_archivo_demo2" { 32 | value = local_file.demo2.filename 33 | } 34 | 35 | output "nombre_archivo_demo1" { 36 | value = local_file.demo1.filename 37 | } 38 | -------------------------------------------------------------------------------- /ejemplos/04-docker-nginx-html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hola Mundo Terraform by Roxs 7 | 136 | 137 | 138 |
139 | 140 |
141 | 144 | 145 |

¡Hola Mundo!

146 |
Desplegado con Terraform
147 | 148 |
149 |

Esta página fue creada y desplegada usando Terraform, una herramienta de infraestructura como código que permite crear, cambiar y versionar infraestructura de forma segura y eficiente.

150 |
151 | 152 |
153 | Documentación 154 | Explorar Más 155 |
156 | 157 |
By Roxs
158 |
159 | 160 | 189 | 190 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # workshop-tfroxs 2 | ### by RoxsRoss 3 | 4 | ![JavaScript](https://img.shields.io/badge/-JavaScript-F7DF1E?style=for-the-badge&logo=JavaScript&logoColor=black) 5 | ![Node.js](https://img.shields.io/badge/-Node.js-339933?style=for-the-badge&logo=node.js&logoColor=white) 6 | ![HTML5](https://img.shields.io/badge/-HTML5-E34F26?style=for-the-badge&logo=html5&logoColor=white) 7 | ![Terraform](https://img.shields.io/badge/terraform-7B42BC?logo=terraform&logoColor=white&style=for-the-badge) 8 | ![VSCode](https://img.shields.io/badge/Visual_Studio_Code-0078D4?style=for-the-badge&logo=visual%20studio%20code&logoColor=white) 9 | ![Kubernetes](https://img.shields.io/badge/kubernetes-326CE5?logo=kubernetes&logoColor=white&style=for-the-badge) 10 | ![Azure](https://img.shields.io/badge/azure-0078D4?logo=microsoft-azure&logoColor=white&style=for-the-badge) 11 | ![AWS](https://img.shields.io/badge/Amazon_AWS-232F3E?style=for-the-badge&logo=amazon-aws&logoColor=white) 12 | ![GCP](https://img.shields.io/badge/Google_Cloud-4285F4?style=for-the-badge&logo=google-cloud&logoColor=white) 13 | ![Docker](https://img.shields.io/badge/docker-2496ED?logo=docker&logoColor=white&style=for-the-badge) 14 | ![Python](https://img.shields.io/badge/python-3776AB?logo=python&logoColor=white&style=for-the-badge) 15 | ![Golang](https://img.shields.io/badge/Go-00ADD8?style=for-the-badge&logo=go&logoColor=white) 16 | ![GitHub Actions](https://img.shields.io/badge/GitHub_Actions-2088FF?style=for-the-badge&logo=github-actions&logoColor=white) 17 | ![GitLab](https://img.shields.io/badge/GitLab-330F63?style=for-the-badge&logo=gitlab&logoColor=white) 18 | ![Jenkins](https://img.shields.io/badge/Jenkins-D24939?style=for-the-badge&logo=Jenkins&logoColor=white) 19 | ![TeamCity](https://img.shields.io/badge/TeamCity-000000?style=for-the-badge&logo=TeamCity&logoColor=white) 20 | 21 | --- 22 | 23 | # 🌱 **Primer Set de Desafíos Prácticos con Terraform** 24 | 25 | Este conjunto de actividades está diseñado para introducirte al mundo de la **Infraestructura como Código (IaC)** de una manera práctica, simple y con resultados visibles desde el primer día. ¡Aquí comienza tu camino como DevOps! 26 | 27 | --- 28 | 29 | ## 🎯 **¿Qué vas a lograr?** 30 | 31 | - **Dominar Terraform** para automatizar tareas comunes de infraestructura en la nube. 32 | - **Desplegar aplicaciones en contenedores** utilizando Docker y Terraform. 33 | - **Simular servicios de AWS** como **S3** y **DynamoDB** de manera local con **LocalStack**. 34 | - **Adoptar buenas prácticas** de estructura de archivos, modularización y reutilización de código. 35 | 36 | --- 37 | 38 | ## 💡 **Motivación** 39 | 40 | Terraform no es solo una herramienta, es una **mentalidad de organización y escalabilidad**. Con este set de desafíos, aprenderás a escribir y gestionar infraestructura como si fuera código de aplicación. No solo verás resultados desde el primer commit, sino que también te prepararás para asumir roles clave en proyectos DevOps. ¡Comencemos a crear y automatizar como verdaderos DevOps! 41 | 42 | --- 43 | 44 | # 🛠 **Desafíos Terraform Nivel 100** 45 | 46 | A continuación, encontrarás tres desafíos prácticos que te ayudarán a iniciarte en el mundo de Terraform utilizando Docker, LocalStack y AWS DynamoDB. 47 | 48 | --- 49 | 50 | ## 🚀 **Docker Terraform Helloworld** 51 | **Ruta**: `./terraform-labs/docker-terraform-helloworld` 52 | 53 | ### **Objetivo**: 54 | Automatizar la construcción y ejecución de un contenedor Docker con una aplicación Node.js real utilizando Terraform. 55 | 56 | ### **Stack**: 57 | Terraform + Docker 58 | 59 | **Repositorio base**: [helloworld-demo-node](https://github.com/dockersamples/helloworld-demo-node) 60 | 61 | ### **Pasos**: 62 | 1. Clonar el repositorio `helloworld-demo-node`. 63 | 2. Usar el proveedor `kreuzwerker/docker` en Terraform. 64 | 3. Crear un recurso `docker_image` desde el Dockerfile clonado. 65 | 4. Crear un recurso `docker_container` que exponga el puerto 80 al 8080. 66 | 5. Definir variables para la imagen, el contenedor y los puertos. 67 | 6. Mostrar los outputs: URL del contenedor y estado de ejecución. 68 | 69 | ### **Estructura sugerida**: 70 | ```bash 71 | docker-terraform-helloworld/ 72 | ├── main.tf 73 | ├── variables.tf 74 | ├── outputs.tf 75 | └── helloworld-demo-node/ # Clonado desde GitHub 76 | ``` 77 | 78 | ### **Validación**: 79 | Accede a [http://localhost:8080](http://localhost:8080) y verifica que se muestre: 80 | ``` 81 | Hello from Docker! 82 | ``` 83 | 84 | --- 85 | 86 | ## 🏬 **Localstack S3 Ecommerce** 87 | **Ruta**: `./terraform-labs/localstack-s3-ecommerce` 88 | 89 | ### **Objetivo**: 90 | Simular el hosting de una página web estática de e-commerce en **S3** utilizando **LocalStack** y **Terraform**. 91 | 92 | ### **Stack**: 93 | Terraform + LocalStack + S3 94 | 95 | **Plantilla base**: [Start Bootstrap E-commerce Template](https://startbootstrap.com/templates/ecommerce) 96 | 97 | ### **Pasos**: 98 | 1. Descargar la plantilla de e-commerce y colocarla en `web/`. 99 | 2. Configurar el proveedor de AWS apuntando a **LocalStack** (`localhost:4566`). 100 | 3. Crear un bucket de S3 con configuración de sitio web. 101 | 4. Subir los archivos HTML/CSS/JS utilizando `aws_s3_bucket_object` y `for_each`. 102 | 5. Usar `mime_types` en `variables.tf` para especificar los tipos de archivo. 103 | 6. Mostrar la URL del sitio web con el output correspondiente. 104 | 105 | ### **Estructura sugerida**: 106 | ```bash 107 | localstack-s3-ecommerce/ 108 | ├── main.tf 109 | ├── provider.tf 110 | ├── variables.tf 111 | ├── outputs.tf 112 | └── web/ 113 | ├── index.html 114 | ├── css/ 115 | ├── js/ 116 | └── ...otros assets 117 | ``` 118 | 119 | ### **Validación**: 120 | Abre en tu navegador: 121 | ``` 122 | http://localhost:4566/ecommerce-site/index.html 123 | ``` 124 | 125 | --- 126 | 127 | ## 📝 **AWS DynamoDB Items** 128 | **Ruta**: `./terraform-labs/aws-dynamodb-items` 129 | 130 | ### **Objetivo**: 131 | Crear una tabla en **DynamoDB** y precargarla con datos (ítems) utilizando **Terraform**. 132 | 133 | ### **Stack**: 134 | Terraform + AWS DynamoDB 135 | 136 | ### **Pasos**: 137 | 1. Configurar el proveedor de AWS (puedes usar claves o un perfil). 138 | 2. Crear una tabla `aws_dynamodb_table` con una **hash key** `id` y modo **PAY_PER_REQUEST**. 139 | 3. Declarar los ítems como un `jsonencode()` en un local variable. 140 | 4. Crear los ítems utilizando `aws_dynamodb_table_item` y `for_each`. 141 | 5. Mostrar los outputs: nombre de la tabla y su ARN. 142 | 143 | ### **Estructura sugerida**: 144 | ```bash 145 | aws-dynamodb-items/ 146 | ├── main.tf 147 | ├── provider.tf 148 | ├── variables.tf 149 | ├── outputs.tf 150 | ``` 151 | 152 | ### **Validación**: 153 | Entra en la consola de AWS y ve a: 154 | ``` 155 | Consola > DynamoDB > Items 156 | ``` 157 | 158 | Deberías ver algo como esto: 159 | ```json 160 | { "id": "001", "name": "Ada", "score": 95 } 161 | { "id": "002", "name": "Linus", "score": 89 } 162 | ``` 163 | 164 | --- 165 | 166 | ¡Disfruta de estos desafíos y empieza a crear tu infraestructura como código con Terraform! 167 | 168 | 169 | 170 | 171 | > _"DevOps es el arte de la colaboración y la automatización, donde la innovación y la confiabilidad se unen para crear un camino continuo hacia el éxito."_ 172 | 173 | 🔥🔥🔥🔥 174 | 175 | 176 | 177 | ## Contactos 178 | 179 | Me puedes encontrar en las siguientes plataformas: 180 | 181 | - [Hashnode](https://blog.295devops.com) 182 | - [Dev.to](https://dev.to/roxsross) 183 | - [Twitter](https://twitter.com/roxsross) 184 | - [LinkedIn](https://www.linkedin.com/in/roxsross/) 185 | - [Instagram](https://www.instagram.com/roxsross/) 186 | - [YouTube](https://www.youtube.com/channel/UCa-FcaB75ZtqWd1YCWW6INQ) 187 | --------------------------------------------------------------------------------