Acker

Ambiente de desenvolvimento com NodeJS, docker, docker-compose e ansible

Como criar um ambiente de desenvolvimento NodeJS seguro utilizando docker, docker-compose e ansible

Antes de tudo, queria deixar claro que este artigo tem como objetivo mais o estudo, nada aqui pode ser 100% verdade, tudo pode ser mudado e eu gostaria muito de saber sua opinião sobre. E lembrando antes de mais nada que não sou desenvolvedor NodeJS e que já estudei a um tempo, mas que foi um desafio para mim desenvolver tudo isso.

Bom está publicação foi criada para o hackathon da Dockercon, que tem por objetivo informar com base em estudos e análises feitas para a provocação que tem o desafio de dockerizar um ambiente NodeJS utilizando docker-compose e outras ferramentas que irei citar mais pra frente. Para saber mais sobre docker vou deixar este link: https://www.redhat.com/pt-br/topics/containers/what-is-docker

Bom, partindo do princípio que já temos nossa aplicação web em NodeJS partimos para a parte prática de como colocar tudo isso no docker e quais são os benefícios disso.

O primeiro passo antes de tudo é instalar o docker é o docker compose, no meu caso estou utilizando o linux na distribuição Ubuntu que é baseada em Debian, todos os conceitos aqui vão ser passados em linux, mas com alguns cliques e uma pesquisa rápida no Google você acha o que será tratado neste artigo.

Instalando o docker 🐋:

Primeiro, atualize sua lista existente de pacotes:

sudo apt update

Em seguida, instale alguns pacotes pré-requisito que deixam o apt usar pacotes pelo HTTPS:

sudo apt install apt-transport-https ca-certificates curl software-properties-common

Então, adicione a chave GPG para o repositório oficial do Docker no seu sistema:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Adicione o repositório do Docker às fontes do APT:

sudo add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable”

Em seguida, atualize o banco de dados do pacote com os pacotes do Docker do recém adicionado repositório:

sudo apt update

Certifique-se de que você está prestes a instalar do repositório do Docker ao invés do repositório padrão do Ubuntu:

apt-cache policy docker-ce

Você verá um resultado assim, embora o número da versão para o Docker possa ser diferente:

  Installed: (none)
  Candidate: 5:19.03.9~3-0~ubuntu-focal
  Version table:
     5:19.03.9~3-0~ubuntu-focal 500
        500 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages

Observe que o docker-ce não está instalado, mas o candidato para a instalação é do repositório do Docker para o Ubuntu 20.04 (focal).

Finalmente, instale o Docker:

sudo apt install docker-ce

O Docker deve agora ser instalado, o daemon iniciado e o processo habilitado a iniciar no boot. Verifique se ele está funcionando:

sudo systemctl status docker

O resultado deve ser similar ao mostrado a seguir, mostrando que o serviço está ativo e funcionando:

Output:

     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2020-05-19 17:00:41 UTC; 17s ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 24321 (dockerd)
      Tasks: 8
     Memory: 46.4M
     CGroup: /system.slice/docker.service
             └─24321 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Instalando o docker-compose 🐳:

Embora possamos instalar o Docker Compose a partir dos repositórios oficiais do Ubuntu, ele está várias versões menores atrás do último lançamento, então vamos instalar o Docker Compose do repositório do GitHub do Docker. O comando abaixo é ligeiramente diferente daquele que você encontrará na página dos Lançamentos. Use a flag -o para especificar o arquivo de saída primeiro ao invés de redirecionar a saída, essa sintaxe evita executar um erro de autorização negada causada ao usar o sudo.

Vamos verificar o lançamento atual e, se necessário, atualizá lo no comando abaixo:

sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

Em seguida, vamos definir as permissões:

sudo chmod +x /usr/local/bin/docker-compose

Então, vamos verificar se a instalação foi bem sucedida verificando a versão:

docker-compose — version

Isso aparecerá na tela a versão que instalamos:

Output:

docker-compose version 1.21.2, build a133471

Com todo nosso ambiente inicial pronto, borá por a mão na massa e colocar esse NodeJS na nossa amiga baleia.

Foi nos dado como ambiente duas aplicações, uma API e um serviço WEB, os dois precisam se falar e a API precisa se comunicar com um banco de dados PostgreSQL. Os dois ambientes estão em pastas separadas como na imagem abaixo.

Criaremos um Dockerfile para cada aplicação e para se obter mais segurança nestas imagens, vamos utilizar as imagens do NodeJS que são avaliadas e desenvolvidas pela própria Docker. Para mais detalhes entre neste link: https://hub.docker.com/_/ Dockerfile API

Explicando cada linha do Dockerfile:

Faz uma busca no docker hub e procura pelo node na versão 14

FROM node:14

Copia todos os arquivos que tem o nome de package*.json para o container

COPY package*.json ./

Quando startar o docker ele vai rodar o RUN para instalar as dependencias da aplicação

RUN npm install

Copia todos os arquivos para dentro do container

COPY . ./

Roda um comando no terminal bash do linux para startar a aplicação ou seja rodar os serviços

CMD npm run start

Com isso temos nossas imagens do Docker para a gente fazer o build e rodar na nossa máquina, já da para se fazer muitas coisas só com o Dockerfile, o seu ambiente de testes vai ficar redondo e nunca mais vai precisar ficar subindo aplicações no seu host local.

Para se fazer o build dessa aplicação basta apenas rodar os seguintes comando:

docker build -f api/Dockerfile -t api-node ./api docker build -f web/Dockerfile -t web-node ./web

E para rodar tudo isso:

docker run -p 8877:8877-d api-node docker run -p 8080:8080 -d web-node

Nice, já temos nossas primeiras imagens docker rodando dentro da nossa máquina!!!

Next Level com docker-compose

O próximo nível que iremos tratar de docker-compose, que tem como princípal finalizade gerar essas duas aplicações em um único arquivo, além do mais precisamos agora de um banco de dados e vamos subir ele no docker-compose a seguir:

docker-compose

Assim é como ficou nosso docker-compose.yaml

Agora temos um banco de dados rodando na nossa aplicação que se comunica diretamente com nossa API assim armazenando os dados necessários e até podendo consumir esse banco.

Alguns arquivos .env estão sendo passados em nossa aplicação, estes arquivos fornecem ao container dados necessários para os serviços como um todo poder se comunicar, são argumentos do tipo porta de acesso de tal aplicação, password, user e hostname, sem essas configurações os serviços não funcionariam, mais para frente explicarei por que utilizei arquivo .env ao invés de passar a chave direto.

Contudo para rodar a nossa aplicação agora com o docker-compose basta issfoi criada para o hackathon da Dockercono no meu terminal:

docker-compose up

Para acessa bastar entrar em localhost:8080

minha-pag

Essa é minha página web

Ta, mais como eu obtenho mais segurança utilizando minhas imagens docker?

Este assunto é de extrema importância apesar de ser muito complexo por envolver a parte de desenvolvimento multidisciplinar. Mas acaba por ser um dos pilares que vão sustentar uma aplicação de pessoas mal intencionadas a fim de acabar com todo um legado de um profissional ou empresa.

Trazendo um pouco para o contexto da aplicação e depois trago um panorama geral para não ficar tão chato. Na aplicação em si foi criado alguns layers de segurança que podem ser utilizados por qualquer pessoa, coisas simples mas eficazes.

Os argumentos de configuração tanto de banco de dados e da aplicação ficam guardados apenas no host atrávez do uso de arquivos .env

env

Exemplo de uma configuração de um arquivo .env

2. Utilizando o .dockerignore posso ter controle do que a minha imagem vai ignorar mesmo após eu copiar tudo para dentro dela.

dockerignore

Exemplo do arquivo .dockerignore

Utilizando o .dockerignore eu consigo ignorar por exemplo meu próprio Dockerfile ou seja o código e o que implementei para criar a imagem, além de eu poder também ignorar todos meus arquivos .env para que ninguém que tenha acesso roube os dados.

3. Não utilizar root para rodar imagens docker.

A ideia por traz disso é você configurar o docker para rodar sem sudo, pois você tem um controle maior de permissões para usuários dentro do seu Cluster.

4. Utilizar o .gitignore para ignorar os arquivos .env se seu repositório for público.

gitignore

Exemplo de um arquivo .gitignore

O arquivo .gitignore funciona como o .dockerignore só que para o git :)

5. Obter imagens de repositórios do docker hub confiáveis.

O repositórios que utilizei por exemplo é da própria Docker e é atualizado por um time da Docker especializado em NodeJS.

dockerhub

Imagem retirada do docker hub

Automatizando o container

Os próximos passos seriam automatizar o container utilizando ansible devido ao tempo não foi implementado a ideia, mas vou deixar um link de referência: https://www.digitalocean.com/community/tutorials/how-to-use-ansible-to-install-and-set-up-docker-on-ubuntu-18-04-pt

Link do repositório com o desafio: https://github.com/AlestanAlves/devops_challenge

Enjoy the dark side! 🖤