
Olá pessoal. Trabalho como administrador líder de sistema na OK e sou responsável pela operação estável do portal. Quero falar sobre como criamos o processo de substituição automática de discos e, como administrador, foi excluído desse processo e substituído por um bot.
Este artigo é uma espécie de transliteração do
desempenho no HighLoad + 2018
Construindo um processo de substituição de disco
Primeiro alguns números
OK é um serviço gigantesco usado por milhões de pessoas. É servido por cerca de 7 mil servidores, localizados em 4 data centers diferentes. Os servidores custam mais de 70 mil unidades. Se você as empilhar, uma torre terá uma altura superior a 1 km.
Os discos rígidos são um componente do servidor que trava com mais freqüência. Com esses volumes, temos que trocar cerca de 30 discos por semana, e esse procedimento se tornou uma rotina não muito agradável.

Incidentes
Introduzimos um gerenciamento completo de incidentes em nossa empresa. Todo incidente que registramos em Jira e depois resolvemos e desmontamos. Se o incidente teve algum efeito para os usuários, definitivamente pensaremos em como responder mais rapidamente nesses casos, em como reduzir o efeito e, é claro, em como evitar uma recorrência.
Unidades não são exceção. Seu status é monitorado pelo Zabbix. Monitoramos as mensagens no Syslog quanto a erros de gravação / leitura, analisamos o status de ataques HW / SW, monitoramos o SMART e calculamos o desgaste de SSDs.
Como os discos mudaram antes
Quando um gatilho acende no Zabbix, um incidente é criado em Jira e automaticamente colocado nos engenheiros apropriados nos datacenters. Fazemos isso com todos os incidentes de HW, ou seja, aqueles que exigem algum tipo de trabalho físico com o equipamento no data center.
Um engenheiro de um data center é uma pessoa que resolve problemas relacionados ao hardware, é responsável pela instalação, manutenção e desmontagem de servidores. Depois de receber um ingresso, o engenheiro começa a trabalhar. Nas prateleiras de discos, ele troca os discos por conta própria. Mas se ele não tiver acesso ao dispositivo desejado, o engenheiro recorre aos administradores do sistema de plantão para obter ajuda. Primeiro de tudo, você precisa remover o disco da rotação. Para fazer isso, você precisa fazer as alterações necessárias no servidor, parar o aplicativo e desmontar o disco.
O administrador do sistema de plantão durante o turno é responsável pela operação de todo o portal. Ele investiga incidentes, reparos, ajuda os desenvolvedores a realizar pequenas tarefas. Ele não lida apenas com discos rígidos.
Anteriormente, os engenheiros do data center conversavam com o administrador do sistema. Os engenheiros enviaram links para os tickets do Jira, o administrador passou por eles, manteve um registro do trabalho em algum bloco de notas. Mas os bate-papos são inconvenientes para essas tarefas: as informações não são estruturadas e são rapidamente perdidas. E o administrador poderia simplesmente se afastar do computador e, por algum tempo, não responder às solicitações, e o engenheiro ficou no servidor com um monte de discos e esperou.
Mas o pior foi que os administradores não viram a imagem completa: quais incidentes de disco existem, onde o problema pode potencialmente surgir. Isso se deve ao fato de fornecermos todos os incidentes de HW aos engenheiros. Sim, foi possível exibir todos os incidentes no painel do administrador. Mas existem muitos, e o administrador estava envolvido apenas em alguns deles.
Além disso, o engenheiro não pôde priorizar corretamente, porque ele não sabe nada sobre a finalidade de servidores específicos, sobre a distribuição de informações entre unidades.
Novo procedimento de substituição
A primeira coisa que fizemos foi levar todos os incidentes de disco para um tipo separado de "disco HW" e adicionar os campos "nome do dispositivo de bloco", "tamanho" e "tipo de disco" a ele, para que essas informações fossem salvas no ticket e não fossem necessárias. conversando constantemente.
Também concordamos que, no âmbito de um incidente, alteraremos apenas um disco. Isso simplificou bastante o processo de automação, coleta de estatísticas e trabalho.
Além disso, o campo "administrador responsável" foi adicionado. O administrador do sistema é substituído automaticamente lá. Isso é muito conveniente, porque agora o engenheiro sempre vê quem é o responsável. Não há necessidade de ir ao calendário e pesquisar. Foi esse campo que permitiu colocar tickets no painel do administrador, no qual, talvez, sua ajuda fosse necessária.
Para garantir que todos os participantes recebam o máximo benefício das inovações, criamos filtros e painéis, informamos os caras sobre eles. Quando as pessoas entendem as mudanças, elas não se distanciam delas como de algo desnecessário. É importante que um engenheiro saiba o número do rack em que o servidor está localizado, o tamanho e o tipo de disco. O administrador precisa, antes de tudo, entender que tipo de grupo de servidores é esse, que tipo de efeito pode ter ao substituir um disco.
A presença de campos e sua exibição é conveniente, mas isso não nos salvou da necessidade de usar bate-papos. Para fazer isso, tive que alterar o fluxo de trabalho.
Costumava ser assim:
Hoje, os engenheiros continuam trabalhando assim quando não precisam de ajuda do administrador.
A primeira coisa que fizemos foi introduzir um novo status do
Investigate . O ticket está nesse status quando o engenheiro ainda não decidiu se precisará de um administrador ou não. Por esse status, o engenheiro pode passar o ticket ao administrador. Além disso, marcamos tickets com esse status quando uma substituição de disco é necessária, mas não existe um disco em si no site. Isso acontece com CDNs e sites remotos.
Também adicionamos o status
Pronto . O ticket é transferido para ele após a substituição do disco. Ou seja, tudo já foi feito, mas o HW / SW RAID está sincronizado no servidor. Isso pode ser bastante demorado.
Se um administrador estiver envolvido, o esquema é um pouco mais complicado.
No status
Aberto , um ticket pode ser transferido por um administrador do sistema e um engenheiro. No status
Em andamento , o administrador remove o disco da rotação para que o engenheiro possa simplesmente removê-lo: acende a luz de fundo, desmonta o disco e interrompe os aplicativos, dependendo do grupo de servidores específico.
Em seguida, o ticket é convertido em
Pronto para alterar : este é um sinal para o engenheiro de que o disco pode ser extraído. Todos os campos em Jira já estão preenchidos, o engenheiro sabe que tipo e tamanho do disco. Esses dados são afixados no status anterior automaticamente ou pelo administrador.
Após a substituição do disco, o ticket é transferido para o status
Alterado . Verifica-se que o disco correto foi inserido, a marcação foi concluída, o aplicativo foi iniciado e algumas tarefas de recuperação de dados foram executadas. Além disso, o ticket pode ser transferido para o status
Pronto ; nesse caso, o administrador permanecerá responsável, porque iniciou o disco em rotação. O esquema completo é assim.
A adição de novos campos tornou nossa vida muito mais fácil. Os caras começaram a trabalhar com informações estruturadas, ficou claro o que e em que estágio fazer. As prioridades se tornaram muito mais relevantes, pois agora são definidas pelo administrador.
A necessidade de bate-papos desapareceu. Obviamente, o administrador pode escrever para o engenheiro "você precisa substituir mais rápido aqui" ou "já à noite, você terá tempo para substituir?". Mas não conversamos mais diariamente sobre essas questões.
Os discos começaram a mudar de embalagem. Se o administrador chegou ao trabalho um pouco antes, ele tem tempo livre e nada aconteceu, ele pode preparar vários servidores para substituição: colocar campos, remover discos da rotação e transferir a tarefa para o engenheiro. Mais tarde, um engenheiro chega ao data center, vê a tarefa, pega as unidades necessárias no armazém e as altera imediatamente. Como resultado, a velocidade de substituição aumentou.
Lições aprendidas na criação de fluxo de trabalho
- Ao criar um procedimento, você precisa coletar informações de diferentes fontes.
Alguns de nossos administradores não sabiam que o engenheiro alterou os discos por conta própria. Alguns pensaram que os engenheiros monitoravam a sincronização MD RAID, embora alguns deles nem sequer tivessem acesso a isso. Alguns engenheiros líderes fizeram isso, mas nem sempre, porque o processo não foi descrito em nenhum lugar. - O procedimento deve ser simples e direto.
É difícil para uma pessoa manter muitos passos na cabeça. Os status vizinhos mais importantes em Jira precisam ser exibidos na tela principal. Você pode renomeá-los, por exemplo, Em andamento, chamamos Pronto para alterar. E os status restantes podem ser ocultados no menu suspenso para que não causem calos nos olhos. Mas é melhor não limitar as pessoas, dar a oportunidade de fazer a transição.
Explique o valor da inovação. Quando as pessoas entendem, elas aceitam melhor o novo procedimento. Era muito importante para nós que as pessoas não chamassem o processo inteiro, mas o seguissem. Então construímos essa automação. - Espere, analise, entenda.
Levamos cerca de um mês para elaborar o procedimento, implementação técnica, reuniões e discussões. E para implementação - mais de três meses. Vi como as pessoas estão lentamente começando a usar a inovação. Nos estágios iniciais, havia muita negatividade. Mas ele era completamente independente do procedimento em si, sua implementação técnica. Por exemplo, um administrador não usou o Jira, mas o plugin Jira no Confluence, e algumas coisas não estavam disponíveis para ele. Mostrou a ele Jira, o administrador aumentou a produtividade, as tarefas gerais e a substituição de discos.
Automação de substituição de unidades
Passamos para a automação de substituição de discos várias vezes. Já tínhamos tempo operacional, scripts, mas todos funcionavam interativamente ou no modo manual, eles exigiam o lançamento. E somente após a introdução do novo procedimento, percebemos que estávamos faltando.
Como agora o processo de substituição está dividido em estágios, cada um com um executor e uma lista de ações, podemos ativar a automação por estágios, e não todos de uma vez. Por exemplo, a etapa mais simples - Ready (verificação de sincronização RAID / dados) pode ser facilmente delegada ao bot. Quando o bot aprende um pouco, você pode dar a ele uma tarefa mais responsável - colocar o disco em rotação etc.
Configurações do zoológico
Antes de falar sobre o bot, faremos uma pequena excursão ao nosso zoológico de instalação. Primeiro de tudo, é devido ao tamanho gigantesco de nossa infraestrutura. Em segundo lugar, para cada serviço, tentamos escolher a configuração ideal de ferro. Temos cerca de 20 modelos RAID de hardware, principalmente LSI e Adaptec, mas existem HP e DELL de versões diferentes. Cada controlador RAID possui seu próprio utilitário de gerenciamento. O conjunto de comandos e a emissão deles podem diferir de versão para versão de cada controlador RAID. Onde o HW-RAID não é usado, pode haver medo.
Quase todas as novas instalações que fazemos sem backup em disco. Tentamos não usar mais o RAID de hardware e software, pois reservamos nossos sistemas no nível de data centers, não servidores. Mas é claro que existem muitos servidores herdados que precisam ser suportados.
Em algum lugar, os discos nos controladores RAID lançam dispositivos brutos; em algum lugar, eles usam JBOD. Existem configurações com uma unidade de sistema no servidor e, se você precisar substituí-lo, precisará reformatar o servidor com a instalação do sistema operacional e dos aplicativos, com as mesmas versões, adicionar arquivos de configuração e iniciar aplicativos. Também existem muitos grupos de servidores nos quais a redundância é realizada não no nível do subsistema de disco, mas diretamente nos próprios aplicativos.
No total, temos mais de 400 grupos exclusivos de servidores que executam cerca de 100 aplicativos diferentes. Para cobrir um número tão grande de opções, precisávamos de uma ferramenta de automação multifuncional. É aconselhável com uma DSL simples, para que não apenas a pessoa que escreveu isso possa apoiá-la.
Escolhemos o Ansible porque é sem agente: não havia necessidade de preparar a infraestrutura, início rápido. Além disso, está escrito em Python, aceito como padrão na equipe.
Esquema geral
Vejamos um esquema geral de automação usando um incidente como exemplo. O Zabbix detecta que a unidade sdb está com defeito, o gatilho acende e um ticket é criado em Jira. O administrador olhou para ele, percebeu que isso não é um duplicado e não é falso positivo, ou seja, você precisa alterar o disco e converte o ticket em andamento.

O aplicativo DiskoBot escrito em Python pesquisa periodicamente Jira em busca de novos tickets. Ele percebe que um novo tíquete em andamento apareceu, o encadeamento correspondente é acionado, que inicia o manual no Ansible (isso é feito para cada status no Jira). Nesse caso, o Prepare2change é iniciado.
O Ansible vai para o host, remove o disco da rotação e relata o status ao aplicativo por meio de retornos de chamada.

De acordo com os resultados, o bot transfere automaticamente o ticket para Pronto para alterar. O engenheiro recebe uma notificação e muda o disco, após o que transfere o ticket para Alterado.

De acordo com o esquema acima, o ticket retorna ao bot, lança outro manual, vai para o host e entra no disco em rotação. O bot fecha o ticket. Viva!

Agora vamos falar sobre alguns dos componentes do sistema.
Diskobot
Esta aplicação está escrita em Python. Ele seleciona tickets do Jira de acordo com o
JQL . Dependendo do status do ticket, o último chega ao manipulador correspondente, que, por sua vez, inicia o status correspondente do manual Ansible.
Intervalos de pesquisa e JQL são definidos no arquivo de configuração do aplicativo.
jira_states: investigate: jql: '… status = Open and "Disk Size" is EMPTY' interval: 180 inprogress: jql: '… and "Disk Size" is not EMPTY and "Device Name" is not EMPTY' ready: jql: '… and (labels not in ("dbot_ignore") or labels is EMPTY)' interval: 7200
Por exemplo, entre os tickets no status Em andamento, apenas aqueles com os campos Tamanho do disco e Nome do dispositivo são preenchidos. Nome do dispositivo é o nome do dispositivo de bloco necessário para executar o manual. O tamanho do disco é necessário para que o engenheiro saiba qual o tamanho do disco.
E entre os tickets com status Ready, os tickets com o rótulo dbot_ignore são filtrados. A propósito, usamos rótulos Jira tanto para essa filtragem quanto para marcar tickets duplicados e coletar estatísticas.
Se o manual falhar, Jira atribui o rótulo dbot_failed para que você possa descobrir mais tarde.
Interação com Ansible
O aplicativo interage com o Ansible por meio da
API Ansible Python . No playbook_executor, passamos o nome do arquivo e o conjunto de variáveis. Isso permite que você mantenha o projeto Ansible na forma de arquivos yml regulares, em vez de descrevê-lo no código Python.
Também em Ansible, através de * extra_vars *, o nome do dispositivo de bloco, o status do ticket, bem como callback_url, no qual a chave de emissão é costurada, é usado - é usado para retorno de chamada em HTTP.
Para cada ativação, um inventário temporário é gerado, consistindo em um host e no grupo ao qual esse host pertence, para que group_vars seja aplicado.
Aqui está um exemplo de uma tarefa na qual o retorno de chamada HTTP é implementado.
O resultado das cartilhas que usamos usando callaback (s). Eles são de dois tipos:
- Plug-in de retorno de chamada aceitável , fornece dados sobre os resultados de um manual. Ele descreve as tarefas que foram iniciadas, executadas com ou sem êxito. Esse retorno de chamada é chamado no final do manual.
- Retorno de chamada HTTP para obter informações durante a reprodução de um manual. No Ansible, realizamos uma solicitação POST / GET ao lado de nosso aplicativo.
Por meio de retorno (s) de HTTP, são transmitidas as variáveis definidas durante a execução do manual e que queremos salvar e usar nas execuções subseqüentes. Nós escrevemos esses dados no sqlite.
Também por meio de retorno de chamada HTTP, deixamos comentários e alteramos o status do ticket.
Retorno de chamada HTTP # Make callback to Diskobot App # Variables: # callback_post_body: # A dict with follow keys. All keys are optional # msg: If exist it would be posted to Jira as comment # data: If exist it would be saved in Incident.variables # desire_state: Set desire_state for incident # status: If exist Proceed issue to that status - name: Callback to Diskobot app (jira comment/status) uri: url: "{{ callback_url }}/{{ devname }}" user: "{{ diskobot_user }}" password: "{{ diskobot_pass }}" force_basic_auth: True method: POST body: "{{ callback_post_body | to_json }}" body_format: json delegate_to: 127.0.0.1
Como muitas tarefas do mesmo tipo, colocamos em um arquivo comum separado e o incluímos, se necessário, para não repetir constantemente nos manuais. Callback_ url aparece aqui, no qual a chave do problema e o nome do host estão protegidos. Quando o Ansible executa essa solicitação POST, o bot percebe que veio como parte de um incidente desse tipo.
E aqui está um exemplo de um manual, no qual exibimos um disco de um dispositivo MD:
# Save mdadm configuration - include: common/callback.yml vars: callback_post_body: status: 'Ready to change' msg: "Removed disk from mdraid {{ mdadm_remove_disk.msg | comment_jira }}" data: mdadm_data: "{{ mdadm_remove_disk.removed }}" parted_info: "{{ parted_info | default() }}" when: - mdadm_remove_disk | changed - mdadm_remove_disk.removed
Esta tarefa coloca o ticket Jira no status "Pronto para alterar" e adiciona um comentário. Além disso, a variável mdam_data armazena a lista de dispositivos md dos quais o disco foi excluído e o despejo dividido em parted_info.
Quando o engenheiro inserir um novo disco, poderemos usar essas variáveis para restaurar o despejo de partição, além de inserir o disco nos dispositivos md dos quais ele foi excluído.
Modo de verificação Ansible
Ligar a automação foi assustador. Portanto, decidimos executar todos os playbooks no modo
execução a seco , na qual o Ansible não executa nenhuma ação nos servidores, mas apenas as emula.
Esse lançamento é executado por meio de um módulo de retorno de chamada separado, e o resultado do manual é salvo no Jira como um comentário.

Em primeiro lugar, permitiu validar o trabalho do bot e playbooks. Em segundo lugar, aumentou a confiança dos administradores no bot.
Quando passamos pela validação e percebemos que você pode executar o Ansible não apenas no modo de execução a seco, criamos o botão Executar Diskobot no Jira para iniciar o mesmo manual com as mesmas variáveis no mesmo host, mas no modo normal.
Além disso, o botão é usado para reiniciar o manual em caso de falha.
Estrutura de Playbooks
Eu já mencionei que, dependendo do status do ingresso de Jira, o bot lança diferentes playbooks.
Em primeiro lugar, é muito mais fácil organizar a entrada.
Em segundo lugar, em alguns casos, é simplesmente necessário.
Por exemplo, ao substituir um disco do sistema, você primeiro precisa acessar o sistema de implantação, criar uma tarefa e, após a implantação correta, o servidor estará acessível via ssh, e você poderá aplicar o aplicativo nele. Se fizermos tudo isso em um manual, o Ansible não poderá executá-lo devido à inacessibilidade do host.
Usamos funções Ansible para cada grupo de servidores. Aqui você pode ver como os manuais estão organizados em um deles.

Isso é conveniente, porque fica imediatamente claro onde estão localizadas as tarefas. No main.yml, que é a entrada para a função Ansible, podemos incluir apenas pelo status do ticket ou tarefas gerais necessárias para todos, por exemplo, passar a identificação ou receber um token.
Investigation.yml
É executado para tickets no status de Investigação e Aberto. O mais importante para este manual é o nome do dispositivo de bloco. Esta informação nem sempre está disponível.
Para obtê-lo, analisamos o resumo do Jira, o último valor do gatilho Zabbix. Pode conter o nome do dispositivo de bloco - com sorte. Ou pode conter um ponto de montagem, - então você precisa ir ao servidor, analisar e calcular a unidade desejada. Além disso, um gatilho pode transmitir um endereço scsi ou alguma outra informação. Mas também acontece que não há pistas e você precisa analisar.
Após descobrir o nome do dispositivo de bloco, coletamos informações sobre o tipo e tamanho do disco para preencher os campos em Jira. Também removemos informações sobre o fornecedor, modelo, firmware, ID, SMART e inserimos tudo isso em um comentário no ticket Jira. O administrador e o engenheiro não precisam mais procurar esses dados. :)
prepare2change.yml
A saída do disco da rotação, preparação para substituição. O estágio mais difícil e crucial. É aqui que você pode parar o aplicativo quando ele não pode ser parado. Ou retire um disco que não possui réplicas suficientes e, portanto, tenha efeito sobre os usuários, perca alguns dados. Aqui temos o maior número de verificações e notificações no chat.
No caso mais simples, estamos falando sobre remover uma unidade do HW / MD RAID.
Em situações mais complexas (em nossos sistemas de armazenamento), quando o backup é realizado no nível do aplicativo, você precisa acessar o aplicativo usando a API, relatar a saída do disco, desativá-la e iniciar a recuperação.
Agora estamos migrando massivamente para a
nuvem e, se o servidor estiver nublado, o Diskobot acessa a API da nuvem, diz que vai trabalhar com este minion - o servidor no qual os contêineres estão sendo executados - e pergunta "migrar todos os contêineres deste minion". E, ao mesmo tempo, acende a luz de fundo para que o engenheiro veja imediatamente qual retirar.
changing.yml
Depois de substituir um disco, primeiro verificamos sua disponibilidade.
Os engenheiros nem sempre colocam novos discos; portanto, adicionamos uma verificação dos valores SMART que nos satisfazem.
Quais atributos estamos vendoContagem de setores realocados (5) <100
Contagem atual de setores pendentes (107) == 0
Se a unidade falhar no teste, o engenheiro é notificado de uma substituição. Se tudo estiver em ordem, a luz de fundo se apaga, a marcação é aplicada e o disco é inserido em rotação.
ready.yml
O caso mais simples: verificar a sincronização de raides HW / SW ou encerrar a sincronização de dados no aplicativo.
API do aplicativo
Mencionei várias vezes que o bot geralmente acessa as APIs do aplicativo. Obviamente, nem todos os aplicativos tinham os métodos necessários, então eu tive que refiná-los. Aqui estão os métodos mais importantes que usamos:
- Status O status de um cluster ou disco para entender se é possível trabalhar com ele;
- Iniciar / parar. Ativação-desativação do disco;
- Migrar / restaurar. Migração e recuperação de dados durante e após a substituição.
Lições Aprendidas pela Ansible
Eu realmente amo Ansible. Mas, muitas vezes, quando olho para diferentes projetos de código aberto e vejo como as pessoas escrevem playbooks, fico um pouco assustada. Tecido lógico complexo a partir de quando / loop, falta de flexibilidade e idempotência devido ao uso frequente de shell / comando.
Decidimos simplificar tudo o máximo possível, aproveitando o Ansible - modularidade. No nível mais alto estão os playbooks, eles podem ser escritos por qualquer administrador, um desenvolvedor de terceiros que conheça Ansible um pouco.
- name: Blink disk become: True register: locate_action disk_locate: locate: '{{ locate }}' devname: '{{ devname }}' ids: '{{ locate_ids | default(pd_id) | default(omit) }}'
Se alguma lógica é difícil de implementar nos playbooks, a colocamos em um módulo ou filtro Ansible. Os scripts podem ser escritos em Python e em qualquer outro idioma.
Eles são fáceis e rápidos de escrever. Por exemplo, o módulo de destaque de disco, um exemplo do uso acima, consiste em 265 linhas.

No nível mais baixo é a biblioteca. Para este projeto, escrevemos um aplicativo separado, um tipo de abstração sobre os RAIDs de hardware e software que executam as solicitações correspondentes.

Os maiores pontos fortes da Ansible são sua simplicidade e playbooks compreensíveis. Eu acredito que você precisa usar isso e não gerar arquivos yaml assustadores e um grande número de condições, código de shell e loops.
Se você deseja repetir nossa experiência com a API Ansible, lembre-se de duas coisas:
- Playbook_executor e geralmente o playbook não pode ter o tempo limite esgotado. Há um tempo limite na sessão ssh, mas não há tempo limite no manual. Se tentarmos desmontar uma unidade que ainda não existe no sistema, o playbook será executado indefinidamente; portanto, tivemos que envolvê-lo em um invólucro separado e eliminar por tempo limite.
- O Ansible é bifurcado, portanto sua API não é segura para threads. Lançamos todos os nossos playbooks e single-threaded.
Como resultado, conseguimos automatizar a substituição de cerca de 80% das unidades. Em geral, a taxa de substituição dobrou. Hoje, o administrador apenas analisa o incidente e decide se deseja alterar o disco ou não e, em seguida, dá um clique.
Mas agora estamos começando a enfrentar outro problema: alguns novos administradores não sabem como mudar de unidade. :)