Cloud NAT 동적 포트 할당 사용

1. 개요

동적 포트 할당 (DPA)은 Cloud NAT의 새로운 기능입니다. DPA를 사용 설정하면 Cloud NAT가 필요에 따라 인스턴스의 포트 할당을 동적으로 확장/축소합니다. DPA는 최소 포트 아래로 포트가 축소되거나 최대 포트 이상으로 확장되지 않도록 최소 및 최대 포트 한도로 구성됩니다. 이를 통해 NAT 게이트웨이 뒤에 있는 일부 인스턴스는 Cloud NAT 뒤에 있는 모든 인스턴스에 더 많은 포트를 할당하지 않고도 연결 수를 동적으로 확장할 수 있습니다.

DPA가 없으면 Cloud NAT 뒤에 있는 모든 인스턴스에 사용량과 관계없이 minPortsPerVm 매개변수로 정의된 동일한 포트 수가 할당됩니다 .

자세한 내용은 NAT DPA에 관한 문서 섹션 을 참고하세요.

학습할 내용

  • DPA를 준비하기 위해 Cloud NAT 게이트웨이를 설정하는 방법
  • DPA 없이 포트 할당을 검사하는 방법
  • NAT 게이트웨이에 DPA를 사용 설정하고 구성하는 방법
  • 동시 출구 연결을 실행하여 DPA의 효과를 관찰하는 방법
  • DPA가 사용 설정된 NAT 게이트웨이에 NAT 규칙을 추가하는 방법
  • 여러 대상으로 이그레스 연결을 실행하여 규칙이 적용된 DPA의 동작을 확인하는 방법

필요한 항목

  • Google Compute Engine의 기본 지식
  • 기본 네트워킹 및 TCP/IP 지식
  • 기본 Unix/Linux 명령줄 지식
  • Google Cloud의 네트워킹 실습과 같은 Google Cloud의 네트워킹 둘러보기를 완료하는 것이 좋습니다.
  • '알파 액세스'가 사용 설정된 Google Cloud 프로젝트
  • Cloud NAT 기본사항 이해

2. Google Cloud 콘솔 및 Cloud Shell 사용

이 실습에서는 GCP와 상호작용하기 위해 Google Cloud 콘솔과 Cloud Shell을 모두 사용합니다.

Google Cloud Console

Cloud 콘솔은 https://console.cloud.google.com에서 액세스할 수 있습니다.

75eef5f6fd6d7e41.png

자습형 환경 설정

  1. Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • 프로젝트 이름은 이 프로젝트 참가자의 표시 이름입니다. 이는 Google API에서 사용하지 않는 문자열이며 언제든지 업데이트할 수 있습니다.
  • 프로젝트 ID는 모든 Google Cloud 프로젝트에서 고유해야 하며, 변경할 수 없습니다(설정된 후에는 변경할 수 없음). Cloud Console은 고유한 문자열을 자동으로 생성합니다. 일반적으로 신경 쓰지 않아도 됩니다. 대부분의 Codelab에서는 프로젝트 ID를 참조해야 하며(일반적으로 PROJECT_ID로 식별됨), 마음에 들지 않는 경우 임의로 다시 생성하거나 직접 지정해서 사용할 수 있는지 확인하세요. 프로젝트가 생성되면 프로젝트 ID가 '고정'됩니다.
  • 세 번째 값은 일부 API에서 사용하는 프로젝트 번호입니다. 이 세 가지 값에 대한 자세한 내용은 문서를 참조하세요.
  1. 다음으로 Cloud 리소스/API를 사용하려면 Cloud Console에서 결제를 사용 설정해야 합니다. 이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 튜토리얼을 마친 후 비용이 결제되지 않도록 리소스를 종료하려면 Codelab의 끝에 있는 '삭제' 안내를 따르세요. Google Cloud 새 사용자에게는 미화 $300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

Cloud Shell 시작

Google Cloud를 노트북에서 원격으로 실행할 수 있지만, 이 Codelab에서는 Cloud에서 실행되는 명령줄 환경인 Google Cloud Shell을 사용합니다.

GCP 콘솔에서 오른쪽 상단 툴바의 Cloud Shell 아이콘을 클릭합니다.

bce75f34b2c53987.png

환경을 프로비저닝하고 연결하는 데 몇 분 정도 소요됩니다. 완료되면 다음과 같이 표시됩니다.

f6ef2b5f13479f3a.png

가상 머신에는 필요한 개발 도구가 모두 들어있습니다. 영구적인 5GB 홈 디렉토리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 실습의 모든 작업은 브라우저만으로 수행할 수 있습니다.

3. 실습 설정

이 실습에서는 프로젝트를 사용하고 각 프로젝트에 서브넷이 있는 VPC를 두 개 만듭니다. 외부 IP 주소를 예약한 다음 Cloud NAT 게이트웨이 (Cloud Router 포함), 2개의 프로듀서 인스턴스, 2개의 컨슈머 인스턴스를 만듭니다. 기본 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. 프로듀서 VPC 및 인스턴스 설정

이제 프로듀서 리소스의 리소스를 만듭니다. 프로듀서 VPC에서 실행되는 인스턴스는 두 개의 공용 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의 프로듀서 인스턴스에 도달하도록 VPC 방화벽 규칙을 만듭니다.

첫 번째 규칙의 경우 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

다음 단계는 두 개의 프로듀서 인스턴스를 만드는 것입니다.

프로듀서 인스턴스는 간단한 nginx 프록시 배포를 실행합니다.

필요한 모든 소프트웨어를 사용하여 인스턴스를 빠르게 프로비저닝하기 위해 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 게이트웨이를 만들 차례입니다.

VPC와 서브넷을 만든 후 TCP 소스 IP 범위의 IAP를 허용하는 간단한 인그레스 방화벽 규칙을 추가합니다. 이렇게 하면 gcloud를 사용하여 소비자 인스턴스에 직접 SSH할 수 있습니다.

그런 다음 수동 할당 모드에서 간단한 Cloud NAT 게이트웨이와 여기에 연결된 예약된 주소 'nat-address-1'을 만듭니다. Codelab의 후속 부분에서는 동적 포트 할당을 사용 설정하도록 게이트웨이의 구성을 업데이트하고 나중에 맞춤 규칙을 추가합니다.

먼저 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에서 소비자 인스턴스에 도달하도록 허용하는 VPC 방화벽 규칙을 만듭니다.

첫 번째 방화벽 규칙의 경우 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 동작 확인

이 시점에서 소비자 인스턴스는 모든 외부 주소와 통신하는 데 동일한 예약 IP 'nat-address-1'을 사용하는 기본 Cloud NAT 동작을 사용합니다. 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에서 인스턴스당 64개의 포트를 할당했습니다.nat-address-1

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"`

그런 다음 두 프로듀서 인스턴스에 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개 이상의 연결을 사용할 수 없을 것으로 예상됩니다. 오래된 포트가 재설정되도록 2분간 기다린 후 1024보다 큰 수로 curl 루프를 다시 실행하여 이를 테스트할 수 있습니다.

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 이전에는 이 작업이 쉽지 않았으며 Cloud NAT의 DPA 기능을 정확하게 보여줍니다.

get-nat-mapping-info 명령어를 다시 실행하기 전에 2분 동안 기다리면 consumer-instance-1이 할당된 포트가 64개에 불과한 최소값으로 돌아갑니다. DPA가 포트 할당을 늘릴 수 있을 뿐만 아니라 동일한 NAT 게이트웨이 뒤에 있는 다른 인스턴스에서 사용할 수 있도록 사용하지 않을 때 포트 할당을 해제할 수 있음을 보여줍니다.

9. DPA로 Cloud NAT 규칙 테스트

최근에는 Cloud NAT용 NAT 규칙 기능도 출시되어 고객이 특정 외부 대상에 특정 NAT IP를 사용하는 규칙을 작성할 수 있습니다. 자세한 내용은 NAT 규칙 문서 페이지를 참고하세요.

이 실습에서는 DPA와 NAT 규칙 간의 상호작용을 살펴봅니다. 먼저 producer-address-2에 액세스할 때 nat-address-2을 사용하도록 NAT 규칙을 정의해 보겠습니다.

다음 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. 정리 단계

반복되는 요금이 발생하지 않도록 이 Codelab과 연결된 모든 리소스를 삭제해야 합니다.

먼저 모든 인스턴스를 삭제합니다.

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].

VPC 방화벽 규칙을 삭제합니다. 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].

마지막으로 VPC를 삭제합니다. 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 실습을 완료했습니다.

학습한 내용

  • DPA를 준비하기 위해 Cloud NAT 게이트웨이를 설정하는 방법
  • DPA 없이 포트 할당을 검사하는 방법
  • NAT 게이트웨이에 DPA를 사용 설정하고 구성하는 방법
  • 동시 출구 연결을 실행하여 DPA의 효과를 관찰하는 방법
  • DPA가 사용 설정된 NAT 게이트웨이에 NAT 규칙을 추가하는 방법
  • 여러 대상으로 이그레스 연결을 실행하여 규칙이 적용된 DPA의 동작을 확인하는 방법

다음 단계

©Google, Inc. or its affiliates. All rights reserved. 배포 금지.