コンテンツにスキップ

ElasticIP

ElasticIPは、外部から到達可能なIPアドレスを1つ予約するリソースです。

spec.externalNetworkで参照したExternalNetworkに紐づくAddressPoolから1つのアドレスが選ばれます。 ElasticIPで利用されるAddressPoolは、spec.advertiseModeがExternalNetworkのspec.typeと一致している必要があります。

spec.requestedIPは省略可能で、指定した場合はそのIPv4アドレスをElasticIPとして要求します。 指定するアドレスは、spec.externalNetworkで参照したExternalNetworkに紐づくAddressPoolのいずれかに含まれている必要があります。 省略した場合は、利用可能なアドレスから1つが自動的に選ばれます。

2つの使い方

予約したアドレスの使い方は2通りあります。

使い方 設定するもの Podの中から見えるアドレス
NAT ElasticIPAttachmentでNetworkInterfaceに関連付ける Vpc内のアドレス。NodeがElasticIPとの間を1:1 NATで変換します
直接 PodのNICがjuneau.loutres.me/elastic-ipアノテーションか、juneau.loutres.me/networkselasticIPでElasticIPを参照する ElasticIPのアドレスそのもの

1つのElasticIPを2つの使い方で同時に使うことはできません。ElasticIPAttachmentが使っているElasticIPをPodのNICから参照するとPodの作成が拒否され、NICが直接使っているElasticIPを参照するElasticIPAttachmentも拒否されます。

直接使う手順はPodのNICにElasticIPを直接持たせるにあります。

ElasticIPによる1:1 NATは、ICMPエラーメッセージが内包する元パケットのヘッダも書き換えます。Path MTU Discoveryやtracerouteがどう成立するかはElasticIPAttachmentのICMPの扱いを参照してください。直接使う場合はNATを通らないので、書き換えも起きません。

status.attachment

status.attachmentは、いまこのアドレスを使っているものです。kindnameの組で、指す先はElasticIPと同じnamespaceにあります。

  • kind: ElasticIPAttachment:NATで使われています。nameはElasticIPAttachmentの名前です
  • kind: NetworkInterface:直接使われています。nameはアドレスを持っているNetworkInterfaceの名前です

何にも使われていない間は空です。

$ kubectl get elasticip
NAME        EXTERNALNETWORK   ADDRESS       ATTACHMENTKIND        ATTACHMENT         PHASE      ALLOCATED   ATTACHED
nginx-eip   ext-net           10.225.51.5   ElasticIPAttachment   nginx-eip-attach   Attached   True        True
web-eip     ext-net           10.225.51.8   NetworkInterface      web.eth0           Attached   True        True

Phase

  • Pending:参照先ExternalNetworkとAddressPoolは解決できたが、利用可能なアドレスがまだ選ばれていない状態
  • Available:アドレスは選ばれているが、何にも使われていない状態
  • Attached:アドレスが選ばれ、1つのElasticIPAttachmentか、1つのNetworkInterfaceに使われている状態
  • Error:依存リソースの不整合や、複数のElasticIPAttachmentからの参照などで正常に扱えない状態

ElasticIPAttachmentとNetworkInterfaceの両方から参照されたときもErrorになります。reasonはConflictで、messageに両方の名前が出ます。webhookが拒否するので普通は起きませんが、Podを作ってからそのNetworkInterfaceができるまでの間にElasticIPAttachmentを作ると、すり抜けることがあります。

この間はどちらもアドレスを使いません。NetworkInterfaceはPendingで止まり、reason WaitingForElasticIPのmessageにElasticIPAttachmentの名前が出ます。ElasticIPAttachmentもPendingで止まり、NATは設定されません。どちらかを消すと、ElasticIPは残った方に使われ、残った方もそのまま動き出します。

直接使うNetworkInterfaceの選び方

同じElasticIPを参照するNetworkInterfaceが、同時に2つ以上存在することがあります。終了中のPodと入れ替わりの新しいPodが並んだときや、KubeVirtのvirt-launcher Podが作り直されたときです。アドレスを持てるのはそのうち1つだけで、controllerは次の順に決めます。

  1. status.attachmentに書かれているNetworkInterfaceは、残っている限りアドレスを持ち続けます。削除中でも手放しません
  2. 1に当てはまらず、参照しているNetworkInterfaceのどれかが削除中なら、どれにも渡しません。消えるまで待ちます
  3. どちらでもなければ、一番古いNetworkInterfaceが持ちます。作成時刻が同じなら名前の順です

2で待つのは、ElasticIPが一度Errorを通るとstatus.attachmentが消えるからです。そのあとでは、削除中のNetworkInterfaceがまだアドレスを持っているかどうかをcontrollerが確かめられません。

待っている間はPHASE: Availableのままで、AttachedconditionがFalse、reasonがWaitingForHandoverになります。messageには、消えるのを待っているNetworkInterfaceの名前が出ます。

アドレスを持てなかったNetworkInterfaceはPendingで止まり、そのPodは起動しません。詳しくはNetworkInterfaceを参照してください。

削除

NATで使っている場合の削除は、これまでと変わりません。

直接使っているNetworkInterfaceが1つでも残っている間は、ElasticIPの削除が完了しません。finalizerがNetworkInterfaceが無くなるのを待ち、その間はアドレスの予約(AllocationClaim)もARPAdvertisementも外しません。先に予約を外すと、動いているPodのNICがまだ持っているアドレスを、別のElasticIPが取れてしまうからです。

待っている間はAllocatedconditionのreasonがWaitingForNetworkInterfacesになり、messageに残っているNetworkInterfaceの名前が並びます。そのNetworkInterfaceを持つPodを消せば、削除が進みます。

削除中のElasticIPは、新しく作られたNetworkInterfaceにアドレスを渡しません。

type=arpのExternalNetworkを使う場合

外部からの到達性は、経路広報ではなく、ElasticIPを使っているPodが動いているNodeがARP Replyを返すことで成立します。 controllerはeip-<namespace>-<ElasticIP名>という名前のARPAdvertisementを作り、spec.nodeNameに次のNodeを書きます。

  • NATで使っている場合:ElasticIPAttachmentのstatus.nodeName
  • 直接使っている場合:アドレスを持っているNetworkInterfaceのspec.nodeName

Podが別のNodeへ再スケジュールされると、このNodeが変わり、ARPAdvertisementもそれに追従します。

何にも使われていない間はARPAdvertisementが削除され、そのアドレスにはどのNodeも応答しません。 PHASE: Availableのままでも外部からは到達できない、という状態になります。

応答するNodeが移ったときにgratuitous ARPを送らないため、上流のneighborキャッシュが更新されるまで通信は戻りません。詳しくはARPAdvertisementを参照してください。