One place for hosting & domains

      Como automatizar suas implantações Node.js para produção com o Shipit no CentOS 7


      O autor selecionou a Fundação Electronic Frontier para receber uma doação como parte do programa Write for DOnations.

      Introdução

      O Shipit é uma ferramenta de automação e implantação universal para desenvolvedores do Node.js. Ela possui um fluxo de tarefas baseado no pacote popular Orchestrator, comandos de login e SSH interativo através do OpenSSH, além de uma API extensível. Os desenvolvimentos podem usar o Shipit para automatizar os fluxos de trabalho de compilação e DE implantação para uma ampla gama de aplicativos Node.js.

      O fluxo de trabalho do Shipit permite que os desenvolvedores não apenas configurem tarefas, mas também especifiquem a ordem na qual são executadas; se devem ser executadas de maneira sincronizada ou não e em qual ambiente.

      Neste tutorial, você instalará e configurará o Shipit para implantar um aplicativo Node.js a partir do seu ambiente de desenvolvimento local para o seu ambiente de produção. Você usará o Shipit para implantar seu aplicativo e configurar o servidor remoto desta forma:

      • transferindo os arquivos do aplicativo Node.js do seu ambiente local para o ambiente de produção (usando o rsync, git e ssh).
      • instalando as dependências do seu aplicativo (módulos de nó)
      • configurando e gerenciando os processos Node.js em execução no servidor remoto com o PM2.

      Pré-requisitos

      Antes de iniciar este tutorial, você precisará do seguinte:

      • Dois servidores CentOS 7 (neste tutorial, eles serão chamados de app e web), configurados com rede privada, seguindo as instruções do tutorial Como configurar um aplicativo Node.js para produção no CentOS 7.
      • Nginx (no seu servidor web), protegido com o protocolo TLS/SSL como mostrado no tutorial Como proteger o Nginx com o Let’s Encrypt no CentOS 7. Note que, se você estiver seguindo as instruções dos pré-requisitos em ordem cronológica, para o seu servidor web você só terá que realizar os passos 1, 4 e 6.
      • Node.js e npm instalados em seu ambiente de desenvolvimento. Este tutorial usa a versão 10.17.0. Para instalar essa versão em macOS ou Ubuntu 18.04, siga os passos descritos no artigo sobre Como instalar o Node.js e criar um ambiente de desenvolvimento local em macOS ou a seção intitulada Instalando usando um PPA, do artigo sobre Como instalar o Node.js no Ubuntu 18.04. Por ter o Node.js instalado, você também tem o npm instalado; este tutorial usa a versão 6.11.3.
      • Um computador de desenvolvimento local com o rsync e git instalados.
      • Uma conta junto ao GitHub ou outro provedor de serviços git hospedados. Este tutorial usará o GitHub.

      Nota: os usuários do Windows terão que instalar o Subsistema Windows para o Linux para executar os comandos neste guia.

      Passo 1 — Configurando o repositório remoto

      O Shipit exige um repositório Git para a sincronização entre a máquina de desenvolvimento local e o servidor remoto. Neste passo, você criará um repositório remoto no Github.com. Embora cada provedor seja ligeiramente diferente, os comandos são de certo modo transferíveis.

      Para criar um repositório, abra o Github.com em seu navegador Web e faça login. Você notará que, no canto superior de todas as páginas, existe um símbolo de adição +. Clique no + e, em seguida, clique em Novo repositório.

      Github-novo-repositório

      Digite um nome curto e fácil de lembrar para o seu repositório como ,por exemplo, hello-world. Note que, independentemente do nome que escolher aqui, ele será replicado como a pasta do projeto a partir da qual você irá trabalhar em sua máquina local.

      Github-nome-repositório

      De maneira opcional, adicione uma descrição do seu repositório.

      Github-descrição-repositório

      Defina a visibilidade do seu repositório de acordo com sua preferência, como sendo pública ou privada.

      Certifique-se de que o repositório seja inicializado com um .gitignore, selecionando Node na lista suspensa Add .gitignore. Este passo é importante para evitar que arquivos desnecessários (como a pasta node_modules) sejam adicionados ao seu repositório.

      Github-nó-gitignore

      Clique no botão Criar repositório.

      Agora, o repositório precisa ser clonado do Github.com para sua máquina local.

      Abra seu terminal e navegue até o local onde quer armazenar todos os seus arquivos do projeto Node.js. Note que este processo criará uma subpasta dentro do diretório atual. Para clonar o repositório para sua máquina local, execute o seguinte comando:

      • git clone https://github.com/your-github-username/your-github-repository-name.git

      Você precisará substituir o your-github-username e your-github-repository-name para que reflitam seu nome de usuário do Github e o nome do repositório anteriormente fornecido.

      Nota: caso tenha habilitado a autenticação de dois fatores (2FA) no Github.com, ao acessar o Github na linha de comando, você deverá usar um token de acesso pessoal ou uma chave SSH, em vez de sua senha. A página de ajuda do Github relacionada à 2FA fornece mais informações.

      Você verá um resultado parecido com este:

      Output

      Cloning into 'your-github-repository-name'... remote: Enumerating objects: 3, done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3 Unpacking objects: 100% (3/3), done.

      Vá até o repositório, executando o seguinte comando:

      • cd your-github-repository-name

      Dentro do repositório, há um arquivo e uma pasta únicos, sendo ambos arquivos usados pelo Git para gerenciar o repositório. Você pode verificar isso com:

      Você verá um resultado parecido com este:

      Output

      total 8 0 drwxr-xr-x 4 asciant staff 128 22 Apr 07:16 . 0 drwxr-xr-x 5 asciant staff 160 22 Apr 07:16 .. 0 drwxr-xr-x 13 asciant staff 416 22 Apr 07:16 .git 8 -rw-r--r-- 1 asciant staff 914 22 Apr 07:16 .gitignore

      Agora que você configurou um repositório git funcional, irá criar o arquivo shipit.js que gerencia o seu processo de implantação.

      Passo 2 — Integrando o Shipit a um projeto Node.js

      Neste passo, você criará um projeto Node.js como exemplo e, depois, adicionará os pacotes do Shipit. Este tutorial fornece um app exemplo — o servidor web Node.js que aceita solicitações HTTP e responde com um Hello World em texto simples. Para criar o aplicativo, execute o seguinte comando:

      Adicione o seguinte código de aplicativo exemplo ao hello.js (atualizando a variável APP_PRIVATE_IP_ADDRESS com o endereço IP da rede privada do servidor do seu app):

      hello.js

      var http = require('http');
      http.createServer(function (req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello Worldn');
      }).listen(8080, 'APP_PRIVATE_IP_ADDRESS');
      console.log('Server running at http://APP_PRIVATE_IP_ADDRESS:8080/');
      

      Agora, crie seu arquivo package.json para seu aplicativo:

      Esse comando cria um arquivo package.json, que você usará para configurar seu aplicativo Node.js. No próximo passo, você adicionará dependências a esse arquivo com a interface de linha de comando npm.

      Output

      Wrote to ~/hello-world/package.json: { "name": "hello-world", "version": "1.0.0", "description": "", "main": index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }

      Em seguida, instale os pacotes npm necessários com o seguinte comando:

      • npm install --save-dev shipit-cli shipit-deploy shipit-shared

      Aqui, você usará o sinalizador --save-dev, uma vez que os pacotes do Shipit somente são necessários em sua máquina local. Você verá um resultado parecido com este:

      Output

      + shipit-shared@4.4.2 + shipit-cli@4.2.0 + shipit-deploy@4.1.4 updated 4 packages and audited 21356 packages in 11.671s found 62 low severity vulnerabilities run `npm audit fix` to fix them, or `npm audit` for details

      Isso também adicionou os três pacotes ao seu arquivo package.json como dependências de desenvolvimento:

      package.json

      . . .
        "devDependencies": {
          "shipit-cli": "^4.2.0",
          "shipit-deploy": "^4.1.4",
          "shipit-shared": "^4.4.2"
        },
      . . .
      

      Com seu ambiente local configurado, agora você pode prosseguir com a preparação do servidor app remoto para implantações baseadas no Shipit.

      Passo 3 — Preparando o servidor app remoto

      Neste passo, você usará o ssh para se conectar ao seu servidor app e instalar sua dependência remota rsync. O Rsync é um utilitário para transferir e sincronizar arquivos de modo eficiente entre os discos do computador local e os computadores em rede, comparando os tempos de modificação e os tamanhos dos arquivos.

      O Shipit usa o rsync para transferir e sincronizar arquivos entre seu computador local e o servidor app remoto. Você não emitirá qualquer comando diretamente no rsync; o Shipit fará isso por você.

      Nota: o tutorial Como configurar um aplicativo Node.js para produção no CentOS 7 possibilitou que você ficasse com dois servidores, app e web. Esses comandos devem ser executados apenas no app.

      Conecte-se ao seu servidor app remoto via ssh:

      • ssh deployer@your_app_server_ip

      Instale o rsync no seu servidor, executando o seguinte comando:

      Confirme a instalação com:

      Você verá uma linha semelhante no resultado deste comando:

      Output

      rsync version 3.1.2 protocol version 31 . . .

      Você pode encerrar sua sessão ssh, digitando exit.

      Com o rsync instalado e disponível na linha de comando, você pode prosseguir com as tarefas de implantação e sua relação com eventos.

      Passo 4 — Configurando e executando tarefas de implantação

      Tanto events quanto tasks são componentes chave das implantações Shipit. É importante entender como eles complementam a implantação do seu aplicativo. Os eventos desencadeados pelo Shipit representam pontos específicos no ciclo de vida da implantação. Suas tarefas executarão em reposta a esses eventos, com base na sequência do clico de vida do Shipit.

      Um exemplo comum de onde esse sistema de tarefa/evento é útil em um aplicativo Node.js é na instalação das dependências do app (node_modules), no servidor remoto. Mais adiante neste passo, você fará o Shipit escutar para o evento updated (que é emitido depois que os arquivos do aplicativo são transferidos) e executar uma tarefa para instalar as dependências do aplicativo (npm install) no servidor remoto.

      Para escutar eventos e executar tarefas, o Shipit precisa de um arquivo de configuração que possua informações sobre seu servidor remoto (o servidor app) e registre ouvintes de eventos e os comandos a serem executados por essas tarefas. Esse arquivo fica no seu computador de desenvolvimento local, no diretório do seu aplicativo Node.js.

      Para começar, crie esse arquivo, incluindo informações sobre seu servidor remoto, os ouvintes de eventos nos quais quer se inscrever e algumas definições das suas tarefas. Crie o shipitfile.js no diretório raiz do seu aplicativo, em sua máquina local, executando o seguinte comando:

      Agora que você criou um arquivo, ele precisa ser preenchido com as informações iniciais do ambiente que o Shipit precisa. Basicamente, esse é o local do seu repositório Git remoto e, mais importante que tudo, do endereço IP público e da conta de usuário SSH do seu servidor app.

      Adicione essa configuração inicial e atualize as linhas destacadas para que correspondam ao seu ambiente:

      shipitfile.js

      module.exports = shipit => {
        require('shipit-deploy')(shipit);
        require('shipit-shared')(shipit);
      
        const appName = 'hello';
      
        shipit.initConfig({
          default: {
            deployTo: '/home/sammy/your-domain',
            repositoryUrl: 'https://git-provider.tld/YOUR_GIT_USERNAME/YOUR_GIT_REPO_NAME.git',
            keepReleases: 5,
            shared: {
              overwrite: true,
              dirs: ['node_modules']
            }
          },
          production: {
            servers: 'sammy@YOUR_APP_SERVER_PUBLIC_IP'
          }
        });
      
        const path = require('path');
        const ecosystemFilePath = path.join(
          shipit.config.deployTo,
          'shared',
          'ecosystem.config.js'
        );
      
        // Our listeners and tasks will go here
      
      };
      

      Atualizando as variables no seu método shipit.initConfig dá ao Shipit uma configuração específica para sua implantação. Essas variáveis representam o seguinte para o Shipit:

      • deployTo: é o diretório onde o Shipit implantará o código do seu aplicativo no servidor remoto. Aqui, você usa a pasta /home/ para um usuário não raiz com privilégios sudo (/home/sammy) uma vez que é segura e evitará problemas de permissão. O componente /your-domain é uma convenção de nomenclatura para distinguir a pasta das demais na pasta inicial do usuário.
      • repositoryUrl: é a URL do repositório completo do Git. O Shipit usará essa URL para garantir que os arquivos do projeto estejam em sincronia antes da implantação.
      • keepReleases: é o número de lançamentos a ser mantido no servidor remoto. Um release (lançamento) é uma pasta com data que contém os arquivos do seu aplicativo no momento do lançamento. Eles podem ser úteis para rollback (reverter) uma implantação.
      • shared: é a configuração que corresponde aos keepReleases que permite que os diretórios sejam shared (compartilhados) entre os lançamentos. Nessa instância, temos uma única pasta node_modules, que é compartilhada entre todos os lançamentos.
      • production: representa um servidor remoto para o qual implantar seu aplicativo. Nessa instância, você tem um servidor (servidor app) único, ao qual você dá o nome de production, com o servers: configuração que correspondendo ao seu user SSH e ao public ip address do SSH. O nome production corresponde ao comando de implantação do Shipit usado ao final deste tutorial (npx shipit server name deploy ou, no seu caso, npx shipit production deploy).

      No repositório Github para o Shipit, você pode encontrar mais informações sobre a o objeto de Configuração da implantação do Shipit.

      Antes de continuar a atualizar seu shipitfile.js, vamos analisar o seguinte exemplo de trecho de código para entender as tarefas do Shipit:

      Example event listener

      shipit.on('deploy', () => { shipit.start('say-hello'); }); shipit.blTask('say-hello', async () => { shipit.local('echo "hello from your local computer"') });

      Esse é um exemplo de tarefa que utiliza o método shipit.on para se inscrever no evento deploy (implantar). Essa tarefa esperará que o evento deploy seja emitido pelo ciclo de vida do Shipit. Depois, quando o evento é recebido, a tarefa executa o método shipit.start, que diz ao Shipit para start (iniciar) a tarefa say-hello.

      O método shipit.on aceita dois parâmetros, o nome do evento para escutar e a função de callback a ser executada quando o evento for recebido.

      Sob a declaração do método shipit.on, a tarefa é definida com o método shipit.blTask. Isso cria uma tarefa do Shipit que irá bloquear outras tarefas durante sua execução (é uma tarefa síncrona). O método shipit.blTask também aceita dois parâmetros, o nome da tarefa que está definindo e uma função de callback para ser executada quando a tarefa for ativada pelo shipit.start.

      Dentro da função de callback dessa tarefa exemplo (say-hello), o método shipit.local executa um comando na máquina local. O comando local ecoa "hello from your local computer" no resultado do terminal.

      Se quisesse executar um comando no servidor remoto, usaria o método shipit.remote. Os dois métodos, shipit.local e shipit.remote, fornecem uma API para emitir comandos tanto localmente quanto remotamente como parte de uma implantação.

      Agora, atualize o shipitfile.js para incluir ouvintes de eventos para se inscrever no ciclo de vida do Shipit com shipit.on. Adicione os ouvintes de eventos ao seu shipitfile.js, inserindo-os após o espaço reservado para comentário da configuração inicial // Our tasks will go here:

      shipitfile.js

      . . .
        shipit.on('updated', () => {
          shipit.start('npm-install', 'copy-config');
        });
      
        shipit.on('published', () => {
          shipit.start('pm2-server');
        });
      

      Esses dois métodos estão escutando os eventos updated e published que são emitidos como parte do ciclo de vida da implantação do Shipit. Quando os eventos forem recebidos, cada qual irá iniciar tarefas usando o método shipit.start, assim como na tarefa exemplo.

      Agora que você agendou os ouvintes, adicionará a tarefa correspondente. Adicione a seguinte tarefa ao seu shipitfile.js, inserindo-a após seus ouvintes de eventos:

      shipitfile.js

      . . .
      shipit.blTask('copy-config', async () => {
      
      const fs = require('fs');
      
      const ecosystem = `
      module.exports = {
      apps: [
        {
          name: '${appName}',
          script: '${shipit.releasePath}/hello.js',
          watch: true,
          autorestart: true,
          restart_delay: 1000,
          env: {
            NODE_ENV: 'development'
          },
          env_production: {
            NODE_ENV: 'production'
          }
        }
      ]
      };`;
      
        fs.writeFileSync('ecosystem.config.js', ecosystem, function(err) {
          if (err) throw err;
          console.log('File created successfully.');
        });
      
        await shipit.copyToRemote('ecosystem.config.js', ecosystemFilePath);
      });
      

      Primeiro, você declara uma tarefa chamada copy-config. Essa tarefa cria um arquivo local chamado ecosystem.config.js e, depois, copia esse arquivo para o seu servidor remoto app. O PM2 usa esse arquivo para gerenciar seu aplicativo Node.js. Ela fornece as informações necessárias do caminho do arquivo para o PM2 para garantir que ele esteja executando seus arquivos mais recentemente implantados. Mais adiante no processo de compilação, você criará uma tarefa que executa o PM2 com o ecosystem.config.js como configuração.

      Caso seu aplicativo precise de variáveis de ambiente (como uma string de conexão com banco de dados), você pode declará-las tanto localmente em env: quanto no servidor remoto em env_production: da mesma maneira que você definiu a variável NODE_ENV nesses objetos.

      Adicione a próxima tarefa ao seu shipitfile.js após a tarefa copy-config:

      shipitfile.js

      . . .
      shipit.blTask('npm-install', async () => {
        shipit.remote(`cd ${shipit.releasePath} && npm install --production`);
      });
      

      Em seguida, declare uma tarefa chamada npm-install. Essa tarefa usa um terminal bash remoto (via shipit.remote) para instalar as dependências do app (pacotes npm).

      Adicione a última tarefa ao seu shipitfile.js depois da tarefa npm-install:

      shipitfile.js

      . . .
      shipit.blTask('pm2-server', async () => {
        await shipit.remote(`pm2 delete -s ${appName} || :`);
        await shipit.remote(
          `pm2 start ${ecosystemFilePath} --env production --watch true`
        );
      });
      

      Por fim, declare uma tarefa chamada pm2-server. Essa tarefa também usa um terminal bash remoto para primeiro impedir o PM2 de gerenciar sua implantação anterior pelo comando delete e, em seguida, iniciar uma nova instância do seu servidor Node.js, fornecendo o arquivo ecosystem.config.js como uma variável. Além disso, você também avisa o PM2 que ele deve usar variáveis de ambiente a partir do bloco production na sua configuração inicial e pede ao PM2 para monitorar o aplicativo, reiniciando-o caso falhe.

      O arquivo completo do shipitfile.js:

      shipitfile.js

      module.exports = shipit => {
        require('shipit-deploy')(shipit);
        require('shipit-shared')(shipit);
      
        const appName = 'hello';
      
        shipit.initConfig({
          default: {
            deployTo: '/home/deployer/example.com',
            repositoryUrl: 'https://git-provider.tld/YOUR_GIT_USERNAME/YOUR_GIT_REPO_NAME.git',
            keepReleases: 5,
            shared: {
              overwrite: true,
              dirs: ['node_modules']
            }
          },
          production: {
            servers: 'deployer@YOUR_APP_SERVER_PUBLIC_IP'
          }
        });
      
        const path = require('path');
        const ecosystemFilePath = path.join(
          shipit.config.deployTo,
          'shared',
          'ecosystem.config.js'
        );
      
        // Our listeners and tasks will go here
        shipit.on('updated', async () => {
          shipit.start('npm-install', 'copy-config');
        });
      
        shipit.on('published', async () => {
          shipit.start('pm2-server');
        });
      
        shipit.blTask('copy-config', async () => {
          const fs = require('fs');
          const ecosystem = `
      module.exports = {
        apps: [
          {
            name: '${appName}',
            script: '${shipit.releasePath}/hello.js',
            watch: true,
            autorestart: true,
            restart_delay: 1000,
            env: {
              NODE_ENV: 'development'
            },
            env_production: {
              NODE_ENV: 'production'
            }
          }
        ]
      };`;
      
          fs.writeFileSync('ecosystem.config.js', ecosystem, function(err) {
            if (err) throw err;
            console.log('File created successfully.');
          });
      
          await shipit.copyToRemote('ecosystem.config.js', ecosystemFilePath);
        });
      
        shipit.blTask('npm-install', async () => {
          shipit.remote(`cd ${shipit.releasePath} && npm install --production`);
        });
      
        shipit.blTask('pm2-server', async () => {
          await shipit.remote(`pm2 delete -s ${appName} || :`);
          await shipit.remote(
            `pm2 start ${ecosystemFilePath} --env production --watch true`
          );
        });
      };
      

      Salve e saia do arquivo quando estiver pronto.

      Com seu shipitfile.js configurado, ouvintes de eventos e as tarefas finalizadas associadas, você pode prosseguir com a implantação para o servidor app.

      Passo 5 — Implantando seu aplicativo

      Neste passo, você implantará seu aplicativo remotamente e testará se a implantação disponibilizou seu aplicativo na internet.

      Como o Shipit clona os arquivos do projeto do repositório remoto do Git, você precisa mandar seus arquivos do aplicativo local Node.js da sua máquina local para o Github. Navegue até o diretório do seu aplicativo do projeto Node.js (onde seu hello.js e shipitfile.js estão localizados) e execute o seguinte comando:

      O comando git status mostra o estado do diretório de trabalho e a área de preparação. Ele permite que você veja quais alterações foram preparadas, quais não foram e quais arquivos o Git não está rastreando. Seus arquivos não estão rastreados e aparecem em vermelho no resultado:

      Output

      On branch master Your branch is up to date with 'origin/master'. Untracked files: (use "git add <file>..." to include in what will be committed) hello.js package-lock.json package.json shipitfile.js nothing added to commit but untracked files present (use "git add" to track)

      Você pode adicionar esses arquivos ao seu repositório com o seguinte comando:

      Esse comando não gera nenhum resultado, embora caso fosse executar o git status novamente, os arquivos apareceriam em verde, com uma nota avisando que existem alterações a serem confirmadas.

      Você pode criar uma confirmação, executando o seguinte comando:

      • git commit -m "Our first commit"

      O resultado desse comando fornece algumas informações específicas do Git sobre os arquivos.

      Output

      [master c64ea03] Our first commit 4 files changed, 1948 insertions(+) create mode 100644 hello.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 shipitfile.js

      Agora, tudo o que resta é mandar sua confirmação para o repositório remoto, para que o Shipit clonar para o seu servidor app durante a implantação. Execute o seguinte comando:

      O resultado inclui informações sobre a sincronização com o repositório remoto:

      Output

      Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 8 threads Compressing objects: 100% (6/6), done. Writing objects: 100% (6/6), 15.27 KiB | 7.64 MiB/s, done. Total 6 (delta 0), reused 0 (delta 0) To github.com:Asciant/hello-world.git e274312..c64ea03 master -> master

      Para implantar seu aplicativo, execute o seguinte comando:

      • npx shipit production deploy

      O resultado desse comando (que é grande demais para ser incluído por completo) fornece detalhes sobre as tarefas que estão sendo executadas e o resultado da função específica. O resultado que se segue à tarefa pm2-server mostra que o app Node.js foi iniciado:

      Output

      Running 'deploy:init' task... Finished 'deploy:init' after 432 μs . . . Running 'pm2-server' task... Running "pm2 delete -s hello || :" on host "centos-ap-app.asciant.com". Running "pm2 start /home/deployer/example.com/shared/ecosystem.config.js --env production --watch true" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com [PM2][WARN] Node 4 is deprecated, please upgrade to use pm2 to have all features @centos-ap-app.asciant.com [PM2][WARN] Applications hello not running, starting... @centos-ap-app.asciant.com [PM2] App [hello] launched (1 instances) @centos-ap-app.asciant.com ┌──────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬─────┬──────────┬──────────┬──────────┐ @centos-ap-app.asciant.com │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ @centos-ap-app.asciant.com ├──────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼─────┼──────────┼──────────┼──────────┤ @centos-ap-app.asciant.com │ hello │ 0 │ 1.0.0 │ fork │ 4177 │ online │ 0 │ 0s │ 0% │ 4.5 MB │ deployer │ enabled │ @centos-ap-app.asciant.com └──────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴─────┴──────────┴──────────┴──────────┘ @centos-ap-app.asciant.com Use `pm2 show <id|name>` to get more details about an app Finished 'pm2-server' after 5.27 s Running 'deploy:clean' task... Keeping "5" last releases, cleaning others Running "(ls -rd /home/deployer/example.com/releases/*|head -n 5;ls -d /home/deployer/example.com/releases/*)|sort|uniq -u|xargs rm -rf" on host "centos-ap-app.asciant.com". Finished 'deploy:clean' after 1.81 s Running 'deploy:finish' task... Finished 'deploy:finish' after 222 μs Finished 'deploy' [ deploy:init, deploy:fetch, deploy:update, deploy:publish, deploy:clean, deploy:finish ]

      Para visualizar seu aplicativo como um usuário visualizaria, você pode digitar a URL your-domain do seu site em seu navegador para acessar o servidor web. Isso servirá o aplicativo Node.js, por proxy reverso, no servidor app, onde seus arquivos foram implantados.

      Você verá uma saudação Hello World.

      Nota: após a primeira implantação, seu repositório Git irá rastrear um arquivo recém-criado, chamado ecosystem.config.js. Como esse arquivo será recompilado a cada implantação, podendo conter segredos do aplicativo compilado, ele deve ser adicionado ao arquivo .gitignore, no diretório raiz do aplicativo em sua máquina local, antes da sua próxima confirmação do git.

      .gitignore

      . . .
      # ecosystem.config
      ecosystem.config.js
      

      Você implantou seu aplicativo Node.js em seu servidor app, que se refere à sua nova implantação. Com tudo em funcionamento, você pode prosseguir com o monitoramento dos processos do seu aplicativo.

      Passo 6 — Monitorando seu aplicativo

      O PM2 é uma ótima ferramenta para gerenciar seus processos remotos, mas também fornece recursos para monitorar o desempenho desses processos do aplicativo.

      Conecte-se ao seu servidor app remoto via SSH com este comando:

      • ssh deployer@your_app_server_ip

      Para obter informações específicas relacionadas aos seus processos gerenciados pelo PM2, execute o seguinte:

      Você verá um resultado parecido com este:

      Output

      ┌─────────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬──────┬───────────┬──────────┬──────────┐ │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ ├─────────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼──────┼───────────┼──────────┼──────────┤ │ hello │ 0 │ 0.0.1 │ fork │ 3212 │ online │ 0 │ 62m │ 0.3% │ 45.2 MB │ deployer │ enabled │ └─────────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴──────┴───────────┴──────────┴──────────┘

      Você verá um resumo das informações que o PM2 coletou. Para ver informações detalhadas, execute:

      O resultado dá mais detalhes sobre as informações do resumo fornecidas pelo comando pm2 list. Ele também fornece informações sobre vários comandos auxiliares e fornece os locais dos arquivos de registro:

      Output

      Describing process with id 0 - name hello ┌───────────────────┬─────────────────────────────────────────────────────────────┐ │ status │ online │ │ name │ hello │ │ version │ 1.0.0 │ │ restarts │ 0 │ │ uptime │ 82s │ │ script path │ /home/deployer/example.com/releases/20190531213027/hello.js │ │ script args │ N/A │ │ error log path │ /home/deployer/.pm2/logs/hello-error.log │ │ out log path │ /home/deployer/.pm2/logs/hello-out.log │ │ pid path │ /home/deployer/.pm2/pids/hello-0.pid │ │ interpreter │ node │ │ interpreter args │ N/A │ │ script id │ 0 │ │ exec cwd │ /home/deployer │ │ exec mode │ fork_mode │ │ node.js version │ 4.2.3 │ │ node env │ production │ │ watch & reload │ ✔ │ │ unstable restarts │ 0 │ │ created at │ 2019-05-31T21:30:48.334Z │ └───────────────────┴─────────────────────────────────────────────────────────────┘ Revision control metadata ┌──────────────────┬────────────────────────────────────────────────────┐ │ revision control │ git │ │ remote url │ N/A │ │ repository root │ /home/deployer/example.com/releases/20190531213027 │ │ last update │ 2019-05-31T21:30:48.559Z │ │ revision │ 62fba7c8c61c7769022484d0bfa46e756fac8099 │ │ comment │ Our first commit │ │ branch │ master │ └──────────────────┴────────────────────────────────────────────────────┘ Divergent env variables from local env ┌───────────────────────────┬───────────────────────────────────────┐ │ XDG_SESSION_ID │ 15 │ │ HOSTNAME │ N/A │ │ SELINUX_ROLE_REQUESTED │ │ │ TERM │ N/A │ │ HISTSIZE │ N/A │ │ SSH_CLIENT │ 44.222.77.111 58545 22 │ │ SELINUX_USE_CURRENT_RANGE │ │ │ SSH_TTY │ N/A │ │ LS_COLORS │ N/A │ │ MAIL │ /var/mail/deployer │ │ PATH │ /usr/local/bin:/usr/bin │ │ SELINUX_LEVEL_REQUESTED │ │ │ HISTCONTROL │ N/A │ │ SSH_CONNECTION │ 44.222.77.111 58545 209.97.167.252 22 │ └───────────────────────────┴───────────────────────────────────────┘ . . .

      O PM2 também fornece uma ferramenta de monitoramento dentro do terminal, que pode ser acessada com:

      O resultado desse comando é um painel interativo, onde o pm2 fornece informações de processo, registros, métricas e metadados em tempo real. Este painel pode ajudar no monitoramento de recursos e registros de erro:

      Output

      ┌─ Process list ────────────────┐┌─ Global Logs ─────────────────────────────────────────────────────────────┐ │[ 0] hello Mem: 22 MB ││ │ │ ││ │ │ ││ │ └───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘ ┌─ Custom metrics (http://bit.l─┐┌─ Metadata ────────────────────────────────────────────────────────────────┐ │ Heap Size 10.73 ││ App Name hello │ │ Heap Usage 66.14 ││ Version N/A │ │ Used Heap Size 7.10 ││ Restarts 0 │ │ Active requests 0 ││ Uptime 55s │ │ Active handles 4 ││ Script path /home/asciant/hello.js │ │ Event Loop Latency 0.70 ││ Script args N/A │ │ Event Loop Latency p95 ││ Interpreter node │ │ ││ Interpreter args N/A │ └───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘

      Com uma compreensão sobre como você pode monitorar seus processos com o PM2, você pode prosseguir e ver como o Shipit pode ajudar na reversão para uma implantação anterior em funcionamento.

      Termine sua sessão ssh no seu servidor app executando exit.

      Passo 7 — Revertendo uma implantação problemática

      Às vezes, as implantações revelam bugs imprevistos, ou problemas que fazem com que seu site falhe. Os desenvolvedores e mantenedores do Shipit previram esse problema e proporcionaram a capacidade de se fazer a reversão para implantações anteriores (em funcionamento) do seu aplicativo.

      Para garantir que sua configuração PM2 permaneça, adicione outro ouvinte de eventos ao shipitfile.js no evento rollback (reversão):

      shipitfile.js

      . . .
        shipit.on('rollback', () => {
          shipit.start('npm-install', 'copy-config');
        });
      

      Adicione um ouvinte ao evento rollback para executar suas tarefas npm-install e copy-config. Isso é necessário, pois, ao contrário do evento published, o evento updated não é executado pelo ciclo de vida do Shipit quando se reverte uma implantação. Adicionar esse ouvinte de eventos garante que seu gerenciador de processos PM2 apontará para a implantação mais recente, mesmo no caso de uma reversão.

      Esse processo é semelhante ao da implantação, com uma pequena alteração no comando. Para tentar reverter para uma implantação anterior, execute o seguinte:

      • npx shipit production rollback

      Assim como o comando deploy, o rollback fornece detalhes sobre o processo de reversão e as tarefas que estão sendo executadas:

      Output

      Running 'rollback:init' task... Get current release dirname. Running "if [ -h /home/deployer/example.com/current ]; then readlink /home/deployer/example.com/current; fi" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com releases/20190531213719 Current release dirname : 20190531213719. Getting dist releases. Running "ls -r1 /home/deployer/example.com/releases" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com 20190531213719 @centos-ap-app.asciant.com 20190531213519 @centos-ap-app.asciant.com 20190531213027 Dist releases : ["20190531213719","20190531213519","20190531213027"]. Will rollback to 20190531213519. Finished 'rollback:init' after 3.96 s Running 'deploy:publish' task... Publishing release "/home/deployer/example.com/releases/20190531213519" Running "cd /home/deployer/example.com && if [ -d current ] && [ ! -L current ]; then echo "ERR: could not make symlink"; else ln -nfs releases/20190531213519 current_tmp && mv -fT current_tmp current; fi" on host "centos-ap-app.asciant.com". Release published. Finished 'deploy:publish' after 1.8 s Running 'pm2-server' task... Running "pm2 delete -s hello || :" on host "centos-ap-app.asciant.com". Running "pm2 start /home/deployer/example.com/shared/ecosystem.config.js --env production --watch true" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com [PM2][WARN] Node 4 is deprecated, please upgrade to use pm2 to have all features @centos-ap-app.asciant.com [PM2][WARN] Applications hello not running, starting... @centos-ap-app.asciant.com [PM2] App [hello] launched (1 instances) @centos-ap-app.asciant.com ┌──────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬─────┬──────────┬──────────┬──────────┐ @centos-ap-app.asciant.com │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ @centos-ap-app.asciant.com ├──────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼─────┼──────────┼──────────┼──────────┤ @centos-ap-app.asciant.com │ hello │ 0 │ 1.0.0 │ fork │ 4289 │ online │ 0 │ 0s │ 0% │ 4.5 MB │ deployer │ enabled │ @centos-ap-app.asciant.com └──────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴─────┴──────────┴──────────┴──────────┘ @centos-ap-app.asciant.com Use `pm2 show <id|name>` to get more details about an app Finished 'pm2-server' after 5.55 s Running 'deploy:clean' task... Keeping "5" last releases, cleaning others Running "(ls -rd /home/deployer/example.com/releases/*|head -n 5;ls -d /home/deployer/example.com/releases/*)|sort|uniq -u|xargs rm -rf" on host "centos-ap-app.asciant.com". Finished 'deploy:clean' after 1.82 s Running 'rollback:finish' task... Finished 'rollback:finish' after 615 μs Finished 'rollback' [ rollback:init, deploy:publish, deploy:clean, rollback:finish ]

      Você configurou o Shipit para manter 5 versões de lançamento, através da configuração de keepReleases: 5 no shipitfile.js. O Shipit monitora essas versões internamente para garantir a capacidade de reverter quando necessário. O Shipit também fornece uma maneira conveniente de identificar as versões, criando um diretório nomeado na forma de um carimbo de data/hora (YYYYMMDDHHmmss – Exemplo: /home/deployer/your-domain/releases/20190420210548).

      Se quisesse personalizar ainda mais o processo de reversão, você poderia ouvir eventos específicos para a operação de reversão. Na sequência, você poderá usar esses eventos para executar tarefas que irão complementar sua reversão. Você pode consultar a lista de eventos fornecida no detalhamento do ciclo de vida do Shipit e configurar as tarefas/ouvintes dentro do seu shipitfile.js.

      Capacidade de reversão significa que sempre será possível oferecer aos seus usuários uma versão do seu aplicativo que funcione, mesmo se uma implantação introduzir erros/problemas inesperados.

      Conclusão

      Neste tutorial, você configurou um fluxo de trabalho que permite que crie uma alternativa altamente personalizável da Plataforma como um Serviço, tudo a partir de alguns servidores. Esse fluxo de trabalho leva em consideração implantações e configurações personalizadas, o monitoramento de processos com o PM2, a possibilidade de dimensionar e adicionar serviços, servidores adicionais ou ambientes à implantação, quando necessário.

      Se estiver interessado em continuar no desenvolvimento de suas habilidades com o Node.js, confira o material sobre Node.js da DigitalOcean, bem como a série sobre Como programar no Node.js.



      Source link

      Como Escalar Automaticamente suas Cargas de Trabalho no Kubernetes da DigitalOcean


      Introdução

      Ao trabalhar com uma aplicação criada no Kubernetes, os desenvolvedores frequentemente precisam provisionar pods adicionais para lidar com períodos de pico de tráfego ou aumento da carga de processamento. Por padrão, provisionar esses pods adicionais é uma etapa manual; o desenvolvedor deve alterar o número de réplicas desejadas no objeto do deployment para contar com o aumento do tráfego e alterá-lo novamente quando os pods adicionais não forem mais necessários. Essa dependência da intervenção manual pode não ser o ideal em muitos cenários. Por exemplo, sua carga de trabalho pode atingir o horário de pico no meio da noite, quando ninguém está acordado para escalar os pods, ou seu site pode receber um aumento inesperado no tráfego quando uma resposta manual não seria rápida o suficiente para lidar com a carga. Nessas situações, a abordagem mais eficiente e menos sujeita a erros é automatizar o escalonamento dos seus clusters com o Horizontal Pod Autoscaler (HPA).

      Usando informações do Metrics Server, o HPA detectará aumento no uso de recursos e responderá escalando sua carga de trabalho para você. Isso é especialmente útil nas arquiteturas de microsserviço e dará ao cluster Kubernetes a capacidade de escalar seu deployment com base em métricas como a utilização da CPU. Quando combinado como o DigitalOcean Kubernetes (DOKS), uma oferta de Kubernetes gerenciada que fornece aos desenvolvedores uma plataforma para fazer o deploy de aplicações containerizadas, o uso do HPA pode criar uma infraestrutura automatizada que se ajusta rapidamente às mudanças no tráfego e na carga.

      Nota: Ao considerar a possibilidade de usar o autoscaling para sua carga de trabalho, lembre-se de que o autoscaling funciona melhor para aplicativos sem estado ou stateless, especialmente aqueles capazes de ter várias instâncias da aplicação em execução e aceitando tráfego em paralelo. Esse paralelismo é importante porque o principal objetivo do autoscaling é distribuir dinamicamente a carga de trabalho de uma aplicação por várias instâncias no cluster Kubernetes para garantir que sua aplicação tenha os recursos necessários para atender o tráfego de maneira ágil e estável, sem sobrecarregar nenhuma instância única.

      Um exemplo de carga de trabalho que não apresenta esse paralelismo é o autoscaling de banco de dados. A configuração do autoscaling para um banco de dados seria muito mais complexa, pois você precisaria considerar race conditions, problemas com a integridade dos dados, sincronização de dados e adições e remoções constantes de membros do cluster de banco de dados. Por razões como essas, não recomendamos o uso da estratégia de autoscaling deste tutorial para bancos de dados.

      Neste tutorial você vai configurar um deployment de exemplo do Nginx no DOKS que pode auto escalar horizontalmente para dar conta do aumento da carga de CPU. Você conseguirá isso ao fazer o deploy do Metrics Server em seu cluster para reunir métricas de pod para o HPA usar para determinar quando escalar.

      Pré-requisitos

      Antes de começar este guia, você precisará do seguinte:

      • Um cluster Kubernetes na DigitalOcean com sua conexão configurada como padrão kubectl. As instruções sobre como configurar o kubectl são mostradas no passo Connect to your Cluster quando você cria seu cluster. Para criar um cluster Kubernetes na DigitalOcean, consulte Kubernetes Quickstart.

      • O gerenciador de pacotes Helm instalado em sua máquina local e o Tiller instalado em seu cluster. Para fazer isso, execute os passos 1 e 2 do tutorial How To Install Software on Kubernetes Clusters with the Helm Package Manager

      Passo 1 — Criando um Deployment de Teste

      Para mostrar o efeito do HPA, você primeiro fará o deploy de uma aplicação que você utilizará para fazer autoscale. Este tutorial usa uma imagem Nginx Docker padrão como um deployment porque ela é totalmente capaz de operar em paralelo, é amplamente usada no Kubernetes com ferramentas como o Nginx Ingress Controller, e é leve para configurar. Esse deployment do Nginx servirá uma página estática Welcome to Nginx!, que vem por padrão na imagem base. Se você já possui um deployment que gostaria de escalar, sinta-se à vontade para usá-lo e pule este passo.

      Crie o deployment de exemplo usando a imagem base do Nginx executando o seguinte comando. Você pode substituir o nome web se desejar atribuir um nome diferente ao seu deployment:

      • kubectl create deployment web --image=nginx:latest

      A flag --image=nginx:latest criará o deployment a partir da versão mais recente da imagem base do Nginx.

      Após alguns segundos, seu pod web será lançado. Para ver este pod, execute o seguinte comando, que mostrará os pods em execução no namespace atual:

      Isso lhe dará uma saída semelhante à seguinte:

      Output

      NAME READY STATUS RESTARTS AGE web-84d7787df5-btf9h 1/1 Running 0 11s

      Observe que há apenas um pod deployado originalmente. Depois que o autoscaling é acionado, mais pods serão criados automaticamente.

      Agora você tem um deployment básico em funcionamento no cluster. Este é o deployment que você irá configurar para o autoscaling. Seu próximo passo é configurar esse deployment para definir suas solicitações de recursos e limites.

      Passo 2 — Definindo Limites e Solicitações de CPU em seu Deployment

      Neste passo, você irá definir solicitações e limites no uso da CPU para seu deployment. Limites ou Limits no Kubernetes são definidos no deployment para descrever a quantidade máxima de recursos (CPU ou Memória) que o pod pode usar. Solicitações ou Requests são definidas no deployment para descrever quanto desse recurso é necessário em um node para que esse node seja considerado como um node válido para escalonamento. Por exemplo, se seu servidor web tivesse uma solicitação de memória definida em 1 GB, apenas os nodes com pelo menos 1 GB de memória livre seriam considerados para escalonamento. Para o autoscaling, é necessário definir esses limites e solicitações, pois o HPA precisará ter essas informações ao tomar decisões de escalonamento e provisionamento.

      Para definir solicitações e limites, você precisará fazer alterações no deployment que você acabou de criar. Este tutorial usará o seguinte comando kubectl edit para modificar a configuração do objeto API armazenada no cluster. O comando kubectl edit abrirá o editor definido por suas variáveis de ambiente KUBE_EDITOR ou EDITOR, ou cairá de volta no vi para Linux ou notepad para Windows por padrão.

      Edite seu deployment:

      • kubectl edit deployment web

      Você verá a configuração para o deployment. Agora você pode definir limites de recursos e solicitações especificadas para o uso de CPU do seu deployment. Esses limites definem a linha de base de quanto de cada recurso um pod deste deployment pode usar individualmente. Definir isso dará ao HPA um quadro de referência para saber se um pod está sendo sobrecarregado. Por exemplo, se você espera que seu pod tenha um limit superior de 100 milicores de CPU e o pod esteja usando 95 milicores atualmente, a HPA saberá que está com 95% da capacidade. Sem fornecer esse limite de 100 milicores, o HPA não pode decifrar a capacidade total do pod.

      Podemos definir os limites e solicitações na seção resources:

      Deployment Configuration File

      . . .
        template:
          metadata:
            creationTimestamp: null
            labels:
              app: web
          spec:
            containers:
            - image: nginx:latest
              imagePullPolicy: Always
              name: nginx
              resources: {}
              terminationMessagePath: /dev/termination-log
              terminationMessagePolicy: File
            dnsPolicy: ClusterFirst
            restartPolicy: Always
            schedulerName: default-scheduler
            securityContext: {}
            terminationGracePeriodSeconds: 30
      status:
        availableReplicas: 1
      . . .
      

      Para este tutorial, você definirá requests para CPU como 100m e memória para 250Mi. Esses valores são apenas para fins de demonstração; cada carga de trabalho é diferente, portanto, esses valores podem não fazer sentido para outras cargas de trabalho. Como regra geral, esses valores devem ser definidos no máximo que um pod dessa carga de trabalho deve usar. Recomenda-se o monitoramento da aplicação e a coleta de dados de uso de recursos sobre o desempenho em períodos de baixa e de pico para ajudar a determinar esses valores. Esses valores também podem ser ajustados e alterados a qualquer momento, assim você sempre pode voltar e otimizar seu deployment posteriormente.

      Vá em frente e insira as seguintes linhas destacadas na seção resources do seu container Nginx:

      Deployment Configuration File

      . . .
        template:
          metadata:
            creationTimestamp: null
            labels:
              app: web
          spec:
            containers:
            - image: nginx:latest
              imagePullPolicy: Always
              name: nginx
              resources:
                limits:
                  cpu: 300m
                requests:
                  cpu: 100m
                  memory: 250Mi
              terminationMessagePath: /dev/termination-log
              terminationMessagePolicy: File
            dnsPolicy: ClusterFirst
            restartPolicy: Always
            schedulerName: default-scheduler
            securityContext: {}
            terminationGracePeriodSeconds: 30
      status:
        availableReplicas: 1
      . . .
      

      Depois de inserir essas linhas, salve e saia do arquivo. Se houver um problema com a sintaxe, o kubectl irá reabrir o arquivo para você com um erro publicado para que você obtenha mais informações.

      Agora que você definiu seus limites e solicitações, você precisa garantir que suas métricas sejam reunidas para que o HPA possa monitorar e aderir corretamente a esses limites. Para fazer isso, você irá configurar um serviço para reunir as métricas de CPU. Para este tutorial, você usará o projeto Metrics Server para coletar essas métricas, que você instalará com um chart do Helm.

      Passo 3 — Instalando o Metrics Server

      Agora você instalará o Kubernetes Metric Server. Esse é o servidor que extrai as métricas do pod, que reunirá as métricas que o HPA usará para decidir se o autoscaling é necessário.

      Para instalar o Metrics Server usando o Helm, execute o seguinte comando:

      • helm install stable/metrics-server --name metrics-server

      Isso instalará a versão estável mais recente do Metrics Server. A flag --name nomeia este release como metrics-server.

      Depois de aguardar a inicialização deste pod, tente usar o comando kubectl top pod para exibir as métricas do seu pod:

      Este comando tem como objetivo fornecer uma visão em nível de pod do uso de recursos em seu cluster, mas devido à maneira como o DOKS lida com o DNS, esse comando retornará um erro neste momento:

      Output

      Error: Metrics not available for pod Error from server (ServiceUnavailable): the server is currently unable to handle the request (get pods.metrics.k8s.io)

      Esse erro ocorre porque os nodes DOKS não criam um registro DNS para eles mesmos e, como o Metrics Server entra em contato com os nodes por meio de seus nomes de host, os nomes de host não são resolvidos corretamente. Para corrigir esse problema, altere a maneira como o Metrics Server se comunica com os nodes adicionando flags de runtime ao container do Metrics Server usando o seguinte comando:

      • kubectl edit deployment metrics-server

      Você estará adicionando uma flag na seção command.

      metrics-server Configuration File

      . . .
        template:
          metadata:
            creationTimestamp: null
            labels:
              app: metrics-server
              release: metrics-server
          spec:
            affinity: {}
            containers:
            - command:
              - /metrics-server
              - --cert-dir=/tmp
              - --logtostderr
              - --secure-port=8443
              image: gcr.io/google_containers/metrics-server-amd64:v0.3.4
              imagePullPolicy: IfNotPresent
              livenessProbe:
                failureThreshold: 3
                httpGet:
                  path: /healthz
      . . .
      

      A flag que você está adicionando é --kubelet-preferred-address-types=InternalIP. Essa flag informa ao metrics server para contatar os nodes usando seu internalIP em oposição ao nome do host. Você pode usar essa flag como uma solução alternativa para se comunicar com os nodes por meio de endereços IP internos.

      Adicione também a flag --metric-resolution para alterar a taxa padrão na qual o Metrics Server extrai as métricas. Para este tutorial, configuraremos o Metrics Server para realizar pontos de coletas de dados a cada 60s, mas se você quiser mais dados de métricas, poderá solicitar ao Metrics Server que extraia as métricas a cada 10s ou 20s. Isso lhe fornecerá mais pontos de dados de uso de recursos por período de tempo. Sinta-se livre para ajustar esta resolução para atender às suas necessidades.

      Adicione as seguintes linhas destacadas ao arquivo:

      metrics-server Configuration File

      . . .
        template:
          metadata:
            creationTimestamp: null
            labels:
              app: metrics-server
              release: metrics-server
          spec:
            affinity: {}
            containers:
            - command:
              - /metrics-server
              - --cert-dir=/tmp
              - --logtostderr
              - --secure-port=8443
              - --metric-resolution=60s
              - --kubelet-preferred-address-types=InternalIP
              image: gcr.io/google_containers/metrics-server-amd64:v0.3.4
              imagePullPolicy: IfNotPresent
              livenessProbe:
                failureThreshold: 3
                httpGet:
                  path: /healthz
      . . .
      

      Após a adição da flag, salve e saia do seu editor.

      Para verificar se o Metrics Server está em execução, use o kubectl top pod após alguns minutos. Como antes, este comando nos fornecerá o uso de recursos em um nível de pod. Dessa vez, um Metrics Server funcionando permitirá que você veja as métricas em cada pod:

      Isso fornecerá a seguinte saída, com o seu pod do Metrics Server em execução:

      Output

      NAME CPU(cores) MEMORY(bytes) metrics-server-db745fcd5-v8gv6 3m 12Mi web-555db5bf6b-f7btr 0m 2Mi

      Agora você tem um Metrics Server funcional e pode visualizar e monitorar o uso de recursos de pods em seu cluster. Em seguida, você irá configurar o HPA para monitorar esses dados e reagir a períodos de alto uso da CPU.

      Passo 4 — Criando e Validando o Autoscaler Horizontal de Pod

      Por fim, é hora de criar o Horizontal Pod Autoscaler (HPA) para seu deployment. O HPA é o objeto real do Kubernetes que verifica rotineiramente os dados de uso de CPU coletados do Metrics Server e escala seu deployment com base nos limites que você definiu no Passo 2.

      Crie o HPA usando o comando kubectl autoscale:

      • kubectl autoscale deployment web --max=4 --cpu-percent=80

      Este comando cria o HPA para seu deployment web. Ele também usa a flag --max para definir o máximo de réplicas nas quais web pode ser escalado, o que, neste caso, você define como 4.

      A flag --cpu-percent informa ao HPA em qual porcentagem de uso do limite que você definiu no Passo 2 você deseja que o autoscale ocorra. Isso também usa os requests para ajudar a provisionar os pods escalados para um node que possa acomodar a alocação inicial de recursos. Neste exemplo, se o limite que você definiu para o seu deployment no Passo 1 fosse 100 milicores (100m), esse comando dispararia um autoscale assim que o pod atingisse 80m no uso médio da CPU. Isso permitiria que o deployment fosse escalado automaticamente antes de estourar seus recursos de CPU.

      Agora que seu deployment pode ser escalado automaticamente, é hora de testar isso.

      Para validar, você irá gerar uma carga que colocará seu cluster acima do seu limite e assistirá o autoscaler assumir o controle. Para começar, abra um segundo terminal para observar os pods provisionados no momento e atualizar a lista de pods a cada 2 segundos. Para fazer isso, use o comando watch neste segundo terminal:

      O comando watch emite o comando dado como argumento continuamente, exibindo a saída no seu terminal. A duração entre repetições pode ser configurada mais finamente com a flag -n. Para os fins deste tutorial, a configuração padrão de dois segundos será suficiente.

      O terminal agora exibirá a saída do kubectl top pods inicialmente e, a cada 2 segundos, atualizará a saída que esse comando gera, que será semelhante a esta:

      Output

      Every 2.0s: kubectl top pods NAME CPU(cores) MEMORY(bytes) metrics-server-6fd5457684-7kqtz 3m 15Mi web-7476bb659d-q5bjv 0m 2Mi

      Anote o número de pods atualmente deployados para o web.

      Volte ao seu terminal original. Agora você abrirá um terminal dentro do seu pod web atual usando kubectl exec e criará uma carga artificial. Você pode fazer isso entrando no pod e instalando o stress CLI tool.

      Digite seu pod usando kubectl exec, substituindo o nome do pod realçado pelo nome do seu pod web:

      • kubectl exec -it web-f765fd676-s9729 /bin/bash

      Este comando é muito semelhante em conceito ao de usar ssh para efetuar login em outra máquina. O /bin/bash estabelece um shell bash no seu pod.

      Em seguida, no shell bash dentro do seu pod, atualize os metadados do repositório e instale o pacote stress.

      • apt update; apt-get install -y stress

      Nota: Para containers baseados no CentOS, isso seria assim:

      Em seguida, gere alguma carga de CPU no seu pod usando o comando stress e deixe-o executar:

      Agora, volte ao seu comando watch no segundo terminal. Aguarde alguns minutos para o Metrics Server reunir dados de CPU acima do limite definido pelo HPA. Observe que as métricas por padrão são coletadas na taxa que você definir como --metric-resolution ao configurar o metrics server. Pode demorar um minuto para que as métricas de uso sejam atualizadas.

      Após cerca de dois minutos, você verá pods adicionais web subindo:

      Output

      Every 2.0s: kubectl top pods NAME CPU(cores) MEMORY(bytes) metrics-server-db745fcd5-v8gv6 6m 16Mi web-555db5bf6b-ck98q 0m 2Mi web-555db5bf6b-f7btr 494m 21Mi web-555db5bf6b-h5cbx 0m 1Mi web-555db5bf6b-pvh9f 0m 2Mi

      Agora você pode ver que o HPA provisionou novos pods com base na carga de CPU coletada pelo Metrics Server. Quando estiver satisfeito com esta validação, use CTRL+C para interromper o comando stress no seu primeiro terminal e então, saia do shell bash do seu pod.

      Conclusão

      Neste artigo, você criou um deployment que será escalado automaticamente com base na carga de CPU. Você adicionou limites de recursos e solicitações de CPU ao seu deployment, instalou e configurou o Metrics Server em seu cluster por meio do uso do Helm e criou um HPA para tomar decisões de escalabilidade.

      Esse foi um deployment de demonstração tanto do Metrics Server quanto do HPA. Agora você pode ajustar a configuração para se adequar aos seus casos de uso específicos. Certifique-se de verificar a documentação do Kubernetes HPA para ajuda e informação sobre requests e limits. Além disso, confira o Projeto Metrics Server para ver todas as configurações ajustáveis que podem ser aplicadas ao seu caso de uso.

      Se você gostaria de fazer mais com o Kubernetes, visite nossa Página da Comunidade Kubernetes ou explore nosso Serviço Gerenciado de Kubernetes.



      Source link