Colocando sua App em um container Docker

Sabe aquele código de aplicação parado no seu repo git?

Você não dá nada para aquela aplicação web ou projeto de estudo (e nós também — rs’), mas já pensou em disponibilizá-la como uma imagem de container Docker?

Pois bem, vamos lá…

Neste exemplo, vamos usar uma aplicação em Nodejs. Mas os conceitos poderão ser aplicados em outros casos.

Repositório com a aplicação:

GitHub – danilomarquesn/hello-nodejs

Passo 1: O Clone

#easteregg

Vamos clonar a aplicação para o nosso diretório de trabalho:

$ git clone git@github.com:danilomarquesn/hello-nodejs.git




Passo 2: Dockerfile

Vamos construir o arquivo de Dockerfile (receita da nossa imagem), mas antes precisamos entender o que é o Dockerfile e como a aplicação funciona, assim como, suas dependências.

Dockerfile: De uma maneira bem simples, pode ser usado para automatizar a criação das suas imagens.

Sabemos que a app foi constuída em Nodejs, logo teremos que garantir que a imagem base atenda a este requisito. No dockerhub, vamos localizar a imagem oficial do Node, para o nosso projeto.

node
Node.js is a JavaScript-based platform for server-side and networking applications.hub.docker.com

Nota: Nós poderíamos utilizar uma imagem linux “pura” e instalar todas a dependências do projeto e depois disponibilizar? SIM. Mas o finalidade aqui não é reinventar a roda ou redescobrir o fogo. Essa abordagem, fará muito mais sentido em contextos onde você precisa ter total controle e saber exatamente tudo o que a imagem contém (no contexto de segurança, por exemplo). Em nosso exemplo, a imagem oficial do Node atende aos requisitos.

Agora que já sabemos a imagem base que iremos utilizar, vamos nos certificar que estamos usando a mesma tag/versão da máquina local em que a app foi desenvolvida.

$ node --version

Retornará algo como: v16.15.1 (a sua versão provavelmente estará diferente)

Após clonar o projeto, vamos acessar a pasta src, para criarmos os arquivos necessários.

$ cd src/

Dockerfile

# indicamos a imagem base + versao, para garantir a idempotencia
FROM node:16.15.1

# diretorio de trabalho, onde estará nossa app dentro do container
WORKDIR /app

# copiamos apenas os arquivos de dependencias do src para o WORKDIR
COPY package*.json ./

# instalamos as dependencias restantes para a app rodar com sucesso
RUN npm install

# copiamos todo o conteúdo do src para o WORKDIR
COPY . .

# expomos nossa app para a porta 3000 do container
EXPOSE 3000

# comando para executar a app (start)
CMD ["node", "server.js"]

Passo 3: Build

# docker build seu_namespace_dockerhub/nome-da-app:versao (v1..v2..latest)

$ docker build -t danilomarques/hello-nodejs:v1

Pulo do gato…

Repare que copiamos apenas os arquivos de dependência da app (package-lock.json e package.json). Após a instalação, copiamos os arquivos restantes, por quê?

Porque queremos aproveitar o conceito de camadas do Docker.

Vamos testar?

Altere o seu Dockerfile para o seguinte modelo:

FROM node:16.15.1
WORKDIR /app
# COPY package*.json ./
COPY . .
RUN npm install
EXPOSE 3000
CMD ["node", "server.js"]

Agora adicione a seguinte linha em qualquer arquivo da sua app. Neste exemplo, vamos alterar o server.js:

// Hello world

Execute novamente o build do Docker:

$ docker build -t seu_namespace_dockerhub/hello-nodejs:v1

Repare que pelo simples fato de ter adicionado um comentário no código da aplicação, o docker build entende que houve alteração nos arquivos copiados, então precisa instalar novamente todas as dependências na imagem do container (atualizar a camada correspondente).

No modelo anterior, o docker só irá refazer a camada de dependências quando houver alteração nos arquivos de dependências (package-lock.json e package.json).

Coisa que só irá “pegar” na utilização do dia a dia… E acredite, cada segundo conta, principalmente em projetos maiores.

#PorqueNaPráticaATeoriaÉDiferente

Passo 4: .dockerignore

Se você já executou a sua app, provavelmente encontrará vários arquivos e diretórios temporários necessários para aquela execução local. Mas esses arquivos e diretórios precisam estar na imagem? Muito provavelmente não. Só deixarão a imagem maior, mais pesada…

Semelhante o .gitignore, vamos criar o .dockerignore para informar tudo o que não precisamos na imagem.

$ vi .dockerignore

Como estamos trabalhando com Nodejs no exemplo, só teremos os conteúdo abaixo para adicionar ao arquivo:

node_modules

Nosso diretório atual ficou assim:

Vamos “buildar” e subir nossa app…

$ docker build -t seu_namespace_dockerhub/hello-nodejs:v1
$ docker run -d -p 3000:3000 seu_namespace_dockerhub/hello-nodejs:v1

Nesta etapa, sua aplicação já deve estar pronta para receber solicitações na porta disponibilizada.

Passo 5: Push

Se você já possui uma conta no Docker Hub e criou a imagem com o seu namespace corretamente, basta dar um “docker push” (assumindo que o seu docker login também esteja correto 😑) para enviar par o hub.

$ docker push seu_namespace_dockerhub/hello-nodejs:v1


Comentários

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *