Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Os contêineres fornecem um ambiente consistente e portátil para seus aplicativos Java nos estágios de desenvolvimento, teste e produção. Este artigo apresenta conceitos de conteinerização para aplicativos Java e orienta você na criação, depuração, otimização e implantação de aplicativos Java em contêineres nos Aplicativos de Contêiner do Azure.
Neste artigo, você aprenderá conceitos essenciais de conteinerização para desenvolvedores Java e as seguintes habilidades:
- Configurando seu ambiente de desenvolvimento para aplicativos Java em contêineres.
- Criação de Dockerfiles otimizados para cargas de trabalho Java.
- Configurando fluxos de trabalho de desenvolvimento local com contêineres.
- Depuração de aplicativos Java em contêineres.
- Otimizando contêineres Java para produção.
- Implantando seus aplicativos Java em contêineres nos Aplicativos de Contêiner do Azure.
Ao conteinerizar seus aplicativos Java, você obtém ambientes consistentes, implantação simplificada, utilização eficiente de recursos e escalabilidade aprimorada.
Contêineres para aplicativos Java
Os contêineres empacotam aplicativos com suas dependências, garantindo consistência entre ambientes. Para desenvolvedores Java, isso significa agrupar o aplicativo, suas dependências, o Java Runtime Environment/Java Development Kit (JRE/JDK) e os arquivos de configuração em uma única unidade portátil.
A conteinerização tem vantagens importantes sobre a virtualização, o que a torna ideal para o desenvolvimento em nuvem. Ao contrário de uma máquina virtual, um contêiner é executado no kernel do sistema operacional host de um servidor. Isso é benéfico para aplicativos Java, que já são executados na máquina virtual Java (JVM). A conteinerização de aplicativos Java adiciona sobrecarga mínima e fornece benefícios significativos de implantação.
O ecossistema de contêineres inclui os seguintes componentes principais:
- Imagens - os planos.
- Contêineres - instâncias em execução.
- Registros - onde as imagens são armazenadas.
- Orquestradores – sistemas que gerenciam contêineres em escala.
O Docker é a plataforma de conteinerização mais popular e tem suporte no ecossistema do Azure por meio dos Aplicativos de Contêiner do Azure.
Configurar seu ambiente de desenvolvimento
Esta seção orienta você na instalação das ferramentas necessárias e na configuração do ambiente de desenvolvimento para construir, executar e depurar aplicativos Java em contêineres.
Instalar ferramentas obrigatórias
Para conteinerizar aplicativos Java, você precisa das seguintes ferramentas instaladas em sua máquina de desenvolvimento:
- Área de Trabalho do Docker. Fornece o mecanismo do Docker, a CLI e o Docker Compose para Windows ou macOS.
- Código do Visual Studio. Disponível como um editor de código gratuito.
- As seguintes extensões do Visual Studio Code:
- Extensão do Docker para gerenciar contêineres.
- Pacote de extensão Java para desenvolvimento Java.
- Dev Containers para desenvolvimento dentro de containers.
Verifique sua instalação usando os seguintes comandos:
docker --version
docker compose version
Configurar o Visual Studio Code para desenvolvimento de contêiner
Para o desenvolvimento Java em contêineres, configure o Visual Studio Code instalando o Java Extension Pack e configurando o JDK. A extensão Dev Containers permite que você abra qualquer pasta dentro de um contêiner e use o conjunto completo de recursos do Visual Studio Code dentro desse contêiner.
Para permitir que o Visual Studio Code compile e se conecte automaticamente a um contêiner de desenvolvimento, crie um arquivo devcontainer.json.devcontainer/ em seu projeto.
Por exemplo, a configuração de exemplo a seguir define uma construção Java:
{
"name": "Java Development",
"image": "mcr.microsoft.com/devcontainers/java:21",
"customizations": {
"vscode": {
"extensions": [
"vscjava.vscode-java-pack",
"ms-azuretools.vscode-docker"
]
}
},
"forwardPorts": [8080, 5005],
"remoteUser": "vscode"
}
Essa configuração usa a imagem de contêiner de desenvolvimento Java da Microsoft, adiciona extensões essenciais e encaminha a porta do aplicativo, 8080, e a porta de depuração, 5005.
Criar um Dockerfile
Um Dockerfile contém instruções para criar uma imagem do Docker. Para aplicativos Java, o Dockerfile normalmente inclui os seguintes componentes:
- Uma imagem base com o JDK ou JRE.
- Instruções para copiar arquivos de aplicativos.
- Comandos para definir variáveis de ambiente.
- Configurações de pontos de entrada.
Selecione uma imagem base
Escolher a imagem base certa é crucial. Considere estas opções:
| Descrição | Nome | Observações |
|---|---|---|
| Imagem de desenvolvimento Java da Microsoft | mcr.microsoft.com/java/jdk:21-zulu-ubuntu |
JDK completo e otimizado para o Azure |
| Imagem de produção Java da Microsoft | mcr.microsoft.com/java/jre:21-zulu-ubuntu |
Somente tempo de execução e otimizado para o Azure |
| Imagem oficial de desenvolvimento do OpenJDK | openjdk:21-jdk |
JDK completo |
| Imagem de produção oficial do OpenJDK | openjdk:21-jre |
Somente tempo de execução |
Para ambientes de desenvolvimento, use uma imagem JDK completa. Para produção, use uma imagem JRE ou sem distribuição para minimizar o tamanho e a superfície de ataque do aplicativo.
As imagens Java da Microsoft vêm com otimizações específicas do Azure e são atualizadas regularmente com patches de segurança, tornando-as ideais para aplicativos direcionados a Aplicativos de Contêiner do Azure.
Exemplos básicos do Dockerfile
O exemplo a seguir mostra um Dockerfile simples para um aplicativo Java:
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
WORKDIR /app
COPY target/myapp.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Para aplicativos Spring Boot, você pode configurar seu Dockerfile com a seguinte base:
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-Dspring.profiles.active=docker", "-jar", "app.jar"]
Para implementações de produção, use a imagem JRE mostrada no exemplo a seguir para reduzir o tamanho e minimizar a superfície de ataque do seu aplicativo:
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENV JAVA_OPTS="-Dserver.port=8080"
ENTRYPOINT ["java", ${JAVA_OPTS}, "-jar", "app.jar"]
Desenvolvimento local com contêineres
Os contêineres foram projetados para serem executados em vários contextos. Nesta seção, você aprenderá um fluxo de desenvolvimento local para uso com contêineres.
Usar o Docker Compose para aplicativos de vários contêineres
A maioria dos aplicativos Java interage com bancos de dados, caches ou outros serviços. O Docker Compose ajuda você a definir e orquestrar aplicativos de vários contêineres usando um arquivo de configuração YAML simples.
O que é o Docker Compose?
O Docker Compose é uma ferramenta que permite executar as seguintes tarefas:
- Defina aplicativos de vários contêineres em um único arquivo.
- Gerencie o ciclo de vida do aplicativo, incluindo início, parada e recompilação.
- Mantenha ambientes isolados.
- Crie redes para comunicação de serviços.
- Persista os dados usando volumes.
Exemplo: aplicativo Java com banco de dados
O seguinte arquivo compose.yml configura um aplicativo Java com um banco de dados PostgreSQL:
version: '3.8'
services:
app:
build: . # Build from Dockerfile in current directory
ports:
- "8080:8080" # Map HTTP port
- "5005:5005" # Map debug port
environment:
- SPRING_PROFILES_ACTIVE=dev
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/myapp
volumes:
- ./target:/app/target # Mount target directory for hot reloads
depends_on:
- db # Ensure database starts first
db:
image: postgres:13
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=myapp
ports:
- "5432:5432" # Expose PostgreSQL port
volumes:
- postgres-data:/var/lib/postgresql/data # Persist database data
volumes:
postgres-data: # Named volume for database persistence
Este arquivo tem as seguintes características:
- Os serviços podem fazer referência uns aos outros pelo nome, por exemplo,
dbna URL do JDBC. - O Docker Compose cria automaticamente uma rede para os serviços.
- O aplicativo Java aguarda a inicialização do banco de dados, devido ao
depends_on. - Os dados do banco de dados persistem entre reinicializações usando um volume nomeado.
Comandos comuns do Docker Compose
Depois de criar seu arquivo compose.yml , gerencie seu aplicativo usando os seguintes comandos:
# Build images without starting containers
docker compose build
# Start all services defined in compose.yml
docker compose up
# Start in detached mode (run in background)
docker compose up -d
# View running containers managed by compose
docker compose ps
# View logs from all containers
docker compose logs
# View logs from a specific service
docker compose logs app
# Stop all services
docker compose down
# Stop and remove volumes (useful for database resets)
docker compose down -v
Fluxo de trabalho de desenvolvimento
Um fluxo de trabalho de desenvolvimento Java típico usando o Docker Compose contém as seguintes etapas:
- Crie o arquivo compose.yml e o Dockerfile.
- Executar
docker compose uppara iniciar todos os serviços. - Faça alterações no código Java.
- Recompile seu aplicativo. Dependendo da configuração, talvez seja necessário reiniciar seus contêineres.
- Teste as alterações no ambiente em contêiner.
- Quando terminar, execute
docker compose down.
Executar contêineres individuais com o Docker
Para cenários mais simples, quando você não precisa de vários serviços interconectados, você pode usar o docker run comando para iniciar contêineres individuais.
Os seguintes comandos do Docker são típicos para aplicativos Java:
# Run a Java application JAR directly
docker run -p 8080:8080 myapp:latest
# Run with environment variables
docker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=prod" myapp:latest
# Run in detached mode (background)
docker run -d -p 8080:8080 myapp:latest
# Run with a name for easy reference
docker run -d -p 8080:8080 --name my-java-app myapp:latest
# Run with volume mount for persistent data
docker run -p 8080:8080 -v ./data:/app/data myapp:latest
Depurar aplicativos em contêineres
A depuração de aplicativos Java em contêineres às vezes é desafiadora porque seu código é executado em um ambiente isolado dentro do contêiner.
As abordagens de depuração padrão nem sempre se aplicam diretamente, mas com a configuração correta, você pode estabelecer uma conexão de depuração remota com seu aplicativo. Esta seção mostra como configurar seus contêineres para depuração, conectar suas ferramentas de desenvolvimento a contêineres em execução e solucionar problemas comuns relacionados a contêineres.
Configurar a depuração remota
A depuração de aplicações Java em contêineres requer a exposição de uma porta de depuração e a configuração do IDE para se conectar a ela. Você pode realizar essas tarefas usando as seguintes etapas:
Para habilitar a depuração, modifique o Dockerfile para que ele contenha o seguinte conteúdo:
Observação
Em vez disso, você pode modificar o comando de inicialização do contêiner.
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu WORKDIR /app COPY target/*.jar app.jar EXPOSE 8080 5005 ENTRYPOINT ["java", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "-jar", "app.jar"]Configure o arquivo launch.json do Visual Studio Code para se conectar à porta de depuração, conforme mostrado no exemplo a seguir:
{ "version": "0.2.0", "configurations": [ { "type": "java", "name": "Debug in Container", "request": "attach", "hostName": "localhost", "port": 5005 } ] }Inicie o contêiner com a porta
5005mapeada para o host e inicie o depurador no Visual Studio Code.
Solucionar problemas de contêiner
Quando os contêineres não se comportam conforme o esperado, você pode inspecionar os logs do aplicativo para investigar o problema.
Use os comandos a seguir para solucionar problemas do aplicativo. Antes de executar esses comandos, certifique-se de substituir os espaços reservados (<...>) por seus próprios valores.
# View logs
docker logs <CONTAINER_ID>
# Follow logs in real-time
docker logs -f <CONTAINER_ID>
# Inspect container details
docker inspect <CONTAINER_ID>
# Get a shell in the container
docker exec -it <CONTAINER_ID> bash
Para problemas específicos do Java, ative os sinalizadores da JVM para obter um melhor diagnóstico, conforme mostrado no exemplo a seguir:
ENTRYPOINT ["java", "-XX:+PrintFlagsFinal", "-XX:+PrintGCDetails", "-jar", "app.jar"]
A tabela a seguir lista os problemas comuns e as soluções correspondentes:
| Erro | Solução possível |
|---|---|
| Memória insuficiente | Aumentar os limites de memória do contêiner |
| Tempos limite da conexão | Verifique se há erros na configuração de rede. Verifique as portas e as regras de roteamento. |
| Problemas de permissão | Verifique as permissões do sistema de arquivos. |
| Problemas de classpath | Verifique a estrutura e as dependências do JAR. |
Otimizar contêineres Java
Os aplicativos Java em contêineres requerem consideração especial para o desempenho ideal. A JVM foi projetada antes que os contêineres fossem comuns. O uso de contêineres pode levar a problemas de alocação de recursos se eles não estiverem configurados corretamente.
Você pode melhorar significativamente o desempenho e a eficiência de seus aplicativos Java em contêiner ajustando as configurações de memória, otimizando o tamanho da imagem e configurando a coleta de lixo. Esta seção aborda otimizações essenciais para contêineres Java, com foco no gerenciamento de memória, tempo de inicialização e utilização de recursos.
Configuração de memória JVM em contêineres
A JVM não detecta automaticamente os limites de memória do contêiner no Java 8. Para Java 9+, o reconhecimento de contêiner é ativado por padrão.
Configure sua JVM para respeitar os limites do contêiner, conforme mostrado no exemplo a seguir:
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
Os seguintes sinalizadores da JVM são importantes para aplicativos em contêineres:
-
-XX:MaxRAMPercentage=75.0. Define o tamanho máximo da pilha como uma porcentagem da memória disponível. -
-XX:InitialRAMPercentage=50.0. Configura o tamanho inicial do heap. -
-Xmxe-Xms. Esses sinalizadores também estão disponíveis, mas exigem valores fixos.
Prepare-se para a implantação de produção
Mover aplicativos Java em contêineres para produção requer considerações além da funcionalidade básica.
Os ambientes de produção exigem segurança robusta, monitoramento confiável, alocação adequada de recursos e flexibilidade de configuração.
Esta seção aborda as práticas e configurações essenciais necessárias para preparar seus contêineres Java para uso em produção. A seção se concentra em segurança, verificações de integridade e gerenciamento de configuração, para garantir que seus aplicativos sejam executados de forma confiável na produção.
Melhores práticas de segurança
Proteja seus aplicativos Java em contêineres usando as seguintes práticas:
Contexto de segurança padrão. Execute seus aplicativos como um usuário não raiz, conforme mostrado no exemplo a seguir:
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu WORKDIR /app COPY target/*.jar app.jar RUN addgroup --system javauser && adduser --system --ingroup javauser javauser USER javauser ENTRYPOINT ["java", "-jar", "app.jar"]Identifique problemas de forma proativa. Verifique regularmente as imagens de contêiner em busca de vulnerabilidades usando o seguinte comando:
docker scan myapp:latestAtualização da imagem base. Mantenha suas imagens base atualizadas.
Gerenciamento de segredos. Implemente o gerenciamento adequado de segredos. Por exemplo, não codifique dados confidenciais em seu aplicativo e use um cofre de chaves sempre que possível.
Contextos de segurança restritos. Aplique o princípio do menor privilégio a todos os contextos de segurança.
Acesso ao sistema de arquivos. Use sistemas de arquivos somente leitura sempre que possível.
Verificações e monitoramento de saúde
Verifique a integridade do aplicativo com sondas para garantir que seu aplicativo esteja sendo executado corretamente.
Para aplicações Spring Boot, inclua a dependência do Actuator para obter pontos de extremidade de integridade abrangentes, conforme mostrado no exemplo a seguir:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Configure seu aplicativo para gerar logs em um formato adequado para ambientes de contêiner, como JSON.
Implantar nos Aplicativos de Contêiner do Azure
Esta seção orienta você na preparação de seus contêineres Java para implantação de Aplicativos de Contêiner do Azure e destaca as principais considerações de configuração.
Preparar seu contêiner para o Azure
Configuração de porta. Verifique se o contêiner escuta na porta fornecida pelo Azure, conforme mostrado no exemplo a seguir:
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu WORKDIR /app COPY target/*.jar app.jar ENV PORT=8080 EXPOSE ${PORT} CMD java -jar app.jar --server.port=${PORT}Sonda de integridade. Implemente sondas de integridade para verificações de vivacidade e prontidão do Azure.
Configuração de registro. Configure o log para saída em
stdout/stderr.Planeje para o imprevisto. Configure um processo adequado de desligamento gradual com configuração de tempo limite. Para obter mais informações, consulte Gerenciamento do ciclo de vida do aplicativo nos Aplicativos de Contêiner do Azure.