Tecnologia / Artigos / O Guia Definitivo do Salt /
Parte 2

Cléber

![Saltstack](/files/95) *09/11/2018|01/12/2018* # Introdução No artigo anterior, apresentei os principais conceitos contidos na operação do sistema de gerenciamento de configurações "Salt". Agora pretendo falar sobre alguns casos mais práticos para que você seja capaz de já começar a usar o Salt para gerenciar pelo menos algumas coisas básicas de algumas máquinas. # 1- Topologia O Salt funciona com vários tipos de tolopogia: pode ter um *master*, pode não ter nenhum, pode ter vários. Lembre-se: o "mestre" é a máquina (ou "nó") que é a **fonte da verdade**. Eu acho a abordagem "apenas um mestre" melhor por uma série de motivos. Um deles é porque manter um mestre envolve manter também um conjunto de **chaves secretas**. Como é função do mestre ditar os valores que serão gravados nas configurações de diversos sistemas, manteremos nessa máquina diversas chaves e tokens que **não podem ser gravados num repositório de código** (porque **nunca** se deve guardar chaves secretas em repositórios de código). Sendo assim, caso você tenha múltiplos mestres, terá provavelmente várias cópias dessas chaves, o que geralmente pode ser considerado algo ruim. E caso não tenha nenhum, provavelmente estará operando tudo de sua própria máquina (literalmente: o laptop do desenvolvedor), o que pode ser okay caso você trabalhe sozinho, mas é péssimo caso trabalhe com uma equipe. Além disso, você provavelmente configurará uma máquina remota para ser o mestre, e o acesso será controlado via SSH, o que é uma forma até bem segura e simples de se gerenciar (é fácil invalidar as chaves de um funcionário que deixe a empresa, por exemplo). ## 1.1- Instalação **Não recomendo usar pacotes do sistema**. Me pareceu que o script de "bootstrap" funciona melhor. ### 1.1.1- Master ```bash curl -L https://bootstrap.saltstack.com -o install_salt.sh sudo sh install_salt.sh -P -M ``` ### 1.1.2- Minions Você provavelmente **não** criará minions "na unha", pois o *salt-cloud* está aí para cuidar disso. Mas, caso precise: ```bash curl -L https://bootstrap.saltstack.com -o install_salt.sh sudo sh install_salt.sh -P ``` ## 1.2- Configuração Novamente, eu recomendo não criar nenhum minion manualmente, deixando que o salt-cloud faça isso para você. O motivo principal é, além de que **máquinas são gado**, que o salt-cloud cuidará do **gerenciamento de chaves**. Porque, afinal, **o Salt é seguro** e você não quer que teus minions obedeçam a comandos vindos de algum terceiro espertalhão, certo? # 2- O mestre é um minion! A melhor dica que eu posso dar agora é a seguinte: **use o Salt para configurar o próprio Mestre**. Por exemplo: o salt-cloud tem um arquivo em que você define o "mapa" da topologia, ou seja, quais *nós* você quer que existam no seu "parque de máquinas". **Não escreva esse arquivo manualmente**, mas preencha-o usando o próprio salt. # 2- salt-cloud ## 2.1- Instalação O *salt-cloud* era um pacote à parte, antigamente, mas hoje já é parte do próprio Salt. Então, se o Salt está instalado, o comando `salt-cloud` já deverá estar disponível. ## 2.2- Configuração ### 2.2.1- /etc/salt/cloud.providers Esse é o arquivo que informa o salt-cloud a respeito dos **provedores de infraestrutura** disponíveis. No meu caso, o único provedor de infraestrutura é a Amazon (AWS EC2). ```yaml ec2-private: minion: master: ᐸIP-DO-MESTRE (recomendo usar o "ip interno")ᐳ grains: provider: ec2 ssh_interface: private_ips # EC2 access credentials id: ᐸAWS_ACCESS_IDᐳ key: ᐸAWS_ACCESS_SECRET_KEYᐳ private_key: /root/ᐸCHAVE-DE-ACESSO-DEFAULTᐳ.pem keyname: ᐸNOME-DA-CHAVE-DE-ACESSOᐳ securitygroup: default location: us-east-1 ssh_username: ubuntu script: /etc/salt/cloud.deploy.d/bootstrap-salt.sh driver: ec2 ``` Repare na linha 21: eu precisei informar explicitamente onde ficava o script de *bootstrap* do Salt. Isso me pareceu ser devido a um bug na versão que eu uso. Talvez isso seja desnecessário nas versões mais novas. Caso você crie minions que não "conectem-se" no master, é sinal que o salt-cloud não está instalando o Salt nos minions. Então, provavelmente, você deverá manter a entrada da linha 21. ### 2.2.2- /etc/salt/cloud.profiles Esse arquivo serve para você dar nomes que possa usar para referenciar "perfis" de máquinas do seu provedor de infraestrutura. No caso do AWS EC2, isso envolve o tamanho da máquina e o sistema operacional, basicamente: ```yaml t2_small: provider: ec2-private image: ami-80861296 # ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20170414 size: t2.small t2_medium: provider: ec2-private image: ami-80861296 # ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20170414 size: t2.medium t2_large: provider: ec2-private image: ami-80861296 # ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20170414 size: t2.large t2_large_with_volume: provider: ec2-private image: ami-80861296 # ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20170414 size: t2.large volumes: - { size: 200, device: /dev/sdf } del_all_vols_on_destroy: True t2_2xlarge_with_volume: provider: ec2-private image: ami-80861296 # ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20170414 size: t2.2xlarge # 8 CPUs, 32GB RAM, 37 cents per hour. volumes: - { size: 200, device: /dev/sdf } del_all_vols_on_destroy: True m5d_xlarge: provider: ec2-private image: ami-80861296 # ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20170414 size: m5d.xlarge c5d_xlarge: provider: ec2-private image: ami-80861296 # ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20170414 size: c5d.xlarge ``` Perceba que cada entrada referencia seu "provider". Ou seja: mesmo que você tivesse mais de um provedor de infraestrutura (digamos que também usasse Google Cloud Computing, por exemplo), ainda assim todos os perfis constariam nesse mesmo arquivo. ### 2.2.3- O mapa da topologia Eu salvei o mapa em `/etc/salt/cloud.maps/main_map.sls`. Mas, conforme citado anteriormente, eu não preencho esse arquivo manualmente. Para manter esse arquivo atualizado, eu uso o próprio Salt. O que eu fiz foi criar um template de estado chamado `/srv/salt/orch/files/main_map.sls`. Os templates de estado ficam em `/srv/salt/`. Eu criei o diretório `orch`. Referência a "orquestração". Eu separo os templates de estado em várias pastas, já que cada tipo de nó geralmente requer mais de um arquivo. Em praticamente todo diretório desses eu crio um subdiretório chamado `files`, que é onde ficam os templates **de arquivos**. Esses templates de arquivos serão preenchidos pelo Salt e servirão para criar arquivos reais nas máquinas por ele gerenciadas. Então, veja que curioso: eu mantenho um template de arquivo no meu salt-master que serve para criar um arquivo no próprio salt-master. :) O template do arquivo é o seguinte: ```yaml # Nano: 1 CPU, 0.5GB RAM # t2_nano: # Micro: 1 CPU, 1GB RAM t2_micro: - dequeuer.master.0: grains: app: dequeuer stage: 0 minion_class: master minion_index: 0 - webhooks.0: grains: app: webhooks stage: 0 # Small: 1 CPU, 2GB RAM t2_small: - aramaki.main: grains: app: aramaki stage: 0 - constantino.main: grains: app: constantino stage: 0 - dequeuer.cleric.0: grains: app: dequeuer3 stage: 0 minion_class: cleric minion_index: 0 {% set ishikawa_servers = salt['pillar.get']('aramaki')['servers'] %} {% for server_name, options in ishikawa_servers.items() %} - {{ server_name }}.ishikawa2.main: grains: app: ishikawa2 server_name: {{ server_name }} stage: 0 {% endfor %} # Medium: 2 CPUs, 4GB RAM t2_medium: - dequeuer.warrior.0: grains: app: dequeuer3 stage: 0 minion_class: warrior minion_index: 0 - dequeuer.warrior.1: grains: app: dequeuer3 stage: 0 minion_class: warrior minion_index: 1 # Large: 2 CPUs, 8GB RAM = 0.0928/hour # t2_large_with_volume: # c5d.xlarge: 4 CPUs, 8GB RAM, 100GB SSD = 0.1920/hour # c5d_xlarge: # m5d.xlarge: 4 CPUs, 16GB RAM, 150GB SSD = 0.2260/hour m5d_xlarge: - dequeuer.paladin.0: grains: app: dequeuer3 stage: 0 minion_class: paladin minion_index: 0 - dequeuer.paladin.1: grains: stage: 0 minion_class: paladin minion_index: 1 # c5d.4xlarge: 16 CPUs, 32GB RAM, 400GB SSD = 0.7680/hour # c5d_4xlarge: # c5d.9xlarge: 36 CPUs, 72GB RAM, 900GB SSD = 1.7280/hour c5d_9xlarge: - dequeuer.saito.0: grains: app: dequeuer3 stage: 0 minion_class: saito minion_index: 0 - dequeuer.saito.1: grains: app: dequeuer3 stage: 0 minion_class: saito minion_index: 1 ``` Eu admito que nesse arquivo não é feito um bom uso do sistema de templates do Salt (o `jinja2`). Essas listas em que só se muda um índice deveriam ser criadas com um bloco `{% for %}`. Mas tudo bem: pelo menos fica mais legível. ### 2.2.4- /srv/salt/top.sls O `top.sls` é responsável por dizer qual template de estado será usado e em que ocasião. No meu caso, quem define a regra de aplicação são os valores dos grains "app" e "stage". ``` {% set apps = ("ishikawa2", "dequeuer2", "dequeuer3",ᐸE-OUTRAS...ᐳ) %} base: 'salt-master': - core.pkgs - core.grains - orch.companies - orch.hosts - orch.cloudflare - orch.netlify 'stage:0': - match: grain - core.pkgs - core.grains - core.files - pyenv - utils.increment_stage {% for app in apps %} - {{ app }}.stage_0 {% endfor %} {% for stage in (1, 2, 3) %} 'stage:{{ stage }}': - match: grain - utils.increment_stage - core.stage_{{ stage }} {% for app in apps %} - {{ app }}.stage_{{ stage }} {% endfor %} {% endfor %} 'stage:4': - match: grain {% for app in apps %} - {{ app }}.update {% endfor %} ``` Percebeu as entradas `stage:N`? O que está sendo dito é: "aplique essa e essa regra caso o nó tenha o grain `stage` igual a N". #### 2.2.4.1- Por que "estágios"? Eu acabei descobrindo que configurar um novo nó de uma aplicação acaba sendo um processo em várias etapas. Você tem, por exemplo, que configurar o `.ssh/id_rsa` antes de conseguir clonar um repositório git. Alguns exemplos: ᐳ .ssh/id_rsa + id_rsa.pub -ᐳ git clone -ᐳ preencher o arquivo .env do projeto ᐳ Criar instância RDS -ᐳ pegar o endpoint de acesso ao banco -ᐳ criar o banco de dados #### 2.2.4.2- update.sls O `top.sls` determina que após a execução dos estágios intermediários, seja chamado o `utils/increment_stage.sls`: ```yaml {% set next_stage = salt['grains.get']('stage') + 1 %} increment_stage: grains.present: - name: stage - value: {{ next_stage }} ``` O que esse template de estado faz é descobrir qual é o *stage* atual e setar um novo valor com acréscimo de 1. E isso acontece em todos os estágios,**exceto no último**. Esse último estágio eu chamo de "update", porque só o que ele faz é atualizar repositórios e reiniciar serviços (eu não cheguei a implementar nenhum sistema de *continuous delivery* ainda). # Resumo Você já viu, com muitos exemplos, alguns cenários interessantes de uso do Salt e até do *salt-cloud*. Não entrei em detalhes sobre alguns aspectos, ainda, porque achei que o artigo já ficou de tamanho razoável. No próximo capítulo pretendo explicar em mais detalhes como os templates de estado são "executados", porque isso ajuda muito a não cometer alguns erros bobos que eu mesmo cometi quando comecei a trabalhar com Salt.

Curti

58 visitantes curtiram esse Item.

Anterior: Artigos / O caráter perigoso dos dados de "analytics" | Próximo: Parte 1