Colocando sua App em um container Docker

Autor(a):

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

Deixe um comentário

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