/ #Devops #AWS 

Criando Infraestrutura No Aws Com Sceptre

Sceptre? O que é isso?

Sceptre é uma ferramenta de IaC ou Infraestrutura como Código (Infrastructure as Code). Se este termo ainda é novidade para você, sugiro uma lida em um post no qual explico o que é e quais as vantagens de se utilizar Infraestrutura como Código: Infraestrutura como Código com Terraform

Assim como o Terraform, o Sceptre nos ajuda a gerenciar infraestruturas no AWS de forma mais eficiente. Criado pela empresa CloudReach, o Sceptre possui algumas diferenças marcantes quando comparado ao Terraform. A primeira delas é que não se trata de uma ferramenta para gerenciamento de infraestrutura como código de forma generalista, ou seja, não pode ser utilizado para qualquer provedor de nuvem por exemplo. O Sceptre foi criado especificamente com o intuito de gerenciar infraestrutura no AWS. Além disso, o Sceptre não funciona de forma 100% autônoma, como no caso do Terraform que gerencia e manipula recursos na nuvem mantendo um arquivo (ou vários) para seu status. O Sceptre na verdade utiliza-se do já existente CloudFormation do AWS.

Se você não conhece o CloudFormation, trata-se da solução nativa da Amazon para gerenciamento de infraestrutura na nuvem AWS utilizando-se de infraestrutura como código. Mas.. espera aí… algo está esquisito…

Estranho

Se o AWS já possui sua própria ferramenta nativa de infraestrutura como código, que é o CloudFormation… É compreensível o uso de Terraform como uma alternativa por ser um padrão mais genérico e que pode ser utilizado para todas as nuvens, não apenas o AWS. Mas o que justificaria utilizar o Sceptre ao invés do CloudFormation se por baixo ele acabará utilizando o CloudFormation?

calma

O Sceptre foi criado para gerenciar o CloudFormation, sim. Ninguém criaria algo apenas por criar, portanto o Sceptre veio com a proposta de lidar com algumas carências já existentes no CloudFormation. O Sceptre é capaz de criar, atualizar e deletar stacks ou conjuntos de recursos no AWS, além de fornecer informações mais detalhadas, metadata bem como recuperar facilmente tais dados.

Criado em Python, o Sceptre pode ser utilizado como um comando CLI ou como um módulo Python, pronto para ser utilizado em ambientes de produção e enterprise e desenhado para ser executado como parte de pipelines de CI/CD.

A principal motivação para a criação do Sceptre foi o fato de o CloudFormation não possuir recursos mais robustos para gerenciamento de stacks ou conjuntos de recursos, enquanto que a CLI padrão do AWS bem como a biblioteca Boto3 para Python oferecem alguns destes recursos, mas ainda assim nenhuma delas disponibiliza:

  • Links entre a saída de uma stack com parâmetros de outra stack;
  • Facilidade para se trabalhar com roles ou mesmo com múltiplas contas do AWS;

Sem mais lenga lenga, vamos ao que interessa.

Instalação

As duas formas mais simples de se utilizar o Sceptre são via docker ou instalando via Pip. Sinta-se livre para utilizar a forma que mais lhe agradar.

Ao longo do post estarei utilizando o sceptre instalado localmente através do pip, mas os passos deverão funcionar via docker também caso prefira este método.

Utilizando Docker

Esta opção assume que você já possua o Docker instalado.

Baixe a imagem Docker do Sceptre da seguinte forma:

➜ docker pull cloudreach/sceptre

Caso queira baixar alguma versão em específico, inclua a versão desejada ao seu comando:

➜ docker pull cloudreach/sceptre:2.1.3

Deixando em branco ele buscará a última versão disponível (latest).

Podemos testar o Sceptre via Docker utilizando o comando a seguir para vermos a versão do Sceptre utilizada.

➜ docker run cloudreach/sceptre:latest --version

Sceptre, version 3.0.0

Sim, o container Docker é iniciado, executa o que pedimos e se encerra em seguida. Oi, simples assim.

Vale lembrar que será necessário sempre montar o seu diretório local em seu container docker para que o sceptre executado no container tenha acesso ao seu código, portanto para cada comando que executaremos a seguir você utilizaria algo similar a isto:

docker run -v $(pwd):/project -v ~/.aws/:/root/.aws/:ro cloudreach/sceptre:latest

Utilizando Pip

Esta opção assume que você já possua o Python e o Pip instalados.

Sendo uma ferramenta Python, podemos intalar o sceptre com o pip:

➜ pip install sceptre

Em seguida podemos confirmar a versão do sceptre instalada:

➜ sceptre --version

Utilizando o Sceptre

Autenticação com o AWS

O Sceptre utilizará os mesmos arquivos de configuração utilizados pela CLI do AWS para autenticar-se, portanto este post assume que você já possui também o AWS CLI instalado e configurado em sua máquina.

Caso você ainda não possua, siga os passos descritos aqui para instalar e configurar o seu AWS CLI:

Você pode testar seu AWS CLI através do seguinte comando:

➜ aws sts get-caller-identity

{
    "UserId": "ABLABLABLABLABLABLADH",
    "Account": "6777777777775",
    "Arn": "arn:aws:iam::6777777777775:user/marcelo"
}

Se você recebeu um retorno similar a este, informando o ID do seu usuário AWS, o ID de sua conta AWS e o ARN de seu uruário, significa que seu AWS CLI está devidamente configurado e conseguindo autenticar e se comunicar com o AWS.

Iniciando com o Sceptre

Agora que sabemos que o Sceptre já conseguirá autenticar-se com o AWS vamos iniciar a configuração básica de nossa infraestrutura.

O Sceptre utiliza uma árvore ou estrutura de diretórios seguindo o padrão a seguir:

meu-projeto-sceptre
    ├── config
    │   └── config.yaml
    └── templates

Basicamente a estrutura mais simples é com o diretório principal de seu projeto e dentro dele dois diretórios, sendo um deles para as configurações e o outro para os templates.

O Sceptre pode criar esta árvore de diretórios automaticamente ao criarmos um novo projeto. Para isto utilizaremos o comando sceptre new project. Perceba que ele lhe pedirá que indique a região na qual deseja o seu projeto. Esta seria a região a ser utilizada no AWS para a sua infraestrutura. No meu caso estou utilizando ca-central-1, pois é onde moro. Sinta-se livre para usar a região de sua preferência, como por exemplo sa-east-1 (para São Paulo, Brasil). A lista de regiões pode ser encontrada aqui: Lista de Regiões AWS. Em seguida o Sceptre lhe pedirá um código para o projeto, pode deixar em branco:

➜ sceptre new project meu-projeto-sceptre

Please enter a region []: ca-central-1
Please enter a project_code [meu-projeto-sceptre]:

Podemos confirmar a criação do diretório de nosso projeto, bem como os dois sub-diretórios:

➜ ls meu-projeto-sceptre

config    templates

Agora que temos nosso projeto criado, podemos começar a inserir nosso código de fato.

Verifcando o que foi criado pelo Sceptre automaticamente veremos que o diretório de templates está vazio, mas o diretório de config possui um arquivo padrão config.yaml com o seguinte conteúdo:

0
1
project_code: meu-projeto-sceptre
region: ca-central-1

O diretório config é onde manteremos as configurações de nossas stacks e o diretório templates é onde manteremos os arquivos de template do CloudFormation.

Vamos iniciar criando um stack chamado test e iniciaremos criando uma VPC nesta stack, visto que VPCs são geralmente o nosso ponto de partida em uma nuvem já que todo e qualquer recurso deve ser criado em uma VPC.

Criaremos um diretório chamado test dentro do diretório config. Sinta-se livre para criá-lo da forma que preferir. Em Linux ou OS X(mac) podemos fazer isto através do comando mkdir executado dentro do diretório de nosso projeto, meu-projeto-sceptre:

➜ mkdir config/test

➜ ls config
config.yaml test

Em seguida vamos criar o arquivo de configuração de nossa stack test, o arquivo de configuração de nossa VPC e também o template de nossa vpc:

➜ touch config/test/config.yaml config/test/vpc.yaml templates/vpc.yaml

A nossa árvore de diretórios e arquivos deverá estar da seguinte forma:

➜ tree .
.
├── config
│   ├── config.yaml
│   └── test
│       ├── config.yaml
│       └── vpc.yaml
└── templates
    └── vpc.yaml

3 directories, 4 files

Nestes arquivos teremos:

  • templates/vpc.yaml: o template CloudFormation de nossa VPC
  • config/test/vpc.yaml: as configurações referentes a este template de VPC
  • config/test/config.yaml: a configuração do ambiente

Vamos iniciar pela configuração do nosso ambiente. Para isto daremos um código de projeto e a região na qual desejamos nossa infraestrutura. Vamos inserir o seguinte conteúdo no arquivo config/test/config.yaml:

0
1
project_code: projeto-sceptre
region: ca-central-1

Novamente, lembre-se de usar a região que melhor lhe sirva, não precisa utilizar a região canadense como estou utilizando aqui.

Em seguida vamos inserir a configuração do template de nossa VPC no arquivo config/test/vpc.yaml:

0
1
2
3
4
template:
  path: vpc.yaml
  type: file
parameters:
  CidrBlock: 10.0.0.0/16

Repare que aqui temos dois blocos de código:

  • template: definimos que template será usado com esta configuração. Indicamos que o path é vpc.yaml, pois este é o caminho referente ao nosso template de vpc que fica dentro do diretório de templates.
  • parameters: aqui listamos parâmetros, que podem ser utilizados como variáveis para nosso template. Neste caso estamos utilizando apenas um parâmetro, que é o bloco de endereços IP de nossa VPC, o CidrBlock.

Agora vamos ao nosso template CloudFormation em si. Insira o seguinte código no arquivo templates/vpc.yaml:

 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Parameters:
  CidrBlock:
    Type: String
Resources:
  VPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock:
        Ref: CidrBlock
Outputs:
  VpcId:
    Value:
      Ref: VPC

Perceba que este código yaml é bem parecido com o yaml já utilizado pelo CloudFormation padrão. O tipo do recurso (type) também é exatamente como definido e utilizado pelo CloudFormation, AWS::EC2::VPC. O único detalhe aqui é o parâmetro que estamos utilizando nas propriedades (Properties), onde estamos referenciando (Ref) o parâmetro CidrBlock. Apenas lembrando, nós definimos este parâmetro em nosso arquivo de configuração /config/test/vpc.yaml, portanto aqui o valor 10.0.0.0/16 será utilizado para a nossa VPC.

**Agora que nosso código está utilizável podemos começar a testar o que fizemos até agora.

Antes disto, podemos ver que não possuo nenhuma stack já criada em minha conta do AWS, bem como ainda não temos a VPC que será criada com este CidrBlock que definimos.

AWS

AWS

Agora podemos executar nosso código. Com o comando sceptre create test/vpc.yaml poderemos aplicar e criar nosso stack. O comando nos pedirá uma confirmação, bastando digitar y para confirmar a execução:

➜ sceptre create test/vpc.yaml

Do you want to create 'test/vpc.yaml' [y/N]: y
[2022-03-13 13:41:37] - test/vpc - Creating Stack
[2022-03-13 13:41:38] - test/vpc projeto-sceptre-test-vpc AWS::CloudFormation::Stack CREATE_IN_PROGRESS User Initiated
[2022-03-13 13:41:42] - test/vpc VPC AWS::EC2::VPC CREATE_IN_PROGRESS
[2022-03-13 13:41:42] - test/vpc VPC AWS::EC2::VPC CREATE_IN_PROGRESS Resource creation Initiated
[2022-03-13 13:41:59] - test/vpc VPC AWS::EC2::VPC CREATE_COMPLETE
[2022-03-13 13:42:03] - test/vpc projeto-sceptre-test-vpc AWS::CloudFormation::Stack CREATE_COMPLETE

Repare que a execução não reportou nenhum erro. Se durante esta execução checarmos novamente a página de stacks do CLoudFormation, poderemos ver que a nossa stack está sendo criada:

AWS

Após a finalização da execução, deveremos ver a stack já criada bem como a VPC:

AWS

AWS

Também podemos utilizar o próprio Sceptre para verificar a lista de nossos recursos no ambiente test com o comando sceptre list resources:

➜ sceptre list resources test

StackLogicalResourceIdPhysicalResourceId

test/vpcVPCvpc-027cb3d73fcc7aa64

Algo que devemos sempre ter em nossa lista de prioridades para todo e qualquer recurso criado em nossa infraestrutura é a identificação. No caso do AWS, utilizamos Tags. As tags são essenciais para organização e identificação de nossos recursos. Como esquecemos de inserir tags em nossa VPC, vamos alterar nosso arquivo templates/vpc.yaml:

 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Parameters:
  CidrBlock:
    Type: String
Resources:
  VPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock:
        Ref: CidrBlock
      Tags:
      - Key: Ambiente
        Value: test
Outputs:
  VpcId:
    Value:
      Ref: VPC

Aqui inserimos apenas uma tag para este exemplo. Para efetuarmos esta atualização podemos usar o comando sceptre update:

➜ sceptre update test/vpc.yaml

Do you want to update 'test/vpc.yaml' [y/N]: y
[2022-03-13 13:56:45] - test/vpc - Updating Stack
[2022-03-13 13:56:45] - test/vpc projeto-sceptre-test-vpc AWS::CloudFormation::Stack UPDATE_IN_PROGRESS User Initiated
[2022-03-13 13:56:49] - test/vpc VPC AWS::EC2::VPC UPDATE_IN_PROGRESS
[2022-03-13 13:56:49] - test/vpc VPC AWS::EC2::VPC UPDATE_COMPLETE
[2022-03-13 13:56:53] - test/vpc projeto-sceptre-test-vpc AWS::CloudFormation::Stack UPDATE_COMPLETE_CLEANUP_IN_PROGRESS
[2022-03-13 13:56:53] - test/vpc projeto-sceptre-test-vpc AWS::CloudFormation::Stack UPDATE_COMPLETE

Podemos voltar à nossa página de VPCs do AWS e veremos que nossa VPC agora possui a nossa tag:

AWS

Vamos criar então um recurso mais tangível, como por exemplo uma Instância EC2 (VM). Primeiramente, podemos ver que não possuo nenhuma instância já existente:

AWS

Criaremos dois novos arquivos, sendo um de configuração para nosso ec2 e um de template para o ec2:

➜ touch config/test/ec2.yaml templates/ec2.yaml

Para simplificar nosso exemplo, definiremos 2 parâmetros em nosso arquivo test/config/ec2.yaml, sendo eles ImageId e InstanceType:

0
1
2
3
4
5
template:
  path: ec2.yaml
  type: file
parameters:
  ImageId: ami-041d49677629acc40 # AMI para Amazon Linux distro
  InstanceType: t2.micro

Agora inserimos o código de nosso arquivo templates/ec2.yaml onde referenciaremos os dois parâmetros já definidos no arquivo de config:

 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
Parameters:
  ImageId:
    Type: String
  InstanceType:
    Type: String
Resources:
  Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId:
        Ref: ImageId
      InstanceType:
        Ref: InstanceType
      Tags:
      - Key: Ambiente
        Value: test
      - Key: Name
        Value: Instancia-test
Outputs:
  InstanceId:
    Value:
      Ref: Instance

Agora podemos criar esta nova stack com o comando sceptre create test/ec2.yaml:

➜ sceptre create test/ec2.yaml

Do you want to create 'test/ec2.yaml' [y/N]: y
[2022-03-13 14:32:16] - test/ec2 - Creating Stack
[2022-03-13 14:32:17] - test/ec2 projeto-sceptre-test-ec2 AWS::CloudFormation::Stack CREATE_IN_PROGRESS User Initiated
[2022-03-13 14:32:21] - test/ec2 Instance AWS::EC2::Instance CREATE_IN_PROGRESS
[2022-03-13 14:32:25] - test/ec2 Instance AWS::EC2::Instance CREATE_IN_PROGRESS Resource creation Initiated
[2022-03-13 14:32:37] - test/ec2 Instance AWS::EC2::Instance CREATE_COMPLETE
[2022-03-13 14:32:41] - test/ec2 projeto-sceptre-test-ec2 AWS::CloudFormation::Stack CREATE_COMPLETE

Repare que tanto a nova stack quanto a instância EC2 foram devidamente criadas no AWS:

AWS

AWS

Através do sceptre podemos ainda listar os outputs que definimos em nossos templates com o comando sceptre list outputs:

➜ sceptre list outputs test

StackOutputKeyOutputValue

test/ec2InstanceIdi-05031a4a80244fd17
test/vpcVpcIdvpc-027cb3d73fcc7aa64

Obviamente que não precisamos lidar com cada stack individualmente. Aqui criamos com o sceptre a stack de vpc e em seguida a stack de ec2. Mas e se tivéssemos 20 stacks? 50 stacks? Não queremos ter que executar um comando para cada uma, certo?!

Vamos testar isso limpando nosso ambiente com o comando sceptre delete:

➜ sceptre delete test/ec2.yaml

The following stacks, in the following order, will be deleted:
test/ec2

Do you want to delete 'test/ec2.yaml' [y/N]: y
[2022-03-13 14:45:21] - test/ec2 - Deleting stack
[2022-03-13 14:45:21] - test/ec2 projeto-sceptre-test-ec2 AWS::CloudFormation::Stack DELETE_IN_PROGRESS User Initiated
[2022-03-13 14:45:25] - test/ec2 Instance AWS::EC2::Instance DELETE_IN_PROGRESS
[2022-03-13 14:45:54] - test/ec2 - delete complete

e…

➜ sceptre delete test/vpc.yaml

The following stacks, in the following order, will be deleted:
test/vpc

Do you want to delete 'test/vpc.yaml' [y/N]: y
[2022-03-13 14:46:07] - test/vpc - Deleting stack
[2022-03-13 14:46:08] - test/vpc projeto-sceptre-test-vpc AWS::CloudFormation::Stack DELETE_IN_PROGRESS User Initiated
[2022-03-13 14:46:12] - test/vpc VPC AWS::EC2::VPC DELETE_IN_PROGRESS
[2022-03-13 14:46:29] - test/vpc - delete complete

Agora que nossas stacks e recursos foram excluídos com sucesso, podemos criar tudo de uma vez com o comando sceptre create test, sem especificar uma stack em específico. Desta forma o sceptre entenderá que precisa executar todas as stacks que se encontram dentro de test:

➜ sceptre create test

Do you want to create 'test' [y/N]: y
[2022-03-13 14:49:20] - test/ec2 - Creating Stack
[2022-03-13 14:49:20] - test/vpc - Creating Stack
[2022-03-13 14:49:21] - test/ec2 projeto-sceptre-test-ec2 AWS::CloudFormation::Stack CREATE_IN_PROGRESS User Initiated
[2022-03-13 14:49:21] - test/vpc projeto-sceptre-test-vpc AWS::CloudFormation::Stack CREATE_IN_PROGRESS User Initiated
[2022-03-13 14:49:25] - test/vpc VPC AWS::EC2::VPC CREATE_IN_PROGRESS
[2022-03-13 14:49:25] - test/ec2 Instance AWS::EC2::Instance CREATE_IN_PROGRESS
[2022-03-13 14:49:25] - test/vpc VPC AWS::EC2::VPC CREATE_IN_PROGRESS Resource creation Initiated
[2022-03-13 14:49:29] - test/ec2 Instance AWS::EC2::Instance CREATE_IN_PROGRESS Resource creation Initiated
[2022-03-13 14:49:41] - test/ec2 Instance AWS::EC2::Instance CREATE_COMPLETE
[2022-03-13 14:49:41] - test/vpc VPC AWS::EC2::VPC CREATE_COMPLETE
[2022-03-13 14:49:46] - test/vpc projeto-sceptre-test-vpc AWS::CloudFormation::Stack CREATE_COMPLETE
[2022-03-13 14:49:46] - test/ec2 projeto-sceptre-test-ec2 AWS::CloudFormation::Stack CREATE_COMPLETE

Repare que desta vez tanto a stack de vpc quanto a de ec2 foram criadas.

Obviamente que este foi apenas um exemplo simplista do uso do Sceptre, mas a ideia era de fato apresentar esta alternativa.

Abraço!