使用 Cloud NAT 動態通訊埠分配

1. 總覽

動態通訊埠分配 (DPA) 是 Cloud NAT 的新功能。啟用 DPA 後,Cloud NAT 會視執行個體需求,動態擴充/縮減通訊埠分配。DPA 會設定通訊埠下限和上限,因此絕不會將通訊埠縮減至低於下限,也不會擴充至超過上限。這樣一來,NAT 閘道後方的部分執行個體就能動態擴充連線數,不必為 Cloud NAT 後方的所有執行個體分配更多通訊埠。

如果沒有 DPA,無論用量為何,Cloud NAT 後方的所有執行個體都會分配到相同數量的通訊埠,如 minPortsPerVm 參數所定義。

詳情請參閱說明文件中的 NAT DPA 相關章節

課程內容

  • 如何設定 Cloud NAT 閘道,為 DPA 做好準備。
  • 如何在沒有 DPA 的情況下檢查連接埠分配。
  • 如何為 NAT 閘道啟用及設定 DPA。
  • 如何執行並行輸出連線,觀察 DPA 的效果。
  • 如何將 NAT 規則新增至已啟用 DPA 的 NAT 閘道。
  • 如何透過執行輸出連線至多個目的地,查看 DPA 搭配規則的行為。

軟硬體需求

  • Google Compute Engine 的基本知識
  • 基本的網路和 TCP/IP 知識
  • 基本的 Unix/Linux 指令列知識
  • 建議您先完成 Google Cloud 網路導覽,例如「Google Cloud 中的網路技術」實驗室。
  • 已啟用「Alpha 版存取權」的 Google Cloud 專案。
  • 瞭解 Cloud NAT 的基本概念

2. 使用 Google Cloud 控制台和 Cloud Shell

在本實驗室中,我們將使用 Google Cloud 控制台和 Cloud Shell 與 GCP 互動。

Google Cloud Console

如要使用 Cloud 控制台,請前往 https://console.cloud.google.com

75eef5f6fd6d7e41.png

自修實驗室環境設定

  1. 登入 Google Cloud 控制台,然後建立新專案或重複使用現有專案。如果沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • 專案名稱是這個專案參與者的顯示名稱。這是 Google API 未使用的字元字串,您隨時可以更新。
  • 專案 ID 在所有 Google Cloud 專案中不得重複,且設定後即無法變更。Cloud 控制台會自動產生專屬字串,通常您不需要在意該字串為何。在大多數程式碼研究室中,您需要參照專案 ID (通常會標示為 PROJECT_ID),因此如果您不喜歡該字串,可以產生另一個隨機字串,或是嘗試使用自己的字串,看看是否可用。專案建立後,系統就會「凍結」該值。
  • 還有第三個值,也就是部分 API 使用的「專案編號」。如要進一步瞭解這三種值,請參閱說明文件
  1. 接著,您需要在 Cloud 控制台中啟用帳單,才能使用 Cloud 資源/API。完成本程式碼研究室的費用應該不高,甚至完全免費。如要停用資源,避免在本教學課程結束後繼續產生帳單費用,請按照程式碼研究室結尾的「清除」操作說明操作。Google Cloud 新使用者可參加價值$300 美元的免費試用計畫。

啟動 Cloud Shell

雖然可以透過筆電遠端操作 Google Cloud,但在本程式碼研究室中,您將使用 Google Cloud Shell,這是可在雲端執行的指令列環境。

在 GCP 主控台,按一下右上角工具列的 Cloud Shell 圖示:

bce75f34b2c53987.png

佈建並連線至環境的作業需要一些時間才能完成。完成後,您應該會看到如下的內容:

f6ef2b5f13479f3a.png

這部虛擬機器搭載各種您需要的開發工具,並提供永久的 5GB 主目錄,而且可在 Google Cloud 運作,大幅提升網路效能並強化驗證功能。本實驗室的所有工作都可在瀏覽器上完成。

3. 實驗室設定

在本實驗室中,您將使用專案,並建立兩個虛擬私有雲,每個虛擬私有雲都有一個子網路。您將預留外部 IP 位址,然後建立及設定 Cloud NAT 閘道 (搭配 Cloud Router)、兩個 Producer 執行個體和兩個 Consumer 執行個體。驗證預設 Cloud NAT 行為後,您將啟用動態連接埠配置,並驗證其行為。最後,您也會設定 NAT 規則,並觀察 DPA 與 NAT 規則之間的互動。

網路架構總覽:

a21caa6c333909d8.png

4. 保留外部 IP 位址

請保留本實驗室中要使用的所有外部 IP 位址。這有助於您在消費者和生產者 VPC 中編寫所有相關的 NAT 和防火牆規則。

透過 Cloud Shell:

gcloud compute addresses  create nat-address-1 nat-address-2 \
 producer-address-1 producer-address-2 --region us-east4

輸出內容:

Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/addresses/nat-address-1].
Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/addresses/nat-address-2].
Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/addresses/producer-address-1].
Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/addresses/producer-address-2].

將預留的 IP 位址填入環境變數。

export natip1=`gcloud compute addresses list --filter name:nat-address-1 --format="get(address)"`
export natip2=`gcloud compute addresses list --filter name:nat-address-2 --format="get(address)"`
export producerip1=`gcloud compute addresses list --filter name:producer-address-1 --format="get(address)"`
export producerip2=`gcloud compute addresses list --filter name:producer-address-2 --format="get(address)"`

系統不會輸出任何內容,但會確認地址是否已正確填入。現在來輸出所有環境變數的值。

env | egrep '^(nat|producer)ip[1-3]'

輸出內容:

producerip1=<Actual Producer IP 1>
producerip2=<Actual Producer IP 2>
natip1=<NAT IP 1>
natip2=<NAT IP 2>

5. 設定供應商虛擬私有雲和執行個體。

我們現在要建立生產者資源的資源。在生產端虛擬私有雲中執行的執行個體,會使用兩個公開 IP「producer-address-1」和「producer-address-2」,提供面向網際網路的服務。

首先,請建立 VPC。透過 Cloud Shell:

gcloud compute networks create producer-vpc --subnet-mode custom

輸出內容:

Created [https://www.googleapis.com/compute/v1/projects/<Project-ID>/global/networks/producer-vpc].
NAME      SUBNET_MODE  BGP_ROUTING_MODE  IPV4_RANGE  GATEWAY_IPV4
producer-vpc  CUSTOM       REGIONAL

Instances on this network will not be reachable until firewall rules
are created. As an example, you can allow all internal traffic between
instances as well as SSH, RDP, and ICMP by running:

$ gcloud compute firewall-rules create <FIREWALL_NAME> --network producer-vpc --allow tcp,udp,icmp --source-ranges <IP_RANGE>
$ gcloud compute firewall-rules create <FIREWALL_NAME> --network producer-vpc --allow tcp:22,tcp:3389,icmp

接著,我們在 us-east4 中建立子網路。透過 Cloud Shell:

gcloud compute networks subnets create prod-net-e4 \
   --network producer-vpc --range 10.0.0.0/24 --region us-east4

輸出內容:

Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/subnetworks/prod-net-e4].
NAME         REGION    NETWORK       RANGE        STACK_TYPE  IPV6_ACCESS_TYPE  IPV6_CIDR_RANGE  EXTERNAL_IPV6_CIDR_RANGE
prod-net-e4  us-east4  producer-vpc  10.0.0.0/24  IPV4_ONLY

接下來,請建立虛擬私有雲防火牆規則,允許 NAT IP 位址透過通訊埠 8080 連線至生產者執行個體。

如要設定第一條規則,請在 Cloud Shell 中執行下列指令:

gcloud compute firewall-rules create producer-allow-80 \
  --network producer-vpc --allow tcp:80 \
  --source-ranges $natip1,$natip2

輸出內容:

Creating firewall...⠹Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/global/firewalls/producer-allow-80].
Creating firewall...done.
NAME                 NETWORK       DIRECTION  PRIORITY  ALLOW     DENY  DISABLED
producer-allow-80    producer-vpc  INGRESS    1000      tcp:80          False

下一步是建立兩個 Producer 執行個體。

製作人執行個體會執行簡單的 nginx Proxy 部署作業。

為了快速佈建執行個體和所有必要軟體,我們會使用開機指令碼建立執行個體,並透過 Debian APT 套件管理工具安裝 nginx。

如要編寫 NAT 規則,我們將為每個執行個體佈建不同的保留 IP 位址。

建立第一個執行個體。透過 Cloud Shell:

gcloud compute instances create producer-instance-1 \
--zone=us-east4-a --machine-type=e2-medium \
--network-interface=address=producer-address-1,network-tier=PREMIUM,subnet=prod-net-e4 \
--metadata startup-script="#! /bin/bash
sudo apt update
sudo apt install -y nginx
mkdir /var/www/html/nginx/
cat <<EOF > /var/www/html/nginx/index.html
<html><body><h1>This is producer instance 1</h1>
</body></html>
EOF"

輸出內容:

Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/zones/us-east4-a/instances/producer-instance-1].
NAME                 ZONE        MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP    STATUS
producer-instance-1  us-east4-a  e2-medium                  10.0.0.2     <Producer IP1>  RUNNING

然後建立第二個執行個體。透過 Cloud Shell:

gcloud compute instances create producer-instance-2 \
--zone=us-east4-a --machine-type=e2-medium \
--network-interface=address=producer-address-2,network-tier=PREMIUM,subnet=prod-net-e4 \
--metadata startup-script="#! /bin/bash
sudo apt update
sudo apt install -y nginx
mkdir /var/www/html/nginx/
cat <<EOF > /var/www/html/nginx/index.html
<html><body><h1>This is producer instance 2</h1>
</body></html>
EOF"

輸出內容:

Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/zones/us-east4-a/instances/producer-instance-2].
NAME                 ZONE        MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP    STATUS
producer-instance-2  us-east4-a  e2-medium                  10.0.0.3     <Producer IP2>  RUNNING

6. 設定消費者 VPC、Cloud NAT 和執行個體

您已建立生產端服務,現在可以建立用戶端 VPC 和其 Cloud NAT 閘道。

建立虛擬私有雲和子網路後,我們會新增簡單的輸入防火牆規則,允許 TCP 來源 IP 範圍的 IAP。這樣我們就能使用 gcloud 直接透過 SSH 連線至消費者執行個體。

接著,我們會在手動分配模式中建立簡單的 Cloud NAT 閘道,並將保留的「nat-address-1」位址與其建立關聯。在程式碼研究室的後續部分,我們會更新閘道的設定,啟用動態通訊埠配置,稍後再新增自訂規則。

首先,請建立 VPC。透過 Cloud Shell:

gcloud compute networks create consumer-vpc --subnet-mode custom

輸出內容:

Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/global/networks/consumer-vpc].
NAME          SUBNET_MODE  BGP_ROUTING_MODE  IPV4_RANGE  GATEWAY_IPV4
consumer-vpc  CUSTOM       REGIONAL

Instances on this network will not be reachable until firewall rules
are created. As an example, you can allow all internal traffic between
instances as well as SSH, RDP, and ICMP by running:

$ gcloud compute firewall-rules create <FIREWALL_NAME> --network consumer-vpc --allow tcp,udp,icmp --source-ranges <IP_RANGE>
$ gcloud compute firewall-rules create <FIREWALL_NAME> --network consumer-vpc --allow tcp:22,tcp:3389,icmp

接著,我們在 us-east4 中建立子網路。透過 Cloud Shell:

gcloud compute networks subnets create cons-net-e4 \
   --network consumer-vpc --range 10.0.0.0/24 --region us-east4

輸出內容:

Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/subnetworks/cons-net-e4].
NAME         REGION    NETWORK       RANGE        STACK_TYPE  IPV6_ACCESS_TYPE  IPV6_CIDR_RANGE  EXTERNAL_IPV6_CIDR_RANGE
cons-net-e4  us-east4  consumer-vpc  10.0.0.0/24  IPV4_ONLY

接著,我們來建立虛擬私有雲防火牆規則,允許 IAP 範圍位址連上通訊埠 22 的消費者執行個體。

如要建立第一個防火牆規則,請從 Cloud Shell 執行下列指令:

gcloud compute firewall-rules create consumer-allow-iap \
  --network consumer-vpc --allow tcp:22 \
  --source-ranges 35.235.240.0/20

輸出內容:

Creating firewall...⠹Created [https://www.googleapis.com/compute/v1/projects/<Project-ID>/global/firewalls/consumer-allow-iap].
Creating firewall...done.
NAME                 NETWORK       DIRECTION  PRIORITY  ALLOW     DENY  DISABLED
consumer-allow-iap  consumer-vpc  INGRESS    1000      tcp:22        False

建立 NAT 閘道前,我們需要先建立 Cloud Router 執行個體 (我們使用私人 ASN 編號,但與本實驗室的活動無關)。透過 Cloud Shell:

gcloud compute routers create consumer-cr \
--region=us-east4 --network=consumer-vpc \
 --asn=65501

輸出內容:

Creating router [consumer-cr]...done.
NAME         REGION       NETWORK
consumer-cr  us-east4  consumer-vpc

然後建立 NAT 閘道執行個體。透過 Cloud Shell:

gcloud compute routers nats create consumer-nat-gw \
    --router=consumer-cr \
    --router-region=us-east4 \
    --nat-all-subnet-ip-ranges \
    --nat-external-ip-pool=nat-address-1

輸出內容:

Creating NAT [consumer-nat-gw] in router [consumer-cr]...done.

請注意,Cloud NAT 閘道預設會以 minPortsPerVm 設為 64 的狀態建立

建立消費者測試執行個體。我們會在這裡填入保留的製作人 IP,以便稍後在執行個體中參照。透過 Cloud Shell:

gcloud compute instances create consumer-instance-1 --zone=us-east4-a \
--machine-type=e2-medium --network-interface=subnet=cons-net-e4,no-address \
--metadata=producer-service-ip1=$producerip1,producer-service-ip2=$producerip2

gcloud compute instances create consumer-instance-2 --zone=us-east4-a \
--machine-type=e2-medium --network-interface=subnet=cons-net-e4,no-address \
--metadata=producer-service-ip1=$producerip1,producer-service-ip2=$producerip2

輸出內容:

Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/zones/us-east4-a/instances/consumer-instance-1].
NAME                ZONE        MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP  STATUS
consumer-instance-1  us-east4-a  e2-medium                  10.0.0.2                  RUNNING

Created [https://www.googleapis.com/compute/v1/projects/<Project ID>/zones/us-east4-a/instances/consumer-instance-2].
NAME                ZONE        MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP  STATUS
consumer-instance-2  us-east4-a  e2-medium                  10.0.0.3                  RUNNING

7. 驗證預設 Cloud NAT 行為

此時,取用端執行個體會使用預設的 Cloud NAT 行為,也就是使用相同的保留 IP「nat-address-1」與所有外部位址通訊。Cloud NAT 也尚未啟用 DPA。

請執行下列指令,驗證 Cloud NAT 為消費者執行個體分配的連接埠

gcloud  compute routers get-nat-mapping-info consumer-cr --region=us-east4

輸出範例

---
instanceName: consumer-instance-1
interfaceNatMappings:
- natIpPortRanges:
  - <NAT Consumer IP1>:1024-1055
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2
- natIpPortRanges:
  - <NAT Consumer IP1>:32768-32799
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2
---
instanceName: consumer-instance-2
interfaceNatMappings:
- natIpPortRanges:
  - <NAT Address IP1>:1056-1087
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.3
- natIpPortRanges:
  - <NAT Address IP1>:32800-32831
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.3

如上方的輸出內容所示,Cloud NAT 已從同一個外部 IP nat-address-1 為每個執行個體分配 64 個連接埠。

啟用 DPA 前,請先驗證我們可以並行開啟多少連線。

透過 SSH 連線至第一個消費者執行個體。透過 Cloud Shell:

gcloud compute ssh consumer-instance-1 --zone=us-east4-a

您現在應該位於執行個體殼層。

輸出內容範例 (為簡潔起見,完整輸出內容已截斷)

External IP address was not found; defaulting to using IAP tunneling.
...
...
<username>@consumer-instance-1:~$

在消費者執行個體中,首先擷取兩個生產端 IP,並填入環境變數

export producerip1=`curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/producer-service-ip1" -H "Metadata-Flavor: Google"`

export producerip2=`curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/producer-service-ip2" -H "Metadata-Flavor: Google"`

然後嘗試對兩個 Producer 執行個體執行 curl,確保可以順利連線。

<username>@consumer-instance-1:~$ curl http://$producerip1/nginx/
<html><body><h1>This is producer instance 1</h1>
</body></html>
<username>@consumer-instance-1:~$ curl http://$producerip2/nginx/
<html><body><h1>This is producer instance 2</h1>
</body></html>

現在,我們來試著透過迴圈執行 curl,對其中一個生產端執行個體建立多個平行連線。請注意,Cloud NAT 不允許在 2 分鐘內重複使用已關閉的通訊端。因此,只要我們能在 2 分鐘內完成所有連線嘗試的迴圈,就能以這種方式模擬平行連線。

在執行個體 SSH 工作階段中執行下列指令

while true; do for i in {1..64}; do curl -s -o /dev/null --connect-timeout 5 http://$producerip1/nginx/; if [ $? -ne 0 ] ; then echo -e "\nConnection # $i failed" ; else echo -en "\rConnection # $i successful"; fi; done; echo -e "\nLoop Done, Sleeping for 150s"; sleep 150; done

您應該可以順利開啟 64 個平行連線,且指令碼應會列印下列內容

Connection # 64 successful

Loop Done, Sleeping for 150s
Connection # 64 successful

Loop Done, Sleeping for 150s

如要確認我們無法超過 64 個並行連線,請先等待 2 分鐘,讓所有舊的通訊端清除完畢。接著將同一行程式碼調整為下列內容,然後重新執行

while true; do for i in {1..70}; do curl -s -o /dev/null --connect-timeout 5 http://$producerip1/nginx/; if [ $? -ne 0 ] ; then echo -e "\nConnection # $i failed" ; else echo -en "\rConnection # $i successful"; fi; done; echo -e "\nLoop Done, Sleeping for 150s"; sleep 150; done

現在您應該會看到下列輸出內容

Connection # 64 successful
Connection # 65 failed
Connection # 66 failed
Connection # 67 failed
Connection # 68 failed
Connection # 69 failed
Connection # 70 failed

Loop Done, Sleeping for 150s

這表示前 64 個連線成功,但由於沒有可用連接埠,其餘 6 個連線失敗。

那麼,我們就來解決這個問題吧!請結束 SSH 殼層,並在下一節中啟用 DPA。

8. 啟用 DPA 並驗證其行為

執行下列 gcloud 指令,啟用 DPA,並將每個 VM 的通訊埠分配下限設為 64,上限設為 1024。

gcloud alpha compute routers nats update consumer-nat-gw --router=consumer-cr \
--region=us-east4 --min-ports-per-vm=64 --max-ports-per-vm=1024 \
--enable-dynamic-port-allocation

這會輸出下列內容:

Updating nat [consumer-nat-gw] in router [consumer-cr]...done.

現在請重新執行 get-nat-mapping-info,確認兩個執行個體仍只分配到 64 個連接埠

gcloud  compute routers get-nat-mapping-info consumer-cr --region=us-east4

輸出內容範例 (為簡潔起見,已截斷)

---
instanceName: consumer-instance-1
...
  - <NAT Consumer IP1>:1024-1055
  numTotalNatPorts: 32
...
- natIpPortRanges:
  - <NAT Consumer IP1>:32768-32799
  numTotalNatPorts: 32
...
---
instanceName: consumer-instance-2
...
  - <NAT Address IP1>:1056-1087
  numTotalNatPorts: 32
...
  - <NAT Address IP1>:32800-32831
  numTotalNatPorts: 32
...

由於執行個體尚未主動使用任何連接埠,因此連接埠分配作業沒有太大變化。

讓我們透過 SSH 重新連入執行個體:

gcloud compute ssh consumer-instance-1 --zone=us-east4-a

重新匯出生產端 IP 環境變數。

export producerip1=`curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/producer-service-ip1" -H "Metadata-Flavor: Google"`

export producerip2=`curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/producer-service-ip2" -H "Metadata-Flavor: Google"`

然後重新執行先前的迴圈,模擬平行連線:

while true; do for i in {1..70}; do curl -s -o /dev/null --connect-timeout 5 http://$producerip1/nginx/; if [ $? -ne 0 ] ; then echo -e "\nConnection # $i failed" ; else echo -en "\rConnection # $i successful"; fi; done; echo -e "\nLoop Done, Sleeping for 150s"; sleep 150; done

現在應該會看到下列輸出內容

Connection # 64 successful
Connection # 65 failed

Connection # 66 failed
Connection # 70 successful
Loop Done, Sleeping for 150s

那麼,這裡發生了什麼事?Cloud NAT 會在通訊埠用量增加時提高通訊埠分配量,但這需要一些時間才能在整個網路層中完成程式設計。因此,在成功完成其餘連線嘗試之前,我們會看到 1 到 3 次連線逾時。

我們已為 curl 指定積極的逾時時間 (5 秒),但逾時時間較長的應用程式應該能夠順利完成連線,同時 DPA 會增加連接埠分配。

當我們執行迴圈,嘗試 1024 次連線時,這種升速行為會更明顯:

while true; do for i in {1..1024}; do curl -s -o /dev/null --connect-timeout 5 http://$producerip1/nginx/; if [ $? -ne 0 ] ; then echo -e "\nConnection # $i failed" ; else echo -en "\rConnection # $i successful"; fi; done; echo -e "\nLoop Done, Sleeping for 150s"; sleep 150; done

現在預期會看到下列輸出內容

Connection # 64 successful
Connection # 65 failed

Connection # 66 failed
Connection # 129 successful
Connection # 130 failed

Connection # 131 failed
Connection # 258 successful
Connection # 259 failed

Connection # 260 failed
Connection # 515 successful
Connection # 516 failed

Connection # 1024 successful
Loop Done, Sleeping for 150s

由於 Cloud NAT 會以 2 的次方分配連接埠,因此基本上每個步驟都會將分配量加倍,我們發現連線逾時問題會出現在 64 到 1024 之間的 2 的次方。

由於我們將 maxPortsPerVM 設為 1024,因此預期連線數不會超過 1024。我們可以重新執行 curl 迴圈,並將計數設為高於 1024 (等待 2 分鐘重設過時的連接埠後),藉此進行測試。

while true; do for i in {1..1035}; do curl -s -o /dev/null --connect-timeout 5 http://$producerip1/nginx/; if [ $? -ne 0 ] ; then echo -e "\nConnection # $i failed" ; else echo -en "\rConnection # $i successful"; fi; done; echo -e "\nLoop Done, Sleeping for 150s"; sleep 150; done

如預期,輸出內容顯示超過 1024 個的連線開始失敗

<truncated output>
...
Connection # 1028 successful
Connection # 1029 failed
Connection # 1030 failed
Connection # 1031 failed
Connection # 1032 failed
Connection # 1033 failed
Connection # 1034 failed
Connection # 1035 failed
...
Loop Done, Sleeping for 150s

maxPortsPerVM 設為 1024,即指示 Cloud NAT 每個 VM 的通訊埠分配量絕不超過 1024。

如果我們結束 SSH 工作階段,並快速重新執行 get-nat-mapping-info,就能看到分配的額外連接埠

gcloud  compute routers get-nat-mapping-info consumer-cr --region=us-east4

並觀察下列輸出內容

---
instanceName: consumer-instance-1
interfaceNatMappings:
- natIpPortRanges:
  - <NAT Address IP1>:1024-1055
  - <NAT Address IP1>1088-1119
  -<NAT Address IP1>:1152-1215
  - <NAT Address IP1>:1280-1407
  - <NAT Address IP1>:1536-1791
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 512
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2
- natIpPortRanges:
  - <NAT Address IP1>:32768-32799
  - <NAT Address IP1>:32832-32863
  - <NAT Address IP1>:32896-32959
  - <NAT Address IP1>:33024-33151
  - <NAT Address IP1>:33536-33791
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 512
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2
---
instanceName: consumer-instance-2
interfaceNatMappings:
- natIpPortRanges:
  - <NAT Address IP1>:1056-1087
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.3
- natIpPortRanges:
  - <NAT Address IP1>:32800-32831
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.3

請注意,consumer-instance-1 分配到 1024 個通訊埠,但 consumer-instance-2 只分配到 64 個通訊埠。這在 DPA 推出前並不容易,正好凸顯 DPA 對於 Cloud NAT 的強大功能。

如果等待 2 分鐘後再重新執行 get-nat-mapping-info 指令,您會發現 consumer-instance-1 回到最低值,也就是只分配了 64 個連接埠。不僅說明 DPA 增加通訊埠分配量的能力,也說明 DPA 在通訊埠閒置時釋出通訊埠,供相同 NAT 閘道後方的其他執行個體使用。

9. 使用 DPA 測試 Cloud NAT 規則

我們最近也發布了 Cloud NAT 的 NAT 規則功能,讓客戶編寫規則,針對特定外部目的地使用特定 NAT IP。詳情請參閱 NAT 規則說明文件頁面

在本練習中,我們將觀察 DPA 和 NAT 規則之間的互動。首先,請定義 NAT 規則,以便在存取 producer-address-2 時使用 nat-address-2

執行下列 gcloud 指令,使用

gcloud alpha compute routers nats rules create 100 \
 --match='destination.ip == "'$producerip2'"' \
 --source-nat-active-ips=nat-address-2 --nat=consumer-nat-gw \
 --router=consumer-cr --router-region=us-east4

預期的輸出內容如下:

Updating nat [consumer-nat-gw] in router [consumer-cr]...done.

現在重新執行 get-nat-mapping-info,查看新 NAT 規則的效果。

gcloud alpha compute routers get-nat-mapping-info consumer-cr --region=us-east4

這會輸出下列內容

---
instanceName: consumer-instance-1
interfaceNatMappings:
- natIpPortRanges:
  - <NAT Address IP1>:1024-1055
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  ruleMappings:
  - natIpPortRanges:
    - <NAT Address IP2>:1024-1055
    numTotalDrainNatPorts: 0
    numTotalNatPorts: 32
    ruleNumber: 100
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2
- natIpPortRanges:
  - <NAT Address IP1>:32768-32799
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  ruleMappings:
  - natIpPortRanges:
    - <NAT Address IP2>:32768-32799
    numTotalDrainNatPorts: 0
    numTotalNatPorts: 32
    ruleNumber: 100
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2

請注意,現在我們已在 ruleMappings 階層下,為 nat-address-2 分配額外通訊埠 (同樣是指定的最小值 64)。

因此,如果執行個體開啟多個連線,連至 NAT 規則指定目的地,會發生什麼情況?讓我們一起來看看。

讓我們透過 SSH 重新連入執行個體:

gcloud compute ssh consumer-instance-1 --zone=us-east4-a

重新匯出生產端 IP 環境變數。

export producerip1=`curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/producer-service-ip1" -H "Metadata-Flavor: Google"`

export producerip2=`curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/producer-service-ip2" -H "Metadata-Flavor: Google"`

現在,請針對 producerip2 重新執行 curl 迴圈

while true; do for i in {1..1024}; do curl -s -o /dev/null --connect-timeout 5 http://$producerip2/nginx/; if [ $? -ne 0 ] ; then echo -e "\nConnection # $i failed" ; else echo -en "\rConnection # $i successful"; fi; done; echo -e "\nLoop Done, Sleeping for 150s"; sleep 150; done

您應該會看到類似以下的輸出內容

Connection # 64 successful
Connection # 65 failed

Connection # 66 failed
Connection # 129 successful
Connection # 130 failed

Connection # 131 failed
Connection # 258 successful
Connection # 259 failed

Connection # 260 failed
Connection # 515 successful
Connection # 516 failed

Connection # 1024 successful
Loop Done, Sleeping for 150s

基本上與先前的測試相同。讓我們結束執行個體的 SSH 工作階段,然後再次查看 NAT 對應。

gcloud alpha compute routers get-nat-mapping-info consumer-cr --region=us-east4

這會輸出下列內容

---
instanceName: consumer-instance-1
interfaceNatMappings:
- natIpPortRanges:
  - <NAT Address IP1>:1024-1055
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  ruleMappings:
  - natIpPortRanges:
    - <NAT Address IP2>:1024-1055
    - <NAT Address IP2>:1088-1119
    - <NAT Address IP2>:1152-1215
    - <NAT Address IP2>:1280-1407
    - <NAT Address IP2>:1536-1791
    numTotalDrainNatPorts: 0
    numTotalNatPorts: 512
    ruleNumber: 100
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2
- natIpPortRanges:
  - <NAT Address IP1>:32768-32799
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  ruleMappings:
  - natIpPortRanges:
    - <NAT Address IP2>:32768-32799
    - <NAT Address IP2>:32832-32863
    - <NAT Address IP2>:32896-32959
    - <NAT Address IP2>:33024-33151
    - <NAT Address IP2>:33280-33535
    numTotalDrainNatPorts: 0
    numTotalNatPorts: 512
    ruleNumber: 100
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2
---
instanceName: consumer-instance-2
interfaceNatMappings:
- natIpPortRanges:
  - <NAT Address IP1>:1056-1087
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  ruleMappings:
  - natIpPortRanges:
    - <NAT Address IP2>:1056-1087
    numTotalDrainNatPorts: 0
    numTotalNatPorts: 32
    ruleNumber: 100
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.3
- natIpPortRanges:
  - <NAT Address IP1>:32800-32831
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  ruleMappings:
  - natIpPortRanges:
    - <NAT Address IP2>:32800-32831
    numTotalDrainNatPorts: 0
    numTotalNatPorts: 32
    ruleNumber: 100
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.3

---
instanceName: consumer-instance-1
interfaceNatMappings:
- natIpPortRanges:
  - <NAT Address IP1>:1024-1055
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  ruleMappings:
  - natIpPortRanges:
    - <NAT Address IP2>:1024-1055
    numTotalDrainNatPorts: 0
    numTotalNatPorts: 32
    ruleNumber: 100
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2
- natIpPortRanges:
  - <NAT Address IP1>:32768-32799
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  ruleMappings:
  - natIpPortRanges:
    - <NAT Address IP2>:32768-32799
    numTotalDrainNatPorts: 0
    numTotalNatPorts: 32
    ruleNumber: 100
  sourceAliasIpRange: ''
  sourceVirtualIp: 10.0.0.2

如上所示,consumer-instance-1的預設 NAT IP ( nat-address-1 的 IP) 仍只分配到 64 個通訊埠,但 NAT 規則的 IP (nat-address-2 的 IP) 則分配到 1024 個通訊埠。同時,consumer-instance-2 也為所有 NAT IP 保留預設的 64 個連接埠分配。

您可以測試反向案例做為練習。讓 Cloud NAT 取消分配所有額外連接埠,然後對 producerip1 執行 curl 迴圈,並觀察 get-nat-mapping-info 輸出內容的影響

10. 清除步驟

為避免產生週期性費用,請刪除與本程式碼研究室相關的所有資源。

請先刪除所有執行個體。

透過 Cloud Shell:

gcloud compute instances delete consumer-instance-1 consumer-instance-2 \
 producer-instance-1 producer-instance-2 \
 --zone us-east4-a --quiet

預期輸出內容:

Deleted [https://www.googleapis.com/compute/v1/projects/<Project Id>/zones/us-east4-a/instances/consumer-instance-1].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project Id>/zones/us-east4-a/instances/consumer-instance-2].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project Id>/zones/us-east4-a/instances/producer-instance-1].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project Id>/zones/us-east4-a/instances/producer-instance-2].

接著,刪除 Cloud Router。透過 Cloud Shell:

gcloud compute routers delete consumer-cr \
 --region us-east4 --quiet

您應該會看到下列輸出內容:

Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/routers/consumer-cr].

釋出所有外部 IP 位址。透過 Cloud Shell:

gcloud compute addresses delete nat-address-1 \
 nat-address-2 producer-address-1 \
 producer-address-2 --region us-east4 --quiet

您應該會看到下列輸出內容:

Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/addresses/nat-address-1].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/addresses/nat-address-2].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/addresses/nat-address-3].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/addresses/producer-address-1].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/addresses/producer-address-2].

刪除虛擬私有雲防火牆規則。透過 Cloud Shell:

gcloud compute firewall-rules delete consumer-allow-iap \
 producer-allow-80 --quiet

您應該會看到下列輸出內容:

Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/global/firewalls/consumer-allow-iap].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/global/firewalls/producer-allow-80].

刪除子網路。透過 Cloud Shell:

gcloud compute networks subnets delete cons-net-e4 \
 prod-net-e4 --region=us-east4 --quiet

您應該會看到下列輸出內容:

Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/subnetworks/cons-net-e4].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/us-east4/subnetworks/prod-net-e4].

最後,請刪除虛擬私有雲。透過 Cloud Shell:

gcloud compute networks delete consumer-vpc \
 producer-vpc --quiet

您應該會看到下列輸出內容:

Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/global/networks/consumer-vpc].
Deleted [https://www.googleapis.com/compute/v1/projects/<Project ID>/global/networks/producer-vpc].

11. 恭喜!

您已完成 Cloud NAT DPA 實驗室!

涵蓋內容

  • 如何設定 Cloud NAT 閘道,為 DPA 做好準備。
  • 如何在沒有 DPA 的情況下檢查連接埠分配。
  • 如何為 NAT 閘道啟用及設定 DPA。
  • 如何執行並行輸出連線,觀察 DPA 的效果。
  • 如何將 NAT 規則新增至已啟用 DPA 的 NAT 閘道。
  • 如何透過執行輸出連線至多個目的地,查看 DPA 搭配規則的行為。

後續步驟

©Google Inc. 或其關係企業。版權所有。請勿散布。