Cómo instalar Terraform y aprovisionar la instancia en la nube AWS EC2
Las primitivas de terraform utilizadas para definir la infraestructura como código (IaaC). Puede construir, cambiar y versionar su infraestructura en AWS, Digital Ocean, Google Cloud, Heroku, Microsoft Azure, etc. usando la misma herramienta. Describa los componentes de su aplicación única o del centro de datos completo utilizando terraform. En este tutorial, crearemos una infraestructura utilizando terraform y aprovisionaremos la instancia AWS EC2.
1. Instale Terraform
Descargar terraform dependiendo de su sistema. La instalación es muy sencilla. Descargue el archivo zip terraform y descomprímalo en una ubicación adecuada. Una vez que hayamos descomprimido terraform, actualizaremos la variable de entorno PATH apuntando a terraform. Dado que la carpeta / usr / local / bin ya está configurada en la variable de entorno PATH, no es necesario volver a configurarla. Si está utilizando cualquier otra ubicación, especifíquela en la variable de entorno PATH en .bash_profile o en / etc / profile.
[thegeek@mysandbox ~]$ cd /usr/local/src [root@mysandbox src]# wget https://releases.hashicorp.com/terraform/0.8.5/terraform_0.8.5_linux_386.zip [root@mysandbox src]# unzip terraform_0.8.5_linux_386.zip [root@mysandbox src]# mv terraform /usr/local/bin/
Ahora agregue la siguiente línea para agregar terraform en la ubicación PATH.
export PATH=$PATH:/terraform-path/
Verifique la instalación de terraform con el siguiente comando
[root@mysandbox src]# terraform Usage: terraform [--version] [--help] <command> [args] The available commands for execution are listed below. The most common, useful commands are shown first, followed by less common or more advanced commands. If you're just getting started with Terraform, stick with the common commands. For the other commands, please read the help and docs before usage. Common commands: apply Builds or changes infrastructure console Interactive console for Terraform interpolations destroy Destroy Terraform-managed infrastructure fmt Rewrites config files to canonical format get Download and install modules for the configuration graph Create a visual graph of Terraform resources import Import existing infrastructure into Terraform init Initializes Terraform configuration from a module output Read an output from a state file plan Generate and show an execution plan push Upload this Terraform module to Atlas to run refresh Update local state file against real resources remote Configure remote state storage show Inspect Terraform state or plan taint Manually mark a resource for recreation untaint Manually unmark a resource as tainted validate Validates the Terraform files version Prints the Terraform version All other commands: debug Debug output management (experimental) state Advanced state management
2. Cree un usuario de EC2
Cuando crea una cuenta en AWS por primera vez, se le proporciona un inicio de sesión de root que accede a todos los servicios / funciones en AWS. Para conocer las mejores prácticas de seguridad de AWS, utilice una cuenta raíz y cree cuentas de usuario con acceso limitado a los servicios de AWS. Dado que crearemos una infraestructura en AWS utilizando la API de terraform que interactuará con los servicios EC2, crearemos un usuario con acceso a todos los servicios EC2 únicamente.
Inicie sesión en AWS consola usando la cuenta root. Seleccione servicios-> AZ-> IAM
Haga clic en Usuarios en el panel de IAM.
Haga clic en «Agregar usuario»
Proporcione un nombre de usuario y haga clic solo en «Acceso programático». Hemos proporcionado el nombre de usuario como «terraformuser». Haga clic en «Siguiente: Permiso»
A continuación, haga clic en «Crear grupo». Proporcione un nombre de grupo y en el tipo de política, filtre por AmazonEC2. Seleccione la primera fila que le da acceso completo a Amazon EC2.
Haga clic en «Siguiente: Revisar»
Haga clic en «Crear usuario».
Descargue el ID de la clave de acceso y la clave secreta de los usuarios recién creados haciendo clic en «Descargar .csv». Estas credenciales son necesarias para conectarse al servicio Amazon EC2 a través de terraform
3. Archivo Terraform
Como ya sabemos que terraform es una herramienta de línea de comandos para crear, actualizar y versionar la infraestructura en la nube, obviamente queremos saber cómo lo hace. Terraform describe la infraestructura en un archivo usando el lenguaje llamado Hashicorp Configuration Language (HCL) con la extensión .tf Es un lenguaje declarativo que describe la infraestructura en la nube. Cuando escribimos nuestra infraestructura usando HCL en un archivo .tf, terraform genera un plan de ejecución que describe lo que hará para alcanzar el estado deseado. Una vez que el plan de ejecución está listo, terraform ejecuta el plan y genera un archivo de estado con el nombre terraform.tfstate por defecto. Este archivo asigna metadatos de recursos a la ID de recurso real y permite que terraform sepa qué está administrando en la nube.
4. Terraform y aprovisionamiento de AWS
Para implementar una instancia EC2 a través de terraform, cree un archivo con extensión .tf Este archivo contiene dos secciones. La primera sección declara el proveedor (en nuestro caso es AWS). En la sección de proveedor especificaremos la clave de acceso y la clave secreta que está escrita en el archivo CSV que hemos descargado anteriormente al crear el usuario EC2. También elija la región de su elección. El bloque de recursos define qué recursos queremos crear. Como queremos crear una instancia EC2, lo especificamos con «aws_instance» y los atributos de la instancia dentro de ella como ami, instance_type y etiquetas. Para encontrar las imágenes de EC2, navegue por ubuntu imagen de la nube.
[root@mysandbox src]# cd [root@mysandbox ~]# mkdir terraform [root@mysandbox ~]# cd terraform/ [root@mysandbox terraform]# vi aws.tf provider "aws" { access_key = "ZKIAITH7YUGAZZIYYSZA" secret_key = "UlNapYqUCg2m4MDPT9Tlq+64BWnITspR93fMNc0Y" region = "ap-southeast-1" } resource "aws_instance" "example" { ami = "ami-83a713e0" instance_type = "t2.micro" tags { Name = "your-instance" } }
Primero aplique terraform plan para averiguar qué hará terraform. El plan terraform nos permitirá saber qué cambios, adiciones y eliminaciones se realizarán en la infraestructura antes de aplicarla. Se van a crear los recursos con el signo ‘+’, se van a eliminar los recursos con el signo ‘-‘ y se van a modificar los recursos con el signo ‘~’.
[root@mysandbox terraform]# terraform plan
Ahora para crear la instancia, ejecute terraform apply
[root@mysandbox terraform]# terraform apply aws_instance.example: Creating... ami: "" => "ami-83a713e0" associate_public_ip_address: "" => "<computed>" availability_zone: "" => "<computed>" ebs_block_device.#: "" => "<computed>" ephemeral_block_device.#: "" => "<computed>" instance_state: "" => "<computed>" instance_type: "" => "t2.micro" key_name: "" => "<computed>" network_interface_id: "" => "<computed>" placement_group: "" => "<computed>" private_dns: "" => "<computed>" private_ip: "" => "<computed>" public_dns: "" => "<computed>" public_ip: "" => "<computed>" root_block_device.#: "" => "<computed>" security_groups.#: "" => "<computed>" source_dest_check: "" => "true" subnet_id: "" => "<computed>" tags.%: "" => "1" tags.Name: "" => "your-instance" tenancy: "" => "<computed>" vpc_security_group_ids.#: "" => "<computed>" aws_instance.example: Still creating... (10s elapsed) aws_instance.example: Still creating... (20s elapsed) aws_instance.example: Creation complete Apply complete! Resources: 1 added, 0 changed, 0 destroyed. The state of your infrastructure has been saved to the path below. This state is required to modify and destroy your infrastructure, so keep it safe. To inspect the complete state use the `terraform show` command.
A continuación, nos dirigimos al panel de EC2, encontraremos que la nueva instancia se está inicializando.
5. Un ejemplo de terraforma más complejo
Ahora que hemos entendido cómo crear una instancia EC2 usando terraform, creemos una infraestructura un poco más avanzada usando terraform. Nuestro objetivo de infraestructura incluye-
→ Crear una VPC con CIDR 10.0.0.0/16
→ Una subred pública dentro de VPC con CIDR 10.0.1.0/24
→ Una subred privada dentro de VPC con CIDR 10.0.2.0/24
→ Grupos de seguridad para instancias públicas y privadas
→ Tres instancias EC2: servidor web, servidor de base de datos e instancia NAT
Primero, creamos un par de claves con el nombre linoxide-deployer.pem a través de la consola de AWS. Para hacer eso, haga clic en «Pares de claves» en el panel de EC2 seguido de «Crear par de claves» y guárdelo en un directorio recién creado dentro de la carpeta terraform que hemos creado en el paso 4.
[root@mysandbox ]# cd ~/terraform [root@mysandbox ]# mkdir ssh
Descargue y copie linoxide-deployer.pem dentro del directorio ~ / terraform / ssh.
Ahora, comenzamos a crear recursos uno por uno a partir de VPC. Además, dividiremos la configuración en varios archivos .tf en función de lo que hacen. Por ejemplo, para crear un recurso VPC, crearemos un archivo con el nombre vpc.tf para que podamos realizar un seguimiento de lo que hace cada archivo. Antes de crear recursos, declaremos todas las variables en el archivo variables.tf.
variables.tf
variable "access_key" { description = "AWS access key" default = "ZKIAITH7YUGAZZIYYSZA" } variable "secret_key" { description = "AWS secret key" default = "UlNapYqUCg2m4MDPT9Tlq+64BWnITspR93fMNc0Y" } variable "region" { description = "AWS region for hosting our your network" default = "ap-southeast-1" } variable "key_path" { description = "Key path for SSHing into EC2" default = "./ssh/linoxide-deployer.pem" } variable "key_name" { description = "Key name for SSHing into EC2" default = "linoxide-deployer" } variable "vpc_cidr" { description = "CIDR for VPC" default = "10.0.0.0/16" } variable "public_subnet_cidr" { description = "CIDR for public subnet" default = "10.0.1.0/24" } variable "private_subnet_cidr" { description = "CIDR for private subnet" default = "10.0.2.0/24" } variable "amis" { description = "Base AMI to launch the instances" default = { ap-southeast-1 = "ami-83a713e0" ap-southeast-2 = "ami-83a713e0" } }
Definamos VPC con el bloque CIDR de 10.0.0.0/16
vpc.tf
resource "aws_vpc" "default" { cidr_block = "${var.vpc_cidr}" enable_dns_hostnames = true tags { Name = "terraform-aws-vpc" } }
Definir la puerta de enlace
gateway.tf
resource "aws_internet_gateway" "default" { vpc_id = "${aws_vpc.default.id}" tags { Name = "linoxide gw" } }
Definir subred pública con CIDR 10.0.1.0/24
public.tf
resource "aws_subnet" "public-subnet-in-ap-southeast-1" { vpc_id = "${aws_vpc.default.id}" cidr_block = "${var.public_subnet_cidr}" availability_zone = "ap-southeast-1a" tags { Name = "Linoxide Public Subnet" } }
Definir subred privada con CIDR 10.0.2.0/24
private.tf
resource "aws_subnet" "private-subnet-ap-southeast-1" { vpc_id = "${aws_vpc.default.id}" cidr_block = "${var.private_subnet_cidr}" availability_zone = "ap-southeast-1a" tags { Name = "Linoxide Private Subnet" } }
Tabla de ruta para subred pública / privada
route.tf
resource "aws_route_table" "public-subnet-in-ap-southeast-1" { vpc_id = "${aws_vpc.default.id}" route { cidr_block = "0.0.0.0/0" gateway_id = "${aws_internet_gateway.default.id}" } tags { Name = "Linoxide Public Subnet" } } resource "aws_route_table_association" "public-subnet-in-ap-southeast-1-association" { subnet_id = "${aws_subnet.public-subnet-in-ap-southeast-1.id}" route_table_id = "${aws_route_table.public-subnet-in-ap-southeast-1.id}" } resource "aws_route_table" "private-subnet-in-ap-southeast-1" { vpc_id = "${aws_vpc.default.id}" route { cidr_block = "0.0.0.0/0" instance_id = "${aws_instance.nat.id}" } tags { Name = "Linoxide Private Subnet" } } resource "aws_route_table_association" "private-subnet-in-ap-southeast-1-association" { subnet_id = "${aws_subnet.private-subnet-in-ap-southeast-1.id}" route_table_id = "${aws_route_table.private-subnet-in-ap-southeast-1.id}" }
Definir grupo de seguridad NAT
natsg.tf
resource "aws_security_group" "nat" { name = "vpc_nat" description = "NAT security group" ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["${var.private_subnet_cidr}"] } ingress { from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["${var.private_subnet_cidr}"] } ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = -1 to_port = -1 protocol = "icmp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["${var.vpc_cidr}"] } egress { from_port = -1 to_port = -1 protocol = "icmp" cidr_blocks = ["0.0.0.0/0"] } vpc_id = "${aws_vpc.default.id}" tags { Name = "NATSG" } }
Definir grupo de seguridad para Web
websg.tf
resource "aws_security_group" "web" { name = "vpc_web" description = "Accept incoming connections." ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = -1 to_port = -1 protocol = "icmp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 3306 to_port = 3306 protocol = "tcp" cidr_blocks = ["${var.private_subnet_cidr}"] } vpc_id = "${aws_vpc.default.id}" tags { Name = "WebServerSG" } }
Definir grupo de seguridad para la base de datos en la subred privada
dbsg.tf
resource "aws_security_group" "db" { name = "vpc_db" description = "Accept incoming database connections." ingress { from_port = 3306 to_port = 3306 protocol = "tcp" security_groups = ["${aws_security_group.web.id}"] } ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["${var.vpc_cidr}"] } ingress { from_port = -1 to_port = -1 protocol = "icmp" cidr_blocks = ["${var.vpc_cidr}"] } egress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } vpc_id = "${aws_vpc.default.id}" tags { Name = "DBServerSG" } }
Definir instancia de servidor web
webserver.tf
resource "aws_instance" "web-1" { ami = "${lookup(var.amis, var.region)}" availability_zone = "ap-southeast-1a" instance_type = "t2.micro" key_name = "${var.key_name}" vpc_security_group_ids = ["${aws_security_group.web.id}"] subnet_id = "${aws_subnet.public-subnet-in-ap-southeast-1.id}" associate_public_ip_address = true source_dest_check = false tags { Name = "Web Server LAMP" } }
Definir instancia de base de datos
dbinstance.tf
resource "aws_instance" "db-1" { ami = "${lookup(var.amis, var.region)}" availability_zone = "ap-southeast-1a" instance_type = "t2.micro" key_name = "${var.key_name}" vpc_security_group_ids = ["${aws_security_group.db.id}"] subnet_id = "${aws_subnet.private-subnet-in-ap-southeast-1.id}" source_dest_check = false tags { Name = "Database Server" } }
Definir instancia NAT
natinstance.tf
resource "aws_instance" "nat" { ami = "ami-1a9dac48" # this is a special ami preconfigured to do NAT availability_zone = "ap-southeast-1a" instance_type = "t2.micro" key_name = "${var.key_name}" vpc_security_group_ids = ["${aws_security_group.nat.id}"] subnet_id = "${aws_subnet.public-subnet-in-ap-southeast-1.id}" associate_public_ip_address = true source_dest_check = false tags { Name = "NAT instance" } }
Asignar EIP para NAT e instancia web
eip.tf
resource "aws_eip" "nat" { instance = "${aws_instance.nat.id}" vpc = true } resource "aws_eip" "web-1" { instance = "${aws_instance.web-1.id}" vpc = true }
Ejecute primero el plan terraform para averiguar qué hará terraform. También puede realizar una revisión final de su infraestructura antes de ejecutar terraform apply
[root@mysandbox terraform]# terraform plan ---------------------------- ---------------------------- Plan: 16 to add, 0 to change, 0 to destroy.
Hay un total de 16 planes para agregar, nada que cambiar o destruir
Ahora ejecute terraform apply
[root@mysandbox terraform]# terraform apply
Una vez completada la ejecución del comando anterior, nuestra infraestructura cobrará vida con una VPC, dos subredes, puerta de enlace, tablas de enrutamiento, grupos de seguridad, asociación EIP, las tres instancias EC2, etc. Puede crear el gráfico de infraestructura con el siguiente comando.
[root@mysandbox terraform]# terraform graph | dot -Tpng > infrastructure_graph.png
Ahora conéctese a la instancia NAT desde su estación de trabajo local, estará dentro de la instancia NAT. La IP privada asignada a la instancia NAT en nuestra infraestructura es 10.0.1.220. Acceda a la instancia dentro de la subred privada, es decir, la instancia de base de datos a través de la instancia NAT, así como la instancia ‘Web Server LAMP’. La IP privada asignada a las instancias de servidor web y de base de datos son 10.0.2.220 y 10.0.1.207 respectivamente. Explore el panel de EC2 para encontrar la IP privada asignada a sus instancias.
[root@mysandbox terraform]# ssh -i "./ssh/linoxide-deployer.pem" ec2-user@ec2-52-220-223-173.ap-southeast-1.compute.amazonaws.com
Hacer ping a la instancia de base de datos desde NAT
[ec2-user@ip-10-0-1-220 ~]$ ping 10.0.2.220 PING 10.0.2.220 (10.0.2.220) 56(84) bytes of data. 64 bytes from 10.0.2.220: icmp_seq=1 ttl=64 time=0.321 ms 64 bytes from 10.0.2.220: icmp_seq=2 ttl=64 time=0.452 ms 64 bytes from 10.0.2.220: icmp_seq=3 ttl=64 time=0.393 ms
Hacer ping a la instancia del servidor web desde NAT
[ec2-user@ip-10-0-1-220 ~]$ ping 10.0.1.207 PING 10.0.1.207 (10.0.1.207) 56(84) bytes of data. 64 bytes from 10.0.1.207: icmp_seq=1 ttl=64 time=0.747 ms 64 bytes from 10.0.1.207: icmp_seq=2 ttl=64 time=0.517 ms
Hemos instalado terraform y aprovisionamos AWS. Ahora puede usar el código para actualizar fácilmente su infraestructura e incluso implementarlo en otra región con modificaciones menores.
Conclusión:
¡Eso es todo por terraform! Hemos definido el estado de la infraestructura en archivos terraform e implementamos la infraestructura con un solo comando. Examinar la documentación para obtener más información sobre los detalles del proveedor de terraform / AWS. Gracias por leer este artículo.