Использование динамического распределения портов Cloud NAT

1. Обзор

Динамическое распределение портов (DPA) — это новая функция в Cloud NAT. При включении DPA Cloud NAT динамически увеличивает/уменьшает количество выделяемых портов для экземпляров в зависимости от их потребностей. DPA настраивается с минимальными и максимальными ограничениями на количество портов, так что оно никогда не уменьшает количество портов ниже минимального значения и не увеличивает его выше максимального. Это позволяет некоторым экземплярам за шлюзами NAT динамически увеличивать количество подключений без необходимости выделения дополнительных портов всем экземплярам за Cloud NAT.

Без DPA всем экземплярам за Cloud NAT выделяется одинаковое количество портов независимо от их использования, как определено параметром minPortsPerVm .

Для получения более подробной информации ознакомьтесь с разделом «Документация» о NAT DPA .

Что вы узнаете

  • Как настроить шлюз Cloud NAT в рамках подготовки к DPA.
  • Как проверить распределение портов без использования DPA.
  • Как включить и настроить DPA для NAT-шлюза.
  • Как наблюдать за эффектами DPA путем организации параллельных выходных соединений.
  • Как добавить правила NAT в NAT-шлюз с включенной функцией DPA.
  • Как отследить поведение DPA с помощью правил, запуская исходящие соединения с несколькими пунктами назначения.

Что вам понадобится

  • Базовые знания Google Compute Engine.
  • Базовые знания сетевых технологий и протокола TCP/IP.
  • Базовые знания командной строки Unix/Linux.
  • Полезно предварительно ознакомиться с основами работы с сетями в Google Cloud, например, пройти лабораторную работу «Сети в Google Cloud» .
  • Проект Google Cloud с включенным режимом «Альфа-доступ».
  • Понимание основ облачного NAT.

2. Использование консоли Google Cloud и Cloud Shell

Для взаимодействия с GCP в ходе этой лабораторной работы мы будем использовать как консоль Google Cloud, так и Cloud Shell.

Консоль Google Cloud

Доступ к консоли Cloud Console можно получить по адресу https://console.cloud.google.com .

75eef5f6fd6d7e41.png

Настройка среды для самостоятельного обучения

  1. Войдите в консоль Google Cloud и создайте новый проект или используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • Название проекта — это отображаемое имя участников данного проекта. Это строка символов, не используемая API Google, и вы можете изменить её в любое время.
  • Идентификатор проекта должен быть уникальным для всех проектов Google Cloud и неизменяемым (его нельзя изменить после установки). Консоль Cloud автоматически генерирует уникальную строку; обычно вам неважно, какая она. В большинстве практических заданий вам потребуется указать идентификатор проекта (обычно он обозначается как PROJECT_ID ), поэтому, если он вам не нравится, сгенерируйте другой случайный идентификатор или попробуйте свой собственный и посмотрите, доступен ли он. Затем он "замораживается" после создания проекта.
  • Существует третье значение — номер проекта , который используется некоторыми API. Подробнее обо всех трех значениях можно узнать в документации .
  1. Далее вам потребуется включить оплату в консоли Cloud, чтобы использовать ресурсы/API Cloud. Выполнение этого практического задания не должно стоить дорого, если вообще что-либо. Чтобы отключить ресурсы и избежать дополнительных расходов после завершения этого урока, следуйте инструкциям по «очистке», приведенным в конце практического задания. Новые пользователи Google Cloud имеют право на бесплатную пробную версию стоимостью 300 долларов США .

Запустить Cloud Shell

Хотя Google Cloud можно управлять удаленно с ноутбука, в этом практическом занятии вы будете использовать Google Cloud Shell — среду командной строки, работающую в облаке.

В консоли GCP щелкните значок Cloud Shell на панели инструментов в правом верхнем углу:

bce75f34b2c53987.png

Подготовка и подключение к среде займут всего несколько минут. После завершения вы должны увидеть что-то подобное:

f6ef2b5f13479f3a.png

Эта виртуальная машина оснащена всеми необходимыми инструментами разработки. Она предоставляет постоянный домашний каталог размером 5 ГБ и работает в облаке Google, что значительно повышает производительность сети и аутентификацию. Всю работу в этой лаборатории можно выполнять с помощью обычного браузера.

3. Подготовка лаборатории

Для этой лабораторной работы вы будете использовать проект и создадите две VPC с подсетью в каждой. Вы зарезервируете внешние IP-адреса, а затем создадите и настроите шлюз Cloud NAT (с Cloud Router), два экземпляра производителя, а также два экземпляра потребителя. После проверки поведения Cloud NAT по умолчанию вы включите динамическое распределение портов и проверите его работу. Наконец, вы также настроите правила NAT и понаблюдаете за взаимодействием между DPA и правилами NAT.

Обзор сетевой архитектуры:

a21caa6c333909d8.png

4. Резервирование внешних IP-адресов

Давайте зарезервируем все внешние IP-адреса для использования в этой лабораторной работе. Это поможет вам написать все необходимые правила NAT и брандмауэра как в потребительской, так и в исходящей VPC.

Из 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

Далее создадим правила брандмауэра VPC, чтобы разрешить IP-адресам NAT доступ к экземплярам производителя через порт 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

Следующий шаг — создание двух экземпляров производителя.

Экземпляры производителя будут запускать простую прокси-систему Nginx.

Для быстрого развертывания экземпляров со всем необходимым программным обеспечением мы создадим экземпляры с помощью скрипта запуска, который установит nginx, используя менеджер пакетов Debian APT.

Для возможности написания правил 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, облачного NAT и экземпляров.

Теперь, когда вы создали службу производителя, пришло время создать VPC потребителя и его шлюз Cloud NAT.

После создания VPC и подсети мы добавим простое правило брандмауэра для входящего трафика, разрешающее доступ к IAP для диапазонов исходных IP-адресов TCP. Это позволит нам напрямую подключаться к экземплярам потребителей по SSH с помощью gcloud.

Затем мы создадим простой шлюз 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

Далее создадим правила брандмауэра VPC, разрешающие адреса диапазонов 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 выделил 64 порта на каждый экземпляр с одного и того же внешнего IP 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, устанавливает минимальное количество выделяемых портов для каждой виртуальной машины на 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

Что же здесь произошло? Облачный 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 выделяет порты степенями двойки, по сути удваивая выделение на каждом шаге, мы видим, что таймауты соединения выделяются в диапазоне значений, кратных степеням двойки, от 64 до 1024.

Поскольку мы установили 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

Установив значение параметра `set maxPortsPerVM равным 1024, мы дали указание Cloud NAT никогда не увеличивать количество выделяемых портов сверх 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 для облачного NAT.

Если подождать 2 минуты, прежде чем повторно запустить команду get-nat-mapping-info , вы заметите, что consumer-instance-1 вернулось к минимальному значению — всего 64 выделенных порта. Это демонстрирует не только способность DPA увеличивать количество выделенных портов, но и освобождать их, когда они не используются, для потенциального использования другими экземплярами за тем же NAT-шлюзом.

9. Тестирование правил Cloud NAT с помощью DPA.

Мы также недавно выпустили функционал правил NAT для Cloud NAT, позволяющий клиентам создавать правила, использующие определенные IP-адреса NAT для определенных внешних адресов. Для получения дополнительной информации обратитесь к странице документации по правилам NAT.

В этом упражнении мы рассмотрим взаимодействие между правилами DPA и NAT. Давайте сначала определим правило NAT для использования nat-address-2 при доступе к producer-address-2 .

Выполните следующую команду gcloud, которая создаст правило NAT, используя

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

Обратите внимание, что теперь у нас выделены дополнительные порты (также по 64, что является указанным минимумом) специально для nat-address-2 в иерархии ruleMappings .

Что же произойдет, если один экземпляр откроет множество соединений с местом назначения, указанным в правиле 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"`

А теперь давайте снова запустим цикл curl для producerip2

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

Как видно из приведенного выше примера, IP-адрес NAT по умолчанию для consumer-instance-1 (IP-адрес для nat-address-1 ) по-прежнему имеет только 64 выделенных порта, в то время как IP-адрес правила NAT (IP-адрес для nat-address-2 ) имеет 1024 выделенных порта. При этом consumer-instance-2 сохранил свои значения по умолчанию в 64 порта для всех IP-адресов NAT.

В качестве упражнения вы можете проверить обратный случай. Пусть Cloud NAT освободит все лишние порты, затем запустите цикл curl для producerip1 и понаблюдайте за влиянием на вывод команды 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].

Удалите правила брандмауэра 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!

Что вы осветили

  • Как настроить шлюз Cloud NAT в рамках подготовки к DPA.
  • Как проверить распределение портов без использования DPA.
  • Как включить и настроить DPA для NAT-шлюза.
  • Как наблюдать за эффектами DPA путем организации параллельных выходных соединений.
  • Как добавить правила NAT в NAT-шлюз с включенной функцией DPA.
  • Как отследить поведение DPA с помощью правил, запуская исходящие соединения с несколькими пунктами назначения.

Следующие шаги

©Google, Inc. или ее дочерние компании. Все права защищены. Распространение запрещено.