SlideShare uma empresa Scribd logo
1 de 39
Baixar para ler offline
Infraestructura como Código (I)
Publicado por Ignacio Sánchez Ginés el 08 May 2017
DevOpsInfraestructuraEntrega ContinuaCloudInfraestructura como Código
É fato que as metodologias ágeis vieram para ficar. Empresas com visão estão começando a reduzir
drasticamente o Time To Market , enquanto aumentam a qualidade de seu produto final, adotando
frameworks ágeis, como Scrum ou Kanban. Mas em muitas ocasiões a infra-estrutura ainda é um
gargalo.
O problema
Normalmente, descobrimos que essas metodologias são aplicadas apenas no desenvolvimento de
aplicativos. Elementos importantes como infraestructura, qualidade e gestão dos dados, normalmente
estão fora do framework de aplicativos Agil.
É comum ver equipes de programadores trabalhando em sprints semanais, com cerimônias e lançamentos
no final da semana. Mas quando eles têm que colocar seu produto para funcionar em um dos ambientes
corporativos, eles são vítimas de um processo baseado em ”solicitação/resposta”.
Além disso, este “pedido/resposta” é normalmente necessário para todos: Para pedir um passar entre
ambientes, para pedir a build de um novo ambiente, para solicitar alterações na configuração e um longo
etc..
Na maioria dos casos, são processos burocráticos, desatualizado e muito lento: planilhas de Excel
enviadas por e-mail que tem que aprovar várias pessoas ... você sabe o que significa?
Este é geralmente o caso porque o departamento de infra-estrutura (chama-se “produção” ou chamamos de
“sistemas”) são “verticalizados” e orientado como serviço.
Muitas vezes acontece que esse departamento não é informado dos requisitos até que seja tarde demais e
acaba pedindo uma infraestrutura que não foi planejada, que é entregue semanas depois com inúmeros
problemas.: desempenho, capacidade, escalabilidade, resiliência, ...
Visto desta forma, é fácil entender que, do ponto de vista de Time To Market, estamos limitando a
agilidade da equipe. Mas o que podemos fazer?
A solução
A primeira coisa é pensar em produto e não em serviço.
O Departamento de Desenvolvimento já recebeu uma boa manobra para alinhar com as reais necessidades
do Negócio. Eles foram distribuídos em equipes orientado para produtos. Por que não fazemos o mesmo
com o departamento de infraestrutura?
Se as pessoas desse departamento fizessem parte das equipes que desenvolvem os produtos, cada uma
delas só precisaria se preocupar com o produto., dos servidores do seu produto, as redes do seu produto, o
armazenamento do seu produto, as regras de firewall do seu produto, etc.
Se eles também fizeram parte da equipe do começo ao fim como um dos times, poderia dar uma solução
correta para os requisitos não-funcionais, aceitar alterações a qualquer momento e se adaptar às
necessidades reais do aplicativo à medida que se desenvolve, com controle contínuo da infra-estrutura
necessária.
Mas, claro, criar um ambiente leva dias ou semanas! Instalar um sistema operacional, plataforma de uma
máquina, atualizá-lo, configurá-lo, requer muito tempo. E os ambientes têm muitas máquinas!
Acima, uma vez que o ambiente é criado, é facilmente corrompido, perde o alinhamento com outros
ambientes (desenvolvimento e produção sempre foram os mesmos?), a execução de testes de usuário os
bloqueia por semanas e problemas sem fim decorrentes da operação manual.
Está claro: necesitamos AUTOMAÇÃO.
Agora, a automação só é possível se nossa infraestrutura for virtualizada. Mas não só isso, precisamos que
a virtualização tenha uma API de controle.
Não adianta para nós que tudo seja virtualizado se cada vez que precisarmos de um novo elemento,
tivermos que entrar nos consoles de gerenciamento.
Felizmente, os provedores de IaaS na nuvem e a maioria dos sistemas já virtualizam hardware ”on
premise” e eles já nos oferecem a API que precisamos.
As ferramentas
A evolução que os processos de desenvolvimento sofreram durante estes últimos anos é evidente. Os
programadores têm ferramentas para escrever código em arquivos de texto de uma
forma paralela, distribuida e totalmente descentralizada (Git e Gitflow, por ejemplo).
Por que não nos aproveitamos deles?
Se você já ouviu falar sobre DevOps, você terá reconhecido instantaneamente: é a abordagem das
Operações para o Desenvolvimento e vice-versa.
Escrever infra-estrutura em um arquivo de texto como se você fosse um programador já é possível.
Se incluirmos esses arquivos de texto como parte do ciclo de vida de nossos produtos, poderemos ter as
mesmas vantagens: Versionamento de infraestrutura!, Gerenciamento de dependência de infraestrutura!
Integração contínua de infraestrutura! Teste de infraestrutura automatizado!
Soa bem. Como fazemos?
Na Amazon AWS, você pode usar CloudFormation.
Azure tem Resource Manager.
E no OpenStack existe Heat.
Essas três soluções são proprietárias e, obviamente, só funcionam com seus produtos.
Mas há uma ferramenta que não se importa com o fornecedor e temos o : Terraform.
Com o Terraform você pode escrever (descrever) infra-estrutura em arquivos de texto para qualquer um
deles ou para todos de uma vez!
Sua linguagem declarativa é orientada para ser escrita por humanos e é muito fácil de aprender.
Na próxima parte deste artigo descrevemos Terraform como um cenário real na Azure com vários
elementos típicos de uma moderna infra-estrutura (redes, VMs, balanceadores, armazenamento).
Siga-nos no Twitter para não perder os próximos posts!
A propósito, em relação a este tópico, temos um artigo neste blog sobre como criar Configuração do
ambiente como dependência usando Gradle.
Infraestructura como Código (II): Terraform
Publicado por Ignacio Sánchez Ginés el 03 August 2017
DevOpsInfraestructuraEntrega ContinuaCloudMicrosoft AzureTerraformInfraestructura como Código
A infraestrutura como um código é um elemento-chave nas equipes de agilidade.
No artigo anterior Vimos a importância de orientar nossa infra-estrutura para produto e como o Terraform
pode nos ajudar a acelerar seu build e manutenção de forma automatizada.
Nosso objetivo
Neste artigo, veremos um exemplo prático: descreveremos a infraestrutura no Azure usando o Terraform.
Para isso, teremos o seguinte repositório do GitHub onde tudo está pronto para que você não precise
escrever nada: https://github.com/drhelius/terraform-azure-demo
Este é o nosso objetivo desse cenário:
Criaremos um cluster de máquinas que exporá o mesmo aplicativo na porta 8080. Cada máquina terá seu
próprio disco virtual dentro da mesma conta de armazenamento.
Para garantir a alta disponibilidade do serviço e a distribuição uniforme da carga, usaremos
um balanceador(LB).
Configuraremos o LB para incluir automaticamente todas as máquinas que compõem o cluster, ou seja,
aquelas que estão no mesmo conjunto de disponibilidade e cujo serviço está operacional.. Se, ao contrário, o
serviço deles estiver indisponível, eles serão removidos do grupo de balanceamento.
Este último será alcançado colocando uma sonda, ou Probe, para verificar a porta 8080 de cada máquina.
Finalmente, para acessar do lado de fora, vamos atribuir um IP público ao LB, abrir a porta 80 e mapeá-lo
para a porta 8080 das máquinas que fazem parte do cluster.
Mãos à obra
Antes de começarmos, teremos que preparar nossa conta do Azure para poder usá-la com o Terraform,
para o qual seguiremos a documentação oficial.
Após essa etapa, teremos as credenciais necessárias para vincular o Terraform à nossa conta da Azure.
Vamos começar criando uma pasta para o nosso projeto e dentro do arquivo demo.tf, onde iremos
descrever todos os elementos da infraestrutura para este artigo.
Você pode ver o arquivo completo aqui: https://github.com/drhelius/terraform-azure-
demo/blob/master/demo.tf
Antes de criar o Grupo de Recursos, devemos fornecer os dados necessários do Provider da Azure:
provider “azurerm” {
client_id = “${var.azure_client_id}”
client_secret = “${var.azure_client_secret}”
subscription_id = “${var.azure_subscription_id}”
tenant_id = “${var.azure_tenant_id}”
}
Uma vez que a forma de “conectarmos” podemos declarar nosso novo Resource Group:
resource “azurerm_resource_group” “demo” {
name = “demo-terraform”
location = “${var.azure_location}”
}
Como você pode ver, a configuração do provedor é feita com variáveis. As variáveis no Terraform são
assim:
${var.mi_variable}
Estas variáveis devem ser declaradas em um arquivo chamado variables.tf:
variable “azure_client_id” {
type = “string”
}
variable “azure_client_secret” {
type = “string”
}
variable “azure_location” {
type = “string”
default = “West Europe”
}
variable “azure_subscription_id” {
type = “string”
}
variable “azure_tenant_id” {
type = “string”
}
variable “demo_instances” {
type = “string”
default = “2”
}
variable “demo_admin_password” {
type = “string”
}
Na declaração, podemos colocar valores padrão. O resto do valor que podemos fornecer de muitas formas:
por linha de comando, como variables de ambiente, usando Vault ou usando um arquivo especial
chamado terraform.tfvars.
Este arquivo é útil para variáveis sensíveis que queremos fornecer localmente. Nós o colocamos na raiz do
projeto e o Terraform o lê automaticamente quando realizamos qualquer operação:
azure_client_id = “xxxxxx-xx-xx-xx-xxxxxxx”
azure_tenant_id = “xxxxxx-xx-xx-xx-xxxxxxx”
azure_client_secret = “xxxx”
azure_subscription_id = “xxxxxx-xx-xx-xx-xxxxxxx”
Em seguida, declaramos os dados da rede privada para o cluster:
resource “azurerm_virtual_network” "demo" {
name = “demo-virtual-network”
address_space = [“10.0.0.0/16”]
location = “${var.azure_location}”
resource_group_name = “${azurerm_resource_group.demo.name}”
}
resource “azurerm_subnet” “demo” {
name = “demo-subnet"
resource_group_name = “${azurerm_resource_group.demo.name}"
virtual_network_name = "${azurerm_virtual_network.demo.name}"
address_prefix = "10.0.1.0/24"
}
Podemos ver que na referência de sub-rede é feita para a rede virtual já declarada. A ordem de declaração
no arquivo não é importante.
Continuamos com um IP público para o LB e com uma interface de rede (NIC) que utilizaremos em cada
VM:
resource "azurerm_public_ip" "demo" {
name = "demo-public-ip"
location = "${var.azure_location}"
resource_group_name = "${azurerm_resource_group.demo.name}"
public_ip_address_allocation = "static"
}
resource "azurerm_network_interface" "demo" {
count = "${var.demo_instances}"
name = "demo-interface-${count.index}"
location = "${var.azure_location}"
resource_group_name = "${azurerm_resource_group.demo.name}"
ip_configuration {
name = "demo-ip-${count.index}"
subnet_id = "${azurerm_subnet.demo.id}"
private_ip_address_allocation = "dynamic"
load_balancer_backend_address_pools_ids = ["${azurerm_lb_backend_address_pool.demo.id}"]
}
}
Nós usamos um atributo chamado ”count” para criar mais de um elemento do tipo
“azurerm_network_interface” e para isso nós usamos um variável (var.demo_instances).
Continuamos com todos os elementos necessários para criar o balanceador no Azure: LB, regra de
balanceamento, probe, pool addres e conjunto de disponibilidade. Todos eles devidamente referenciados
entre si:
resource "azurerm_lb" "demo" {
name = "demo-lb"
location = "${var.azure_location}"
resource_group_name = "${azurerm_resource_group.demo.name}"
frontend_ip_configuration {
name = "default"
public_ip_address_id = "${azurerm_public_ip.demo.id}"
private_ip_address_allocation = "dynamic"
}
}
resource "azurerm_lb_rule" “demo" {
name = “demo-lb-rule-80-8080"
resource_group_name = “${azurerm_resource_group.demo.name}"
loadbalancer_id = “${azurerm_lb.demo.id}"
backend_address_pool_id = "${azurerm_lb_backend_address_pool.demo.id}"
probe_id = "${azurerm_lb_probe.demo.id}"
protocol = "tcp"
frontend_port = 80
backend_port = 8080
frontend_ip_configuration_name = "default"
}
resource "azurerm_lb_probe" "demo" {
name = "demo-lb-probe-8080-up"
loadbalancer_id = "${azurerm_lb.demo.id}"
resource_group_name = "${azurerm_resource_group.demo.name}"
protocol = "Http"
request_path = "/"
port = 8080
}
resource "azurerm_lb_backend_address_pool" "demo" {
name = "demo-lb-pool"
resource_group_name = "${azurerm_resource_group.demo.name}"
loadbalancer_id = "${azurerm_lb.demo.id}"
}
resource "azurerm_availability_set" "demo" {
name = "demo-availability-set"
location = "${var.azure_location}"
resource_group_name = "${azurerm_resource_group.demo.name}"
}
O que conseguimos é que o LB equilibre as máquinas que usam IPs do pool de endereços.
Continuamos com o armazenamento, um container por VM na mesma conta de armazenamento:
resource "azurerm_storage_account" "demo" {
name = "demoterraformstorage"
resource_group_name = "${azurerm_resource_group.demo.name}"
location = "${var.azure_location}"
account_type = "Standard_LRS"
}
resource "azurerm_storage_container" "demo" {
count = "${var.demo_instances}"
name = "demo-storage-container-${count.index}"
resource_group_name = "${azurerm_resource_group.demo.name}"
storage_account_name = "${azurerm_storage_account.demo.name}"
container_access_type = "private"
}
E finalmente a descrição da própria VM:
resource "azurerm_virtual_machine" "demo" {
count = "${var.demo_instances}"
name = "demo-instance-${count.index}"
location = "${var.azure_location}"
resource_group_name = "${azurerm_resource_group.demo.name}"
network_interface_ids = ["${element(azurerm_network_interface.demo.*.id, count.index)}"]
vm_size = "Standard_A0"
availability_set_id = "${azurerm_availability_set.demo.id}"
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
storage_os_disk {
name = "demo-disk-${count.index}"
vhd_uri =
"${azurerm_storage_account.demo.primary_blob_endpoint}${element(azurerm_storage_container.demo
.*.name, count.index)}/demo.vhd"
caching = "ReadWrite"
create_option = "FromImage"
}
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true
os_profile {
computer_name = "demo-instance-${count.index}"
admin_username = "demo"
admin_password = "${var.demo_admin_password}"
custom_data = "${base64encode(file(“${path.module}/provision.sh"))}"
}
os_profile_linux_config {
disable_password_authentication = false
}
}
Com tudo isso preparado e localizado no caminho onde o nosso arquivo demo.tf está localizado, nós
executamos este comando:
$ terraform init
Que inicializa nosso projeto e baixa os providers necessários, no nosso caso o Azure. Então podemos
executar o seguinte:
$ terraform plan
Este comando nos informa sem fazer alterações do que aconteceria se aplicássemos a configuração que
descrevemos.
Nos solicitará por linha de comando o valor daquelas variáveis que não estabelecemos. No nosso caso, a
senha das VMs:
var.demo_admin_password
Enter a value:
Mais tarde, veremos uma descrição dos recursos que seriam criados ou modificados na Azure:
Plan: 16 to add, 0 to change, 0 to destroy.
Estamos prontos para aplicar as alterações e tudo é criado automaticamente na Azure. Para isso,
executamos o seguintecomando:
$ terraform apply
Pouco a pouco, os elementos começarão a ser criados. Uma vez terminado, informe-nos do resultado e
mostre-nos as variáveis de saída (outputs) que definimos no arquivo output.tf, no nosso caso, o IP público
do LB:
output "lb_public_ip" {
value = "${azurerm_public_ip.demo.ip_address}"
}
Nós veríamos algo assim:
Apply complete! Resources: 16 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.
State path:
Outputs:
lb_public_ip = 52.233.156.135
Neste momento podemos colocar o IP público em nosso navegador e testá-lo.
O aplicativo de amostra é um serviço da web dentro de um container do Docker que retorna o nome do
host do container em que está sendo executado. Toda vez que atualizamos a página, devemos ver até dois
nomes de host diferentes:
Hello World from host “d270d4254e38”.
Agora vamos modificar o valor da variável demo_instances no arquivo variables.tf e aumentá-lo, por
exemplo, para 4:
variable “demo_instances” {
type = “string”
default = “4”
}
Voltamos a executar o comando terraform apply e veremos como os elementos ausentes serão criados, o
resto fica como está:
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
Ou seja, as duas novas VMs com suas interfaces de rede, o armazenamento será criado, etc. Além disso,
eles serão incluídos no grupo de balanceamento e o aplicativo estará disponível a partir de 4 servidores
usando o IP público do LB.
Podemos colocar o IP público novamente no nosso navegador para testá-lo. Toda vez que atualizamos a
página, devemos ver até 4 nomes de host diferentes.
Se entramos em nossa conta da Azure, veríamos todos os elementos criados:
Este é apenas o começo porque com o Terraform podemos modelar cenários muito mais complexos, com
centenas de elementos e todos os versionados sob o Git ou qualquer outro SCM.
Para acompanhar os próximos capítulos desta série sobre infra-estrutura, como código e outros posts, siga-
nos Twitter!
Infraestrutura como Código (III): Terraform e AWS
Publicado por Carlos M. Cornejo el 07 November 2017
DevOpsEntrega ContinuaCloudTerraformAmazon AWSInfraestructura como Código
No artigo anteriormente estávamos falando do Terraform e como descrever infra-estrutura para seu uso
na Microsoft Azure.
Nesta parte, vamos nos concentrar em como replicar a infraestrutura que criamos no Azure, mas, dessa vez,
vamos fornecê-la emAWS.
Antes de analisar como vamos implementar o exemplo na AWS, vamos analisar alguns conceitos básicos.
Apresentação da AWS
Conceitos de rede de EC2 na AWS
O serviço gerenciado da Amazon EC2 pode ser hospedado em vários locais ao redor do mundo, mais
conhecida como Região. Por sua vez, dentro de cada Região existem áreas de disponibilidade, a partir de
agora AZ's (Availabily Zones). A Amazon EC2 permite colocar recursos, como instâncias e dados de
EC2, em vários AZ's.
A Amazon Virtual Private Cloud (VPC) permite que você execute recursos da AWS em uma rede virtual,
que por padrão é separado no nível lógico de outras redes. As VPCs dentro da AWS podem ser
configuradas com um intervalo de IPs, tabelas de roteamento, sub-redes, gateways de rede e parâmetros de
segurança, como ACLs (access control lists)
Uma sub-rede agrupa um intervalo de IPs dentro de um VPC. Cada sub-rede reside exclusivamente dentro
de uma AZ. Por sua vez, uma sub-rede pode ser pública ou privada. Uma sub-rede pública é acessível pela
Internet, enquanto uma sub-rede privada é usada para os recursos que não devem ser diretamente expostos
à Internet, como um banco de dados..
Um security group representa um firewall virtual que controla o tráfego de uma ou mais instâncias do
EC2. Quando uma instância do EC2 é iniciada, é necessário associar pelo menos um security group a essa
instância. Para permitir tráfego de/para a instância, é necessário criar regras (rules). Essas regras podem ser
modificadas a qualquer momento e são aplicadas automaticamente a todas as instâncias associadas
ao security group.
Para mais detalhes sobre esses conceitos, consulte a documentação oficial da AWS:
 Regiões e AZ's
 Introdução a VPC
 VPC e Subnets
 Grupos de segurança na Amazon EC2
Criação de um novo usuario IAM
Para interagir com a API da AWS, precisamos criar um usuário e atribuir uma policy que permita criar
recursos dentro da EC2. Este usuário será aquele que o Terraform usa internamente para se comunicar
com a API da AWS.
Com base no fato de que temos uma conta criada na AWS, o seguir mostramos como criar um novo
usuário IAM(Identity and Access Management).
Nós selecionamos IAM:
Criamos o usuário e selecionamos o Programatic access. Isso nos permitirá configurar as credenciais de
acesso que usaremos com o Terraform:
Selecionamos as permissões necessárias para podermos usar os recursos de EC2. Nós devemos selecionar
o grupo ec2-FullAccess:
Nós criamos o usuário:
Na última etapa, devemos salvar as credenciais (Access key ID y Secret access key)
Na postagem anterior, mencionamos como configurar credenciais, mas dessa vez vamos configurá-lo por
meio das credenciais aws cli em ~/.aws/credentials. Desta forma, quando executamos o Terraform, eles
serão localizadas automaticamente com nossas credenciais
Finalmente, vamos configurar a chave de acesso SSH que precisamos para criar instâncias EC2. Observe
que cada chave SSH é local para cada Região, com o qual nós temos que ter certeza que quando nós
executarmos este exemplo nós criamos a chave na mesma Região que é usada em variables.tf
En nuestro ejemplo, vamos a utilizar la Region London:
Seleccionamos Key Pairs:
Create Key Pair como enmilocalfunciona-terraform-key-eu-west-2
Como veremos mais adiante, essa chave é a que usaremos quando usarmos o recurso correspondente
de EC2.
Terraform e AWS
No ponto anterior, descrevemos e explicamos uma série de elementos necessários para entender o modo
como a AWS trabalha no nível de rede.
Assim que o nosso acesso à AWS estiver configurado, poderemos descrever nossa infraestrutura
usando Terraform.
Todo código está disponível em nosso repositório de sistemas.
Devemos lembrar que, em um nível conceitual, estamos descrevendo a mesma infraestrutura que criamos
para o Azure, mas, no caso da AWS, há elementos que são chamados de forma diferente, mas que têm a
mesma responsabilidade.. Por exemplo, no Azure, temos um Availability Set enquanto na AWS é
chamado Auto Scaling Group.
Nós vamos criar um Auto Scaling Group (ASG), que é onde vamos instanciar os serviços de EC2, para
que poçamos escalar horizontalmente para garantir alta disponibilidade, usaremos as AZ’s de cada região
por trás de um balanceador e por meio do AWS Launch Configuration poderemos atribuir
automaticamente novas instâncias do EC2 dentro da ASG.
Se olharmos, ao contrário do post anterior, não mencionamos nenhum elemento de rede. Para simplificar a
solução, escolhemos usar todos os elementos padrão em uma região (VPC, sub-rede, roteador e IGW).
Lembre-se de que nosso objetivo é descrever essa infraestrutura:
O arquivo variables.tf contém a definição das variáveis que vamos usar no exemplo.
Region, nomes das chaves e da ami:
Variables usadas para configurar a SG:
Variáveis de output que usaremos para mostrar informações no arquivo output.tf:
O arquivo main.tf contém a descrição da infra-estrutura
Nós usamos o provider da AWS:
Criamos um Security Group que permite acesso à porta do aplicativo (80):
Recuperamos a lista de AZs disponíveis para o referida Region:
Criamos um balanceador (ELB) configurando seu Security Group e os AZs nos quais queremos balancear
o tráfego. Observe a porta do balanceador (80), bem como a porta usada pelo probe (80) para conhecer o
status de integridade de nosso aplicativo:
Nós criamos o Configuration Launcher que é o template que o ASG usa para lançar instâncias de EC2:
 image_id: É a imagem que queremos fornecer dentro da região que estamos usando.
 instance_type: Tamanho da máquina EC2.
 user_data: Script usado para configurar a instância EC2.
 key_name: É a chave SSH com a qual o acesso SSH será configurado.
A última peça que precisamos configurar é a ASG:
 availability_zones: As AZ’s são onde queremos criar as instâncias EC2.
 min_ size y max_size: Representa o número mínimo e máximo de instâncias do EC2 que queremos
provisionar.
 desired_capacity: Representa o número atual de instâncias EC2.
 force_delete: Para forçar a exclusão da instâncias EC2.
 launch_configuration: O template que definimos antes.
 load_balancers: O balanceador associado.
Um aspecto importante a considerar é que, em nosso exemplo, configuramos o ASG manualmente. Em um
cenário real, devemos considerar situações de carga ou demanda do serviço para escalar automaticamente
com base, por exemplo, em limites de CPU, memória, etc.
Com este último passo, preparamos o exemplo e podemos testá-lo:
Inicialize o diretório de trabalho com terraform init :
terraform plan Analisa a descrição da infraestrutura que criamos nos informa sobre as alterações que
serão feitas (essa etapa não altera a AWS):
O próximo passo é o build da nossa infraestrutura na AWS através do comando terraform apply obtendo
na tela os valores das variáveis que definimos como output:
Após alguns minutos (tempo do build da EC2, provisionamento do serviço de teste que requer a instalação
do docker e o download da imagem), o DNS de saída estará disponível e veremos como a atualização do
navegador retornará ids de serviço diferentes.
O que conseguimos com essa configuração inicial é provisionar essa infraestrutura e também criar um
cluster de dois nós em alta disponibilidade nos AZ's da região que usamos.
Podemos verificá-lo no console da AWS, na seção EC2 e em balanceadores de carga:
Selecionamos instâncias e vemos como duas instâncias do EC2 foram criadas em cada AZ disponível.
Se quisermos criar programaticamente mais instâncias e ver se o ASG está funcionando corretamente,
podemos executar de novo terraform apply -var asg_desired=6 para confirmar como o ASG escala
horizontalmente:
Conclusões
Para fechar, vamos rever o conteúdo do post:
 Nós usamos o Terraform para descrever um exemplo de infraestrutura, mas desta vez na AWS.
 Antes de implementar o exemplo, analisamos alguns conceitos de rede na AWS.
 Os acessos às chaves AWS e SSH foram configurados.
 Nós explicamos alguns elementos da AWS para alcançar o escalonamento horizontal e como usar o
Terraform para neste propósito.
 Ajustamos o número de instâncias para verificar se o exemplo inteiro funcionou corretamente.
Com isso fechamos o post, esperando que você tenha gostado. Não hesite em comentar qualquer dúvida ou
detalhe aqui, ou através da nossa conta Twitter.
Stay tunned!!
DevOps Terraform Amazon AWS OpenShift
Terraform + AWS + OpenShift
Publicado por Alejandro Nieto el 14 August 2018
Neste artigo, vamos nos concentrar em como executar o provisionamento da infraestrutura necessária para uma deploy do Openshift na AWS
e sua configuração automaticamente. Para isso vamos usar o Terraform e o playbook oficial do openshift-ansible (utilizar branch release-3.9).
Para rever os fundamentos do Terraform, recomendo a leitura do seguinte artigo, assim como outros já publicados neste blog:
http://enmilocalfunciona.io/infraestructura-como-codigo-iii-terrafom-y-aws/
Vamos criar a infraestrutura baseada na arquitetura de referência da Red Hat:
$ terraform workspace newdev
$ terraform workspace newpre
$ terraform workspace newpro
terraform workspace select pre
Terraform
De acordo com Hashicorp, para escrever um módulo Terraform é aconselhável usar três arquivos para definir os recursos
main.tf
outputs.tf
variables.tf
Como este módulo é um pouco mais complexo, vamos definir arquivos por tipo de recursos:
00-main.tf
01-security.tf
02-lb.tf
03-network.tf
outputs.tf
variables.tf
Para facilitar a transição de ambientes e isolar o estado de nossa infraestrutura, dependendo do ambiente, é aconselhável usar a função
"workspaces" fornecida pela ferramenta Terraform. Nós os criamos da seguinte forma:
Se trabalharmos com workspace, podemos usar a variável $ {terraform.workspace} para fazer a transição facilmente entre os ambientes:
resource “aws_vpc” “openshift” {
cidr_block = “${var.cidr_block}”
enable_dns_hostnames = true
tags {
Name = “${var.cluster_id}-${terraform.workspace}”
}
}
Incluindo essa variável, diferenciamos os recursos de um ambiente para outro sem a necessidade de reescrever o código, apenas alterando
o workspace:
Nós também usaremos um arquivo .tfvars (onde as variáveis são indicadas) por ambiente:
dev.tfvars
pre.tfvars
pro.tfvars
As variáveis que serão mencionadas em todo o post devem ser definidas nesses arquivos.
Elementos de rede
Vamos definir os primeiros recursos. A primeira coisa que vamos definir são os elementos da rede:
VPC
Subnets
region = "eu-west-1"
azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
cidr_block = "172.16.0.0/16"
cidr_master_blocks = ["172.16.10.0/24","172.16.11.0/24","172.16.12.0/24"]
cidr_infra_blocks = ["172.16.20.0/24","172.16.21.0/24","172.16.22.0/24"]
cidr_node_blocks = ["172.16.30.0/24","172.16.31.0/24","172.16.32.0/24"]
cidr_public_blocks =["172.16.40.0/24","172.16.50.0/24","172.16.60.0/24"]
resource "aws_vpc" "openshift" {
cidr_block = "${var.cidr_block}"
enable_dns_hostnames = true tags {
Name = "${var.cluster_id}-${terraform.workspace}"
}
}
vpc_id = "${aws_vpc.openshift.id}" tags {
Name = "${var.cluster_id}-${terraform.workspace}"
}
}
resource "aws_default_route_table" "openshift_igw" { default_route_table_id =
"${aws_vpc.openshift.main_route_table_id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.openshift.id}"
}
Nat Gateway
Internet Gateway
Tablas de enrutamiento
As variáveis a serem usadas para os elementos de rede seriam as seguintes:
O elemento base é a vpc:
As sub-redes serão criadas por função e AZ. Ou seja, um subnet_master para cada AZ e o mesmo para cada uma das variáveis que
especificamos acima. Sub-redes podem ser criadas com a máscara desejada, não é necessário usar a indicada nas variáveis.
O Internet Gateway é a peça pela qual as instâncias com ip público sairão para a Internet, neste caso, temos um bastião, a única máquina
com um ip público). O Gateway de Internet está associado ao VPC:
Subseqüentemente, devemos criar uma rota e na qual o gateway é o "Internet Gateway" que acabamos de criar. Esta rota permitirá que as
máquinas com endereço público acessem a Internet e estejam na tabela padrão:
resource "aws_subnet" "master" {
count = "${length(var.cidr_master_blocks)}"
vpc_id = "${aws_vpc.openshift.id}"
cidr_block = "${var.cidr_master_blocks[count.index]}"
availability_zone = "${element(var.azs,count.index)}"
tags {
Name = "${var.cluster_id}-master${format("%02d", count.index + 1)}-${terraform.workspace}"
}
}
resource "aws_nat_gateway" "openshift_nat_gw" {
count = "${length(var.azs)}"
allocation_id = "${aws_eip.nat_gateway.*.id[count.index]}"
subnet_id = "${aws_subnet.public.*.id[count.index]}"
depends_on = ["aws_internet_gateway.openshift"]
}
resource "aws_route_table" "openshift_nat_route" { count
= "${length(var.azs)}"
vpc_id = "${aws_vpc.openshift.id}"
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = "${aws_nat_gateway.openshift_nat_gw.*.id[count.index]}"
}
tags {
Name = "openshift-nat-${aws_subnet.public.*.id[count.index]}-${terraform.workspace}"
}
}
security_groups = ["bastion","master","infra","node"]
data "aws_security_group" "default" {
name = "default"
vpc_id = "${aws_vpc.openshift.id}"
}
Para que as instâncias com ips privados acessem a Internet, devemos criar um Nat Gateway (com seu ip público correspondente). Este nat
gateway deve ser implantado nas sub-redes públicas que criamos anteriormente, ou seja, três Nat Gateway:
Assim como no Internet Gateway, você precisa criar rotas de roteamento e associá-las às sub-redes privadas (master, infra e node).):
:
Segurança
políticas de segurança que usamos no post são mais permissivas do que realmente deveria ser, mas o propósito do post não é a infra-
estrutura de securança então vamos simplificar incidindo sobre o acesso que permitirá a partir de fora do nosso vpc, que serão as portas 22
(bastião) e as portas para acessar consoles e aplicativos (8443, 443 e 80).
Ao criar um vpc, é criado automaticamente um grupo de segurança que será aplicado por padrão que permitirá todo o tráfego dos elementos
internos desse vpc.
Neste caso, precisamos apenas de uma variável na qual definiremos a quantidade e os nomes dos grupos de segurança que vamos criar:
Terraform também pode se referir a recursos já criados e com um life cycle (ciclo de vida) diferente dos recursos do nosso módulo. Eles
podem ser referenciados da seguinte forma, onde a variável :
Em seguida, criaremos os grupos de segurança. Como um ponto, na AWS eles não estão associados a sub-redes, eles estão associados a
instâncias; portanto, você poderia ter duas instâncias na mesma sub-rede com políticas de segurança diferentes.
resource "aws_route_table_association" "route_nat_master" {
count = "${length(var.cidr_master_blocks)}"
subnet_id = "${aws_subnet.master.*.id[count.index]}"
route_table_id = "${aws_route_table.openshift_nat_route.*.id[count.index]}"
}
resource "aws_security_group" "sg_tf" {
count = "${length(var.security_groups)}"
name = "${var.security_groups[count.index]}-${terraform.workspace}"
description = "${var.security_groups[count.index]}"
vpc_id = "${aws_vpc.openshift.id}"
tags {
"kubernetes.io/cluster/openshift-cluster" = "${var.aws_label_value}"
}
}
resource "aws_security_group_rule" "bastion_ssh_tf" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = "${element(aws_security_group.sg_tf.*.id, 0)}"
}
resource "aws_security_group_rule" "infra_443_tf" {
type = "ingress"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = "${element(aws_security_group.sg_tf.*.id, 2)}"
}
resource "aws_security_group_rule" "infra_80_tf" {
type = "ingress"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = "${element(aws_security_group.sg_tf.*.id, 2)}"
}
bastion_instance_type = "t2.micro"
instance_type = "m4.xlarge"
image = "ami-3548444c"
key_name = "your_key"
key_file = "certs/your_key"
master_count = 3
As regras necessárias são as seguintes:
Permitir que a porta 22 acesse o bastião:
Sobre o master, precisamos apenas acessar o console da web openshift, que é exibido por padrão na porta 8443:
Os nodes "infra" da Openshift são os que expõem as aplicações ao exterior, então isso poderia ser feito mais do jeito que gostaríamos,
mas incluiremos as portas mais usuais:
Instâncias
Na Contrução de instâncias, vamos nos referir a recursos já definidos, como sub-redes e grupos de segurança.
Com o uso de variáveis e usando "count" nos recursos, podemos exibir dinamicamente o número de instâncias que queremos para cada
função.
Variáveis para utilizar:
resource "aws_security_group_rule" "master_8443_tf" {
type = "ingress"
from_port = 8443
to_port = 8443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = "${element(aws_security_group.sg_tf.*.id, 1)}"
}
Nosso bastião vai ser de onde vamos executar a instalação do Openshift, então você vai precisar de várias ferramentas instaladas, vamos
fazer isso usando a opção "provisioner" do Terraform, que permite transferir arquivos e executar um shell. Neste caso, é simples, então
faremos isso executando um shell e a máquina estará pronta para executar o playbook ansible quando tivermos o inventário pronto (isso
será feito mais tarde):
A seguir, vamos criar quantas instâncias da função X dependendo das variáveis que definimos para este. Neste caso nós escolhemos instalar
o etcd no "master", então deixamos a variável "etcd_count" como 0.
Para implantar um master, seria o seguinte:
Como você pode ver, as variáveis referentes à função de master são usadas, como 'master_count'. Para implantar infraestruturas ou nodes
de aplicativos, é necessário apenas fazer referência às variáveis de cada função.
Balanceadores de carga
Para ter alta disponibilidade, vamos expor os masters e nodes infra usando os balanceadores de carga que a AWS nos fornece. Esses
balanceadores devem estar localizados nas sub-redes públicas e aplicar os grupos de segurança que definimos anteriormente de
acordo com a função.
As variáveis a serem usadas para esses recursos são as seguintes:
resource "aws_instance" "bastion" { ami
= "${var.image}"
instance_type = "${var.bastion_instance_type}"
availability_zone = "${element(var.azs, 0)}"
key_name = "${var.key_name}"
subnet_id = "${element(aws_subnet.public.*.id, 0)}"
associate_public_ip_address = true
vpc_security_group_ids = ["${data.aws_security_group.default.id}","${element(aws_security_group.sg_tf.*.id, 0)}"]
tags {
Name = "bastion-tf-${terraform.workspace}"
}
provisioner "remote-exec" {
connection {
user = "centos"
private_key = "${file("${path.module}/certs/your_key")}"
}
inline = [
"sudo yum install -y epel-release",
"sudo yum install -y git python-pip pyOpenSSL python-cryptography python-lxml python-passlib httpd-tools java-1.8.0-openjdk-headless", "sudo pip install
--upgrade pip",
"sudo pip install 'ansible==2.5.5'",
"git clone -b release-3.9 https://github.com/openshift/openshift-ansible.git",
]
}
}
resource "aws_instance" "master" {
count = "${var.master_count}"
ami = "${var.image}"
instance_type = "${var.instance_type}"
availability_zone = "${element(var.azs, count.index)}"
key_name = "${var.key_name}"
subnet_id = "${element(aws_subnet.master.*.id, count.index)}"
associate_public_ip_address = false
vpc_security_group_ids = ["${data.aws_security_group.default.id}","${element(aws_security_group.sg_tf.*.id, 1)}"]
root_block_device {
volume_size = "${var.osdisk_size}"
}
tags {
Name = "master-tf${format("%02d", count.index + 1)}-${terraform.workspace}"
"kubernetes.io/cluster/openshift-cluster" = "${var.cluster_id}"
}
}
hosted_zone = "yourdomain.com."
domain = "yourdomain.com"
company = "atsistemas"
elb_names = ["openshift-lb-master","openshift-lb-infra"]
As portas que exporão os balanceadores devem ser as mesmas que definimos nos grupos de segurança:
Como você pode ver, em "instâncias" você pode facilmente referenciar as instâncias que criamos antes, independentemente do número de
máquinas que foram criadas.
Para criar o balanceador de carga correspondente a infra, basta alterar as variáveis para que elas se refiram a elas. como fizemos com as
instâncias.
Também definiremos os registros de DNS dinamicamente para que os recursos sejam acessíveis externamente usando o AWS Route 53. Neste
exemplo, a " hosted zone" escapa do life cycle (ciclo de vida), portanto, obtemos os dados da seguinte forma:
Criamos dois registros no hosted_zone, que serão usados para acessar o console e os aplicativos:
Conexão entre Terraform e Ansible
Se soubermos como brincar com as variáveis e as informações fornecidas pela Terraform sobre os recursos criados, podemos vincular o
provisionamento da infraestrutura com a geração de um inventário que podemos usar como objetivo na execução de um playbook Ansible..
Terraform permite que você crie templates nos quais podemos reaproveitar dados que possam ser úteis
Bem, o inventário para instalar o openshift seria algo assim:
Como você pode ver, dependendo do grupo a que pertencem, eles devem incluir uma ou outra informação. Para lidar com isso, posteriormente
definiremos vários templates para gerar as informações necessárias, dependendo do grupo de hosts ou role.
O template final do inventário será o seguinte:
data "aws_route53_zone" "hosted_zone" {
name = "${var.hosted_zone}"
}
resource "aws_route53_record" "openshift" {
zone_id = "${data.aws_route53_zone.hosted_zone.zone_id}" name
= "console.${var.company}.${var.domain}"
type = "CNAME" ttl
= "300"
records = ["${aws_elb.master.dns_name}"]
}
resource "aws_route53_record" "openshift-apps" {*
zone_id = "${data.aws_route53_zone.hosted_zone.zone_id}" name
= "*.apps.${var.company}.${var.domain}"
type = "CNAME" ttl
= "300"
records = ["${aws_elb.infra.dns_name}"]
}
[OSEv3:children]
masters
nodes
etcd
[masters]
ip-172-16-10-x.eu-west-1.compute.internal openshift-ip=172.16.10.x openshift_schedulable=true
[etcd]
ip-172-16-10-x.eu-west-1.compute.internal openshift-ip=172.16.10.x openshift_schedulable=true
[nodes]
ip-172-16-10-x.eu-west-1.compute.internal openshift-ip=172.16.10.x openshift_schedulable=true openshift_node_labels="{'region': 'primary', 'zone': 'east'}" ip-172-16-
20-x.eu-west-1.compute.internal openshift-ip=172.16.20.x openshift_schedulable=true openshift_node_labels="{'region': 'infra', 'zone': 'default'}"
ip-172-16-30-x.eu-west-1.compute.internal openshift-ip=172.16.30.x openshift_schedulable=true openshift_node_labels="{'region': 'primary', 'zone': 'east'}"
...
Como você pode ver, as variáveis nos templates são referências de uma forma diferente: ${variable}. Em um arquivo .tf seria assim:
${var.variable}
Para construir os dados necessários a serem incluídos no inventário, definiremos um template com certas variáveis para gerar as informações
necessárias:
Bem, dependendo da função da máquina, vamos gerar dados diferentes na variável ${data}. Para gerar os dados necessários no grupo [master]
passaremos o texto "openshift_schedulable=true" para a variável ${data}:
Os masters também devem ser incluídos no grupo de hosts [nodes], então geramos as informações necessárias:
[OSEv3:children]
masters
nodes
etcd
[masters]
${master_hosts}
[etcd]
${etcd_hosts}
[nodes]
${master_node_hosts}
${infra_hosts}
${node_hosts}
${name} openshift-ip=${ip} ${data}
data "template_file" "master-inventory" {
count = "${var.master_count}"
template = "${file("templates/hostname.tpl")}" vars
{
name = "${aws_instance.master.*.private_dns[count.index]}" ip
= "${aws_instance.master.*.private_ip[count.index]}" data =
"openshift_schedulable=true"
}
}
data "template_file" "master-node-inventory" {
count = "${var.master_count}"
template = "${file("templates/hostname.tpl")}" vars
{
name = "${aws_instance.master.*.private_dns[count.index]}" ip =
"${aws_instance.master.*.private_ip[count.index]}"
data = "openshift_schedulable=true openshift_node_labels="{'region': 'primary', 'zone': 'east'}""
}
}
Para gerar o template final você tem que definir vários blocos de recursos como o anterior, mas você pode gerar o código do anterior
modificando os recursos dos quais os dados são obtidos. Para infra será:
Para os nodes será:
Por fim, passaremos todas as variáveis que geramos para o template final, que será o que gera o inventário do openshift:
Execução
Já definimos todos os recursos necessários para criar a infraestrutura e vincular a execução do Ansible ao inventário gerado a partir do
Terraform. Para isso:
Uma vez que o inventário for gerado, vamos passá-lo para o bastião e desta máquina vamos executar os playbooks para instalar o openshift
(a deploy levará dependendo do número de máquinas que foram definidas):
data "template_file" "openshift-inventory" {
template = "${file("templates/${var.inventory_template_name}")}" vars {
master_hosts = "${join(" ",data.template_file.master-inventory.*.rendered)}"
master_node_hosts = "${join(" ",data.template_file.master-node-inventory.*.rendered)}"
etcd_hosts = "${join(" ",data.template_file.master-inventory.*.rendered)}" infra_hosts
= "${join(" ",data.template_file.infra-inventory.*.rendered)}"
node_hosts = "${join(" ",data.template_file.node-inventory.*.rendered)}"
aws_access_key_id = "${var.aws_access_key}"
aws_secret_access_key = "${var.aws_secret_key}"
cluster_id = "${var.cluster_id}"
domain = "${var.domain}"
console_master_dns = "${aws_route53_record.openshift.name}"
subdomain_openshift_dns = "apps.${var.company}.${var.domain}"
}
}
name = "${aws_instance.infra.*.private_dns[count.index]}" ip =
"${aws_instance.infra.*.private_ip[count.index]}"
name = "${aws_instance.node.*.private_dns[count.index]}" ip =
"${aws_instance.node.*.private_ip[count.index]}"
terraform plan -var-file='pre.tfvars' -var-file='aws-pre.tfvars' -out='aws-pre.tfplan'
terraform apply "aws-pre.tfplan"
terraform output openshift-inventory > ../openshift-inventory
ansible-playbook -i /home/centos/openshift-inventory openshift-ansible/playbooks/prerequisites.yml
ansible-playbook -i /home/centos/openshift-inventory openshift-ansible/playbooks/deploy_cluster.yml
E aqui, o Openshift está disponível:
Conclusões
Por fim, faremos um breve resumo do post:
Usamos o Terraform para descrever a infraestrutura necessária na AWS para uma deploy completa do Openshift.
O uso de 'workspaces' para a transição entre ambientes (dev/pre/pro)
A infraestrutura foi construída de acordo com o número de instâncias que foram obtidas através de variáveis.
Usamos uma hosted zone já criada para o cluster ser acessível de fora da nossa rede.
Nós geramos o inventário Ansible usando variáveis de output, este passo é o que conecta o Terraform com o Ansible e torna a
instalação dinâmica.
Na última etapa, executamos os comandos necessários para a deploy. Como uma melhoria, isso pode ser incluído em um script para
torná-lo totalmente automático.
Com isso fechamos o post, esperando que você tenha gostado. Não hesite em comentar qualquer dúvida ou detalhe aqui, ou através da nossa
conta Twitter.
Autor
Infraestructura como Código (V): Terraform vs Ansible
Publicado por Alejandro Nieto el 29 May 2019
DevOpsInfraestructura como CódigoTerraformAnsible
No post anterior, falamos sobre tratar a infraestructura como código, simplificar a sua build e todas as
vantagens que isso implica. Mais tarde nós implementamos vários exemplos usando Terraform, mas é
possível que muitos de vocês perguntem O que a Terraform oferece a você em relação ao Ansible, se
você já tem conhecimento neste último. Este é o propósito deste post.
Gerenciamento de configurações & Infrastructure as Code
Ansible (e outros gostam de Chef, Puppet, ...) nasceu como uma ferramenta de “Gerenciamento de
configurações”, Isso significa que ele é projetado para tarefas como instalar e gerenciar software ou
configurar servidores existentes. Isso não significa que a Ansible não seja capaz de lidar com infraestrutura
como um código, na verdade é..
Com o Terraform, apenas nos encarregamos do provisionamento da infraestrutura e deixamos a
configuração do mesmo nas mãos de outras ferramentas (como o Ansible).
Agora você estará pensando que com a Ansible você pode resolver os dois problemas: o provisionamento
da infraestrutura e sua configuração, mas depois você verá as diferenças entre as duas ferramentas, como o
gerenciamento do estado da nossa infraestrutura.
Estilo & Linguagem
Dentro do escopo das ferramentas de DevOps, podemos distinguir as ferramentas que usam um estilo
declarativo e aquelas que têm um estilo procedural.
Se um estilo procedural for usado, é necessário indicar as etapas exatas a seguir em nosso código, como
Ansible, em que uma série de tarefas consecutivas é definida.
Se usarmos uma ferramenta com um estilo declarativo, é necessário apenas indicar o resultado que
queremos com nosso código. Neste caso, Ansible usa um estilo procedural e Terraform um estilo
declarativo.
Estudo de caso
Vamos aplicar alguns exemplos práticos nos quais veremos as informações apresentadas por ambas as
ferramentas ao planejar uma mudança e como elas executam essas mudanças.
Ansible
Para criar um VPC da AWS com o Ansible precisamos do seguinte bloco (assumindo que o provedor já
esteja configurado):
# ansible-aws.yml
- hosts: localhost
connection: local
gather_facts: False
vars:
cidr_block: 10.10.0.0/16
tasks:
- name: create a VPC with dedicated tenancy and a couple of tags
ec2_vpc_net:
name: enmilocalfunciona
cidr_block: "{{ cidr_block }}"
region: eu-west-1
Neste caso, dizemos ao Ansible para criar um VPC com o cidr_block 10.10.0.0/16 e executar o playbook:
$ ansible-playbook ansible-aws.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit
localhost does not match 'all'
PLAY [localhost]
**********************************************************************************************
**********************************************************************************************
******
TASK [create a VPC with dedicated tenancy and a couple of tags]
**********************************************************************************************
*****************************************************
changed: [localhost]
PLAY RECAP
**********************************************************************************************
**********************************************************************************************
************
localhost : ok=1 changed=1 unreachable=0 failed=0
Imagine que queremos mudar um argumento do recurso que criamos, nesse caso podemos alterar o
cidr_block:
# ansible-aws.yml
- hosts: localhost
connection: local
gather_facts: False
vars:
cidr_block: 10.20.0.0/16
tasks:
- name: create a VPC with dedicated tenancy and a couple of tags
ec2_vpc_net:
name: enmilocalfunciona
cidr_block: "{{ cidr_block }}"
region: eu-west-1
Se quisermos obter informações sobre as alterações a serem feitas pelo Ansible, podemos obtê-las da
seguinte forma:
$ ansible-playbook ansible-aws.yml --check
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit
localhost does not match 'all'
PLAY [localhost]
**********************************************************************************************
**********************************************************************************************
******
TASK [create a VPC with dedicated tenancy and a couple of tags]
**********************************************************************************************
*****************************************************
changed: [localhost]
PLAY RECAP
**********************************************************************************************
**********************************************************************************************
************
localhost : ok=1 changed=1 unreachable=0 failed=0
Como você pode ver, a única informação que isso nos dá é que haverá uma mudança, mas não nos diz onde
ou o que vai mudar.
Se executarmos manualmente, veremos que o que ele faz é criar um novo VPC com o cidr_block
10.20.0.0/16 sem modificar o que criamos anteriormente.
Terraform
Vamos realizar exatamente o mesmo com o Terraform. Defina um recurso (neste caso, VPC) e execute-o:
resource "aws_vpc" "enmilocalfunciona" {
cidr_block = "10.10.0.0/16"
enable_dns_hostnames = true
tags {
Name = "enmilocalfunciona"
}
}
Para executar com o Terraform, você deve primeiro criar um plano, que nos mostre informações sobre o
que será executado. Este plano será armazenado em um arquivo, neste caso emmeulocal.tf:
$ terraform plan -var-file='aws.tfvars' -out='emmeulocal.tfplan'
...
+ create
Terraform will perform the following actions:
+ aws_vpc.enmilocalfunciona
id: <computed>
arn: <computed>
assign_generated_ipv6_cidr_block: "false"
cidr_block: "10.10.0.0/16"
...
tags.%: "1"
tags.Name: "enmilocalfunciona"
Plan: 1 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
This plan was saved to: emmeulocal.tfplan
To perform exactly these actions, run the following command to apply:
terraform apply "emmeulocal.tfplan"
Em um ambiente real, esses parâmetros devem ser definidos como variáveis e trabalhar com eles. Neste
caso, vamos alterar o cidr_block para10.20.0.0/16 no código:
resource "aws_vpc" " emmeulocalfunciona" {
cidr_block = "10.20.0.0/16"
enable_dns_hostnames = true
tags {
Name = "emmeulocalfunciona"
}
}
$ terraform plan -var-file='aws.tfvars' -out= emmeulocal.tfplan'
...
-/+ destroy and then create replacement
Terraform will perform the following actions:
-/+ aws_vpc.emmeulocalfunciona (new resource required)
id: "vpc-012a080f9f1f2d6cd" => <computed> (forces new
resource)
arn: "arn:aws:ec2:eu-west-1:104102502792:vpc/vpc-
012a080f9f1f2d6cd" => <computed>
assign_generated_ipv6_cidr_block: "false" => "false"
cidr_block: "10.10.0.0/16" => "10.20.0.0/16" (forces new resource)
...
Plan: 1 to add, 0 to change, 1 to destroy.
------------------------------------------------------------------------
This plan was saved to: emmeulocal.tfplan
To perform exactly these actions, run the following command to apply:
terraform apply "emmeulocal.tfplan"
Sendo uma linguagem declarativa e controlando o estado de nossa infraestrutura, a Terraform entende que
queremos que o VPC tenha um bloco cidr diferente e não crie outro VPC adicional com o bloco cidr que
indicamos, que é o que o Ansible executa.
Ao aplicar o plan:
terraform apply "enmilocal.tfplan"
aws_vpc.enmilocalfunciona: Creating...
arn: "" => "<computed>"
assign_generated_ipv6_cidr_block: "" => "false"
cidr_block: "" => "10.10.0.0/16"
...
enable_dns_hostnames: "" => "true"
enable_dns_support: "" => "true"
instance_tenancy: "" => "default"
ipv6_association_id: "" => "<computed>"
ipv6_cidr_block: "" => "<computed>"
main_route_table_id: "" => "<computed>"
owner_id: "" => "<computed>"
tags.%: "" => "1"
tags.Name: "" => "enmilocalfunciona"
aws_vpc.enmilocalfunciona: Creation complete after 4s (ID: vpc-0f7ad36df5258bbaa)
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Se mais tarde quisermos alterar o recurso, por exemplo, o cidr, eles indicam as mudanças que serão
executadas:
terraform plan -var-file='aws.tfvars' -out='emmeulocal.tfplan'
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
aws_vpc.enmilocalfunciona: Refreshing state... (ID: vpc-0f7ad36df5258bbaa)
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
-/+ aws_vpc.enmilocalfunciona (new resource required)
id: “vpc-0f7ad36df5258bbaa” => <computed> (forces new
resource)
arn: “arn:aws:ec2:eu-west-1:104102502792:vpc/vpc-
0f7ad36df5258bbaa” => <computed>
assign_generated_ipv6_cidr_block: “false” => “false”
cidr_block: “10.10.0.0/16” => “10.20.0.0/16” (forces new resource)
...
tags.Name: “emmeulocalfunciona” => “emmeulocalfunciona”
Plan: 1 to add, 0 to change, 1 to destroy.
------------------------------------------------------------------------
This plan was saved to: enmilocal.tfplan
To perform exactly these actions, run the following command to apply:
terraform apply “emmeulocal.tfplan”
Você pode ver na linha cidr_block qual a mudança será realizada, e se para realizá-lo é necessário destruí-lo
e construí-lo novamente:
cidr_block: “10.10.0.0/16” => “10.20.0.0/16” (forces new resource)
Aplicamos o plan atualizado novamente e observamos como o recurso é destruído e criado novamente:
aws_vpc.enmilocalfunciona: Destroying... (ID: vpc-0f7ad36df5258bbaa)
aws_vpc.enmilocalfunciona: Destruction complete after 0s
aws_vpc.enmilocalfunciona: Creating...
arn: ““ => “<computed>“
assign_generated_ipv6_cidr_block: ““ => “false”
cidr_block: ““ => “10.20.0.0/16”
...
tags.Name: ““ => “emmeulocalfunciona”
aws_vpc.enmilocalfunciona: Creation complete after 4s (ID: vpc-0ca954b8c15912e69)
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
➜ enmilocalfunciona
Conclusão
Ambas as ferramentas são poderosas e fáceis de aprender. Se você já conhece Ansible ou quer ter todo o
código unificado (Configuration Management e IaC), você pode achar o Ansible mais atraente. Se você não
conhece nenhuma das ferramentas, quer separar responsabilidades e obter mais informações, aplicar
GitOps, etc., é possível que o Terraform seja o mais atraente para você. A escolha é sua, mas Terraform é
uma ferramenta mais completa em termos de Infraestrutura como Código.
Se você gostou, siga-nos no Twitter para se manter atualizado sobre as próximas postagens!
Infraestructura como Código (I) y (II): Terraform en Azure

Mais conteúdo relacionado

Mais procurados

Nbr iec 61439 1 - 2016 - versão corrigida-2017 - conjuntos de manobra e coman...
Nbr iec 61439 1 - 2016 - versão corrigida-2017 - conjuntos de manobra e coman...Nbr iec 61439 1 - 2016 - versão corrigida-2017 - conjuntos de manobra e coman...
Nbr iec 61439 1 - 2016 - versão corrigida-2017 - conjuntos de manobra e coman...EdmilsonNDosSantos
 
Material de Apoio de Algoritmo e Lógica de Programação
Material de Apoio de Algoritmo e Lógica de ProgramaçãoMaterial de Apoio de Algoritmo e Lógica de Programação
Material de Apoio de Algoritmo e Lógica de Programaçãorodfernandes
 
Pop+ +procedimento+operacional+padrao
Pop+ +procedimento+operacional+padraoPop+ +procedimento+operacional+padrao
Pop+ +procedimento+operacional+padraoGlaucione Garcia
 
Relatorio dos equipamentos eletricos
Relatorio dos equipamentos eletricosRelatorio dos equipamentos eletricos
Relatorio dos equipamentos eletricosEdson da Silva
 
Desenvolvendo Apps Nativos com Flutter
Desenvolvendo Apps Nativos com FlutterDesenvolvendo Apps Nativos com Flutter
Desenvolvendo Apps Nativos com FlutterPaulo Henrique
 
Apresentando a Linguagem de Programação Python
Apresentando a Linguagem de Programação PythonApresentando a Linguagem de Programação Python
Apresentando a Linguagem de Programação PythonPriscila Mayumi
 
Git e GitHub: Versionamento de Código Fácil
Git e GitHub: Versionamento de Código FácilGit e GitHub: Versionamento de Código Fácil
Git e GitHub: Versionamento de Código FácilTiago Antônio da Silva
 
FlD02 formulário levantamento sobre o nível de serviços de TI (V1)
FlD02   formulário levantamento sobre o nível de serviços  de TI (V1)FlD02   formulário levantamento sobre o nível de serviços  de TI (V1)
FlD02 formulário levantamento sobre o nível de serviços de TI (V1)Saulo Oliveira
 
Orientação a objetos em Python (compacto)
Orientação a objetos em Python (compacto)Orientação a objetos em Python (compacto)
Orientação a objetos em Python (compacto)Luciano Ramalho
 
Aumentando a produtividade e Automatizando Processos com Jira
Aumentando a produtividade e Automatizando Processos com JiraAumentando a produtividade e Automatizando Processos com Jira
Aumentando a produtividade e Automatizando Processos com JiraLuís Cesar Teodoro
 
Introdução ao Web Design: Aula 1 - Imersão ao Web Design
Introdução ao Web Design: Aula 1 - Imersão ao Web DesignIntrodução ao Web Design: Aula 1 - Imersão ao Web Design
Introdução ao Web Design: Aula 1 - Imersão ao Web DesignGustavo Zimmermann
 
Algoritmos e lógica de programação com Python
Algoritmos e lógica de programação com PythonAlgoritmos e lógica de programação com Python
Algoritmos e lógica de programação com PythonBruno Luvizotto Carli
 
Python Módulo Básico - Introdução a linguagem Python
Python Módulo Básico - Introdução a linguagem PythonPython Módulo Básico - Introdução a linguagem Python
Python Módulo Básico - Introdução a linguagem Pythonantonio sérgio nogueira
 
Apostila Java Web (Servlets e JSPs)
Apostila Java Web (Servlets e JSPs)Apostila Java Web (Servlets e JSPs)
Apostila Java Web (Servlets e JSPs)Ricardo Terra
 
Lista de exercícios em portugol
Lista de exercícios em portugolLista de exercícios em portugol
Lista de exercícios em portugolGabriel Faustino
 

Mais procurados (20)

Python - Introdução
Python - IntroduçãoPython - Introdução
Python - Introdução
 
Introdução à linguagem python
Introdução à linguagem pythonIntrodução à linguagem python
Introdução à linguagem python
 
Modelo Planilha Qualificacao Tecnica
Modelo Planilha Qualificacao TecnicaModelo Planilha Qualificacao Tecnica
Modelo Planilha Qualificacao Tecnica
 
Kanban para Desenvolvimento de Software
Kanban para Desenvolvimento de SoftwareKanban para Desenvolvimento de Software
Kanban para Desenvolvimento de Software
 
Nbr iec 61439 1 - 2016 - versão corrigida-2017 - conjuntos de manobra e coman...
Nbr iec 61439 1 - 2016 - versão corrigida-2017 - conjuntos de manobra e coman...Nbr iec 61439 1 - 2016 - versão corrigida-2017 - conjuntos de manobra e coman...
Nbr iec 61439 1 - 2016 - versão corrigida-2017 - conjuntos de manobra e coman...
 
Material de Apoio de Algoritmo e Lógica de Programação
Material de Apoio de Algoritmo e Lógica de ProgramaçãoMaterial de Apoio de Algoritmo e Lógica de Programação
Material de Apoio de Algoritmo e Lógica de Programação
 
Pop+ +procedimento+operacional+padrao
Pop+ +procedimento+operacional+padraoPop+ +procedimento+operacional+padrao
Pop+ +procedimento+operacional+padrao
 
Relatorio dos equipamentos eletricos
Relatorio dos equipamentos eletricosRelatorio dos equipamentos eletricos
Relatorio dos equipamentos eletricos
 
Desenvolvendo Apps Nativos com Flutter
Desenvolvendo Apps Nativos com FlutterDesenvolvendo Apps Nativos com Flutter
Desenvolvendo Apps Nativos com Flutter
 
Apresentando a Linguagem de Programação Python
Apresentando a Linguagem de Programação PythonApresentando a Linguagem de Programação Python
Apresentando a Linguagem de Programação Python
 
Git e GitHub: Versionamento de Código Fácil
Git e GitHub: Versionamento de Código FácilGit e GitHub: Versionamento de Código Fácil
Git e GitHub: Versionamento de Código Fácil
 
FlD02 formulário levantamento sobre o nível de serviços de TI (V1)
FlD02   formulário levantamento sobre o nível de serviços  de TI (V1)FlD02   formulário levantamento sobre o nível de serviços  de TI (V1)
FlD02 formulário levantamento sobre o nível de serviços de TI (V1)
 
Orientação a objetos em Python (compacto)
Orientação a objetos em Python (compacto)Orientação a objetos em Python (compacto)
Orientação a objetos em Python (compacto)
 
Aumentando a produtividade e Automatizando Processos com Jira
Aumentando a produtividade e Automatizando Processos com JiraAumentando a produtividade e Automatizando Processos com Jira
Aumentando a produtividade e Automatizando Processos com Jira
 
Introdução ao Web Design: Aula 1 - Imersão ao Web Design
Introdução ao Web Design: Aula 1 - Imersão ao Web DesignIntrodução ao Web Design: Aula 1 - Imersão ao Web Design
Introdução ao Web Design: Aula 1 - Imersão ao Web Design
 
Algoritmos e lógica de programação com Python
Algoritmos e lógica de programação com PythonAlgoritmos e lógica de programação com Python
Algoritmos e lógica de programação com Python
 
Python Módulo Básico - Introdução a linguagem Python
Python Módulo Básico - Introdução a linguagem PythonPython Módulo Básico - Introdução a linguagem Python
Python Módulo Básico - Introdução a linguagem Python
 
Apostila Java Web (Servlets e JSPs)
Apostila Java Web (Servlets e JSPs)Apostila Java Web (Servlets e JSPs)
Apostila Java Web (Servlets e JSPs)
 
Lista de exercícios em portugol
Lista de exercícios em portugolLista de exercícios em portugol
Lista de exercícios em portugol
 
Estrutura de diretorios
Estrutura de diretoriosEstrutura de diretorios
Estrutura de diretorios
 

Semelhante a Infraestructura como Código (I) y (II): Terraform en Azure

DDD e Microsservicos - do negócio à arquitetura
DDD e Microsservicos - do negócio à arquiteturaDDD e Microsservicos - do negócio à arquitetura
DDD e Microsservicos - do negócio à arquiteturaGraziella Bonizi
 
Function as a Service: IT forum expo 2017
Function as a Service: IT forum expo 2017Function as a Service: IT forum expo 2017
Function as a Service: IT forum expo 2017Igor Rosa Macedo
 
Tendências e Dicas para o Desenvolvimento de Software
Tendências e Dicas para o Desenvolvimento de SoftwareTendências e Dicas para o Desenvolvimento de Software
Tendências e Dicas para o Desenvolvimento de SoftwareNorberto Santos
 
Phprs meetup - deploys automatizados com gitlab
Phprs   meetup - deploys automatizados com gitlabPhprs   meetup - deploys automatizados com gitlab
Phprs meetup - deploys automatizados com gitlabJackson F. de A. Mafra
 
O desafio de sustentar centenas de servicos
O desafio de sustentar centenas de servicosO desafio de sustentar centenas de servicos
O desafio de sustentar centenas de servicosGraziella Bonizi
 
Como DDD e Strategic Design estão nos ajudando a modernizar um Legado
Como DDD e Strategic Design estão nos ajudando a modernizar um LegadoComo DDD e Strategic Design estão nos ajudando a modernizar um Legado
Como DDD e Strategic Design estão nos ajudando a modernizar um LegadoLuiz Costa
 
Operações - Base de Conhecimento - Parte 01
Operações - Base de Conhecimento - Parte 01Operações - Base de Conhecimento - Parte 01
Operações - Base de Conhecimento - Parte 01Alan Carlos
 
The Ultimate Guide to Development in WordPress
The Ultimate Guide to Development in WordPressThe Ultimate Guide to Development in WordPress
The Ultimate Guide to Development in WordPressJackson F. de A. Mafra
 
Pangea - Plataforma digital com Google Cloud Platform
Pangea - Plataforma digital com Google Cloud PlatformPangea - Plataforma digital com Google Cloud Platform
Pangea - Plataforma digital com Google Cloud PlatformAndré Paulovich
 
Ferramenta de Cloud Computer para apoio à Engenharia de Software
Ferramenta de Cloud Computer para apoio à Engenharia de SoftwareFerramenta de Cloud Computer para apoio à Engenharia de Software
Ferramenta de Cloud Computer para apoio à Engenharia de SoftwareDanilo Sousa
 
DevOps & Docker com a stack Microsoft
DevOps & Docker com a stack MicrosoftDevOps & Docker com a stack Microsoft
DevOps & Docker com a stack MicrosoftGraziella Bonizi
 
Trabalho 4 Semestre e 5 Semestre 2015
Trabalho 4 Semestre e 5 Semestre 2015Trabalho 4 Semestre e 5 Semestre 2015
Trabalho 4 Semestre e 5 Semestre 2015Rodrigo Marinho
 
Boas Práticas de programação WordPress
Boas Práticas de programação WordPressBoas Práticas de programação WordPress
Boas Práticas de programação WordPressThiago Mendes
 
Construindo aplicações Cloud Native em Go
Construindo aplicações Cloud Native em GoConstruindo aplicações Cloud Native em Go
Construindo aplicações Cloud Native em GoAlvaro Viebrantz
 

Semelhante a Infraestructura como Código (I) y (II): Terraform en Azure (20)

Escalando apps com React e Type Script e SOLID
Escalando apps com React e Type Script e SOLIDEscalando apps com React e Type Script e SOLID
Escalando apps com React e Type Script e SOLID
 
DDD e Microsservicos - do negócio à arquitetura
DDD e Microsservicos - do negócio à arquiteturaDDD e Microsservicos - do negócio à arquitetura
DDD e Microsservicos - do negócio à arquitetura
 
Function as a Service: IT forum expo 2017
Function as a Service: IT forum expo 2017Function as a Service: IT forum expo 2017
Function as a Service: IT forum expo 2017
 
Tendências e Dicas para o Desenvolvimento de Software
Tendências e Dicas para o Desenvolvimento de SoftwareTendências e Dicas para o Desenvolvimento de Software
Tendências e Dicas para o Desenvolvimento de Software
 
Phprs meetup - deploys automatizados com gitlab
Phprs   meetup - deploys automatizados com gitlabPhprs   meetup - deploys automatizados com gitlab
Phprs meetup - deploys automatizados com gitlab
 
O desafio de sustentar centenas de servicos
O desafio de sustentar centenas de servicosO desafio de sustentar centenas de servicos
O desafio de sustentar centenas de servicos
 
Servico ad
Servico adServico ad
Servico ad
 
Revista programar 12
Revista programar 12Revista programar 12
Revista programar 12
 
Como DDD e Strategic Design estão nos ajudando a modernizar um Legado
Como DDD e Strategic Design estão nos ajudando a modernizar um LegadoComo DDD e Strategic Design estão nos ajudando a modernizar um Legado
Como DDD e Strategic Design estão nos ajudando a modernizar um Legado
 
Operações - Base de Conhecimento - Parte 01
Operações - Base de Conhecimento - Parte 01Operações - Base de Conhecimento - Parte 01
Operações - Base de Conhecimento - Parte 01
 
Artigo cloud computing pdf
Artigo cloud computing pdfArtigo cloud computing pdf
Artigo cloud computing pdf
 
The Ultimate Guide to Development in WordPress
The Ultimate Guide to Development in WordPressThe Ultimate Guide to Development in WordPress
The Ultimate Guide to Development in WordPress
 
Pangea - Plataforma digital com Google Cloud Platform
Pangea - Plataforma digital com Google Cloud PlatformPangea - Plataforma digital com Google Cloud Platform
Pangea - Plataforma digital com Google Cloud Platform
 
Ferramenta de Cloud Computer para apoio à Engenharia de Software
Ferramenta de Cloud Computer para apoio à Engenharia de SoftwareFerramenta de Cloud Computer para apoio à Engenharia de Software
Ferramenta de Cloud Computer para apoio à Engenharia de Software
 
DevOps & Docker com a stack Microsoft
DevOps & Docker com a stack MicrosoftDevOps & Docker com a stack Microsoft
DevOps & Docker com a stack Microsoft
 
Trabalho 4 Semestre e 5 Semestre 2015
Trabalho 4 Semestre e 5 Semestre 2015Trabalho 4 Semestre e 5 Semestre 2015
Trabalho 4 Semestre e 5 Semestre 2015
 
Java no Google App Engine - TDC2011
Java no Google App Engine - TDC2011Java no Google App Engine - TDC2011
Java no Google App Engine - TDC2011
 
Boas Práticas de programação WordPress
Boas Práticas de programação WordPressBoas Práticas de programação WordPress
Boas Práticas de programação WordPress
 
Construindo aplicações Cloud Native em Go
Construindo aplicações Cloud Native em GoConstruindo aplicações Cloud Native em Go
Construindo aplicações Cloud Native em Go
 
Artigo Bruno Rodrigues Spark Toolkit 0317
Artigo Bruno Rodrigues Spark Toolkit 0317Artigo Bruno Rodrigues Spark Toolkit 0317
Artigo Bruno Rodrigues Spark Toolkit 0317
 

Infraestructura como Código (I) y (II): Terraform en Azure

  • 1. Infraestructura como Código (I) Publicado por Ignacio Sánchez Ginés el 08 May 2017 DevOpsInfraestructuraEntrega ContinuaCloudInfraestructura como Código É fato que as metodologias ágeis vieram para ficar. Empresas com visão estão começando a reduzir drasticamente o Time To Market , enquanto aumentam a qualidade de seu produto final, adotando frameworks ágeis, como Scrum ou Kanban. Mas em muitas ocasiões a infra-estrutura ainda é um gargalo. O problema Normalmente, descobrimos que essas metodologias são aplicadas apenas no desenvolvimento de aplicativos. Elementos importantes como infraestructura, qualidade e gestão dos dados, normalmente estão fora do framework de aplicativos Agil. É comum ver equipes de programadores trabalhando em sprints semanais, com cerimônias e lançamentos no final da semana. Mas quando eles têm que colocar seu produto para funcionar em um dos ambientes corporativos, eles são vítimas de um processo baseado em ”solicitação/resposta”. Além disso, este “pedido/resposta” é normalmente necessário para todos: Para pedir um passar entre ambientes, para pedir a build de um novo ambiente, para solicitar alterações na configuração e um longo etc.. Na maioria dos casos, são processos burocráticos, desatualizado e muito lento: planilhas de Excel enviadas por e-mail que tem que aprovar várias pessoas ... você sabe o que significa? Este é geralmente o caso porque o departamento de infra-estrutura (chama-se “produção” ou chamamos de “sistemas”) são “verticalizados” e orientado como serviço. Muitas vezes acontece que esse departamento não é informado dos requisitos até que seja tarde demais e acaba pedindo uma infraestrutura que não foi planejada, que é entregue semanas depois com inúmeros problemas.: desempenho, capacidade, escalabilidade, resiliência, ... Visto desta forma, é fácil entender que, do ponto de vista de Time To Market, estamos limitando a agilidade da equipe. Mas o que podemos fazer?
  • 2. A solução A primeira coisa é pensar em produto e não em serviço. O Departamento de Desenvolvimento já recebeu uma boa manobra para alinhar com as reais necessidades do Negócio. Eles foram distribuídos em equipes orientado para produtos. Por que não fazemos o mesmo com o departamento de infraestrutura? Se as pessoas desse departamento fizessem parte das equipes que desenvolvem os produtos, cada uma delas só precisaria se preocupar com o produto., dos servidores do seu produto, as redes do seu produto, o armazenamento do seu produto, as regras de firewall do seu produto, etc. Se eles também fizeram parte da equipe do começo ao fim como um dos times, poderia dar uma solução correta para os requisitos não-funcionais, aceitar alterações a qualquer momento e se adaptar às necessidades reais do aplicativo à medida que se desenvolve, com controle contínuo da infra-estrutura necessária. Mas, claro, criar um ambiente leva dias ou semanas! Instalar um sistema operacional, plataforma de uma máquina, atualizá-lo, configurá-lo, requer muito tempo. E os ambientes têm muitas máquinas! Acima, uma vez que o ambiente é criado, é facilmente corrompido, perde o alinhamento com outros ambientes (desenvolvimento e produção sempre foram os mesmos?), a execução de testes de usuário os bloqueia por semanas e problemas sem fim decorrentes da operação manual. Está claro: necesitamos AUTOMAÇÃO. Agora, a automação só é possível se nossa infraestrutura for virtualizada. Mas não só isso, precisamos que a virtualização tenha uma API de controle. Não adianta para nós que tudo seja virtualizado se cada vez que precisarmos de um novo elemento, tivermos que entrar nos consoles de gerenciamento. Felizmente, os provedores de IaaS na nuvem e a maioria dos sistemas já virtualizam hardware ”on premise” e eles já nos oferecem a API que precisamos. As ferramentas A evolução que os processos de desenvolvimento sofreram durante estes últimos anos é evidente. Os programadores têm ferramentas para escrever código em arquivos de texto de uma forma paralela, distribuida e totalmente descentralizada (Git e Gitflow, por ejemplo). Por que não nos aproveitamos deles? Se você já ouviu falar sobre DevOps, você terá reconhecido instantaneamente: é a abordagem das Operações para o Desenvolvimento e vice-versa. Escrever infra-estrutura em um arquivo de texto como se você fosse um programador já é possível. Se incluirmos esses arquivos de texto como parte do ciclo de vida de nossos produtos, poderemos ter as mesmas vantagens: Versionamento de infraestrutura!, Gerenciamento de dependência de infraestrutura! Integração contínua de infraestrutura! Teste de infraestrutura automatizado! Soa bem. Como fazemos? Na Amazon AWS, você pode usar CloudFormation. Azure tem Resource Manager.
  • 3. E no OpenStack existe Heat. Essas três soluções são proprietárias e, obviamente, só funcionam com seus produtos. Mas há uma ferramenta que não se importa com o fornecedor e temos o : Terraform. Com o Terraform você pode escrever (descrever) infra-estrutura em arquivos de texto para qualquer um deles ou para todos de uma vez! Sua linguagem declarativa é orientada para ser escrita por humanos e é muito fácil de aprender. Na próxima parte deste artigo descrevemos Terraform como um cenário real na Azure com vários elementos típicos de uma moderna infra-estrutura (redes, VMs, balanceadores, armazenamento). Siga-nos no Twitter para não perder os próximos posts! A propósito, em relação a este tópico, temos um artigo neste blog sobre como criar Configuração do ambiente como dependência usando Gradle.
  • 4. Infraestructura como Código (II): Terraform Publicado por Ignacio Sánchez Ginés el 03 August 2017 DevOpsInfraestructuraEntrega ContinuaCloudMicrosoft AzureTerraformInfraestructura como Código A infraestrutura como um código é um elemento-chave nas equipes de agilidade. No artigo anterior Vimos a importância de orientar nossa infra-estrutura para produto e como o Terraform pode nos ajudar a acelerar seu build e manutenção de forma automatizada. Nosso objetivo Neste artigo, veremos um exemplo prático: descreveremos a infraestrutura no Azure usando o Terraform. Para isso, teremos o seguinte repositório do GitHub onde tudo está pronto para que você não precise escrever nada: https://github.com/drhelius/terraform-azure-demo Este é o nosso objetivo desse cenário: Criaremos um cluster de máquinas que exporá o mesmo aplicativo na porta 8080. Cada máquina terá seu próprio disco virtual dentro da mesma conta de armazenamento. Para garantir a alta disponibilidade do serviço e a distribuição uniforme da carga, usaremos um balanceador(LB). Configuraremos o LB para incluir automaticamente todas as máquinas que compõem o cluster, ou seja, aquelas que estão no mesmo conjunto de disponibilidade e cujo serviço está operacional.. Se, ao contrário, o serviço deles estiver indisponível, eles serão removidos do grupo de balanceamento.
  • 5. Este último será alcançado colocando uma sonda, ou Probe, para verificar a porta 8080 de cada máquina. Finalmente, para acessar do lado de fora, vamos atribuir um IP público ao LB, abrir a porta 80 e mapeá-lo para a porta 8080 das máquinas que fazem parte do cluster. Mãos à obra Antes de começarmos, teremos que preparar nossa conta do Azure para poder usá-la com o Terraform, para o qual seguiremos a documentação oficial. Após essa etapa, teremos as credenciais necessárias para vincular o Terraform à nossa conta da Azure. Vamos começar criando uma pasta para o nosso projeto e dentro do arquivo demo.tf, onde iremos descrever todos os elementos da infraestrutura para este artigo. Você pode ver o arquivo completo aqui: https://github.com/drhelius/terraform-azure- demo/blob/master/demo.tf Antes de criar o Grupo de Recursos, devemos fornecer os dados necessários do Provider da Azure: provider “azurerm” { client_id = “${var.azure_client_id}” client_secret = “${var.azure_client_secret}” subscription_id = “${var.azure_subscription_id}” tenant_id = “${var.azure_tenant_id}” } Uma vez que a forma de “conectarmos” podemos declarar nosso novo Resource Group: resource “azurerm_resource_group” “demo” { name = “demo-terraform” location = “${var.azure_location}” } Como você pode ver, a configuração do provedor é feita com variáveis. As variáveis no Terraform são assim: ${var.mi_variable} Estas variáveis devem ser declaradas em um arquivo chamado variables.tf: variable “azure_client_id” { type = “string” } variable “azure_client_secret” { type = “string” } variable “azure_location” { type = “string” default = “West Europe” } variable “azure_subscription_id” { type = “string” } variable “azure_tenant_id” {
  • 6. type = “string” } variable “demo_instances” { type = “string” default = “2” } variable “demo_admin_password” { type = “string” } Na declaração, podemos colocar valores padrão. O resto do valor que podemos fornecer de muitas formas: por linha de comando, como variables de ambiente, usando Vault ou usando um arquivo especial chamado terraform.tfvars. Este arquivo é útil para variáveis sensíveis que queremos fornecer localmente. Nós o colocamos na raiz do projeto e o Terraform o lê automaticamente quando realizamos qualquer operação: azure_client_id = “xxxxxx-xx-xx-xx-xxxxxxx” azure_tenant_id = “xxxxxx-xx-xx-xx-xxxxxxx” azure_client_secret = “xxxx” azure_subscription_id = “xxxxxx-xx-xx-xx-xxxxxxx” Em seguida, declaramos os dados da rede privada para o cluster: resource “azurerm_virtual_network” "demo" { name = “demo-virtual-network” address_space = [“10.0.0.0/16”] location = “${var.azure_location}” resource_group_name = “${azurerm_resource_group.demo.name}” } resource “azurerm_subnet” “demo” { name = “demo-subnet" resource_group_name = “${azurerm_resource_group.demo.name}" virtual_network_name = "${azurerm_virtual_network.demo.name}" address_prefix = "10.0.1.0/24" } Podemos ver que na referência de sub-rede é feita para a rede virtual já declarada. A ordem de declaração no arquivo não é importante. Continuamos com um IP público para o LB e com uma interface de rede (NIC) que utilizaremos em cada VM: resource "azurerm_public_ip" "demo" { name = "demo-public-ip" location = "${var.azure_location}" resource_group_name = "${azurerm_resource_group.demo.name}" public_ip_address_allocation = "static" } resource "azurerm_network_interface" "demo" { count = "${var.demo_instances}" name = "demo-interface-${count.index}" location = "${var.azure_location}" resource_group_name = "${azurerm_resource_group.demo.name}" ip_configuration { name = "demo-ip-${count.index}" subnet_id = "${azurerm_subnet.demo.id}" private_ip_address_allocation = "dynamic" load_balancer_backend_address_pools_ids = ["${azurerm_lb_backend_address_pool.demo.id}"]
  • 7. } } Nós usamos um atributo chamado ”count” para criar mais de um elemento do tipo “azurerm_network_interface” e para isso nós usamos um variável (var.demo_instances). Continuamos com todos os elementos necessários para criar o balanceador no Azure: LB, regra de balanceamento, probe, pool addres e conjunto de disponibilidade. Todos eles devidamente referenciados entre si: resource "azurerm_lb" "demo" { name = "demo-lb" location = "${var.azure_location}" resource_group_name = "${azurerm_resource_group.demo.name}" frontend_ip_configuration { name = "default" public_ip_address_id = "${azurerm_public_ip.demo.id}" private_ip_address_allocation = "dynamic" } } resource "azurerm_lb_rule" “demo" { name = “demo-lb-rule-80-8080" resource_group_name = “${azurerm_resource_group.demo.name}" loadbalancer_id = “${azurerm_lb.demo.id}" backend_address_pool_id = "${azurerm_lb_backend_address_pool.demo.id}" probe_id = "${azurerm_lb_probe.demo.id}" protocol = "tcp" frontend_port = 80 backend_port = 8080 frontend_ip_configuration_name = "default" } resource "azurerm_lb_probe" "demo" { name = "demo-lb-probe-8080-up" loadbalancer_id = "${azurerm_lb.demo.id}" resource_group_name = "${azurerm_resource_group.demo.name}" protocol = "Http" request_path = "/" port = 8080 } resource "azurerm_lb_backend_address_pool" "demo" { name = "demo-lb-pool" resource_group_name = "${azurerm_resource_group.demo.name}" loadbalancer_id = "${azurerm_lb.demo.id}" } resource "azurerm_availability_set" "demo" { name = "demo-availability-set" location = "${var.azure_location}" resource_group_name = "${azurerm_resource_group.demo.name}" } O que conseguimos é que o LB equilibre as máquinas que usam IPs do pool de endereços. Continuamos com o armazenamento, um container por VM na mesma conta de armazenamento: resource "azurerm_storage_account" "demo" { name = "demoterraformstorage" resource_group_name = "${azurerm_resource_group.demo.name}" location = "${var.azure_location}" account_type = "Standard_LRS" }
  • 8. resource "azurerm_storage_container" "demo" { count = "${var.demo_instances}" name = "demo-storage-container-${count.index}" resource_group_name = "${azurerm_resource_group.demo.name}" storage_account_name = "${azurerm_storage_account.demo.name}" container_access_type = "private" } E finalmente a descrição da própria VM: resource "azurerm_virtual_machine" "demo" { count = "${var.demo_instances}" name = "demo-instance-${count.index}" location = "${var.azure_location}" resource_group_name = "${azurerm_resource_group.demo.name}" network_interface_ids = ["${element(azurerm_network_interface.demo.*.id, count.index)}"] vm_size = "Standard_A0" availability_set_id = "${azurerm_availability_set.demo.id}" storage_image_reference { publisher = "Canonical" offer = "UbuntuServer" sku = "16.04-LTS" version = "latest" } storage_os_disk { name = "demo-disk-${count.index}" vhd_uri = "${azurerm_storage_account.demo.primary_blob_endpoint}${element(azurerm_storage_container.demo .*.name, count.index)}/demo.vhd" caching = "ReadWrite" create_option = "FromImage" } delete_os_disk_on_termination = true delete_data_disks_on_termination = true os_profile { computer_name = "demo-instance-${count.index}" admin_username = "demo" admin_password = "${var.demo_admin_password}" custom_data = "${base64encode(file(“${path.module}/provision.sh"))}" } os_profile_linux_config { disable_password_authentication = false } } Com tudo isso preparado e localizado no caminho onde o nosso arquivo demo.tf está localizado, nós executamos este comando: $ terraform init Que inicializa nosso projeto e baixa os providers necessários, no nosso caso o Azure. Então podemos executar o seguinte: $ terraform plan
  • 9. Este comando nos informa sem fazer alterações do que aconteceria se aplicássemos a configuração que descrevemos. Nos solicitará por linha de comando o valor daquelas variáveis que não estabelecemos. No nosso caso, a senha das VMs: var.demo_admin_password Enter a value: Mais tarde, veremos uma descrição dos recursos que seriam criados ou modificados na Azure: Plan: 16 to add, 0 to change, 0 to destroy. Estamos prontos para aplicar as alterações e tudo é criado automaticamente na Azure. Para isso, executamos o seguintecomando: $ terraform apply Pouco a pouco, os elementos começarão a ser criados. Uma vez terminado, informe-nos do resultado e mostre-nos as variáveis de saída (outputs) que definimos no arquivo output.tf, no nosso caso, o IP público do LB: output "lb_public_ip" { value = "${azurerm_public_ip.demo.ip_address}" } Nós veríamos algo assim: Apply complete! Resources: 16 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. State path: Outputs: lb_public_ip = 52.233.156.135 Neste momento podemos colocar o IP público em nosso navegador e testá-lo. O aplicativo de amostra é um serviço da web dentro de um container do Docker que retorna o nome do host do container em que está sendo executado. Toda vez que atualizamos a página, devemos ver até dois nomes de host diferentes: Hello World from host “d270d4254e38”. Agora vamos modificar o valor da variável demo_instances no arquivo variables.tf e aumentá-lo, por exemplo, para 4: variable “demo_instances” { type = “string” default = “4” }
  • 10. Voltamos a executar o comando terraform apply e veremos como os elementos ausentes serão criados, o resto fica como está: Apply complete! Resources: 6 added, 0 changed, 0 destroyed. Ou seja, as duas novas VMs com suas interfaces de rede, o armazenamento será criado, etc. Além disso, eles serão incluídos no grupo de balanceamento e o aplicativo estará disponível a partir de 4 servidores usando o IP público do LB. Podemos colocar o IP público novamente no nosso navegador para testá-lo. Toda vez que atualizamos a página, devemos ver até 4 nomes de host diferentes. Se entramos em nossa conta da Azure, veríamos todos os elementos criados: Este é apenas o começo porque com o Terraform podemos modelar cenários muito mais complexos, com centenas de elementos e todos os versionados sob o Git ou qualquer outro SCM. Para acompanhar os próximos capítulos desta série sobre infra-estrutura, como código e outros posts, siga- nos Twitter!
  • 11. Infraestrutura como Código (III): Terraform e AWS Publicado por Carlos M. Cornejo el 07 November 2017 DevOpsEntrega ContinuaCloudTerraformAmazon AWSInfraestructura como Código No artigo anteriormente estávamos falando do Terraform e como descrever infra-estrutura para seu uso na Microsoft Azure. Nesta parte, vamos nos concentrar em como replicar a infraestrutura que criamos no Azure, mas, dessa vez, vamos fornecê-la emAWS. Antes de analisar como vamos implementar o exemplo na AWS, vamos analisar alguns conceitos básicos. Apresentação da AWS Conceitos de rede de EC2 na AWS O serviço gerenciado da Amazon EC2 pode ser hospedado em vários locais ao redor do mundo, mais conhecida como Região. Por sua vez, dentro de cada Região existem áreas de disponibilidade, a partir de agora AZ's (Availabily Zones). A Amazon EC2 permite colocar recursos, como instâncias e dados de EC2, em vários AZ's. A Amazon Virtual Private Cloud (VPC) permite que você execute recursos da AWS em uma rede virtual, que por padrão é separado no nível lógico de outras redes. As VPCs dentro da AWS podem ser configuradas com um intervalo de IPs, tabelas de roteamento, sub-redes, gateways de rede e parâmetros de segurança, como ACLs (access control lists) Uma sub-rede agrupa um intervalo de IPs dentro de um VPC. Cada sub-rede reside exclusivamente dentro de uma AZ. Por sua vez, uma sub-rede pode ser pública ou privada. Uma sub-rede pública é acessível pela Internet, enquanto uma sub-rede privada é usada para os recursos que não devem ser diretamente expostos à Internet, como um banco de dados.. Um security group representa um firewall virtual que controla o tráfego de uma ou mais instâncias do EC2. Quando uma instância do EC2 é iniciada, é necessário associar pelo menos um security group a essa instância. Para permitir tráfego de/para a instância, é necessário criar regras (rules). Essas regras podem ser modificadas a qualquer momento e são aplicadas automaticamente a todas as instâncias associadas ao security group. Para mais detalhes sobre esses conceitos, consulte a documentação oficial da AWS:  Regiões e AZ's  Introdução a VPC  VPC e Subnets  Grupos de segurança na Amazon EC2
  • 12. Criação de um novo usuario IAM Para interagir com a API da AWS, precisamos criar um usuário e atribuir uma policy que permita criar recursos dentro da EC2. Este usuário será aquele que o Terraform usa internamente para se comunicar com a API da AWS. Com base no fato de que temos uma conta criada na AWS, o seguir mostramos como criar um novo usuário IAM(Identity and Access Management). Nós selecionamos IAM: Criamos o usuário e selecionamos o Programatic access. Isso nos permitirá configurar as credenciais de acesso que usaremos com o Terraform:
  • 13. Selecionamos as permissões necessárias para podermos usar os recursos de EC2. Nós devemos selecionar o grupo ec2-FullAccess: Nós criamos o usuário: Na última etapa, devemos salvar as credenciais (Access key ID y Secret access key) Na postagem anterior, mencionamos como configurar credenciais, mas dessa vez vamos configurá-lo por meio das credenciais aws cli em ~/.aws/credentials. Desta forma, quando executamos o Terraform, eles serão localizadas automaticamente com nossas credenciais
  • 14. Finalmente, vamos configurar a chave de acesso SSH que precisamos para criar instâncias EC2. Observe que cada chave SSH é local para cada Região, com o qual nós temos que ter certeza que quando nós executarmos este exemplo nós criamos a chave na mesma Região que é usada em variables.tf En nuestro ejemplo, vamos a utilizar la Region London: Seleccionamos Key Pairs: Create Key Pair como enmilocalfunciona-terraform-key-eu-west-2 Como veremos mais adiante, essa chave é a que usaremos quando usarmos o recurso correspondente de EC2. Terraform e AWS No ponto anterior, descrevemos e explicamos uma série de elementos necessários para entender o modo como a AWS trabalha no nível de rede. Assim que o nosso acesso à AWS estiver configurado, poderemos descrever nossa infraestrutura usando Terraform. Todo código está disponível em nosso repositório de sistemas. Devemos lembrar que, em um nível conceitual, estamos descrevendo a mesma infraestrutura que criamos para o Azure, mas, no caso da AWS, há elementos que são chamados de forma diferente, mas que têm a mesma responsabilidade.. Por exemplo, no Azure, temos um Availability Set enquanto na AWS é chamado Auto Scaling Group. Nós vamos criar um Auto Scaling Group (ASG), que é onde vamos instanciar os serviços de EC2, para que poçamos escalar horizontalmente para garantir alta disponibilidade, usaremos as AZ’s de cada região por trás de um balanceador e por meio do AWS Launch Configuration poderemos atribuir automaticamente novas instâncias do EC2 dentro da ASG.
  • 15. Se olharmos, ao contrário do post anterior, não mencionamos nenhum elemento de rede. Para simplificar a solução, escolhemos usar todos os elementos padrão em uma região (VPC, sub-rede, roteador e IGW). Lembre-se de que nosso objetivo é descrever essa infraestrutura: O arquivo variables.tf contém a definição das variáveis que vamos usar no exemplo. Region, nomes das chaves e da ami: Variables usadas para configurar a SG:
  • 16. Variáveis de output que usaremos para mostrar informações no arquivo output.tf: O arquivo main.tf contém a descrição da infra-estrutura Nós usamos o provider da AWS: Criamos um Security Group que permite acesso à porta do aplicativo (80):
  • 17. Recuperamos a lista de AZs disponíveis para o referida Region: Criamos um balanceador (ELB) configurando seu Security Group e os AZs nos quais queremos balancear o tráfego. Observe a porta do balanceador (80), bem como a porta usada pelo probe (80) para conhecer o status de integridade de nosso aplicativo: Nós criamos o Configuration Launcher que é o template que o ASG usa para lançar instâncias de EC2:
  • 18.  image_id: É a imagem que queremos fornecer dentro da região que estamos usando.  instance_type: Tamanho da máquina EC2.  user_data: Script usado para configurar a instância EC2.  key_name: É a chave SSH com a qual o acesso SSH será configurado. A última peça que precisamos configurar é a ASG:  availability_zones: As AZ’s são onde queremos criar as instâncias EC2.  min_ size y max_size: Representa o número mínimo e máximo de instâncias do EC2 que queremos provisionar.  desired_capacity: Representa o número atual de instâncias EC2.  force_delete: Para forçar a exclusão da instâncias EC2.  launch_configuration: O template que definimos antes.  load_balancers: O balanceador associado. Um aspecto importante a considerar é que, em nosso exemplo, configuramos o ASG manualmente. Em um cenário real, devemos considerar situações de carga ou demanda do serviço para escalar automaticamente com base, por exemplo, em limites de CPU, memória, etc. Com este último passo, preparamos o exemplo e podemos testá-lo: Inicialize o diretório de trabalho com terraform init :
  • 19. terraform plan Analisa a descrição da infraestrutura que criamos nos informa sobre as alterações que serão feitas (essa etapa não altera a AWS): O próximo passo é o build da nossa infraestrutura na AWS através do comando terraform apply obtendo na tela os valores das variáveis que definimos como output: Após alguns minutos (tempo do build da EC2, provisionamento do serviço de teste que requer a instalação do docker e o download da imagem), o DNS de saída estará disponível e veremos como a atualização do navegador retornará ids de serviço diferentes. O que conseguimos com essa configuração inicial é provisionar essa infraestrutura e também criar um cluster de dois nós em alta disponibilidade nos AZ's da região que usamos. Podemos verificá-lo no console da AWS, na seção EC2 e em balanceadores de carga: Selecionamos instâncias e vemos como duas instâncias do EC2 foram criadas em cada AZ disponível.
  • 20. Se quisermos criar programaticamente mais instâncias e ver se o ASG está funcionando corretamente, podemos executar de novo terraform apply -var asg_desired=6 para confirmar como o ASG escala horizontalmente: Conclusões Para fechar, vamos rever o conteúdo do post:  Nós usamos o Terraform para descrever um exemplo de infraestrutura, mas desta vez na AWS.  Antes de implementar o exemplo, analisamos alguns conceitos de rede na AWS.  Os acessos às chaves AWS e SSH foram configurados.  Nós explicamos alguns elementos da AWS para alcançar o escalonamento horizontal e como usar o Terraform para neste propósito.  Ajustamos o número de instâncias para verificar se o exemplo inteiro funcionou corretamente. Com isso fechamos o post, esperando que você tenha gostado. Não hesite em comentar qualquer dúvida ou detalhe aqui, ou através da nossa conta Twitter. Stay tunned!!
  • 21. DevOps Terraform Amazon AWS OpenShift Terraform + AWS + OpenShift Publicado por Alejandro Nieto el 14 August 2018 Neste artigo, vamos nos concentrar em como executar o provisionamento da infraestrutura necessária para uma deploy do Openshift na AWS e sua configuração automaticamente. Para isso vamos usar o Terraform e o playbook oficial do openshift-ansible (utilizar branch release-3.9). Para rever os fundamentos do Terraform, recomendo a leitura do seguinte artigo, assim como outros já publicados neste blog: http://enmilocalfunciona.io/infraestructura-como-codigo-iii-terrafom-y-aws/ Vamos criar a infraestrutura baseada na arquitetura de referência da Red Hat:
  • 22. $ terraform workspace newdev $ terraform workspace newpre $ terraform workspace newpro terraform workspace select pre Terraform De acordo com Hashicorp, para escrever um módulo Terraform é aconselhável usar três arquivos para definir os recursos main.tf outputs.tf variables.tf Como este módulo é um pouco mais complexo, vamos definir arquivos por tipo de recursos: 00-main.tf 01-security.tf 02-lb.tf 03-network.tf outputs.tf variables.tf Para facilitar a transição de ambientes e isolar o estado de nossa infraestrutura, dependendo do ambiente, é aconselhável usar a função "workspaces" fornecida pela ferramenta Terraform. Nós os criamos da seguinte forma: Se trabalharmos com workspace, podemos usar a variável $ {terraform.workspace} para fazer a transição facilmente entre os ambientes: resource “aws_vpc” “openshift” { cidr_block = “${var.cidr_block}” enable_dns_hostnames = true tags { Name = “${var.cluster_id}-${terraform.workspace}” } } Incluindo essa variável, diferenciamos os recursos de um ambiente para outro sem a necessidade de reescrever o código, apenas alterando o workspace: Nós também usaremos um arquivo .tfvars (onde as variáveis são indicadas) por ambiente: dev.tfvars pre.tfvars pro.tfvars As variáveis que serão mencionadas em todo o post devem ser definidas nesses arquivos. Elementos de rede Vamos definir os primeiros recursos. A primeira coisa que vamos definir são os elementos da rede: VPC Subnets
  • 23. region = "eu-west-1" azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"] cidr_block = "172.16.0.0/16" cidr_master_blocks = ["172.16.10.0/24","172.16.11.0/24","172.16.12.0/24"] cidr_infra_blocks = ["172.16.20.0/24","172.16.21.0/24","172.16.22.0/24"] cidr_node_blocks = ["172.16.30.0/24","172.16.31.0/24","172.16.32.0/24"] cidr_public_blocks =["172.16.40.0/24","172.16.50.0/24","172.16.60.0/24"] resource "aws_vpc" "openshift" { cidr_block = "${var.cidr_block}" enable_dns_hostnames = true tags { Name = "${var.cluster_id}-${terraform.workspace}" } } vpc_id = "${aws_vpc.openshift.id}" tags { Name = "${var.cluster_id}-${terraform.workspace}" } } resource "aws_default_route_table" "openshift_igw" { default_route_table_id = "${aws_vpc.openshift.main_route_table_id}" route { cidr_block = "0.0.0.0/0" gateway_id = "${aws_internet_gateway.openshift.id}" } Nat Gateway Internet Gateway Tablas de enrutamiento As variáveis a serem usadas para os elementos de rede seriam as seguintes: O elemento base é a vpc: As sub-redes serão criadas por função e AZ. Ou seja, um subnet_master para cada AZ e o mesmo para cada uma das variáveis que especificamos acima. Sub-redes podem ser criadas com a máscara desejada, não é necessário usar a indicada nas variáveis. O Internet Gateway é a peça pela qual as instâncias com ip público sairão para a Internet, neste caso, temos um bastião, a única máquina com um ip público). O Gateway de Internet está associado ao VPC: Subseqüentemente, devemos criar uma rota e na qual o gateway é o "Internet Gateway" que acabamos de criar. Esta rota permitirá que as máquinas com endereço público acessem a Internet e estejam na tabela padrão: resource "aws_subnet" "master" { count = "${length(var.cidr_master_blocks)}" vpc_id = "${aws_vpc.openshift.id}" cidr_block = "${var.cidr_master_blocks[count.index]}" availability_zone = "${element(var.azs,count.index)}" tags { Name = "${var.cluster_id}-master${format("%02d", count.index + 1)}-${terraform.workspace}" } }
  • 24. resource "aws_nat_gateway" "openshift_nat_gw" { count = "${length(var.azs)}" allocation_id = "${aws_eip.nat_gateway.*.id[count.index]}" subnet_id = "${aws_subnet.public.*.id[count.index]}" depends_on = ["aws_internet_gateway.openshift"] } resource "aws_route_table" "openshift_nat_route" { count = "${length(var.azs)}" vpc_id = "${aws_vpc.openshift.id}" route { cidr_block = "0.0.0.0/0" nat_gateway_id = "${aws_nat_gateway.openshift_nat_gw.*.id[count.index]}" } tags { Name = "openshift-nat-${aws_subnet.public.*.id[count.index]}-${terraform.workspace}" } } security_groups = ["bastion","master","infra","node"] data "aws_security_group" "default" { name = "default" vpc_id = "${aws_vpc.openshift.id}" } Para que as instâncias com ips privados acessem a Internet, devemos criar um Nat Gateway (com seu ip público correspondente). Este nat gateway deve ser implantado nas sub-redes públicas que criamos anteriormente, ou seja, três Nat Gateway: Assim como no Internet Gateway, você precisa criar rotas de roteamento e associá-las às sub-redes privadas (master, infra e node).): : Segurança políticas de segurança que usamos no post são mais permissivas do que realmente deveria ser, mas o propósito do post não é a infra- estrutura de securança então vamos simplificar incidindo sobre o acesso que permitirá a partir de fora do nosso vpc, que serão as portas 22 (bastião) e as portas para acessar consoles e aplicativos (8443, 443 e 80). Ao criar um vpc, é criado automaticamente um grupo de segurança que será aplicado por padrão que permitirá todo o tráfego dos elementos internos desse vpc. Neste caso, precisamos apenas de uma variável na qual definiremos a quantidade e os nomes dos grupos de segurança que vamos criar: Terraform também pode se referir a recursos já criados e com um life cycle (ciclo de vida) diferente dos recursos do nosso módulo. Eles podem ser referenciados da seguinte forma, onde a variável : Em seguida, criaremos os grupos de segurança. Como um ponto, na AWS eles não estão associados a sub-redes, eles estão associados a instâncias; portanto, você poderia ter duas instâncias na mesma sub-rede com políticas de segurança diferentes. resource "aws_route_table_association" "route_nat_master" { count = "${length(var.cidr_master_blocks)}" subnet_id = "${aws_subnet.master.*.id[count.index]}" route_table_id = "${aws_route_table.openshift_nat_route.*.id[count.index]}" }
  • 25. resource "aws_security_group" "sg_tf" { count = "${length(var.security_groups)}" name = "${var.security_groups[count.index]}-${terraform.workspace}" description = "${var.security_groups[count.index]}" vpc_id = "${aws_vpc.openshift.id}" tags { "kubernetes.io/cluster/openshift-cluster" = "${var.aws_label_value}" } } resource "aws_security_group_rule" "bastion_ssh_tf" { type = "ingress" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = "${element(aws_security_group.sg_tf.*.id, 0)}" } resource "aws_security_group_rule" "infra_443_tf" { type = "ingress" from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = "${element(aws_security_group.sg_tf.*.id, 2)}" } resource "aws_security_group_rule" "infra_80_tf" { type = "ingress" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = "${element(aws_security_group.sg_tf.*.id, 2)}" } bastion_instance_type = "t2.micro" instance_type = "m4.xlarge" image = "ami-3548444c" key_name = "your_key" key_file = "certs/your_key" master_count = 3 As regras necessárias são as seguintes: Permitir que a porta 22 acesse o bastião: Sobre o master, precisamos apenas acessar o console da web openshift, que é exibido por padrão na porta 8443: Os nodes "infra" da Openshift são os que expõem as aplicações ao exterior, então isso poderia ser feito mais do jeito que gostaríamos, mas incluiremos as portas mais usuais: Instâncias Na Contrução de instâncias, vamos nos referir a recursos já definidos, como sub-redes e grupos de segurança. Com o uso de variáveis e usando "count" nos recursos, podemos exibir dinamicamente o número de instâncias que queremos para cada função. Variáveis para utilizar: resource "aws_security_group_rule" "master_8443_tf" { type = "ingress" from_port = 8443 to_port = 8443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = "${element(aws_security_group.sg_tf.*.id, 1)}" }
  • 26. Nosso bastião vai ser de onde vamos executar a instalação do Openshift, então você vai precisar de várias ferramentas instaladas, vamos fazer isso usando a opção "provisioner" do Terraform, que permite transferir arquivos e executar um shell. Neste caso, é simples, então faremos isso executando um shell e a máquina estará pronta para executar o playbook ansible quando tivermos o inventário pronto (isso será feito mais tarde): A seguir, vamos criar quantas instâncias da função X dependendo das variáveis que definimos para este. Neste caso nós escolhemos instalar o etcd no "master", então deixamos a variável "etcd_count" como 0. Para implantar um master, seria o seguinte: Como você pode ver, as variáveis referentes à função de master são usadas, como 'master_count'. Para implantar infraestruturas ou nodes de aplicativos, é necessário apenas fazer referência às variáveis de cada função. Balanceadores de carga Para ter alta disponibilidade, vamos expor os masters e nodes infra usando os balanceadores de carga que a AWS nos fornece. Esses balanceadores devem estar localizados nas sub-redes públicas e aplicar os grupos de segurança que definimos anteriormente de acordo com a função. As variáveis a serem usadas para esses recursos são as seguintes: resource "aws_instance" "bastion" { ami = "${var.image}" instance_type = "${var.bastion_instance_type}" availability_zone = "${element(var.azs, 0)}" key_name = "${var.key_name}" subnet_id = "${element(aws_subnet.public.*.id, 0)}" associate_public_ip_address = true vpc_security_group_ids = ["${data.aws_security_group.default.id}","${element(aws_security_group.sg_tf.*.id, 0)}"] tags { Name = "bastion-tf-${terraform.workspace}" } provisioner "remote-exec" { connection { user = "centos" private_key = "${file("${path.module}/certs/your_key")}" } inline = [ "sudo yum install -y epel-release", "sudo yum install -y git python-pip pyOpenSSL python-cryptography python-lxml python-passlib httpd-tools java-1.8.0-openjdk-headless", "sudo pip install --upgrade pip", "sudo pip install 'ansible==2.5.5'", "git clone -b release-3.9 https://github.com/openshift/openshift-ansible.git", ] } } resource "aws_instance" "master" { count = "${var.master_count}" ami = "${var.image}" instance_type = "${var.instance_type}" availability_zone = "${element(var.azs, count.index)}" key_name = "${var.key_name}" subnet_id = "${element(aws_subnet.master.*.id, count.index)}" associate_public_ip_address = false vpc_security_group_ids = ["${data.aws_security_group.default.id}","${element(aws_security_group.sg_tf.*.id, 1)}"] root_block_device { volume_size = "${var.osdisk_size}" } tags { Name = "master-tf${format("%02d", count.index + 1)}-${terraform.workspace}" "kubernetes.io/cluster/openshift-cluster" = "${var.cluster_id}" } } hosted_zone = "yourdomain.com." domain = "yourdomain.com" company = "atsistemas" elb_names = ["openshift-lb-master","openshift-lb-infra"]
  • 27. As portas que exporão os balanceadores devem ser as mesmas que definimos nos grupos de segurança: Como você pode ver, em "instâncias" você pode facilmente referenciar as instâncias que criamos antes, independentemente do número de máquinas que foram criadas. Para criar o balanceador de carga correspondente a infra, basta alterar as variáveis para que elas se refiram a elas. como fizemos com as instâncias. Também definiremos os registros de DNS dinamicamente para que os recursos sejam acessíveis externamente usando o AWS Route 53. Neste exemplo, a " hosted zone" escapa do life cycle (ciclo de vida), portanto, obtemos os dados da seguinte forma:
  • 28. Criamos dois registros no hosted_zone, que serão usados para acessar o console e os aplicativos: Conexão entre Terraform e Ansible Se soubermos como brincar com as variáveis e as informações fornecidas pela Terraform sobre os recursos criados, podemos vincular o provisionamento da infraestrutura com a geração de um inventário que podemos usar como objetivo na execução de um playbook Ansible.. Terraform permite que você crie templates nos quais podemos reaproveitar dados que possam ser úteis Bem, o inventário para instalar o openshift seria algo assim: Como você pode ver, dependendo do grupo a que pertencem, eles devem incluir uma ou outra informação. Para lidar com isso, posteriormente definiremos vários templates para gerar as informações necessárias, dependendo do grupo de hosts ou role. O template final do inventário será o seguinte: data "aws_route53_zone" "hosted_zone" { name = "${var.hosted_zone}" } resource "aws_route53_record" "openshift" { zone_id = "${data.aws_route53_zone.hosted_zone.zone_id}" name = "console.${var.company}.${var.domain}" type = "CNAME" ttl = "300" records = ["${aws_elb.master.dns_name}"] } resource "aws_route53_record" "openshift-apps" {* zone_id = "${data.aws_route53_zone.hosted_zone.zone_id}" name = "*.apps.${var.company}.${var.domain}" type = "CNAME" ttl = "300" records = ["${aws_elb.infra.dns_name}"] } [OSEv3:children] masters nodes etcd [masters] ip-172-16-10-x.eu-west-1.compute.internal openshift-ip=172.16.10.x openshift_schedulable=true [etcd] ip-172-16-10-x.eu-west-1.compute.internal openshift-ip=172.16.10.x openshift_schedulable=true [nodes] ip-172-16-10-x.eu-west-1.compute.internal openshift-ip=172.16.10.x openshift_schedulable=true openshift_node_labels="{'region': 'primary', 'zone': 'east'}" ip-172-16- 20-x.eu-west-1.compute.internal openshift-ip=172.16.20.x openshift_schedulable=true openshift_node_labels="{'region': 'infra', 'zone': 'default'}" ip-172-16-30-x.eu-west-1.compute.internal openshift-ip=172.16.30.x openshift_schedulable=true openshift_node_labels="{'region': 'primary', 'zone': 'east'}" ...
  • 29. Como você pode ver, as variáveis nos templates são referências de uma forma diferente: ${variable}. Em um arquivo .tf seria assim: ${var.variable} Para construir os dados necessários a serem incluídos no inventário, definiremos um template com certas variáveis para gerar as informações necessárias: Bem, dependendo da função da máquina, vamos gerar dados diferentes na variável ${data}. Para gerar os dados necessários no grupo [master] passaremos o texto "openshift_schedulable=true" para a variável ${data}: Os masters também devem ser incluídos no grupo de hosts [nodes], então geramos as informações necessárias: [OSEv3:children] masters nodes etcd [masters] ${master_hosts} [etcd] ${etcd_hosts} [nodes] ${master_node_hosts} ${infra_hosts} ${node_hosts} ${name} openshift-ip=${ip} ${data} data "template_file" "master-inventory" { count = "${var.master_count}" template = "${file("templates/hostname.tpl")}" vars { name = "${aws_instance.master.*.private_dns[count.index]}" ip = "${aws_instance.master.*.private_ip[count.index]}" data = "openshift_schedulable=true" } } data "template_file" "master-node-inventory" { count = "${var.master_count}" template = "${file("templates/hostname.tpl")}" vars { name = "${aws_instance.master.*.private_dns[count.index]}" ip = "${aws_instance.master.*.private_ip[count.index]}" data = "openshift_schedulable=true openshift_node_labels="{'region': 'primary', 'zone': 'east'}"" } }
  • 30. Para gerar o template final você tem que definir vários blocos de recursos como o anterior, mas você pode gerar o código do anterior modificando os recursos dos quais os dados são obtidos. Para infra será: Para os nodes será: Por fim, passaremos todas as variáveis que geramos para o template final, que será o que gera o inventário do openshift: Execução Já definimos todos os recursos necessários para criar a infraestrutura e vincular a execução do Ansible ao inventário gerado a partir do Terraform. Para isso: Uma vez que o inventário for gerado, vamos passá-lo para o bastião e desta máquina vamos executar os playbooks para instalar o openshift (a deploy levará dependendo do número de máquinas que foram definidas): data "template_file" "openshift-inventory" { template = "${file("templates/${var.inventory_template_name}")}" vars { master_hosts = "${join(" ",data.template_file.master-inventory.*.rendered)}" master_node_hosts = "${join(" ",data.template_file.master-node-inventory.*.rendered)}" etcd_hosts = "${join(" ",data.template_file.master-inventory.*.rendered)}" infra_hosts = "${join(" ",data.template_file.infra-inventory.*.rendered)}" node_hosts = "${join(" ",data.template_file.node-inventory.*.rendered)}" aws_access_key_id = "${var.aws_access_key}" aws_secret_access_key = "${var.aws_secret_key}" cluster_id = "${var.cluster_id}" domain = "${var.domain}" console_master_dns = "${aws_route53_record.openshift.name}" subdomain_openshift_dns = "apps.${var.company}.${var.domain}" } } name = "${aws_instance.infra.*.private_dns[count.index]}" ip = "${aws_instance.infra.*.private_ip[count.index]}" name = "${aws_instance.node.*.private_dns[count.index]}" ip = "${aws_instance.node.*.private_ip[count.index]}" terraform plan -var-file='pre.tfvars' -var-file='aws-pre.tfvars' -out='aws-pre.tfplan' terraform apply "aws-pre.tfplan" terraform output openshift-inventory > ../openshift-inventory ansible-playbook -i /home/centos/openshift-inventory openshift-ansible/playbooks/prerequisites.yml ansible-playbook -i /home/centos/openshift-inventory openshift-ansible/playbooks/deploy_cluster.yml
  • 31. E aqui, o Openshift está disponível: Conclusões Por fim, faremos um breve resumo do post: Usamos o Terraform para descrever a infraestrutura necessária na AWS para uma deploy completa do Openshift. O uso de 'workspaces' para a transição entre ambientes (dev/pre/pro) A infraestrutura foi construída de acordo com o número de instâncias que foram obtidas através de variáveis. Usamos uma hosted zone já criada para o cluster ser acessível de fora da nossa rede.
  • 32. Nós geramos o inventário Ansible usando variáveis de output, este passo é o que conecta o Terraform com o Ansible e torna a instalação dinâmica. Na última etapa, executamos os comandos necessários para a deploy. Como uma melhoria, isso pode ser incluído em um script para torná-lo totalmente automático. Com isso fechamos o post, esperando que você tenha gostado. Não hesite em comentar qualquer dúvida ou detalhe aqui, ou através da nossa conta Twitter.
  • 33. Autor Infraestructura como Código (V): Terraform vs Ansible Publicado por Alejandro Nieto el 29 May 2019 DevOpsInfraestructura como CódigoTerraformAnsible No post anterior, falamos sobre tratar a infraestructura como código, simplificar a sua build e todas as vantagens que isso implica. Mais tarde nós implementamos vários exemplos usando Terraform, mas é possível que muitos de vocês perguntem O que a Terraform oferece a você em relação ao Ansible, se você já tem conhecimento neste último. Este é o propósito deste post. Gerenciamento de configurações & Infrastructure as Code Ansible (e outros gostam de Chef, Puppet, ...) nasceu como uma ferramenta de “Gerenciamento de configurações”, Isso significa que ele é projetado para tarefas como instalar e gerenciar software ou configurar servidores existentes. Isso não significa que a Ansible não seja capaz de lidar com infraestrutura como um código, na verdade é.. Com o Terraform, apenas nos encarregamos do provisionamento da infraestrutura e deixamos a configuração do mesmo nas mãos de outras ferramentas (como o Ansible). Agora você estará pensando que com a Ansible você pode resolver os dois problemas: o provisionamento da infraestrutura e sua configuração, mas depois você verá as diferenças entre as duas ferramentas, como o gerenciamento do estado da nossa infraestrutura. Estilo & Linguagem Dentro do escopo das ferramentas de DevOps, podemos distinguir as ferramentas que usam um estilo declarativo e aquelas que têm um estilo procedural. Se um estilo procedural for usado, é necessário indicar as etapas exatas a seguir em nosso código, como Ansible, em que uma série de tarefas consecutivas é definida. Se usarmos uma ferramenta com um estilo declarativo, é necessário apenas indicar o resultado que queremos com nosso código. Neste caso, Ansible usa um estilo procedural e Terraform um estilo declarativo. Estudo de caso Vamos aplicar alguns exemplos práticos nos quais veremos as informações apresentadas por ambas as ferramentas ao planejar uma mudança e como elas executam essas mudanças. Ansible Para criar um VPC da AWS com o Ansible precisamos do seguinte bloco (assumindo que o provedor já esteja configurado):
  • 34. # ansible-aws.yml - hosts: localhost connection: local gather_facts: False vars: cidr_block: 10.10.0.0/16 tasks: - name: create a VPC with dedicated tenancy and a couple of tags ec2_vpc_net: name: enmilocalfunciona cidr_block: "{{ cidr_block }}" region: eu-west-1 Neste caso, dizemos ao Ansible para criar um VPC com o cidr_block 10.10.0.0/16 e executar o playbook: $ ansible-playbook ansible-aws.yml [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' PLAY [localhost] ********************************************************************************************** ********************************************************************************************** ****** TASK [create a VPC with dedicated tenancy and a couple of tags] ********************************************************************************************** ***************************************************** changed: [localhost] PLAY RECAP ********************************************************************************************** ********************************************************************************************** ************ localhost : ok=1 changed=1 unreachable=0 failed=0 Imagine que queremos mudar um argumento do recurso que criamos, nesse caso podemos alterar o cidr_block: # ansible-aws.yml - hosts: localhost connection: local gather_facts: False vars: cidr_block: 10.20.0.0/16 tasks: - name: create a VPC with dedicated tenancy and a couple of tags ec2_vpc_net: name: enmilocalfunciona cidr_block: "{{ cidr_block }}" region: eu-west-1 Se quisermos obter informações sobre as alterações a serem feitas pelo Ansible, podemos obtê-las da seguinte forma: $ ansible-playbook ansible-aws.yml --check [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
  • 35. PLAY [localhost] ********************************************************************************************** ********************************************************************************************** ****** TASK [create a VPC with dedicated tenancy and a couple of tags] ********************************************************************************************** ***************************************************** changed: [localhost] PLAY RECAP ********************************************************************************************** ********************************************************************************************** ************ localhost : ok=1 changed=1 unreachable=0 failed=0 Como você pode ver, a única informação que isso nos dá é que haverá uma mudança, mas não nos diz onde ou o que vai mudar. Se executarmos manualmente, veremos que o que ele faz é criar um novo VPC com o cidr_block 10.20.0.0/16 sem modificar o que criamos anteriormente. Terraform Vamos realizar exatamente o mesmo com o Terraform. Defina um recurso (neste caso, VPC) e execute-o: resource "aws_vpc" "enmilocalfunciona" { cidr_block = "10.10.0.0/16" enable_dns_hostnames = true tags { Name = "enmilocalfunciona" } } Para executar com o Terraform, você deve primeiro criar um plano, que nos mostre informações sobre o que será executado. Este plano será armazenado em um arquivo, neste caso emmeulocal.tf: $ terraform plan -var-file='aws.tfvars' -out='emmeulocal.tfplan' ... + create Terraform will perform the following actions: + aws_vpc.enmilocalfunciona id: <computed> arn: <computed> assign_generated_ipv6_cidr_block: "false" cidr_block: "10.10.0.0/16" ... tags.%: "1" tags.Name: "enmilocalfunciona" Plan: 1 to add, 0 to change, 0 to destroy.
  • 36. ------------------------------------------------------------------------ This plan was saved to: emmeulocal.tfplan To perform exactly these actions, run the following command to apply: terraform apply "emmeulocal.tfplan" Em um ambiente real, esses parâmetros devem ser definidos como variáveis e trabalhar com eles. Neste caso, vamos alterar o cidr_block para10.20.0.0/16 no código: resource "aws_vpc" " emmeulocalfunciona" { cidr_block = "10.20.0.0/16" enable_dns_hostnames = true tags { Name = "emmeulocalfunciona" } } $ terraform plan -var-file='aws.tfvars' -out= emmeulocal.tfplan' ... -/+ destroy and then create replacement Terraform will perform the following actions: -/+ aws_vpc.emmeulocalfunciona (new resource required) id: "vpc-012a080f9f1f2d6cd" => <computed> (forces new resource) arn: "arn:aws:ec2:eu-west-1:104102502792:vpc/vpc- 012a080f9f1f2d6cd" => <computed> assign_generated_ipv6_cidr_block: "false" => "false" cidr_block: "10.10.0.0/16" => "10.20.0.0/16" (forces new resource) ... Plan: 1 to add, 0 to change, 1 to destroy. ------------------------------------------------------------------------ This plan was saved to: emmeulocal.tfplan To perform exactly these actions, run the following command to apply: terraform apply "emmeulocal.tfplan" Sendo uma linguagem declarativa e controlando o estado de nossa infraestrutura, a Terraform entende que queremos que o VPC tenha um bloco cidr diferente e não crie outro VPC adicional com o bloco cidr que indicamos, que é o que o Ansible executa. Ao aplicar o plan: terraform apply "enmilocal.tfplan" aws_vpc.enmilocalfunciona: Creating... arn: "" => "<computed>" assign_generated_ipv6_cidr_block: "" => "false" cidr_block: "" => "10.10.0.0/16" ... enable_dns_hostnames: "" => "true" enable_dns_support: "" => "true" instance_tenancy: "" => "default" ipv6_association_id: "" => "<computed>" ipv6_cidr_block: "" => "<computed>" main_route_table_id: "" => "<computed>" owner_id: "" => "<computed>" tags.%: "" => "1" tags.Name: "" => "enmilocalfunciona" aws_vpc.enmilocalfunciona: Creation complete after 4s (ID: vpc-0f7ad36df5258bbaa) Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
  • 37. Se mais tarde quisermos alterar o recurso, por exemplo, o cidr, eles indicam as mudanças que serão executadas: terraform plan -var-file='aws.tfvars' -out='emmeulocal.tfplan' Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_vpc.enmilocalfunciona: Refreshing state... (ID: vpc-0f7ad36df5258bbaa) ------------------------------------------------------------------------ An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: -/+ destroy and then create replacement Terraform will perform the following actions: -/+ aws_vpc.enmilocalfunciona (new resource required) id: “vpc-0f7ad36df5258bbaa” => <computed> (forces new resource) arn: “arn:aws:ec2:eu-west-1:104102502792:vpc/vpc- 0f7ad36df5258bbaa” => <computed> assign_generated_ipv6_cidr_block: “false” => “false” cidr_block: “10.10.0.0/16” => “10.20.0.0/16” (forces new resource) ... tags.Name: “emmeulocalfunciona” => “emmeulocalfunciona” Plan: 1 to add, 0 to change, 1 to destroy. ------------------------------------------------------------------------ This plan was saved to: enmilocal.tfplan To perform exactly these actions, run the following command to apply: terraform apply “emmeulocal.tfplan” Você pode ver na linha cidr_block qual a mudança será realizada, e se para realizá-lo é necessário destruí-lo e construí-lo novamente: cidr_block: “10.10.0.0/16” => “10.20.0.0/16” (forces new resource) Aplicamos o plan atualizado novamente e observamos como o recurso é destruído e criado novamente: aws_vpc.enmilocalfunciona: Destroying... (ID: vpc-0f7ad36df5258bbaa) aws_vpc.enmilocalfunciona: Destruction complete after 0s aws_vpc.enmilocalfunciona: Creating... arn: ““ => “<computed>“ assign_generated_ipv6_cidr_block: ““ => “false” cidr_block: ““ => “10.20.0.0/16” ... tags.Name: ““ => “emmeulocalfunciona” aws_vpc.enmilocalfunciona: Creation complete after 4s (ID: vpc-0ca954b8c15912e69) Apply complete! Resources: 1 added, 0 changed, 1 destroyed. ➜ enmilocalfunciona Conclusão Ambas as ferramentas são poderosas e fáceis de aprender. Se você já conhece Ansible ou quer ter todo o código unificado (Configuration Management e IaC), você pode achar o Ansible mais atraente. Se você não conhece nenhuma das ferramentas, quer separar responsabilidades e obter mais informações, aplicar
  • 38. GitOps, etc., é possível que o Terraform seja o mais atraente para você. A escolha é sua, mas Terraform é uma ferramenta mais completa em termos de Infraestrutura como Código. Se você gostou, siga-nos no Twitter para se manter atualizado sobre as próximas postagens!