Infraestrutura ágil em Cloud

O primeiro ganho tangível com a adoção de virtualização e Cloud foi a agilidade no tempo de provisionamento de infraestrutura. Com a parte física (servidores, switches e storages) da infraestrutura instalada em grandes quantidades e templates de VMs prontos, passou-se  a entregas VMs em questão de minutos. Há incontáveis artigos e depoimentos sobre isso, atualmente qualquer provedor de Cloud entrega novas VMs, Redes, Storage e LoadBalancer em minutos (as vezes até mesmo em segundos).

Entretanto mesmo utilizando o painel de qualquer provedor de Cloud para provisionar infraestrutura, você vai gastar mais tempo dando cliques do que esperando os recursos serem disponibilizados. Se antes o gargalo era o tempo de instalação e configuração fisica de equipamentos agora passou a ser o humano que faz a interação com as APIs via um painel de controle. Além disso fazer o deploy manual não garante que alguém consiga reproduzir o que foi feito, não há reaproveitamento ou padronização.

Para se atingir o próximo patamar em termos de agilidade e eficiência é necessário fazer provisionamento de infraestrutura de forma programática, ou se preferir utilizar a infraestrutura como código.

Quando falamos em provisionar infraestrutura de forma programática estamos falando em utilizar APIs (disponibilizadas por todos os provedores de Cloud) para criação de VMs, Redes, LoadBalancers, etc. Atualmente existem módulos que possibilitam utilizar APIs de provedores em praticamente qualquer linguagem, mas ainda assim deve-se conhecer alguma linguagem e escrever rotinas de conexão, fazer tratamento de erros, etc.

Outra possibilidade é utilizando uma ferramenta chamada terraform da Hashicorp (www.terraform.io). O terraform permite criar, alterar e evoluir infraestrutura de forma segura e previsível utilizando templates que tem uma linguagem bastante simples e intuitiva. Não é necessário aprender a programar, apesar de que neste tema cada vez mais serão aplicados conceitos de engenharia de software em questões relacionadas a infraestrutura e aprender a programar (em qualquer linguaguem) é algo cada vez mais importante para administradores de sistemas.

Entrando na prática, segue abaixo o exemplo de um template para deploy de uma infraestrutura em OpenStack para uma aplicação web tradicional, com loadbalancer, servidores web/aplicação e banco de dados, com múltiplas instâncias e regras de acesso.

 

variable web_instances  { default = "4" }
variable db_instances   { default = "2" }

provider "openstack" {
  user_name  = "uolcloud"
  tenant_name = "uolcloud"
  password  = "mySecretPassword"
  auth_url  = "https://keystone.br-sp1.openstack.uolcloud.com.br:5000/v2.0"
}

#
# Configurações de Rede
#
resource "openstack_networking_router_interface_v2" "int-net-web" {
  router_id = "538845d8-278e-433f-994a-d868fe1f9d22"
  subnet_id = "${openstack_networking_subnet_v2.subnet-web.id}"
}

resource "openstack_networking_router_interface_v2" "int-net-db" {
  router_id = "538845d8-278e-433f-994a-d868fe1f9d22"
  subnet_id = "${openstack_networking_subnet_v2.subnet-db.id}"
}


resource "openstack_networking_network_v2" "net-web" {
  name = "net-web"
}

resource "openstack_networking_network_v2" "net-db" {
  name = "net-db"
}

resource "openstack_networking_subnet_v2" "subnet-web" {
  name = "subnet-web"
  network_id = "${openstack_networking_network_v2.net-web.id}"
  cidr = "192.168.1.0/27"
}

resource "openstack_networking_subnet_v2" "subnet-db" {
  name = "subnet-db"
  network_id = "${openstack_networking_network_v2.net-db.id}"
  cidr = "192.168.2.0/29"
}

#
# Configurações de Grupos de Segurança
#
resource "openstack_networking_secgroup_v2" "webservers" {
  name = ${openstack_compute_secgroup_v2.webservers.name}"
  description = "The appservers security group"
}

resource "openstack_networking_secgroup_rule_v2" "app_to_db" {
  direction = "egress"
  ethertype = "IPv4"
  protocol = "tcp"
  port_range_min = 3306
  port_range_max = 3306
  remote_group_id  = "${openstack_networking_secgroup_v2.dbservers.id}"
  security_group_id = "${openstack_networking_secgroup_v2.webservers.id}"
}

resource "openstack_networking_secgroup_rule_v2" "public_web" {
  direction = "egress"
  ethertype = "IPv4"
  protocol = "tcp"
  port_range_min = 80
  port_range_max = 80
  remote_ip_prefix  = "0.0.0.0/0"
  security_group_id = "${openstack_networking_secgroup_v2.webservers.id}"
}

resource "openstack_networking_secgroup_v2" "dbservers" {
  name = "dbservers"
  description = "The dbservers security group"
}

#
# Deploy LoadBalancer
#
resource "openstack_compute_floatingip_v2" "web_public_ip" {
  pool = "public301"
}

resource "openstack_lb_monitor_v1" "monitor_1" {
  type = "TCP"
  delay = 30
  timeout = 5
  max_retries = 3
  admin_state_up = "true"
}

resource "openstack_lb_pool_v1" "webpool" {
  name = "webpool"
  protocol = "TCP"
  subnet_id = "${openstack_networking_subnet_v2.subnet-web.id}"
  lb_method = "ROUND_ROBIN"
  monitor_ids = ["${openstack_lb_monitor_v1.monitor_1.id}"]
}

resource "openstack_lb_member_v1" "members" {
  count   = "${var.web_instances}"
  pool_id = "${openstack_lb_pool_v1.webpool.id}"
  address = "${element(openstack_compute_instance_v2.webserver.*.network.0.fixed_ip_v4, count.index)}"
  port    = 80
}

resource "openstack_lb_vip_v1" "vip_web" {
  name        = "vip_1"
  subnet_id   = "${openstack_networking_subnet_v2.subnet-web.id}"
  protocol    = "TCP"
  port        = 80
  pool_id     = "${openstack_lb_pool_v1.webpool.id}"
  floating_ip = "${openstack_compute_floatingip_v2.web_public_ip.address}"
}

#
# Deploy de VMs (instancias)
#
resource "openstack_compute_instance_v2" "webserver" {
  count   = "${var.web_instances}"
  name = "${format("webserver%d", count.index + 1)}"
  image_id = "33a3995d-c9a5-45de-ab78-a27cccebd9fd"  # Ubuntu-16.04 64Bits
  flavor_id = "110d0823-3433-4332-b139-6aebd04dfed3" # small.2GB
  key_pair = "my_keypair"
  security_groups = ["webservers"]
  network {
    "uuid" = "${openstack_networking_network_v2.net-web.id}"
  }
}

resource "openstack_compute_instance_v2" "db" {
  count   = "${var.db_instances}"
  name = "${format("db%d", count.index + 1)}"
  image_id = "33a3995d-c9a5-45de-ab78-a27cccebd9fd"  # Ubuntu-16.04 64Bits
  flavor_id = "33c2df4f-62b6-4dfc-aa88-f7a85b56fcd9" # large.8GB
  key_pair = "my_keypair"
  #security_groups = ["dbservers"]
  network {
    "uuid" = "${openstack_networking_network_v2.net-db.id}"
  }
}

 

Executando o terraforma com o template, a criação de todos esses componentes no UOL Cloud OpenStack demorou apenas 27 segundos !!! Eu não tentei fazer este deploy manualmente via Painel, mas não acredito que seja possível fazê-lo em menos de 10 ou 15 minutos…

A melhor parte é que o template ainda pode ser reutilizado para deploy de outros ambientes similares, utilizando estratégias de Blue/Green deployment ou algo do tipo.

 

Alexandre Biancalana

Com mais de 18 anos de experiência em administração de sistemas, ambientes de missão crítica e infraestrutura internet de alto tráfego, trabalha com plataformas de Cloud desde 2008.