將 Tomcat 應用程式遷移至 Azure Kubernetes Service 上的容器 (AKS)
本指南說明當您想要移轉現有的Tomcat應用程式以在 Azure Kubernetes Service 上執行時應該注意的事項。
移轉前
為確保成功移轉,在開始之前,請先完成下列各節中所述的評量和清查步驟。
清查外部資源
外部資源,例如數據源、JMS 訊息代理程式,以及其他資源會透過 Java 命名和目錄介面 (JNDI) 插入。 某些這類資源可能需要移轉或重新設定。
在應用程式內
檢查META-INF/context.xml檔案。 尋找 <Resource>
元素內的 <Context>
元素。
在應用程式伺服器上
檢查 $CATALINA_BASE/conf/context.xml 和 $CATALINA_BASE/conf/server.xml 檔案,以及 $CATALINA_BASE/conf/[engine-name]/[host-name] 目錄中找到的.xml檔案。
在context.xml檔案中,最上層<Context>
元素內的元素將會描述 <Resource>
JNDI 資源。
在server.xml檔案中,專案內的<GlobalNamingResources>
元素將會描述 <Resource>
JNDI 資源。
資料來源
資料來源是 JNDI 資源, type
屬性設定為 javax.sql.DataSource
。 針對每個數據源,記載下列資訊:
- 數據源名稱為何?
- 連線集區設定是什麼?
- 哪裡可以找到 JDBC 驅動程式 JAR 檔案?
如需詳細資訊,請參閱 Tomcat檔中的JNDI資料源操作說明 。
所有其他外部資源
在本指南中記載每個可能的外部相依性並不可行。 您的小組有責任確認您可以在移轉後滿足應用程式的每個外部相依性。
清查秘密
密碼和安全字串
檢查生產伺服器上的所有屬性和組態檔,以取得任何秘密字串和密碼。 請務必在 $CATALINA_BASE/conf 中檢查server.xml和context.xml。 您也可以在應用程式內找到包含密碼或認證的組態檔。 這可能包括 META-INF/context.xml,以及 Spring Boot 應用程式、 application.properties 或 application.yml 檔案。
判斷是否要使用檔案系統及如何使用
每當使用應用程式伺服器上的檔案系統時,都必須重新設定,或在罕見的情況下,還需要進行架構變更。 您可以識別下列部分或所有案例。
唯讀靜態內容
如果應用程式目前提供靜態內容,則必須為其提供替代位置。 您可能想要考慮將靜態內容移至 Azure Blob 儲存體,並新增 Azure CDN 以進行全球閃電快速下載。 如需詳細資訊,請參閱 Azure 儲存體中的靜態網站裝載和快速入門:整合 Azure 儲存體帳戶與 Azure CDN。
動態發佈的靜態內容
如果您的應用程式允許您應用程式上傳/產生的靜態內容,但在建立後不可變,則您可以使用上述的 Azure Blob 儲存體和 CDN,搭配 Azure 函式來處理上傳和 CDN 重新整理。 我們已在使用 Azure Functions 上傳和透過 CDN 預先載入靜態內容中提供範例實作供您使用。
動態或內部內容
對於您應用程式經常寫入和讀取的檔案 (例如暫存資料檔案),或只有您的應用程式才能看見的靜態檔案,您可以掛接 Azure 儲存體共用,作為永續性磁碟區。 如需詳細資訊,請參閱在 Azure Kubernetes Service 中建立和使用具有 Azure 檔案儲存體 的磁碟區(AKS)。
識別會話持續性機制
若要識別正在使用中的會話持續性管理員,請檢查 應用程式和 Tomcat 組態中的context.xml 檔案。 尋找 <Manager>
項目,然後記下 屬性的值 className
。
Tomcat 的內建 PersistentManager 實作,例如 StandardManager 或 FileStore 不是專為搭配分散式、縮放平臺使用而設計,例如 Kubernetes。 AKS 可能會在數個 Pod 之間進行負載平衡,並隨時以透明方式重新啟動任何 Pod,不建議將可變狀態保存到文件系統。
如果需要會話持續性,您必須使用替代 PersistentManager
實作來寫入外部數據存放區,例如具有 Redis 快取的 VMware Tanzu 會話管理員。 如需詳細資訊,請參閱 搭配 Tomcat 使用 Redis 作為會話快取。
特殊情況
某些生產案例可能需要額外的變更,或施加額外的限制。 雖然這類案例可能不常發生,但請務必確保它們無法套用至您的應用程式或正確解決。
判斷應用程式是否依賴排程的作業
排程的作業,例如讓排程器工作或cron作業無法與容器化Tomcat部署搭配使用。 如果您的應用程式相應放大,每個排程期間可能會執行一次以上的排程工作。 這種情況可能會導致非預期的後果。
清查應用程式伺服器內部或外部的任何排程工作。
判斷您的應用程式是否包含 OS 特定程式代碼
如果您的應用程式包含任何可容納應用程式執行之作業系統的程式代碼,則您的應用程式必須重構為 NOT 依賴基礎 OS。 例如,檔案系統路徑中的任何 使用 /
或 \
可能需要取代為 File.Separator
或 Path.get
。
判斷是否使用MemoryRealm
MemoryRealm 需要保存的 XML 檔案。 在 Kubernetes 上,此檔案必須新增至容器映像,或上傳至 可供容器使用的共享記憶體。 pathName
參數必須據以修改。
若要判斷目前是否MemoryRealm
使用,請檢查您的server.xml和context.xml檔案,並搜尋 <Realm>
屬性設定為org.apache.catalina.realm.MemoryRealm
的專案className
。
判斷是否使用 SSL 工作階段追蹤
在容器化部署中,SSL 會話通常會從應用程式容器外卸除,通常是由輸入控制器卸除。 如果您的應用程式需要 SSL 會話追蹤,請確定 SSL 流量會直接傳遞至應用程式容器。
判斷是否使用 AccessLogValve
如果使用 AccessLogValve,directory
參數應該設定為掛接 Azure 檔案儲存體 共用或其子目錄之一。
就地測試
建立容器映像之前,請先將應用程式移轉至您想要在 AKS 上使用的 JDK 和 Tomcat。 徹底測試您的應用程式,以確保相容性和效能。
參數化組態
在移轉前,您可能會在server.xml和context.xml檔案中識別秘密和外部相依性,例如數據源。 因此,針對所識別的每個專案,將任何使用者名稱、密碼、連接字串 或URL取代為環境變數。
例如,假設 context.xml 檔案包含下列元素:
<Resource
name="jdbc/dbconnection"
type="javax.sql.DataSource"
url="jdbc:postgresql://postgresdb.contoso.com/wickedsecret?ssl=true"
driverClassName="org.postgresql.Driver"
username="postgres"
password="t00secure2gue$$"
/>
在此情況下,您可以變更它,如下列範例所示:
<Resource
name="jdbc/dbconnection"
type="javax.sql.DataSource"
url="${postgresdb.connectionString}"
driverClassName="org.postgresql.Driver"
username="${postgresdb.username}"
password="${postgresdb.password}"
/>
遷移
除了第一個步驟(「布建容器登錄和 AKS」之外,我們建議您針對您想要移轉的每個應用程式個別遵循下列步驟。
注意
某些 Tomcat 部署可能會有多個應用程式在單一 Tomcat 伺服器上執行。 如果您的部署是這種情況,強烈建議您在個別 Pod 中執行每個應用程式。 這可讓您優化每個應用程式的資源使用率,同時將複雜度和結合度降至最低。
布建容器登錄和 AKS
建立容器登錄和 Azure Kubernetes 叢集,其服務主體在登錄上具有讀取者角色。 請務必 為叢集的網路需求選擇適當的網路模型 。
az group create \
--resource-group $resourceGroup \
--location eastus
az acr create \
--resource-group $resourceGroup \
--name $acrName \
--sku Standard
az aks create \
--resource-group $resourceGroup \
--name $aksName \
--attach-acr $acrName \
--network-plugin azure
準備部署成品
複製 Tomcat On Containers 快速入門 GitHub 存放庫。 其中包含一些建議優化功能的 Dockerfile 和 Tomcat 組態檔。 在下列步驟中,我們概述您可能需要對這些檔案所做的修改,再建置容器映像並部署至 AKS。
視需要開啟叢集的埠
如果您想要在 AKS 上使用 Tomcat 叢集 ,請確定 Dockerfile 中會公開必要的埠範圍。 若要在 server.xml 中指定伺服器 IP 位址,請務必使用從容器啟動時初始化之變數的值,初始化至 Pod 的 IP 位址。
或者,會話狀態可以 保存至替代位置 ,以便跨複本使用。
若要判斷您的應用程式是否使用叢集,請在 server.xml 檔案中尋找 <Cluster>
或 <Engine>
元素內的 <Host>
元素。
新增 JNDI 資源
編輯 server.xml 以新增您在移轉前步驟中準備的資源,例如數據源。
例如:
<!-- Global JNDI resources
Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml"
/>
<!-- Migrated datasources here: -->
<Resource
name="jdbc/dbconnection"
type="javax.sql.DataSource"
url="${postgresdb.connectionString}"
driverClassName="org.postgresql.Driver"
username="${postgresdb.username}"
password="${postgresdb.password}"
/>
<!-- End of migrated datasources -->
</GlobalNamingResources>
如需其他數據源指示,請參閱Tomcat檔中 JNDI 資料源操作說明的下列各節:
組建並推送映像
建置映像並將其上傳至 Azure Container Registry (ACR) 以供 AKS 使用的最簡單方式是使用 az acr build
命令。 此命令不需要在您的電腦上安裝 Docker。 例如,如果您的上述 Dockerfile 和目前目錄中的應用程式套件 petclinic.war ,您可以使用一個步驟在 ACR 中建置容器映射:
az acr build \
--image "${acrName}.azurecr.io/petclinic:{{.Run.ID}}" \
--registry $acrName \
--build-arg APP_FILE=petclinic.war \
--build-arg=prod.server.xml .
如果您的 WAR 檔案名為 ROOT.war,--build-arg APP_FILE...
您可以省略 參數。 如果您的伺服器 XML 檔案名為 server.xml,您可以省略 --build-arg SERVER_XML...
參數。 這兩個檔案必須位於與 Dockerfile 相同的目錄中。
或者,您可以使用 Docker CLI 在本機建置映像。 這種方法可以簡化在初始部署至 ACR 之前測試和精簡映像。 不過,它需要安裝 Docker CLI 並執行 Docker 精靈。
# Build the image locally
sudo docker build . --build-arg APP_FILE=petclinic.war -t "${acrName}.azurecr.io/petclinic:1"
# Run the image locally
sudo docker run -d -p 8080:8080 "${acrName}.azurecr.io/petclinic:1"
# Your application can now be accessed with a browser at http://localhost:8080.
# Log into ACR
sudo az acr login --name $acrName
# Push the image to ACR
sudo docker push "${acrName}.azurecr.io/petclinic:1"
如需詳細資訊,請參閱在 Azure 中建置和儲存容器映射的 Learn 課程模組。
布建公用IP位址
如果您的應用程式可從內部或虛擬網路外部存取,則需要公用靜態IP位址。 此IP位址應該布建在叢集的節點資源群組內。
export nodeResourceGroup=$(az aks show \
--resource-group $resourceGroup \
--name $aksName \
--query 'nodeResourceGroup' \
--output tsv)
export publicIp=$(az network public-ip create \
--resource-group $nodeResourceGroup \
--name applicationIp \
--sku Standard \
--allocation-method Static \
--query 'publicIp.ipAddress' \
--output tsv)
echo "Your public IP address is ${publicIp}."
部署到 AKS
建立並套用 Kubernetes YAML 檔案。。 如果您要建立外部負載平衡器(無論是您的應用程式還是輸入控制器),請務必提供上一節中布建的IP位址作為 LoadBalancerIP
。
將外部化參數納入 為環境變數。 請勿包含秘密(例如密碼、API 金鑰和 JDBC 連接字串)。 設定 KeyVault FlexVolume 一節涵蓋秘密。
設定永續性記憶體
如果您的應用程式需要非揮發性記憶體,請設定一或多個 永續性磁碟區。
您可能想要使用掛接至 Tomcat 記錄目錄(/tomcat_logs)的 Azure 檔案儲存體 來建立永續性磁碟區,以集中保留記錄。 如需詳細資訊,請參閱在 Azure Kubernetes Service 中動態建立和使用永續性磁碟區搭配 Azure 檔案儲存體。
設定 KeyVault FlexVolume
建立 Azure KeyVault 並填入所有必要的秘密。 然後,設定 KeyVault FlexVolume ,讓 Pod 能夠存取這些秘密。
您必須修改啟動文本(startup.sh 在 容器 上的 Tomcat GitHub 存放庫中),才能將憑證匯入容器上的本機密鑰存放區。
移轉排程的工作
若要在 AKS 叢集上執行排程的工作,請視需要定義 Cron 作業 。
移轉後
既然您已將應用程式移轉至 AKS,您應該確認它如預期般運作。 完成之後,我們有一些建議可讓您的應用程式更原生雲端。
請考慮將 DNS 名稱新增至配置給輸入控制器或應用程式負載平衡器的 IP 位址。 如需詳細資訊,請參閱 在 Azure Kubernetes Service (AKS) 上搭配輸入控制器使用 TLS。
請考慮 為您的應用程式新增 HELM 圖表。 Helm 圖表可讓您將應用程式部署參數化,以供一組更多樣化的客戶使用和自定義。
設計和實作DevOps策略。 若要在提高開發速度的同時維護可靠性,請考慮 使用 Azure Pipelines 將部署和測試自動化。
啟用 叢集 的 Azure 監視,以允許收集容器記錄、追蹤使用率等等。
請考慮透過 Prometheus 公開應用程式特定計量。 Prometheus 是 Kubernetes 社群中廣泛採用的開放原始碼計量架構。 您可以在 Azure 監視器中設定 Prometheus 計量,而不是裝載自己的 Prometheus 伺服器,以啟用應用程式的計量匯總,以及自動回應或呈報異常狀況。
設計和實作商務持續性和災害復原策略。 針對任務關鍵性應用程式,請考慮 多區域部署架構。
檢閱 Kubernetes 版本支持原則。 您必須繼續 更新 AKS 叢集 ,以確保它一律執行支援的版本。
讓負責叢集管理和應用程式開發的所有小組成員檢閱相關的 AKS 最佳做法。
評估 logging.properties 檔案中的專案。 請考慮排除或減少一些記錄輸出以改善效能。
請考慮 監視程序代碼快取大小 ,並將 參數
-XX:InitialCodeCacheSize
和-XX:ReservedCodeCacheSize
新增至JAVA_OPTS
Dockerfile 中的變數,以進一步優化效能。