本文說明如何實作新式 Web 應用程式模式。 新式 Web 應用程式模式會定義如何將雲端 Web 應用程式現代化,並引進服務導向架構。 此模式提供規範的架構、程式代碼和組態指引,符合 Azure Well-Architected Framework
為什麼要使用新式 Web 應用程式模式?
新式 Web 應用程式模式可協助您優化 Web 應用程式的高需求區域。 它提供將這些區域分離的詳細指引,以針對成本優化啟用獨立調整。 此方法可讓您將專用資源配置給重要元件,以提升整體效能。 分離可分離的服務可以藉由防止應用程式中某個部分的變慢影響其他人,來改善可靠性。 它也會啟用個別應用程式元件的獨立版本控制。
如何實作新式 Web 應用程式模式
本文包含實作新式 Web 應用程式模式的指引。 使用下列連結來移至您需要的特定指引:
- 架構指引。 瞭解如何將 Web 應用程式元件模組化,並選取適當的平臺即服務 (PaaS) 解決方案。
- 程式代碼指引。 實作四種設計模式來優化分離元件:Strangler Fig、Queue-Based 負載撫平、競爭取用者和健康情況端點監視。
- 組態指引。 設定分離元件的驗證、授權、自動調整和容器化。
提示
新式 Web 應用程式模式有 參考實作(範例應用程式)。 它代表新式 Web 應用程式實作的結束狀態。 這是生產等級的 Web 應用程式,其功能包含本文所討論的所有程式代碼、架構和組態更新。 部署並使用參考實作來引導您實作新式 Web 應用程式模式。
架構指導
新式 Web 應用程式模式是以可靠的 Web 應用程式模式為基礎。 它需要一些額外的架構元件。 您需要消息佇列、容器平臺、記憶體服務和容器登錄,如下圖所示:
針對較高的服務等級目標 (SLO),您可以將第二個區域新增至 Web 應用程式架構。 根據您的業務需求,將您的負載平衡器設定為將流量路由傳送至第二個區域,以支持主動-主動或主動-被動設定。 這兩個區域需要相同的服務,但其中一個區域有中樞虛擬網路。 使用中樞和輪輻網路拓撲來集中和共用資源,例如網路防火牆。 透過中樞虛擬網路存取容器存放庫。 如果您有虛擬機,請將防禦主機新增至中樞虛擬網路,以增強安全性來管理它們。 下圖顯示此架構:
將架構分離
若要實作新式 Web 應用程式模式,您需要將現有的 Web 應用程式架構分離。 將架構分離需要將整合型應用程式分解成較小的獨立服務,每個服務都負責特定功能或函式。 此程式包括評估目前的 Web 應用程式、修改架構,最後將 Web 應用程式程式代碼擷取至容器平臺。 目標是要有系統地識別和擷取受益於分離的應用程式服務。 若要分離您的架構,請遵循下列建議:
識別服務界限。 套用網域驅動設計原則,以識別整合型應用程式內的限定內容。 每個限定內容都代表邏輯界限,而且是分離的候選專案。 代表不同商務功能且相依性較少的服務是很好的候選專案。
評估服務優點。 專注於受益於獨立調整的服務。 例如,LOB 應用程式中的電子郵件服務提供者之類的外部相依性可能需要與失敗隔離更多。 請考慮經常進行更新或變更的服務。 分離這些服務可讓獨立部署,並降低影響應用程式其他部分的風險。
評估技術可行性。 檢查目前的架構,以識別可能影響分離程序的技術條件約束和相依性。 規劃如何跨服務管理和共享數據。 分離的服務應該管理自己的數據,並將跨服務界限的直接數據庫存取降到最低。
部署 Azure 服務。 選取並部署您需要的 Azure 服務,以支援您想要擷取的 Web 應用程式服務。 如需指引,請參閱本文的 選取正確的 Azure 服務 一節。
將 Web 應用程式服務分離。 定義新擷取 Web 應用程式服務可用來與系統其他部分互動的清楚介面和 API。 設計數據管理策略,讓每個服務都能管理自己的數據,但可確保一致性和完整性。 如需在此擷取程式期間要使用的特定實作策略和設計模式,請參閱 程式代碼指引 一節。
針對分離的服務使用獨立記憶體。 若要簡化版本設定和部署,請確定每個分離的服務都有自己的數據存放區。 例如,參考實作會分隔電子郵件服務與 Web 應用程式,並不需要服務存取資料庫。 相反地,服務會透過 Azure 服務匯流排 訊息將電子郵件傳遞狀態傳回 Web 應用程式,而 Web 應用程式會將附註儲存至其資料庫。
為每個分離的服務實作個別的部署管線。 如果您實作個別的部署管線,則可以根據自己的排程來更新每個服務。 如果公司內的不同小組或組織擁有不同的服務,使用個別的部署管線可讓每個小組控制自己的部署。 使用 Jenkins、GitHub Actions 或 Azure Pipelines 等持續整合和持續傳遞 (CI/CD) 工具來設定這些管線。
修訂安全性控制。 請確定您的安全性控制已更新,以考慮新的架構,包括防火牆規則和訪問控制。
選取正確的 Azure 服務
如需架構中的每個 Azure 服務,請參閱架構完善的架構中的相關 Azure 服務指南 。 針對新式 Web 應用程式模式,您需要傳訊系統來支援異步傳訊、支援容器化的應用程式平臺,以及容器映射存放庫。
選擇消息佇列。 消息佇列是服務導向架構的重要元件。 它會分離訊息傳送者和接收者,以啟用 異步傳訊。 使用選擇 Azure 傳訊服務的 指引,挑選支援您設計需求的 Azure 傳訊系統。 Azure 有三個傳訊服務:Azure 事件方格、Azure 事件中樞 和 服務匯流排。 從服務總線開始,如果服務總線不符合您的需求,請使用另外兩個選項之一。
服務 使用案例 服務匯流排 選擇 服務匯流排,以取得企業應用程式中高價值訊息可靠、已排序且可能的交易式傳遞。 Event Grid 當您需要有效率地處理大量離散事件時,請選擇 [事件方格]。 事件方格可調整為事件驅動應用程式,其中許多小型獨立事件(例如資源狀態變更)必須在低延遲發佈-訂閱模型中路由傳送給訂閱者。 事件中樞 選擇事件中樞來擷取大量高輸送量的數據擷取,例如遙測、記錄或即時分析。 事件中樞已針對需要持續內嵌和處理大量數據的串流案例進行優化。 實作容器服務。 針對您想要容器化之應用程式的元素,您需要支援容器的應用程式平臺。 選擇 Azure 容器服務 指引可協助您選取一個。 Azure 有三個主要容器服務:Azure Container Apps、Azure Kubernetes Service (AKS)和 Azure App 服務。 從 Container Apps 開始,如果 Container Apps 不符合您的需求,請使用另外兩個選項之一。
服務 使用案例 容器應用程式 如果您需要自動調整和管理事件驅動應用程式中容器的無伺服器平臺,請選擇 [容器應用程式]。 AKS 如果您需要對 Kubernetes 設定和進階功能進行詳細控制,以調整、網路和安全性,請選擇 AKS。 適用於容器的 Web 應用程式 選擇 App Service 中適用於容器的 Web 應用程式,以取得最簡單的 PaaS 體驗。 實作容器存放庫。 當您使用容器型計算服務時,必須有存放庫來儲存容器映像。 您可以使用公用容器登錄,例如 Docker Hub 或 Azure Container Registry 之類的受控登錄。 Azure 中容器登錄的 簡介 指引可協助您選擇一個登錄。
程序代碼指引
若要成功分離並擷取獨立服務,您必須使用下列設計模式來更新 Web 應用程式程式代碼:Strangler Fig、Queue-Based 負載撫平、競爭取用者、健康情況端點監視和重試。 下圖顯示這些模式的角色:
Strangler Fig 模式:Strangler Fig 模式會以累加方式將功能從整合型應用程式移轉至分離服務。 在主要 Web 應用程式中實作此模式,藉由根據端點引導流量,逐漸將功能移轉至獨立服務。
佇列型負載撫平模式:佇列型負載撫平模式會使用佇列作為緩衝區來管理產生者和取用者之間的訊息流程。 在分離服務的產生者部分上實作此模式,以使用佇列以異步方式管理訊息流程。
競爭取用者模式:競爭取用者模式可讓分離服務的多個實例獨立讀取相同的消息佇列,並競爭以處理訊息。 在分離服務中實作此模式,以將工作分散到多個實例。
健全狀況端點監視模式:健康情況端點監視模式會公開端點,以監視 Web 應用程式不同元件的狀態和健康情況。 (4a) 在主要 Web 應用程式中實作此模式。 (4b) 也在分離服務中加以實作,以追蹤端點的健康情況。
重試模式:重試模式會重試間歇性失敗的作業來處理暫時性失敗。 (5a) 在主要 Web 應用程式中,在所有對其他 Azure 服務的輸出呼叫上實作此模式,例如對消息佇列和私人端點的呼叫。 (5b) 在分離服務中也實作此模式,以處理私人端點呼叫中的暫時性失敗。
每個設計模式都提供符合一或多個 Well-Architected 架構支柱的優點。 下表提供詳細數據。
設計模式 | 實作位置 | 可靠性 (RE) | 安全性 (SE) | 成本優化 (CO) | 卓越營運(OE) | 效能效率(PE) | 支持架構完善的架構原則 |
---|---|---|---|---|---|---|---|
Strangler Fig 圖樣 | 主要 Web 應用程式 | ✔ | ✔ | ✔ |
RE:08 CO:07 CO:08 OE:06 OE:11 |
||
基於佇列的負載調節模式 | 分離服務的產生者 | ✔ | ✔ | ✔ |
RE:06 RE:07 CO:12 PE:05 |
||
競爭取用者模式 | 分離服務 | ✔ | ✔ | ✔ |
RE:05 RE:07 CO:05 CO:07 PE:05 PE:07 |
||
健全狀況端點監視模式 | 主要 Web 應用程式和分離服務 | ✔ | ✔ | ✔ |
RE:07 RE:10 OE:07 PE:05 |
||
重試模式 | 主要 Web 應用程式和分離服務 | ✔ | RE:07 |
實作 Strangler Fig 模式
使用 Strangler Fig 模式,逐漸將功能從整合型程式代碼基底移轉至新的獨立服務。 從現有的整合型程式代碼基底擷取新的服務,並緩慢地將Web應用程式的重要部分現代化。 若要實作 Strangler Fig 模式,請遵循下列建議:
設定路由層。 在整合型 Web 應用程式程式代碼基底中,實作路由層,以根據端點導向流量。 視需要使用自定義路由邏輯來處理特定商務規則來引導流量。 例如,如果您的整合型應用程式中有一個
/users
端點,並將該功能移至分離的服務,路由層會將所有要求導向至/users
至新的服務。管理功能推出。實作功能旗標和分段推出,以逐漸推出分離的服務。 現有的整合型應用程式路由應該控制分離服務收到的要求數目。 從少量的要求開始,並隨著時間增加使用量,因為您對服務的穩定性和效能有信心。
例如,參考實作會將電子郵件傳遞功能擷取到獨立服務。 您可以逐漸引進此服務來處理包含 Contoso 支援指南之電子郵件的較大百分比要求。 隨著新服務證明其可靠性和效能,它最終可以從整合型接管整個電子郵件責任集,完成轉換。
使用外觀服務(如有必要)。 當單一要求需要與多個服務互動,或想要隱藏基礎系統的複雜性時,外觀服務就很有用。 不過,如果分離服務沒有任何公開的 API,則可能不需要外觀服務。
在整合型 Web 應用程式程式代碼基底中,實作外觀服務,將要求路由傳送至適當的後端(整合型或微服務)。 確定新的分離服務可以在透過外觀存取要求時獨立處理要求。
實作佇列型負載撫平模式
在 分離服務的產生者部分實作佇列型負載撫平模式 ,以異步方式處理不需要立即回應的工作。 此模式使用佇列來管理工作負載散發,藉此增強整體系統回應性和延展性。 它可讓分離服務以一致的速率處理要求。 若要有效地實作此模式,請遵循下列建議:
使用非封鎖消息佇列。 確定傳送訊息至佇列的進程不會在等候分離服務處理佇列中的訊息時封鎖其他進程。 如果進程需要分離服務作業的結果,請實作替代方式來處理等候佇列作業完成時的情況。 例如,在 Spring Boot 中,您可以使用
StreamBridge
類別,以異步方式將訊息發佈至佇列,而不會封鎖呼叫線程:private final StreamBridge streamBridge; public SupportGuideQueueSender(StreamBridge streamBridge) { this.streamBridge = streamBridge; } // Asynchronously publish a message without blocking the calling thread @Override public void send(String to, String guideUrl, Long requestId) { EmailRequest emailRequest = EmailRequest.newBuilder() .setRequestId(requestId) .setEmailAddress(to) .setUrlToManual(guideUrl) .build(); log.info("EmailRequest: {}", emailRequest); var message = emailRequest.toByteArray(); streamBridge.send(EMAIL_REQUEST_QUEUE, message); log.info("Message sent to the queue"); }
這個 Java 範例會使用
StreamBridge
異步傳送訊息。 此方法可確保主要應用程式保持回應,而且可以在分離的服務以可管理的速度處理佇列要求時,同時處理其他工作。實作訊息重試和移除。 實作機制,以重試無法成功處理的佇列訊息處理。 如果失敗持續發生,則應該從佇列中移除這些訊息。 例如,服務匯流排 具有內建的重試和寄不出的信件佇列功能。
設定等冪訊息處理。 處理來自佇列訊息的邏輯必須是等冪的,才能處理訊息可能多次處理的情況。 在 Spring Boot 中,您可以使用
@StreamListener
或@KafkaListener
搭配唯一訊息識別碼,以防止重複處理。 或者,您可以使用 Spring Cloud Stream 組織商務程式以運作方式運作,其中consume
方法是以重複執行時產生相同結果的方式定義。 如需管理訊息取用行為的設定清單,請參閱使用服務總線Spring Cloud Stream。 管理用戶體驗的變更。 當您使用異步處理時,工作可能不會立即完成。 若要設定預期並避免混淆,請確定使用者知道工作何時仍在處理中。 使用視覺提示或訊息來指出工作正在進行中。 提供使用者在工作完成時接收通知的選項,例如電子郵件或推播通知。
實作競爭取用者模式
在 分離服務中實作競爭取用者模式 ,以管理來自消息佇列的連入工作。 此模式牽涉到將工作分散到多個分離服務實例。 這些服務會處理來自佇列的訊息。 此模式可增強負載平衡,並增加系統處理同時要求的容量。 競爭取用者模式在下列情況下有效:
- 訊息處理的順序並不重要。
- 佇列不會受到格式不正確的訊息影響。
- 處理作業是等冪的,這表示它可以多次套用,而不需要在初始應用程式之後變更結果。
若要實作競爭取用者模式,請遵循下列建議:
處理並行訊息。 當服務從佇列接收訊息時,請藉由設定並行以符合系統設計的方式,確保系統可預測地進行調整。 負載測試結果可協助您判斷要處理的並行訊息數目。 您可以從一個開始測量系統的執行方式。
停用預先擷取。 停用預先擷取訊息,讓取用者在準備好時只擷取訊息。
使用可靠的訊息處理模式。 使用可靠的處理模式,例如 Peek-Lock,可自動重試處理失敗的訊息。 此模式比刪除優先方法更可靠。 如果某個背景工作角色無法處理訊息,則即使訊息已處理多次,另一個背景工作角色也必須能夠處理該訊息,而不會發生錯誤。
實作錯誤處理。 將格式不正確或無法處理的訊息路由傳送至個別的寄不出的信件佇列。 此設計可防止重複處理。 例如,您可以在訊息處理期間攔截例外狀況,並將有問題的訊息移至不同的佇列。 使用服務總線時,訊息會在指定的傳遞嘗試次數或應用程式明確拒絕時,移至寄不出的佇列。
處理順序錯誤的訊息。 設計取用者來處理依序抵達的訊息。 當您有多個平行取用者時,它們可能會依序處理訊息。
根據佇列長度進行調整。 從佇列取用訊息的服務應該根據佇列長度自動調整。 調整型自動調整可有效處理傳入訊息的尖峰。
使用訊息回復佇列。 如果您的系統需要訊息後置處理的通知,請設定專用的回復或回應佇列。 此設定會將作業傳訊與通知程式分開。
使用無狀態服務。 請考慮使用無狀態服務來處理來自佇列的要求。 這麼做可讓您輕鬆調整資源,並有效率地使用資源。
設定記錄。 在訊息處理工作流程中整合記錄和特定例外狀況處理。 專注於擷取串行化錯誤,並將這些有問題的訊息導向死信機制。 這些記錄提供寶貴的深入解析以進行疑難解答。
參考實作會在 Container Apps 中執行的無狀態服務上使用競爭取用者模式,來處理來自服務總線佇列的電子郵件傳遞要求。
處理器會記錄訊息處理詳細數據,以協助進行疑難解答和監視。 它會擷取還原串行化錯誤,並提供在偵錯期間很有用的見解。 服務會在容器層級進行調整,以根據佇列長度有效處理訊息尖峰。 以下是程式代碼:
@Configuration
public class EmailProcessor {
private static final Logger log = LoggerFactory.getLogger(EmailProcessor.class);
@Bean
Function<byte[], byte[]> consume() {
return message -> {
log.info("New message received");
try {
EmailRequest emailRequest = EmailRequest.parseFrom(message);
log.info("EmailRequest: {}", emailRequest);
EmailResponse emailResponse = EmailResponse.newBuilder()
.setEmailAddress(emailRequest.getEmailAddress())
.setUrlToManual(emailRequest.getUrlToManual())
.setRequestId(emailRequest.getRequestId())
.setMessage("Email sent to " + emailRequest.getEmailAddress() + " with URL to manual " + emailRequest.getUrlToManual())
.setStatus(Status.SUCCESS)
.build();
return emailResponse.toByteArray();
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException("Error parsing email request message", e);
}
};
}
}
實作健全狀況端點監視模式
在 主要應用程式程式代碼和分離的服務程式代碼中實作健全狀況端點監視模式 ,以追蹤應用程式端點的健康情況。 AKS 或 Container Apps 等協調器可以輪詢這些端點,以確認服務健康情況並重新啟動狀況不良的實例。 Spring Boot 執行器提供健康情況檢查的內建支援。 它可以公開金鑰相依性的健全狀況檢查端點,例如資料庫、訊息代理程式和記憶體系統。 若要實作健全狀況端點監視模式,請遵循下列建議:
實作健康情況檢查。 使用 Spring Boot 執行器提供健康情況檢查端點。 執行器會公開
/actuator/health
端點,其中包含內建的健康情況指標和各種相依性的自定義檢查。 若要啟用健康情況端點,請在pom.xml
或build.gradle
檔案中新增spring-boot-starter-actuator
相依性:<!-- Add Spring Boot Actuator dependency --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
在
application.properties
中設定健康情況端點,如參考實作所示:management.endpoints.web.exposure.include=metrics,health,info,retry,retryevents
驗證相依性。 Spring Boot 執行器包含各種相依性的健康情況指標,例如資料庫、訊息代理程式(RabbitMQ 或 Kafka),以及記憶體服務。 若要驗證 Azure Blob 記憶體或服務總線等 Azure 服務的可用性,請使用 Azure Spring Apps 或 Micrometer 等技術,為這些服務提供健康情況指標。 如果您需要自定義檢查,您可以藉由建立自訂
HealthIndicator
豆來實作它們:import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; @Component public class CustomAzureServiceBusHealthIndicator implements HealthIndicator { @Override public Health health() { // Implement your health check logic here (for example, ping Service Bus). boolean isServiceBusHealthy = checkServiceBusHealth(); return isServiceBusHealthy ? Health.up().build() : Health.down().build(); } private boolean checkServiceBusHealth() { // Implement health check logic (pinging or connecting to the service). return true; // Placeholder. Implement the actual logic. } }
設定 Azure 資源。 設定 Azure 資源以使用應用程式的健康情況檢查 URL 來確認即時性和整備程度。 例如,您可以使用 Terraform 來確認部署至容器應用程式之應用程式的活躍度和整備程度。 如需詳細資訊,請參閱 容器應用程式中的健康情況探查。
實作重試模式
重試模式 可讓應用程式從暫時性錯誤復原。 此模式是 Reliable Web 應用程式模式的核心,因此您的 Web 應用程式應該已經使用重試模式。 將重試模式套用至訊息系統的要求,以及您從 Web 應用程式擷取的分離服務所發出的要求。 若要實作重試模式,請遵循下列建議:
設定重試選項。 請務必使用適當的重試設定,設定負責與消息佇列互動的用戶端。 指定參數,例如重試次數上限、重試之間的延遲,以及最大延遲。
使用指數輪詢。 針對重試嘗試實作指數輪詢策略。 此策略牽涉到以指數方式增加每次重試之間的時間,這有助於在高失敗率期間減少系統上的負載。
使用 SDK 重試功能。 對於具有特殊 SDK 的服務,例如服務總線或 Blob 記憶體,請使用內建的重試機制。 這些內建機制已針對服務的典型使用案例進行優化,可以更有效率地處理重試,而且需要較少的設定。
針對 HTTP 用戶端使用標準復原連結庫。 針對 HTTP 用戶端,您可以使用 Resilience4j 搭配 Spring 的 RestTemplate 或 WebClient 來處理 HTTP 通訊中的重試。 您可以使用 Resilience4j 的重試邏輯來包裝 RestTemplate,以有效處理暫時性 HTTP 錯誤。
處理訊息鎖定。 針對訊息型系統,實作支援重試且不會遺失數據的訊息處理策略。 例如,當可用時,請使用查看鎖定模式。 請確定失敗的訊息會有效重試,並在重複失敗後移至寄不出的信件佇列。
設定指引
下列各節提供實作組態更新的指引。 每個區段都與 Well-Architected Framework 的一或多個支柱對齊。
組態 | 可靠性 (RE) | 安全性 (SE) | 成本優化 (CO) | 卓越營運(OE) | 效能效率(PE) | 支持架構完善的架構原則 |
---|---|---|---|---|---|---|
設定驗證和授權 | ✔ | ✔ |
SE:05 OE:10 |
|||
實作獨立的自動調整 | ✔ | ✔ | ✔ |
RE:06 CO:12 PE:05 |
||
容器化服務部署 | ✔ | ✔ |
CO:13 PE:09 PE:03 |
設定驗證和授權
若要在新增至 Web 應用程式的任何新 Azure 服務上設定驗證和授權(工作負載身分識別),請遵循下列建議:
針對每個新服務使用受控識別。 每個獨立服務都應該有自己的身分識別,並使用受控識別進行服務對服務驗證。 受控識別不需要管理程式碼中的認證,並降低認證外泄的風險。 它們可協助您避免在程式碼或組態檔中包含連接字串等敏感性資訊。
將最低許可權授與每個新服務。 僅將必要許可權指派給每個新的服務身分識別。 例如,如果身分識別只需要推送至容器登錄,請勿授與提取許可權。 請定期檢閱這些許可權,並視需要加以調整。 針對不同的角色使用不同的身分識別,例如部署和應用程式。 這樣做會限制一個身分識別遭到入侵時的潛在損害。
使用基礎結構即程序代碼 (IaC)。 使用 Bicep 或類似的 IaC 工具,例如 Terraform 來定義和管理您的雲端資源。 IaC 可確保部署中安全性設定的一致應用,並可讓您控制基礎結構設定的版本控制。
若要設定使用者(使用者身分識別)的驗證和授權,請遵循下列建議:
將最低許可權授與使用者。 如同服務,請確定使用者只有執行其工作所需的許可權。 定期檢閱並調整這些許可權。
定期進行安全性稽核。 定期檢閱和稽核您的安全性設定。 尋找錯誤設定和不必要的許可權,並立即加以修正或移除。
參考實作會使用 IaC 將受控識別指派給每個身分識別新增服務和特定角色。 它會定義容器登錄推送和提取的角色,以定義部署的角色和許可權存取權。 以下是程式代碼:
resource "azurerm_role_assignment" "container_app_acr_pull" {
principal_id = var.aca_identity_principal_id
role_definition_name = "AcrPull"
scope = azurerm_container_registry.acr.id
}
resource "azurerm_user_assigned_identity" "container_registry_user_assigned_identity" {
name = "ContainerRegistryUserAssignedIdentity"
resource_group_name = var.resource_group
location = var.location
}
resource "azurerm_role_assignment" "container_registry_user_assigned_identity_acr_pull" {
scope = azurerm_container_registry.acr.id
role_definition_name = "AcrPull"
principal_id = azurerm_user_assigned_identity.container_registry_user_assigned_identity.principal_id
}
# For demo purposes, allow the current user to access the container registry.
# Note: When running as a service principal, this is also needed.
resource "azurerm_role_assignment" "acr_contributor_user_role_assignement" {
scope = azurerm_container_registry.acr.id
role_definition_name = "Contributor"
principal_id = data.azuread_client_config.current.object_id
}
設定獨立的自動調整
新式 Web 應用程式模式會開始分解整合型架構,並引進服務分離。 當您分離 Web 應用程式架構時,您可以獨立調整分離的服務。 調整 Azure 服務以支援獨立的 Web 應用程式服務,而不是整個 Web 應用程式,將調整成本優化,同時符合需求。 若要自動調整容器,請遵循下列建議:
使用無狀態服務。 請確定您的服務是無狀態的。 如果您的 Web 應用程式包含行程內工作階段狀態,請將它外部化為 Redis 之類的分散式快取,或 SQL Server 之類的資料庫。
設定自動調整規則。 使用自動調整組態,為您的服務提供最符合成本效益的控制。 針對容器化服務,事件型調整,例如 Kubernetes Event-Driven Autoscaler (KEDA),通常會提供細微的控制,可讓您根據事件計量進行調整。 容器應用程式和 AKS 支援 KEDA。 對於不支援 KEDA 的服務,例如 App Service,請使用平臺本身所提供的自動調整功能。 這些功能通常包括根據計量型規則或 HTTP 流量進行調整。
設定最小復本。 若要防止冷啟動,請設定自動調整設定,以維持至少一個複本。 冷啟動是從已停止狀態初始化服務。 冷啟動通常會延遲回應。 如果最小化成本是優先順序,而且您可以容忍冷啟動延遲,請在設定自動調整時,將復本計數下限設定為 0。
設定冷卻期間。 套用適當的冷卻期間,以在調整事件之間引入延遲。 目標是 防止暫時負載尖峰觸發的過度調整 活動。
設定佇列型調整。 如果您的應用程式使用服務總線之類的消息佇列,請設定自動調整設定,以根據要求消息佇列的長度進行調整。 縮放程式會嘗試針對佇列中每個 N 訊息維護一個服務複本(四捨五入)。
例如,參考實作會使用 服務匯流排 KEDA 縮放程式,根據 服務匯流排 佇列的長度自動調整容器應用程式。 名為 service-bus-queue-length-rule
的縮放規則會根據指定服務總線佇列中的訊息計數來調整服務複本數目。
messageCount
參數會設定為10,這會設定縮放程式為佇列中每10則訊息新增一個複本。 複本計數上限 (max_replicas
) 設定為 10。 除非覆寫最小復本計數,否則會隱含為 0。 此設定可讓服務在佇列中沒有任何訊息時相應減少為零。 服務總線佇列的連接字串會儲存為 Azure 中的秘密,名為 azure-servicebus-connection-string
,用來向服務總線驗證縮放程式。 以下是 Terraform 程式代碼:
max_replicas = 10
min_replicas = 1
custom_scale_rule {
name = "service-bus-queue-length-rule"
custom_rule_type = "azure-servicebus"
metadata = {
messageCount = 10
namespace = var.servicebus_namespace
queueName = var.email_request_queue_name
}
authentication {
secret_name = "azure-servicebus-connection-string"
trigger_parameter = "connection"
}
}
容器化服務部署
容器化是應用程式在輕量型映射中所需的所有相依性封裝,可可靠地部署到各種主機。 若要容器化部署,請遵循下列建議:
識別網域界限。 從識別整合型應用程式中的網域界限開始。 這樣做可協助您判斷您可以擷取至個別服務的應用程式部分。
建立 Docker 映像。 當您建立 Java 服務的 Docker 映射時,請使用官方 OpenJDK 基底映射。 這些映像只包含 Java 需要執行的最小套件集。 使用這些影像可將封裝大小和受攻擊介面區降到最低。
使用多階段 Dockerfiles。 使用多階段 Dockerfile 來分隔建置時間資產與運行時間容器映射。 使用此類型的檔案有助於讓您的生產映像保持小型且安全。 您也可以使用預先設定的組建伺服器,並將 JAR 檔案複製到容器映射中。
以非根使用者身分執行。 以非根使用者身分執行 Java 容器(透過使用者名稱或 UID $APP_UID),以符合最低許可權原則。 這樣做會限制遭入侵容器的潛在影響。
接聽埠 8080。 當您以非根使用者身分執行容器時,請將應用程式設定為接聽埠 8080。 這是非根用戶常見的慣例。
封裝相依性。 確定應用程式所需的所有相依性都會封裝在 Docker 容器映像中。 封裝可讓應用程式可靠地部署到各種主機。
選擇正確的基底映像。 您選擇的基底映像取決於您的部署環境。 例如,如果您部署至 Container Apps,則需要使用 Linux Docker 映射。
參考實作示範用於容器化 Java 應用程式的 Docker 建置程式。 Dockerfile 會使用具有 OpenJDK 基底映射的單一階段組建(mcr.microsoft.com/openjdk/jdk:17-ubuntu
),以提供必要的 Java 運行時間環境。
Dockerfile 包含下列步驟:
- 宣告磁碟區。 定義暫存磁碟區 (
/tmp
)。 此磁碟區提供與容器主要文件系統分開的暫存盤記憶體。 - 複製成品。 應用程式的 JAR 檔案(
email-processor.jar
)會複製到容器中,以及用於監視的 Application Insights 代理程式(applicationinsights-agent.jar
)。 - 設定進入點。 容器已設定為執行已啟用ApplicationInsights代理程式的應用程式。 程式代碼會使用
java -javaagent
在運行時間監視應用程式。
Dockerfile 只會包含運行時間相依性,讓映像保持很小。 它適用於支援Linux型容器的容器應用程式等部署環境。
# Use the OpenJDK 17 base image on Ubuntu as the foundation.
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu
# Define a volume to allow temporary files to be stored separately from the container's main file system.
VOLUME /tmp
# Copy the packaged JAR file into the container.
COPY target/email-processor.jar app.jar
# Copy the Application Insights agent for monitoring.
COPY target/agent/applicationinsights-agent.jar applicationinsights-agent.jar
# Set the entrypoint to run the application with the Application Insights agent.
ENTRYPOINT ["java", "-javaagent:applicationinsights-agent.jar", "-jar", "/app.jar"]
部署參考實作
部署適用於 Java 的新式 Web 應用程式模式參考實作。 存放庫中有開發和生產部署的指示。 部署實作之後,您可以模擬並觀察設計模式。
下圖顯示參考實作的架構:
下載此架構的 Visio 檔案。