Juju-62q's blog

参加記録やメモ書き、思考のまとめをしています

EKSでネットワークのデバッグをするときはネットワークインターフェースも確認しよう

f:id:Juju_62q:20190619233631p:plain

EKSのネットワークでどっぷり嵌ってました。無知というのは怖いものです。 同じようなところで時間を溶かす人が現れないことを願って自分のブログに戒めの気持ちも込めて書き記しておきます。

TL;DR

  • EKSでネットワークの確認をするときはノードのセキュリティグループ(以降 sg)だけでなく、ネットワークインターフェース(以降 eni)のものも確認する
  • EKSを本番運用するのであればEKSのCNIがどういうものなのかをきちんと確認してから使う
  • 自分が使っているものがどういう動きでどういうリソースを使っているのかはきちんと確認する

どんな事態になっていたか

  • EKSのコンテナが部分的に他のリソース(例えばRDSとか)と疎通ができない
  • 全てのpodをdeleteして、applyしなおすと通信できないpodが変わる
  • 通信できていないpodがlivenessProbeにより再起動しても接続はできないままなのに、deploymentをdeleteしてapplyすると疎通できるようになることがある
  • 同一インスタンス上のPodで、外部と疎通できるものとできないものがある

なるほど? f:id:Juju_62q:20190619234620p:plain

なぜこのようなことが起きたか

結論から言うとWorkerノードとしたインスタンスのsgとそのノードにアタッチされているeniのsgが異なっていたためです。

自分はインフラ管理をする際には基本的にはTerraform, CloudFormationのようなInfrastructure as Codeのためのツールを利用することが多いです。 一方で適当にデバッグする際なんかはいきなり定義を編集せずに、AWSコンソールをちょちょいといじって挙動を確認、リソースを作り直すなどして再現性を確認、その後ようやくコードを修正しています。

今回の場合、EKSクラスタを作成したのちにインスタンスに手作業でsgを追加していました。 ちなみに自分の今までの使い方の場合eniのsgとインスタンスのsgは一致していたため、この時点で自分にはsgはeniごとに設定できると言うことすら認知していませんでした。

EKSのネットワークはPodにVPC上のIPアドレスを直接割り当てるVPCネイティブな方式を採用しています。

VPCネイティブの話はKubernetes Meetup Tokyoで青山さんがお話していたものがわかりやすいので、存じない方はぜひ目を通してみてください。

speakerdeck.com

つまるところ、Podはeniに割り当てられたVPC内で一意なIPアドレスを占有します。 また、1つのeniでは6つのIPアドレスしかもつことができません。 EKSでは1台のWorkerノードになるべく多くのPodを載せられる状態を作りたいので、WorkerノードにPodが増えてくるとeniを追加してアタッチします。*1 このときに増えるeniにはインスタンスに設定されたsgは設定されず、AutoscaleGroupのlaunch configやlaunch templateで登録されたsgが設定されます。

この辺りの挙動が、自分の"インスタンスにsgを設定した"と言う感覚と食い違っていてはまっていました笑

上記の現象が発生した直接的な原因は?

ここまでがわかると、上記の現象がなぜ発生したのか説明がつきます。

EKSのコンテナが部分的に他のリソース(例えばRDSとか)と疎通ができない

  1. 外部と疎通するためのsgを設定していない、launch configをもつAutoscaleGroupを作成し、EKSのWorkerノードに設定する
  2. AWSコンソールから外部と疎通するためのsgをインスタンスに追加する*2
  3. Podをデプロイする
  4. Podの増加を受け、外部と疎通するためのsgが付いていないeniがWorkerノードにアタッチされ、そのeniに割り当てられたIPアドレスをもつPodが爆誕する

全てのpodをdeleteして、applyしなおすと通信できないpodが変わる

KubernetesによるPodの配置が毎回同一でないために利用するeniが毎回変更になっていた

通信できていないpodがlivenessProbeにより再起動しても接続はできないままなのに、deploymentをdeleteしてapplyすると疎通できるようになることがある

Podの再起動では基本的にPodのIPアドレスが変更されないため、同じeniを使い続けている。 一方でdelete後、applyしなおすとそもそものIPアドレスが変更となり、eniが変更となる場合がある。

同一インスタンス上のPodで、外部と疎通できるものとできないものがある

利用しているeniが異なり、そのsgも異なる

外部へ疎通ができないPodでも外部からアクセスすると正常に疎通できる

kube-proxyは基本的に初めからアタッチされているeniに載るためServiceやIngressを経由する場合にはPodのeniに適切なsgがなくとも接続可能

原因がわかるとめちゃくちゃ不可解だと感じていた事象1つ1つにきちんと説明がつきますね。

まとめ

EKSのネットワーク周りはきちんと把握しておくと、今までの感覚で違和感だと感じるようなことにも立ち向かえるようになりますのできちんと把握しておくといいです。 取っ掛かりとしてはこの資料なんかが知りたいことが載っている!!と言う感じだったので目を通しておくと幸せになれるかもしれません。

speakerdeck.com

*1:インスタンスタイプに応じて、アタッチできるeniの数に上限がある。EKSのPodの数の上限がやや小さいのはこのため

*2:このときにアタッチ済みのeniにはsgの設定が反映される