Infraestructura: Uso de Terraform: Nginx en una VPS en AWS EC2, Key Pair, ESB y EIP
Dentro del mundo de los servidores está habiendo una revolución en la automatización del despliegue de servidores. Proyectos como Ansible, Chef o Puppet se han convertido en herramientas fundamentales a la hora de gestionar servidores en masa de una manera eficiente. Pero con la llegada del mundo de la cloud se ha visto necesario automatizar la creación de los servidores y las herramientas que debemos instalar. En esta ocasión cómo crear una máquina en AWS con EC2 con un dispositivo de bloques EBS y una Elastic IP con Terraform.
Recuerda que esta guía es una continuación de la primera parte para instalar y configurar terraform con AWS y DigitalOcean. Ahora iremos viendo los recursos que son necesarios para el despliegue de la VPS en AWS.
Variables
Definir las variables nos permitirá que nuestro código de despliegue sea mucho más reutilizable, ya que cambiando estas variables podremos desplegar distintas máquinas con distintas configuraciones.
Las variables mínimas de funcionamiento que necesitamos para gestionar esta VPS son las siguientes, por ejemplo en el main.tf:
variable "project_name" {}
variable "region_name" {}
variable "availability_zone" {}
variable "vpc_id"{}
-
- Project name: sería como el nombre del proyecto, esto nos va a permitir que los nombres de los distintos recursos que tenemos que crear se relacionen entre sí editando los nombres o etiquetas de cada componente a desplegar.
- Region name: es el nombre de la región donde queremos hacer el despliegue: en nuestro caso será eu-west-3 el data center de París. Es muy importante que revises usar l aregión correcta porque dependiendo de la región puedes disponer de recursos desplegados distintos.
- Availability zone: dentro de las regiones suelen haber distintas zonas normlamente nombradas por a, b, y c. En nuestro ejemplo por simplicidad elegiremos eu-west-3a
- vpc_id: es el identificativo de la red VPC, de nuestra cuenta.Si quieres averiguar su valor simplemente vete a la página de manejo de VPC dentro de AWS y coge el dato del id de la tuya
Provider
Como siempre elegiremos el proveedor que necesitamos, en este caso aws:
provider "aws" {
region = var.region_name
}
Como se puede ver, usamos la variable definida var.region_name para rellenar el provider. Recuerda que puedes definir esta variable en el fichero terraform.tfvars
region_name="eu-west-3"
Al igual que peudes definir todas las variables que necesites.
Key Pair
Los pares de claves permiten la gestión de claves ssh para el acceso a las máquinas vps. En AWS es otro recurso que podemos añadir con Terraform. veamos un ejemplo:
variable "ssh_key" {}
resource “aws_key_pair” “deployer” {
key_name = “${var.project_name}-deployer-key”
public_key = var.ssh_key
}
Como puede verse se define el recurso mediante una variable que debe contener la clave SSH y que se asocia con el parámetro public key. Además modificamos el nombre de la clave, teniendo en cuenta el nombre del proyecto definido como variable. Es una buena práctica que todos los recursos definidos en el despliegue tengan algún tipo de referencia al proyecto o aplicación que queremos desplegar. Para que los usuarios de aws puedan localizar fácilmente los recursos desde la consola de AWS.
Veamos un ejemplo de definición de la clave como variable:
ssh_key="ssh-rsa AAAAB3BLABLABLABLAESTACADENAESSUPERLARGAQUELOSEPAS9Tw== correo@ejemplo.com"
Si no sabes generar estas claves, mira esta guía para ubuntu.
EBS, dispositivos de bloques
Aunque el sistema operativo no suele ocupar mucho espacio en disco, a no ser que uses windows claro, normalmente es una buena práctica, que los datos de las aplicaciones que necesitamos desplegar en las VPS’s, vayan alojados en una unidad de disco distinta del sistema, de esta manera si el disco del servidor se destruye, o si destruimos la máquina y la volvemos a crear, así no se perderían los datos que ya tuviésemos en ese dispositivo de bloques. Veamos ahora cómo definimos el recurso.
resource "aws_ebs_volume" "web" {
availability_zone = var.availability_zone
size = 4
tags = {
Name = "${var.project_name}-web-ebs"
}
}
En este caso estamos definiendo un volumen de 4GB de capacidad y como puede verse se ha de elegir el nombre de la zona donde se puede desplegar, eu-west-3a en este ejemplo, y el tag con el nombre del recurso teniendo en cuenta el nombre del proyecto.
Security Groups
Los segurity group son reglas de firewall para la red donde nos encontremos, que luego podremos aplicar a nuestras VPS de EC2. Vemos un ejemplo para aplicar acceso ssh y http:
resource "aws_security_group" "allow_ssh" {
name = "allow_ssh"
description = "Allow SSH inbound traffic"
vpc_id = var.vpc_id
ingress {
description = “SSH from VPC”
from_port = 22
to_port = 22
protocol = “tcp”
cidr_blocks = [“0.0.0.0/0”]
}
egress {
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“0.0.0.0/0”]
}
tags = {
Name = “allow_ssh”
}
}
resource “aws_security_group” “allow_http” {
name = “allow_http”
description = “Allow http inbound traffic”
vpc_id = var.vpc_id
ingress {
description = “http from VPC”
from_port = 80
to_port = 80
protocol = “tcp”
cidr_blocks = [“0.0.0.0/0”]
}
egress {
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“0.0.0.0/0”]
}
tags = {
Name = “allow_http”
}
}
En este caso estamos definiendo una regla que permite el tráfico al puerto SSH (22) y el HTTP (80) desde cualquier parte del mundo. para que podamos conectarnos a nivel de red con la VPS desde donde queramos. Luego deberemos asociar esto a la VPS.
EIP, Elastic IP
Una cosa curiosa en AWS con las VPS de EC2 es que la ip pública que genera para acceder a la VPS desde internet cambia cada vez que reinicias la máquina, para resolver este problema, AWS tiene las Elastic IP, que se pueden asociar a una máquina y nos da un IP que no va a cambiar independientemente de las veces que reiniciemos la máquina. Veamos cómo definirla:
resource "aws_eip" "eip" {
instance = aws_instance.web.id
vpc = true
tags = {
Name = "${var.project_name}-web-epi"
}
}
Después para acceder a este valor necesitaremos saber cual es esa IP que nos han asignado a la VPS. Para ello generaremos un Output de Terraform:
output "eip_ip" {
description = "The eip ip for ssh access"
value = aws_eip.eip.public_ip
}
User Data
user_data en un parámetro de la creación de una instancia que permite la ejecución de código mediante un script, veamos el ejemplo del fichero userdata.sh:
#!/usr/bin/env bash
set -x
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
export PATH="$PATH:/usr/bin"
sudo apt-get update
sudo apt-get -y install nginx
sudo mkfs -t xfs /dev/nvme1n1
sudo mkdir /mnt/demo_web_volume
sudo mount /dev/nvme1n1 /mnt/demo_web_volume
sudo rm -rf /var/www/html
sudo mkdir /mnt/demo_web_volume/html
sudo ln -s /mnt/demo_web_volume/html /var/www/html
sudo echo "
Hola Terraform
" >> /var/www/html/index.html
sudo chown -R www-data:www-data /var/www/html/index.html
sudo chmod -R 755 /var/www/html/index.html
Si queremos ejecutar este script debemos crear una plantilla que cargue este script:
data "template_file" "userdata" {
template = "${file("${path.module}/userdata.sh")}"
}
Desde la definición del recurso de la instancia le diremos que use esta plantilla para ejecutarla.
Instancia EC2
Ahora ya podemos definir la VPS en EC2.
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
availability_zone = var.availability_zone
instance_type = var.instance_type
vpc_security_group_ids = [
aws_security_group.allow_ssh.id,
aws_security_group.allow_http.id
]
user_data = "${data.template_file.userdata.rendered}"
key_name = aws_key_pair.deployer.key_name
tags = {
Name = "${var.project_name}-web-instance"
}
}
En este recurso estamos asociando casi todos lo demás, además de definir el tipo de instancia, esta vez por variable. El ami tal como definimos anteriormente, buscaremos la última imagen de ubuntu 20.04, necesitamos también definir la zona disponible, asociarle el key pair, los security groups como array, el user_data a ejecutar en el arranque y el nombre como tag de la VPS asociado al nombre del proyecto.
Volume Attachment
En este caso es cómo asociamos el volumen a la VPS a través de un nombre de dispositivo /dev/sdh en este caso. Aunque luego lo veremos con el nombre /dev/nvmen1, tal como definimos en el script userdata.sh
resource "aws_volume_attachment" "web" {
device_name = "/dev/sdh"
volume_id = aws_ebs_volume.web.id
instance_id = aws_instance.web.id
}
Ouputs/Salidas
En este caso definiremos las variables necesarias para interactuar con la máquina:
output "ssh" {
value = "ssh -l ubuntu ${aws_eip.eip.public_ip}"
}
output "url" {
value = "http://${aws_eip.eip.public_ip}/"
}
Despliegue
Ahora ya sólo nos faltaría hacer los pasos de siempre:
- $ terraform validate
- $ terraform plan
- $ terraform apply
- y para borrar la infraestrcutura $ terraform destroy
Comments