Estamos usando o systemd para executar vários serviços em produção. (Dã...)
Estamos construindo um site de "recuperação de desastres" correspondente, que terá o mesmo aplicativo instalado -- com as mesmas unidades de sistema para ativar seus vários componentes em caso de desastre .
Este ambiente de DR é "quente", pronto para assumir o controle em pouco tempo (quanto mais curto, melhor) - tornando-se assim a própria produção. Então, quando o "desastre" for resolvido, o outro ambiente se tornará o DR.
Minha pergunta é: como manter esses serviços do systemd prontos para iniciar, mas não iniciando até que uma determinada condição se torne verdadeira?
Para concluir que um determinado site é atualmente o primário (produção), um comando ( amIthePrimary
) precisa ser executado e sair com um código de saída 0. A verificação é fácil e rápida - e pode ser realizada uma vez por minuto. Mas, porque requer a execução de um comando, não há Condition
para isso fornecido pelo systemd .
Eu coloco esse comando em cada unidade ExecPre
, ou isso se tornará um erro barulhento, incomodando desnecessariamente os administradores? Coloco-o em uma unidade própria, com todos os outros serviços Require
?
Separadamente, uma vez que a condição é verdadeira -- e os serviços são iniciados -- como continuo verificando, para que todos sejam desligados, caso se torne falso novamente?
Como seu caso de uso é bastante personalizado e suas necessidades podem mudar no futuro, por que você não faz algo como o seguinte...
crie um novo timer systemd (por exemplo
failover-manager
, ) em ambas as máquinas que execute uma vez por minuto. O timer systemd iniciará um serviço systemd one-shot associado em intervalos regulares.Esse serviço systemd one-shot pode apenas executar um script bash que contém sua lógica:
amIthePrimary
chequeDessa forma, você sempre sabe que pode monitorar se sua verificação regular/temporizador está sendo executada sem erros. Se o seu serviço de timer tiver problemas (saída diferente de zero), você poderá detectar isso com o monitoramento. Você pode monitorar as falhas do seu serviço de aplicativo principal separadamente.
Se suas necessidades mudarem, você pode facilmente adaptar seu script de timer ou a frequência em que ele é executado.
Provavelmente existem maneiras mais limpas de fazer isso, mas elas provavelmente dependeriam de um evento sendo gerado a partir do que está por trás do seu
amIthePrimary
cheque... e você não forneceu nenhum detalhe sobre isso. ou seja, failover orientado a eventos em vez de polling.Você também pode colocar sua
amIthePrimary
verificação emExecStartPre=
... mas quando ele falhar em impedir que o serviço seja iniciado, seu serviço estará em um estado FAILED, o que pode confundir seu monitoramento porque não é uma falha ruim, mas sim uma falha intencional. Portanto, talvez você prefira usar a abordagem do temporizador, pois pode monitorar seu processo de temporizador e seu processo de serviço principal separadamente. timer deve estar sempre em execução, ativo e não falhando. Seu serviço (se estiver em execução) nunca deve estar em um estado de falha ou o monitoramento deve ser desativado. Há outra questão sobre como saber se o serviço deve ou não estar sendo executado sob uma perspectiva de monitoramento, mas isso está além do escopo da questão.Atualização - incluindo exemplo de implementação de amostra
Não testado, mas apenas para deixar minha sugestão mais clara.
failover-manager.sh
Digamos que este script seja implantado para
/opt/failover-manager/failover-manager.sh
failover-manager.timer
failover-manager.service
Esse cara é executado pelo temporizador acima.
opções puras do systemd?
Se você estiver procurando por um mecanismo systemd puro para fazer isso de maneira limpa, talvez não seja possível.
Seu caso de uso é personalizado e IMO além do escopo do systemd.
Portanto, você pode "hackear" usando
ExecStartPre
ou usandorequires
/wants
mecanismos de dependência de tipo ... mas todas essas abordagens dependem de um processo estar no estado parado devido a uma falha (monitoramento de interrupções ... ... ou esse processo sendo iniciado/parado por "algo" que está ciente de algo fora do mundo systemd. O último não interrompe o monitoramento, mas requer algo além do systemd e o que propus é uma maneira de fazer isso.alternativas
Como @anx sugeriu... talvez re-engenharia como seu failover de DR funciona.
Essa também é a abordagem que adotamos. Se tivermos uma caixa de espera/nuvem/rack/etc, então gostamos de ter certeza de que tudo já está funcionando (por exemplo, serviços, etc).
Então a questão é apenas... como fazer a transição.
Há duas maneiras comuns de realizar o failover para um endpoint em espera...
1 - Failover DNS
Defina um ttl DNS baixo (tempo de cache) para seus terminais críticos e atualize seus registros DNS para apontar para o terminal em espera (por exemplo, atualização de DNS CNAME, A, AAAA) quando uma falha for detectada.
Muitos provedores de DNS gerenciados (por exemplo, dnsmadeeasy, dynect) oferecem isso como parte de seu serviço (detecção e failover). Mas é claro que você pode implementar isso com seu próprio DNS ou qualquer provedor de DNS que permita definir um TTL baixo e facilmente, manual ou automaticamente (monitoramento + API DNS) atualizar seus registros DNS.
Um problema potencial aqui é que você pode se preocupar com bots fazendo solicitações para o endpoint "não ativo". Isso definitivamente acontecerá, mas se seu aplicativo for bem projetado, não interromperá nada ter algumas solicitações chegando ao ponto de extremidade de DR em espera.
O bom é que isso força você a pensar em como tornar sua arquitetura de aplicativo mais robusta em termos de vários endpoints simultâneos recebendo tráfego (compartilhamento de bancos de dados, replicação, etc).
Se for um grande problema você pode adicionar regras do iptables para gerenciar isso...mas então você pode ter o mesmo problema de antes... para que o failover aconteça).
2 - failover do balanceador de carga
É bastante comum ter servidores em espera que não estão ativos em um balanceador de carga e podem ser rapidamente adicionados/trocados no pool de servidores ativos atrás do balanceador de carga.
Nesse caso, o balanceador de carga ou um terceiro componente pode gerenciar as verificações de integridade e atualizar a configuração do balanceador de carga para trocar servidores íntegros por não íntegros.
Isso não funciona tão bem para um caso de DR, pois os balanceadores de carga geralmente são locais de rack ou datacenter. Portanto, para DR, provavelmente é melhor criar um failover baseado em DNS para um data center/região diferente.