読むべきドキュメント
- 公式ドキュメント:https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/what-is-eks.html
- EKSベストプラクティス:https://jawsdays2019.jaws-ug.jp/session/1918/
- EKSベストプラクティス:https://aws.github.io/aws-eks-best-practices/
これら以外にも「Production Ready」とか「アンチパターン」とか「ハマった」などの検索ワードでしらべたり、kubernetes周りの勉強会・セミナーの事例をとにかく探しまくって自力をつけましょう。EKSなのかGKEなのかは気にしなくていいです。ほとんど気にするポイントは同じです。
EKSクラスタとしての設計
k8sは半年に一回のバージョンアップを迎えるためそれに追随する必要があります。EKSクラスタ自体のアップデートはAWSで用意されていますが、どのような方法を取るのかはユーザの戦略次第です。
どのような方法を取るのかによって設計が全く異なるので最初にこれを考える必要があります。
EKSクラスタのバージョンアップ戦略
大きく分けて2つあります。
- クラスタは1つ。そのクラスタのバージョンを単純に上げる。
- クラスタは1つだが、バージョンアップ時に新しいクラスタを作りそっちに切り替える
ネットを見てもどちらも存在しているようです。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の振り分けを操作して切り替えができます。
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へのアクセスについて
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