Создание экземпляров виртуальных машин только с IPv6 и включение NAT64/DNS64

1. Введение

Одна из основных проблем при переходе на IPv6 — обеспечение доступности конечных точек и сетей, использующих только IPv4. Ведущая технология для решения этой проблемы — это сочетание использования DNS64 (определено в RFC6147) для преобразования записей A в записи AAAA для клиентов, которое затем комбинируется с NAT64 (определено в RFC6146) для преобразования специально отформатированных адресов IPv6 в IPv4, где адрес IPv4 встроен в специальный адрес IPv6. Эта лабораторная работа поможет пользователю настроить обе функции в виртуальном частном облаке (VPC) Google Cloud Platform (GCP). При совместной настройке GCP NAT64 и DNS64 позволяют экземплярам, использующим только IPv6, взаимодействовать с серверами, использующими только IPv4, в Интернете.

В этой лабораторной работе вы настроите VPC с различными типами подсетей и экземпляров IPv6: GUA (глобальный индивидуальный адрес) только для IPv6, ULA (уникальный локальный адрес) только для IPv6 и ULA с двойным стеком. Затем вы настроите и протестируете управляемые сервисы DNS64 и NAT64 Google Cloud для доступа к веб-сайтам, использующим только IPv4.

2. Чему вы научитесь

  • Как создать подсети и экземпляры только с IPv6
  • Как включить управляемую службу DNS64 Google Cloud для VPC.
  • Как создать шлюз Google Cloud NAT, настроенный для NAT64.
  • Как протестировать разрешение DNS64 из экземпляров, поддерживающих только IPv6, в пункты назначения, поддерживающие только IPv4.
  • Чем отличается поведение DNS64 и NAT64 в экземплярах с одним и двумя стеками.
  • Как настроить шлюз NAT для NAT64.
  • Как проверить подключение NAT64 от экземпляров, поддерживающих только IPv6, к пунктам назначения, поддерживающим только IPv4.

3. Прежде чем начать

Обновите проект для поддержки кодовой лаборатории

В этой лабораторной работе используются $переменные для упрощения реализации конфигурации gcloud в Cloud Shell.

Внутри Cloud Shell выполните следующие действия.

gcloud config list project
gcloud config set project [YOUR-PROJECT-ID]
export projectname=$(gcloud config list --format="value(core.project)")
export zonename=[COMPUTE ZONE NAME]
export regionname=[REGION NAME]

Общая архитектура лаборатории

63e4293e033da8d3.png

Чтобы продемонстрировать взаимодействие NAT64 и DNS64 с различными типами подсетей IPv6, вы создадите одну VPC с подсетями IPv6 в вариантах GUA и ULA. Вы также создадите подсеть с двойным стеком (с адресацией ULA), чтобы продемонстрировать, что DNS64 и NAT64 не применяются к виртуальным машинам с двойным стеком.

Затем вы настроите DNS64 и NAT64 и протестируете подключение к адресам назначения IPv6 и IPv4 в Интернете.

4. Подготовительные этапы

Сначала настройте необходимую учетную запись службы, IAM, сетевую инфраструктуру и экземпляры в вашем проекте Google Cloud.

Создание учетной записи службы и привязок IAM

Начнём с создания новой учётной записи сервиса, чтобы позволить экземплярам подключаться друг к другу по SSH через gcloud. Эта возможность понадобится нам, поскольку мы не можем использовать IAP для доступа к экземпляру GUA, работающему только по IPv6, а CloudShell пока не поддерживает прямой доступ по IPv6. Выполните следующие команды в CloudShell.

gcloud iam service-accounts create ipv6-codelab \
     --description="temporary service account for a codelab" \
     --display-name="ipv6codelabSA" \
     --project $projectname

gcloud projects add-iam-policy-binding  $projectname \
--member=serviceAccount:ipv6-codelab@$projectname.iam.gserviceaccount.com \
--role=roles/compute.instanceAdmin.v1

gcloud iam service-accounts add-iam-policy-binding \
    ipv6-codelab@$projectname.iam.gserviceaccount.com \
--member=serviceAccount:ipv6-codelab@$projectname.iam.gserviceaccount.com \
--role=roles/iam.serviceAccountUser

Создайте VPC и включите ULA

Создайте сеть VPC с пользовательским режимом подсети и включенным внутренним IPv6 ULA, выполнив следующие команды в CloudShell.

gcloud compute networks create ipv6-only-vpc \
--project=$projectname \
--subnet-mode=custom \
--mtu=1500 --bgp-routing-mode=global \
--enable-ula-internal-ipv6

Создать правила брандмауэра

Создайте правила брандмауэра, разрешающие доступ по SSH. Одно правило разрешает SSH из всего диапазона ULA (fd20::/20). Два других правила разрешают трафик из предопределенных IAP диапазонов IPv6 и IPv4 (2600:2d00:1:7::/64, 35.235.240.0/20 соответственно).

Выполните следующие команды в Cloudshell:

gcloud compute firewall-rules create allow-v6-ssh-ula \
--direction=INGRESS --priority=200 \
--network=ipv6-only-vpc --action=ALLOW \
--rules=tcp:22 --source-ranges=fd20::/20 \
--project=$projectname 

gcloud compute firewall-rules create allow-v6-iap \
--direction=INGRESS --priority=300 \
--network=ipv6-only-vpc --action=ALLOW \
--rules=tcp --source-ranges=2600:2d00:1:7::/64 \
--project=$projectname 

gcloud compute firewall-rules create allow-v4-iap \
--direction=INGRESS --priority=300 \
--network=ipv6-only-vpc --action=ALLOW \
--rules=tcp --source-ranges=35.235.240.0/20 \
--project=$projectname 

Создать подсети

Создайте подсеть только GUA v6, подсеть только ULA v6 и подсеть ULA с двумя стеками. Выполните следующие команды в CloudShell:

gcloud compute networks subnets create gua-v6only-subnet \
--network=ipv6-only-vpc \
--project=$projectname \
--stack-type=IPV6_ONLY \
--ipv6-access-type=external \
--region=$regionname 

gcloud compute networks subnets create ula-v6only-subnet  \
--network=ipv6-only-vpc \
--project=$projectname \
--stack-type=IPV6_ONLY \
--ipv6-access-type=internal \
--enable-private-ip-google-access \
--region=$regionname

gcloud compute networks subnets create ula-dualstack-subnet  \
--network=ipv6-only-vpc \
--project=$projectname \
--stack-type=IPV4_IPV6 \
--range=10.120.0.0/16 \
--ipv6-access-type=internal \
--region=$regionname 

Создать экземпляры

Создайте экземпляры в каждой из только что созданных подсетей. Экземпляр ULA только с IPv6 указан в облачной платформе, чтобы мы могли использовать его в качестве переходного узла к экземпляру GUA только с IPv6. Выполните следующие команды в CloudShell:

gcloud compute instances create gua-instance \
--subnet gua-v6only-subnet \
--stack-type IPV6_ONLY \
--zone $zonename \
--scopes=https://www.googleapis.com/auth/cloud-platform \
--service-account=ipv6-codelab@$projectname.iam.gserviceaccount.com \
--project=$projectname

gcloud compute instances create ula-instance \
--subnet ula-v6only-subnet \
--stack-type IPV6_ONLY \
--zone $zonename \
--scopes=https://www.googleapis.com/auth/cloud-platform \
--service-account=ipv6-codelab@$projectname.iam.gserviceaccount.com \
--project=$projectname

gcloud compute instances create dualstack-ula-instance \
--subnet ula-dualstack-subnet \
--stack-type IPV4_IPV6 \
--zone $zonename \
--project=$projectname

Первоначальный доступ к экземпляру и настройка

Подключитесь по SSH к экземпляру ULA, который по умолчанию будет использовать IAP. Для подключения по SSH к экземпляру ULA используйте следующую команду в CloudShell:

gcloud compute ssh ula-instance --project $projectname --zone $zonename

<username>@ula-instance:~$ 

Мы также будем использовать экземпляр ULA в качестве точки перехода для экземпляра GUA (поскольку IAP не работает с экземплярами GUA, а виртуальные машины Cloudshell не могут получить доступ к адресам назначения IPv6).

Находясь внутри оболочки экземпляра ULA, попробуйте подключиться по SSH к экземпляру GUA, используя следующую команду gcloud.

При первом запуске команды SSH внутри экземпляра вам будет предложено настроить пару ключей SSH. Продолжайте нажимать Enter, пока ключ не будет создан, и команда SSH не будет выполнена. Это создаст новую пару ключей без парольной фразы.

ula-instance:~$ gcloud compute ssh gua-instance

WARNING: The private SSH key file for gcloud does not exist.
WARNING: The public SSH key file for gcloud does not exist.
WARNING: You do not have an SSH key for gcloud.
WARNING: SSH keygen will be executed to generate a key.
Generating public/private rsa key pair.

Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/galhabian/.ssh/google_compute_engine
Your public key has been saved in /home/galhabian/.ssh/google_compute_engine.pub
The key fingerprint is:
SHA256:5PYzydjcpWYiFtzetYCBI6vmy9dqyLsxgDORkB9ynqY galhabian@ula-instance
The key's randomart image is:
+---[RSA 3072]----+
|..               |
|+.o      .       |
|o= o  . + .      |
| o=    * o o     |
|+o.   . S o . o  |
|Eo . . . O + = . |
|   .=. .+ @ * .  |
|   +ooo... *     |
|    **..         |
+----[SHA256]-----+

В случае успеха команда SSH будет выполнена успешно, и вы успешно подключитесь по SSH к экземпляру GUA:

Updating instance ssh metadata...done.                                                                                                                                                                                                                                                                                            
Waiting for SSH key to propagate.
Warning: Permanently added 'compute.3639038240056074485' (ED25519) to the list of known hosts.
Linux gua-instance 6.1.0-34-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.135-1 (2025-04-25) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

<username>@gua-instance:~$ 

5. Проверьте экземпляры, поддерживающие только IPv6.

Давайте проверим оба экземпляра, поддерживающие только IPv6, подключившись к ним по SSH и изучив их таблицы маршрутизации.

Проверить экземпляр GUA

Подключитесь по SSH к «gua-instance», сначала пройдя через экземпляр «ula-instance».

gcloud compute ssh ula-instance --project $projectname --zone $zonename
<username>@ula-instance:~$ gcloud compute ssh gua-instance

Давайте посмотрим на таблицу маршрутизации IPv6 экземпляра с помощью следующей команды.

<username>@gua-instance:~$ ip -6 route

2600:1900:4041:461::/65 via fe80::56:11ff:fef9:88c1 dev ens4 proto ra metric 100 expires 81sec pref medium
fe80::/64 dev ens4 proto kernel metric 256 pref medium
default via fe80::56:11ff:fef9:88c1 dev ens4 proto ra metric 100 expires 81sec mtu 1500 pref medium

Мы замечаем три записи в таблице маршрутизации

  1. Маршрут /65 для подсети GUA, к которой принадлежит экземпляр, с производным следующим переходом, использующим локальный адрес канала для шлюза по умолчанию. Помните, что верхний диапазон /65 зарезервирован для балансировщиков нагрузки IPv6 Pass-Through.
  2. Встроенный маршрут /64 для локального префикса одноадресной рассылки fe80::/64
  3. Маршрут по умолчанию, указывающий на локальный адрес канала для шлюза по умолчанию подсети.

Давайте посмотрим на таблицу маршрутизации IPv4, выполнив эту команду.

<username>@gua-instance:~$ ip -4 route

default via 169.254.1.1 dev ens4 proto dhcp src 169.254.1.2 metric 100 
169.254.1.1 dev ens4 proto dhcp scope link src 169.254.1.2 metric 100 
169.254.169.254 via 169.254.1.1 dev ens4 proto dhcp src 169.254.1.2 metric 100

Удивительно? На самом деле мы поддерживаем таблицу маршрутизации IPv4 в экземплярах, поддерживающих только IPv6, исключительно для обеспечения доступа к серверу Compute Metadata (169.254.169.154), поскольку это всё ещё конечная точка, поддерживающая только IPv4.

Поскольку экземпляр использует IP-адрес 169.254.1.2, когда он работает только с IPv6, этот IP-адрес не маршрутизируется никуда, кроме сервера Compute Metadata, поэтому экземпляр фактически изолирован от всех сетей IPv4.

Тесты на завитки

Давайте протестируем фактическое подключение к веб-сайтам, поддерживающим только v4 и v6, с помощью curl.

<username>@gua-instance:~$ curl -vv --connect-timeout 10 v6.ipv6test.app
<username>@gua-instance:~$ curl -vv --connect-timeout 10 v4.ipv6test.app

Ниже приведен пример вывода.

<username>@gua-instance:~$ curl -vv --connect-timeout 10 v6.ipv6test.app
*   Trying [2600:9000:20be:cc00:9:ec55:a1c0:93a1]:80...
* Connected to v6.ipv6test.app (2600:9000:20be:cc00:9:ec55:a1c0:93a1) port 80 (#0)
> GET / HTTP/1.1
> Host: v6.ipv6test.app
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 OK
!! Rest of output truncated

<username>@gua-instance:~$ curl -vv --connect-timeout 10 v4.ipv6test.app
*   Trying 3.163.165.4:80...
* ipv4 connect timeout after 4985ms, move on!
*   Trying 3.163.165.50:80...
* ipv4 connect timeout after 2492ms, move on!
*   Trying 3.163.165.127:80...
* ipv4 connect timeout after 1246ms, move on!
*   Trying 3.163.165.37:80...
* ipv4 connect timeout after 1245ms, move on!
* Failed to connect to v4.ipv6test.app port 80 after 10000 ms: Timeout was reached
* Closing connection 0
curl: (28) Failed to connect to v4.ipv6test.app port 80 after 10000 ms: Timeout was reached

Как и ожидалось, доступ к конечной точке интернета IPv4 с экземпляра, работающего только с IPv6, отсутствует. Без поддержки DNS64 и NAT64 экземпляр, работающий только с IPv6, не имеет пути к адресу назначения IPv4. Доступ к адресу назначения IPv6 работает нормально, поскольку у экземпляра есть IPv6-адрес GUA.

Проверить экземпляр ULA

Подключитесь по SSH к экземпляру «ula-instance» (по умолчанию использует IAP).

gcloud compute ssh ula-instance --project $projectname --zone $zonename

Давайте посмотрим на таблицу маршрутизации IPv6 экземпляра с помощью следующей команды.

<username>@ula-instance:~$ ip -6 route

fd20:f06:2e5e:2000::/64 via fe80::55:82ff:fe6b:1d7 dev ens4 proto ra metric 100 expires 84sec pref medium
fe80::/64 dev ens4 proto kernel metric 256 pref medium
default via fe80::55:82ff:fe6b:1d7 dev ens4 proto ra metric 100 expires 84sec mtu 1500 pref medium

Мы видим три записи в таблице маршрутизации, аналогичные записи в экземпляре GUA, за исключением маски /64 вместо /65. И маршрут подсети принадлежит диапазону ULA (в рамках агрегата fd20::/20).

Давайте посмотрим на таблицу маршрутизации IPv4, выполнив эту команду.

<username>@ula-instance:~$ ip -4 route

default via 169.254.1.1 dev ens4 proto dhcp src 169.254.1.2 metric 100 
169.254.1.1 dev ens4 proto dhcp scope link src 169.254.1.2 metric 100 
169.254.169.254 via 169.254.1.1 dev ens4 proto dhcp src 169.254.1.2 metric 100

Что демонстрирует аналогичную ситуацию с случаем GUA.

Тесты на завитки

Повторение тестов подключения к веб-сайтам только v4 и v6 с использованием curl.

<username>@ula-instance:~$ curl -vv --connect-timeout 10 v6.ipv6test.app
<username>@ula-instance:~$ curl -vv --connect-timeout 10 v4.ipv6test.app

Ниже приведен пример вывода.

<username>@ula-instance:~$ curl -vv --connect-timeout 10 v6.ipv6test.app
*   Trying [2600:9000:20be:8400:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 4986ms, move on!
*   Trying [2600:9000:20be:9000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 2493ms, move on!
*   Trying [2600:9000:20be:d600:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 1246ms, move on!
*   Trying [2600:9000:20be:b000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 622ms, move on!
*   Trying [2600:9000:20be:7200:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 312ms, move on!
*   Trying [2600:9000:20be:8600:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 155ms, move on!
*   Trying [2600:9000:20be:7a00:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 77ms, move on!
*   Trying [2600:9000:20be:ce00:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 77ms, move on!
* Failed to connect to v6.ipv6test.app port 80 after 10000 ms: Timeout was reached
* Closing connection 0

<username>@ula-instance:~$ curl -vv --connect-timeout 10 v4.ipv6test.app
*   Trying 3.163.165.4:80...
* ipv4 connect timeout after 4985ms, move on!
*   Trying 3.163.165.50:80...
* ipv4 connect timeout after 2492ms, move on!
*   Trying 3.163.165.127:80...
* ipv4 connect timeout after 1246ms, move on!
*   Trying 3.163.165.37:80...
* ipv4 connect timeout after 1245ms, move on!
* Failed to connect to v4.ipv6test.app port 80 after 10000 ms: Timeout was reached
* Closing connection 0
curl: (28) Failed to connect to v4.ipv6test.app port 80 after 10000 ms: Timeout was reached

В случае экземпляра ULA отсутствует доступ к обеим конечным точкам Интернета, поскольку для конечной точки IPv6 мы не можем использовать адрес ULA для связи, а экземпляр не имеет доступа к IPv4, поскольку является экземпляром, поддерживающим только IPv6.

6. Включите NAT64 и DNS64.

Настройте управляемые службы DNS64 и NAT64 для вашего VPC.

DNS64

Включите политику DNS64 Server для вашего VPC. Это заставит DNS-резолвер VPC синтезировать записи AAAA для ответов типа A-only. Выполните следующие команды в CloudShell:

gcloud beta dns policies create allow-dns64 \
    --description="Enable DNS64 Policy" \
    --networks=ipv6-only-vpc \
    --enable-dns64-all-queries \
    --project $projectname

НАТ64

Создайте облачный маршрутизатор, необходимый для Cloud NAT. Затем создайте шлюз Cloud NAT, настроенный для NAT64, включив его для всех диапазонов IP-адресов подсетей, поддерживающих только IPv6, и автоматически выделяя внешние IP-адреса. Выполните следующие команды в CloudShell:

gcloud compute routers create nat64-router \
--network=ipv6-only-vpc \
--region=$regionname \
--project=$projectname


gcloud beta compute routers nats create nat64-natgw \
--router=nat64-router \
--region=$regionname \
--auto-allocate-nat-external-ips \
--nat64-all-v6-subnet-ip-ranges \
--project=$projectname
 

7. Проверьте NAT64 и DNS64

Теперь давайте проверим вашу конфигурацию NAT64 и DNS64 с экземпляров, поддерживающих только IPv6, начав с экземпляра GUA, а затем перейдя к экземпляру ULA.

Тестирование DNS64/NAT64 с экземпляра GUA

Подключитесь по SSH к «gua-instance», сначала пройдя через экземпляр «ula-instance».

gcloud compute ssh ula-instance --project $projectname --zone $zonename
<username>@ula-instance:~$ gcloud compute ssh gua-instance

DNS-тесты

Проверьте разрешение DNS веб-сайта, поддерживающего только IPv6 (например, v6.ipv6test.app , но любой веб-сайт, поддерживающий только IPv6, должен выдать аналогичный результат).

<username>@gua-instance:~$ host -t AAAA v6.ipv6test.app
<username>@gua-instance:~$ host -t A v6.ipv6test.app

Мы ожидаем получить только ответы IPv6 AAAA.

Пример вывода

<username>@gua-instance:~$ host -t AAAA v6.ipv6test.app
v6.ipv6test.app has IPv6 address 2600:9000:269f:1000:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:6600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:b600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:3e00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:9c00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:b200:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:a600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:1400:9:ec55:a1c0:93a1

<username>@gua-instance:~$ host -t A v6.ipv6test.app
v6.ipv6test.app has no A record

Тестовое разрешение DNS для веб-сайта, работающего только по протоколу IPv4 (например, v4.ipv6test.app). Ожидается как запись A (исходный IPv4), так и запись AAAA, синтезированная DNS64 с использованием известного префикса 64:ff9b::/96.

<username>@gua-instance:~$ host -t AAAA v4.ipv6test.app
<username>@gua-instance:~$ host -t A v4.ipv6test.app

Пример вывода

<username>@gua-instance:~$ host -t AAAA v4.ipv6test.app
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3318
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3344
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:333c
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3326

<username>@gua-instance:~$ host -t A v4.ipv6test.app
v4.ipv6test.app has address 54.192.51.68
v4.ipv6test.app has address 54.192.51.24
v4.ipv6test.app has address 54.192.51.60
v4.ipv6test.app has address 54.192.51.38

В приведенном выше примере адрес IPv4 (54.192.51.38) в десятичном формате будет преобразован в (36 c0 33 26) в шестнадцатеричном формате, и, следовательно, мы ожидаем, что ответ для записи AAAA будет (64:ff9b::36c0:3326), что соответствует одному из полученных нами ответов AAAA.

Тесты на завитки

Давайте проверим фактическое подключение к тем же конечным точкам только v4 и только v6, используя curl поверх IPv6.

<username>@gua-instance:~$ curl -vv -6 v6.ipv6test.app

<username>@gua-instance:~$ curl -vv -6 v4.ipv6test.app

Ниже приведен пример вывода.

<username>@gua-instance:~$ curl -vv -6 v6.ipv6test.app
*   Trying [2600:9000:269f:1000:9:ec55:a1c0:93a1]:80...
* Connected to v6.ipv6test.app (2600:9000:269f:1000:9:ec55:a1c0:93a1) port 80 (#0)
> GET / HTTP/1.1

##
## <Output truncated for brevity>
##

<username>@gua-instance:~$ curl -vv -6 v4.ipv6test.app
*   Trying [64:ff9b::36c0:333c]:80...
* Connected to v4.ipv6test.app (64:ff9b::36c0:333c) port 80 (#0)
> GET / HTTP/1.1

##
## <Output truncated for brevity>
##

Обе команды curl выполнены успешно. Обратите внимание, как подключение к веб-сайту, поддерживающему только IPv4, по IPv6 стало возможным благодаря совместной работе NAT64 и DNS64, обеспечившей успешное подключение.

Проверить исходные IP-адреса

Давайте воспользуемся службой отражения IP-адресов, чтобы проверить исходный IP-адрес, наблюдаемый получателем.

<username>@gua-instance:~$ curl -6 v4.ipv6test.app

<username>@gua-instance:~$ curl -6 v6.ipv6test.app

Пример вывода

<username>@gua-instance:~$ curl -6 v4.ipv6test.app
34.47.60.91

<username>@gua-instance:~$ curl -6 v6.ipv6test.app
2600:1900:40e0:6f:0:1::

Указанный IPv6-адрес должен совпадать с IPv6-адресом экземпляра. Этот адрес должен соответствовать результату команды "ip -6 address" на экземпляре. Например,

<username>@gua-instance:~$ ip -6 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2600:1900:40e0:6f:0:1::/128 scope global dynamic noprefixroute
       valid_lft 79912sec preferred_lft 79912sec
    inet6 fe80::86:d9ff:fe34:27ed/64 scope link
       valid_lft forever preferred_lft forever

Однако указанный IPv4-адрес должен совпадать с внешним IP-адресом шлюза Cloud NAT, поскольку он выполняет функцию NAT64 перед выходом в интернет. Это можно проверить, выполнив команду gcloud в CloudShell.

gcloud compute routers get-nat-ip-info \
       nat64-router \
       --region=$regionname

Пример вывода

result:
- natIpInfoMappings:
  - mode: AUTO
    natIp: 34.47.60.91
    usage: IN_USE
  natName: nat64-natgw

Обратите внимание, что указанный в выходных данных «natIp» совпадает с выходными данными, полученными с веб-сайта отражения IP-адресов.

Тестирование DNS64/NAT64 из экземпляра ULA

Сначала подключитесь по SSH к экземпляру ULA "ula-instance"

gcloud compute ssh ula-instance --project $projectname --zone $zonename

<username>@ula-instance:~$

DNS-тесты

Проверьте разрешение DNS веб-сайта, поддерживающего только IPv6 (например, v6.ipv6test.app , но любой веб-сайт, поддерживающий только IPv6, должен выдать аналогичный результат).

<username>@ula-instance:~$ host -t AAAA v6.ipv6test.app
<username>@ula-instance:~$ host -t A v6.ipv6test.app

Мы ожидаем получить только ответы IPv6 AAAA.

Пример вывода

<username>@ula-instance:~$ host -t AAAA v6.ipv6test.app
v6.ipv6test.app has IPv6 address 2600:9000:269f:1000:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:6600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:b600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:3e00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:9c00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:b200:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:a600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:1400:9:ec55:a1c0:93a1

<username>@ula-instance:~$ host -t A v6.ipv6test.app
v6.ipv6test.app has no A record

Тестовое разрешение DNS для веб-сайта, работающего только по протоколу IPv4 (например, v4.ipv6test.app). Ожидается как запись A (исходный IPv4), так и запись AAAA, синтезированная DNS64 с использованием известного префикса 64:ff9b::/96.

<username>@ula-instance:~$ host -t AAAA v4.ipv6test.app
<username>@ula-instance:~$ host -t A v4.ipv6test.app

Пример вывода

<username>@gua-instance:~$ host -t AAAA v4.ipv6test.app
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3318
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3344
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:333c
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3326

<username>@gua-instance:~$ host -t A v4.ipv6test.app
v4.ipv6test.app has address 54.192.51.68
v4.ipv6test.app has address 54.192.51.24
v4.ipv6test.app has address 54.192.51.60
v4.ipv6test.app has address 54.192.51.38

В приведенном выше примере адрес IPv4 (54.192.51.38) в десятичном формате будет преобразован в (36 c0 33 26) в шестнадцатеричном формате, и, следовательно, мы ожидаем, что ответ для записи AAAA будет (64:ff9b::36c0:3326), что соответствует одному из полученных нами ответов AAAA.

Тесты на завитки

Давайте протестируем фактическое подключение к тем же конечным точкам только v4 и только v6 с помощью curl.

Для начала покажем, что достижимость по IPv4 невозможна, поскольку экземпляр поддерживает только IPv6.

<username>@ula-instance:~$ curl -vv -4 --connect-timeout 10 v6.ipv6test.app
<username>@ula-instance:~$ curl -vv -4 --connect-timeout 10 v4.ipv6test.app

Хотя оба варианта curl не сработают. Причины сбоя разные. Ниже представлен пример вывода.

<username>@ula-instance:~$ curl -vv -4 v6.ipv6test.app
* Could not resolve host: v6.ipv6test.app
* Closing connection 0
curl: (6) Could not resolve host: v6.ipv6test.app

<username>@ula-instance:~$ curl -vv -4 --connect-timeout 10 v4.ipv6test.app
*   Trying 54.192.51.68:80...
* ipv4 connect timeout after 4993ms, move on!
*   Trying 54.192.51.38:80...
* ipv4 connect timeout after 2496ms, move on!
*   Trying 54.192.51.24:80...
* ipv4 connect timeout after 1248ms, move on!
*   Trying 54.192.51.60:80...
* Connection timeout after 10000 ms
* Closing connection 0
curl: (28) Connection timeout after 10000 ms

Запрос IPv4 Curl к конечной точке, поддерживающей только IPv6, не удаётся из-за сбоя разрешения DNS для записи A (что было продемонстрировано во время тестов DNS). Запрос IPv4 Curl к конечной точке, поддерживающей только IPv4, не удаётся из-за того, что экземпляр, поддерживающий только IPv6, не имеет доступа ни к одному адресу IPv4, и из-за этого возникает тайм-аут.

Теперь давайте проверим достижимость по IPv6.

<username>@ula-instance:~$ curl -vv -6 v6.ipv6test.app

<username>@ula-instance:~$ curl -vv -6 v4.ipv6test.app

Ниже приведен пример вывода.

<username>@ula-instance:~$ curl -vv -6 v6.ipv6test.app
*   Trying [2600:9000:20be:c000:9:ec55:a1c0:93a1]:80...
* connect to 2600:9000:20be:c000:9:ec55:a1c0:93a1 port 80 failed: Connection timed out
*   Trying [2600:9000:20be:f000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 84507ms, move on!
*   Trying [2600:9000:20be:ae00:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 42253ms, move on!
*   Trying [2600:9000:20be:2000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 21126ms, move on!
*   Trying [2600:9000:20be:b600:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 10563ms, move on!
*   Trying [2600:9000:20be:7600:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 5282ms, move on!
*   Trying [2600:9000:20be:b000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 2640ms, move on!
*   Trying [2600:9000:20be:3400:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 2642ms, move on!
* Failed to connect to v6.ipv6test.app port 80 after 300361 ms: Timeout was reached
* Closing connection 0

<username>@ula-instance:~$ curl -vv -6 v4.ipv6test.app
*   Trying [64:ff9b::36c0:333c]:80...
* Connected to v4.ipv6test.app (64:ff9b::36c0:333c) port 80 (#0)
> GET / HTTP/1.1

##
## <Output truncated for brevity>
##

В то время как Curl для сайта, работающего только по IPv6, не работает, поскольку подсети ULA не имеют прямого доступа к Интернету. Curl для сайта, работающего только по IPv4, работает, поскольку DNS64 и NAT64 работают одинаково для экземпляров GUA и ULA; единственное требование — чтобы экземпляр работал только по IPv6.

Тестирование DNS64/NAT64 с помощью экземпляра ULA с двойным стеком

Сначала подключитесь по SSH к экземпляру Dual-Stack ULA "dualstack-ula-instance". Необходимо использовать флаг "–tunnel-through-iap", чтобы заставить gcloud использовать IPv4-адрес для IAP.

gcloud compute ssh dualstack-ula-instance --project $projectname --zone $zonename --tunnel-through-iap 

<username>@dualstack-ula-instance:~$

Давайте теперь протестируем DNS64 с помощью утилиты «host».

<username>@dualstack-ula-instance:~$ host v4.ipv6test.app
v4.ipv6test.app has address 54.192.51.38
v4.ipv6test.app has address 54.192.51.24
v4.ipv6test.app has address 54.192.51.68
v4.ipv6test.app has address 54.192.51.60

<username>@dualstack-ula-instance:~$ host v6.ipv6test.app
v6.ipv6test.app has IPv6 address 2600:9000:269f:fc00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:1c00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:a200:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:8a00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:c800:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:c200:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:5800:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:dc00:9:ec55:a1c0:93a1

Обратите внимание, что сайт, работающий только по протоколу IPv4, теперь возвращает только IPv4-адреса, а не синтетические ответы DNS64. Это связано с тем, что DNS64 применяется только к экземплярам, работающим только по протоколу IPv6, и не оценивается для экземпляров с двойным стеком.

Чтобы обойти необходимость использования DNS64, добавим запись в файл /etc/hosts для проверки работы NAT64. Выполните следующую команду внутри экземпляра с двойным стеком:

<username>@dualstack-ula-instance:~$ echo '64:ff9b::36c0:3326 v4.ipv6test.app' | sudo tee -a /etc/hosts

Давайте воспользуемся curl для проверки доступа к сайту IPv4 по IPv6.

<username>@dualstack-ula-instance:~$ curl -vv -6 --connect-timeout 10 v4.ipv6test.app

Вот пример вывода вышеуказанной команды.

<username>@dualstack-ula-instance:~$ curl -vv -6 --connect-timeout 10 v4.ipv6test.app

*   Trying [64:ff9b::36c0:3326]:80...
* ipv6 connect timeout after 10000ms, move on!
* Failed to connect to v4.ipv6test.app port 80 after 10001 ms: Timeout was reached
* Closing connection 0
curl: (28) Failed to connect to v4.ipv6test.app port 80 after 10001 ms: Timeout was reached

Время ожидания curl должно истечь, поскольку, как и DNS64, для применения NAT64 также требуется, чтобы экземпляр поддерживал только IPv6.

Чтобы убедиться, что NAT64 фактически не применяется к экземпляру с двойным стеком, воспользуемся командой "get-nat-mapping" для получения списка всех сопоставлений портов, применяемых шлюзом NAT. Выполните следующие команды в CloudShell:

gcloud compute routers get-nat-mapping-info \
      nat64-router --region $regionname \
      --project $projectname

Вы должны ожидать вывод, аналогичный приведенному ниже фрагменту:

---
instanceName: gua-instance
interfaceNatMappings:
- natIpPortRanges:
  - 34.47.60.91:1024-1055
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: '2600:1900:40e0:6f:0:1::'
- natIpPortRanges:
  - 34.47.60.91:32768-32799
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: '2600:1900:40e0:6f:0:1::'
---
instanceName: ula-instance
interfaceNatMappings:
- natIpPortRanges:
  - 34.47.60.91:1056-1087
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: fd20:9c2:93fc:2800:0:0:0:0
- natIpPortRanges:
  - 34.47.60.91:32800-32831
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: fd20:9c2:93fc:2800:0:0:0:0

Выходные данные NAT показывают, что шлюз NAT64 выделил порты только для экземпляров GUA и ULA, использующих только IPv6, но не для экземпляра с двойным стеком.

8. Уборка

Очистка облачного маршрутизатора

Внутри Cloud Shell выполните следующие действия:

gcloud compute routers delete nat64-router \
      --region $regionname \
      --project $projectname --quiet

Отменить привязку и очистить политику DNS

Внутри Cloud Shell выполните следующие действия:

gcloud beta dns policies update allow-dns64 \
    --networks="" \
    --project $projectname
gcloud beta dns policies delete allow-dns64 \
    --project $projectname --quiet

Очистка экземпляров

Внутри Cloud Shell выполните следующие действия: (обратите внимание, бета-версия gcloud используется для того, чтобы мы могли использовать флаг no-graceful-shutdown для более быстрой операции удаления экземпляра)

gcloud beta compute instances delete gua-instance \
         --zone $zonename \
         --no-graceful-shutdown \
         --project=$projectname --quiet

gcloud beta compute instances delete ula-instance \
         --zone $zonename \
         --no-graceful-shutdown \
         --project=$projectname --quiet

gcloud beta compute instances delete dualstack-ula-instance \
         --zone $zonename \
         --no-graceful-shutdown \
         --project=$projectname --quiet

Очистка подсетей

Внутри Cloud Shell выполните следующие действия:

gcloud compute networks subnets delete gua-v6only-subnet \
    --project=$projectname --quiet \
    --region=$regionname
 
gcloud compute networks subnets delete ula-v6only-subnet \
    --project=$projectname --quiet \
    --region=$regionname

gcloud compute networks subnets delete ula-dualstack-subnet \
    --project=$projectname --quiet \
    --region=$regionname

Очистите правила брандмауэра

Внутри Cloud Shell выполните следующие действия:

gcloud compute firewall-rules delete allow-v6-iap \
       --project=$projectname \
       --quiet

gcloud compute firewall-rules delete allow-v6-ssh-ula \
       --project=$projectname \
       --quiet

gcloud compute firewall-rules delete allow-v4-iap \
--project=$projectname \
--quiet

Очистка VPC

Внутри Cloud Shell выполните следующие действия:

gcloud compute networks delete ipv6-only-vpc \
       --project=$projectname \
       --quiet

Очистите разрешения IAM и учетную запись службы

Внутри Cloud Shell выполните следующие действия:

gcloud projects remove-iam-policy-binding  $projectname \
--member=serviceAccount:ipv6-codelab@$projectname.iam.gserviceaccount.com \
--role=roles/compute.instanceAdmin.v1

gcloud iam service-accounts delete \
     ipv6-codelab@$projectname.iam.gserviceaccount.com \
     --quiet \
     --project $projectname

9. Поздравления

Вы успешно использовали NAT64 и DNS64, чтобы разрешить экземплярам, использующим только IPv6, достигать пунктов назначения в Интернете, использующих только IPv4.

Что дальше?

Ознакомьтесь с некоторыми из этих практикумов...

Дополнительные материалы и видео

Справочные документы