非常に便利で、そしてモダンな Kubernetes ですが、その仕組み故に「送信元アドレス」が書き換わる問題、つまり SNAT されてしまう挙動がデフォルトであり、ミドルウェアレベルで送信元アドレスに基づいてなんらかの制御(例えばログやアクセス制御)をしている場合は問題になることがあります。
対処方法としてはいくつかあります。
その一つが externalTrafficPolicy: Local です。これはデフォルトでは LB を経由すると LB のアドレスに書き換えるのですが、それを書き換えない設定です。詳しく調べてられていませんが、ちょっとした問題があるようです(多分切り替え時のパケットロスでは?)。ただ、BGP だと OK のように記載されている場合もあり、私は一応 BGP モードで MetalLB を使用しています。
次に、hostnetwork を使ってしまう案です。この場合は、ノードの分散処理は外部の LB に任せることになります。副次的なメリットとして、CNI を経由しない通信になるため、パフォーマンスは最高かもしれません。また、Kubernetes の効果を得つつ、シンプルなネットワーク構成でもあります。デメリットとしてはノード IP に対するポート番号になるので柔軟性には欠けるかもしれません(外部の LB でなんとでもなりますけど)。
最後は Calico の BGP を使用して Pod のセグメントをそのまま外部に公開してしまう案です。これもシンプルですし、ノード IP にも依存しないので、柔軟性もあります。デメリットは Pod のセグメントを重複しないように厳密に管理する必要がある点と、Pod の IP を固定化する必要がある点です。Kubernetes はご存知の通り、かなり広いアドレス空間を求めるため、IPv4 だと結構割り当てに悩みます。IPv6 はまあ楽なのですが。Pod の IP 固定はそういう運用にすれば良いのですが、Deployment で複数の Pod が登場する場合は固定化できるんだっけ?とか、考えきれていない部分もあります。
なので、最初の MetalLB + BGP + externalTrafficPolicy: Local が結局一番良いとは思うものの、他の案なども継続してベストプラクティスを考えていきたいところです。