Puppet e AWS: subindo uma EC2

Este artigo é o primeiro de uma série sobre Puppet e AWS.

A integração do Puppet com a AWS funciona bem e é um assunto que desperta interesse em muita gente. Há boa documentação na Internet sobre o tema, mas aqui escrevo para as pessoas que já pesquisaram sobre o assunto e acabaram desistindo por terem achado que seria muito complexo e/ou trabalhoso realizar esta integração.

Digo isso pois a maior parte dos materiais que encontrei eram extensos, detalhados e sem exemplos práticos. Eu particularmente gosto desse tipo de documentação que te explica os conceitos, como a coisa funciona e depois te deixa livre pra implementar do seu jeito. Porém, essa abordagem só funciona se você dispuser de tempo e paciência para realmente compreender o assunto antes de meter a mão na massa, pois caso contrário, é bem provável que não funcione, perca o interesse no assunto e desista.

Por isso, nesta série de artigos, a abordagem utilizada será: “Vamos botar pra funcionar. Viu que não é tão difícil ? Depois você estuda detalhadamente cada uma das opções dos resources…”.

Sendo o primeiro artigo, trataremos da atividade mais básica: ter uma EC2 rodando em um ambiente completamente definido pelo Puppet, sem contato com o painel da Amazon.

Pré-requisitos:

  • Puppet instalado. Não é necessário nenhuma configuração especial. Pode ser seu puppet master de produção, pode ser um servidor novo com puppet recém instalado, pode ser seu computador pessoal, seja ele Linux ou MacOS… o Puppet é seu, você decide.
  • Instalar o módulo aws do forge: https://forge.puppet.com/puppetlabs/aws
  • Instalar a ferramenta awscli: https://aws.amazon.com/cli/ (ou pelo sistema de pacotes da sua distro)

É necessário configurar a awscli antes de qualquer coisa. Ná página do módulo aws ele descreve como fazê-lo exportando variáveis e configurando arquivos, mas você também pode simplesmente digitar aws configure e responder as perguntas:

[root@foreman ~]# aws configure
AWS Access Key ID [None]: SUA_ACCESS_KEY
AWS Secret Access Key [None]: SUA_SECRET_ACCESS_KEY
Default region name [None]: VCQSABE
Default output format [None]: json
[root@foreman ~]#

Para testar, tente:

[root@foreman ~]# aws ec2 describe-instances

Se estiver tudo ok, não dará erro. Se você tiver instâncias configuradas, elas serão listadas.

Com o awscli configurado, você já pode usar os resources do Puppet para ter uma ideia da visão do Puppet sobre sua infraestrutura na AWS.

Dependendo da distro e da versão do Puppet, pode ser necessário instalar gemas ruby:

/opt/puppetlabs/puppet/bin/gem install aws-sdk-core retries

Liste os resources do Puppet e observe os resources relacionados à ec2, por exemplo:

[root@foreman ~]# puppet describe --list | grep ec2
 ec2_autoscalinggroup - .. no documentation ..
 ec2_elastic_ip - .. no documentation ..
 ec2_instance - .. no documentation ..
 ec2_launchconfiguration - .. no documentation ..
 ec2_scalingpolicy - .. no documentation ..
 ec2_securitygroup - .. no documentation ..
 ec2_vpc - .. no documentation ..
 ec2_vpc_customer_gateway - .. no documentation ..
 ec2_vpc_dhcp_options - .. no documentation ..
 ec2_vpc_internet_gateway - .. no documentation ..
 ec2_vpc_routetable - .. no documentation ..
 ec2_vpc_subnet - .. no documentation ..
 ec2_vpc_vpn - .. no documentation ..
 ec2_vpc_vpn_gateway - .. no documentation ..

Apesar de aparecerem com “.. no documentation ..”, o que realmente importa são os atributos que cada resource aceita, e isso está lá, por exemplo o ec2_vpc:

[root@foreman ~]# puppet describe ec2_vpc
ec2_vpc
=======
A type representing an AWS VPC.
Parameters
----------
- **cidr_block**
 The IP range for the VPC.
- **dhcp_options**
 The DHCP option set to use for this VPC.
- **ensure**
 The basic property that the resource should be in.
 Valid values are `present`, `absent`.
- **instance_tenancy**
 The supported tenancy options for instances in this VPC.
 Valid values are `default`, `dedicated`.
- **name**
 The name of the VPC.
- **region**
 The region in which to launch the VPC.
- **tags**
 The tags to assign to the VPC.

Vamos ver como o Puppet vê meus VPCs (apenas o Default no momento) na AWS:

[root@foreman ~]# puppet resource ec2_vpc
ec2_vpc { 'Default':
  ensure => 'present',
  cidr_block => '172.31.0.0/16',
  dhcp_options => 'Ramoni',
  instance_tenancy => 'default',
  region => 'us-east-1',
}



Feito isso, vamos começar.

Se você conhece Puppet, sabe como o puppet resource é útil para ver um recurso atual e usar como base para criar um novo em sua nova classe. Foi usando esse método que eu criei as definições que vou mostrar a seguir. Eu criei um novo VPC, uma nova subnet, um novo security group, uma instância EC2 e fui usando o puppet resource em cada um deles para gravar as definições que depois eu utilizaria para recriar pelo Puppet.

Aqui a única dificuldade foi por falta de prática na própria AWS, pois eu recriei o ambiente todo mas não conseguia acessar a instância porque faltava uma entrada na route table…

Em fim, se você quer apenas criar uma EC2 ao lado de uma outra que você já tem (mesmo VPC, secgrp etc), um simples puppet resource ec2_instance na instância que já está rodando para usar como base pra sua classe onde vai definir a nova, já será suficiente.

Mas, se você quer subir um ambiente totalmente novo, como uma aplicação nova isolada, é bom saber que você precisa de:

  • VPC (ec2_vpc)
  • Subnet (ec2_vpc_subnet)
  • Security Group (ec2_securitygroup)
  • Internet Gateway (ec2_vpc_internet_gateway)
  • Route Table (ec2_vpc_routetable)
  • EC2 Instance (ec2_instance)

Então, em nosso cenário básico desse primeiro artigo, você pode criar um módulo para declarar uma classe com os parametros abaixo (é necessário um básico conhecimento de puppet para criar o módulo, definir uma classe e aplicá-la):

ec2_vpc { 'vpc01':
  ensure => 'present',
  cidr_block => '10.0.0.0/16',
  region => 'us-east-1',
}
ec2_vpc_subnet { 'subnet01':
  ensure => 'present',
  availability_zone => 'us-east-1a',
  cidr_block => '10.0.1.0/24',
  map_public_ip_on_launch => 'true',
  region => 'us-east-1',
  vpc => 'vpc01',
  route_table => 'routetable01',
}
ec2_securitygroup { 'secgrp01':
  ensure => 'present',
  description => 'Security Group 01',
  ingress => [{'cidr' => '0.0.0.0/0', 'from_port' => '0', 'protocol' => '-1', 'to_port' => '0'}],
  region => 'us-east-1',
  vpc => 'vpc01',
}
ec2_vpc_internet_gateway { 'ig01':
  ensure => 'present',
  region => 'us-east-1',
  vpc => 'vpc01',
}
ec2_vpc_routetable { 'routetable01':
  ensure => 'present',
  region => 'us-east-1',
  routes => [
    {'destination_cidr_block' => '10.0.0.0/16', 'gateway' => 'local'},
    {'destination_cidr_block' => '0.0.0.0/0', 'gateway' => 'ig01'},
  ],
  vpc => 'vpc01',
}
ec2_instance { 'Instance01':
  ensure => 'running',
  availability_zone => 'us-east-1a',
  block_devices => [{'delete_on_termination' => 'false', 'device_name' => '/dev/sda1', 'volume_size' => '10' }],
  ebs_optimized => 'false',
  image_id => 'ami-6d1c2007', # Imagem CentOS 7 nessa regiao
  instance_type => 't2.micro',
  key_name => 'Nome_do_key',
  region => 'us-east-1',
  security_groups => ['secgrp01'],
  subnet => 'subnet01',
}

 

 

Sinta-se livre para fazer isso com um novo módulo, classe, puppet apply etc. Pode trocar os nomes dos recursos, a região e tudo mais. Uma sugestão é utilizar variáveis. O único ponto de atenção é que se escolher outra região, o ID da imagem do CentOS 7 será outro.

Ao rodar:

[root@foreman manifests]# puppet apply init.pp
Notice: Compiled catalog for foreman in environment production in 0.16 seconds
Notice: /Stage[main]/Awstest/Ec2_vpc[vpc01]/ensure: created
Notice: /Stage[main]/Awstest/Ec2_securitygroup[secgrp01]/ensure: created
Notice: /Stage[main]/Awstest/Ec2_vpc_internet_gateway[ig01]/ensure: created
Notice: /Stage[main]/Awstest/Ec2_vpc_routetable[routetable01]/ensure: created
Notice: /Stage[main]/Awstest/Ec2_vpc_subnet[subnet01]/ensure: created
Notice: /Stage[main]/Awstest/Ec2_instance[Instance01]/ensure: changed absent to running
Notice: Finished catalog run in 68.48 seconds

(no meu init.pp eu coloquei o include para ela mesma tambem… mas não façam isso… criem o smoke test porque como eu fiz a classe não pode ser usada pelo classificador)

Se estiver tudo certo, não deve haver nenhum erro (gênio). E ao rodar o Puppet novamente (após a EC2 subir), nada deve acontecer:

[root@foreman manifests]# puppet apply init.pp
Notice: Compiled catalog for foreman.ramoni.com.br in environment production in 0.16 seconds
Notice: Finished catalog run in 71.00 seconds

Entrando na instância com a sua chave:

$ ssh -i suachave.pem centos@
Last login: Mon Oct 17 00:23:12 2016 from 189.60.173.64
[centos@ip-10-0-1-40 ~]$ uptime
 00:27:21 up 5 min, 1 user, load average: 1.70, 1.43, 0.67

No painel AWS (em cada respectiva seção):

screenshot-2016-10-16-22-37-28screenshot-2016-10-16-22-36-28screenshot-2016-10-16-22-35-54screenshot-2016-10-16-22-35-22screenshot-2016-10-16-22-34-52screenshot-2016-10-16-22-33-58

Tudo criado pelo Puppet em 68 segundos ! Quantos cliques isso economizou ? 🙂

“Mas como crio um autoscaling group ? Não acaba sendo muito lento usar o Puppet para escalar instâncias EC2 ?”

Calma mancebo. Isso é assunto para os próximos artigos relacionados.

“Pela atenção, obrigado.” – comissário de bordo sobre o artigo.