Como criar uma docker image para sua API feita com Java?

antiduhring

Mateus Vinícius

Posted on February 21, 2023

Como criar uma docker image para sua API feita com Java?

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!

💖 💪 🙅 🚩
antiduhring
Mateus Vinícius

Posted on February 21, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related