Google Cloud PlatformのCompute EngineでIPv4/IPv6両対応なVMインスタンスを作成する

# 初めに

不勉強で恥ずかしいのですが、Google Cloud Platform(以下GCP)のCompute EngineでIPv4/Ipv6両対応なVMインスタンスを作成可能になったことを最近になって知りました。だた、GCPのコンソールから「Compute Engine」→「VMインスタンス」と進んで「インスタンス作成」をクリックして必要な情報を入力して「作成」をクリックするだけと、現時点でも出来たVMインスタンスはIPv4のみのサポートとなってしまいます。それであれこれ検索しながらいろいろと試行錯誤した結果何とかIPv4/IPv6両対応のVMインスタンスを作成することに成功したので、その補法をまとめてみることにしました。

# 前提条件

取り敢えず以下のような前提条件で作成します。

* Compute Engineの無料枠に収まるVMインスタンスを作成する
  * リージョンは``us-west1``
  * ゾーンは``us-west1-a``
  * マシンタイプは``e2-micro``
  * ブートディスクの種類は標準永続ディスク
  * ブートディスクのサイズは30GB
* ブートディスクはDebian GNU/Linux 12 (bookworm) x86_64の公開イメージを利用して作成
* 外部IPv4アドレス及びIPv6アドレスは静的IPアドレスを予約したものを用いる
* ホスト名は``test.example.jp``とする

# 手順

IPv4/IPv6両対応のVMインスタンスを作成するには以下の3つのステップを踏む必要があります。

1. IPv4/IPv6両対応なVPCネットワークを作成する
1. 外部IPv4アドレス及びIPv6アドレスを静的IPアドレスとして予約する
1. 作成したIPv4/IPv6両対応なVPCネットワークと予約した静的IPアドレスを用いてVMインスタンスを作成する

以下各ステップの詳細を説明します。

## IPv4/IPv6両対応なVPCネットワークの作成

VMインスタンスを作成する場合、インスタンス作成画面の「詳細オプション」→「ネットワーキング」→「ネットワーク インターフェース」では``default``というVPCネットワークがデフォルトで選択されているのですが、この``default``というVPCネットワークはIPv4のみなので、IPv4/IPv6両対応なVPCネットワークを新規に作成します。

### 事前準備

実際にVPCネットワークを作成する前に、以下の手順を準備として行います。

1. コンソールからナビゲーションメニューで「VPCネットワーク」→「VPCネットワーク」を選択
1. VPCネットワークの一覧で「現在のプロジェクトのサブネット」のタブを選択。
1. サブネットの一覧で、リージョンが``use-west1``でVPCネットワークが``default``なものの「内部IP範囲」の値(``10.138.0.0/20``)を記録しておく。

### VPCネットワークの作成

VPC ネットワークの一覧の画面で「VPCネットワークを作成」をクリックして各項目を以下のように入力します。

<dl>
<dt>名前</dt>
<dd><code>dual-stack</code></dd>
<dt>説明</dt>
<dd>任意で入力</dd>
<dt>VPC ネットワーク ULA の内部 IPv6 範囲</dt>
<dd>無効</dd>
<dt>サブネット→サブネット作成モード</dt>
<dd>カスタム</dd>
<dt>サブネット→サブネットの編集→名前</dt>
<dd><code>dual-stack</code></dd>
<dt>サブネット→サブネットの編集→説明</dt>
<dd>任意で入力</dd>
<dt>サブネット→サブネットの編集→リージョン</dt>
<dd><code>us-west1</code></dd>
<dt>サブネット→サブネットの編集→IPスタックタイプ</dt>
<dd>Pv4とIPv6（デュアルスタック）</dd>
<dt>サブネット→サブネットの編集→IPv4範囲</dt>
<dd>事前準備で記録した「内部IP範囲」の値(<code>10.138.0.0/20</code>)</dd>
<dt>サブネット→サブネットの編集→IPv6アクセスタイプ</dt>
<dd>外部</dd>
<dt>サブネット→サブネットの編集→限定公開の Google アクセス</dt>
<dd>オフ</dd>
<dt>サブネット→サブネットの編集→フローログ</dt>
<dd>オフ</dd>
<dt>ファイアウォール ルール→IPV4ファイアウォールルール</dt>
<dd><code>dual-stack-allow-custom</code>,<code>dual-stack-allow-icmp</code>,<code>dual-stack-allow-ssh</code>を選択</dd>
<dt>ファイアウォール ルール→IPV6ファイアウォールルール</dt>
<dd><code>dual-stack-allow-ipv6-custom</code>,<code>dual-stack-allow-ipv6-icmp</code>,<code>dual-stack-allow-ipv6-ssh</code>を選択</dd>
<dt>動的ルーティング モード</dt>
<dd>リージョン</dd>
<dt>最大伝達単位(MTU)</dt>
<dd>1460</dd>
</dl>

入力が完了したら「作成」をクリックするとVPCネットワークが作成されます。

## 静的IPアドレスの予約

コンソールからナビゲーションメニューで「VPCネットワーク」→「IPアドレス」を選択し、「外部静的IPアドレスを予約」をクリックして部IPv4アドレス及びIPv6アドレスを予約します。

外部IPv4アドレスの場合は、各項目を以下のように入力します。

<dl>
<dt>名前</dt>
<dd><code>test-ipv4</code></dd>
<dt>説明</dt>
<dd>任意で入力</dd>
<dt>ネットワークサービスティア</dt>
<dd>プレミアム</dd>
<dt>IPバージョン</dt>
<dd>IPv4</dd>
<dt>タイプ</dt>
<dd>リージョン</dd>
<dt>リージョン</dt>
<dd><code>us-west1</code></dd>
<dt>接続先</dt>
<dd>なし</dd>
</dl>

IPv6アドレスの場合は、各項目を以下のように入力します。

<dl>
<dt>名前</dt>
<dd><code>test-ipv6</code></dd>
<dt>説明</dt>
<dd>任意で入力</dd>
<dt>ネットワークサービスティア</dt>
<dd>プレミアム</dd>
<dt>IPバージョン</dt>
<dd>IPv6</dd>
<dt>タイプ</dt>
<dd>リージョン</dd>
<dt>リージョン</dt>
<dd><code>us-west1</code></dd>
<dt>ネットワーク</dt>
<dd><code>dual-stack</code></dd>
<dt>サブネットワーク</dt>
<dd><code>dual-stack</code></dd>
<dt>エンドポイントのタイプ</dt>
<dd>VM インスタンス</dd>
<dt>接続先</dt>
<dd>なし</dd>
</dl>

項目の入力が完了したら「予約」をクリックすると静的IPアドレスが予約されます。

## VMインスタンスの作成

作成したVPCネットワークと予約した静的IPアドレスを用いてIPv4/IPv6両対応なVMインスタンスを作成します。

コンソールからナビゲーションメニューの「Computing Engine」→「VMインスタンス」を選択し、「インスタンスを作成」をクリックして各項目を以下のように入力します。

<dl>
<dt>名前</dt>
<dd><code>test</code><dd>
<dt>リージョン</dt>
<dd><code>us-west1</code></dd>
<dt>ゾーン</dt>
<dd><code>us-west1-a</code></dd>
<dt>マシンの構成→シリーズ</dt>
<dd><code>E2</code></dd>
<dt>マシンの構成→マシンタイプ</dt>
<dd><code>e2-micro</code></dd>
<dt>ブートディスク→名前</dt>
<dd><code>test</code></dd>
<dt>ブートディスク→タイプ</dt>
<dd>新しい標準永続ディスク</dd>
<dt>ブートディスク→サイズ</dt>
<dd><code>30G</code></dd>
<dt>ブートディスク→ライセンスの種類</dt>
<dd>無料</dd>
<dt>ブートディスク→イメージ</dt>
<dd>Debian GNU/Linux 12 (bookworm)</dd>
<dt>アイデンティティとAPIへのアクセス→サービスアカウント</dt>
<dd>Compute Engine default service account</dd>
<dt>アイデンティティとAPIへのアクセス→アクセススコープ</dt>
<dd>デフォルトのアクセス権を許可</dd>
<dt>ファイアウォール→HTTPトラフィックを許可する</dt>
<dd>必要に応じてチェックを入れる</dd>
<dt>ファイアウォール→HTTPSトラフィックを許可する</dt>
<dd>必要に応じてチェックを入れる</dd>
<dt>詳細オプション→ネットワーキング→ネットワークタグ</dt>
<dd>空白のまま</dd>
<dt>詳細オプション→ネットワーキング→ホスト名</dt>
<dd>空白のまま</dd>
<dt>詳細オプション→ネットワーキング→IP転送</dt>
<dd>無効のまま</dd>
<dt>詳細オプション→ネットワーキング→ネットワーク パフォーマンスの構成→ネットワークインターフェースカード</dt>
<dd>未選択のまま</dd>
<dt>詳細オプション→ネットワーキング→ネットワーク インターフェース→ネットワーク インターフェースの編集→ネットワーク</dt>
<dd><code>dual-stack</code></dd>
<dt>詳細オプション→ネットワーキング→ネットワーク インターフェース→ネットワーク インターフェースの編集→サブネットワーク</dt>
<dd><code>dual-stack</code></dd>
<dt>詳細オプション→ネットワーキング→ネットワーク インターフェース→ネットワーク インターフェースの編集→IP スタックタイプ</dt>
<dd>IPv4とIPv6（デュアル スタック）</dd>
<dt>詳細オプション→ネットワーキング→ネットワーク インターフェース→ネットワーク インターフェースの編集→プライマリ内部IPv4アドレス</dt>
<dd>エフェメラル（自動）</dd>
<dt>詳細オプション→ネットワーキング→ネットワーク インターフェース→ネットワーク インターフェースの編集→外部IPv4アドレス</dt>
<dd><code>test-ipv4</code></dd>
<dt>詳細オプション→ネットワーキング→ネットワーク インターフェース→ネットワーク インターフェースの編集→外部IPv6アドレス</dt>
<dd><code>test-ipv6</code></dd>
<dt>詳細オプション→ネットワーキング→ネットワーク インターフェース→ネットワーク インターフェースの編集→パブリックDNS PTRレコード→IPv4対応にする</dt>
<dd>有効にして「PTRドメイン名に」<code>test.example.jp</code>と入力</dd>
<dt>詳細オプション→ネットワーキング→ネットワーク インターフェース→ネットワーク インターフェースの編集→パブリックDNS PTRレコード→IPv6対応にする</dt>
<dd>有効にして「PTRドメイン名に」<code>test.example.jp</code>と入力</dd>
<dt>詳細オプション→ディスク</dt>
<dd>そのまま</dt>
<dt>詳細オプション→セキュリティ</dt>
<dd>そのまま</dt>
<dt>詳細オプション→管理</dt>
<dd>そのまま</dt>
<dt>詳細オプション→単一テナンシー</dt>
<dd>そのまま</dt>
</dl>

入力が完了したら「作成」をクリックするとVMインスタンスが作成されます。

# 不具合？

IPアドレスの逆引き情報ですが、VMインスタンス作成直後はIPv4/IPv6共に作成時に指定した値が返されるものの、そのまま運用していると何かのタイミングでIPv6の方の逆引きの値が``x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.bc.googleusercontent.com.``のようなデフォルト値らしきものに変わってしまうという現象が発生します。この状態でVMインスタンスの設定を確認すると、パブリックDNS PTRレコードをIPv6対応にする設定が無効になっているのですが、これを再び有効にしようとすると

> VM インスタンス「test」の編集に失敗しました。エラー: Invalid value for field 'resource.name': 'external-ipv6'. Access config name is immutable.

と言われてしまい有効にすることが出来ません。エラーメッセージで検索してみたところ同じ問題の話がいくつか見つかるものの解決策は書かれていないので、既知の未解決な不具合なのかもしれません。

# まとめ

GCPのCompute EngineでIPv4/IPv6両対応なVMインスタンスを作成する方法についてまとめました。正直なところ、一応それらしく動いているものの本当にこれでいいのか確信が持てない部分もあるので、もし何かおかしな点がありましたらその旨コメントで指摘していただけるとありがたいです。