Docker化Spring Boot應用

2023-06-10 21:00:46

本文翻譯自國外論壇 medium,原文地址:https://medium.com/@bubu.tripathy/dockerizing-your-spring-boot-application-75bf2c6568d0

Docker 是一個強大的工具,允許開發人員將他們的應用程式打包在容器中可以在任何平臺上輕鬆部署和執行。在對 Spring Boot 應用程式進行 Docker 化時,每個開發人員都應遵循一些最佳實踐,以確保應用程式平穩高效地執行。在本文中,我們將探索這些最佳實踐並提供程式碼範例和解釋,以幫助大家對 Spring Boot 應用程式進行 Docker 化改造。

使用正確的基礎映象

在對 Spring Boot 應用程式進行 Docker 化時,為應用程式選擇正確的基礎映象非常重要。基礎映象提供應用程式所需的底層作業系統和依賴項。選擇正確的基礎映象有助於確保應用程式在 Docker 容器中平穩高效地執行。

對於 Spring Boot 應用程式,我們建議使用 OpenJDK 基礎映象。 OpenJDK 是 Java 開發工具包 (JDK) 的開源實現,並提供 Java 執行時環境。 OpenJDK 基礎映象有不同的版本,例如 Java 8、Java 11 和 Java 16。下面是一個使用 OpenJDK 11 基礎映象的 Dockerfile 範例:

FROM openjdk:11
COPY target/my-application.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

在此範例中,我們使用 openjdk:11 基礎映象為 Spring Boot 應用程式建立 Docker 映象。我們將 my-application.jar 檔案複製到容器中,並使用 java 命令執行應用程式。

為 Spring Boot 應用程式使用正確的基礎映象有助於確保應用程式在 Docker 容器中平穩高效地執行。 OpenJDK 是 Java 應用程式的熱門選擇,因為它提供了輕量級且安全的 Java 執行時環境。

映象儘可能精簡

在對 Spring Boot 應用程式進行 Docker 化時,保持 Docker 映象的大小盡可能小很重要。較小的映象大小有幾個優點,例如更快的映象傳輸時間、更低的儲存要求和更快的容器啟動時間。

實現較小映象大小的一種方法是在 Dockerfile 中使用多階段構建。在多階段構建中,我們可以使用多個 FROM 指令來定義構建過程中的不同階段。每個階段都可以有自己的一組指令和依賴項,最終映象只包含最後一個階段的檔案和依賴項。下面是一個使用多階段構建來建立 slim(精簡) Spring Boot 映象的 Dockerfile 範例:

# 第一階段:構建應用
FROM maven:3.8.3-jdk-11 AS build
COPY . /app
WORKDIR /app
RUN mvn package -DskipTests

# 第二階段: 建立一個 slim 映象
FROM openjdk:11-jre-slim
COPY --from=build /app/target/my-application.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

在此範例中,第一階段使用 Maven 基礎映象構建 Spring Boot 應用程式並生成 jar 檔案。第二階段使用 OpenJDK slim 基礎映象,它是基礎映象的較小版本,僅包含 Java 執行時環境。

COPY --from=build 指令將 jar 檔案從第一階段複製到第二階段,ENTRYPOINT 指令指定容器啟動時應執行的命令。

以這種方式使用多階段構建允許我們建立一個精簡的 Docker 映象,它只包含執行 Spring Boot 應用程式所需的依賴項和檔案。通過這樣做,可以減小影象的大小並提高應用程式的效能。

使用環境變數

在對 Spring Boot 應用程式進行 Docker 化時,使用環境變數來設定應用程式很重要。使用環境變數允許更改應用程式的設定而無需重建 Docker 映象。

Spring Boot 應用程式可以使用 application.propertiesapplication.yml 檔案來指定設定屬性。這些屬性可以在執行時使用環境變數覆蓋,Spring Boot 會自動將其對映到屬性。下面是一個 Dockerfile 範例,它設定了一個環境變數來為 Spring Boot 應用程式指定使用哪個組態檔:

FROM openjdk:11
ENV SPRING_PROFILES_ACTIVE=production
COPY target/my-application.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

在此範例中,我們將 SPRING_PROFILES_ACTIVE 環境變數設定為 production,這將啟用 Spring Boot 應用程式中的 production 組態檔。

當容器啟動時,在 ENTRYPOINT 指令中指定的 java 命令與 -jar 選項一起執行以啟動 Spring Boot 應用程式。由於我們設定了 SPRING_PROFILES_ACTIVE 環境變數,應用程式將自動使用 production 組態檔。

以這種方式使用環境變數可以輕鬆更改 Spring Boot 應用程式的設定,而無需重建 Docker 映象。我們可以在執行容器時使用 -e 選項設定環境變數,或者使用 Docker Compose 檔案來定義環境變數。

使用Docker Compose

在對 Spring Boot 應用程式進行 Docker 化時,使用 Docker Compose 來定義應用程式的服務和依賴項非常重要。 Docker Compose 是一個用於定義和執行多容器 Docker 應用程式的工具。它允許我們在單個檔案中定義應用程式的 services, networks, 和 volumes,從而輕鬆管理和部署我們的應用程式。這是一個定義 Spring Boot 應用程式和 MySQL 資料庫的範例 Docker Compose 檔案:

version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: my-secret-pw
      MYSQL_DATABASE: my-database
    volumes:
      - db_data:/var/lib/mysql
  web:
    build: .
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/my-database
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: my-secret-pw
volumes:
  db_data:

在這個例子中,我們定義了兩個服務:dbwebdb 服務使用官方 MySQL 映象,並使用環境變數設定 root 密碼和資料庫名稱。它還為持久儲存建立一個命名卷 db_data

Web 服務使用 . 構建上下文並公開埠 8080。它還為資料庫 URL、使用者名稱和密碼設定環境變數,Spring Boot 應用程式使用這些變數連線到 MySQL 資料庫。

以這種方式使用 Docker Compose 可以讓我們輕鬆管理和部署 Spring Boot 應用程式及其依賴項。可以使用單個命令啟動 Docker Compose 檔案中定義的所有服務,並且可以根據需要擴充套件或縮減服務。此外,還可以使用 Docker Compose 定義額外的設定選項,例如 volumes、networks和environment 變數,從而輕鬆管理和部署應用程式。

使用反向代理

在對 Spring Boot 應用程式進行 Docker 化時,使用反向代理來處理傳入流量並將其分發到應用程式的容器非常重要。反向代理是位於應用程式和網際網路之間的伺服器,它根據特定規則將請求轉發到應用程式的容器。

使用反向代理有幾個優點,例如負載平衡、SSL 終止和改進的安全性。通過使用反向代理,可以在多個容器之間平均分配傳入流量,在代理級別終止 SSL 連線以減少應用程式容器的負載,併為應用程式新增額外的安全層。下面是一個定義 Spring Boot 應用程式和 Nginx 反向代理的 Docker Compose 檔案範例:

version: '3'
services:
  web:
    build: .
    environment:
      SPRING_PROFILES_ACTIVE: production
    ports:
      - "8080:8080"
  proxy:
    image: nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - web

在這個例子中,我們定義了兩個服務:webproxyWeb 服務構建Spring Boot應用,暴露 8080 埠,proxy 服務使用官方Nginx映象,根據 nginx.conf 檔案中定義的規則,將請求轉發給 Web 服務。

下面是一個範例 nginx.conf 檔案,它定義了將請求轉發到 Web 服務的規則:

events {
}

http {
    server {
        listen 80;

        location / {
            proxy_pass http://web:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

在此範例中,我們使用 proxy_pass 指令將請求轉發到埠 8080 上的 Web 服務。我們還設定了各種檔頭以保留原始使用者端 IP 和協定資訊。

以這種方式使用反向代理有助於提高 Spring Boot 應用程式 Docker 化後的可延伸性、安全性和效能。通過使用反向代理,我們可以輕鬆地跨多個容器分發傳入流量,為應用程式新增額外的安全層,並通過在代理級別終止 SSL 連線來減少應用程式容器的負載。

使用健康檢查

在對 Spring Boot 應用程式進行 Docker 化時,使用健康檢查來監控應用程式的健康狀況並確保其正常執行非常重要。健康檢查可用於檢測應用程式何時不健康,並根據應用程式的健康狀況自動執行恢復或縮放。

要向 Docker 映象新增健康檢查,可以在 Dockerfile 中使用 HEALTHCHECK 指令。 HEALTHCHECK 指令告訴 Docker 如何檢查應用程式的健康狀況。下面是一個 Dockerfile 範例,它向 Spring Boot 應用程式新增了健康檢查:

FROM openjdk:11
COPY target/my-application.jar app.jar
HEALTHCHECK --interval=5s \
            --timeout=3s \
            CMD curl -f http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-jar", "/app.jar"]

在此範例中,我們使用 HEALTHCHECK 指令來檢查 Spring Boot 應用程式的執行狀況。 --interval 選項指定執行狀況檢查的頻率,--timeout 選項指定等待響應的時間。 CMD 指令執行健康檢查命令,這是一個 curl 命令,檢查應用程式的 /actuator/health 端點。

執行容器時,可以使用 docker ps 命令檢視容器的健康狀態:

$ docker ps
CONTAINER ID   IMAGE                COMMAND                  CREATED         STATUS          PORTS                    NAMES
e8e1a6440e5e   my-application:1.0   "java -jar /app.jar"     5 seconds ago   Up 4 seconds    0.0.0.0:8080->8080/tcp   my-application
$ docker inspect --format='{{json .State.Health}}' my-application
{"Status":"healthy","FailingStreak":0,"Log":[{"Start":"2023-03-25T09:21:08.272130387Z","End":"2023-03-25T09:21:08.310105965Z","ExitCode":0,"Output":"\n"}]}

在此範例中,docker ps 命令顯示容器已啟動並在埠 8080 上執行。docker inspect 命令顯示容器的健康狀態,當前為健康狀態。如果健康檢查失敗,容器將被標記為不健康,我們可以使用 Docker Compose 或 Kubernetes 等工具自動恢復或擴充套件容器。

以這種方式使用健康檢查有助於提高 Spring Boot 應用程式 Docker 化後的可靠性和可用性。通過使用健康檢查,我們可以自動檢測應用程式中的問題並從中恢復,確保應用程式始終可供使用者使用。

使用 Docker 快取

在對 Spring Boot 應用程式進行 Docker 化時,使用 Docker 快取來加快構建過程並減少構建新 Docker 映象所需的時間非常重要。 Docker 快取允許重用之前構建的 Docker 映象層,避免每次構建新映象時都需要重建這些層。下面是一個使用 Docker 快取來加速構建過程的 Dockerfile 範例:

FROM openjdk:11 as builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline

COPY src/ ./src/
RUN mvn package -DskipTests

FROM openjdk:11
COPY --from=builder /app/target/my-application.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

在此範例中,我們使用多階段構建首先在單獨的層中構建 Spring Boot 應用程式,然後將構建的 jar 檔案複製到最終影象中。通過為構建過程使用一個單獨的層,我們可以利用 Docker 快取來避免每次構建新影象時都重建依賴項。

構建過程的第一階段使用 openjdk:11 基礎映象並將 pom.xml 檔案複製到容器中。然後它執行 mvn dependency:go-offline 命令來下載應用程式所需的所有依賴項。此命令確保所有需要的依賴項都在本地可用,這將加快後續構建的速度。

構建過程的第二階段使用 openjdk:11 基礎映象並將原始碼複製到容器中。然後它執行 mvn package 命令來構建應用程式 jar 檔案。由於我們在前一階段已經下載了依賴,Docker會使用快取層,跳過依賴下載這一步。

最後,COPY --from=builder 指令將構建的 jar 檔案從構建器階段複製到最終映象,ENTRYPOINT 指令指定容器啟動時應執行的命令。

以這種方式使用 Docker 快取有助於減少構建新 Docker 映象所需的時間並加快部署過程。通過利用 Docker 快取,可以避免不必要的重建,並確保儘可能快速高效地構建 Docker 映象。

使用.dockerignore檔案

在對 Spring Boot 應用程式進行 Docker 化時,使用 .dockerignore 檔案從 Docker 構建上下文中排除不必要的檔案和目錄非常重要。構建上下文是 Docker 用來構建 Docker 映象的一組檔案和目錄。通過使用 .dockerignore 檔案,可以排除 Docker 映象不需要的檔案和目錄,從而減少構建上下文的大小並提高構建效能。這是 Spring Boot 應用程式的範例 .dockerignore 檔案:

# 忽略根目錄中的所有檔案
*
# 包含 src 目錄
!src/
# 包含 pom.xml 檔案
!pom.xml
# 排除目標目錄及其內容
target/

在此範例中,我們使用 .dockerignore 檔案排除根目錄 (*) 中的所有檔案,但構建 Spring Boot 應用程式所需的 src/ 目錄和 pom.xml 檔案除外。我們還排除了 target/ 目錄,它包含構建的工件並且 Docker 映象不需要。

通過使用 .dockerignore 檔案,我們可以減少構建上下文的大小並提高構建效能。 Docker 只會複製構建上下文中包含的檔案和目錄,而忽略 .dockerignore 檔案中排除的檔案和目錄。

使用 .dockerignore 檔案是對 Spring Boot 應用程式進行 Docker 化的一種好做法,因為它有助於確保儘可能高效快速地構建 Docker 映象。

此外,使用 .dockerignore 檔案還可以幫助提高 Docker 映象的安全性。通過排除不必要的檔案和目錄,可以減少 Docker 映象的攻擊面,並最大限度地降低暴露敏感資訊或憑據的風險。例如,如果在構建目錄中儲存了組態檔或憑據,將它們排除在 .dockerignore 檔案中將阻止它們包含在 Docker 映象中。

還值得注意的是,.dockerignore 檔案遵循與 .gitignore 檔案類似的語法,後者用於從 Git 儲存庫中排除檔案和目錄。如果熟悉 .gitignore 檔案,我們應該會發現 .dockerignore 檔案易於使用。

總之,使用 .dockerignore 檔案是對 Spring Boot 應用程式進行 Docker 化的一種好做法。它有助於減小構建上下文的大小、提高構建效能並提高 Docker 映象的安全性。

使用標籤

在對 Spring Boot 應用程式進行 Docker 化時,使用標籤將後設資料新增到 Docker 映象非常重要。標籤是鍵值對,可以新增到 Docker 映象以提供有關映象的其他資訊,例如版本、維護者或構建日期。下面是一個使用標籤將後設資料新增到 Spring Boot 應用程式的 Dockerfile 範例:

FROM openjdk:11
LABEL maintainer="John Doe <[email protected]>"
LABEL version="1.0"
LABEL description="My Spring Boot application"
COPY target/my-application.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

在此範例中,我們使用 LABEL 指令將後設資料新增到 Docker 映象。我們為映象的維護者、版本和描述新增了標籤。這些標籤提供有關 Docker 映象的附加資訊,並幫助使用者瞭解映象包含的內容及其構建方式。

我們可以使用 docker inspect 命令檢視 Docker 映象的標籤:

$ docker inspect my-application
[
    {
        "Id": "sha256:...",
        "RepoTags": [
            "my-application:latest"
        ],
        "Labels": {
            "maintainer": "John Doe <[email protected]>",
            "version": "1.0",
            "description": "My Spring Boot application"
        },
        ...
    }
]

在此範例中,docker inspect 命令顯示 my-application Docker 映象的標籤。標籤提供有關影象的附加資訊,可以幫助使用者瞭解影象的構建方式和使用方式。

以這種方式使用標籤有助於提高 Docker 映象的可用性和可維護性。通過將後設資料新增到 Docker 映象,可以幫助使用者瞭解映象包含的內容以及它是如何構建的。隨著時間的推移,此資訊可用於偵錯、故障排除和維護 Docker 映象。

使用容器編排

在對 Spring Boot 應用程式進行 Docker 化時,使用容器編排工具在生產環境中管理和擴充套件應用程式非常重要。容器編排工具可以幫助我們自動化部署、擴充套件和管理 Docker 容器,從而更輕鬆地管理分散式環境中的大量容器。

一些流行的 Docker 容器編排工具包括 Kubernetes、Docker Swarm 和 Apache Mesos。這些工具提供負載平衡、自動縮放、服務發現和捲動更新等功能,有助於確保應用程式可用並響應使用者。以下是 Spring Boot 應用程式的 Kubernetes 部署檔案範例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-application
  labels:
    app: my-application
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-application
  template:
    metadata:
      labels:
        app: my-application
    spec:
      containers:
      - name: my-application
        image: my-registry/my-application:1.0
        ports:
        - containerPort: 8080

在此範例中,我們使用 Kubernetes 部署檔案來部署 Spring Boot 應用程式。部署檔案指定我們要執行應用程式的三個副本,並使用選擇器來識別應該成為部署一部分的 pod。部署檔案還指定了應該用於執行應用程式的容器映象,以及應用程式應該偵聽的埠。

以這種方式使用容器編排工具可以幫助提高 Spring Boot 應用程式 Docker 化後的可延伸性、可靠性和可用性。通過使用容器編排工具,可以在分散式環境中輕鬆管理和擴充套件應用程式,從而更輕鬆地確保應用程式可用並響應使用者。

總結

Docker 化 Spring Boot 應用程式可能是一個複雜的過程,但通過遵循這些最佳實踐,開發人員可以確保他們的應用程式在 Docker 容器中平穩高效地執行。通過實施這些最佳實踐,可以利用 Docker 的優勢並將應用程式輕鬆部署到任何平臺。

關注公眾號【waynblog】每週分享技術乾貨、開源專案、實戰經驗、高效開發工具等,您的關注將是我的更新動力!