Posts
Configurando Integração Contínua no Ubuntu com Nodejs
15 de agosto de 2015 • 12 min de leitura

Passei por sangue, suor e lágrimas para trazer isso para você. Sofri o calor escaldante do Vale da Morte e escalei os picos do Monte McKinley. Sacrifiquei muito.
Muito do conteúdo compartilhado neste post não é meu trabalho original. Onde posso, faço link de volta ao trabalho original.
Este artigo assume que você consegue se virar no Linux.
Não consegui encontrar um guia abrangente sobre hospedagem e gerenciamento de aplicações Nodejs no Ubuntu em capacidade de produção. Juntei vários artigos sobre o assunto. Ao final deste artigo espero que você seja capaz de configurar seu próprio servidor Ubuntu e ter o Nodejs fazendo deploy via servidor de integração contínua.
Ambiente
Estou usando TeamCity no Windows que então faz deploy do código do GitHub para Ubuntu hospedado na AWS.
Tecnologias
Para este artigo usei as seguintes tecnologias:
- Ubuntu 14.04 na AWS
- Plink 0.64
- TeamCity 9.1
- GitHub
- Nginx 1.9.3
Configurando o Ubuntu
Não vou entrar em detalhes aqui. Amazon Web Services (AWS) torna isso bem fácil de fazer. Não importa onde está ou se está no seu próprio servidor.
Encontrei algumas pegadinhas. Primeiro, certifique-se de que a porta 80 esteja aberta. Cometi o erro tolo de tentar conectar com a porta 80 fechada. Uma vez que descobri meu erro, me senti como o traseiro de um rinoceronte.
Instalando Nodejs do Código Fonte
Nodejs é uma tecnologia de servidor usando o motor javascript V8 do Google. Desde seu lançamento em 2010, tornou-se amplamente popular.
As seguintes instruções originalmente vieram de um post da Digital Ocean.
Você sempre tem a opção de instalar o Nodejs do apt-get, mas estará algumas versões atrasado. Para obter os bits mais recentes, instale o Nodejs do código fonte.
Ao final desta seção teremos baixado a versão estável mais recente do node (na data deste artigo), teremos compilado o código fonte e instalado o Nodejs.
Faça login no seu servidor. Começaremos atualizando as listas de pacotes.
sudo apt-get update
Também sugiro que você atualize todos os pacotes. Isso não é necessário para o Nodejs, mas é uma boa prática manter seu servidor atualizado.
sudo apt-get upgrade
Seu servidor está todo atualizado. É hora de baixar o código fonte.
cd ~
Na data da escrita, 12.7 é a versão estável mais recente do Nodejs. Confira nodejs.org para a versão mais recente.
wget https://nodejs.org/dist/v0.12.7/node-v0.12.7.tar.gz
Extraia o arquivo que você baixou.
tar xvf node-v*
Mova para o diretório recém-criado
cd node-v*
Configure e compile o Nodejs.
./configure
make
Instale o Nodejs
sudo make install
Para remover os arquivos baixados e extraídos. Claro, isso é opcional.
cd ~
rm -rf node-v*
Parabéns! O Nodejs agora está instalado! E não foi muito difícil.
Configurando o Nginx
O Nodejs pode atuar como um servidor web, mas não é o que eu gostaria de expor ao mundo. Um servidor web industrial, endurecido e rico em recursos é mais adequado para isso. Recorri ao Nginx para esta tarefa.
É um servidor web maduro com os recursos que precisamos. Para executar mais de uma instância do Nodejs, precisaremos de encaminhamento de porta.
Você pode estar pensando, por que precisamos de mais de uma instância do Nodejs rodando ao mesmo tempo. Essa é uma pergunta justa… No meu cenário, tenho um servidor e preciso executar DEV, QA e PROD na mesma máquina. Sim, eu sei que não é ideal, mas não quero levantar 3 servidores para cada ambiente.
Para começar, vamos instalar o Nginx
sudo -s
add-apt-repository ppa:nginx/stable
apt-get update
apt-get install nginx
Uma vez que o Nginx foi instalado com sucesso, precisamos configurar os domínios. Vou assumir que você vai querer ter cada um dos seus sites em seu próprio domínio/subdomínio. Se você não quiser e quiser usar diferentes subpastas, isso é possível e muito fácil de fazer. Não vou cobrir esse cenário aqui. Há uma tonelada de documentação sobre como fazer isso. Há muito pouca documentação sobre configurar diferentes domínios e encaminhamento de porta para as instâncias correspondentes do Nodejs. Isso é o que vou cobrir.
Agora que o Nginx está instalado, crie um arquivo para seudominio.com em /etc/nginx/sites-available/
sudo nano /etc/nginx/sites-available/seudominio.com
Adicione a seguinte configuração ao seu arquivo recém-criado
# o(s) IP(s) no qual seu servidor node está rodando. Escolhi a porta 9001.
upstream app_myapp1 {
server 127.0.0.1:9001;
keepalive 8;
}
# a instância do servidor nginx
server {
listen 80;
server_name seudominio.com;
access_log /var/log/nginx/seudominio.log;
# passa a requisição para o servidor node.js com os cabeçalhos corretos
# e muito mais pode ser adicionado, veja as opções de configuração do nginx
location / {
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://app_myapp1;
}
}
Certifique-se de substituir “seudominio.com” pelo seu domínio real. Salve e saia do seu editor.
Crie um link simbólico para este arquivo no diretório sites-enabled.
cd /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/seudominio.com seudominio.com
Para testar se tudo está funcionando corretamente, crie um aplicativo node simples e salve-o em /var/www/seudominio.com/app.js
e execute-o.
Aqui está um aplicativo nodejs simples se você não tiver um à mão.
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');}).listen(9001, "127.0.0.1");
console.log('Server running at http://127.0.0.1:9001/');
Vamos reiniciar o Nginx.
sudo /etc/init.d/nginx restart
Não se esqueça de iniciar sua instância do Nodejs, se ainda não o fez.
cd /var/www/seudominio/ && node app.js
Se tudo estiver funcionando corretamente, quando você navegar para seudominio.com verá “Hello World.”
Para adicionar outro domínio para uma instância diferente do Nodejs, você precisa repetir os passos acima. Especificamente, você precisará alterar o nome do upstream, a porta e o domínio no seu novo arquivo de configuração do Nginx. O endereço proxy_pass deve corresponder ao nome do upstream no arquivo de configuração do nginx. Olhe o nome do upstream e o valor do proxy_pass e você verá o que quero dizer.
Para recapitular, instalamos o NodeJS do código fonte e acabamos de terminar de instalar o Nginx. Configuramos e testamos o encaminhamento de porta com Nginx e Nodejs
Instalando o PM2
Você pode estar perguntando “O que é PM2?” como eu perguntei quando ouvi falar pela primeira vez. PM2 é um gerenciador de processos para aplicações Nodejs. O Nodejs não vem com muito. Isso é parte do seu apelo. A desvantagem disso é, bem, você tem que fornecer as camadas na frente dele. PM2 é uma dessas camadas.
O PM2 gerencia a vida do processo Nodejs. Quando é terminado, o PM2 o reinicia. Quando o servidor reinicia, o PM2 reinicia todos os processos Nodejs para você. Ele também tem um extenso processo de ciclo de vida de desenvolvimento. Não vamos cobrir este aspecto do PM2. Encorajo você a ler a documentação bem escrita.
Assumindo que você está logado no terminal, começaremos instalando o PM2 via NPM. Npm é o gerenciador de pacotes do Nodejs (npm). Foi instalado quando você instalou o Nodejs.
sudo npm install pm2 -g
É isso. O PM2 agora está instalado.
Usando o PM2
O PM2 é fácil de usar.
O hello world para PM2 é simples.
pm2 start hello.js
Isso adiciona sua aplicação à lista de processos do PM2. Esta lista é exibida cada vez que uma aplicação é iniciada.
Neste exemplo há duas aplicações Nodejs rodando. Uma chamada api.dev e api.pre.
O PM2 automaticamente atribui o nome do app ao “App name” na lista.
Por padrão, o PM2 não se configura para inicializar quando o servidor reinicia. O comando é diferente para os diferentes sabores do Linux. Estou rodando no Ubuntu, então vou executar o comando do Ubuntu.
pm2 start ubuntu
Ainda não terminamos. Temos que adicionar um caminho para o binário do PM2. Felizmente, a saída do comando anterior nos diz como fazer isso.
Saída:
[PM2] You have to run this command as root
[PM2] Execute the following command :
[PM2] sudo env PATH=$PATH:/usr/local/bin pm2 startup ubuntu -u sammy
Execute o comando que foi gerado (similar à saída destacada acima) para configurar o PM2 para iniciar na inicialização (use o comando da sua própria saída):
sudo env PATH=$PATH:/usr/local/bin pm2 startup ubuntu -u sammy
Exemplos de outros usos do PM2 (opcional)
Parando uma aplicação pelo nome do app
pm2 stop example
Reiniciando pelo nome do app
pm2 restart example
Lista de aplicações atuais gerenciadas pelo PM2
pm2 list
Especificando um nome ao iniciar um processo. Se você chamar, o PM2 usa o arquivo javascript como nome. Isso pode não funcionar para você. Aqui está como especificar o nome.
pm2 start www.js --name api.pre
Isso deve ser suficiente para você começar com o PM2. Para aprender mais sobre as capacidades do PM2, visite o Repositório GitHub.
Configurando e Usando o Plink
Você provavelmente está pensando, “O que diabos é Plink?” Pelo menos foi isso que pensei. Ainda não tenho certeza do que pensar sobre isso. Nunca vi nada parecido.
Você já assistiu o filme Wall-e? Wall-e puxa um spork. Primeiro ele tenta colocá-lo com os garfos, mas não se encaixa e então ele tenta colocá-lo com as colheres, mas não se encaixa. Bem, isso é o Plink. É um cruzamento entre Putty (SSH) e a Linha de Comando do Windows.
Plink basicamente permite que você execute comandos bash via linha de comando do Windows enquanto está logado em um shell Linux (e provavelmente Unix).
Comece baixando o Plink. É apenas um executável. Recomendo colocá-lo em C:/Program Files (x86)/Plink
. Precisaremos referenciá-lo mais tarde.
Se você está executando uma instância Ubuntu na AWS. Você já terá um certificado configurado para Putty (estou assumindo que você está usando Putty).
Se não estiver, você precisará garantir que tem um certificado ssh compatível para Ubuntu na AWS.
Se você não está usando AWS, pode especificar o nome de usuário e senha na linha de comando e não precisará se preocupar com os certificados ssh.
Aqui está um exemplo de linha de comando que conecta ao Ubuntu com Plink.
"C:\Program Files (x86)\Plink\plink.exe" -ssh ubuntu@xx.xx.xx.xx -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk"
Isso pode estar se adiantando, mas para executar um script ssh no servidor Ubuntu adicionamos o caminho completo ao final do comando Plink.
"C:\Program Files (x86)\Plink\plink.exe" -ssh ubuntu@xx.xx.xx.xx -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk" /var/www/deploy-dev-ui.sh
E isso, caro leitor, é o Plink.
Entendendo NODE_ENV
NODE_ENV
é uma variável de ambiente popularizada pelo expressjs. Antes de iniciar a instância do node, defina o NODE_ENV
para o ambiente. No código você pode carregar arquivos específicos baseados no ambiente.
Definindo NODE_ENV
Linux & Mac: export NODE_ENV=PROD
Windows: set NODE_ENV=PROD
A variável de ambiente é recuperada dentro de uma instância Nodejs usando process.env.NODE_ENV
.
exemplo
var environment = process.env.NODE_ENV
ou com expressjs
app.get('env')
*Nota: app.get('env')
tem como padrão “development”.
Juntando tudo
Nodejs
, PM2
, Nginx
e Plink
estão instalados e esperançosamente funcionando. Agora precisamos juntar todas essas peças em uma solução de integração contínua.
Clone seu repositório GitHub em /var/www/seudominio.com
. Embora SSH seja mais seguro que HTTPS, recomendo usar HTTPS. Sei que isso não é ideal, mas não consegui fazer o Plink funcionar com GitHub no Ubuntu. Sem entrar em muito detalhe, os formatos de certificado SSH do Plink e GitHub são diferentes e chamar o GitHub via Plink através de SSH não funcionou. Se você conseguir descobrir o problema, me avise!
Para tornar o pull do GitHub sem intervenção manual, o nome de usuário e senha precisarão fazer parte da url de origem.
Aqui está como você define sua url de origem. Claro que você precisará substituir suas informações onde apropriado.
git remote set-url origin https://username:password@github.com/username/seudominio.git
Clone seu repositório.
cd /var/www/seudominio.com
git clone https://username:password@github.com/username/seudominio.git .
Note que se este diretório não estiver completamente vazio, incluindo arquivos ocultos, o Git não clonará o repo para este diretório.
Para encontrar arquivos ocultos no diretório execute este comando
ls -a
Para a cola, estamos usando um script shell. Aqui está uma cópia do meu script.
#!/bin/bash
echo "> Apps PM2 Atuais"
pm2 list
echo "> Parando API em execução"
pm2 stop api.dev
echo "> Definir variável de ambiente."
export NODE_ENV=DEV
echo "> Mudando diretório para dev.momentz.com."
cd /var/www/seudominio.com
echo "> Listando o conteúdo do diretório."
ls -a
echo "> Remover diretórios não rastreados além de arquivos não rastreados."
git clean -f -d
echo "> Puxar atualizações do Github."
git pull
echo "> Instalar atualizações npm."
sudo npm install
echo "> Transpilar o código ECMAScript 2015"
gulp babel
echo "> Reiniciar a API"
pm2 start transpiled/www.js --name api.dev
echo "> Listar diretórios de pasta"
ls -a
echo "> Tudo pronto."
Eu lanço este script shell com TeamCity, mas você pode lançar com qualquer coisa.
Aqui está o comando bruto.
"C:\Program Files (x86)\Plink\plink.exe" -ssh ubuntu@xx.xx.xx.xx -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk" /var/www/deploy-seudominio.sh
exit
>&2
É isso.
Concluindo
Este processo tem algumas arestas ásperas… Espero polir essas arestas com o tempo. Se você tiver sugestões, por favor deixe-as nos comentários.
Este documento está no meu Repositório GitHub. As tecnologias mudam, então se você encontrar um erro, por favor atualize-o. Eu então atualizarei este post.
Autor: Chuck Conway é especialista em engenharia de software e IA Generativa. Conecte-se com ele nas redes sociais: X (@chuckconway) ou visite-o no YouTube.