DEV Community

Cover image for Primeiros passos no Docker
Clinton Rocha
Clinton Rocha

Posted on

Primeiros passos no Docker

Desenvolvendo de forma simples e direta, é hoje que você vai começar a usar o Docker. Nada de termos complicados, apenas uma abordagem fácil para que você possa usar containers sem stress. Você provavelmente já deve ter ouvido falar de Docker em requisitos de vagas ou em projetos de algum outro desenvolvedor e com isso tentou usá-lo e não conseguiu ou então não entendeu como usar. Nesse artigo vou te mostrar de maneira simples como é o processo de conteinerização de uma aplicação.

Table of contents

Objetivo

Meu principal objetivo é ajudar você leitor com os primeiros passos com Docker no desenvolvimento de seus projetos. Pretendo ter uma abordagem pautada no contexto da aplicação que vou usar, vamos começar explicando as ferramentas de uma forma diferente das que encontrei pela internet, em seguida vou mostrá-las mais a prática, usando uma pequena aplicação como exemplo. Esse artigo conciliado ao conteúdo teórico que vou disponibilizar por links durante e ao final vão te dar uma boa base do que é essa ferramenta e como ela funciona por baixo dos panos, ao fim de tudo eu espero que você seja capaz de dar seus primeiros passos criando container de tudo 🐳.

Requisitos

Ter instalado:

O que é

Dockerfile

É um arquivo de configuração, onde está o passo inicial para a criação de uma Docker Image. Nele contem as instruções para configurar sua aplicação no container. Veja o dockerfile como um manual que lista o passo a passo de como montar algo (sua aplicação no caso) e as instruções de como ligar esse algo na tomada.

Docker Image

A Docker Image é o aglomerado de tudo o que é necessário para sua aplicação funcionar, é onde se encontra o código-fonte, bibliotecas, dependências e mais o que for necessário para que ela funcione. Seu app em uma foto.

Container

Imagine que você queira fazer uma festa independente do local que esteja, e para isso você carrega uma caixa com balões, caixinha de som e luzes coloridas, coisas leves. Pronto sua festa pode ser feita em qualquer lugar, essa caixa é o nosso container, ele reúne tudo o que é necessário para uma aplicação funcionar. Ele resolve aquele famoso problema de "Na minha máquina funciona".

Em outras palavras, os containers são ambientes de software leves, portáteis e isolados que permitem aos desenvolvedores executar e empacotar aplicativos com suas dependências, de forma consistente em diferentes plataformas. Eles ajudam a agilizar os processos de desenvolvimento, implantação e gerenciamento de aplicativos, garantindo ao mesmo tempo que os aplicativos sejam executados de forma consistente, independentemente da infraestrutura.

Volume

Em termos simples, um volume no contexto do Docker é um mecanismo que permite que dados sejam compartilhados e persistam entre o host e os containers. Ele oferece uma maneira de armazenar e compartilhar informações de forma independente do ciclo de vida dos containers.

Por exemplo, se você tiver um container de banco de dados, pode usar um volume para armazenar os dados do banco de forma que esses dados persistam mesmo se o container for removido. Isso proporciona flexibilidade e consistência na gestão de dados em ambientes Docker.

Compose

O mascote do docker e o mascote do compose

O Docker Compose é uma ferramenta que simplifica a gestão de aplicações Docker compostas por vários containers. Ele permite definir, configurar e executar vários serviços, redes e volumes em um arquivo YAML, facilitando a criação e a execução de ambientes complexos com apenas um comando.

CLI do Docker

Existe o Docker Desktop onde você pode fazer a maioria das configurações, ele é até amigável, porem o mais indicado é você se acostumar com os comandos pelo terminal, até por que em caso de qualquer dúvida as respostas que você vai encontrar pela internet na sua grande maioria vão ser em formato de comandos, caso você queria configurar através do aplicativo desktop recomendo você olhar a documentação. Nesse tópico eu pretendo mostrar alguns comandos básicos e fala o que cada um faz.

docker --help
Enter fullscreen mode Exit fullscreen mode

Começando pelo mais simples, mas também muito importante, o --help mostra todos os comandos do Docker junto a uma pequena explicação, ele também pode ser usado em conjunto com os próximos comandos que vou mostrar no caso de você não se lembrar das opções que aquele comando tem.

Todos os comandos que vou usar são da nova versão feita para fornecer uma experiência de usuário mais estruturada ao usar a linha de comando. Que eu saiba, ainda não houve nenhum anúncio oficial para abandonar o suporte aos comandos antigos (como docker ps e outros), embora possa ser razoável supor que isso possa acontecer em algum momento no futuro.

Para gerenciar containers:

Criar e executar container:

docker container run nome-da-imagem
Enter fullscreen mode Exit fullscreen mode

Listar containers em execução:

docker container ls
Enter fullscreen mode Exit fullscreen mode

Listar todos os containers (Inclusive parados):

docker container ls -a
Enter fullscreen mode Exit fullscreen mode

Parar um container:

docker container stop nome-ou-ID-do-container
Enter fullscreen mode Exit fullscreen mode

Iniciar um container parado:

docker container start nome-ou-ID-do-container
Enter fullscreen mode Exit fullscreen mode

Remover um container (deve estar parado):

docker container rm nome-ou-ID-do-container
## com a opção '-f' ele força a parada do container e em seguida o remove
Enter fullscreen mode Exit fullscreen mode

Para Gerenciar Imagens:

Listar imagens locais:

docker image ls
Enter fullscreen mode Exit fullscreen mode

Baixar uma imagem do Docker Hub:

docker pull nome-da-imagem
Enter fullscreen mode Exit fullscreen mode

Construir uma imagem a partir de um Dockerfile:

docker build -t nome-da-imagem caminho-do-Dockerfile
Enter fullscreen mode Exit fullscreen mode

Remover uma imagem local:

docker rm nome-da-imagem
Enter fullscreen mode Exit fullscreen mode

Para Gerenciar Redes:

Listar redes Docker:

docker network ls
Enter fullscreen mode Exit fullscreen mode

Criar uma rede Docker:

docker network create nome-da-rede
Enter fullscreen mode Exit fullscreen mode

Conectar um container a uma rede:

docker network connect nome-da-rede nome-ou-ID-do-container
Enter fullscreen mode Exit fullscreen mode

Desconectar um container de uma rede:

docker network disconnect nome-da-rede nome-ou-ID-do-container
Enter fullscreen mode Exit fullscreen mode

Outros comandos úteis:

Logs de um container:

docker logs nome-ou-ID-do-container
Enter fullscreen mode Exit fullscreen mode

Informações Detalhadas de um container:

docker inspect nome-ou-ID-do-container
Enter fullscreen mode Exit fullscreen mode

Botando a mão na massa

imagem mostrando o caminho do dockerfile até o container

Nesse tópico vamos abordar as ferramentas acima citadas um pouco mais prática, e para isso vamos usar uma pequena aplicação com as tecnologias React, Vite,Express e PostgreSQL.

Link do repositório da aplicação🐳

Seu primeiro Dockerfile

No diretório ./front podemos ver o arquivo .dockerignore que funcionar parecido com o .gitignore, nele você define arquivos ou pastas que não são necessárias na imagem da sua aplicação. O arquivo Dockerfile tem a seguinte estrutura:

FROM node:18.17.0-alpine
WORKDIR /app
COPY package*.json ./
COPY . .
RUN npm install
RUN npm run build
EXPOSE 8080
CMD [ "npm", "run", "preview" ]
Enter fullscreen mode Exit fullscreen mode

FROM

Aqui é o ponto de partida da sua imagem, é onde você define a base do seu container, e para essa aplicação eu estou baixando a imagem do node na versão 18.17.0-alpine e quando você ver o alpine em alguma imagem significa que a imagem foi construída usando Alpine Linux como base. Essas imagens são populares porque são eficientes, rápidas de baixar e fornecem um ambiente leve para executar aplicativos em containers.

WORKDIR

Define o diretório de trabalho dentro do container como /app. Isso significa que os próximos comandos serão executados dentro deste diretório.

COPY

Copia o arquivo package.json (e qualquer arquivo que comece com "package") do diretório local para o diretório /app no container.

O segundo COPY copia todos os outros arquivos do diretório local para o diretório /app no container.

RUN

Executa o comando npm install dentro do container, que instala as dependências especificadas no arquivo package.json.

O segundo RUN executa o comando npm run build para construir a aplicação. Esse comando é geralmente usado para compilar e preparar a aplicação para execução.

EXPOSE

Informa que a aplicação dentro do container estará escutando na porta 8080. Isso não faz com que a porta seja automaticamente aberta, mas é uma informação útil para quem está usando a imagem para entender qual porta a aplicação espera ser exposta.

CMD

Define o comando padrão a ser executado quando um container baseado nesta imagem for iniciado. Neste caso, o comando é npm run preview, que inicia o servidor da aplicação para que ela possa ser acessada.

Essas vão ser as instruções mais básicas que vamos usar, existem algumas outras e recomendo você dá uma olhada na documentação para ter uma base melhor.

Configuração do Vite

No Vite para que nossa aplicação rode na porta 8080 é necessário configurar o arquivo vite.config.ts. Caso você queira abordar outras configurações recomendo ler a documentação do Vite .

Artigo que me ajudou a entender a configuração usada nesse projeto.

Criando a imagem do front

Pronto, com o Dockerfile preenchido corretamente podemos criar nossa primeira imagem. Se você prestou atenção no tópico CLI do Docker já deve ter uma ideia de como vamos fazer isso, vá no terminal e acesse o diretório ./front e execute o seguinte comando:

docker image build -t front .
Enter fullscreen mode Exit fullscreen mode
  • -t ou -tag é usado para dar nome e dar tag para a imagem, nesse exemplo estou dando o nome da imagem como front caso eu quisesse ter diferentes versões dessa imagem poderia ser usado o segundo argumento para uma tag como front:nome-da-tag, geralmente na tag é colocado a versão ou algo que facilite a identificação front:1.0.
  • No terminal eu estou no diretório ./front que é onde está o dockerfile é por isso que só uso o . (ponto).

Se você presta atenção no seu terminal, vai notar que o Docker esta seguindo as instruções feitas no Dockerfile.

gif monstrando os comandos que foram mostrados antes

No gif a build da imagem foi rápido porque boa parte dessa imagem no meu pc já estava em cache, no seu deve demorar mais.

Criando o container do front

Já temos a imagem do front e com ela podemos criar o tão sonhado container, novamente vá no seu terminal e execute o comando:

docker container run -d -p 8080:8080 front
Enter fullscreen mode Exit fullscreen mode
  • -d: É usado para executar um container em segundo plano, ou seja, em modo "detached". Quando você executa um container Docker, por padrão, ele é iniciado em primeiro plano.
  • -p 8080:8080: essa opção indica que estamos mapeando a porta 8080 do container para a porta 8080 do host.
  • front: é o nome da imagem o container vai usar.

Image com os comandos acima citados

Acessando o http://localhost:8080 em seu navegador já vamos conseguir acessar o front da nossa aplicação, mas ainda falta o nosso back e banco esta no ar.

Image do front no ar

Criando uma network

imagem mostrando um diagrama mostrando a conexão do entre os containers

O docker network é um recurso do Docker que permite criar redes isoladas para containers. As redes do Docker desempenham um papel fundamental ao fornecer comunicação entre containers, garantindo isolamento, segurança e flexibilidade nas interações entre os diferentes componentes de um sistema distribuído.

docker network artigo
Enter fullscreen mode Exit fullscreen mode

O nome da rede vai ser artigo😁.

Baixando a imagem do Postgres

O próximo passo é baixar a imagem do Postgres a partir do Docker Hub. Para fazer isso, execute o seguinte comando em seu terminal:

docker pull postgres
Enter fullscreen mode Exit fullscreen mode

Criando um volume para persistência de dados

Antes de executar o containers do banco e do back, é importante criar um volume para persistência de dados. Isso garantirá que os dados do Postgres não sejam perdidos quando o container for interrompido ou excluído. Para criar um volume, execute o seguinte comando em seu terminal:

docker volume create pgdata
Enter fullscreen mode Exit fullscreen mode

O nome do volume vai ser pgdata.

Executando container Postgres

Com o volume criado, agora você pode executar o container Postgres. Para fazer isso, execute o seguinte comando em seu terminal:

docker container run -d --name postgres --network=artigo -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_HOST=postgres -e POSTGRES_DATABASE=postgres -e POSTGRES_PASSWORD=password -v pgdata:/var/lib/postgresql/data postgres
Enter fullscreen mode Exit fullscreen mode
  • -d: essa opção indica que o container será executado em segundo plano.
  • --name postgres: com essa opção, você pode dar um nome ao seu container. Neste caso, estamos nomeando o container como "postgres".
  • --network: essa opção é utilizada para especificar a rede à qual um container deve ser conectado durante sua execução.
  • -p 5432:5432: essa opção indica que estamos mapeando a porta 5432 do container para a porta 5432 do host. A porta 5432 é a porta padrão do Postgres.
  • -e POSTGRES_USER=postgres: essa opção define a variável de ambiente POSTGRES_USER com o user que você escolher. Por padrão, o user do PostgreSQL é postgres.
  • -e POSTGRES_HOST=postgres: normalmente se refere ao endereço do host onde o banco de dados PostgreSQL está em execução. Se você está executando o PostgreSQL em um container Docker, o POSTGRES_HOST pode ser o nome do container ou o endereço IP do container, dependendo de como você está configurando a comunicação.
  • -e POSTGRES_DATABASE=postgres: essa opção é usada para especificar o nome do banco de dados ao qual você deseja se conectar.
  • -e POSTGRES_PASSWORD=sua-senha: essa opção define a variável de ambiente POSTGRES_PASSWORD com a senha que você escolher.
  • -v pgdata:/var/lib/postgresql/data: essa opção define o volume pgdata criado anteriormente como o local onde os dados do Postgres serão armazenados.
  • postgres: esse é o nome da imagem que estamos utilizando para criar o container.

  • -d (ou --detach)

  • -p (ou --publish)

  • -e (ou --env)

  • -v (ou --volume)

Criando a imagem do back

O Dockerfile que esta no diretório /back não muda muita coisa do que fizemos no front, apenas o EXPOSE e o CMD para fazer o start na aplicação.

FROM node:18.17.0-alpine
WORKDIR /app
COPY package*.json ./
COPY . .
RUN npm install
EXPOSE 3000
CMD ["npm", "run", "start"]
Enter fullscreen mode Exit fullscreen mode

No terminal e acesse o diretório ./back e execute o seguinte comando:

docker image build -t back .
Enter fullscreen mode Exit fullscreen mode

Criando o container do back

Sem segredo algum, vamos fazer o mesmo processo que fizemos com o container do front. Já temos a imagem do back e com ela podemos criar o tão sonhado container, novamente vá no seu terminal e execute o comando:

docker container run -d --network=artigo -p 3000:3000 back
Enter fullscreen mode Exit fullscreen mode

gif com exemplo de uso do comando do exemplo

Agora nossa aplicação está funcionando completamente, você pode acessar http://localhost:8080 e criar uma tarefa e deletar.

Docker Compose

imagem mostrando a relação do compose com containers

Podemos notar a quantidade de comandos no terminal que foi necessário para que essa pequena aplicação fosse ao ar, com o compose vamos encurtar todo esse processo colocando tudo em um só lugar, facilitando o nosso desenvolvimento. A estrutura do compose.yaml lembra um pouco o Dockerfile.

version: '3'
services:
  back:
    build: ./back/.
    ports:
      - 3000:3000
    depends_on:
      - postgres
  front:
    build: ./front/.
    ports:
      - 8080:8080
  postgres:
    image: postgres:latest
    environment:
      POSTGRES_USER: postgres
      POSTGRES_HOST: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DATABASE: postgres
    volumes:
      - api-postgres-data:/var/lib/postgresql/data
    ports:
      - 5432:5432
volumes:
  api-postgres-data:
Enter fullscreen mode Exit fullscreen mode
  • version: '3': Especifica a versão da sintaxe do Docker Compose que está sendo usada. Neste caso, é a versão 3.
  • services: Define os serviços que serão executados.
    • back: Configurações para o serviço chamado "back".
      • build: ./back/.: Especifica que a imagem para o serviço "back" deve ser construída a partir do diretório ./back/.
      • ports: - 3000:3000: Mapeia a porta 3000 do contêiner para a porta 3000 do host.
      • depends_on: - postgres: Indica que o serviço "back" depende do serviço "postgres", garantindo que o serviço "postgres" seja iniciado antes do serviço "back".
    • front: Configurações para o serviço chamado "front".
      • build: ./front/.: Especifica que a imagem para o serviço "front" deve ser construída a partir do diretório ./front/.
      • ports: - 8080:8080: Mapeia a porta 8080 do contêiner para a porta 8080 do host.
    • postgres: Configurações para o serviço chamado "postgres".
      • image: postgres:latest: Usa a imagem oficial mais recente do PostgreSQL disponível no Docker Hub.
      • environment:: Define variáveis de ambiente para configurar o PostgreSQL.
        • POSTGRES_USER, POSTGRES_HOST, POSTGRES_PASSWORD, e POSTGRES_DATABASE são configurados para criar um usuário, host, senha e banco de dados no PostgreSQL.
      • volumes: - api-postgres-data:/var/lib/postgresql/data: Mapeia um volume chamado "api-postgres-data" para o diretório onde os dados do PostgreSQL são armazenados dentro do contêiner.
      • ports: - 5432:5432: Mapeia a porta 5432 do contêiner para a porta 5432 do host. volumes::
  • Define um volume chamado "api-postgres-data". Este volume é usado para persistir os dados do PostgreSQL, permitindo que os dados persistam mesmo se o contêiner for removido.

Antes de executar o comando do Compose finalize os dois containers feitos anteriormente para que não de conflito nas portas. Após isso no seu terminal acesse o diretório raiz do projeto, onde está o compose.yaml e use o seguinte comando:

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

gif com o comando do exemplo

O processo de build demora um pouco, lembre-se que esse comando faz o build de 3 containers, no gif é nessa velocidade porque o build esta em cash.

Espero que você tenha percebido o quão maravilhoso é o Compose, a quantidade de trabalho que ele te poupa é absurdo. Apenas com um comando ele cria a imagem do front e back, cria um container a partir da imagem criada para o front, back e para o postgres e ainda cria uma network para que os container possam se comunicar entre eles. Existem muitas outras funcionalidades e opções para se fazer no compose, espero que você tenha ficado curioso com o que possa ser feito.

Conteúdo complementar

Tenha a documentação oficial como sua melhor amiga no processo de estudo, mas além dela existe o treinamento da LINUXtips, feito pelo Jeferson Fernando. Ele disponibilizou completamente de graça o:
Livro Descoplicando o Docker

Treinamento completo no Youtube:
Descomplicando Docker

Para quem é muito agoniado, tem o resumo:
Tudo o que você precisa saber sobre docker em 2h

Para quem quer se especializar um pouco mais:
Roadmap Docker (english)

Conclusão

Esse conteúdo foi o resultado de um aglomerado de anotações e abstrações que tive durante meu processo de estudo sobre docker, a parte que mais bati cabeça foi com o network, durante os meus testes eu ficava tentando fazer os container se comunicarem entre eles, mas um não encontrava o outro, foi uma grande dor de cabeça, mas no fim deu tudo certo. Algumas explicações acabei sendo bem raso, mas foi no intuito de tentar facilitar seu entendimento sobre alguns tópicos.

Caso eu tenha feito alguma explicação errada, ficarei agradecido com seu feedback, você pode me encontrar no Twitter ou no Discord da He4rt.

Obrigado por ler ate aqui.

Top comments (5)

Collapse
 
cherryramatis profile image
Cherry Ramatis

Artigo muito foda e suuuuuuuper detalhado, ja salvei como livro de bolso pra sempre que eu travar com docker kkkkk ❤️

Adoraria ver um conteúdo futuro sobre networks no docker, seria mto incrivel na sua didática

Collapse
 
leandronsp profile image
Leandro Proença

artigo sensacional hein, completíssimo

Collapse
 
camilacodes profile image
Camila Figueira

muito massa e completo

Collapse
 
phenriquesousa profile image
Pedro Henrique

Thanks for sharing

Collapse
 
nikolai1312 profile image
Nicolas Evangelista

Texto massa, mandou bem, cara! Explicou várias coisas de uma forma muito didática e foi direto ao ponto.