コンテナーは、開発、テスト、運用の各段階で Java アプリケーションに一貫性のある移植可能な環境を提供します。 この記事では、Java アプリケーションのコンテナー化の概念について説明し、コンテナー化された Java アプリケーションの作成、デバッグ、最適化、および Azure Container Apps へのデプロイについて説明します。
この記事では、Java 開発者にとって重要なコンテナー化の概念と、次のスキルについて説明します。
- コンテナー化された Java アプリケーションの開発環境を設定する。
- Java ワークロード用に最適化された Dockerfile の作成。
- コンテナーを使用したローカル開発ワークフローの構成。
- コンテナー化された Java アプリケーションのデバッグ。
- 運用環境用の Java コンテナーの最適化。
- コンテナー化された Java アプリケーションを Azure Container Apps にデプロイする。
Java アプリケーションをコンテナー化することで、一貫性のある環境、デプロイの簡素化、効率的なリソース使用率、およびスケーラビリティの向上を実現できます。
Java アプリケーション用のコンテナー
コンテナーはアプリケーションを依存関係と共にパッケージ化し、環境間の一貫性を確保します。 Java 開発者の場合、これは、アプリケーション、その依存関係、Java ランタイム環境/Java 開発キット (JRE/JDK)、および構成ファイルを 1 つの移植可能な単位にバンドルすることを意味します。
コンテナー化には、クラウド開発に最適な仮想化よりも重要な利点があります。 仮想マシンとは異なり、コンテナーはサーバーのホスト OS カーネルで実行されます。 これは、Java 仮想マシン (JVM) で既に実行されている Java アプリケーションに役立ちます。 Java アプリケーションをコンテナー化すると、オーバーヘッドが最小限になり、デプロイ上の大きな利点が得られます。
コンテナー エコシステムには、次の主要なコンポーネントが含まれています。
- イメージ - ブループリント。
- コンテナー - 実行中のインスタンス。
- レジストリ - イメージが格納される場所。
- オーケストレーター - コンテナーを大規模に管理するシステム。
Docker は最も一般的なコンテナー化プラットフォームであり、Azure Container Apps を通じて Azure エコシステムで十分にサポートされています。
開発環境を設定する
このセクションでは、必要なツールをインストールし、コンテナー化された Java アプリケーションをビルド、実行、デバッグするように開発環境を構成する手順について説明します。
必要なツールのインストール
Java アプリケーションをコンテナー化するには、開発用コンピューターに次のツールがインストールされている必要があります。
- Docker Desktop。 Windows または macOS 用の Docker エンジン、CLI、および Docker Compose を提供します。
- Visual Studio Code。 無料のコード エディターとして使用できます。
- 次の Visual Studio Code 拡張機能:
- コンテナーを管理するための Docker 拡張機能。
- Java 開発用 Java 拡張機能パック。
- Devコンテナーを使用してコンテナー内で開発するための環境。
次のコマンドを使用して、インストールを確認します。
docker --version
docker compose version
コンテナー開発用に Visual Studio Code を構成する
コンテナーでの Java 開発の場合は、Java 拡張機能パックをインストールして JDK を設定して Visual Studio Code を構成します。 Dev Containers 拡張機能を使用すると、コンテナー内の任意のフォルダーを開き、そのコンテナー内で Visual Studio Code の完全な機能セットを使用できます。
Visual Studio Code で開発コンテナーを自動的にビルドして接続できるようにするには、プロジェクトに .devcontainer/devcontainer.json ファイルを作成します。
たとえば、次の構成例では 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"
}
この構成では、Microsoft の Java 開発コンテナー イメージを使用し、重要な拡張機能を追加し、アプリケーション ポート、 8080
、デバッグ ポートの両方を転送 5005
。
Dockerfile を作成する
Dockerfile には、Docker イメージを構築するための手順が含まれています。 Java アプリケーションの場合、 Dockerfile には通常、次のコンポーネントが含まれます。
- JDK または JRE を含む基本イメージ。
- アプリケーション ファイルをコピーする手順。
- 環境変数を設定するコマンド。
- エントリ ポイントの構成。
基本イメージを選択する
適切な基本イメージを選択することが重要です。 次のオプションを検討してください。
説明 | 名前 | 注釈 |
---|---|---|
Microsoft Java 開発イメージ | mcr.microsoft.com/java/jdk:21-zulu-ubuntu |
完全な JDK と Azure 用に最適化 |
Microsoft Java 運用イメージ | mcr.microsoft.com/java/jre:21-zulu-ubuntu |
ランタイムのみ、および Azure 向けに最適化 |
OpenJDK の公式開発イメージ | openjdk:21-jdk |
完全な JDK |
OpenJDK の公式実稼働イメージ | openjdk:21-jre |
ランタイムのみ |
開発環境では、完全な JDK イメージを使用します。 運用環境では、JRE またはディストリビューションレス イメージを使用して、アプリケーションのサイズと攻撃面を最小限に抑えます。
Microsoft Java イメージには Azure 固有の最適化が付属しており、セキュリティ パッチで定期的に更新されるため、Azure Container Apps を対象とするアプリケーションに最適です。
Dockerfile の基本的な例
次の例は、Java アプリケーション用の単純な Dockerfile を示しています。
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
WORKDIR /app
COPY target/myapp.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Spring Boot アプリケーションの場合は、次のベースを使用して Dockerfile を設定できます。
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"]
運用環境のデプロイでは、次の例に示す JRE イメージを使用して、サイズを小さくし、アプリケーションの攻撃対象領域を最小限に抑えます。
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"]
コンテナーを使用したローカル開発
コンテナーは、さまざまなコンテキストで実行するためのものです。 このセクションでは、コンテナーで使用するローカル開発フローについて説明します。
複数コンテナー アプリケーションに Docker Compose を使用する
ほとんどの Java アプリケーションは、データベース、キャッシュ、またはその他のサービスと対話します。 Docker Compose は、単純な YAML 構成ファイルを使用してマルチコンテナー アプリケーションを定義および調整するのに役立ちます。
Docker Compose とは
Docker Compose は、次のタスクを実行できるツールです。
- 1 つのファイルでマルチコンテナー アプリケーションを定義します。
- 開始、停止、リビルドなど、アプリケーションのライフサイクルを管理します。
- 分離された環境を維持する。
- サービス通信用のネットワークを作成します。
- ボリュームを使用してデータを保持します。
例: データベースを含む Java アプリケーション
次の compose.yml ファイルは、PostgreSQL データベースを使用して Java アプリケーションを構成します。
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
このファイルには、次の特性があります。
- サービスは名前で相互に参照できます 。たとえば、JDBC URL の
db
。 - Docker Compose は、サービスのネットワークを自動的に作成します。
-
depends_on
が原因で、Java アプリケーションはデータベースの起動を待機します。 - データベース データは、名前付きボリュームを使用して再起動後も保持されます。
一般的な Docker Compose コマンド
compose.yml ファイルを作成したら、次のコマンドを使用してアプリケーションを管理します。
# 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
開発ワークフロー
Docker Compose を使用する一般的な Java 開発ワークフローには、次の手順が含まれています。
- compose.yml ファイルと Dockerfile を作成します。
-
docker compose up
を実行して、すべてのサービスを開始します。 - Java コードに変更を加えます。
- アプリケーションをリビルドします。 構成によっては、コンテナーの再起動が必要になる場合があります。
- コンテナー化された環境での変更をテストします。
- 完了したら、
docker compose down
を実行します。
Docker を使用して単一コンテナーを実行する
複数の相互接続されたサービスが必要ない場合は、より単純なシナリオで、 docker run
コマンドを使用して個々のコンテナーを開始できます。
Java アプリケーションでは、次の Docker コマンドが一般的です。
# 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
コンテナー化されたアプリケーションをデバッグする
コンテナー化された Java アプリケーションのデバッグは、コンテナー内の分離された環境でコードが実行されるため、困難な場合があります。
標準的なデバッグ方法は常に直接適用されるわけではありませんが、適切な構成では、アプリケーションへのリモート デバッグ接続を確立できます。 このセクションでは、デバッグ用にコンテナーを構成し、開発ツールを実行中のコンテナーに接続し、コンテナー関連の一般的な問題のトラブルシューティングを行う方法について説明します。
リモート デバッグを設定する
コンテナー化された Java アプリケーションをデバッグするには、デバッグ ポートを公開し、それに接続するように IDE を構成する必要があります。 これらのタスクは、次の手順を使用して実行できます。
デバッグを有効にするには、次の内容が含まれるように Dockerfile を変更します。
注
代わりに、コンテナーのスタートアップ コマンドを変更できます。
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"]
次の例に示すように、デバッグ ポートに接続するように Visual Studio Code の launch.json ファイルを構成します。
{ "version": "0.2.0", "configurations": [ { "type": "java", "name": "Debug in Container", "request": "attach", "hostName": "localhost", "port": 5005 } ] }
ポート
5005
をホストにマップしてコンテナーを起動し、Visual Studio Code でデバッガーを起動します。
コンテナーの問題のトラブルシューティング
コンテナーが期待どおりに動作しない場合は、アプリのログを調べて問題を調査できます。
次のコマンドを使用して、アプリケーションのトラブルシューティングを行います。 これらのコマンドを実行する前に、プレースホルダー (<...>
) を実際の値に置き換えてください。
# 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
Java 固有の問題の場合は、次の例に示すように、診断を改善するために JVM フラグを有効にします。
ENTRYPOINT ["java", "-XX:+PrintFlagsFinal", "-XX:+PrintGCDetails", "-jar", "app.jar"]
次の表に、一般的な問題と対応する解決策を示します。
エラー | 考えられる解決策 |
---|---|
メモリ不足 | コンテナーのメモリ制限を増やす |
接続タイムアウト | ネットワーク構成でエラーがないか確認します。 ポートとルーティング規則を確認します。 |
アクセス許可の問題 | ファイル システムのアクセス許可を確認します。 |
Classpath の問題 | JAR の構造と依存関係を確認します。 |
Java コンテナーを最適化する
コンテナー内の Java アプリケーションでは、最適なパフォーマンスを得るための特別な考慮事項が必要です。 JVM は、コンテナーが一般的である前に設計されました。 コンテナーを使用すると、適切に構成されていない場合、リソースの割り当ての問題につながる可能性があります。
メモリ設定の微調整、イメージ サイズの最適化、ガベージ コレクションの構成により、コンテナー化された Java アプリケーションのパフォーマンスと効率を大幅に向上させることができます。 このセクションでは、メモリ管理、起動時間、およびリソース使用率に重点を置いて、Java コンテナーの基本的な最適化について説明します。
コンテナー内の JVM メモリ構成
JVM は、Java 8 のコンテナー メモリ制限を自動的に検出しません。 Java 9 以降では、コンテナー認識は既定で有効になっています。
次の例に示すように、コンテナーの制限に従って JVM を構成します。
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"]
コンテナー化されたアプリケーションでは、次の JVM フラグが重要です。
-
-XX:MaxRAMPercentage=75.0
。 使用可能なメモリの割合として最大ヒープを設定します。 -
-XX:InitialRAMPercentage=50.0
。 初期ヒープ サイズを設定します。 -
-Xmx
と-Xms
. これらのフラグも使用できますが、固定値が必要です。
運用環境デプロイの準備
コンテナー化された Java アプリケーションを運用環境に移行するには、基本的な機能以外の考慮事項が必要です。
運用環境では、堅牢なセキュリティ、信頼性の高い監視、適切なリソース割り当て、構成の柔軟性が必要です。
このセクションでは、運用環境で使用するために Java コンテナーを準備するために必要な基本的なプラクティスと構成について説明します。 このセクションでは、アプリケーションが運用環境で確実に実行されるように、セキュリティ、正常性チェック、および構成管理に重点を置いています。
セキュリティのベスト プラクティス
次のプラクティスを使用して、コンテナー化された Java アプリケーションをセキュリティで保護します。
既定のセキュリティ コンテキスト。 次の例に示すように、非ルート ユーザーとしてアプリケーションを実行します。
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"]
問題を事前に探します。 次のコマンドを使用して、コンテナー イメージの脆弱性を定期的にスキャンします。
docker scan myapp:latest
基本イメージの鮮度。 基本イメージを最新の状態に保ちます。
シークレット管理。 適切なシークレット管理を実装します。 たとえば、機密データをアプリケーションにハードコーディングせず、可能な限りキー コンテナーを使用します。
制限付きセキュリティ コンテキスト。 すべてのセキュリティ コンテキストに最小特権の原則を適用します。
ファイル システム へのアクセス。 可能な限り、読み取り専用ファイル システムを使用します。
健康診断と監視
プローブを使用してアプリケーション の 正常性を確認し、アプリケーションが正しく実行されていることを確認します。
Spring Boot アプリケーションの場合は、次の例に示すように、包括的な正常性エンドポイントのアクチュエータの依存関係を含めます。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
JSON などのコンテナー環境に適した形式でログを出力するようにアプリケーションを構成します。
Azure Container Apps へのデプロイ
このセクションでは、Azure Container Apps のデプロイ用に Java コンテナーを準備する手順について説明し、主要な構成に関する考慮事項について説明します。
Azure 用にコンテナーを準備する
ポート構成。 次の例に示すように、コンテナーが Azure によって提供されるポートでリッスンしていることを確認します。
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}
正常性のプローブ。 Azure の liveness と readiness のチェックのために、正常性プローブを実行します。
不測の事態に備えましょう。 タイムアウト構成を使用して適切なグレースフル シャットダウン処理を設定します。 詳細については、「 Azure Container Apps でのアプリケーション ライフサイクル管理」を参照してください。