オーバーレイネットワークと私

日頃から仕事でお世話になっている方からこんな記事を教えてもらった。2004年の記事だが、当時IntelのCTOだったPat Gelsinger(現VMwareのCEO)がオーバーレイネットワークの構想を持っていたのには驚かされる。Patが思い描いていた世界は(当時彼がIntelにいたということを考えると)全てのデスクトップやノートブックPCにまでオーバーレイネットワークが伸びていき、そこで色々なネットワークサービス面に接続して使う、というような姿だったのではないかと想像する。今日のオーバーレイネットワークは我々の手元のPCまで届いているとは言い難い状況だが、クラウドやデータセンターにおいてはそれに近い姿が実現されているので、2004年にこのような世界観を持っていたPatの先見性には驚かされるばかりである。

Patのような先見の明を持ち合わせていたわけではないが、なぜか私もこれまでオーバーレイネットワークに携わることがとても多かった。今回はその辺を少し振り返ってみようと思う。

私は1997年にAscend Communicationsに入社したのだが、当時Ascendはアクセスサーバーとして圧倒的なシェアを持っていて、どのISPもAscendを使っていた時代だった。そんな中、ネットワーク業界の経験がない私がAscendのSEとして飛び込んでいったわけで、最初の1年は「自分は本当に役に立っているのだろうか?」と自問自答する日々だった。PPPの16進ダンプを見るだけですらすらデバッグができる人たちがゴロゴロしている中で、自分は何をしたらいいのかと悩んでいたのである。であれば、他の人とは少し違ったことをやろう、と思い、当時Ascend MAXが持っていたAscend Tunnel Management Protocol (ATMP) を触り始めたのが、私にとってオーバーレイネットワークとの最初の出会いであった。当時はダイアルアップ系のトンネリングプロトコルとしては、ATMP、PPTP、L2Fなどベンダー色が強いものが乱立していたため、IETFとして標準的なトンネリングプロトコルを作ろうということでL2TP (Layter 2 Tunneling Protocol) が生まれた。AscendがL2TPの仕様策定にも関わっていたこともあり、私も比較的早い段階でL2TPの実装に触ることができた。ちょうどその頃、VPN周りの検証や運用に関する知見などの共有を目的とするグループvpnops(発起人は当時IRIにおられた松本直人さん)でL2TPの相互接続性の試験をしようということになり、幸い私にもお声がけを頂き検証に参加することとなった。この相互運用試験時のデバッグのためにtcpdump用のL2TP dissectorを書いて持って行ったのだが、このコードをのちにitojunさんがtcpdumpのtrunkにマージをしてくださったのは良い思い出である。

こんなことをしているうちにそこそこL2TPに関する知見が溜まっていったわけだが、丁度そんなタイミングでNTTが初のインターネット定額サービス(フレッツISDN)を始めるにあたりL2TPを使うかもしれないということで、Ascendで一番L2TPと戯れていたと思われる私がこのプロジェクトに引き込まれることになった。このプロジェクトは私にとって人生の転機となるプロジェクトであり、その際にお世話になった方々には本当に感謝しても仕切れない。そんなこんなでL2TPどっぷりな日々を送ることになり、気がつけば私もL2TPプロコルのコントロールメッセージを全てそらで言えるようになっていた(笑)

Ascendでの心残りはIPsecができなかったことだ。プロトタイプの製品はあったものの、残念ながら市場に出る製品にはならなかった。個人的にはIPsecにとても興味があったので、2000年にAscendからCoSine Communicationsという会社に移った(IPsecだけが理由ではないが、IPsecは大きな動機の一つであった)。CoSineがやっていたのは、完全な仮想ルータをIPsecでトンネルすることでオーバーレイ型のVPNを実現する、というものであった。当時は仮想ルータという概念はまだ一般的ではなく、VRFが出てきたばかりという時代だったので、CoSineがやろうとしていたことは当時としてはかなり先進的であったと思う(一方、ソフトウェアの品質はお世辞にも高くはなかったので、色々ご迷惑をおかけしました。すみません)。

当時はVPNに関しては2大派閥があった。Peerモデル派とオーバーレイモデル派である。Peerモデル派の代表はBGP/MPLS VPN(いわゆるRFC2547/RFC4364)。それに対してCoSineがやっていたのはオーバーレイモデルなVPNである。注意したのいのは、ここでいう「Peer vs オーバーレイ」というのはデータプレーンでのオーバーレイ(トンネル/カプセル化)をするかどうかの話ではなく、サービスプロバイダが顧客の経路情報に関与するかどうか、という話である。Peerモデルは顧客の経路情報とサービスプロバイダの経路情報を同じように扱うモデルである。顧客経路とサービスプロバイダのバックボーンの経路を対等(peer)に扱うのでこのように呼ばれている。一方、オーバーレイモデルではサービスプロバイダは顧客の経路情報には関与せず、顧客側の経路制御は顧客側で行う。典型的には、トンネル上でルーティングプロトコルを動かして顧客経路を交換するモデルだ。

Peerモデル vs オーバーレイモデルに関してはIETFのMailing Listでもしばしば宗教論争が起こった。当時はPeerモデル派が優勢で、Peerモデル派からは「オーバーレイモデルなどスケールするはずがない」など、こてんぱんに言われることも多く、悔しい思いをしていたのを良く憶えている。真っ向から対立していた両陣営の主張の正当性はさておき、商業的に成功したのは圧倒的にBGP/MPLS VPNであったのはみなさんよくご存知の通りである。

ひょんなことから2011年にNiciraと出会い、Niciaに行くことになった経緯についてはこちらをご参照いただきたいが、はからずもNiciraもまたオーバーレイ技術をベースとする会社であった。Niciraが開発していた製品「NVP」は、ネットワーク機能をハードウェアから切り離しネットワークの抽象化を行う、というアーキテクチャとなっており、STT(Stateless Transport Tunneling)を使って仮想スイッチ間をトンネルして仮想ネットワークを作り出す、というものであった。Niciraは2012年にVMwareに買収され、NVPはNSXとして製品に取り込まれ、年間1000億円の市場に成長した。

Nicira/VMwareのあと、2016年にViptelaというSD-WANのスタートアップに行ったが、SD-WANもやはりオーバーレイ技術をベースにしたものである。多くのSD-WAN製品はIPsecトンネルで作られるオーバーレイネットワークだ。SD-WANの柔軟性と普遍性はコントローラの存在だけでなく、オーバーレイアーキテクチャによるところも大きい。先の「Peerモデル vs オーバーレイモデル」的な観点で見ると、CPE同士で経路を交換するSD-WANはオーバーレイモデル的なVPNということになる。2000年の頃には「スケールしない」などと散々非難をされたオーバーレイモデルのVPNが、CPEの性能向上やクラウド上のコントロールプレーンの利用により、15年の時を経て実際に大規模環境で動いているのを見るとなんだか嬉しい気分になる。

オーバーレイにはオーバーヘッドは付き物である。この性能的なオーバーヘッドを理由にオーバーレイ技術が批判されるケースをしばしば目にするが、これは非常に近視的なものの見方ではないかと思う。新しいオーバーレイネットワーク技術が生まれると、それは通常ハードウェアが想定していないカプセル化であるため、性能が劣化する。しかし、そのような問題はハードウェアの進化とともに解決されていくことが多い。特にカプセル化などはハードウェアで扱いやすい問題に属すると思うので、多くの場合時とともに性能的な問題は解決されていく。長期的にはオーバーレイによる「抽象化」がもたらす技術の進化の方がはるかに大きな意味を持つと思う。

ネットワークの話ではないが、いくつか例をあげてみたい。近代的なコンピュータとオペレーティングシステムは仮想メモリシステムを使っている。仮想アドレス空間を物理アドレス空間にマップしてメモリを使っているわけだが、これはCPUが持つMMUやTLBなどの仕組みによって大きな性能劣化なく仮想メモリシステムが使えているわけである。今日、性能的なオーバーヘッドを理由に仮想メモリシステムを否定する人はいないだろう。それよりもアドレス空間の仮想化によって得られるメリットのが方が遥かに大きいのは明らかだからだ。もう一つ別の例を挙げよう。x86 CPUの仮想化も当初は性能的なオーバーヘッドが大きく実現困難と思われていたが(それを現実的な速度でやって見せて世の中をびっくりさせたのがVMwareだったわけだが)、その後Intel VTやAMD-VなどのCPUによる仮想化支援機能によって、大きな性能の劣化なくx86の仮想化ができるようになった。今日、CPUの仮想化のメリットはおそらく誰も否定しないだろうし、性能的オーバーヘッドは相対的に無視できるほど小さくなっている。オーバーレイネットワークによるネットワーク抽象化もこれらと同じ話であると思う。イノベーションは抽象化から生まれ、抽象化する事で発生するオーバーヘッドは、多くの場合ハードウェアがのちに解決してくれるのである。

私自身、初めからこのようなことを考えて約20年間一貫してオーバーレイ・ネットワークに携わってきたわけではない。「たまたま」といえばそうなのだが、きっとオーバーレイによる抽象化とそこから生まれるワクワク感がきっと本質的に好きなのだろうと思う。

今までネットワーク機器は自分たちの手の届くところにあったので、ネットワーク機器を直接「触る」ことでネットワークを構築、管理をしてきた。しかし、これからはクラウドの時代である。クラウドにも当然物理ルーターや物理スイッチはあるが、通常我々はそれらを直接触ることはできない。物理ネットワーク機器に直接触れない環境でどのようにネットワークをエンド to エンドで構築・管理していけば良いのだろうか? クラウド時代においては、オーバーレイでネットワークを作りエンド to エンドで管理していくのは必然の事のように思える。そんなわけで、これからも大いにオーバーレイネットワークに絡んでいきたいと思う次第である。

Photo by Joshua Forbes on Unsplash

Kubernetes Cluster API – Part 1 –

Cluster APIはKubernetesスタイルのAPIを使ってKubernetesのクラスタの管理するための仕組みで、Kubernetes SIG (Special Interest Group) のうちの1つであるCluster Lifecycle SIGで仕様の策定が行われています。

Kubernetes環境の構築ツールにはkubeadm、kops、Kubesprayなど多数存在していますが、それぞれスコープが異なります。kubeadmはKubernetesのコンポーネントのインストールをしてくれますが、それを動かすためのプラットフォームの面倒は見てくれません。kubeadmの実行時にはすでにKubernetesを動かすための環境(サポートされているOSが動いているベアメタルや仮想マシン、container runtime、kubeletやkubectlなどのツール、など)が整っていることが前提になっています。一方、kopsはKubernetesを動かすプラットフォーム(Cluster)まで含めて構築をしてくれますが、プラットフォームを個別にサポートしていく必要があります。2019年9月時点でオフィシャルにサポートされているプラットフォームはAWSのみ、GCEとOpenStackがbetaサポート、vSphereとDigitalOceanがalphaサポートとなっています(コードを見るとAliCloudやベアメタルもサポートしようとしているように見えます)。

今後もこのようなKubernetesクラスタ環境設定ツールが他にも出てくる可能性がありますが、今のままだとそれぞれのツールで個別にプラットフォームをサポートしていかなければいけません。また、Kubernetesを動かしたいプラットフォームも、AWSやGCPだけでなく他のパッブリッククラウドやベアメタルなど、多様な環境をサポートしたくなるに違いありません。さらに、クラスタを構築する(Day1 Operation)だけでなく、クラスターを大きくしたい/小さくしたい、クラスタノードのOSのバージョンアップをしたい、といったいわゆるクラスタのDay2 Operationも必要になりますが、これらもプラットフォームごとに考えなければいけないことになります。これはKubernetesのユーザーにとっても環境構築ツールのエコシステムにとっても大きな苦痛です。

このような問題を解決するために、クラスタを含むKubernetes環境全体を管理するための汎用的な仕組みを提供することを目的に生まれたのがCluster APIです(CAPIと呼べばれることもあります)。”API” という名前が付いていますが、どちらかというとフレームワーク的な色合いが強いと思います。

「汎用的」と言っても、当然プラットフォームごとに必要な処理は異なりますので、Cluster APIではプラットフォームごとに個別の “Provider” を用意してプラットフォームの差異を吸収し、どのようなプラットフォームに対しても統一的なのAPIでコントロールできるように作られています。現在さまざまなProviderが用意されており、これらのProviderがサポートしているプラットフォーム上であればCluster APIを使ってKubernetes環境を簡単に構築・管理することができます。2019年9月時点でサポートされているProviderは以下の通りです。

  • AWS
  • Azure
  • Baidu
  • Baremetal
  • DigitalOcean
  • Exoscale
  • GCP
  • IBM Cloud
  • OpenStack
  • Packet
  • Talos
  • Tencent Cloud
  • vSphere

一般的にはKubernetesはコンテナ管理のプラットフォーム(オーケストレータ)として知られていますが、実はKubernetesはコンテナ以外のものも管理することできる枠組みが備わっています。Kubernetes のアーキテクチャの根本をなす部分として、システムをあるべき状態(Desired State)に保つ、という機能があります。Kubernetesでは、さまざまなリソースのあるべき状態を宣言的に定義しリソースの作成を行うと、それらのリソースの状態は常に監視され、あるべき状態と現在の状態(Current State)に差が生じている事を検出すると、あるべき状態に戻そうという動きをします。これはKubernetesのReconciliation Loopと呼ばれるメカニズムによって実現されています。

例えば、Podが3つ動いているはずなのに実際にはPodが2つしか動いていなければ、Kubernetesは自動的にPodを1つ新たに立ち上げて、常に3つのPodが動いているように調整(修復)をしてくれます。このようないわゆる自己修復(Self Healing)機能が働くのはReconciliation Loopのおかげです。

KubernetesではDeployment、Replicaset、Pod、Node、Secret、StorageClassなど50種類ほどのリソースがあらかじめ定義されていますが、Kubernetesはこれらの定義済みのリソース以外のものを定義する仕組みが備わっており、Custom Resource Definition(CRD)と呼ばれています。CRDを定義しそれに対応するコントローラを書けば、自由にさまざまなリソースをKubernetesで扱うことができるようになります。これらのCRDで定義されたリソースにもReconciliation Loopによる自己修復機能を働かせることができるため、Kubernetesは変化に富む分散システムのライフサイクル管理をする汎用的なフレームワークとしても使うこともできるわけです。

Cluster APIはこのようなKubernetesの特性を活かし、クラスタなどのプラットフォームを規定するリソースをCRDとして定義して、それらをKubernetes自体で管理することで、KubernetesをKubernetesで管理する、というアーキテクチャになっています。

ClusterAPIでは以下の5つのCRDを用意しています。

  • Cluster
  • Machine
  • MachineSet
  • MachineDeployment
  • MachinClass

Cluster

Clusterリソースはクラスター全体の設定を規定します。例えば、ServiceやPodで使用するCIDRブロックの指定やドメイン名を指定します。またproviderSpecアトリビュートでクラスタ全体に関わるProvider固有の設定も行えます。

apiVersion: "cluster.k8s.io/v1alpha1"
kind: Cluster
metadata:
  name: workload-cluster-1
spec:
  clusterNetwork:
    services:
      cidrBlocks: ["100.64.0.0/13"]
    pods:
      cidrBlocks: ["100.96.0.0/11"]
    serviceDomain: "cluster.local"
  providerSpec:
    ...

Machine

Machineリソースは、Kubernetesを動作させるノードの設定を規定します。例えばkubeletやKubernetesのコントロールプレーンのバージョンなどを指定します。また、providerSpecアトリビュートではノードが使用するメモリ量やCPU数、インスタンスのタイプなどを指定します。

apiVersion: cluster.k8s.io/v1alpha1
kind: Machine
metadata:
  name: "workload-cluster-1-controlplane-1"
  labels:
    cluster.k8s.io/cluster-name: "workload-cluster-1"
spec:
  providerSpec:
    ...
versions:
    kubelet: "1.13.6"
    controlPlane: "1.13.6"

MachineSet

MachineSetリソースではMachineリソースがいくつ動いているべきかをreplicasアトリビュートで指定します。

apiVersion: cluster.k8s.io/v1alpha1
kind: MachineSet
metadata:
  name: "workload-cluster-1-machineset-1"
  labels:
    machineset-name: "workload-cluster-1-machineset-1"
    cluster.k8s.io/cluster-name: "workload-cluster-1"
spec:
  replicas: 3
  selector:
    matchLabels:
      machineset-name: "workload-cluster-1-machineset-1"
      cluster.k8s.io/cluster-name: "workload-cluster-1"
  template:
    metadata:
      ...
    spec:
      ...

MachineDeployment

MachineDeploymentリソースはMachine、MachineSetのアップデートポリシーを規定します。現在サポートされているアップデートポリシーはRollingUpdateのみです。

apiVersion: "cluster.k8s.io/v1alpha1"
kind: MachineDeployment
metadata:
  name: "workload-cluster-1-machineset-1"
  labels:
    cluster.k8s.io/cluster-name: "workload-cluster-1"
spec:
  replicas: 3
  selector:
    matchLabels:
      cluster.k8s.io/cluster-name: "workload-cluster-1"
      set: node
  template:
    metadata:
      ...
    spec:
      ...

MachineClass

MachineClassリソースは、どのProviderSpecを使用するのかを規定します。Machine、MachineSet、MachineDeploymentリソースは、どれもproviderSpecアトリビュートでプロバイダに固有な情報を設定することができますが、プロバイダ情報は共通であることが多いので、何箇所も同じ設定をするのは面倒です。そこでMachineClassを使ってプロバイダ固有の情報を記述し、他のリソースからそれを参照するようにすることで、よりシンプルにMachine関係のリソースを記述することができるようになります。

apiVersion: "cluster.k8s.io/v1alpha1"
kind: MachineClass
metadata:
  name: "workload-cluster-1-machine"
providerSpec:
  value:
    apiVersion: ...
    kind: ...

お気付きの方も多いかと思いますが、Cluster APIのCRDは、標準でサポートされているリソースと類似性があります。

Machine — Pod
MachineSet — ReplicaSet
MachineDeployment — Deployment
MachineClass — StorageClas

このような類似性を踏まえると、Kubernetesをすでに使っている人にとってはClusterAPIは理解しやすいのになるのではないかと思います。

次回はCluster APIとvSphere用のProviderを使ってvSphere上にKubernetesのクラスタを立てる解説し、、、ようと思ったのですが、ちょうど@masanaraさんがQiitaにこのトピックについて記事をあげて下さいましたので、皆さんこちらをご参照ください。

Photo by apoorv mittal on Unsplash

RADIO 2019

VMwareが行なっているRADIOというイベントに参加するためにサンフランシスコに来ています。RADIOはResearch And Development Innovation Offsiteの略で、年に一度VMwareのエンジニアリングチームが集まり、4日間かけて先進的な取り組みついて発表をする場となっています。RADIOでセッションをするためには社内論文を出して採択される必要があり、かなり狭き門となっています。そのためRADIOでの発表はエンジニアリングにとって大きなモチベーションになっていて、これに向けて1年(あるいは複数年に渡って)頑張ってリサーチに取り組んでいるエンジニアも多いです。ここで発表されものから多くの特許が生まれ、また実際に製品となったりします。特に優秀と認められたものには全員の前で発表するResearch Talkが認められ、その他にも各種Breakoutセッション、BoF、JIT BoF(その場でテーマが決められて行うBoF)、Posterセッション(ブース出展)、など様々な機会が与えられています。VMwareのExecutiveたちも参加しますので、Executiveたちからの話を聞けるのはもちろんのこと、毎年著名なGeust Speakerを呼んで話をしてもらうのが通例となっているようです(今年誰が来るのかはまだ分かりません)。

2000名近くのエンジニアが一堂に会して、かつ、キャンパスででなくオフサイトで行われるイベントですのでコストもそれなりにかかっていると思われますが、「会社が元気 -> R&Dに投資できる -> イノベーションが生まれ新製品が出てくる -> 収益が上がり会社が元気になる」という正のフィードバックループがうまく回っているな、と感じます。

原則エンジニアリング向けのイベントなのでフィールドから参加することはできないのですが、若干名フィールドからの参加が認められており、今回日本からも数名参加をしています。実は私もRADIOに参加するのは今回が初めてです。今まで何度か参加の機会はあったのですが、色々な理由で実際に参加することはできていませんでした。同僚からはRADIOの素晴らしさはよく聞くのでとてもワクワクしています。RADIOでされる話は製品化前の話がほとんどですので、どんな話があったかは基本的に非公開でお話しすることはできないのですが、一部はメディアに公開される予定ですのでご期待ください。

(Photo by Kristopher Roller on Unsplash

Blogお引っ越し

長年の懸案であったこのBlogサイトの引っ越しを行いました。2011年よりさくらインターネットのVPSインスタンス上に立てたWordpressを使ってきましたが(さくらインターネットさん、長い間ありがとうございました!)、メモリ1GB、ディスク20GBという小さなインスタンスだったたので、(攻撃を受けた時など)度々Out of Memoryで落ちたり、運用的に苦労もしてました(最近のさくらさんは、ping監視してメールやSlackで通知してくれるサービスを提供してくれているようですね。知らなかったw)。

ただ、いまどき自分でBlogをマネージするのもイケてないなと思い、今回他のサービスへの乗り換えも検討しました。カスタムドメインをサポートしていたMedium.comが筆頭候補だったのですが、残念ながらMedium.comは最近カスタムドメインのサービスを廃止してしまったようです。その他、note、Qiitaなどのサービスも検討はしたものの、現サイトのコンテンツに対する他のサイトからのリンクなども結構あるので、できることなら記事のURLを変えたくなく、結局自宅のESXi上の仮想マシンにWordpressを立てる、という技術的にはあまり代わり映えのしないお引越しとなってしまいました。

なお、今回の引っ越しにはAll-in-One WP Migrationというプラグインを使いました。これを使うとほぼ全てのWordpressのデータとプラグインなどを含む環境を簡単にマイグレーションすることができて大変便利です。前の環境がPHP5系、新しい環境がPHP7系だったので少し心配でしたが、特に問題なく移行する事ができました。

ESXi環境になりスナップショットを気軽に取れるようになったので、いろいろ設定変更しやすい環境にはなりました。しばらくはこの構成で運用して行こうと思います。

という記事を新環境でポストしてみるテスト。

追伸:Simple Tweetが動かなくなってしまったようです。原因調査中。

(Photo by Harshil Gudka on Unsplash)

2018年総括

主な出来事

1月 大雪にやられる。
2月 Cisco退社。
3月 スペイン&ポルトガル旅行。
4月 VMwareへ2度目の入社、Tesla試乗して加速にビビる。
5月 KONAMIに通い出す(のち挫折)。
6月 CIO Forum、INTEROP Tokyo、香港出張、VMバンド応援、ユッケ丼にやられる。
7月 シンガポール出張、立教キャンパス巡り、猛暑。
8月 Palo Alto出張、VMworld@Las Vegas。
9月 HBDメッセージ107件、オフサイト@湯沢、コサインreuion、sd-wan.jp退役、ServerlessConf、まり古墳ツアー。
10月 ONC@軽井沢、盛況。
11月 vForum Tokyo、登録者10,000人超え。靭帯損傷。
12月 JKD v18.12、vForum Osaka、VMバンドライブ。

新たな取り組み

  • 浜松町で働き出す(昨年も同じような事言ってて済みません)

Facebook Most Likes

3位 琴音の習字(大穴)  225件
2位 VMware入社  307件
1位 Cisco最終日  335件

映画

約30本。洋画ベスト:「Three Billboards」、邦画ベスト:「カメラを止めるな」。出張が少なめだったため、本数もかなり少なめ。Facebookの映画記録アプリがあまりにウ◯コなため、来年からはFimarksで記録を取っていくことにした。

バイタル

体重ほぼ横ばい(前半は減少、後半は増加)。平均睡眠時間は5時間40分(だいぶ改善)。一度食中毒に苦しんだ以外は至って健康。なぜか足をグキッとやり靭帯損傷。KONAMIに通い始めるも挫折。

読んだ本

10冊程度。ほとんど技術書。いかんわー。

コミュニティーへの貢献

  • DockerMachineのFusion Driverのbug fix
  • Dispatch CLIのBash Completion

フライト

  • JAL 6回、16,804 FLY ONポイント(2017年は 8回、23,779 FLY ONポイント)
  • ANA 8回、20,040ポイント(2017年は8回、11,816ポイント)

今年も出張は少なめ。来年はANAでマイルを貯める予定。

開拓した肉屋

  • 炭火焼肉 壱牛
  • 焼肉京城 水道橋店
  • とんかつ檍 大門店
  • まるたけ 近江 西川
  • 焼肉やよい
  • 蕃 YORONIKU
  • 徳壽
  • 焼肉ヒロミヤ 3号店
  • 東京食肉市場直送 肉焼屋 D-29
  • USHIHACHI 品川港南口店
  • 和牛焼肉KIM 茅場町
  • みやび 六本木店

思いの外開拓できた。歓送迎があった、という要因が大きいかもw

2019年の目標

  • KONAMI再開
  • 英語頑張る
  • コミュニティーへの貢献
  • ライブ
  • non-技術書を読む
  • 少し体重を落とす

2018年にやり残したものが多いなー。ま、継続は力なり。諦めずに頑張って行きたいと思います。

画像クレジット:unsplash-logoSteven VanDesande Jr

Dispatch Serverless Framework

Dispatch は Function as a Service (FaaS) のためのフレームワークで、VMware が中心となってオープンソースで開発が進められています。

一般的に FaaS は大きく分けるとホスティングされたサービスとして提供されるもの(e.g. AWS Lambda、Azure Functions、Google Cloud Function、など)と、自らインストールして使うもの(Apache OpenWhisk、OpenFaaS、Fission、Kubreless、Riff、など)がに分けられますが、この分類でいくと Dispatch は後者に分類されるものになります。ただし、Dispatch はいわゆる FaaS 機能の中核となる部分(エンジン)を提供しているわけでありません。OpenFaaS、Kubeless、Riff など、現在  FaaS エンジンには多くの選択肢があります。このような状況の中で Dispatch がこれらの FaaS エンジンと似たような機能を提供してもあまり価値がありません。まだ、どの FaaS エンジンが今後主流になって行きそうかも分からない状況なので、特定のエンジンを前提にするのもあまり筋がよろしくなさそう、ということで、Dispatch は FaaS エンジン部分を pluggable にして、その周辺機能を実装する、という戦略を取っています。Dispatch が「FaaS フレームワーク」と呼ばれる所以です。

現在、Dispatch には2つのバージョン(ブランチ)があります。一つは Dispatch-Solo と呼ばれるもの、もう一つは Dispatch-Knative と呼ばれるものです。

Knative というのは Google Cloud Next 2018 で発表されたプロジェクトで、Google、Pivotal、RedHat、IBM などが開発に関わっています。その狙いは Dispatch に近く、FaaS / Serverless に対して、Build / Serving / Events といった基本的な building block を提供しよう、というものです。Dispatch は Knative が発表された際に、Knative と競合路線を取るのではなく、Knative と協調していく、という判断をしました。つまり、Knative が提供する基本機能(Build、Serving、Events)は Knative のものを利用し、マルチテナンシーなど、Knative にはない Dispatch ならではの機能を Dispatch として提供していこう、というわけです。この Knative  をベースにした Dispatch が Dispatch-Knativeで、商用環境で使われることを想定したフル機能版の Dispatch の開発を目指しています。Dispatch-Knative はプラットフォームとして Kubernetes を利用しており、現在盛んに開発が行われています。

Dispatch-Knative アーキテクチャ

一方、Dispatch-Solo は、Dispatch-Knative の持つ様々な依存関係を極力最小化して、出来るだけ手軽に使えるものを提供することを目的に作られています。Dispatch-Solo はプラットフォームに Kubernetes を必要とせず、Docker だけで動くようになっています。また Photon OS をベースとした OVA としてパッケージされていますので、手軽に ESXi、VMware Workstation、VMware Fusion 上に展開して使うことができます。Dispatch-Solo は Dispatch-Knative とほぼ同様な機能を提供していますが、スケールアウト、マルチテナンシー、サービス連携の機能がない等、一部機能に制限があります。プロダクション利用ではなく、お手軽に利用できることに注力をしているバージョンです。

Dispatch-Solo アーキテクチャ

Dispatch は以下のような機能を持っています。

  • Kubernetes 上で動作(Dispatch-Knative のみ)
  • Pluggable FaaS Engine (OpenFaaS, Riff, Kubeless)
  • Runtime (Pyhton3, Nodejs, Java, Powershell, Clojure)
  • Let’s Encrypt サポート
  • OpenTracing 対応
  • 複数 IDP (Google, Auth0, vIDM, GitHub) のサポート(Dispatch-Knativeのみ)
  • Organization に基づいたマルチテナンシー(Dispatch-Knative のみ)
  • RBAC 機能
  • Cloud Events 対応
  • 拡張可能なイベントドライバ
  • Open Service Broker 統合(Dispatch-Knative のみ)

Dispatch によって作られた Function は大きく分けて2つの方法で呼び出されます。一つは Function に API の Endpoint を設けて、それを明示的(同期的)に呼び出す方法です。Dispatch には Kong というオープンソースの API Gateway が組み込まれており、これを利用して API Endpoint を Function に紐づけることができます。もう一つの Function の呼び出し方法はイベントドライバによる呼び出しです。イベントドライバがサポートしているイベントと Dispatch によって作られた Function を binding することにより、非同期的に発生するイベントによって Function を呼び出すことができます。

現在 Dispatch がサポートしているイベントドライバは以下の通りです。

  • CloudEvent
  • vCenter
  • AWS
  • EventGrid
  • Cron

VMware が開発を主導していることもあり、vCenter のイベントドライバがサポートされているのが特徴的です。これにより例えば ESXi 上の仮想マシンの Power ON/OFF などをトリガーにして Dispatch に登録された Function を実行しオペレーションの自動化を実現する、といったことが可能になります。

今回はお手軽に利用できる Dispatch-Solo を使って、簡単に動作をみてみることにしましょう。

Dispatch-Solo の最新版の OVA は以下の方法で入手することができます。

$ curl -OL http://vmware-dispatch.s3-website-us-west-2.amazonaws.com/ova/dispatch-latest-solo.ova

次にこの OVA ファイルをデプロイします。今回は VMware Fusion を使うことにします。アプリケーションおよびネットワークの設定を聞かれますが、root パスワードだけ設定すれば大丈夫です。

Dispatch のバイナリをダウンロードしてインストールします。現在 Mac 用と Linux 用のバイナリが用意されています(残念ながら Windows 用のバイナリは今のところ用意されていません)。

(Mac/Linux共通)
$ export LATEST=$(curl -s https://api.github.com/repos/vmware/dispatch/releases/latest | jq -r .name)

(Macの場合)
$ curl -OL https://github.com/vmware/dispatch/releases/download/$LATEST/dispatch-darwin$ chmod +x dispatch-darwin$ mv dispatch-darwin /usr/local/bin/dispatch

(Linuxの場合)
$ curl -OL https://github.com/vmware/dispatch/releases/download/$LATEST/dispatch-linux$ chmod +x dispatch-linux$ mv dispatch-linux /usr/local/bin/dispatch

インストールした Dispatch-Solo の仮想マシンに振られた IP アドレスを確認し、それを DISPATCH_HOST という環境変数に設定して Dispatch が使用する設定ファイルを作っておきます。

$ export DISPATCH_HOST=10.156.250.95
$ cat << EOF > $HOME/.dispatch/config.json
{
"current": "solo",
"contexts": {
"solo": {
"host": "${DISPATCH_HOST}",
"port": 8080,
"scheme": "http",
"organization": "dispatch",
"cookie": "cookie",
"insecure": true,
"api-https-port": 443
}
}
}
EOF

これで Dispatch を使う準備が一通り整いました。ここから Dispatch を使って Function を作っていきます。まず、Funciton を実行するベースとなるイメージを作ります。各ランタイム(言語)ごとにイメージが用意されていますが、”create seed-image” コマンドを使うと、Node.js、Python 3、Java、Powershell 用のイメージを一発で作ることができるので便利です。

$ dispatch create seed-images
Created BaseImage: nodejs-base
Created BaseImage: python3-base
Created BaseImage: powershell-base
Created BaseImage: java-base
Created Image: nodejs
Created Image: python3
Created Image: powershell
Created Image: java
$ dispatch get images
     NAME    | URL |    BASEIMAGE    |  STATUS  |         CREATED DATE         
--------------------------------------------------------------------------
  java       |     | java-base       | CREATING | Sat Dec  8 16:16:24 JST 2018 
  nodejs     |     | nodejs-base     | CREATING | Sat Dec  8 16:16:24 JST 2018 
  powershell |     | powershell-base | CREATING | Sat Dec  8 16:16:24 JST 2018 
  python3    |     | python3-base    | CREATING | Sat Dec  8 16:16:24 JST 2018 

“create seed-image” コマンド実行直後は “get image” コマンド結果の STATUS の欄が “CREATING” になっていますが、しばらく待つと全てのランタイムの STATUS が “READY” になります。

$ dispatch get images
     NAME    |                         URL                          |    BASEIMAGE    | STATUS |         CREATED DATE         
-------------------------------------------------------------------------------------------------------------------------
  java       | dispatch/dd3c73a4-2cf7-40db-8944-6c0d11f9157b:latest | java-base       | READY  | Sat Dec  8 16:16:24 JST 2018 
  nodejs     | dispatch/bbd15fbc-cfef-43d6-9d56-105c359fdedd:latest | nodejs-base     | READY  | Sat Dec  8 16:16:24 JST 2018 
  powershell | dispatch/1efa88c4-55cc-4bf8-a6d9-0a80c084cc89:latest | powershell-base | READY  | Sat Dec  8 16:16:24 JST 2018 
  python3    | dispatch/bcd7a157-117e-47c3-a276-3012d07b1848:latest | python3-base    | READY  | Sat Dec  8 16:16:24 JST 2018 

次に実際に実行される Function を作っていきます。今回は Python を使って簡単な関数を作ってみましょう。

$ cat << EOF > hello.py
def handle(ctx, payload):
    name = "Noone"
    place = "Nowhere"
    if payload:
        name = payload.get("name", name)
        place = payload.get("place", place)
    return {"myField": "Hello, %s from %s" % (name, place)}
EOF

handle() という関数がいわゆるハンドラ関数で、関数のエントリポイントとなります。この handle() という関数は2つの引数を取ります。”ctx” は Context の意で、ホスト側から渡される情報(例えば Secret など)が入ってきます。一方、”payload” の方は HTTP(S) のリクエストで渡されれてくる情報が入ってきます。今回の例では HTTP POST されてくる “name” というアトリビュートと “place” というアトリビュートを payload  から取り出しています。

次に “create function” コマンドで今しがた作った関数を Dispatch に登録します。今回はその関数に “hello-world” という名前を付けることにします。

$ dispatch create function hello-world --image python3 ./hello.py
Created function: hello-world

“get function” コマンドで関数が作られたのを確認することができます(STATUS の欄が READY になれば OK です)。

$ dispatch get function
     NAME     |                       FUNCTIONIMAGE                       | STATUS |         CREATED DATE         
--------------------------------------------------------------------------------------------------------------
  hello-world | dispatch/func-02625403-7cf4-477f-aca8-793a9cc2d55c:latest | READY  | Sat Dec  8 16:18:18 JST 2018 

では、この関数を実際に呼び出してみましょう。それには “exec” コマンドを使います。HTTP のパラメータは “–input” に続く文字列で指定できます。

$ dispatch exec hello-world --input '{"name": "Jon", "place": "Winterfell"}' --wait
{
    "blocking": true,
    "executedTime": 1544253540926528854,
    "faasId": "02625403-7cf4-477f-aca8-793a9cc2d55c",
    "finishedTime": 1544253540930869980,
    "functionId": "4a550524-85da-4d28-9d5f-47b35a425cd8",
    "functionName": "hello-world",
    "input": {
        "name": "Jon",
        "place": "Winterfell"
    },
    "logs": {
        "stderr": null,
        "stdout": [
            "Serving on http://0.0.0.0:9000"
        ]
    },
    "name": "440256c2-7710-4ea1-bc20-5231c2bd4363",
    "output": {
        "myField": "Hello, Jon from Winterfell"
    },
    "reason": null,
    "secrets": [],
    "services": null,
    "status": "READY",
    "tags": []
}

“–wait” というパラメータはこの関数の呼び出しを同期的に行う、という意味です。”–wait” を付けないと、関数は実行されますが、”exec” コマンドはその関数の終了を待たずに終了しますので、結果は別途確認する必要があります。今回は “–wait” を付けて実行していますので、返された JSON の中の “output” に期待された結果が返ってきているのが確認できます。

次に、この関数に API Endpoint を設定してみましょう。API Endpoint の設定には “create api” コマンドを使用します。

$ dispatch create api api-hello hello-world --method POST --path /hello
Created api: api-hello
shindom-a01:Downloads shindom$ dispatch get api api-hello
    NAME    |  FUNCTION   | PROTOCOL  | METHOD | DOMAIN |                   PATH                   |  AUTH  | STATUS | ENABLED 
--------------------------------------------------------------------------------------------------------------------------------
  api-hello | hello-world | http      | POST   |        | http://10.156.250.95:8081/dispatch/hello | public | READY  | true    
            |             | https     |        |        | https://10.156.250.95/dispatch/hello     |        |        |         
--------------------------------------------------------------------------------------------------------------------------------

では、この API Endpoint を呼び出してみましょう。

$ curl http://10.156.250.95:8081/dispatch/hello -H "Content-Type: application/json" -d '{"name": "Motonori", "place": "Tokyo"}'
{"myField":"Hello, Motonori from Tokyo"}

さて、ここまでは関数を CLI もしくは API Endpoint から同期的に関数を呼び出す例をみてきましたが、今度はイベントドライバによる非同期的な関数の呼び出しを試してみましょう。

Dispatch でサポートされているいくつかのイベントドライバの中から、今回は最もシンプルな Cron Event Driver を使ってみましょう。Cron Event Driver はその名の通りで、定期的に関数を呼び出してくれるイベントドライバで、UNIX の cron と同じような書式で起動するタイミングを指定をすることができます。

Dispatch のイベントドライバを使うためには3つのステップを踏む必要があります。1つ目は Event Driver Type の設定です。今回はdispatchframework にある Cron Event Driver に “cron” という名前を付けてやります。

$ dispatch create eventdrivertype cron dispatchframework/dispatch-events-cron:0.0.1
Created event driver type: cron

次に行うのは Event Driver の登録です。先ほど作った “cron” という Event Driver Type のドライバを作り “every-10-seconds” という名前を付け、イベントドライバに cron 書式(e.g. “0/10 * * * *”)で実行されるべきタイミングを指定します。

$ dispatch create eventdriver cron --name every-10-seconds --set cron="0/10 * * * *"
Created event driver: every-10-seconds

最後にイベントに対する subscription の設定を行います。具体的には Funciotn(今回の例で hello-world)とイベントドライバが生成するイベント(今回の例では cron.trigger)の紐付け( binding) 設定を行うことになります。

$ dispatch create subscription hello-world --name cron-sub --event-type cron.trigger
created subscription: cron-sub

これで設定は終わりです。この設定を行うと、10秒ごとに hello-world という Function が呼ばれることになり、その結果は “get runs” コマンドで確認をすることができます。

$ dispatch get runs
                   ID                  |  FUNCTION   | STATUS |               STARTED               |              FINISHED               
-------------------------------------------------------------------------------------------------------------------------------------
  5f9a79e0-1612-4169-90e8-e28e1f26640c | hello-world | READY  | 2018-12-08T16:35:30.003557189+09:00 | 2018-12-08T16:35:30.006887242+09:00 
  55fc2066-bd53-4e04-b0b6-bc1bb7940833 | hello-world | READY  | 2018-12-08T16:35:20.003363373+09:00 | 2018-12-08T16:35:20.007476442+09:00 
  19878a0d-312d-44ca-94b7-dc4999caf433 | hello-world | READY  | 2018-12-08T16:35:11.482092927+09:00 | 2018-12-08T16:35:11.485768711+09:00 
  14d2f6dc-2aa6-4bef-b9c4-a1cd6db6fe1f | hello-world | READY  | 2018-12-08T16:35:00.003163345+09:00 | 2018-12-08T16:35:00.007290792+09:00 
  d55328b0-53a5-48b0-b828-0ddff6648cd9 | hello-world | READY  | 2018-12-08T16:34:50.002078415+09:00 | 2018-12-08T16:34:50.006185049+09:00 
  3bc0d86b-1d73-4a94-bd7b-142f6d4743ae | hello-world | READY  | 2018-12-08T16:34:41.469205488+09:00 | 2018-12-08T16:34:41.472881958+09:00 

いかがでしたでしょうか? Dispatch はまだまだ若いプロジェクトで、活発に開発が行われています。みなさん、是非 Dispatch を使ってみてフィードバックをしていただだけると助かります。また、Dispatch はまだまだ把握しやすい規模のプロジェクトですので、開発にも参加しやすいと思います。色々な形で皆で Dispatch を盛り上げていけると嬉しいです!

VMware is the Dialtone for Kubernetes / 20代の人には分からないだろうけどw

最近たびたび “Dialtone” という言葉を耳にすることがあります。例えば今年(2018年)のVMworld U.S. Day 1 の General Session で、CEO の Pat Gelsinger が “VMware is the Daltone for Kubernetes” というフレーズを使っていました。最近の若者には馴染みがないかもしれませんが、この “Dialtone”、いわゆる電話の受話器をあげた時にするあの「ツーー」という音のことです。Pat も壇上で「20代の人には分からないかもしれないけど・・」とジョークを飛ばしてしましたね。

私は思い切り “元祖 Dialtone” 世代な人間ですが、上記のような新しい使われ方をした “Dialtone” という言葉を聞くたびに、何となく意味が分かるような分からないようなで、眠れない日々を送っていました(嘘)。このままではいかん、ってことで、この Dialtone ってのは一体どういう意味なんだ、と上司(Bruce Davie)に聞いてみたところ明快な説明をしてくれました。最近の Dialtone という言葉は、「世界中どこにいても普遍的(ubiquitous)に存在していて、誰しもがそれの意味を理解していて使うことができる」ということを比喩的に表しているんだそうです。確かに昔の電話の「ツーー」という音も、ほぼグローバルで共通で皆がその意味を理解できていたと思います。別の Dialtone の例としては、例えば HTTP is the dialtone for the Internet なんて言い方もできるそうです(HTTP はほぼインターネット上の共通言語なので)。

なるほど、これですっきり眠れるようになりました!(笑)

画像クレジット:unsplash-logoPaweł Czerwiński

2017年総括

今まではFacebookに書いていた「今年の総括」ですが、せっかくなのでこちらに書いて置こうかと思います(あんまりBlog記事書けてないので、記事数稼ぎですw)

2017年も残すところあと数時間となりました。今年も簡単に一年を振り返ってみたいと思います。

主な出来事

1月 スタバで相武紗季に遭遇。
2月 特筆すべきことなし。
3月 ギターを新調。Ascend時代の友人と20年ぶりの再会。
4月 車を小型化。
5月 CiscoによるViptela買収発表。
6月 INTEROP、本棚大幅増設。
7月 我が家に蟻侵入、たくろーさんライブ、素晴らしかった。
8月 買収完了。Cisco GSXに参加、デカイ。
9月 今年も沢山のHBDメッセージ、ありがとうございました!
10月 ONIC Japan、大盛況でした。姪っ子の結婚式。シンガポール出張。
11月 EBC & Sales Kickoff。
12月 パラオへ。

2017年の新たな取り組み

  • 六本木で働く^^
  • Enriched Air 取得

2017年 Most “Like!” On Facebook

  • Ciscoロゴの前でとった写真(237件)。そんなに違和感があるかしら?ww

2017年に読んだ本

  • 3〜4冊? ひどい状態。

フライト

  • JAL 8回、23,779 FLOY ONポイント(去年 23回、50,245 FLY ONポイント)
  • ANA 8回、 11,816 ポイント(去年 6回、10,674 ポイント)

今年は出張が少なかったため、去年と比べるとかなり減った。

2017年に開拓した肉屋

  • USHIHACHI 武蔵小杉店
  • 鉄板焼き 貴真
  • うしごろ 銀座店
  • トラジ葉菜 上大岡店
  • Dish Dash Grill Milpitas店
  • Strip Steak Honolulu店
  • Jan Su Jan Milpitas店

こちらも去年と比べると激減。忙しかったからなー。

2017年に見た映画

  • 約30本。
  • 洋画ベスト「きっと、星のせいじゃない(原題:The Fault in Our Starts)」。
  • 邦画ベストは該当なし。

出張が減ったぶん見た本数も減ったが、Amazon Videoで少し補った。

2018年目標

  • 2017年にやり残したこと
  • 新たしいことへの挑戦(いろいろ)
  • 英語頑張ろう!

こんなところです。また来年もよろしくお願いいたします。

NATは意外と難しい

以下の議論はNATでもNAPTでも成り立つので、どちらの場合でも単にNATと書くことにします。

ViptelaのIPsecの認証方法はauthentication-typeというパラメータで指定することができます。例えばこんな感じです。

security
 ipsec
  authentication-type ah-sha1-hmac sha1-hmac ah-no-id
 !
!

ah-sha1-hmac、sha1-hmacはほぼ自明だと思いますが、ah-no-idという見慣れない設定は何のためにあるのでしょう?

一般的にはNATが途中にあるとAHは機能しません。NATが書き換えるフィールドがAHで守られているからです。しかし、Viptelaのアーキテクチャでは、仮にNATが途中にあっても変換前と後のIPアドレス、ポート番号をシステムが把握しているため、NAT環境であってもAHを使用することができるようになっています。ただし、NATで書き換えられるのがIPアドレスとポート番号だけであれば良いのですが、一部のNATの中にはIPヘッダのIdentificationフィールド(以下、IDフィールド)を書き換えるものがあります。ah-no-idというパラメータはこのようなNATデバイスがある場合に使用するもので、AHによる検証をする際にIDフィールドを無視する、という意味になります。

世の中のNATにIDフィールドを書き換えるNATがいるのか最初は疑っていたのですが、実際このようなNAT実装は存在するようで、少なくともApple AirMac ExtremeやAirMac Expressはそのように動くようです。実際、手元にあったAirMac Expressで試してみました。
[shell]$ sudo hping3 -c 1 -N 12345 -S -s 11111 -p 22222 8.8.8.8[/shell]
のようにパケットを出してみて、NATされる前と後のパケットを比較してみました(ちなみに-SオプションをつけてSYNフラグを付けているのは、NATの実装の多くはTCPのステートをみていて、SYNパケットがくる前にパケットが来てもトランスレーションせずに廃棄するからです)。

NAT変換前(AirPort Express):
[shell]06:21:06.670952 IP (tos 0x0, ttl 64, id 12345, offset 0, flags [none], proto TCP (6), length 40)
10.0.1.3.11111 > 8.8.8.8.22222: Flags [S], cksum 0xa76d (correct), seq 868543788, win 512, length 0[/shell]
NAT変換後(AirPort Express):
[shell]15:20:52.361257 IP (tos 0x0, ttl 63, id 14428, offset 0, flags [none], proto TCP (6), length 40)
10.156.250.80.44210 > 8.8.8.8.22222: Flags [S], cksum 0x2c38 (correct), seq 868543788, win 512, length 0[/shell]
このように確かにIDフィールドが12345から14428に変換されています。

比較のためにVyOSのNATを使って同じように試験をしてみましょう。

NAT変換前(VyOS):
[shell]08:37:57.157399 IP (tos 0x0, ttl 64, id 12345, offset 0, flags [none], proto TCP (6), length 40)
10.200.1.11.11111 > 8.8.8.8.22222: Flags [S], cksum 0x5623 (correct), seq 7492057, win 512, length 0[/shell]
NAT変換前(VyOS):
[shell]08:37:57.157410 IP (tos 0x0, ttl 63, id 12345, offset 0, flags [none], proto TCP (6), length 40)
221.245.168.210.11111 > 8.8.8.8.22222: Flags [S], cksum 0xdb2d (correct), seq 7492057, win 512, length 0[/shell]
こちらはNAT変換前も変換後もIDフィールドは12345のままです。

今まで私はIDフィールドはデータグラムがフラグメントされた際のリアセンブルに使用されるためのものなので、途中の機器で書き換えられるべきではない、と考えていました。したがって、このようにIDフィールドまで書き換えるNATはかなり特殊で、いわゆるキワモノ(変態)であると思っていたのですが、先日 RFC6864 “Updated Specification of the IPv4 ID Field” を見つけて読んでみると、この考えが変わりました。

このRFCではIPデータグラムをAtomicなものとNon-Atomicなものに分類して考えています。

Atomicなデータグラム
まだフラグメントされておらず、その後もフラグメントされることのない(フラグメントが禁じられている)データグラム
Non-Atomicなデータグラム
すでにフラグメントされているか、今後フラグメントされる可能性のあるデータグラム

歴史的にはIDフィールドはリアセンブル以外の目的(例えば重複検知、など)での使い方も考えられていたものの、このRFCでは改めてIDフィールドはリアセンブル以外の目的で使うことを禁止することを明確化し、それに伴いAtomicなデータグラムに対してはIDフィールドに関する要求条件を緩めています(AtomicなデータグラムにIDフィールドは不必要なため)。しかしながら、Non-Atomicなデータグラムに対しては依然RFC791で規定されている「MDL (Max Datagram Lifetime、典型的には2分)の間は同じIDを使い廻してはいけない」という要求をしています。

これはNATのようないわゆるミドルボックスにはかなりややこしい問題です。本RFCでも、

NATs/ASMs/rewriters present a particularly challenging situation for
fragmentation. Because they overwrite portions of the reassembly
tuple in both directions, they can destroy tuple uniqueness and
result in a reassembly hazard. Whenever IPv4 source address,
destination address, or protocol fields are modified, a
NAT/ASM/rewriter needs to ensure that the ID field is generated
appropriately, rather than simply copied from the incoming datagram.

Specifically:
>> Address-sharing or rewriting devices MUST ensure that the IPv4 ID
field of datagrams whose addresses or protocols are translated
comply with these requirements as if the datagram were sourced by
that device.

(拙訳)NAT/ASM (Address-Sharing Mechanism)/rewriterはフラグメンテーションに困難をもたらす。両方向においてリアセンブルするためのタプルの一部を書き換えるため、タプルのユニーク性を担保することができなくなり、リアセンブルができなくなるからである。IPv4送信元、送信先アドレスまたはプロトコルフィールドが書き換えられる場合は、NAT/ASM/rewriterは単に元のデータグラムのIDフィールドをコピーするのではなく、IDフィールドが正しく生成されることを保障しなければならない。

具体的には、Address-sharingまたはrewriterデバイスがIPv4データグラムのアドレスやプロトコル番号を書き換えた場合は、IDフィールドが、あたかもデータグラムがそのデバイスから出たかのごとく、これらの要求条件を満たすようにIDフィールドを使わなければいけない。

と書かれています。確かによく考えると、送信元、送信先アドレス、プロトコルのタプルでのIDフィールドのユニーク性を担保するためには、アドレスを書き換えるNATデバイスは、元のパケットのIDフィールドを単純にコピーするべきではなく、あたかも自分が出したパケットかのようにユニーク性を担保したIDを新たに払い出す必要があります。経験的には多くのNATデバイスはVyOS (多くのLinuxベースのもの同様でしょう)のように動くように思いますが、Apple AirMac Extreme/Expressの動作の方が正しい(というか素性がよろしい)ということになります。

Appleさん、今まで変態扱いしてごめんなさい。

Catch-22

本日、iPhoneのバッテリーがなくなってしまい、ソフトバンクショップに駆け込んだ。モバイル・バッテリーは持っていたものの、Lightningケーブルを忘れてしまったので充電することができなかったのだ。ショップで充電はしてくれたのだが、その間仕事ができないので、ソフトバンクショップで繋がる無線LANを探すも、残念ながら無料で繋がるものはなし。0001softbankというSSIDは繋がるものの、ソフトバンクのデバイスでないと使えないので、Mac/PCはダメ。

一方、SWS1dayというSSIDはソフトバンクのWi-Fiスポットで、ソフトバンク以外の端末でも一日467円で使えるようだ。

しかたない、何事も経験かと思い、これを使おうと試みてみたが、サインアップの過程でメールでPINが送られてくる模様。ネット接続できないからネット接続サービスに申し込もうとしているのに、申し込みにネット接続がいる。詰んだ orz

こんな顛末をオフラインで書いている間に充電されたiPhoneが戻ってきました。ちゃんちゃんw