本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
AWS App Mesh 和 Amazon 入門 EC2
重要
支援終止通知:2026 年 9 月 30 日 AWS 將停止對 的支援 AWS App Mesh。2026 年 9 月 30 日後,您將無法再存取 AWS App Mesh 主控台或 AWS App Mesh 資源。如需詳細資訊,請造訪此部落格文章,從 遷移 AWS App Mesh 至 Amazon ECS Service Connect
本主題可協助您 AWS App Mesh 在 Amazon 上執行的實際服務使用 EC2。本教學課程涵蓋多種 App Mesh 資源類型的基本功能。
案例
若要說明如何使用 App Mesh,請假設您有具有下列特性的應用程式:
-
由兩個名為
serviceA
和 的服務組成serviceB
。 -
這兩個服務都註冊到名稱為
apps.local
的命名空間。 -
ServiceA
與serviceB
超過 HTTP/2、連接埠 80 通訊。 -
您已部署
serviceB
第 2 版,並在apps.local
命名空間中將其註冊為名稱serviceBv2
。
您有以下要求:
-
您想要將 75% 的流量從
serviceA
傳送至serviceB
,並將 25% 的流量serviceBv2
首先傳送至 。透過僅將 25% 傳送到serviceBv2
,您可以在從 傳送 100% 流量之前驗證其是否無錯誤serviceA
。 -
您希望能夠輕鬆地調整流量權重,以便證實流量可靠之後,能夠 100% 流入
serviceBv2
。將所有流量傳送到 後serviceBv2
,您想要停止serviceB
。 -
您不想變更實際服務的任何現有應用程式碼或服務探索註冊,以符合先前的要求。
為了滿足您的需求,您決定建立具有虛擬服務、虛擬節點、虛擬路由器和路由的 App Mesh 服務網格。實作網格後,您將更新服務以使用 Envoy 代理。一旦更新,您的服務會透過 Envoy 代理彼此通訊,而非直接相互通訊。
必要條件
App Mesh 支援已向 DNS AWS Cloud Map、 或兩者註冊的 Linux 服務。若要使用此入門指南,我們建議您有三項已在 註冊的現有服務DNS。即使服務不存在,您也可以建立服務網格及其資源,但在部署實際服務之前,您無法使用網格。
如果您尚未執行服務,您可以啟動 Amazon EC2執行個體,並將應用程式部署到這些執行個體。如需詳細資訊,請參閱 Amazon 使用者指南中的教學課程:Amazon EC2 Linux 執行個體入門。 EC2其餘步驟假設實際服務名稱為 serviceA
、serviceB
和 serviceBv2
,而且所有服務皆可透過名稱為 apps.local
的命名空間探索。
步驟 1:建立網格和虛擬服務
服務網格是在它之內各服務之間網路流量的邏輯邊界。如需詳細資訊,請參閱服務網格。虛擬服務是實際服務的抽象化。如需詳細資訊,請參閱虛擬服務。
建立下列資源:
-
名稱為
apps
的網格,因為案例中的所有服務皆註冊到apps.local
命名空間。 -
名稱為
serviceb.apps.local
的虛擬服務,因為虛擬服務代表可使用該名稱探索的服務,而且您不想將程式碼變更為參照其他名稱。稍後的步驟會新增名稱為servicea.apps.local
的虛擬服務。
您可以使用 AWS Management Console 或 1.18 AWS CLI .116 或更新版本或 2.0.38 或更新版本來完成下列步驟。如果使用 AWS CLI,請使用 aws --version
命令來檢查已安裝的 AWS CLI 版本。如果您沒有安裝 1.18.116 或更新版本或 2.0.38 或更新版本,則必須安裝或更新 AWS CLI。為您要使用的工具選取索引標籤。
步驟 2:建立虛擬節點
虛擬節點可做為實際服務的邏輯指標。如需詳細資訊,請參閱虛擬節點。
建立名稱為 serviceB
的虛擬節點,因為其中一個虛擬節點代表名稱為 serviceB
的實際服務。虛擬節點代表的實際服務可透過 DNS
(主機名稱為 serviceb.apps.local
) 探索。或者,您可以使用 AWS Cloud Map探索實際服務。虛擬節點會使用連接埠 80 上的 HTTP/2 通訊協定接聽流量。也支援其他通訊協定,以及運作狀態檢查。您可以在稍後的步驟serviceBv2
中為 serviceA
和 建立虛擬節點。
步驟 3:建立虛擬路由器和路由
虛擬路由器會路由網格內一或多個虛擬服務的流量。如需詳細資訊,請參閱 虛擬路由器 和 路由。
建立下列資源:
-
名為
serviceB
的虛擬路由器,因為serviceB.apps.local
虛擬服務不會啟動與任何其他服務的對外通訊。請記住,您先前建立的虛擬服務是實際serviceb.apps.local
服務的抽象。虛擬服務會將流量傳送至虛擬路由器。虛擬路由器會使用連接埠 80 上的 HTTP/2 通訊協定接聽流量。也支援其他通訊協定。 -
名為
serviceB
的路由。它將 100% 的流量路由到serviceB
虛擬節點。新增serviceBv2
虛擬節點後,權重會進入後續步驟。雖然未涵蓋在本指南中,但您可以為路由新增其他篩選條件,並新增重試政策,使 Envoy 代理在遇到通訊問題時多次嘗試將流量傳送至虛擬節點。
步驟 4:檢閱和建立
依照先前的指示檢閱設定。
步驟 5:建立其他資源
若要完成案例,您必須:
-
建立一個名為
serviceBv2
的虛擬節點,以及另一個名為serviceA
的虛擬節點。兩個虛擬節點都會接聽 HTTP/2 連接埠 80 上的請求。針對serviceA
虛擬節點,設定後端的serviceb.apps.local
。來自serviceA
虛擬節點的所有傳出流量都會傳送至名為 的虛擬服務serviceb.apps.local
。雖然未涵蓋在本指南中,但您也可以指定將虛擬節點的存取日誌寫入其中的檔案路徑。 -
建立名為 的其他虛擬服務
servicea.apps.local
,將所有流量直接傳送至serviceA
虛擬節點。 -
更新您在上一個步驟中建立的
serviceB
路由,將 75% 的流量傳送到serviceB
虛擬節點,以及 25% 的流量傳送到serviceBv2
虛擬節點。隨著時間的推移,您可以繼續修改權重,直到serviceBv2
收到 100% 的流量為止。將所有流量傳送到 後serviceBv2
,您可以關閉並停止serviceB
虛擬節點和實際服務。當您更改權重時,您的程式碼不需要任何修改,因為serviceb.apps.local
虛擬和實際服務名稱不會變更。記住,serviceb.apps.local
虛擬服務會將流量傳送至虛擬路由器,接著虛擬路由器會將流量路由至虛擬節點。虛擬節點的服務探索名稱可以隨時變更。
網格摘要
在您建立服務網格之前,您有三個名稱為 servicea.apps.local
、serviceb.apps.local
和 servicebv2.apps.local
的實際服務。除了實際服務以外,您目前擁有包含代表實際服務之下列資源的服務網格:
-
兩個虛擬服務。代理會透過虛擬路由器將
servicea.apps.local
虛擬服務的所有流量傳送至serviceb.apps.local
虛擬服務。 -
名稱為
serviceA
、serviceB
和serviceBv2
的三個虛擬節點。Envoy 代理會使用針對虛擬節點設定的服務探索資訊,來查詢實際服務的 IP 地址。 -
具有單一路由的虛擬路由器,其指示 Envoy 代理將 75% 的傳入流量路由到
serviceB
虛擬節點,將 25% 的流量路由到serviceBv2
虛擬節點。
步驟 6:更新服務
在建立網格之後,您需要完成下列任務:
-
授權您隨每個服務一起部署的 Envoy 代理,以讀取一或多個虛擬節點的組態。如需如何授權代理的詳細資訊,請參閱 Envoy Proxy 授權。
-
若要更新現有的服務,請完成下列步驟。
將 Amazon EC2執行個體設定為虛擬節點成員
-
建立 IAM 角色。
-
使用下列內容建立名為
ec2-trust-relationship.json
的檔案。{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
-
使用下列命令建立IAM角色。
aws iam create-role --role-name
mesh-virtual-node-service-b
--assume-role-policy-document file://ec2-trust-relationship.json
-
-
將IAM政策連接至角色,允許其從 Amazon 讀取,ECR並只讀取特定 App Mesh 虛擬節點的組態。
-
使用下列內容建立名為
virtual-node-policy.json
的檔案。apps
是您在 步驟 1:建立網格和虛擬服務 建立的網格名稱,而serviceB
是您在 步驟 2:建立虛擬節點 建立的虛擬節點名稱。Replace (取代)111122223333
使用您的帳戶 ID 和us-west-2
您建立網格的區域。{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "appmesh:StreamAggregatedResources", "Resource": [ "arn:aws:appmesh:
us-west-2
:111122223333
:mesh/apps
/virtualNode/serviceB
" ] } ] } -
使用下列命令建立政策。
aws iam create-policy --policy-name
virtual-node-policy
--policy-document file://virtual-node-policy.json -
將您在上一個步驟中建立的政策連接到角色,以便角色只能從 App Mesh 讀取
serviceB
虛擬節點的組態。aws iam attach-role-policy --policy-arn arn:aws:iam::
111122223333
:policy/virtual-node-policy --role-namemesh-virtual-node-service-b
-
將
AmazonEC2ContainerRegistryReadOnly
受管政策連接至角色,以便從 Amazon 提取 Envoy 容器映像ECR。aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly --role-name
mesh-virtual-node-service-b
-
-
使用您建立IAM的角色啟動 Amazon EC2執行個體。
-
透過 連線至您的執行個體SSH。
-
根據您的作業系統文件,在執行個體 AWS CLI 上安裝 Docker 和 。
-
驗證至您希望 Docker 用戶端從中提取映像的區域中的 Envoy Amazon ECR儲存庫。
-
除了
me-south-1
、ap-east-1
、、ap-southeast-3
eu-south-1
、il-central-1
和 以外的所有區域af-south-1
。您可以取代us-west-2
除了me-south-1
、ap-east-1
、、ap-southeast-3
eu-south-1
、il-central-1
和 以外的任何支援區域af-south-1
。$
aws ecr get-login-password \ --region
us-west-2
\ | docker login \ --username AWS \ --password-stdin 840364872350.dkr.ecr.us-west-2
.amazonaws.com -
me-south-1
區域$
aws ecr get-login-password \ --region me-south-1 \ | docker login \ --username AWS \ --password-stdin 772975370895.dkr.ecr.me-south-1.amazonaws.com
-
ap-east-1
區域$
aws ecr get-login-password \ --region ap-east-1 \ | docker login \ --username AWS \ --password-stdin 856666278305.dkr.ecr.ap-east-1.amazonaws.com
-
-
執行下列其中一個命令,以啟動執行個體上的 App Mesh Envoy 容器,視您要從哪個區域提取映像而定。所以此
apps
以及serviceB
值是案例中定義的網格和虛擬節點名稱。此資訊會告訴代理程式要從 App Mesh 讀取哪些虛擬節點組態。若要完成案例,您也需要為託管serviceBv2
和serviceA
虛擬節點所代表之服務的 Amazon EC2執行個體完成這些步驟。對於您自己的應用程式,將這些值取代為您自己的值。-
除了
me-south-1
、ap-east-1
、、ap-southeast-3
eu-south-1
、il-central-1
和 以外的所有區域af-south-1
。您可以取代Region-code
除了me-south-1
、ap-east-1
、ap-southeast-3
、、eu-south-1
il-central-1
和 區域以外的任何支援af-south-1
區域。您可以將
換成1337
0
到2147483647
之間的任何值。sudo docker run --detach --env APPMESH_RESOURCE_ARN=
mesh/
\ -uapps
/virtualNode/serviceB
1337
--network host 840364872350.dkr.ecr.region-code
.amazonaws.com/aws-appmesh-envoy:v1.29.9.0-prod -
me-south-1
區域。您可以將
換成1337
0
到2147483647
之間的任何值。sudo docker run --detach --env APPMESH_RESOURCE_ARN=
mesh/
\ -uapps
/virtualNode/serviceB
1337
--network host 772975370895.dkr.ecr.me-south-1.amazonaws.com/aws-appmesh-envoy:v1.29.9.0-prod -
ap-east-1
區域。您可以將
換成1337
0
到2147483647
之間的任何值。sudo docker run --detach --env APPMESH_RESOURCE_ARN=
mesh/
\ -uapps
/virtualNode/serviceB
1337
--network host 856666278305.dkr.ecr.ap-east-1.amazonaws.com/aws-appmesh-envoy:v1.29.9.0-prod
注意
APPMESH_RESOURCE_ARN
屬性需要版本1.15.0
或更新版本的 Envoy 映像。如需詳細資訊,請參閱Envoy 映像。重要
僅支援 v1.9.0.0 版或更新版本搭配 App Mesh 使用。
-
請在下方選取
Show more
。使用下列命令在您的執行個體上建立名為envoy-networking.sh
的檔案。Replace (取代)8000
您的應用程式程式碼用於傳入流量的連接埠。您可以變更APPMESH_IGNORE_UID
的值,但值必須與您在上一個步驟中指定的值相同;例如1337
。如有必要,您可以新增其他地址到APPMESH_EGRESS_IGNORED_IP
。請勿修改任何其他行。#!/bin/bash -e # # Start of configurable options # #APPMESH_START_ENABLED="0" APPMESH_IGNORE_UID="
1337
" APPMESH_APP_PORTS="8000
" APPMESH_ENVOY_EGRESS_PORT="15001" APPMESH_ENVOY_INGRESS_PORT="15000" APPMESH_EGRESS_IGNORED_IP="169.254.169.254,169.254.170.2" # Enable routing on the application start. [ -z "$APPMESH_START_ENABLED" ] && APPMESH_START_ENABLED="0" # Enable IPv6. [ -z "$APPMESH_ENABLE_IPV6" ] && APPMESH_ENABLE_IPV6="0" # Egress traffic from the processess owned by the following UID/GID will be ignored. if [ -z "$APPMESH_IGNORE_UID" ] && [ -z "$APPMESH_IGNORE_GID" ]; then echo "Variables APPMESH_IGNORE_UID and/or APPMESH_IGNORE_GID must be set." echo "Envoy must run under those IDs to be able to properly route it's egress traffic." exit 1 fi # Port numbers Application and Envoy are listening on. if [ -z "$APPMESH_ENVOY_EGRESS_PORT" ]; then echo "APPMESH_ENVOY_EGRESS_PORT must be defined to forward traffic from the application to the proxy." exit 1 fi # If an app port was specified, then we also need to enforce the proxies ingress port so we know where to forward traffic. if [ ! -z "$APPMESH_APP_PORTS" ] && [ -z "$APPMESH_ENVOY_INGRESS_PORT" ]; then echo "APPMESH_ENVOY_INGRESS_PORT must be defined to forward traffic from the APPMESH_APP_PORTS to the proxy." exit 1 fi # Comma separated list of ports for which egress traffic will be ignored, we always refuse to route SSH traffic. if [ -z "$APPMESH_EGRESS_IGNORED_PORTS" ]; then APPMESH_EGRESS_IGNORED_PORTS="22" else APPMESH_EGRESS_IGNORED_PORTS="$APPMESH_EGRESS_IGNORED_PORTS,22" fi # # End of configurable options # function initialize() { echo "=== Initializing ===" if [ ! -z "$APPMESH_APP_PORTS" ]; then iptables -t nat -N APPMESH_INGRESS if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then ip6tables -t nat -N APPMESH_INGRESS fi fi iptables -t nat -N APPMESH_EGRESS if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then ip6tables -t nat -N APPMESH_EGRESS fi } function enable_egress_routing() { # Stuff to ignore [ ! -z "$APPMESH_IGNORE_UID" ] && \ iptables -t nat -A APPMESH_EGRESS \ -m owner --uid-owner $APPMESH_IGNORE_UID \ -j RETURN [ ! -z "$APPMESH_IGNORE_GID" ] && \ iptables -t nat -A APPMESH_EGRESS \ -m owner --gid-owner $APPMESH_IGNORE_GID \ -j RETURN [ ! -z "$APPMESH_EGRESS_IGNORED_PORTS" ] && \ for IGNORED_PORT in $(echo "$APPMESH_EGRESS_IGNORED_PORTS" | tr "," "\n"); do iptables -t nat -A APPMESH_EGRESS \ -p tcp \ -m multiport --dports "$IGNORED_PORT" \ -j RETURN done if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then # Stuff to ignore ipv6 [ ! -z "$APPMESH_IGNORE_UID" ] && \ ip6tables -t nat -A APPMESH_EGRESS \ -m owner --uid-owner $APPMESH_IGNORE_UID \ -j RETURN [ ! -z "$APPMESH_IGNORE_GID" ] && \ ip6tables -t nat -A APPMESH_EGRESS \ -m owner --gid-owner $APPMESH_IGNORE_GID \ -j RETURN [ ! -z "$APPMESH_EGRESS_IGNORED_PORTS" ] && \ for IGNORED_PORT in $(echo "$APPMESH_EGRESS_IGNORED_PORTS" | tr "," "\n"); do ip6tables -t nat -A APPMESH_EGRESS \ -p tcp \ -m multiport --dports "$IGNORED_PORT" \ -j RETURN done fi # The list can contain both IPv4 and IPv6 addresses. We will loop over this list # to add every IPv4 address into `iptables` and every IPv6 address into `ip6tables`. [ ! -z "$APPMESH_EGRESS_IGNORED_IP" ] && \ for IP_ADDR in $(echo "$APPMESH_EGRESS_IGNORED_IP" | tr "," "\n"); do if [[ $IP_ADDR =~ .*:.* ]] then [ "$APPMESH_ENABLE_IPV6" == "1" ] && \ ip6tables -t nat -A APPMESH_EGRESS \ -p tcp \ -d "$IP_ADDR" \ -j RETURN else iptables -t nat -A APPMESH_EGRESS \ -p tcp \ -d "$IP_ADDR" \ -j RETURN fi done # Redirect everything that is not ignored iptables -t nat -A APPMESH_EGRESS \ -p tcp \ -j REDIRECT --to $APPMESH_ENVOY_EGRESS_PORT # Apply APPMESH_EGRESS chain to non local traffic iptables -t nat -A OUTPUT \ -p tcp \ -m addrtype ! --dst-type LOCAL \ -j APPMESH_EGRESS if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then # Redirect everything that is not ignored ipv6 ip6tables -t nat -A APPMESH_EGRESS \ -p tcp \ -j REDIRECT --to $APPMESH_ENVOY_EGRESS_PORT # Apply APPMESH_EGRESS chain to non local traffic ipv6 ip6tables -t nat -A OUTPUT \ -p tcp \ -m addrtype ! --dst-type LOCAL \ -j APPMESH_EGRESS fi } function enable_ingress_redirect_routing() { # Route everything arriving at the application port to Envoy iptables -t nat -A APPMESH_INGRESS \ -p tcp \ -m multiport --dports "$APPMESH_APP_PORTS" \ -j REDIRECT --to-port "$APPMESH_ENVOY_INGRESS_PORT" # Apply AppMesh ingress chain to everything non-local iptables -t nat -A PREROUTING \ -p tcp \ -m addrtype ! --src-type LOCAL \ -j APPMESH_INGRESS if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then # Route everything arriving at the application port to Envoy ipv6 ip6tables -t nat -A APPMESH_INGRESS \ -p tcp \ -m multiport --dports "$APPMESH_APP_PORTS" \ -j REDIRECT --to-port "$APPMESH_ENVOY_INGRESS_PORT" # Apply AppMesh ingress chain to everything non-local ipv6 ip6tables -t nat -A PREROUTING \ -p tcp \ -m addrtype ! --src-type LOCAL \ -j APPMESH_INGRESS fi } function enable_routing() { echo "=== Enabling routing ===" enable_egress_routing if [ ! -z "$APPMESH_APP_PORTS" ]; then enable_ingress_redirect_routing fi } function disable_routing() { echo "=== Disabling routing ===" iptables -t nat -F APPMESH_INGRESS iptables -t nat -F APPMESH_EGRESS if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then ip6tables -t nat -F APPMESH_INGRESS ip6tables -t nat -F APPMESH_EGRESS fi } function dump_status() { echo "=== iptables FORWARD table ===" iptables -L -v -n echo "=== iptables NAT table ===" iptables -t nat -L -v -n if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then echo "=== ip6tables FORWARD table ===" ip6tables -L -v -n echo "=== ip6tables NAT table ===" ip6tables -t nat -L -v -n fi } function clean_up() { disable_routing ruleNum=$(iptables -L PREROUTING -t nat --line-numbers | grep APPMESH_INGRESS | cut -d " " -f 1) iptables -t nat -D PREROUTING $ruleNum ruleNum=$(iptables -L OUTPUT -t nat --line-numbers | grep APPMESH_EGRESS | cut -d " " -f 1) iptables -t nat -D OUTPUT $ruleNum iptables -t nat -X APPMESH_INGRESS iptables -t nat -X APPMESH_EGRESS if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then ruleNum=$(ip6tables -L PREROUTING -t nat --line-numbers | grep APPMESH_INGRESS | cut -d " " -f 1) ip6tables -t nat -D PREROUTING $ruleNum ruleNum=$(ip6tables -L OUTPUT -t nat --line-numbers | grep APPMESH_EGRESS | cut -d " " -f 1) ip6tables -t nat -D OUTPUT $ruleNum ip6tables -t nat -X APPMESH_INGRESS ip6tables -t nat -X APPMESH_EGRESS fi } function main_loop() { echo "=== Entering main loop ===" while read -p '> ' cmd; do case "$cmd" in "quit") clean_up break ;; "status") dump_status ;; "enable") enable_routing ;; "disable") disable_routing ;; *) echo "Available commands: quit, status, enable, disable" ;; esac done } function print_config() { echo "=== Input configuration ===" env | grep APPMESH_ || true } print_config initialize if [ "$APPMESH_START_ENABLED" == "1" ]; then enable_routing fi main_loop-
若要設定
iptables
規則以將應用程式流量路由至 Envoy 代理,請執行您在上一個步驟中建立的指令碼。sudo ./envoy-networking.sh
-
啟動您的虛擬節點應用程式程式碼。
注意
如需 App Mesh 的更多範例和逐步解說,請參閱 App Mesh 範例儲存庫