Mateus Vinícius
Posted on February 21, 2023
Introdução
Uma Docker Image é um pacote executável que contém todas as ferramentas e softwares necessários para executar uma aplicação, incluindo, além do próprio código-fonte, bibliotecas, dependências, configurações e variáveis de ambiente. Ao executar uma Docker Image o resultado é a criação de um container , que é o ambiente isolado onde o conteúdo da imagem irá rodar.
O container é como se fosse uma miniatura do sistema operacional, que isola a aplicação do ambiente em que está sendo executada. Esse isolamento permite que ela funcione de forma independente do sistema operacional ou hardware da máquina utilizada.
As Docker Images permitem que nós possamos criar ambientes de desenvolvimento e produção consistentes, sem conflitos ou problemas de compatibilidade. É o fim definitivo para o problema "Mas na minha máquina funciona!".
Além disso, as imagens podem ser compartilhadas no Docker Hub, e reutilizadas por outras equipes de desenvolvimento, tornando o processo de desenvolvimento mais eficiente e escalável.
O objetivo deste tutorial será a criação de uma imagem especificamente para uma API Java com Spring Boot. Será usado Maven para gerenciamento e build, na sua versão 3.8.7.
Instalando o Docker
Primeiro é necessário instalar o Docker no seu computador. A própria documentação da ferramenta já traz tutoriais simplificados, com passo-à-passo específico para cada sistema operacional, basta escolher uma opção e seguir os comandos.
Criando o Dockerfile
O Dockerfile é o arquivo que conterá as instruções para a construção da Docker Image, como uma receita de cozinha que descreve todos os ingredientes e passos necessários para criar uma refeição. No caso do Dockerfile, as instruções descrevem o que deve ser incluído na imagem Docker, como o sistema operacional, as bibliotecas e as dependências, e como configurar o ambiente para a aplicação.
O primeiro passo é criar um arquivo de nome Dockerfile, sem extensão, dentro da pasta raiz da aplicação.
- app
- .idea/
- .mvn/
- src/
- target/
- .gitignore
- Dockerfile
- HELP.md
- mvnw
- mvnw.cmd
- pom.xml
O arquivo irá apontar para uma Docker Image que será usada como base para a criação da nossa própria imagem e também conterá todos os comandos necessários para a build da aplicação e sua execução.
Escolhendo a imagem base
Por termos escolhido o Maven 3.8.7 como compilador e gerenciamento e o JDK 19 para a execução da aplicação Java, deveremos usar como base a Docker Image maven:3.8.7-eclipse-temurin-19-alpine, que já contém ambas as ferramentas e suas dependências instaladas sob um sistema operacional linux.
A escolha da imagem base vai variar conforme as necessidades, sendo possível utilizar desde uma imagem base de um Ubuntu novo, e dentro do próprio Dockerfile configurar comandos para que o Maven e a JDK sejam instalados, quanto utilizar uma imagem já com ferramentas pré-instaladas, como é o caso da maven:3.8.7-eclipse-temurin-19-alpine.
Adicionando a imagem base ao arquivo Dockerfile
Agora iremos adicionar conteúdo ao arquivo Dockerfile, e o primeiro passo será apontar para a imagem base, e isso é feito com o comando FROM image-name
.
# Start with maven:3.8.7-eclipse-temurin-19-alpine base image
FROM maven:3.8.7-eclipse-temurin-19-alpine
# Maintaner data
LABEL maintainer="Mateus Vinícius <mateus.limavn@gmail.com>"
# End
O comando LABEL
é usado para adicionar informações e metadados à imagem que está sendo criada, como o nome do mantenedor, a versão da imagem, a descrição da aplicação e etc. Essa prática ajuda na organização e identificação das imagens, já que o comando docker images
exibe essas informações registradas no LABEL
juntamente com as informações da própria imagem.
Adicionando comandos para a build da aplicação
Após apontarmos a imagem que será usada como base, é hora de configurar os comandos que serão executados para fazer a build da nossa aplicação Java. O build será feito com o comando mvn package
.
# Start with maven:3.8.7-eclipse-temurin-19-alpine base image
FROM maven:3.8.7-eclipse-temurin-19-alpine
LABEL maintainer="Mateus Vinícius <mateus.limavn@gmail.com>"
# Set the working directory to /app
WORKDIR /app
# Copy the source code to the container
COPY . .
# Build the application with Maven
RUN mvn package
#End
O comando WORKDIR
define o diretório de trabalho padrão para as próximas instruções do arquivo. Isso permite que os comandos que serão executados saibam qual é o caminho do diretório da aplicação sem que seja necessário repetir o caminho absoluto a todo momento. O padrão é usar o diretório /app
.
Já o comando COPY <fonte> <destino>
copia o conteúdo da imagem para o container que será criado, que é o ambiente de execução da aplicação. Nesse caso todo o conteúdo da imagem será copiado para o container.
Para fazer a build da aplicação Java utilizaremos o comando mvn package
do Maven, por isso ele é chamado com o RUN
, que serve para executar outros comandos ou instruções.
Definindo as variáveis de ambiente
A maioria dos projetos utilizam variáveis de ambiente, elas são usadas tanto pelas aplicações quanto pelo próprio sistema operacional para acessar as configurações definidas.
No caso da aplicação Java que é usada de exemplo, as variáveis de ambiente estão sendo chamadas dentro do arquivo application-prod.properties da seguinte forma:
spring.datasource.url=${DATASOURCE_URL}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.datasource.username=${DATASOURCE_USERNAME}
spring.datasource.password=${DATASOURCE_PASSWORD}
No caso, os valores ${DATASOURCE_URL}
, ${DATASOURCE_USERNAME}
e ${DATASOURCE_PASSWORD}
são as variáveis de ambiente. Elas estão definindo a url de conexão com o banco de dados, o usuário root
desse banco e a sua senha.
Pra facilitar o reaproveitamento da imagem o ideal é que essas propriedades de configuração da aplicação que sejam dinâmicas passem a ser atribuídas à variáveis de ambiente, assim o desenvolvedor poderá modificá-las antes de executar o container.
Mas é importante, também, atribuir valores padrão à essas variáveis, e é pra isso que serve o comando ENV
.
# Start with maven:3.8.7-eclipse-temurin-19-alpine base image
FROM maven:3.8.7-eclipse-temurin-19-alpine
LABEL maintainer="Mateus Vinícius <mateus.limavn@gmail.com>"
# Set the working directory to /app
WORKDIR /app
# Copy the source code to the container
COPY . .
# Build the application with Maven
RUN mvn package
# Set environment variables if needed
ENV DATASOURCE_URL=jdbc:postgresql://localhost:5432/db
ENV DATASOURCE_USERNAME=postgres
ENV DATASOURCE_PASSWORD=postgrespassword
#End
Informando as portas que o container estará executando
As portas que serão expostas para que a API receba requisições são definidas com o comando EXPOSE
, e, nesse caso, utilizaremos a padrão 8080.
# Start with maven:3.8.7-eclipse-temurin-19-alpine base image
FROM maven:3.8.7-eclipse-temurin-19-alpine
LABEL maintainer="Mateus Vinícius <mateus.limavn@gmail.com>"
# Set the working directory to /app
WORKDIR /app
# Copy the source code to the container
COPY . .
# Build the application with Maven
RUN mvn package
# Set environment variables if needed
ENV DATASOURCE_URL=jdbc:postgresql://localhost:5432/db
ENV DATASOURCE_USERNAME=postgres
ENV DATASOURCE_PASSWORD=postgrespassword
# Expose default Spring Boot port
EXPOSE 8080
#End
Definindo o comando para execução do arquivo jar
Agora que o container já fez a build da aplicação, configurou as variáveis de ambiente e expôs as portas para requisições, chegou o momento de definir o comando para executar o arquivo jar
que é gerado pela build do Maven.
Para isso iremos utilizar o comando CMD
, que recebe uma array de argumentos que será executado em uma linha do terminal.
O comando para executar uma aplicação java, que está compilada num arquivo jar
, e utilizando o profile de produção é java -jar target/myapp-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
, portanto, o comando CMD
correspondente será CMD ["java", "-jar", "target/myapp-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=prod"]
.
Ao final nosso arquivo Dockerfile ficará com o seguinte conteúdo:
# Start with maven:3.8.7-eclipse-temurin-19-alpine base image
FROM maven:3.8.7-eclipse-temurin-19-alpine
LABEL maintainer="Mateus Vinícius <mateus.limavn@gmail.com>"
# Set the working directory to /app
WORKDIR /app
# Copy the source code to the container
COPY . .
# Build the application with Maven
RUN mvn package
# Set environment variables if needed
ENV DATASOURCE_URL=jdbc:postgresql://localhost:5432/db
ENV DATASOURCE_USERNAME=postgres
ENV DATASOURCE_PASSWORD=postgrespassword
# Expose default Spring Boot port
EXPOSE 8080
# Run the jar file
CMD ["java", "-jar", "target/myapp-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=prod"]
#End
Criando a Docker Image
Já com o Docker instalado e o arquivo Dockerfile configurado, podemos realizar a build da imagem. Para isso, basta abrir no terminal ou prompt de comando a pasta da aplicação - a mesma em que o arquivo Dockerfile se encontra - e executar o comando docker image build -t myapp-api .
O Docker irá executar todos os comandos presentes no arquivo Dockerfile, o que inclui a build da aplicação usando o mvn build
, e, ao fim, irá gerar a imagem automaticamente.
Para ver e executar a imagem gerada, basta rodar o comando docker images
no terminal ou prompt de comando.
Conclusão
Com a imagem gerada rodar a aplicação se torna muito mais fácil, já que basta rodar o comando docker run <nome-da-imagem>
para que o container de execução seja criado.
Agora você pode salvar essa imagem num repositório no Docker Hub para executar em qualquer servidor ou máquina pessoal, sem se preocupar com a configuração do ambiente ou problemas de incompatibilidade. Sua aplicação pode rodar em qualquer lugar!
Posted on February 21, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.