├── .gitignore ├── README.md ├── main.tf ├── modules ├── frontend-server │ ├── main.tf │ └── outputs.tf └── networking │ ├── main.tf │ └── output.tf ├── outputs.tf ├── playbooks ├── create-react-app.sh ├── dependencies.yaml └── nginx-template ├── secrets └── .gitignore ├── terraform.tfvars.example └── vars.tf /.gitignore: -------------------------------------------------------------------------------- 1 | course/ 2 | 3 | terraform.tfvars 4 | 5 | terraform.tfstate* 6 | 7 | .terraform* 8 | 9 | .terraform/ 10 | 11 | id_rsa* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # conociendo-iac-con-terraform 2 | Repositorio utilizado para Charla denominada "Infraestructura como código con Terraform". 3 | 4 | ## Terraform version 5 | 6 | Este proyecto fue realizado en Terraform version 7 | 8 | ```` 9 | Terraform v0.12.18 10 | + provider.digitalocean v1.22.2 11 | + provider.null v2.1.2 12 | + provider.template v2.1.2 13 | ```` 14 | 15 | ## Instalación de Terraform 16 | 17 | Recomiendo mucho instalar Terraform a través de "tfenv" debido que nos permite gestionar las versiones de Terraform y es usable en MacOS, Unix based systems y Windows (Git-bash) 18 | 19 | [Click para acceder al repositorio](https://github.com/tfutils/tfenv) 20 | 21 | ## Cumple los requisitos para correr la demo 22 | 23 | Requisitos: 24 | 25 | - Cuenta en Digitalocean [registrate aquí.](m.do.co/c/e3c4799e0fa4) 26 | - Crear un Personal Access Token [documentación aquí](www.digitalocean.com/docs/apis-clis/api/create-personal-access-token/) 27 | 28 | ## Clona el repositorio 29 | 30 | Clona el repositorio en tu local 31 | 32 | ```` 33 | git clone https://github.com/ShankyJS/iac-con-terraform 34 | ```` 35 | 36 | ## Preparandonos para correr el proyecto 37 | 38 | Entra a la carpeta "secrets" y genera una llave ssh y dejala con el nombre por defecto (id_rsa) 39 | 40 | ```` 41 | cd secrets 42 | ssh-keygen -t rsa -b 4096 -C "demo@shanky-demos.com" -f $PWD/id_rsa 43 | ```` 44 | 45 | Deberias de tener los siguientes archivos en tu carpeta secrets: 46 | 47 | ```` 48 | 2020-08-29 17:04:10 ⌚ shanky in ~/Documents/OS/Speaking/iac-con-terraform/secrets 49 | → ls 50 | id_rsa id_rsa.pub 51 | ```` 52 | 53 | ### Crea tu archivo de variables y llenalo. 54 | 55 | Copia la plantilla de variables en un nuevo archivo y llenalas con los valores especificos que utilizarás. 56 | 57 | ```` 58 | cp terraform.tfvars.example terraform.tfvars 59 | ```` 60 | 61 | Modifica el archivo ``terraform.tfvars`` y reemplaza las "XXXXX" por los valores de tus variables. 62 | 63 | ### Inicializa, crea y destruye 64 | 65 | Inicializa el proyecto, esto hará que Terraform descargue los módulos y providers necesarios. 66 | 67 | (Corre estos comandos desde el root del repositorio) 68 | 69 | ```` 70 | terraform init 71 | ```` 72 | 73 | Luego de inicializar el proyecto puedes planearlo para ver que recursos serán creados. 74 | 75 | ```` 76 | terraform plan 77 | ```` 78 | 79 | Si estás de acuerdo con los recursos que serán creados puedes aplicar estos cambios. 80 | 81 | ```` 82 | terraform apply --auto-approve 83 | ```` 84 | 85 | Una vez que termines de probar el proyecto puedes destruirlo. 86 | 87 | ```` 88 | terraform destroy --auto-approve 89 | ```` -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | provider "digitalocean" { 2 | token = var.digitalocean_token 3 | } 4 | #convencion de digital ocean #Nombre personalizado por el user 5 | resource "digitalocean_ssh_key" "ssh_key_frontend" { 6 | name = var.nombre_llave_ssh 7 | public_key = file("./secrets/id_rsa.pub") 8 | } 9 | 10 | module "frontend-server" { 11 | source = "./modules/frontend-server" 12 | vm_size = var.vm_size[5] 13 | llave_ssh_fingerprint = digitalocean_ssh_key.ssh_key_frontend.fingerprint 14 | } 15 | 16 | module "networking" { 17 | source = "./modules/networking" 18 | domain_name = "${var.domain_name}" 19 | record_name = "${var.record_name}" 20 | frontend-server_ipv4 = "${module.frontend-server.frontend-server_ipv4}" 21 | } 22 | 23 | -------------------------------------------------------------------------------- /modules/frontend-server/main.tf: -------------------------------------------------------------------------------- 1 | 2 | variable "vm_size" { 3 | 4 | } 5 | 6 | variable "llave_ssh_fingerprint" { 7 | 8 | } 9 | # Creacion de una maquina virtual 10 | resource "digitalocean_droplet" "frontend-server" { 11 | image = "ubuntu-18-04-x64" 12 | name = "frontend-server" 13 | region = "sfo2" 14 | size = var.vm_size 15 | ssh_keys = [var.llave_ssh_fingerprint] 16 | 17 | connection { 18 | type = "ssh" 19 | host = digitalocean_droplet.frontend-server.ipv4_address 20 | user = "root" 21 | private_key = file("./secrets/id_rsa") 22 | } 23 | 24 | provisioner "file" { 25 | source = "./playbooks/dependencies.yaml" 26 | destination = "/root/dependencies.yaml" 27 | } 28 | 29 | provisioner "file" { 30 | source = "./playbooks/create-react-app.sh" 31 | destination = "/root/create-react-app.sh" 32 | } 33 | 34 | } 35 | 36 | resource "null_resource" "initial_config" { 37 | depends_on = [digitalocean_droplet.frontend-server] 38 | 39 | connection { 40 | type = "ssh" 41 | host = digitalocean_droplet.frontend-server.ipv4_address 42 | user = "root" 43 | private_key = file("./secrets/id_rsa") 44 | } 45 | 46 | provisioner "remote-exec" { 47 | inline = [ 48 | # Run the operations script. 49 | "sudo apt-get update", 50 | "sudo apt-get -y install ansible", 51 | "ansible-playbook dependencies.yaml" 52 | ] 53 | } 54 | } 55 | 56 | resource "null_resource" "react_project_creation" { 57 | depends_on = [null_resource.initial_config] 58 | connection { 59 | type = "ssh" 60 | host = digitalocean_droplet.frontend-server.ipv4_address 61 | user = "root" 62 | private_key = file("./secrets/id_rsa") 63 | } 64 | 65 | provisioner "remote-exec" { 66 | inline = [ 67 | # Run the React script. 68 | ". ./create-react-app.sh", 69 | "cp /root/react_frontend.com /etc/nginx/sites-available/react_frontend.com", 70 | "ln -s /etc/nginx/sites-available/react_frontend.com /etc/nginx/sites-enabled/react_frontend.com", 71 | "sudo systemctl restart nginx" 72 | ] 73 | } 74 | } -------------------------------------------------------------------------------- /modules/frontend-server/outputs.tf: -------------------------------------------------------------------------------- 1 | # Using this output as a variable 2 | output "frontend-server_ipv4" { 3 | value = digitalocean_droplet.frontend-server.ipv4_address 4 | } -------------------------------------------------------------------------------- /modules/networking/main.tf: -------------------------------------------------------------------------------- 1 | variable "domain_name" { 2 | 3 | } 4 | 5 | variable "record_name" { 6 | 7 | } 8 | 9 | variable "frontend-server_ipv4" { 10 | 11 | } 12 | 13 | # Adding a Record to use it with the Rancher 14 | resource "digitalocean_record" "frontend_domain" { 15 | domain = var.domain_name 16 | name = var.record_name 17 | value = var.frontend-server_ipv4 18 | type = "A" 19 | ttl = "30" 20 | } 21 | 22 | resource "template_file" "nginx_frontend" { 23 | depends_on = ["digitalocean_record.frontend_domain"] 24 | template = "${file("./playbooks/nginx-template")}" 25 | vars = { 26 | frontend_domain = digitalocean_record.frontend_domain.fqdn 27 | } 28 | } 29 | 30 | resource "null_resource" "adding_template" { 31 | connection { 32 | type = "ssh" 33 | host = digitalocean_record.frontend_domain.fqdn 34 | user = "root" 35 | private_key = file("./secrets/id_rsa") 36 | } 37 | 38 | provisioner "file" { 39 | content = "${template_file.nginx_frontend.rendered}" 40 | destination = "/root/react_frontend.com" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /modules/networking/output.tf: -------------------------------------------------------------------------------- 1 | output "frontend_domain" { 2 | value = "${digitalocean_record.frontend_domain.fqdn}" 3 | } 4 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "frontend-server_ipv4" { 2 | value = "${module.frontend-server.frontend-server_ipv4}" 3 | } 4 | 5 | output "frontend_domain" { 6 | value = "${module.networking.frontend_domain}" 7 | } -------------------------------------------------------------------------------- /playbooks/create-react-app.sh: -------------------------------------------------------------------------------- 1 | # Install Pm2 2 | npm install pm2 -g 3 | # Generating React Project 4 | npx create-react-app my-app 5 | # Start project with pm2 6 | cd my-app 7 | pm2 start npm -- start -------------------------------------------------------------------------------- /playbooks/dependencies.yaml: -------------------------------------------------------------------------------- 1 | - hosts: 127.0.0.1 2 | connection: local 3 | become: 'yes' 4 | tasks: 5 | - name: Install NGINX 6 | apt: 7 | name: nginx 8 | state: present 9 | update_cache: true 10 | - name: install node 11 | shell: | 12 | curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - && sudo apt-get install -y nodejs 13 | 14 | -------------------------------------------------------------------------------- /playbooks/nginx-template: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name ${frontend_domain}; 4 | 5 | location / { 6 | proxy_pass http://localhost:3000; 7 | proxy_http_version 1.1; 8 | proxy_set_header Upgrade $http_upgrade; 9 | proxy_set_header Connection 'upgrade'; 10 | proxy_set_header Host $host; 11 | proxy_cache_bypass $http_upgrade; 12 | } 13 | } -------------------------------------------------------------------------------- /secrets/.gitignore: -------------------------------------------------------------------------------- 1 | id_rsa* -------------------------------------------------------------------------------- /terraform.tfvars.example: -------------------------------------------------------------------------------- 1 | # Token de Digitalocean 2 | digitalocean_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 3 | # Nombre asignado a llave SSH en Digitalocean 4 | nombre_llave_ssh = "XXXXXXXXXXXXXXXXXXX" 5 | # Dominio importado en digitalocean por ejemplo: shankyjs.me 6 | domain_name = "XXXXXXXXXXXXXXXXXXXX" 7 | # Registro tipo A (subdominio) 8 | record_name = "XXXXXXXXXXXXXXXXXXXX" -------------------------------------------------------------------------------- /vars.tf: -------------------------------------------------------------------------------- 1 | # Input variable 2 | variable "digitalocean_token" { 3 | description = "Token privado para interactuar con la API de Digitalocean" 4 | type = string 5 | } 6 | # Input variable 7 | variable "domain_name" { 8 | description = "Nombre del dominio previamente registrado en Digitalocean" 9 | type = string 10 | } 11 | # Input variable 12 | variable "record_name" { 13 | description = "Nombre del registro que vamos a crear en el dominio" 14 | type = string 15 | } 16 | # Input variable 17 | variable "nombre_llave_ssh" { 18 | description = "Nombre de la llave SSH que registraremos en Digitalocean" 19 | type = string 20 | } 21 | # Extra variables 22 | variable "llave_ssh_fingerprint" { 23 | description = "En esta variable almacenaremos el fingerprint de la llave SSH." 24 | default = "arreeeeeeeeeeeee" 25 | type = string 26 | } 27 | 28 | variable "vm_size" { 29 | type = map(string) 30 | description = "(optional) describe your variable" 31 | default = { 32 | 0 = "s-1vcpu-1gb" 33 | 1 = "s-1vcpu-2gb" 34 | 2 = "s-1vcpu-3gb" 35 | 3 = "s-2vcpu-2gb" 36 | 4 = "s-2vcpu-4gb" 37 | 5 = "s-4vcpu-8gb" 38 | } 39 | } 40 | 41 | 42 | # Number, Bool, string --------------------------------------------------------------------------------