Requisitos para desenvolver uma aplicação em Kubernetes

Hoje pretendo falar sobre como escrever aplicativos e quais são os requisitos para que seu aplicativo funcione bem no Kubernetes. Para que não haja dores de cabeça com o aplicativo, para que você não precise inventar e construir “arranhões” em torno dele - e tudo funcione da maneira que o próprio Kubernetes pretendia.

Esta palestra faz parte do "Slurm Night School no Kubernetes" Você pode assistir às aulas teóricas abertas da Escola Noturna no Youtube, agrupados em uma playlist. Para quem prefere texto ao vídeo, preparamos este artigo.

Meu nome é Pavel Selivanov, atualmente sou engenheiro líder de DevOps na Mail.ru Cloud Solutions, fazemos nuvens, fazemos gerenciamento de kubernetes e assim por diante. Minhas tarefas agora incluem assistência no desenvolvimento, implantação dessas nuvens, implantação dos aplicativos que escrevemos e desenvolvimento direto das ferramentas que fornecemos aos nossos usuários.

Requisitos para desenvolver uma aplicação em Kubernetes

Tenho feito DevOps, acho que provavelmente há três anos. Mas, em princípio, tenho feito o que o DevOps faz há provavelmente cerca de cinco anos. Antes disso, eu estava principalmente envolvido com assuntos administrativos. Comecei a trabalhar com Kubernetes há muito tempo - provavelmente já se passaram cerca de quatro anos desde que comecei a trabalhar com ele.

Em geral, comecei quando o Kubernetes era a versão 1.3, provavelmente, e talvez 1.2 - quando ainda estava em sua infância. Agora não está mais em sua infância - e é óbvio que há uma enorme demanda no mercado por engenheiros que gostariam de poder fazer Kubernetes. E as empresas têm uma demanda muito alta por essas pessoas. Portanto, de fato, esta palestra apareceu.

Se falarmos de acordo com o plano do que irei falar, fica assim, entre colchetes está escrito (TL;DR) - “muito longo; não leia". Minha apresentação de hoje consistirá em listas intermináveis.

Requisitos para desenvolver uma aplicação em Kubernetes

Na verdade, eu mesmo não gosto dessas apresentações quando são feitas, mas este é um assunto tão grande que quando estava preparando esta apresentação, simplesmente não descobri como organizar essas informações de forma diferente.

Porque, em geral, essas informações são “ctrl+c, ctrl+v”, de, entre outras coisas, nosso Wiki na seção DevOps, onde escrevemos requisitos para desenvolvedores: “pessoal, para que lancemos sua aplicação em Kubernetes, deveria ser assim."

É por isso que a apresentação acabou sendo uma lista tão grande. Desculpe. Tentarei contar o máximo possível para que não seja chato, se possível.

O que vamos ver agora:

  • estes são, em primeiro lugar, logs (logs de aplicativos?), o que fazer com eles no Kubernetes, o que fazer com eles, o que deveriam ser;
  • o que fazer com as configurações no Kubernetes, quais as melhores e piores formas de configurar uma aplicação para Kubernetes;
  • Vamos falar sobre o que são as verificações de acessibilidade em geral, como devem ser;
  • vamos falar sobre o que é um desligamento normal;
  • vamos falar novamente sobre recursos;
  • Vamos abordar o tema armazenamento de dados mais uma vez;
  • e no final direi qual é o termo desse misterioso aplicativo nativo da nuvem. Cloudnativeness, como adjetivo deste termo.

Logs

Sugiro começar com os logs - onde esses logs precisam ser colocados no Kubernetes. Agora você lançou um aplicativo no Kubernetes. De acordo com os clássicos, anteriormente os aplicativos sempre escreviam logs em algum lugar de um arquivo. Aplicativos ruins gravaram logs em um arquivo no diretório inicial do desenvolvedor que iniciou o aplicativo. Bons aplicativos gravaram logs em um arquivo em algum lugar /var/log.

Requisitos para desenvolver uma aplicação em Kubernetes

Assim, além disso, bons administradores tinham algumas coisas configuradas em suas infraestruturas para que esses logs pudessem girar - o mesmo rsyslog, que olha esses logs e quando algo acontece com eles, são muitos, ele cria cópias de backup, coloca os logs lá , exclui arquivos antigos, há mais de uma semana, seis meses e mais alguns. Em teoria, deveríamos ter disposições para que, simplesmente porque a aplicação grava logs, o espaço nos servidores de produção (servidores de combate?) não acabe. E, consequentemente, toda a produção não parou por causa das toras.

Quando passamos para o mundo do Kubernetes e executamos a mesma coisa lá, a primeira coisa que você pode prestar atenção é o fato de que as pessoas, à medida que escrevem logs em um arquivo, continuam a escrevê-los.

Acontece que se falamos sobre Kubernetes, o lugar certo para escrever logs em algum lugar de um contêiner docker é simplesmente gravá-los do aplicativo para o chamado Stdout/Stderr, ou seja, os fluxos de saída padrão do sistema operacional, a saída de erro padrão. Esta é a maneira mais correta, simples e lógica de colocar logs em princípio no Docker e especificamente no Kubernetis. Porque se seu aplicativo grava logs em Stdout/Stderr, cabe ao Docker e ao complemento Kubernetes decidir o que fazer com esses logs. Por padrão, o Docker construirá seus arquivos especiais no formato JSON.

Aqui surge a pergunta: o que você fará a seguir com esses logs? A maneira mais fácil é clara, temos a capacidade de fazer kubectl logs e veja esses registros desses “pods”. Mas, provavelmente, esta não é uma opção muito boa - algo mais precisa ser feito com os logs.

Por enquanto, vamos conversar ao mesmo tempo, já que tocamos no tópico dos logs, sobre como os logs deveriam ser. Ou seja, isso não se aplica diretamente ao Kubernetes, mas quando começarmos a pensar no que fazer com os logs, seria bom pensar nisso também.

Precisamos de algum tipo de ferramenta, de forma amigável, que pegue esses logs que nosso docker coloca em seus arquivos e os envie para algum lugar. Em geral, geralmente lançamos algum tipo de agente dentro do Kubernetes na forma de um DaemonSet - um coletor de log, que simplesmente informa onde estão localizados os logs que o Docker coleta. E esse agente coletor simplesmente os pega, talvez até os analise de alguma forma ao longo do caminho, talvez os enriqueça com alguma metainformação adicional e, em última análise, os envie para armazenamento em algum lugar. Variações já são possíveis lá. O mais comum é provavelmente o Elasticsearch, onde você pode armazenar logs e recuperá-los convenientemente de lá. Então, usando uma solicitação, usando o Kibana, por exemplo, construa gráficos com base neles, construa alertas com base neles e assim por diante.

A ideia mais importante, quero repetir novamente, é que dentro do Docker, em particular dentro do Kubernetes, armazenar seus logs em um arquivo é uma péssima ideia.

Porque, em primeiro lugar, é difícil colocar os logs dentro do contêiner em um arquivo. Você deve primeiro entrar no contêiner, executar lá e depois examinar os logs. O próximo ponto é que se você tiver logs em um arquivo, os contêineres geralmente terão um ambiente minimalista e não haverá utilitários que normalmente são necessários para o trabalho normal com logs. Enterre-os, observe-os, abra-os em um editor de texto. O próximo momento é quando temos logs em um arquivo dentro de um container, se esse container for deletado, você entende, os logs vão morrer junto com ele. Conseqüentemente, qualquer reinicialização do contêiner significa que não há mais logs. Novamente, má opção.

E o último ponto é que dentro dos containers você normalmente tem sua aplicação e pronto – normalmente é o único processo em execução. Não se fala em nenhum processo que rotacione arquivos com seus logs. Assim que os logs começarem a ser gravados em um arquivo, isso significa que, com licença, começaremos a perder o servidor de produção. Porque, em primeiro lugar, são difíceis de encontrar, ninguém os rastreia e ninguém os controla - conseqüentemente, o arquivo cresce indefinidamente até que o espaço no servidor simplesmente acabe. Portanto, repito que fazer login no Docker, em particular no Kubernetes, em um arquivo é uma má ideia.

O próximo ponto, aqui quero falar sobre isso novamente - já que estamos tocando no tópico de logs, seria bom falar sobre como os logs devem ser para facilitar o trabalho com eles. Como eu disse, o tema não está diretamente relacionado ao Kubernetes, mas se relaciona muito bem com o tema DevOps. Sobre o tema cultura de desenvolvimento e amizade entre esses dois departamentos distintos - Dev e Ops, para que todos fiquem confortáveis.

Isso significa que, idealmente, hoje, os logs devem ser escritos no formato JSON. Se você tem algum aplicativo incompreensível que grava logs em formatos incompreensíveis porque você insere algum tipo de impressão ou algo parecido, então é hora de pesquisar no Google algum tipo de estrutura, algum tipo de wrapper que permite implementar o log normal; habilite parâmetros de registro em JSON lá, porque JSON é um formato simples, analisá-lo é simples.

Se o seu JSON não funcionar de acordo com alguns critérios, ninguém sabe quais, pelo menos escreva os logs em um formato que possa ser analisado. Aqui, em vez disso, vale a pena pensar no fato de que, por exemplo, se você estiver executando vários contêineres ou apenas processos com nginx, e cada um tiver suas próprias configurações de log, provavelmente parecerá que será muito inconveniente para você analisá-los. Porque para cada nova instância do nginx você precisa escrever seu próprio analisador, porque eles escrevem logs de maneira diferente. Novamente, provavelmente valeu a pena pensar em garantir que todas essas instâncias do nginx tivessem a mesma configuração de log e escrevessem todos os seus logs de maneira absolutamente uniforme. O mesmo se aplica a absolutamente todos os aplicativos.

No final, também quero colocar lenha na fogueira para que, idealmente, toras em formato multilinha sejam evitadas. O problema é o seguinte: se você já trabalhou com coletores de logs, provavelmente já viu o que eles prometem: que podem trabalhar com logs multilinhas, saber como coletá-los e assim por diante. Na verdade, na minha opinião, nenhum coletor hoje pode coletar toras multilinhas normalmente, de forma completa e sem erros. De forma humana, para que seja cómodo e isento de erros.

Requisitos para desenvolver uma aplicação em Kubernetes

Mas o rastreamento de pilha é sempre log de várias linhas e como evitá-los. A questão aqui é que um log é um registro de um evento e o stactrace não é realmente um log. Se coletarmos logs e colocá-los em algum lugar no Elasticsearch e, em seguida, desenharmos gráficos a partir deles, construirmos alguns relatórios de atividade do usuário em seu site, então, quando você obtiver um rastreamento de pilha, isso significa que algo inesperado está acontecendo, uma situação não tratada em sua aplicação. E faz sentido carregar automaticamente um rastreamento de pilha em algum lugar em um sistema que possa rastreá-los.

Este é um software (o mesmo Sentry) feito especificamente para trabalhar com rastreamento de pilha. Ele pode criar tarefas automatizadas imediatamente, atribuí-las a alguém, alertar quando ocorrerem rastreamentos estatísticos, agrupar esses rastreamentos estatísticos por um tipo e assim por diante. Em princípio, não faz muito sentido falar em stactraces quando falamos de logs, porque, afinal, são coisas diferentes com finalidades diferentes.

Configuração

A seguir falaremos sobre configuração no Kubernetes: o que fazer com ela e como as aplicações dentro do Kubernetes devem ser configuradas. Em geral, costumo dizer que Docker não é sobre containers. Todo mundo sabe que Docker é sobre contêineres, mesmo aqueles que não trabalharam muito com Docker. Repito, Docker não trata de contêineres.

Docker, na minha opinião, trata de padrões. E existem padrões para praticamente tudo: padrões para construir sua aplicação, padrões para instalar sua aplicação.

Requisitos para desenvolver uma aplicação em Kubernetes

E essa coisa - nós usamos isso antes, só se tornou especialmente popular com o advento dos contêineres - essa coisa é chamada de variáveis ​​ENV (ambiente), ou seja, variáveis ​​de ambiente que estão no seu sistema operacional. Geralmente, essa é uma maneira ideal de configurar seu aplicativo, porque se você tiver aplicativos em JAVA, Python, Go, Perl, Deus me livre, e todos eles puderem ler o host do banco de dados, o usuário do banco de dados e as variáveis ​​de senha do banco de dados, então é ideal. Você tem aplicações em quatro idiomas diferentes configuradas no plano de banco de dados da mesma forma. Não há mais configurações diferentes.

Tudo pode ser configurado usando variáveis ​​ENV. Quando falamos sobre Kubernetes, existe uma ótima maneira de declarar variáveis ​​ENV diretamente dentro do Deployment. Assim, se estamos falando de dados secretos, podemos enviar imediatamente dados secretos de variáveis ​​ENV (senhas para bancos de dados, etc.) para um segredo, criar um cluster secreto e indicar na descrição do ENV em Implantação que não estamos declarando diretamente o valor desta variável e o valor desta variável de senha do banco de dados serão lidos do segredo. Este é o comportamento padrão do Kubernetes. E esta é a opção ideal para configurar suas aplicações. Apenas no nível do código, novamente isso se aplica aos desenvolvedores. Se você é DevOps, pode perguntar: “Pessoal, por favor, ensinem sua aplicação a ler variáveis ​​de ambiente. E todos ficaremos felizes.”

Se todos na empresa lerem as mesmas variáveis ​​de ambiente nomeadas, isso será ótimo. Para que não aconteça que alguns estejam aguardando o banco de dados postgres, outros aguardando o nome do banco de dados, outros aguardando outra coisa, outros aguardando algum tipo de dbn, para que, consequentemente, haja uniformidade.

O problema surge quando você tem tantas variáveis ​​de ambiente que basta abrir o Deployment - e há quinhentas linhas de variáveis ​​de ambiente. Nesse caso, você simplesmente superou as variáveis ​​de ambiente - e não precisa mais se torturar. Nesse caso, faria sentido começar a usar configurações. Ou seja, treine seu aplicativo para usar configurações.

A única questão é que as configurações não são o que você pensa. Config.pi não é uma configuração conveniente de usar. Ou alguma configuração em seu próprio formato, alternativamente dotada - essa também não é a configuração que quero dizer.

Estou falando de configuração em formatos aceitáveis, ou seja, de longe o padrão mais popular é o padrão .yaml. É claro como lê-lo, é legível por humanos, é claro como lê-lo no aplicativo.

Assim, além do YAML, você também pode, por exemplo, usar JSON. A análise é tão conveniente quanto o YAML em termos de leitura da configuração do aplicativo a partir daí. É visivelmente mais inconveniente para as pessoas lerem. Você pode tentar o formato, à la ini. É bastante conveniente de ler, do ponto de vista humano, mas pode ser inconveniente processá-lo automaticamente, no sentido de que se você quiser gerar suas próprias configurações, o formato ini já pode ser inconveniente de gerar.

Mas em qualquer caso, seja qual for o formato que você escolher, a questão é que do ponto de vista do Kubernetes é muito conveniente. Você pode colocar toda a sua configuração dentro do Kubernetes, no ConfigMap. E então pegue esse configmap e peça para ele ser montado dentro do seu pod em algum diretório específico, onde sua aplicação irá ler a configuração deste configmap como se fosse apenas um arquivo. Isso, na verdade, é o que é bom fazer quando você tem muitas opções de configuração em sua aplicação. Ou é apenas algum tipo de estrutura complexa, há aninhamento.

Se você tiver um configmap, poderá muito bem ensinar seu aplicativo, por exemplo, a rastrear automaticamente as alterações no arquivo onde o configmap está montado e também recarregar automaticamente seu aplicativo quando as configurações mudarem. Geralmente, essa seria uma opção ideal.

Novamente, já falei sobre isso - informações secretas não estão no configmap, informações secretas não estão em variáveis, informações secretas não estão em segredos. A partir daí, conecte essas informações secretas à diplomacia. Normalmente armazenamos todas as descrições de objetos, implantações, mapas de configuração e serviços do Kubernetes no git. Dessa forma, colocar a senha do banco de dados no git, mesmo que seja o seu git, que você possui internamente na empresa, é uma má ideia. Porque, no mínimo, o git lembra de tudo e simplesmente remover as senhas de lá não é tão fácil.

Exame de saúde

O próximo ponto é essa coisa chamada Verificação de integridade. Em geral, uma verificação de integridade consiste simplesmente em verificar se seu aplicativo está funcionando. Ao mesmo tempo, na maioria das vezes estamos falando de certas aplicações web, para as quais, portanto, do ponto de vista da verificação de saúde (é melhor não traduzir aqui e mais adiante), este será algum tipo de URL especial, que eles processam como um padrão, eles geralmente fazem /health.

Ao acessar esta URL, portanto, nosso aplicativo diz “sim, ok, está tudo bem comigo, 200” ou “não, não está tudo bem comigo, cerca de 500”. Conseqüentemente, se nosso aplicativo não for http, não for um aplicativo da web, agora estamos falando de algum tipo de daemon, podemos descobrir como fazer verificações de saúde. Ou seja, não é necessário, se a aplicação não for http, então tudo funciona sem verificação de saúde e isso não pode ser feito de forma alguma. Você pode atualizar periodicamente algumas informações no arquivo, pode criar algum comando especial para o seu daemon, como, daemon status, que dirá “sim, está tudo bem, o daemon está funcionando, está vivo”.

Para que serve? A primeira e mais óbvia é provavelmente a razão pela qual é necessária uma verificação de integridade - para entender se o aplicativo está funcionando. Quer dizer, é simplesmente estúpido, quando está funcionando agora, parece que está funcionando, então você pode ter certeza de que está funcionando. E acontece que o aplicativo está rodando, o container está rodando, a instância está funcionando, está tudo bem - e aí os usuários já cortaram todos os números de telefone do suporte técnico e dizem “o que é você..., você adormeci, nada está funcionando.

Uma verificação de integridade é apenas uma forma de ver, do ponto de vista do usuário, se funciona. Um dos métodos. Vamos colocar desta forma. Do ponto de vista do Kubernetes, esta também é uma forma de entender quando a aplicação inicia, pois entendemos que existe uma diferença entre quando o container foi lançado, criado e iniciado, e quando a aplicação foi lançada diretamente neste container. Porque se pegarmos um aplicativo Java comum e tentarmos iniciá-lo no dock, por quarenta segundos, ou mesmo um minuto, ou mesmo dez, ele poderá iniciar perfeitamente. Nesse caso, você pode pelo menos bater nas portas dele, ele não vai atender lá, ou seja, ainda não está pronto para receber tráfego.

Novamente, com a ajuda de uma verificação de saúde e com a ajuda do que estamos virando aqui, podemos entender no Kubernetes que não apenas o contêiner subiu no aplicativo, mas o próprio aplicativo foi iniciado, ele já responde ao exame de saúde, o que significa que podemos enviar tráfego para lá.

Requisitos para desenvolver uma aplicação em Kubernetes

O que estou falando agora é chamado de testes de prontidão/vividade no Kubernetes; portanto, nossos testes de prontidão são responsáveis ​​pela disponibilidade da aplicação no balanceamento. Ou seja, se forem realizados testes de prontidão na aplicação, então está tudo bem, o tráfego do cliente está indo para a aplicação. Se os testes de prontidão não forem realizados, o aplicativo simplesmente não participa, esta instância específica não participa do balanceamento, é removida do balanceamento, o tráfego do cliente não flui. Conseqüentemente, os testes de Liveness no Kubernetes são necessários para que, se o aplicativo travar, ele possa ser reiniciado. Se o teste de atividade não funcionar para um aplicativo declarado no Kubernetes, o aplicativo não será apenas removido do balanceamento, mas também reiniciado.

E aqui está um ponto importante que gostaria de mencionar: do ponto de vista prático, o teste de prontidão costuma ser usado com mais frequência e é mais necessário do que o teste de vivacidade. Ou seja, simplesmente declarar impensadamente os testes de prontidão e de atividade, porque o Kubernetes pode fazer isso, e vamos usar tudo o que ele pode fazer, não é uma ideia muito boa. Vou explicar o porquê. Porque o ponto número dois do teste é que seria uma boa ideia verificar o serviço subjacente em suas verificações de integridade. Isso significa que se você possui uma aplicação web que fornece alguma informação, ela, por sua vez, naturalmente deve ser retirada de algum lugar. Em um banco de dados, por exemplo. Bem, ele salva as informações que chegam a esta API REST no mesmo banco de dados. Então, portanto, se o seu healthcheck responder simplesmente como o slashhealth contatado, o aplicativo dirá “200, ok, está tudo bem” e, ao mesmo tempo, o banco de dados do seu aplicativo estará inacessível e o aplicativo healthcheck dirá “200, ok, está tudo bem ” - Este é um exame de saúde ruim. Não é assim que deveria funcionar.

Ou seja, sua aplicação, quando chega uma solicitação /health, ele não responde apenas “200, ok”, ele primeiro vai, por exemplo, ao banco de dados, tenta se conectar a ele, faz algo muito básico lá, como selecionar um, apenas verifica se há conexão no banco de dados e você pode consultar o banco de dados. Se tudo isso deu certo, a resposta é “200, ok”. Se não tiver sucesso, diz que há um erro, o banco de dados está indisponível.

Portanto, a esse respeito, volto novamente aos testes de prontidão/vividade - por que você provavelmente precisa de um teste de prontidão, mas um teste de vivacidade está em questão. Porque se você descrever as verificações de integridade exatamente como acabei de dizer, descobrirá que elas não estão disponíveis na parte da instânciaв или со всех instanceem um banco de dados, por exemplo. Quando você declarou um teste de prontidão, nossas verificações de saúde começaram a falhar e, consequentemente, todos os aplicativos dos quais o banco de dados não está acessível, eles são simplesmente desligados do balanceamento e na verdade “travam” apenas em um estado negligenciado e aguardam que seus bancos de dados sejam trabalhar.

Se declaramos um teste de atividade, imagine que nosso banco de dados quebrou e em seu Kubernetes metade de tudo começa a reiniciar porque o teste de atividade falhou. Isso significa que você precisa reiniciar. Não é isso que você quer, até tive experiência pessoal na prática. Tínhamos um aplicativo de bate-papo escrito em JS e inserido em um banco de dados Mongo. E o problema é que foi no início do meu trabalho com o Kubernetes que descrevemos a prontidão e a vivacidade dos testes com base no princípio de que o Kubernetes pode fazer isso, então vamos usá-lo. Conseqüentemente, em algum momento o Mongo ficou um pouco “chato” e a amostra começou a falhar. Assim, de acordo com o teste de chuva, os frutos começaram a “matar”.

Como você entende, quando eles são “mortos”, isso é um chat, ou seja, tem muitos contatos de clientes pendurados nele. Eles também são “mortos” - não, não clientes, apenas conexões - nem todos ao mesmo tempo, e pelo fato de não serem mortos ao mesmo tempo, alguns antes, outros depois, eles não iniciam ao mesmo tempo tempo. Além do aleatório padrão, não podemos prever com precisão de milissegundos o horário de início do aplicativo a cada vez, então eles fazem isso uma instância de cada vez. Um infospot sobe, é adicionado ao balanceamento, todos os clientes chegam lá, ele não aguenta tanta carga, porque está sozinho e, grosso modo, tem uma dezena deles trabalhando lá, e ele cai. O próximo sobe, toda a carga fica sobre ele, ele também cai. Bem, essas quedas continuam a cair em cascata. No final, como isso foi resolvido - só tivemos que parar estritamente o tráfego de usuários para este aplicativo, deixar todas as instâncias subirem e então iniciar todo o tráfego de usuários de uma vez para que já fosse distribuído entre todas as dez instâncias.

Se não fosse o anúncio deste teste de vivacidade, que forçaria tudo a reiniciar, o aplicativo teria lidado perfeitamente com isso. Mas tudo, desde o balanceamento, está desabilitado para nós, porque os bancos de dados estão inacessíveis e todos os usuários “caíram”. Então, quando esse banco de dados fica disponível, tudo está incluído no balanceamento, mas os aplicativos não precisam ser reiniciados e não há necessidade de perder tempo e recursos com isso. Já estão todos aqui, estão prontos para o trânsito, então o trânsito só abre, está tudo bem - o aplicativo está instalado, tudo continua funcionando.

Portanto, os testes de prontidão e de atividade são diferentes, além disso, você pode teoricamente fazer diferentes verificações de saúde, um tipo de raio, um tipo de vida, por exemplo, e verificar coisas diferentes. Durante os testes de prontidão, verifique seus back-ends. E em um teste de vivacidade, por exemplo, você não verifica do ponto de vista de que o teste de vivacidade geralmente é apenas uma aplicação respondendo, se é que é capaz de responder.

Porque o teste de vivacidade, em geral, ocorre quando estamos “presos”. Um loop infinito foi iniciado ou algo mais - e nenhuma outra solicitação foi processada. Portanto, faz sentido separá-los - e implementar lógicas diferentes neles.

Em relação ao que você precisa responder quando fizer um exame, quando fizer exames de saúde. É realmente uma dor. Quem conhece isso provavelmente vai rir - mas falando sério, já vi serviços na minha vida que respondem “200” em XNUMX% dos casos. Ou seja, quem tem sucesso. Mas, ao mesmo tempo, no corpo da resposta escrevem “tal e tal erro”.

Ou seja, o status da resposta chega até você - tudo deu certo. Mas, ao mesmo tempo, você deve analisar o corpo, porque o corpo diz “desculpe, a solicitação terminou com erro” e isso é apenas a realidade. Eu vi isso na vida real.

E para que algumas pessoas não achem isso engraçado e outras achem muito doloroso, ainda vale a pena seguir uma regra simples. Nas verificações de integridade e, em princípio, ao trabalhar com aplicações web.

Se tudo correu bem, responda com a ducentésima resposta. Em princípio, qualquer ducentésima resposta será adequada para você. Se você lê muito bem e sabe que alguns status de resposta são diferentes de outros, responda com os apropriados: 204, 5, 10, 15, o que for. Se não for muito bom, então apenas “dois zero zero”. Se tudo correr mal e o exame de saúde não responder, responda com qualquer quinhentos. Novamente, se você entender como responder, como os diferentes status de resposta diferem entre si. Se você não entende, então 502 é sua opção para responder às verificações de saúde se algo der errado.

Este é outro ponto, quero voltar um pouco sobre a verificação dos serviços subjacentes. Se você começar, por exemplo, verificando todos os serviços subjacentes que estão por trás do seu aplicativo - tudo em geral. O que obtemos do ponto de vista da arquitetura de microsserviços é um conceito como “baixo acoplamento” - ou seja, quando seus serviços são minimamente dependentes uns dos outros. Se um deles falhar, todos os outros sem esta funcionalidade simplesmente continuarão funcionando. Algumas das funcionalidades simplesmente não funcionam. Da mesma forma, se você vincular todas as verificações de integridade umas às outras, acabará com uma coisa caindo na infraestrutura e, por causa da queda, todas as verificações de integridade de todos os serviços também começarão a falhar - e há mais infraestrutura em geral para o toda a arquitetura de microsserviços No. Tudo ficou escuro lá.

Portanto, quero repetir mais uma vez que você precisa verificar os serviços subjacentes, aqueles sem os quais seu aplicativo em cem por cento dos casos não pode fazer seu trabalho. Ou seja, é lógico que se você possui uma API REST por meio da qual o usuário salva no banco de dados ou recupera do banco de dados, então, na ausência de um banco de dados, você não pode garantir o trabalho com seus usuários.

Mas se seus usuários, quando você os retira do banco de dados, são enriquecidos adicionalmente com alguns outros metadados, de outro backend, que você insere antes de enviar uma resposta para o frontend - e esse backend não está disponível, isso significa que você dá o seu responda sem qualquer parte dos metadados.

A seguir, também temos um dos problemas dolorosos ao lançar aplicativos.

Na verdade, isso não se aplica apenas ao Kubernetes em geral; aconteceu que a cultura de algum tipo de desenvolvimento em massa e do DevOps em particular começou a se espalhar na mesma época que o Kubernetes. Portanto, em geral, você precisa encerrar seu aplicativo normalmente sem o Kubernetes. Mesmo antes do Kubernetes, as pessoas faziam isso, mas com o advento do Kubernetes, começamos a falar sobre isso em massa.

Desligamento Gracioso

Em geral, o que é Graceful Shutdown e por que é necessário? Trata-se de quando seu aplicativo trava por algum motivo, você precisa fazer app stop - ou você recebe, por exemplo, um sinal do sistema operacional, seu aplicativo deve entendê-lo e fazer algo a respeito. O pior cenário, claro, é quando seu aplicativo recebe um SIGTERM e diz “SIGTERM, vamos esperar, trabalhar, não fazer nada”. Esta é uma opção totalmente ruim.

Requisitos para desenvolver uma aplicação em Kubernetes

Uma opção quase igualmente ruim é quando sua aplicação recebe um SIGTERM e fica tipo “disseram segterm, isso significa que estamos terminando, não vi, não conheço nenhuma solicitação de usuário, não sei que tipo de solicitações nas quais estou trabalhando agora, disseram SIGTERM, isso significa que estamos terminando " Esta também é uma má opção.

Qual opção é boa? O primeiro ponto é levar em consideração a conclusão das operações. Uma boa opção é o seu servidor ainda levar em consideração o que fará caso receba um SIGTERM.

SIGTERM é um soft shutdown, é especialmente desenhado, pode ser interceptado no nível do código, pode ser processado, diga isso agora, espere, primeiro terminaremos o trabalho que temos, depois sairemos.

Da perspectiva do Kubernetes, é assim que parece. Quando dizemos a um pod que está em execução no cluster Kubernetes, “por favor, pare, vá embora”, ou somos reiniciados, ou ocorre uma atualização quando o Kubernetes recria os pods, o Kubernetes envia apenas a mesma mensagem SIGTERM para o pod, aguarda algum tempo, e esse é o tempo que ele espera, também está configurado, existe um parâmetro tão especial nos diplomas e se chama Graceful ShutdownTimeout. Como você entende, não é à toa que se chama assim, e não é à toa que estamos falando sobre isso agora.

Lá podemos dizer especificamente quanto tempo precisamos esperar entre o momento em que enviamos o SIGTERM para a aplicação e quando entendemos que a aplicação parece ter enlouquecido por alguma coisa ou está “travada” e não vai acabar – e precisamos envie SIGKILL, ou seja, conclua seu trabalho com força. Ou seja, temos algum tipo de daemon em execução, ele processa operações. Entendemos que, em média, nossas operações nas quais o daemon funciona não duram mais do que 30 segundos por vez. Assim, quando o SIGTERM chega, entendemos que nosso daemon pode, no máximo, terminar 30 segundos após o SIGTERM. Escrevemos, por exemplo, 45 segundos por precaução e dizemos que SIGTERM. Depois disso, esperamos 45 segundos. Em teoria, durante esse período o demônio deveria ter completado seu trabalho e se encerrado. Mas se de repente não conseguir, significa que provavelmente está travado – não está mais processando nossas solicitações normalmente. E em 45 segundos você pode, de fato, prendê-lo com segurança.

E aqui, de fato, até 2 aspectos podem ser levados em consideração. Primeiramente, entenda que se você recebeu uma solicitação, você começou a trabalhar com ela de alguma forma e não deu resposta ao usuário, mas recebeu o SIGTERM, por exemplo. Faz sentido refiná-lo e dar uma resposta ao usuário. Este é o ponto número um a esse respeito. O ponto número dois aqui é que se você escreve seu próprio aplicativo, geralmente constrói a arquitetura de tal forma que você recebe uma solicitação para seu aplicativo, então você inicia algum trabalho, começa a baixar arquivos de algum lugar, baixar um banco de dados e outros enfeites. - Que. Em geral, seu usuário, sua solicitação fica pendurada por meia hora e espera que você responda - então, provavelmente, você precisará trabalhar na arquitetura. Ou seja, basta levar em conta até o bom senso de que se suas operações forem curtas, então faz sentido ignorar o SIGTERM e modificá-lo. Se suas operações forem longas, não faz sentido ignorar o SIGTERM neste caso. Faz sentido redesenhar a arquitetura para evitar operações tão longas. Para que os usuários não fiquem apenas esperando. Não sei, faça algum tipo de websocket aí, faça ganchos reversos que seu servidor já vai enviar para o cliente, qualquer outra coisa, mas não force o usuário a travar meia hora e apenas espere uma sessão até você responda a ele. Porque é imprevisível onde pode quebrar.

Quando seu aplicativo terminar, você deverá fornecer algum código de saída apropriado. Ou seja, se seu aplicativo foi solicitado a fechar, parar e conseguiu parar normalmente, você não precisa retornar algum tipo de código de saída 1,5,255 e assim por diante. Qualquer coisa que não seja código zero, pelo menos em sistemas Linux, tenho certeza disso, é considerada malsucedida. Ou seja, considera-se que sua aplicação neste caso terminou com erro. Assim, de forma amigável, se sua aplicação foi concluída sem erros, você diz 0 na saída. Se seu aplicativo falhar por algum motivo, você dirá diferente de 0 na saída. E você pode trabalhar com essas informações.

E a última opção. É ruim quando seu usuário envia uma solicitação e trava por meia hora enquanto você a processa. Mas, em geral, também gostaria de falar sobre o que geralmente vale a pena por parte do cliente. Não importa se você tem um aplicativo móvel, front-end, etc. É preciso levar em conta que em geral a sessão do usuário pode ser encerrada, tudo pode acontecer. Uma solicitação pode ser enviada, por exemplo, mal processada e nenhuma resposta retornada. Seu frontend ou seu aplicativo móvel - qualquer frontend em geral, digamos assim - deve levar isso em consideração. Se você trabalha com websockets, essa geralmente é a pior dor que já tive.

Quando os desenvolvedores de alguns chats regulares não sabem disso, o websocket pode quebrar. Para eles, quando algo acontece no proxy, basta alterar a configuração e ele recarrega. Naturalmente, todas as sessões de longa duração são interrompidas neste caso. Os desenvolvedores vêm correndo até nós e dizem: “Gente, o que vocês estão fazendo, o chat quebrou para todos os nossos clientes!” Dizemos a eles: “O que vocês estão fazendo? Seus clientes não conseguem se reconectar? Eles dizem: “Não, precisamos que as sessões não sejam rasgadas”. Em suma, isso é realmente um absurdo. O lado do cliente precisa ser levado em consideração. Principalmente, como eu disse, com sessões de longa duração como websockets, ele pode quebrar e, despercebido pelo usuário, você precisa conseguir reinstalar tais sessões. E então tudo fica perfeito.

Recursos

Na verdade, aqui vou apenas contar uma história direta. Novamente da vida real. A coisa mais doentia que já ouvi sobre recursos.

Recursos, neste caso, quero dizer, algum tipo de solicitação, limites que você pode colocar em pods em seus clusters Kubernetes. A coisa mais engraçada que ouvi de um desenvolvedor... Um de meus colegas desenvolvedores em um local de trabalho anterior disse uma vez: “Meu aplicativo não inicia no cluster”. Procurei ver que não estava começando, mas ou não cabia nos recursos ou tinham limites muito pequenos. Resumindo, o aplicativo não pode ser iniciado devido a recursos. Eu digo: “Não vai começar por falta de recursos, você decide quanto precisa e define um valor adequado”. Ele diz: “Que tipo de recursos?” Comecei a explicar a ele que Kubernetes, limites de solicitações e blá, blá, blá precisam ser definidos. O homem ouviu por cinco minutos, acenou com a cabeça e disse: “Vim aqui para trabalhar como desenvolvedor, não quero saber nada sobre nenhum recurso. Vim aqui para escrever código e pronto.” É triste. Este é um conceito muito triste do ponto de vista do desenvolvedor. Especialmente no mundo moderno, por assim dizer, de devops progressivos.

Por que os recursos são necessários? Existem 2 tipos de recursos no Kubernetes. Alguns são chamados de solicitações, outros são chamados de limites. Por recursos entenderemos que basicamente sempre existem apenas duas restrições básicas. Ou seja, limites de tempo de CPU e limites de RAM para um contêiner em execução no Kubernetes.

Um limite estabelece um limite superior sobre como um recurso pode ser usado em seu aplicativo. Ou seja, se você disser 1 GB de RAM nos limites, seu aplicativo não poderá usar mais de 1 GB de RAM. E se de repente ele quiser e tentar fazer isso, então um processo chamado oom killer, sem memória, isto é, virá e matará seu aplicativo - ou seja, ele simplesmente reiniciará. Os aplicativos não serão reiniciados com base na CPU. Em termos de CPU, se uma aplicação tentar usar muito, mais do que o especificado nos limites, a CPU será simplesmente selecionada estritamente. Isso não leva a reinicializações. Este é o limite – este é o limite superior.

E há um pedido. Uma solicitação é como o Kubernetes entende como os nós em seu cluster Kubernetes são preenchidos com aplicativos. Ou seja, uma requisição é uma espécie de commit da sua aplicação. Diz o que eu quero usar: “Gostaria que você reservasse tanta CPU e tanta memória para mim”. Uma analogia tão simples. E se tivermos um nó que tenha, não sei, 8 CPUs no total. E chega lá um pod, cujas solicitações dizem 1 CPU, o que significa que o nó tem 7 CPUs restantes. Ou seja, assim que 8 pods chegam a este nó, cada um com 1 CPU em suas solicitações, o nó, como se do ponto de vista do Kubernetes, ficasse sem CPU e mais pods com solicitações não pudessem ser lançado neste nó. Se todos os nós ficarem sem CPU, o Kubernetes começará a dizer que não há nós adequados no cluster para executar seus pods porque a CPU acabou.

Por que as solicitações são necessárias e por que, sem solicitações, acho que não há necessidade de lançar nada no Kubernetes? Vamos imaginar uma situação hipotética. Você inicia seu aplicativo sem solicitações, o Kubernetes não sabe quanto do que você tem, para quais nós você pode enviá-lo. Bem, ele empurra, empurra, empurra nos nós. Em algum momento, você começará a receber tráfego para seu aplicativo. E um dos aplicativos de repente começa a usar recursos até os limites que tem de acordo com os limites. Acontece que existe outro aplicativo próximo e também precisa de recursos. Na verdade, o nó começa a ficar fisicamente sem recursos, por exemplo, OP. Na verdade, o nó começa a ficar fisicamente sem recursos, por exemplo, memória de acesso aleatório (RAM). Quando um nó fica sem energia, primeiro o docker para de responder, depois o cubelet e depois o sistema operacional. Eles simplesmente ficarão inconscientes e TUDO definitivamente deixará de funcionar para você. Ou seja, isso fará com que seu nó fique preso e você precisará reiniciá-lo. Em suma, a situação não é muito boa.

E quando você tem solicitações, os limites não são muito diferentes, pelo menos não muitas vezes mais do que os limites ou solicitações, então você pode ter um preenchimento normal e racional de aplicativos nos nós dos clusters Kubernetes. Ao mesmo tempo, o Kubernetes está aproximadamente ciente de quanto do que coloca onde, quanto do que é usado e onde. Ou seja, é apenas um desses momentos. É importante entender isso. E é importante controlar que isso seja indicado.

Armazenamento de dados

Nosso próximo ponto é sobre armazenamento de dados. O que fazer com eles e, em geral, o que fazer com a persistência no Kubernetes?

Penso, mais uma vez, dentro do nosso Escola Noturna, havia um tópico sobre o banco de dados no Kubernetes. E me parece que sei aproximadamente o que seus colegas lhe disseram quando questionados: “É possível executar um banco de dados no Kubernetes?” Por alguma razão, parece-me que seus colegas deveriam ter lhe dito que se você está se perguntando se é possível executar um banco de dados no Kubernetes, então é impossível.

A lógica aqui é simples. Por precaução, vou explicar mais uma vez, se você é um cara muito legal que consegue construir um sistema de armazenamento de rede distribuído bastante tolerante a falhas, entenda como encaixar um banco de dados nesse caso, como deve funcionar o nativo da nuvem em containers em um banco de dados em geral. Provavelmente, você não tem dúvidas sobre como executá-lo. Se você tem essa dúvida e quer ter certeza de que tudo se desenrolará e ficará pronto até a morte na produção e nunca cairá, então isso não acontece. Você tem a garantia de dar um tiro no próprio pé com essa abordagem. Portanto, é melhor não fazer isso.

O que devemos fazer com os dados que nossa aplicação gostaria de armazenar, algumas imagens que os usuários carregam, algumas coisas que nossa aplicação gera durante sua operação, na inicialização, por exemplo? O que fazer com eles no Kubernetes?

Em geral, idealmente, sim, claro, o Kubernetes é muito bem projetado e geralmente foi inicialmente concebido para aplicativos sem estado. Ou seja, para aqueles aplicativos que não armazenam nenhuma informação. Isto é ideal.

Mas, claro, nem sempre a opção ideal existe. E daí? O primeiro e mais simples ponto é pegar algum tipo de S3, só que não feito em casa, que também não está claro como funciona, mas de algum fornecedor. Um provedor bom e normal - e ensine seu aplicativo a usar o S3. Ou seja, quando seu usuário quiser fazer upload de um arquivo, diga “aqui, por favor, faça upload para o S3”. Quando ele quiser recebê-lo, diga: “Aqui está um link para o S3 de volta e leve-o daqui”. Isto é ideal.

Se de repente por algum motivo esta opção ideal não for adequada, você tem uma aplicação que não escreveu, não desenvolve, ou é algum tipo de legado terrível, ela não pode usar o protocolo S3, mas deve funcionar com diretórios locais em pastas locais. Pegue algo mais ou menos simples, implante o Kubernetes. Ou seja, isolar imediatamente o Ceph para algumas tarefas mínimas, parece-me, é uma má ideia. Porque Ceph, claro, é bom e está na moda. Mas se você realmente não entende o que está fazendo, depois de colocar algo no Ceph, você pode facilmente e simplesmente nunca mais tirá-lo de lá. Porque, como você sabe, o Ceph armazena dados em seu cluster em formato binário, e não em arquivos simples. Portanto, se de repente o cluster do Ceph falhar, há uma probabilidade alta e completa de que você nunca mais obterá seus dados de lá.

Teremos um curso sobre Ceph, você pode familiarize-se com o programa e envie uma inscrição.

Portanto, é melhor fazer algo simples como um servidor NFS. Kubernetes pode funcionar com eles, você pode montar um diretório em um servidor NFS - seu aplicativo é como um diretório local. Ao mesmo tempo, naturalmente, você precisa entender que, novamente, você precisa fazer algo com o seu NFS, você precisa entender que às vezes ele pode ficar inacessível e considerar a questão do que você fará neste caso. Talvez deva ser feito backup em algum lugar em uma máquina separada.

O próximo ponto que falei é o que fazer se sua aplicação gerar alguns arquivos durante a operação. Por exemplo, ao iniciar, ele gera algum arquivo estático, que se baseia em algumas informações que o aplicativo recebe apenas no momento do lançamento. Que momento. Se não houver muitos desses dados, você não precisa se preocupar, basta instalar este aplicativo e trabalhar. A única questão aqui é o quê, veja. Muitas vezes, todos os tipos de sistemas legados, como WordPress e assim por diante, especialmente com algum tipo de plug-in inteligente modificado, desenvolvedores de PHP inteligentes, eles geralmente sabem como fazer com que gerem algum tipo de arquivo para si mesmos. Assim, um gera um arquivo, o segundo gera um segundo arquivo. Eles são diferentes. O balanceamento acontece no cluster Kubernetes dos clientes simplesmente por acaso. Conseqüentemente, acontece que eles não sabem como trabalhar juntos, por exemplo. Um fornece uma informação, o outro fornece ao usuário outra informação. Isso é algo que você deve evitar. Ou seja, no Kubernetes, tudo o que você inicia tem a garantia de poder funcionar em múltiplas instâncias. Porque o Kubernetes é algo em movimento. Assim, ele pode mover qualquer coisa, quando quiser, sem perguntar a ninguém. Portanto, você precisa contar com isso. Tudo o que for lançado em uma instância irá falhar mais cedo ou mais tarde. Quanto mais reservas você tiver, melhor. Mas, novamente, eu digo, se você tiver alguns desses arquivos, poderá colocá-los logo abaixo de você, eles pesam uma pequena quantidade. Se houver um pouco mais deles, você provavelmente não deveria empurrá-los para dentro do recipiente.

Eu aconselharia que existe uma coisa tão maravilhosa no Kubernetes que você pode usar o volume. Em particular, existe um volume do tipo vazio dir. Ou seja, é só que o Kubernetes criará automaticamente um diretório em seus diretórios de serviço no servidor onde você iniciou. E ele vai dar a você para que você possa usá-lo. Existe apenas um ponto importante. Ou seja, seus dados não serão armazenados dentro do container, mas sim no host em que você está rodando. Além disso, o Kubernetes pode controlar esses diretórios vazios na configuração normal e é capaz de controlar seu tamanho máximo e não permitir que ele seja excedido. O único ponto é que o que você escreveu no diretório vazio não será perdido durante as reinicializações do pod. Ou seja, se o seu pod cair por engano e subir novamente, as informações no diretório vazio não irão a lugar nenhum. Ele pode usá-lo novamente em um novo começo – e isso é bom. Se o seu pod sair de algum lugar, naturalmente ele sairá sem dados. Ou seja, assim que o pod do nó onde foi lançado com o diretório vazio desaparecer, o diretório vazio será excluído.

O que mais há de bom em um diretório vazio? Por exemplo, pode ser usado como cache. Vamos imaginar que nosso aplicativo gera algo na hora, entrega aos usuários e faz isso por um longo tempo. Portanto, o aplicativo, por exemplo, gera e entrega aos usuários, e ao mesmo tempo armazena em algum lugar, para que da próxima vez que o usuário vier buscar a mesma coisa, seja mais rápido entregá-lo gerado imediatamente. Um diretório vazio pode ser solicitado ao Kubernetes para criar na memória. E assim, seus caches geralmente podem funcionar na velocidade da luz - em termos de velocidade de acesso ao disco. Ou seja, você tem um diretório vazio na memória, no SO ele fica armazenado na memória, mas para você, para o usuário dentro do pod, parece apenas um diretório local. Você não precisa do aplicativo para ensinar magia especificamente. Você simplesmente pega e coloca seu arquivo diretamente em um diretório, mas, na verdade, na memória do sistema operacional. Este também é um recurso muito conveniente em termos de Kubernetes.

Que problemas o Minio tem? O principal problema do Minio é que para que isso funcione, ele precisa estar rodando em algum lugar, e deve haver algum tipo de sistema de arquivos, ou seja, armazenamento. E aqui encontramos os mesmos problemas do Ceph. Ou seja, o Minio deve armazenar seus arquivos em algum lugar. É simplesmente uma interface HTTP para seus arquivos. Além disso, a funcionalidade é claramente inferior à do S3 da Amazon. Anteriormente, não era possível autorizar adequadamente o usuário. Agora, pelo que eu sei, ele já pode criar buckets com autorizações diferentes, mas, novamente, parece-me que o principal problema é, por assim dizer, o sistema de armazenamento subjacente, no mínimo.

Como o diretório vazio na memória afeta os limites? Não afeta os limites de forma alguma. Está na memória do host e não na memória do seu contêiner. Ou seja, seu contêiner não vê o diretório vazio na memória como parte da memória ocupada. O anfitrião vê isso. Assim, sim, do ponto de vista do kubernetes, quando você começar a usar isso, seria bom entender que você está dedicando parte da sua memória ao diretório vazio. E, portanto, entenda que a memória pode acabar não apenas por causa dos aplicativos, mas também porque alguém grava nesses diretórios vazios.

Natividade da nuvem

E o subtópico final é o que é Cloudnative. Por que é necessário? Natividade da nuvem e assim por diante.

Ou seja, aqueles aplicativos que são capazes e escritos para funcionar em uma infraestrutura de nuvem moderna. Mas, na verdade, Cloudnative tem outro aspecto. Que esta não seja apenas uma aplicação que leva em consideração todos os requisitos de uma infraestrutura em nuvem moderna, mas também saiba trabalhar com essa infraestrutura em nuvem moderna, aproveite as vantagens e desvantagens de funcionar nessas nuvens. Não exagere e trabalhe nas nuvens, mas aproveite os benefícios de trabalhar na nuvem.

Requisitos para desenvolver uma aplicação em Kubernetes

Vamos tomar o Kubernetes como exemplo. Seu aplicativo está sendo executado no Kubernetes. Seu aplicativo sempre pode, ou melhor, os administradores do seu aplicativo, sempre podem criar uma conta de serviço. Ou seja, uma conta para autorização no próprio Kubernetes em seu servidor. Adicione alguns direitos que precisamos lá. E você pode acessar o Kubernetes de dentro do seu aplicativo. O que você pode fazer dessa maneira? Por exemplo, do aplicativo, receba dados sobre onde seus outros aplicativos, outras instâncias semelhantes estão localizadas e, juntos, de alguma forma, agrupem-se no topo do Kubernetes, se houver necessidade.

Novamente, literalmente tivemos um caso recentemente. Temos um controlador que monitora a fila. E quando algumas novas tarefas aparecem nesta fila, ela vai para o Kubernetes - e dentro do Kubernetes ele cria um novo pod. Dá a este pod alguma nova tarefa e, dentro da estrutura deste pod, o pod executa a tarefa, envia uma resposta ao próprio controlador e o controlador então faz algo com essas informações. Por exemplo, ele adiciona um banco de dados. Isso é, novamente, uma vantagem do fato de nosso aplicativo ser executado no Kubernetes. Podemos usar a própria funcionalidade integrada do Kubernetes para expandir de alguma forma e tornar a funcionalidade do nosso aplicativo mais conveniente. Ou seja, não esconda algum tipo de mágica sobre como iniciar um aplicativo, como iniciar um trabalhador. No Kubernetes, basta enviar uma solicitação no aplicativo se o aplicativo for escrito em Python.

O mesmo se aplica se formos além do Kubernetes. Temos nosso Kubernetes rodando em algum lugar - é bom que esteja em algum tipo de nuvem. Novamente, podemos usar, e até devemos, acredito, usar os recursos da própria nuvem onde estamos executando. Das coisas elementares que a nuvem nos proporciona. Balanceamento, ou seja, podemos criar balanceadores de nuvem e utilizá-los. Esta é uma vantagem direta do que podemos usar. Porque o balanceamento da nuvem, em primeiro lugar, simplesmente remove de nós estupidamente a responsabilidade por como funciona, como está configurado. Além disso, é muito conveniente, porque o Kubernetes normal pode ser integrado às nuvens.

O mesmo vale para o dimensionamento. Kubernetes regulares podem ser integrados a provedores de nuvem. Sabe entender que se o cluster ficar sem nós, ou seja, o espaço do nó acabou, então você precisa adicionar - o próprio Kubernetes adicionará novos nós ao seu cluster e começará a lançar pods neles. Ou seja, quando chega a sua carga, o número de focos começa a aumentar. Quando os nós no cluster desses pods se esgotam, o Kubernetes lança novos nós e, consequentemente, o número de pods ainda pode aumentar. E é muito conveniente. Esta é uma oportunidade direta para dimensionar o cluster em tempo real. Não muito rápido, no sentido de que não é um segundo, é mais um minuto para adicionar novos nós.

Mas, pela minha experiência, novamente, é a coisa mais legal que já vi. Quando o cluster Cloudnative foi dimensionado com base na hora do dia. Era um serviço de back-end usado por pessoas do back office. Ou seja, eles chegam ao trabalho às 9h, começam a fazer login no sistema e, consequentemente, o cluster Cloudnative, onde está tudo rodando, começa a inchar, lançando novos pods para que todos que vierem trabalhar possam trabalhar com a aplicação. Quando saem do trabalho às 8h ou 6h, os clusters Kubernetes percebem que ninguém está mais usando o aplicativo e começam a diminuir. Economias de até 30% são garantidas. Funcionou na Amazon naquela época; naquela época não havia ninguém na Rússia que pudesse fazer isso tão bem.

Vou ser direto, a economia é de 30% simplesmente porque usamos o Kubernetes e aproveitamos os recursos da nuvem. Agora isso pode ser feito na Rússia. Não vou anunciar para ninguém, é claro, mas digamos apenas que existem provedores que podem fazer isso, fornecendo-o imediatamente com um botão.

Há um último ponto para o qual também gostaria de chamar a vossa atenção. Para que sua aplicação, sua infraestrutura seja Cloudnative, faz sentido finalmente começar a adaptar a abordagem chamada Infraestrutura como Código, ou seja, isso significa que sua aplicação, ou melhor, sua infraestrutura, é necessária exatamente da mesma forma que o código Descreva seu aplicativo, sua lógica de negócios na forma de código. E trabalhe com ele como código, ou seja, teste, implemente, armazene no git, aplique CICD nele.

E é exatamente isso que permite, em primeiro lugar, ter sempre controle sobre sua infraestrutura, entender sempre em que estado ela se encontra. Em segundo lugar, evite operações manuais que causem erros. Terceiro, evite simplesmente o que é chamado de rotatividade, quando você precisa executar constantemente as mesmas tarefas manuais. Em quarto lugar, permite uma recuperação muito mais rápida em caso de falha. Na Rússia, sempre que falo sobre isso, há um grande número de pessoas que dizem: “Sim, está claro, mas você tem abordagens, enfim, não há necessidade de consertar nada”. Mas é verdade. Se algo está quebrado na sua infraestrutura, então do ponto de vista da abordagem Cloudnative e do ponto de vista da Infraestrutura como Código, em vez de consertar, ir até o servidor, descobrir o que está quebrado e consertar, é mais fácil para excluir o servidor e criá-lo novamente. E terei tudo isso restaurado.

Todas essas questões são discutidas com mais detalhes em Cursos em vídeo do Kubernetes: Junior, Básico, Mega. Seguindo o link você poderá se familiarizar com o programa e condições. O conveniente é que você pode dominar o Kubernetes estudando em casa ou no trabalho de 1 a 2 horas por dia.

Fonte: habr.com

Adicionar um comentário