Conteinerizando suas aplicações NodeJS com Docker

O Docker é uma ferramenta que a cada dia ganha mais espaço no mercado, nesse artigo ensinarei como conteinerizar suas aplicações node com docker, ganhando com isso flexibilidade e produtividade na hora do desenvolvimento e deploy.

Caso você não saiba nada de docker, aconselho fortemente a ler esse artigo onde dou uma introdução e explico os comandos mais comuns.

Criando a aplicação

Para exemplificarmos, criaremos uma aplicação com express que será executada dentro do conteiner.

Crie um diretório chamado node-app:

$ mkdir node-app

E nele crie um arquivo chamado package.json com o conteúdo abaixo:

{
"name": "node-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "nodemon app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.14.0",
"mongoose": "^4.5.10",
"nodemon": "^1.10.2"
}
}

Em seguida no mesmo diretório, crie um arquivo chamado app.js com o conteúdo abaixo:

var express = require('express');
var app = express();
app.get('/', function(req, res){
res.send("Hello World");
});
app.listen(3000, function(){
console.log('Example app listening on port 3000!');
});

Essa aplicação nos retorna a mensagem ‘Hello World’ quando acessamos o http://localhost:3000 algo relativamente simples, mas útil para o que queremos exemplificar.

Com tudo pronto, é hora de preparar o Dockerfile e fazer as demais configurações.

Preparando o Dockerfile

Para rodar uma aplicação node com docker, precisamos primeiro criar uma imagem que nos servirá de base para geração do nosso conteiner. As imagens do docker são construidas apartir de um Dockerfile, que é um arquivo onde é especificado tudo que a imagem terá, para isso precisamos criar um arquivo chamado Dockerfile e nele colocarmos o conteúdo abaixo:

FROM node:argon
RUN mkdir /app
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
EXPOSE 3000
CMD ["npm", "start"]

O conteúdo acima especifica tudo que nossa imagem terá, nele herdamos da imagem node oficial, criamos um diretório de trabalho, instalamos as dependências do node via npm e expomos a porta 3000 que precisaremos mais a frente. Caso você não tenha entendido muito bem a estruturação do Dockerfile, leia a documentação e se intere das possibilidades.

Com o Dockerfile pronto, precisamos fazer o build da imagem, para isso execute:

$ docker build -t node-app:0.1 .

Com o build finalizado, temos a nossa disposição uma imagem com o nome ‘node-app’, para comprovar execute o comando abaixo e você terá como retorno as informações da imagem:

$ docker images | grep node-app

Com tudo pronto, é hora de rodarmos nosso conteiner e executarmos nossa aplicação, para isso execute o comando abaixo:

$ docker run -ti -p 3000:3000 node-app:0.1

O comando acima executa um conteiner apartir da nossa imagem e linka a porta 3000 do nosso conteiner com a 3000 do nosso host, temos nossa aplicação executando, para comprovar execute:

$ curl -i http://localhost:3000

Caso queira visualizar no browser acesse: http://localhost:3000

Simples não? E se precisarmos utilizar MongoDB, Redis, Nginx ou qualquer outro serviço? Simples, dividiremos em conteineres diferentes esses demais serviços criando com isso uma arquitetura modularizada e organizada.

Dividindo sua arquitetura em conteineres com o docker-compose

O docker-compose é uma ferramenta criada pela comunidade e tem como finalidade facilitar o gerenciamento de multiplos conteineres, através dele conseguimos de forma simples fazer o build, montar volumes, linkar conteineres diferentes, etc.

O compose utiliza um arquivo chamado docker-compose.yml para armazenar suas configurações. Para isso crie um arquivo chamado docker-compose.yml com o conteúdo abaixo:

version: "2"
services:
web:
build: .
volumes:
- ./:/app
ports: [
"3000:3000"
]

Nesse arquivo criamos um serviço chamado web que terá como imagem o Dockerfile que criamos, o conteiner terá um volume entre o diretório atual do arquivo e o diretório ‘/app’ do nosso conteiner, além de um link entre a porta 3000 do nosso conteiner e a 3000 do nosso host.

Com tudo pronto, precisamos refazer o build da nossa imagem, para isso execute o comando abaixo:

$ docker-compose build

Com o build finalizado, precisamos instalar as dependências listadas no nosso package.json, para isso execute o comando abaixo:

$ docker-compose run web npm install

Com tudo instalado, precisamos executar a nossa aplicação, para isso execute o comando abaixo:

$ docker-compose up

Caso queira executar em background, execute:

$ docker-compose up -d

O comando acima executa um conteiner apartir da nossa imagem e linka a porta 3000 do nosso conteiner com a 3000 do nosso host, temos nossa aplicação executando, para comprovar execute:

$ curl -i http://localhost:3000

Caso queira visualizar no browser acesse: http://localhost:3000

Simples né?

E se quisessemos linkar um novo conteiner rodando MongoDB ao nosso conteiner atual?

Precisamos criar um novo serviço, nele criaremos toda a configuração do nosso banco e por fim um link entre os dois serviços, adicione o conteúdo abaixo em negrito no seu docker-compose.yml:

version: "2"
services:
mongodb:
image: bitnami/mongodb:latest
ports: [
"27017:27017"
]
volumes:
- /data/db:/data/db
environment:
- MONGODB_USER=usuario
- MONGODB_PASSWORD=senha
- MONGODB_DATABASE=banco
- MONGODB_ROOT_PASSWORD=senha_do_root

web:
build: .
volumes:
- ./:/app
ports: [
"3000:3000"
]
depends_on:
- mongodb

Dessa vez criamos mais um serviço chamado ‘mongodb’, que terá como imagem o mongo, fizemos o link entre a porta 27017 do nosso conteiner e a porta 27017 do nosso bloco web, criamos um volume entre nosso conteiner e o nosso host (Isso persistirá os nossos dados mesmo o conteiner sendo apagado), definimos usuário, senha, banco e senha de superusuário a ser usado, e por fim fizemos o link entre nossos serviço web e mongodb.

Agora precisamos refazer o build, para isso execute o comando abaixo:

$ docker-compose build

Com o build finalizado, basta rodar o comando abaixo e teremos nossa infraestrutura modularizada em conteineres diferentes e pronta para funcionar:

$ docker-compose up

O próprio composer se encarrega de fazer todo o build, baixar as imagem do mongo e configurar todo o ambiente.

E se precisassemos instalar uma nova dependência na aplicação? Simples.

$ docker-compose run web npm install express-load --save

O pacote seria instalado, e salvo no nosso package.json

Concluindo …

Como visto no artigo, docker facilita e muito nossa vida quando precisamos montar ambientes. Empresas como Google e Microsoft estão investindo pesado nessa nova tecnologia, que vem possibilitando workflows mais complexos com menor custo.

Like what you read? Give Hudson Brendon a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.