AWSでEKS(Elastic Kubernetes Service)を本番運用しようとすると、避けて通れないのがこの問いです。
EKSのコントロールプレーン(APIサーバー・etcdなど)はAWSが3つのAZに自動で冗長化してくれます。しかしワーカーノード(データプレーン)は、ClusterConfig YAMLの設定を適切に書かないと1つのAZに偏ります。AWSの障害はAZ単位で発生するため、ノードが1つのAZに集中していると、そのAZが落ちた瞬間にPodが全滅し、サービスが停止します。
この記事では、eksctlを使ってEKSクラスターをマルチAZ構成で設計する実践手順を解説します。VPCサブネットの設計要件、ClusterConfig YAMLの書き方、ノードグループのAZ分散設定、そしてIRSA(IAM Roles for Service Accounts)によるPodへの最小権限付与まで、実際の設定ファイルと出力例を交えながら紹介します。
この記事のポイント
・EKSのマルチAZ設計はノードグループのAZを3つに分散させることが基本
・eksctlのClusterConfig YAMLでVPC・ノードグループの設定を一括定義できる
・プライベートサブネットにはEKS用タグ(kubernetes.io/role/internal-elb: 1)の設定が必須
・PodへのAWS権限はIRSA(IAM Roles for Service Accounts)で最小権限を実現する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
EKSのアーキテクチャ全体像(コントロールプレーンとデータプレーン)
EKSは「コントロールプレーン」と「データプレーン(ワーカーノード)」の2層構造です。コントロールプレーンはKubernetesのAPIサーバー・etcd・スケジューラーをまとめたもので、AWSが複数のAZにまたがって完全マネージドで提供します。ユーザーはコントロールプレーンの管理を一切しなくてよいのが大きな特徴です。なお、EKSはコントロールプレーンに時間あたり約$0.10(月額約$73)の費用がかかります。ワーカーノード(EC2)の費用に加えてこの固定費も見積もりに含めておいてください。
データプレーン(ワーカーノード)はEC2インスタンス群で構成されます。ここはユーザーが設計・管理する責任範囲です。マルチAZ設計で設定すべきはこのデータプレーンです。
マネージドKubernetesサービスはAWS以外にも存在します。主要3サービスをLinuxエンジニア視点で比較します。
| 比較項目 | EKS(AWS) | AKS(Azure) | GKE(GCP) |
|---|---|---|---|
| コントロールプレーン料金 | $0.10/時間 | 無料 | Standard $0.10/時間 |
| ノード料金 | EC2料金のみ | VM(B2s等)料金のみ | GCE料金のみ |
| CLIコマンド | eksctl / aws eks | az aks | gcloud container |
| IAM・ユーザー管理 | AWS IAMと連携(IRSA) | Entra IDとネイティブ統合 | GCP IAMと連携 |
| マルチAZ設計の自由度 | 高い(AZ明示指定必須) | 自動分散(ゾーン指定も可) | 自動分散(ゾーン指定も可) |
EKSはAWS既存インフラ(VPC・IAM・ALB等)との統合が強みです。AWSを使い込んでいる組織にとって、IRSAやAWS Load Balancer Controllerとの連携が自然な形でできる点が他サービスにはない優位性です。
EKSのマルチAZ設計における基本的な構成要素は次の通りです。
・マネージドノードグループ: AWSがEC2のライフサイクル(起動・停止・交換)を管理するノードグループ。3AZ分散が推奨
・VPC・サブネット: ノードを配置するプライベートサブネットを3AZに分けて作成する
・ALB Ingress Controller: ServiceのロードバランシングにALBを使う場合、複数AZのパブリックサブネットに展開される
・NATゲートウェイ: プライベートサブネットからのアウトバウンド通信を中継する。各AZに1台ずつ配置(HighlyAvailable設定)
VPCとサブネットの設計(EKS専用の要件)
EKSクラスターを作成する前に、VPCとサブネットの設計を固める必要があります。後から変更できない部分があるため、最初の設計が肝心です。1. サブネット数とAZ
EKSのマルチAZ設計では、最低2つのAZに各1つのサブネットが必要です。実務では3AZ(ap-northeast-1a / 1c / 1d)を推奨します。1AZが落ちても残り2/3のノードで継続稼働できます。ap-northeast-1bはAWS東京リージョンでEKSが利用できないアカウントが多いため、ap-northeast-1a / 1c / 1dを使うのが定番です。
サブネット構成は次の通りです。
・パブリックサブネット(3つ): ALB・NATゲートウェイを配置する。インターネットゲートウェイ経由でルーティング
・プライベートサブネット(3つ): ワーカーノードを配置する。インターネットに直接公開しない
2. サブネットタグの設定(必須)
EKSが適切なサブネットを自動選択できるよう、サブネットにタグを設定する必要があります。これを忘れると、Ingress ControllerがALBを作成できずにエラーになります。パブリックサブネット(インターネット向けALB用)に設定するタグ:
# タグキー タグ値 kubernetes.io/cluster/prod-cluster shared kubernetes.io/role/elb 1
# タグキー タグ値 kubernetes.io/cluster/prod-cluster shared kubernetes.io/role/internal-elb 1
eksctlでクラスターを作成する手順
1. eksctlのインストール
eksctlはAWS公式のEKSクラスター管理CLIです。Amazon Linux 2023やRHEL 9系での導入手順を示します。# GitHub公式リリースからバイナリを取得する ARCH=amd64 PLATFORM=$(uname -s)_$ARCH curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_${PLATFORM}.tar.gz" tar -xzf eksctl_${PLATFORM}.tar.gz -C /tmp sudo mv /tmp/eksctl /usr/local/bin # バージョン確認 eksctl version
0.192.0
2. ClusterConfig YAMLを作成する
eksctlにはCLIオプションの直接指定とYAML定義の2通りがあります。本番環境ではYAMLをGitリポジトリで管理することを強く推奨します。設定変更の履歴が残り、レビューを通せるためです。以下のYAMLを cluster-config.yaml として保存します。
# cluster-config.yaml apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: prod-cluster region: ap-northeast-1 version: "1.29" vpc: cidr: "10.0.0.0/16" nat: gateway: HighlyAvailable # 各AZにNATゲートウェイを1台ずつ配置する managedNodeGroups: - name: ng-prod instanceType: t3.medium minSize: 3 maxSize: 9 desiredCapacity: 3 availabilityZones: # 3AZを明示的に指定する(省略すると偏るリスクがある) - ap-northeast-1a - ap-northeast-1c - ap-northeast-1d volumeSize: 30 volumeType: gp3 privateNetworking: true # ノードをプライベートサブネットに配置する iam: withAddonPolicies: autoScaler: true cloudWatch: true addons: - name: vpc-cni - name: coredns - name: kube-proxy
・vpc.nat.gateway: HighlyAvailable: 3AZそれぞれにNATゲートウェイを1台ずつ配置する。1AZのNATが落ちても他AZへの影響がない
・managedNodeGroups[].availabilityZones: 3AZを明示的に指定する。省略するとeksctlが任意に選ぶため、設計意図通りにならない場合がある
・privateNetworking: true: ワーカーノードをプライベートサブネットに配置する。インターネットからの直接アクセスを遮断する
3. クラスターを作成する(eksctl create cluster)
YAMLファイルを使ってクラスターを作成します。eksctl create cluster -f cluster-config.yaml
~/.kube/configを自動で更新するため、完了後はすぐにkubectlでクラスターを操作できる状態になります。作成中にクラスターの状態を確認したい場合は次のコマンドを使います。# CloudFormationスタックの進行状況を確認する aws cloudformation describe-stacks --stack-name eksctl-prod-cluster-cluster --query "Stacks[0].StackStatus" --output text # CREATE_IN_PROGRESS → CREATE_COMPLETE に変わったら完了
4. kubectlでクラスターに接続する(aws eks update-kubeconfig)
eksctl create cluster は完了時にkubeconfigを自動更新しますが、aws CLIを使って接続情報を明示的に取得・更新することもできます。CI/CDパイプラインでkubeconfigを設定する場合や、複数のEKSクラスターを管理する場面で使います。# aws CLIでkubeconfigを更新する aws eks update-kubeconfig --name prod-cluster --region ap-northeast-1 # 接続先クラスターを確認する kubectl config current-context # 複数クラスターを管理している場合は一覧表示 kubectl config get-contexts
# kubectl config current-context の出力 arn:aws:eks:ap-northeast-1:123456789012:cluster/prod-cluster
5. ノードとシステムPodの状態を確認する
クラスターが起動したら、ノードのAZ分散とシステムコンポーネントが正常かどうかを確認します。# ノードの状態とAZ分散を確認する kubectl get nodes --label-columns topology.kubernetes.io/zone # kube-systemのシステムコンポーネント(CoreDNS・kube-proxy等)を確認する kubectl get pods --namespace kube-system
NAME STATUS ROLES AGE VERSION ZONE ip-10-0-97-xxx.ap-northeast-1.compute.internal Ready
5m v1.29.x ap-northeast-1a ip-10-0-130-xxx.ap-northeast-1.compute.internal Ready 5m v1.29.x ap-northeast-1c ip-10-0-162-xxx.ap-northeast-1.compute.internal Ready 5m v1.29.x ap-northeast-1d
Runningであれば、クラスターは正常に動作しています。6. テストDeploymentでPodを起動して動作確認する
クラスターが正常に動作していることを確認するため、Nginxコンテナをデプロイして通信を検証します。# Nginxのテスト用Deploymentを作成する(レプリカ3台=3AZに分散) kubectl create deployment nginx-test --image=nginx:stable --replicas=3 # Podの起動状態とノード配置を確認する kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE NODE nginx-test-5c5d6d9f8b-7hkxg 1/1 Running 0 45s ip-10-0-97-xxx.ap-northeast-1.compute.internal nginx-test-5c5d6d9f8b-qj8nt 1/1 Running 0 45s ip-10-0-130-xxx.ap-northeast-1.compute.internal nginx-test-5c5d6d9f8b-m2wls 1/1 Running 0 45s ip-10-0-162-xxx.ap-northeast-1.compute.internal
# Podのログをリアルタイムで確認する(Linuxの tail -f に相当) kubectl logs -f nginx-test-5c5d6d9f8b-7hkxg
kubectl delete deployment nginx-test
Pod配置のAZ分散制御(topologySpreadConstraints)
ノードが3AZに分散されていても、PodがどのノードにスケジュールされるかはKubernetesのスケジューラーが判断します。重要なサービスは「Podを複数のAZに必ず分散させる」制約をかける必要があります。topologySpreadConstraintsでPodのAZ分散を強制する
Kubernetes 1.19以降で安定版になったtopologySpreadConstraintsを使います。Deployment YAMLのspec.template.specに追加します。# Deployment YAMLの抜粋(spec.template.spec に追加) topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: my-app
・maxSkew: 1: AZ間でのPod数の差を1以内に制限する
・topologyKey: topology.kubernetes.io/zone: AZ単位でPodを分散させる
・whenUnsatisfiable: DoNotSchedule: 制約を満たせない場合はPodをPendingにする(スケジュールしない)
Podのスケールアウトで分散を確認する
topologySpreadConstraintsを適用したDeploymentのレプリカ数を増やして、Podが3AZに均等に分散されることを確認します。# Podの数を3から6に増やす kubectl scale deployment my-app --replicas=6 # Pod一覧とノード配置を確認する kubectl get pods -o wide
NODE列を確認し、6つのPodが3AZのノードに2つずつ均等に配置されていれば、topologySpreadConstraintsが正しく機能しています。スケールインは--replicas=3と指定するだけで元の台数に戻せます。AZ障害時の挙動を確認する
実際の障害を想定して、ノードをcordonし(スケジュール対象から外し)、Podが他のノードへフェイルオーバーされることをテスト環境で確認します。# 1. ap-northeast-1a のノードをスケジュール対象から外す kubectl cordon ip-10-0-97-xxx.ap-northeast-1.compute.internal # 2. ノードの状態を確認する kubectl get nodes # NAME STATUS ROLES # ip-10-0-97-xxx.ap-northeast-1.compute.internal Ready,SchedulingDisabled
# ip-10-0-130-xxx.ap-northeast-1.compute.internal Ready # ip-10-0-162-xxx.ap-northeast-1.compute.internal Ready # 3. テスト完了後、cordonを解除する kubectl uncordon ip-10-0-97-xxx.ap-northeast-1.compute.internal
kubectl drainを実行するか、Deploymentのレプリカ数を一時的に増減させてPodを再作成する方法があります。IRSAでPodにAWS権限を最小権限で付与する
KubernetesのPodからS3やSQSなどのAWSサービスにアクセスする場合、古い方法ではEC2インスタンスプロファイルにIAMポリシーを付与していました。しかしこの方法はノード上の全Podが同じ権限を持つため、最小権限の原則に反します。EKSではIRSA(IAM Roles for Service Accounts)を使い、Pod単位でIAMロールを紐付ける設計を推奨します。
AWSをこれから学ぶ方は、AWS入門ページでAWS全体の基礎知識を身につけてからEKSの設計に取り組むと、各設定の意味が理解しやすくなります。
1. OIDCプロバイダーを確認する
eksctlでクラスターを作成すると、OIDCプロバイダーが自動で設定されます。IRSAはOIDCを使ってKubernetesのServiceAccountとAWS IAMを連携します。# OIDCプロバイダーのエンドポイントを確認する aws eks describe-cluster --name prod-cluster --query "cluster.identity.oidc.issuer" --output text
https://oidc.eks.ap-northeast-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE
2. ServiceAccountとIAMロールを紐付ける
eksctl create iamserviceaccountコマンドを使うと、Kubernetes ServiceAccountの作成とIAMロールの紐付けを一度に実行できます。S3読み取り専用の例を示します。eksctl create iamserviceaccount --cluster prod-cluster --namespace production --name s3-reader-sa --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess --approve
[i] 1 iamserviceaccount (production/s3-reader-sa) was included [i] creating serviceaccount "production/s3-reader-sa" [v] created serviceaccount "production/s3-reader-sa"
spec.template.spec.serviceAccountNameに指定するだけで、そのPodのプロセスのみS3読み取り権限を持つIAMロールを取得します。ノード全体や他のPodには権限が漏れません。よくあるエラーとトラブルシュート
「no subnets found for given AZs」エラー
eksctlがAvailabilityZonesに指定したAZでサブネットを見つけられない場合に出るエラーです。原因として多いのはap-northeast-1bの指定です。東京リージョンのap-northeast-1bはEKSが利用できないアカウントが多いため、ap-northeast-1a / 1c / 1dを指定してください。
ノードが「NotReady」または「0 nodes ready」のままになる
ノードがReady状態にならない場合は、まずノードのイベントを確認します。kubectl describe node <ノード名> | grep -A 20 "Events:"
・プライベートサブネットにNATゲートウェイのルートがない: ECRからコンテナイメージが引けずノードが起動しない。ルートテーブルにNATゲートウェイへのルートを追加する
・セキュリティグループのポート不足: コントロールプレーンとワーカーノード間で443/tcpおよび1025-65535/tcpが必要。ssコマンドやlsofでのポート確認も参考にしてください
・ノードのIAMロールにポリシーが不足: AmazonEKSWorkerNodePolicy・AmazonEKS_CNI_Policy・AmazonEC2ContainerRegistryReadOnlyの3つが最低限必要
PodがImagePullBackOffになる
コンテナイメージを取得できない場合、PodのSTATUSがImagePullBackOffになります。# PodのSTATUSを確認する kubectl get pods # NAME READY STATUS RESTARTS AGE # my-app-7d9c6b8f5-abc12 0/1 ImagePullBackOff 0 2m # イベントでエラー詳細を確認する kubectl describe pod my-app-7d9c6b8f5-abc12 | grep -A 15 "Events:"
・イメージ名・タグの誤記: 存在しないイメージ名またはタグを指定している。kubectl describe podのEventsに「not found」と表示される
・ECRへのアクセス権限不足: ノードのIAMロールにAmazonEC2ContainerRegistryReadOnlyポリシーが付いていない
・プライベートサブネットからECRに到達できない: NATゲートウェイのルートが正しく設定されているか確認する
CoreDNSのPodがPendingになる
EKSのCoreDNSはクラスター内のDNS名前解決を担うコアコンポーネントです。ノードグループが作成される前にCoreDNSのPodが起動しようとしてPendingになることがあります。eksctl create clusterの完了を待てば自動で解消します。ノードグループ作成後もPendingが続く場合は、次のコマンドで状況を確認します。
kubectl describe pod -n kube-system -l k8s-app=kube-dns | grep -A 10 "Events:"
本記事のまとめ
AWS EKSのマルチAZ設計の要点を表にまとめます。| 設計項目 | 推奨設定 |
|---|---|
| ワーカーノードのAZ分散 | managedNodeGroups[].availabilityZonesで3AZを明示指定 |
| NATゲートウェイの冗長化 | vpc.nat.gateway: HighlyAvailable(各AZに1台) |
| プライベートサブネット配置 | privateNetworking: trueでノードをインターネット非公開に |
| PodのAZ分散強制 | topologySpreadConstraints(maxSkew: 1, DoNotSchedule) |
| Internal ALBのサブネット自動選択 | プライベートサブネットにkubernetes.io/role/internal-elb: 1タグを設定 |
| PodへのAWS権限付与 | IRSAでeksctl create iamserviceaccountを使用(最小権限) |
| kubeconfig更新 | aws eks update-kubeconfig --name クラスター名 --region リージョン |
| Podのログ確認 | kubectl logs -f Pod名 |
| Podの詳細確認(障害調査) | kubectl describe pod Pod名 |
EKSのマルチAZ設計はVPCサブネットの設計段階から始まります。後から変更できない部分(VPCのCIDR、NATゲートウェイの配置方針)は最初に確定させてください。ノードグループのAZ分散とtopologySpreadConstraintsを組み合わせることで、AZ単位の障害に対応できる本番環境が整います。
マルチAZ冗長設計の全体パターンは、AWS冗長設計の上級ページで体系的に解説しています。
AWSを基礎から学ぶ方は、AWS入門ページ(Amazon Linux基礎)からスタートすることをお勧めします。
AWS EKSのマルチAZ設計を「実務の型」として身につけませんか?
eksctlの使い方は調べれば分かります。でも「なぜ3AZにノードを分散させるのか」「topologySpreadConstraintsとPodAntiAffinityはどう使い分けるのか」を自信を持って説明できますか?
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます