Kubernetes 大規模クラスタで MAC アドレスが衝突した話
概要
ovs-cni という CNI を用いた際に、 MAC アドレスの衝突が発生するという問題が起きました (https://github.com/k8snetworkplumbingwg/ovs-cni/issues/206)。発生環境は 100 台の worker node、24 個の vlan、 各 vlan ごとに 1000 個のインターフェイスという状態でした。
結論から言いますと、「普通に」使った場合は衝突確率は最大でも0.0639(%)なので気にする必要はありません。「普通」が何を意味するか、算出根拠は、等を知りたい方は以下をお読み下さい。
MACアドレスについて
MACアドレスと言うと「ハードウェアに固有のアドレス」であるため衝突はしないという説明が一般的かと思います。ただ、 Kubernetes クラスタにおいては、仮想インターフェイスを多用するため、MACアドレスも自動生成したものを使用しています。では自動生成した場合にどのぐらいの確率で衝突が起こるかを考える記事になります。
衝突確率の求め方
まず、衝突確率を計算するための式を立てます。わかりやすく書くつもりではありますが、数学が苦手な方は読み飛ばしていただいて構いません。
まず簡単な例として 6 面体のサイコロを 3 回振った場合を考えます。
出目が衝突するとは、少なくとも2つのサイコロが同じ目を出していると言い換えられます。
全ての出目のパターンは
また、全ての面が異なるパターンは
なので、少なくとも2つのサイコロがが同じ目を出す確率は
となり、確率はおよそ 44.4(%) となります。
これを一般化し、出目のパターンを possibility、試行回数を trials と書くと、衝突の確率は
と表すことができます。
衝突確率
では上の式を用いて確率を計算していきます。MACアドレス長は 48bit ですが、 ovs-cni において MAC アドレスは 02:00:00:XX:XX:XX の形式を振っているため、実際の MAC アドレス空間は 24bit です。よって
この不具合の後、MACアドレスを 0A:58:XX:XX:XX:XX に変更する修正が入り、MACアドレス空間は32bitに拡張されました。
さらに、これまで自前で行っていたMACアドレス割当を廃止し、SetupVeth()
関数に割当を任せるように変更しました。これはip link add
コマンドを使った場合に相当し、MACアドレス空間を46bitに拡張することができました。MACアドレス長である 48bit よりも 2bit 少ない理由は、下記2bitが固定されているためです。それぞれのbitの意味については https://en.wikipedia.org/wiki/MAC_address を参照して下さい。
unicast/multicast bit = 0
globally unique/locally administered bit = 1
46bitに拡張することで
ovs-cni にて発生した問題についてはこれで解決ですが、さらにインターフェイスが増えた場合を考えます。Kubernetesは「コンテナ数は300,000以下であること」というベストプラクティスを公表しています。
の条件で計算すると衝突確率は0.0639(%)となります。なので、今のところはMACアドレスの衝突については気にしなくても大丈夫そうですが、Kubernetesの性能向上等によりコンテナ数のベストプラクティスに変化があった場合は再度計算が必要になります。
Discussion