フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

EKS設計ノウハウまとめ

f:id:lirlia:20210604114515p:plain

読むべきドキュメント

これら以外にも「Production Ready」とか「アンチパターン」とか「ハマった」などの検索ワードでしらべたり、kubernetes周りの勉強会・セミナーの事例をとにかく探しまくって自力をつけましょう。EKSなのかGKEなのかは気にしなくていいです。ほとんど気にするポイントは同じです。

EKSクラスタとしての設計

k8sは半年に一回のバージョンアップを迎えるためそれに追随する必要があります。EKSクラスタ自体のアップデートはAWSで用意されていますが、どのような方法を取るのかはユーザの戦略次第です。

どのような方法を取るのかによって設計が全く異なるので最初にこれを考える必要があります。

EKSクラスタのバージョンアップ戦略

大きく分けて2つあります。

  • クラスタは1つ。そのクラスタのバージョンを単純に上げる。
  • クラスタは1つだが、バージョンアップ時に新しいクラスタを作りそっちに切り替える

f:id:lirlia:20210604112908p:plain

ネットを見てもどちらも存在しているようです。1の場合のやり方はAWSコンソールでEKSクラスタのMasterをアップデートし、その後新しいAMIを使ってノードグループをどんどん新しくし、幾つかのシステム用のPodを更新する形です。

一方で2の場合は新しいクラスタを横に作り同じPodをすべて起動し準備が全て整ったらLBで切り替えてサービスインを目指すという方式になります。単純な作業としては2の方が新しく作る分面倒なのですが、バージョンアップ時の切り戻しが可能になるだけでなく事前に本番環境でテストがしやすいです。

この方式を採用する場合次のService設計に関連しますがType: LoadBalancerを使用することが出来ません。というのも移行時を考えるとLoadBalancerは一時的に2つのクラスタ上のPodに通信を飛ばしたりする必要がありますが、k8sでは異なるクラスタが1つのLoadBalancer(NLB/CLB/ALB)を管理することはできないからです。

※補足:type: Loadbalancerをつかっても、外部ドメインに対してうまいことLBのCNAMEを割り振れば制御できるが、DNSキャッシュに依存したりExternalDNSというAdd-onを使わないとk8sでFQDNを管理できないので2の方式ではtype:LoadBalancerの利用は厳しいと思う。またこれにより(そもそも今回は利用予定もなかったが) ALB Ingress Controllerの利用も向いていない

解決策としてはNodePortを利用し、そこに対してLBの振り分けを操作して切り替えができます。

f:id:lirlia:20210604112948p:plain

EKSクラスタのネットワーク設計

EKSクラスタには大きく分けてコントロールプレーンとデータプレーンがあり、これらをPrivate/Publicサブネットのどちら or 両方に展開するのか?が主な観点になります。

コントロールプレーンはAWS的にはPublicに開放しても気にすること無いよといわれています。というのもAWSのAPIはそもそもインターネットに全公開であり、そこに対してIAMによるポリシーベースの権限チェックを行っています。EKSのコントロールプレーンも叩かれるAPIこそk8sのものですが、その裏側にはIAM Policyとk8sのRBACがありキチンと守られています。

データプレーンはPodをインターネットに面したところで動かすか、Privateなところで動かすか?の違いです。

EKSクラスタのノードグループ設計

通常は何も考えずに複数のAZに足を出すAutoScaling Group(Node Group)を1つ作ります。

Statefulset+EBSを使う場合、EBSはAZサービスなのでAZをまたいでAutoScaling Groupが作れません。そのため公式サイトにも書いてありますが、各AZごとにAutoScaling Group(Node Group)を分けて作ります。

EKSの管理方法

eksctl or Terraformのいずれかが選択肢です。TerraformにはEKS用の以下のmoduleが存在するのですが、内容が複雑で抽象度が高いです。

EC2上のpodをどの程度配置させるべきか

確認項目 考慮内容
EC2にアタッチできるIPの数(podごとに1つのIPがつく) EC2の種類ごと ・インスタンスによって制限がある
Elastic Network Interface - Amazon Elastic Compute Cloud
複数の IP アドレス - Amazon Elastic Compute Cloud
EC2にアタッチできるEBSの数(fluentd podごとに1つのEBSがつく) 最大39(ルートボリューム含む) ・ Linux インスタンスに 40 より多くのボリュームをアタッチすることは、ベストエフォートベースでのみサポートされ、保証されません。
インスタンスボリューム数の制限 - Amazon Elastic Compute Cloud
EC2の帯域について EC2の種類ごと https://aws.amazon.com/jp/ec2/instance-types/
EC2-EBS間の帯域について EC2の種類ごと ・EBS最適化インスタンスの場合は通常のNWとは別にEBS専用のNWが用意される。そのとき複数のpodのEBSへの通信が共有される。
Amazon EBS 最適化インスタンス - Amazon Elastic Compute Cloud
datadog観点 10コンテナ/EC2 1EC2上に10コンテナまでがホスト監視の料金に含まれている
サポートの種類によって変わる
CPU インスタンスによる
memory インスタンスによる
Disk(IOPS) EBSごと EBSのサイズに準拠する、pod単位なので他に影響はなさそう
OS(ファイルディスクリプタ) OSによる sh-4.2# cat /proc/sys/fs/file-max
775559
OS(ポート) 65535(調整可能) IPアドレスがPodによって違うためポートレンジはそれぞれのIPごとに65535の範囲で(拡張すれば)利用できるため考慮する必要はなさそう
OS(プロセス数) 32768(調整可能) 1podで数プロセスなので使い切ることはなさそう
sh-4.2# cat /proc/sys/kernel/pid_max
32768
OS(スレッド数) 60780(調整可能) 1podで20スレッド程度なので使い切ることはなさそう
sh-4.2# cat /proc/sys/kernel/threads-max
60780 |

Kubernetesの利用に関する設計

基本はk8sの原則を守るだけなのでそれほどありませんが特徴的なやつだけ。

環境差分の管理

  • Kustomize
  • Helm

Secret情報の管理

Secretの管理は当初kubesecによる暗号化をした上でGitに格納としていました。

しかしArgoCDを前提に置いたGitOpsを実施する際に、kubesecによる復号化を実施できないことがわかったためAWS Parameter StoreにTerraformでSecret情報を格納する方式に変更しています。そしてEKSにてそこからデータを引っ張ってくるために ExternalSecrets というCRDを起動し、定期的にSecretを生成するようにしています。

コンテナの設計

  • Distoroless container

CI&CDの設計

  • GitHubAction
  • ArgoCD

ログ設計

Datadogの導入

監視設計

Datadogの導入

拡張性

  • HPA
  • Cluster Autoscaler

可視化設計

EKSの情報やコンテナのMetricsについてはDatadogなど

これらを入れる

  • metrics-server
  • Kubernetes-state

バックアップ・リストア設計

  • EKSのノード(EC2)はデータを保存しないためバックアップ・リストアは行わず、都度EC2をAMIから再作成する。
  • podのEBS/EFSバックアップは必要によって考える

セキュリティ設計

Kubernetes APIへのアクセスについて

f:id:lirlia:20210604114032p:plain

EKSではEKSを構築したユーザしか操作ができないのでどう管理するのか?検討する必要がある。特定のIAM roleにAssumeすることで制御ができるようにするのがよい。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/amazon-eks-cluster-access/

Pod間通信の制限について

calico / AWS VPC CNI

イメージの脆弱性について

ECRによる脆弱性スキャン / 外部からのものはどうするか?

Workerノードのホストレベル対策について

EPPの導入

Podレベル対策について

Aqua/Twistlock/Sysdigの検討でしょうか。

Podの起動ユーザ/グループについて

rootでの実行を禁止し一般ユーザに限定

コンテナランタイムについて

OCIをセキュアにするという話も出ていますが、マネージドノードグループとして使用しているAmazonLinux2はデフォルトでdockerが使われています。

IMDS(Instance MetaData Service)について

SSRFという攻撃をご存知でしょうか?EC2などのメタデータを外部から無理やり取得し、乗っ取る攻撃です。便利なところには罠がありますね。EKSではIMDSを使っているのでこれをうまいこと制限しないといけません。

詳細はこちら→https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/best-practices-security.html

PodからのAWSリソース操作について

何も設定しないとPodはAWS Nodeのインスタンスプロファイルを利用しますが、それをすると本来権限を与えたくないPodについても権限を与えることになるため我々はIRSAを使いPodごとに限定的なIAM roleをAssumeすることにしています。

https://aws.github.io/aws-eks-best-practices/iam/#iam-roles-for-service-accounts-irsa