次の方法で共有


Java アプリケーションのコンテナーの概要

コンテナーは、開発、テスト、運用の各段階で 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 --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 開発ワークフローには、次の手順が含まれています。

  1. compose.yml ファイルと Dockerfile を作成します。
  2. docker compose upを実行して、すべてのサービスを開始します。
  3. Java コードに変更を加えます。
  4. アプリケーションをリビルドします。 構成によっては、コンテナーの再起動が必要になる場合があります。
  5. コンテナー化された環境での変更をテストします。
  6. 完了したら、 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 を構成する必要があります。 これらのタスクは、次の手順を使用して実行できます。

  1. デバッグを有効にするには、次の内容が含まれるように 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"]
    
  2. 次の例に示すように、デバッグ ポートに接続するように Visual Studio Code の launch.json ファイルを構成します。

    {
      "version": "0.2.0",
      "configurations": [
        {
          "type": "java",
          "name": "Debug in Container",
          "request": "attach",
          "hostName": "localhost",
          "port": 5005
        }
      ]
    }
    
  3. ポート 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 のチェックのために、正常性プローブを実行します。

  • ログの構成。 stdout /に出力するようにstderrを構成します。

  • 不測の事態に備えましょう。 タイムアウト構成を使用して適切なグレースフル シャットダウン処理を設定します。 詳細については、「 Azure Container Apps でのアプリケーション ライフサイクル管理」を参照してください。