Java 應用程式的容器簡介

容器可在開發、測試和生產階段,為您的 Java 應用程式提供一致的可攜式環境。 本文介紹 Java 應用程式的容器化概念,並引導您建立、偵錯、優化和將容器化 Java 應用程式部署至 Azure Container Apps。

在本文中,您將瞭解 Java 開發人員的基本容器化概念,以及下列技能:

  • 設定容器化 Java 應用程式的開發環境。
  • 建立針對 Java 工作負載最佳化的 Dockerfile。
  • 使用容器設定本機開發工作流程。
  • 偵錯容器化 Java 應用程式。
  • 優化生產環境的Java容器。
  • 將您的容器化 Java 應用程式部署至 Azure Container Apps。

藉由容器化 Java 應用程式,您就能取得一致的環境、簡化的部署、有效率的資源使用率,以及改善的延展性。

適用於 Java 應用程式的容器

容器會使用其相依性封裝應用程式,以確保環境之間的一致性。 對於 Java 開發人員來說,這表示將應用程式、其相依性、Java 運行時間環境/Java 開發工具包 (JRE/JDK) 和組態檔結合成單一可攜式單位。

容器化在虛擬化上具有關鍵優勢,因此適合用於雲端開發。 相較於虛擬機,容器會在伺服器的主機OS核心上執行。 這對已在 Java 虛擬機 (JVM) 中執行的 Java 應用程式很有説明。 容器化 Java 應用程式會增加最少的額外負荷,並提供顯著的部署優點。

容器生態系統包含下列重要元件:

  • 影像 - 藍圖。
  • 容器 - 執行中的實例。
  • 登錄 - 儲存映像的位置。
  • 協調流程工具 - 可大規模管理容器的系統。

Docker 是最受歡迎的容器化平臺,而且透過 Azure Container Apps 在 Azure 生態系統中受到很好的支援。

設定開發環境

本節將引導您安裝必要的工具和設定開發環境,以建置、執行和偵錯容器化 Java 應用程式。

安裝所需工具

若要容器化 Java 應用程式,您需要在開發電腦上安裝下列工具:

使用下列命令來確認您的安裝:

docker --version
docker compose version

設定 Visual Studio Code 以進行容器開發

若要在容器中進行 Java 開發,請安裝 Java Extension Pack 並設定 JDK,以完成 Visual Studio Code 設定。 開發容器延伸模組可讓您開啟容器內的任何資料夾,並使用該容器內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 容器應用程式為目標的應用程式。

基本 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 是可讓您執行下列工作的工具:

  • 在單一檔案中定義多容器應用程式。
  • 管理應用程式生命週期,包括啟動、停止和重建。
  • 維護隔離的環境。
  • 建立服務通訊的網路。
  • 使用磁碟區保存資料。

範例:具有資料庫的 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

此檔案具有下列特性:

  • 服務可以依名稱彼此參考 -例如, db 在 JDBC URL 中。
  • Docker Compose 會自動建立服務的網路。
  • Java 應用程式會因為 depends_on 而等候資料庫啟動。
  • 資料庫資料會使用具名磁碟區,在重新啟動後持續保留。

常見的 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 命令來啟動個別容器。

下列 Docker 命令適用於 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

偵錯容器化應用程式

偵錯容器化 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 Codelaunch.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 應用程式,請加入 Actuator 相依性,以提供完整的健康狀態端點,如下列範例所示:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

設定您的應用程式以適合容器環境的格式輸出記錄,例如 JSON。

部署至 Azure 容器應用程式

本節將引導您準備適用於 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 的存留性與就緒性檢查,實作健康狀態探查。

  • 記錄組態。 將 記錄 設定為輸出至 stdout/stderr。

  • 為意外做好規劃。 使用逾時組態,正確設定妥善的正常關機處理。 如需詳細資訊,請參閱 Azure Container Apps 中的應用程式生命週期管理。