estilo de código ansible devops
Ei! Meu nome é
Este guia oferece uma maneira de organizar variáveis na implantação. Este guia é destinado àqueles que já usam papéis em seus manuais e leram
- Tendo encontrado uma variável no código, é impossível entender imediatamente pelo que ela é responsável;
- Existem diversas funções e as variáveis precisam estar associadas a um valor, mas isso simplesmente não funciona;
- Ter dificuldade em explicar aos outros como funciona a lógica das variáveis em seus manuais
Encontramos esses problemas em projetos em nossa empresa, e como resultado chegamos a regras para projetar variáveis em nossos manuais, que até certo ponto resolveram esses problemas.
Variáveis em funções
Uma função é um objeto separado do sistema de implantação. Como qualquer objeto do sistema, ele deve possuir uma interface para interação com o restante do sistema. Essa interface são variáveis de função.
Tomemos, por exemplo, o papel api
, que instala um aplicativo Java no servidor. Que variáveis ele pode ter?
As funções variáveis podem ser divididas em 2 tipos de acordo com o tipo:
1. Свойства
a) независимые от среды
б) зависимые от среды
2. Связи
a) слушатели
б) запросы внутри системы
в) запросы в среду
Propriedades variáveis são variáveis que determinam o comportamento de uma função.
Variáveis de consulta - são variáveis cujo valor é utilizado para designar recursos externos à função.
Ouvintes variáveis - são variáveis cujo valor é utilizado para formar variáveis de solicitação.
Por outro lado, 1a, 2a, 2b são variáveis que não dependem do ambiente (hardware, recursos externos, etc.) e podem ser preenchidas com valores padrão na função de padrões. Porém, é impossível preencher variáveis do tipo 1.b e 2.c com valores diferentes de ‘exemplo’, pois elas mudarão de povoamento para povoamento dependendo do ambiente.
Estilo de código
- O nome da variável deve começar com o nome da função. Isso tornará mais fácil descobrir no futuro qual é a função da variável e pelo que ela é responsável.
- Ao usar variáveis em funções, você deve seguir o princípio do encapsulamento e usar variáveis definidas na própria função ou nas funções das quais a atual depende.
-
Evite usar dicionários para variáveis. Ansible não permite substituir convenientemente valores individuais em um dicionário.
Exemplo de uma variável ruim:
myrole_user: login: admin password: admin
Aqui login é a variável independente e senha é a variável dependente. Mas
já que eles estão combinados em um dicionário, você terá que especificá-lo completamente
Sempre. O que é muito inconveniente. Melhor assim:myrole_user_login: admin myrole_user_password: admin
Variáveis em manuais de implantação
Ao compilar um manual de implantação (doravante denominado manual), aderimos à regra de que ele deve ser colocado em um repositório separado. O mesmo que os papéis: cada um em seu próprio repositório git. Isso permite que você entenda que as funções e o playbook são objetos diferentes e independentes do sistema de implantação e que as alterações em um objeto não devem afetar a operação do outro. Isso é conseguido alterando os valores padrão das variáveis.
Ao compilar um playbook, para resumir, é possível substituir os valores padrão das variáveis de função em dois locais: nas variáveis do playbook e nas variáveis de inventário.
mydeploy # Каталог деплоя
├── deploy.yml # Плейбук деплоя
├── group_vars # Каталог переменных плейбука
│ ├── all.yml # Файл для переменных связи всей системы
│ └── myapi.yml # Файл переменных свойств группы myapi
└── inventories #
└── prod # Каталог окружения prod
├── prod.ini # Инвентори файл
└── group_vars # Каталог для переменных инвентори
└── myapi #
├── vars.yml # Средозависимые переменные группы myapi
└── vault.yml # Секреты (всегда средозависимы) *
A diferença é que as variáveis do playbook são sempre usadas ao chamar playbooks localizados no mesmo nível que ele. Isso significa que essas variáveis são ótimas para alterar os valores padrão de variáveis independentes do ambiente. Por outro lado, as variáveis de inventário serão usadas apenas para um ambiente específico, o que é ideal para variáveis específicas do ambiente.
É importante observar que a prioridade da variável não permitirá que você substitua as variáveis primeiro nas variáveis do playbook e depois separadamente em um inventário.
Isto significa que já nesta fase é necessário decidir se a variável depende do ambiente ou não e colocá-la no local adequado.
Por exemplo, em um projeto, a variável responsável por habilitar o SSL ficou muito tempo dependente do ambiente, pois não pudemos habilitar o SSL por motivos alheios ao nosso controle em um dos estandes. Depois de corrigirmos esse problema, ele se tornou independente do ambiente e passou para as variáveis do playbook.
Variáveis de propriedade para grupos
Vamos expandir nosso modelo na Figura 1 adicionando dois grupos de servidores com um aplicativo Java diferente, mas com configurações diferentes.
Vamos imaginar como será o manual neste caso:
- hosts: myapi
roles:
- api
- hosts: bbauth
roles:
- auth
- hosts: ghauth
roles:
- auth
Temos três grupos no manual, portanto, é imediatamente recomendado criar o mesmo número de arquivos de grupo nas variáveis de inventário group_vars e nas variáveis do manual. Um arquivo de grupo, neste caso, é uma descrição de um componente do aplicativo acima no manual. Ao abrir um arquivo de grupo nas variáveis do playbook, você vê imediatamente todas as diferenças do comportamento padrão das funções instaladas no grupo. Nas variáveis de inventário: diferenças no comportamento do grupo de povoamento para povoamento.
Estilo do código
- Tente não usar variáveis host_vars, pois elas não descrevem o sistema, mas apenas um caso especial, que no futuro levará a perguntas: “Por que este host é diferente dos outros?”, cuja resposta é não sempre fácil de encontrar.
Variáveis de comunicação
No entanto, é disso que se tratam as variáveis de propriedade, mas e as variáveis de comunicação?
A diferença é que devem ter o mesmo significado em grupos diferentes.
No começo foi
hostvars[groups['bbauth'][0]]['auth_bind_port']
, mas eles imediatamente rejeitaram
porque tem desvantagens. Em primeiro lugar, volume. Em segundo lugar, a dependência de um hospedeiro específico do grupo. Em terceiro lugar, antes de iniciar a implantação, é necessário coletar fatos de todos os hosts se não quisermos obter um erro de variável indefinida.
Como resultado, optou-se pela utilização de variáveis de comunicação.
Variáveis de comunicação - são variáveis que pertencem ao manual e são necessárias para conectar objetos do sistema.
Variáveis de comunicação são preenchidas em variáveis gerais do sistema group_vars/all/vars
e são formados removendo todas as variáveis de ouvinte de cada grupo e adicionando o nome do grupo do qual o ouvinte foi removido ao início da variável.
Isso garante a uniformidade e a não sobreposição de nomes.
Vamos tentar vincular as variáveis do exemplo acima:
Vamos imaginar que temos variáveis que dependem umas das outras:
# roles/api/defaults:
# Переменная запроса
api_auth1_address: "http://example.com:80"
api_auth2_address: "http://example2.com:80"
# roles/auth/defaults:
# Переменная слушатель
auth_bind_port: "20000"
Vamos colocar isso em variáveis comuns group_vars/all/vars
todos os ouvintes e adicione o nome do grupo ao título:
# group_vars/all/vars
bbauth_auth_bind_port: "20000"
ghauth_auth_bind_port: "30000"
# group_vars/bbauth/vars
auth_bind_port: "{{ bbauth_auth_bind_port }}"
# group_vars/ghauth/vars
auth_bind_port: "{{ ghauth_auth_bind_port }}"
# group_vars/myapi/vars
api_auth1_address: "http://{{ bbauth_auth_service_name }}:{{ bbauth_auth_bind_port }}"
api_auth2_address: "http://{{ ghauth_auth_service_name }}:{{ ghauth_auth_bind_port }}"
Agora, alterando o valor do conector, teremos certeza de que a solicitação irá para o mesmo local onde está localizada a porta.
Estilo do código
- Como funções e grupos são objetos de sistema diferentes, eles precisam ter nomes diferentes, então as variáveis de link indicarão com precisão que pertencem a um grupo específico de servidores, e não a uma função no sistema.
Arquivos dependentes do ambiente
As funções podem usar arquivos que diferem de ambiente para ambiente.
Um exemplo de tais arquivos são os certificados SSL. Armazene-os em formato de texto
em uma variável não é muito conveniente. Mas é conveniente armazenar o caminho para eles dentro de uma variável.
Por exemplo, usamos a variável api_ssl_key_file: "/path/to/file"
.
Como é óbvio que o certificado chave mudará de ambiente para ambiente, esta é uma variável dependente do ambiente, o que significa que deve estar localizada no arquivo
group_vars/myapi/vars
inventário de variáveis e contém o valor 'por exemplo'.
A maneira mais conveniente neste caso é colocar o arquivo-chave no repositório do playbook ao longo do caminho
files/prod/certs/myapi.key
, então o valor da variável será:
api_ssl_key_file: "prod/certs/myapi.key"
. A comodidade está no fato de os responsáveis pela implantação do sistema em um estande específico também possuírem um espaço próprio no repositório para armazenar seus arquivos. Ao mesmo tempo, ainda é possível especificar o caminho absoluto para o certificado no servidor, caso os certificados sejam fornecidos por outro sistema.
Vários estandes em um ambiente
Muitas vezes há necessidade de implantar vários estandes quase idênticos no mesmo ambiente com diferenças mínimas. Neste caso, dividimos as variáveis dependentes do ambiente entre aquelas que não mudam dentro deste ambiente e aquelas que mudam. E transferimos este último diretamente para os próprios arquivos de inventário. Após esta manipulação, é possível criar outro inventário diretamente no diretório do ambiente.
Ele reutilizará o inventário group_vars e também poderá redefinir algumas variáveis diretamente para si mesmo.
A estrutura de diretório final do projeto de implantação:
mydeploy # Каталог деплоя
├── deploy.yml # Плейбук деплоя
├── files # Каталог для файлов деплоя
│ ├── prod # Католог для средозависимых файлов стенда prod
│ │ └── certs #
│ │ └── myapi.key #
│ └── test1 # Каталог для средозависимых файлов стенда test1
├── group_vars # Каталог переменных плейбука
│ ├── all.yml # Файл для переменных связи всей системы
│ ├── myapi.yml # Файл переменных свойств группы myapi
│ ├── bbauth.yml #
│ └── ghauth.yml #
└── inventories #
├── prod # Каталог окружения prod
│ ├── group_vars # Каталог для переменных инвентори
│ │ ├── myapi #
│ │ │ ├── vars.yml # Средозависимые переменные группы myapi
│ │ │ └── vault.yml # Секреты (всегда средозависимы)
│ │ ├── bbauth #
│ │ │ ├── vars.yml #
│ │ │ └── vault.yml #
│ │ └── ghauth #
│ │ ├── vars.yml #
│ │ └── vault.yml #
│ └── prod.ini # Инвентори стенда prod
└── test # Каталог окружения test
├── group_vars #
│ ├── myapi #
│ │ ├── vars.yml #
│ │ └── vault.yml #
│ ├── bbauth #
│ │ ├── vars.yml #
│ │ └── vault.yml #
│ └── ghauth #
│ ├── vars.yml #
│ └── vault.yml #
├── test1.ini # Инвентори стенда test1 в среде test
└── test2.ini # Инвентори стенда test2 в среде test
Resumindo
Após organizar as variáveis de acordo com o artigo: cada arquivo de variáveis é responsável por uma tarefa específica. E como o arquivo possui determinadas tarefas, tornou-se possível designar alguém responsável pela correção de cada arquivo. Por exemplo, o desenvolvedor da implantação do sistema passa a ser responsável pelo correto preenchimento das variáveis do playbook, enquanto o administrador cujo estande está descrito no inventário é o responsável direto pelo preenchimento do inventário de variáveis.
As funções tornaram-se sua própria unidade de desenvolvimento com sua própria interface, permitindo que o desenvolvedor da função desenvolvesse capacidades em vez de adaptar a função ao sistema. Este problema dizia especialmente respeito aos papéis comuns de todos os sistemas na campanha.
Os administradores de sistema não precisam mais entender o código de implantação. Tudo o que é exigido deles para uma implantação bem-sucedida é preencher os arquivos de variáveis dependentes do ambiente.
Literatura
autor
Kalyuzhny Denis Alexandrovich
Fonte: habr.com