コンテンツにスキップ

EKS@AWSリソース

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. EKS:Elastic Kubernetes Service

コントロールプレーン

▼ コントロールプレーンとは

コンテナオーケストレーションを実行する環境を提供する。

データプレーンのVPC外に存在している。

▼ コントロールプレーンの仕組み

EKSのコントロールプレーンは、開発者や他のAWSリソースからのリクエストを待ち受けるAPI、接続をAPIにルーティングするNLB、データプレーンを管理するコンポーネント、からなる。

eks_control-plane


データプレーン

▼ データプレーンとは

複数のホスト (EC2、Fargate) のOS上でコンテナオーケストレーションを実行する。

on EC2』『on Fargate』という呼び方は、データプレーンがEKSの実行環境 (on environment) の意味合いを持つからである。


01-02. セットアップ

コンソール画面の場合

▼ 設定項目と説明

設定項目 説明 補足
名前 クラスターの名前を設定する。
Kubernetesバージョン EKS上で稼働するKubernetesのバージョンを設定する。 EKSが対応できるKubernetesのバージョンは以下を参考にせよ。
https://docs.aws.amazon.com/eks/latest/userguide/platform-versions.html
クラスターサービスロール EKS Clusterのサービスリンクロールを設定する。 https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html
シークレット Secretに保持するデータをKMSの暗号化キーで暗号化するか否かを設定する。
VPC、サブネット ENIを配置するサブネットを設定する。 複数のAZにまたがっている必要がある。
クラスターセキュリティグループ EKS Clusterのセキュリティグループを設定する。 インバウンドとアウトバウンドの両方のルールで、全てのIPアドレスを許可する必要がある。このセキュリティグループは、追加のセキュリティグループとして設定され、別途、AWSによってeks-cluster-sg-<EKS Cluster名>というセキュリティグループも自動設定される。
https://yuutookun.hatenablog.com/entry/fargate_for_eks
クラスターIPアドレスファミリー PodとServiceに割り当てるClusterIPのIPアドレスタイプ (IPv4、IPv6) を設定する。
CIDRブロック ClusterIP Serviceに割り当てるIPアドレスのCIDRブロックを設定する。
クラスターエンドポイントアクセス kube-apiserverのリクエスト制限を設定する。
ネットワークアドオン ネットワークに関するAWS EKSアドオンを設定する。 執筆時点 (2023/02/05) では、aws-eks-kube-proxyアドオン、aws-eks-corednsアドオン、aws-eks-vpc-cniアドオン、を使用できる。
コントロールプレーンのログ コントロールプレーンコンポーネントのログをCloudWatchログに出力するかどうかを設定する。 執筆時点 (2023/02/05) では、kube-apiserver (処理ログと監査ログの両方) 、aws-iam-authenticator-server (処理ログ) 、kube-controller-manager (処理ログ) 、cloud-controller-manager (処理ログ) 、kube-scheduler (処理ログ) 、のログを出力できる。


Terraformの公式モジュールの場合

ここでは、Terraformの公式モジュールを使用する。

module "eks" {
  source = "terraform-aws-modules/eks/aws"

  version = "<モジュールのバージョン>"

  cluster_name    = foo-eks-cluster
  cluster_version = "<Kubernetesのバージョン>"

  # kube-apiserverをプライベートアクセスにするか否か
  cluster_endpoint_private_access = true

  # kube-apiserverにパブリックリクエストできるか否か
  cluster_endpoint_public_access = false

  # EKS Clusterのkube-apiserverにリクエストを送信できるCIDR
  cluster_endpoint_public_access_cidrs = ["*.*.*.*/32", "*.*.*.*/32", "*.*.*.*/32"]

  # CloudWatchログに送信するログの種類
  cluster_enabled_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler",]

  # ログの保管期間
  cluster_log_retention_in_days = 365

  # セキュリティグループを作成するか否か
  cluster_create_security_group = true

  # セキュリティグループのID
  cluster_security_group_id = "*****"

  # IRSAを有効化するか否か
  enable_irsa = true

  # ワーカーNodeのセキュリティグループを作成するか否か
  worker_create_security_group = true

  # VPCのID
  vpc_id = "vpc-*****"

  # サブネットのID
  subnets = ["subnet-*****", "subnet-*****", "subnet-*****"]

  # AWS EKSアドオン
  cluster_addons = {

    coredns = {
      resolve_conflicts = "OVERWRITE"
    }

    kube-proxy = {
      resolve_conflicts = "OVERWRITE"
    }

    vpc-cni = {
      resolve_conflicts = "OVERWRITE"
    }
  }

  # AWS EKSマネージドグループ
  eks_managed_node_groups = {
    node_group_name = "foo-group"
    instance_types  = ["m5.large"]
    min_size        = 3
    max_size        = 4
    desired_size    = 5
  }
}


EKS Clusterの認証情報の追加

kubectlコマンドでEKS Clusterを操作するためには、kubeconfigファイルへClusterの認証情報を登録する必要がある。

(1)

AWS CLIに認証情報を設定する。

$ aws configure
(2)

EKS Clusterの名前を指定して、kubeconfigファイルにClusterの認証情報を登録する。

$ aws eks update-kubeconfig --region ap-northeast-1 --name foo-eks-cluster
(3)

kubectlコマンドの向き先を、EKS Clusterのkube-apiserverに変更する。

$ kubectl config use-context <ClusterのARN>
(4)

kubectlコマンドの接続を確認する。

$ kubectl get pod


02. コントロールプレーンのコンポーネント

対応関係

コントロールプレーン上のAWSリソース Kubernetesリソース 補足
EKSコントロールプレーン コントロールプレーンNode https://docs.aws.amazon.com/eks/latest/userguide/platform-versions.html
kube-apiserver kube-apiserver
kube-apiserverのロードバランサー (例:HAProxy) NLB


コントロールプレーンNode

コントロールプレーンNodeは、ユーザーの管理外のVPCに所属している。


kube-apiserver

▼ aws-auth (ConfigMap) を介したKubernetes RBACとの連携

eks_auth_architecture

ConfigMapを介して、KubernetesのRBACと連携することにより、kubectlクライアントの認可スコープを制御する。

Kubernetesリソースの認可スコープは、IRSAで制御する。

(1)

あらかじめ、クライアント (kubectlクライアント、Kubernetesリソース) に紐づくIAMユーザーを作成しておく。

(2)

IAMユーザーがkube-apiserverのURLにリクエストを送信する。

kube-apiserverは、aws-iam-authenticator-serverにWebhookを送信する。

admission-controllersアドオンのWebhookではないことに注意する。

(3)

コントロールプレーンNode上のaws-iam-authenticator-serverは、IAM APIを使用してIAMユーザーを認証する。

(4)

もし認証に成功していた場合に、aws-iam-authenticator-serverは、ConfigMap (aws-auth) を確認する。

このConfigMapには、そのIAMユーザーに紐づくUserAccount / ServiceAccount / Group、RoleBinding / ClusterRoleBinding、が定義されている。

この時、kubectlクライアントの場合はUserAccount、Kubernetesリソースの場合はServiceAccount、を取得する。

apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapAccounts: []
  mapUsers: []
  mapRoles: |
    - rolearn: arn:aws:iam::<AWSアカウントID>:role/foo-role # IAMロール名
      username: hiroki-it # IAMユーザー名
      groups:
        - system:masters # ClusterRoleBindingに定義されたGroup名
    - rolearn: arn:aws:iam::<AWSアカウントID>:role/bar-role # ワーカーNodeに紐付けたロール名
      username: system:node:{{EC2PrivateDNSName}} # ワーカーNodeの識別子
      groups:
        - system:bootstrappers
        - system:nodes
(5)

aws-iam-authenticator-serverは、UserAccount / ServiceAccount / Group、RoleBindingやClusterRoleBinding、の情報を含むレスポンスをkube-apiserverに返信する。

(6)

あとは、Kubernetesの標準の認可の仕組みである。

kube-apiserverは、UserAccount / ServiceAccount / Groupに紐づくRoleやClusterRoleを、RoleBindingやClusterRoleBindingを介して取得する。

IAMユーザーは、Kubernetesリソースを操作できる。

▼ プリンシパルIAMロールとアクセスエントリーを介したKubernetes Clusterの操作

プリンシパルIAMロールとアクセスエントリーを使用する場合、従来のaws-auth (ConfigMap) と比較して、AWS EKSへのアクセス制御をKubernetesリソースで管理する必要がない。

プリンシパルIAMロールに紐づくPodがAWS EKSに接続する時に、アクセスエントリーがこれを仲介して動的にIAMポリシーを設定する。

プリンシパルIAMロールとアクセスエントリーを介して、kubectlクライアントの認可スコープを制御する。

▼ パブリックアクセス/プライベートアクセス

kube-apiserverのインターネットへの公開範囲を設定できる。

プライベートアクセスの場合、VPC内部からのみリクエストできるように制限でき、送信元IPアドレスを指定してアクセスを許可できる。

▼ EKS Upgrade insights

非推奨apiVersion検出ツール (例:pluto) のようなクライアント側からの検証ではなく、kube-apiserver側で非推奨apiVersionを検出する。

kube-apiserverの監査ログから非推奨apiVersionを検出する。


NLB

記入中...


03. データプレーンのコンポーネント

対応関係

eks

データプレーン上のAWSリソース Kubernetesリソース 補足
FargateワーカーNode、EC2ワーカーNode ワーカーNode https://docs.aws.amazon.com/eks/latest/userguide/eks-compute.html
EKS Cluster Cluster https://docs.aws.amazon.com/eks/latest/userguide/clusters.html
AWS ALB Ingress IngressはAWS ALBに置き換える必要がある。AWS Load Balancerコントローラーを作成すると、AWS ALBは自動的に作成される。
https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html
https://blog.linkode.co.jp/entry/2020/06/26/095917#AWS-ALB-Ingress-Controller-for-Kubernetes
AWS Load Balancerコントローラー Ingressコントローラー AWS ALBを自動的に作成する。
https://aws.amazon.com/jp/blogs/news/using-alb-ingress-controller-with-amazon-eks-on
API Gateway + NLB https://aws.amazon.com/jp/blogs/news/api-gateway-as-an-ingress-controller-for-eks/
EBS、EFS PersistentVolume https://docs.aws.amazon.com/eks/latest/userguide/storage.html
Secrets Manager Secret https://docs.aws.amazon.com/eks/latest/userguide/manage-secrets.html
IAMユーザー ServiceAccount、UserAccount https://docs.aws.amazon.com/eks/latest/userguide/add-user-role.html
IAMロール Role、ClusterRole https://docs.aws.amazon.com/eks/latest/userguide/add-user-role.html


EKS Cluster

▼ EKS Clusterとは

FargateワーカーNodeやEC2ワーカーNodeの管理グループ単位のこと。

KubernetesのClusterに相当する。


マルチワーカーNode

▼ マルチワーカーNodeとは

マルチワーカーNodeを作成する場合、AZごとにNodeを作成する。

eks_multi-node

▼ ワーカーNode間のファイル共有

EFSを使用して、ワーカーNode間でファイルを共有する。

PodのファイルはワーカーNodeにマウントされるため、異なるワーカーNode上のPod間でファイルを共有したい場合 (例:PrometheusのローカルストレージをPod間で共有したい) に役立つ。

ただしできるだけ、ワーカーNodeをステートフルではなくステートレスにする必要があり、PodのファイルはワーカーNodeの外で管理する必要がある。


IRSA:IAM Roles for Service Accounts

▼ IRSAとは

eks_oidc

特にKubernetesリソースの認可スコープを制御する仕組みのこと。

kubectlクライアントの認可スコープは、RBACで制御する。

EKSをSSOのIDプロバイダーとして使用することにより、IAMの認証フェーズをEKSに委譲する。

▼ セットアップ

ここでは、SSOの種類でOIDCを選ぶとする。

(1)

SSOのIDプロバイダーのタイプは、OIDCとする。

『EKS ClusterのOIDCプロバイダーURL』『OIDCプロバイダーのSSL証明書を署名する中間CA認証局 (例:CertificateManagerなど) のサムプリント』『IDプロバイダーによるトークンの発行対象 (sts.amazonaws.com)』を使用して、OIDCプロバイダーを作成する。

data "tls_certificate" "this" {
  url = module.foo_eks.cluster_oidc_issuer_url
}

# OIDCのIDプロバイダーをAWSに登録する。
resource "aws_iam_openid_connect_provider" "this" {
  url             = module.foo_eks.cluster_oidc_issuer_url
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = data.tls_certificate.this[0].certificates[*].sha1_fingerprint
}
apiVersion: v1
kind: Pod
metadata:
  name: foo-pod
spec:
  containers:
    - name: app
      image: app:1.0.0
      volumeMounts:
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
          name: kube-api-access-*****
          readOnly: "true"
        # OIDCのプロバイダーによるトークンをコンテナにマウントする
        - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
          name: aws-iam-token
          readOnly: "true"
  volumes:
    - name: kube-api-access-*****
      projected:
        defaultMode: 420
        sources:
          - serviceAccountToken:
              expirationSeconds: 3607
              path: token
          - configMap:
              items:
                - key: ca.crt
                  path: ca.crt
              name: kube-root-ca.crt
          - downwardAPI:
              items:
                - fieldRef:
                    apiVersion: v1
                    fieldPath: metadata.namespace
                  path: namespace
    # AWS EKSを使用している場合、AWS-APIへのリクエストに必要なトークンも設定される
    - name: aws-iam-token
      projected:
        defaultMode: 420
        sources:
          - serviceAccountToken:
              # OIDCのIDプロバイダーによるトークンの発行対象
              audience: sts.amazonaws.com
              expirationSeconds: 86400
              path: token
(2)

IRSAで使用するIAMロールの信頼されたエンティティに、EKS ClusterのOIDCプロバイダーURLやユーザー名 (system:serviceaccount:<Namespac名>:<ServiceAccount名>) を設定する。

{"Version": "2012-10-17", "Statement": [
      {
        "Sid": "",
        "Effect": "Allow",
        "Principal":
          {
            "Federated": "arn:aws:iam::<AWSアカウントID>:oidc-provider/<EKS ClusterのOIDCプロバイダーURL>",
          },
        # AssumeRoleWithWebIdentityを使用する
        "Action": "sts:AssumeRoleWithWebIdentity",
        "Condition": {
            # 完全一致
            "StringEquals":
              {
                "<EKS ClusterのOIDCプロバイダーURL>:sub":
                  ["system:serviceaccount:<Namespac名>:<ServiceAccount名>"],
              },
          },
      },
    ]}
(3)

ServiceAccountの.metadata.annotations.eks.amazonaws.com/role-arnキーでIAMロールのARNを設定する。

これにより、EKSで認証済みのServiceAccountにIAMロールを紐付けることができるようになる。

automountServiceAccountTokenキーが有効化されていることを確認する。

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: <IAMロールのARN>
  name: <信頼されたエンティティで指定したユーザー名にあるServiceAccount名>
  namespace: <信頼されたエンティティで指定したユーザー名にあるNamespace名>
automountServiceAccountToken: "true"
(4)

Podで、ServiceAccount名を設定する。

apiVersion: v1
kind: Pod
metadata:
  name: foo-pod
  namespace: foo-namespace
spec:
  serviceAccountName: foo-sa
  containers: ...

もし.metadata.annotations.eks.amazonaws.com/role-arnキーを使用しない場合、KubernetesリソースからAWSリソースへのアクセスがあった時は、EC2ワーカーNodeやFargateワーカーNodeのIAMロールが使用される。

IRSAが登場するまでは、EKS上でのワーカーNode (例:EC2、Fargate) にしかIAMロールを紐付けることができず、KubernetesリソースにIAMロールを直接的に紐付けることはできなかった。

ServiceAccountのトークンは、コンテナにファイルとしてマウントされている。

$ printenv | sort -f

AWS_DEFAULT_REGION=ap-northeast-1
AWS_REGION=ap-northeast-1
AWS_ROLE_ARN=arn:aws:iam::<アカウントID>:role/argocd-reposerver
AWS_STS_REGIONAL_ENDPOINTS=regional
# ServiceAccountのトークン文字列が記載されたファイル
AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token

...


デバッグ

▼ ダッシュボード

(1)

EKS Clusterの名前を指定して、kubeconfigファイルにClusterの認証情報を登録する。

$ aws eks update-kubeconfig --region ap-northeast-1 --name foo-eks-cluster
(2)

kubectlコマンドの向き先を、EKS Clusterのkube-apiserverに変更する。

$ kubectl config use-context <ClusterのARN>
(3)

マニフェストを使用して、ダッシュボードのKubernetesリソースをEKSにデプロイする。

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.5/aio/deploy/recommended.yaml
(4)

ダッシュボードに安全に接続するために、ServiceAccountをEKSにデプロイする

$ kubectl apply -f service-account.yml
(5)

トークン文字列を取得する。

$ kubectl -n kube-system describe secret $(kubectl get secret -n kube-system | grep eks-admin | awk '{print $1}')
(6)

ローカルマシンからEKSにポートフォワーディングを実行する。

$ kubectl proxy
(7)

ダッシュボードに接続する。

GET http://127.0.0.1:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#!/login HTTP/1.1

▼ ワーカーNode (例:EC2、Fargate) への接続

セッションマネージャーを使用して、ワーカーNode (例:EC2、Fargate) に接続できる。


03-02. Cluster内のIPアドレス

ServiceのためのIPアドレス

Serviceに割り当てるIPアドレスは、Service IP範囲によって決まる。

10.100.0.0/16または172.20.0.0/16のいずれかになる。

$ kubectl get service -A jsonpath='{.spec.clusterIP}'

# IP範囲の中からServiceにIPアドレスを割り当てる
172.20.74.199
172.20.0.1
172.20.123.203
172.20.0.10


PodのためのIPアドレス

PodのIPアドレスは、EC2のENIとセカンダリープライベートIPアドレスに割り当てられるIPアドレスによって決まる。

aws-vpc-cniアドオン内のL-IPAMデーモンは、ENIとセカンダリープライベートIPアドレスの情報をCNIプラグインにプールする。


03-03. サブネット内外へのリクエスト

EKSデータプレーンはプライベートサブネットで稼働させ、パブリックネットワーク上のALBから通信を受信すると良い。

この時、パブリックネットワークにあるレジストリから、IstioやArgoCDのコンテナイメージをプルできるように、EKS FargateワーカーNodeとInternet Gateway間のネットワークを繋げる必要がある。

そのために、パブリックサブネットにNAT Gatewayを置く。


03-04. データプレーン内外へのリクエスト

パブリックサブネット内のデータプレーンからのリクエスト

Podをパブリックサブネットに配置した場合に、パブリックネットワークやVPC外にあるAWSリソース (ECR、S3、Systems Manager、CloudWatchログ、DynamoDB、など) に対してリクエストを送信するために特に必要なものは無い。

この時、POD_SECURITY_GROUP_ENFORCING_MODE=standardに設定されたaws-eks-vpc-cniアドオンはSNAT処理を実行し、Podのリクエストの送信元IPアドレスをEC2ワーカーNodeのプライマリーENI (eth0) のIPアドレスに変換する。


プライベートサブネット内のデータプレーンからのリクエスト

▼ Pod外から内へのリクエスト

Podをプライベートサブネットに配置した場合に、プライベートサブネット外から内のデータプレーンへのリクエストをAWS Load Balancerコントローラーで受信し、AWS ALBを使用してPodにルーティングする。

eks_architecture

▼ 宛先情報の管理方法

リクエストの宛先情報は、Secretで管理し、Podにマウントする。

apiVersion: v1
kind: Secret
metadata:
  name: foo-secret
data:
  # RDS (Aurora) の宛先情報
  DB_HOST_PRIMARY: <プライマリーインスタンスのエンドポイント>
  DB_HOST_READ: <リードレプリカのエンドポイント>
  DB_USER: bar
  DB_PASSWORD: baz
  # SQSの宛先情報
  SQS_QUEUE_NAME: foo-queue.fifo
  SQS_REGION: ap-northeast-1

▼ VPC外の他のAWSリソースへのリクエスト

Podをプライベートサブネットに配置した場合に、パブリックネットワークやVPC外にあるAWSリソース (ECR、S3、Systems Manager、CloudWatchログ、DynamoDB、など) に対してリクエストを送信するためには、NAT GatewayまたはVPCエンドポイントを配置する必要がある。

この時、Podのリクエストの送信元IPアドレスは、NAT GatewayまたはVPCエンドポイントに紐づくIPアドレスになる。

以下のようなエラーでPodが起動しない場合、Podが何らかの理由でイメージをプルできない可能性がある。

また、Podが作成されない限り、ワーカーNodeも作成されないことに注意する。

Pod provisioning timed out (will retry) for pod

▼ VPC外のコントロールプレーンへのリクエスト

EKS Clusterを作成すると、ENIも作成する。

これにより、データプレーンがVPC外のコントロールプレーンと通信できるようになる。

データプレーンがコントロールプレーンをリクエストを送受信する場合、コントロールプレーンのクラスターエンドポイントの設定 (パブリック、プライベート) によって、マネージドなInterface型VPCエンドポイントまたはNAT Gatewayが必要になる。

VPCエンドポイントの接続先 タイプ プライベートDNS名 説明
EKSコントロールプレーン (たぶん) Interface マネージド プライベートサブネット内のEC2 NodeからコントロールプレーンのあるVPCにリクエストを送信するため。
CloudWatchログ Interface logs.ap-northeast-1.amazonaws.com Pod内のコンテナのログをPOSTリクエストを送信するため。
ECR Interface api.ecr.ap-northeast-1.amazonaws.com
*.dkr.ecr.ap-northeast-1.amazonaws.com
イメージのGETリクエストを送信するため。
S3 Gateway なし イメージのレイヤーをPOSTリクエストを送信するため
Systems Manager Interface ssm.ap-northeast-1.amazonaws.com Systems ManagerのパラメーターストアにGETリクエストを送信するため。
Secrets Manager Interface ssmmessage.ap-northeast-1.amazonaws.com Secrets Managerを使用するため。

▼ VPC内の他のAWSリソースへのリクエスト

VPC内にあるAWSリソース (RDSなど) の場合、そのAWS側のセキュリティグループにて、PodのプライベートサブネットのCIDRブロックを許可すればよい。


03-05. コントロールプレーン内外へのリクエスト

コントロールプレーンとワーカーNodeのネットワーク

コントロールプレーンはVPC外にあり、ワーカーNodeはVPC内にある。

kubectlコマンドやワーカーNodeからのリクエストのエンドポイントとしてNLBが配置されている。

このNLBを介して、コントロールプレーン内のkube-apiserverにリクエストを送信できる。

VPC外からNLBへの443番ポートに対するネットワークからのリクエストはデフォルトでは許可されているが、拒否するように設定できる。

eks_control-plane_worker_network


クラスターエンドポイントのリクエスト制限

▼ パブリックのみの場合

基本的には、全てのIPアドレスからkube-apiserverにリクエストを送信できる。

プライベートサブネット内にワーカーNodeがある場合、NAT Gatewayを介して、kube-apiserverにリクエストを送信することになる。

▼ パブリックとプライベートの場合

パブリックとプライベートを許可する場合、指定したCIDRブロックに含まれるIPアドレスからのみ、kube-apiserverにリクエストを送信できる。

プライベートサブネット内にワーカーNodeがある場合、以下のいずれかの経路でkube-apiserverにリクエストを送信することになる。

  • NAT Gatewayを介して、NAT Gatewayを介して、パブリック制限を通過する
  • ENI (Interface型のVPCエンドポイント) を介して、プライベート制限を通過する

eks_control-plane_worker_network_public_private_endpoint

VPC外のAWSリソース (例:EKSコントロールプレーン、ECR、S3、Systems Manager、CloudWatchログ、DynamoDB、など) にリクエストを送信する場合、専用のVPCエンドポイントを設ける必要がある。

VPCエンドポイントの接続先 タイプ プライベートDNS名 説明
EKSコントロールプレーン (たぶん) Interface マネージド プライベートサブネット内のEC2 NodeからコントロールプレーンのあるVPCにリクエストを送信するため。
CloudWatchログ Interface logs.ap-northeast-1.amazonaws.com Pod内のコンテナのログをPOSTリクエストを送信するため。
ECR Interface api.ecr.ap-northeast-1.amazonaws.com
*.dkr.ecr.ap-northeast-1.amazonaws.com
イメージのGETリクエストを送信するため。
S3 Gateway なし イメージのレイヤーをPOSTリクエストを送信するため
Systems Manager Interface ssm.ap-northeast-1.amazonaws.com Systems ManagerのパラメーターストアにGETリクエストを送信するため。
Secrets Manager Interface ssmmessage.ap-northeast-1.amazonaws.com Secrets Managerを使用するため。

▼ プライベートのみの場合

プライベートのみを許可する場合、このNLBは閉じられ、VPC内からしかkube-apiserverにリクエストを送信できなくなる。

プライベートサブネット内にワーカーNodeがある場合、VPCエンドポイントを介して、kube-apiserverにリクエストを送信することになる。

この状態で、kubectlコマンドでkube-apiserverにリクエストを送信できるようにする方法としては、以下のパターンがある。

接続元パターン 接続方法パターン
ローカルマシン セッションマネージャー
VPC内の踏み台EC2 セッションマネージャー、SSH
VPC内のCloud9 セッションマネージャー、SSH


04. on EC2 (EC2ワーカーNode)

EC2ワーカーNode

▼ EC2ワーカーNodeとは

EC2で稼働するKubernetesのホストのこと。

Fargateと比べてカスタマイズ性が高く、ワーカーNode当たりで稼働するPod数に重み付けを設定できる。

一方で、各EC2のハードウェアリソースの消費量をユーザーが管理しなければならないため、Kubernetesのホストの管理が大変である。

eks_on_ec2


セットアップ

▼ IAMポリシー

EC2ワーカーNodeが、自身の所属するClusterにリクエストを送信できるように、EC2ワーカーNodeにAmazonEKSWorkerNodePolicyを付与する必要がある。

EC2ワーカーNode内のPodがECRからコンテナイメージをプルできるように、EC2ワーカーNodeにAmazonEC2ContainerRegistryReadOnlyを付与する必要がある。

これにより、PodのコンテナごとにAWSの認証情報をマウントする必要がなくなる。

aws-nodeのPodがAWSのネットワーク系のAPIにリクエストを送信できるように、IRSA用のServiceAccountにAmazonEKS_CNI_Policy (IPv4の場合) または AmazonEKS_CNI_IPv6_Policy (IPv6の場合) を付与する必要がある。


監視

▼ ログ収集

Node上のログの場所 説明
/var/log/containers このディレクトリに、そのEC2ワーカーNode上のPod内コンテナのログファイルのシンボリックリンクを作成する。
var/log/aws-routed-eni/ipamd.log このディレクトリに、aws-vpc-cniアドオンのL-IPAMデーモンのログを出力する。
/var/log/aws-routed-eni/plugin.log 同上


04-02. Nodeグループ (on EC2)

マネージド

▼ マネージドNodeグループ

  • Nodeグループ内の各EC2ワーカーNodeの作成
  • Nodeグループに紐づくAutoScalingグループの作成
  • EC2ワーカーNodeのOSやミドルウェアの各種アップグレード

を自動化する。

Nodeグループは、EC2ワーカーNodeが配置されるプライベートサブネットのAZにこれをスケジューリングさせるように、AutoScalingグループに各AZを自動的に設定する。

AutoScalingグループの機能を使用すれば、EC2ワーカーNodeの自動的な起動/停止を設定できる。

▼ Nodeグループの定期アクション

同じNodeグループのEC2ワーカーNodeの定期アクションを設定する。

EKSのテスト環境の請求料金を節約するために、昼間に通常の個数にスケールアウトし、夜間に0個にスケールインするようにすれば、ワーカーNodeを夜間だけ停止させられる。

▼ 起動テンプレートとAutoScalingグループとの紐付け

マネージドNodeグループは、あくまでEC2 Nodeのライフサイクルを管理するだけである。

どのようなEC2 Nodeを管理するのかは起動テンプレートとAutoScalingグループを使用して定義する必要がある。


セルフマネージド

▼ セルフマネージドNodeグループ

  • Nodeグループ内の各EC2ワーカーNodeの作成
  • Nodeグループに紐づくAutoScalingグループの作成
  • EC2ワーカーNodeのOSやミドルウェアの各種アップグレード

をユーザーが管理する。

AutoScalingグループの機能を使用すれば、EC2ワーカーNodeの自動的な起動/停止を設定できる。


Node数の変更

Nodeグループ (マネージドNodeグループ、セルフマネージドNodeグループ) では、希望数を変更することで現在のNode数を変更できる。

設定後、AutoScalingグループは希望数で設定したNode数を維持する (Karpenterのドキュメントでは、これを『静的』と表現している)。

希望数の他に最大数と最小数を設定できるが、これらは実際は機能しない。

もし負荷の状況に応じてスケーリングしたい場合、Nodeのスケーリングツール (例:ClusterAutoscaler、Karpenter、など) を使用しないと、最大数と最小数の設定に応じたスケーリングを実施してくれない。


EC2へのタグ付けの例

▼ マネージドNodeグループ

タグ 説明
Name EC2ワーカーNodeの名前 Nodeグループで指定する起動テンプレートのタグに、Nameタグを設定しておく。起動するEC2ワーカーNodeにEC2の名前はNameタグで決まる仕組みのため、起動テンプレートによってワーカーNode名を設定させることができる。

▼ セルフマネージドNodeグループ

タグ 説明
Name EC2ワーカーNodeの名前 EC2の名前はNameタグで決まる仕組みのため、Nodeグループに参加させるEC2ワーカーNodeのNameタグに、ワーカーNode名を設定しておく。
kubernetes.io/cluster/<EKS Cluster名> owned セルフマネージド型のEC2ワーカーNodeを使用する場合、ユーザーが作成したEC2をNodeグループに参加させるために、必要である。


04-03. EC2 Node AMI

EC2ワーカーNodeの最適化AMI

▼ EC2ワーカーNodeの最適化AMIとは

任意のEC2ワーカーNodeを使用できるが、AWSが用意している最適化AMIを選んだ方が良い。

このAMIには、EC2がEKSと連携するために必要なソフトウェアがプリインストールされており、EC2ワーカーNodeをセットアップする手間が省ける。

必ずしも、全てのEC2ワーカーNodeを同じAMIで構築する必要はない。

EC2ワーカーNodeを種類ごとに異なるAMIで作成し、特定のアプリを含むPodは特定のEC2ワーカーNodeにスケジューリングさせる (例:計算処理系アプリはEKS最適化高速AMIのEC2ワーカーNode上で動かす) といった方法でもよい。

▼ EKS 最適化 Amazon Linux

EKSのための標準的なEC2を作成できる。最も推奨である。

aws ssm get-parameterコマンドを使用すると、公式が提供するマシンイメージのIDを確認できる。

注意点として、AMIのマイナーバージョンは固定できるが、パッチバージョンは固定できない。

そのため、パッチバージョンがアップグレードされる度に、AMIのIDは変わる。

AMIのIDを固定するためには、AMIをダウンロードして自前で管理する必要がある。

$ aws ssm get-parameter \
    --name /aws/service/eks/optimized-ami/<バージョン>/amazon-linux-2/recommended/image_id \
    --region ap-northeast-1 \
    --query "Parameter.Value" \
    --output text

▼ EKS 最適化高速 Amazon Linux

GPUが搭載されたEC2やAmazon EC2 Inf1インスタンスを作成できる。

GPUが必要なアプリケーションの含むPod (計算処理系、機械学習系のアプリケーション) と相性が良い。

▼ EKS 最適化 ARM Amazon Linux

ARMベースのプロセッサーが搭載されたEC2を作成できる。

▼ EKS 最適化 Bottlerocket AMI

コンテナに特化したEC2を作成できる。

$ aws ssm get-parameter \
    --name /aws/service/bottlerocket/aws-k8s-<バージョン>/x86_64/latest/image_id \
    --region ap-northeast-1 \
    --query "Parameter.Value" \
    --output text


EC2ワーカーNodeのカスタムAMI

▼ EC2ワーカーNodeのカスタムAMIとは

EC2ワーカーNodeの最適化AMIではないAMIのこと。


kubelet-config.jsonファイル (KubeletConfiguration)

EC2ワーカーNodeのkubeletを設定する。

{
  "kind": "KubeletConfiguration",
  "apiVersion": "kubelet.config.k8s.io/v1beta1",
  "address": "0.0.0.0",
  "authentication":
    {
      "anonymous": {"enabled": "false"},
      "webhook": {"cacheTTL": "2m0s", "enabled": "true"},
      "x509": {"clientCAFile": "/etc/kubernetes/pki/ca.crt"},
    },
  "authorization":
    {
      "mode": "Webhook",
      "webhook": {"cacheAuthorizedTTL": "5m0s", "cacheUnauthorizedTTL": "30s"},
    },
  "clusterDomain": "cluster.local",
  "hairpinMode": "hairpin-veth",
  "readOnlyPort": 0,
  "cgroupDriver": "cgroupfs",
  "cgroupRoot": "/",
  "featureGates": {"RotateKubeletServerCertificate": "true"},
  "protectKernelDefaults": "true",
  "serializeImagePulls": "false",
  "serverTLSBootstrap": "true",
  "tlsCipherSuites":
    [
      "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
      "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
      "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
      "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
      "TLS_RSA_WITH_AES_256_GCM_SHA384",
      "TLS_RSA_WITH_AES_128_GCM_SHA256",
    ],
}


ユーザーデータファイル

▼ ユーザーデータファイルとは

EC2 Nodeの起動時に任意のコマンドを実行できるようにする。

また、セルフマネージドNodeグループやマネージドNodeグループにて、EC2ワーカーNodeのAMIにカスタムAMIを使用したり、任意のAMIで起動テンプレートを使用する場合、AWS側で決められたコマンド (bootstrap.shファイル) を実行する必要がある。

一方で、マネージドNodeグループにて、起動テンプレートを使用せずにEC2ワーカーNodeを作成する場合、ユーザーデータファイルを自動で作成してくれるため、これは不要である。

bootstrap.shファイル

EC2ワーカーNodeのカスタムAMIに必要なファイルである。

EC2ワーカーNode起動時のユーザーデータファイル内で、bootstrap.shファイルに決められたパラメーターを渡す必要がある。

ユーザーデータファイル内で、bootstrap.shファイルにパラメーターを渡す必要がある。

#!/bin/bash

# ユーザーデータファイル

set -o xtrace

# 主要なパラメーターは以下の通り。
# その他のパラメーター:https://github.com/awslabs/amazon-eks-ami/blob/584f9a56c76fc9e7e8632f6ea45e29d45f2eab63/files/bootstrap.sh#L14-L35
#
# --b64-cluster-ca:kube-apiserverのSSL証明書の値を設定する。
# --apiserver-endpoint:kube-apiserverのエンドポイントを設定する。
# --container-runtime:コンテナランタイムとしてcontainerdを使用する。代わりとして、dockerも使用できる。

/etc/eks/bootstrap.sh foo-eks-cluster \
  --b64-cluster-ca ***** \
  --apiserver-endpoint https://*****.gr7.ap-northeast-1.eks.amazonaws.com \
  --container-runtime containerd

なお、設定可能な全てのパラメーターは、以下から確認できる。

よく使用するパラメーター配下の通りである。

パラメーター 説明
--apiserver-endpoint AWS EKS Clusterのkube-apiserverのエンドポイントを設定する。
--b64-cluster-ca kube-apiserverのエンドポイントを設定した場合に、HTTPSでリクエストするために、SSL証明書を設定する。
--container-runtime containerd コンテナランタイムの種類を設定する。
--kubelet-extra-args --node-labels=nodetype=foo --max-pods=110 KubeletConfigurationのデフォルト値を上書きする。
--use-max-pods false kubeletの--max-podsオプションを有効化するかどうかを設定する。Kubeletが実行可能なPod数を設定する。Kubeletではこのオプションは非推奨になっており、代わりにKubeletConfigurationに渡すようにする。

ユーザーデータファイル内で必要なパラメーターの注意点として、各パラメーターはハードコーディングしないようにする。

パラメーターストアにパラメーターを永続化し、ユーザーデータファイル内に出力する。

#!/bin/bash

# ユーザーデータファイル

set -o xtrace

PARAMETERS=$(aws ssm get-parameters-by-path --with-decryption --path "/eks/foo-eks-cluster")

# ClusterのSSL証明書、kube-apiserverのエンドポイントの値をパラメーターストアから取得する。
for parameter in $(echo ${PARAMETERS} | jq -r '.Parameters[] | .Name + "=" + .Value'); do
  echo "export ${parameter##*/}"
done >> "${EXPORT_ENVS}"

# 出力する。
source "${EXPORT_ENVS}"

/etc/eks/bootstrap.sh foo-eks-cluster \
  --b64-cluster-ca $B64_CLUSTER_CA \
  --apiserver-endpoint $APISERVER_ENDPOINT \
  --container-runtime containerd

▼ EC2ワーカーNodeのイメージキャッシュ削除

kubeletは、Nodeのイメージのキャッシュを作成する。

イメージのキャッシュは、kubeletによるガベージコレクションまたはNodeの再作成で削除される。

KubeletConfigurationの--image-gc-high-thresholdオプションで、キャッシュ削除の閾値とするディスク使用率を設定する。

--image-gc-low-thresholdオプションで、解放しようとするディスク使用率を設定する。

*実装例*

ディスク使用率が70%を超過した場合に、ディスク使用率50%分を解放する。

#!/bin/bash

# ユーザーデータファイル

set -o xtrace

# --image-gc-high-thresholdオプションに値が既に設定されていなければ、設定を挿入する。
if ! grep -q imageGCHighThresholdPercent /etc/kubernetes/kubelet/kubelet-config.json;
then
    sed -i '/"apiVersion*/a \ \ "imageGCHighThresholdPercent": 70,' /etc/kubernetes/kubelet/kubelet-config.json
fi

# --image-gc-low-thresholdオプションに値が既に設定されていなければ、設定を挿入する。
if ! grep -q imageGCLowThresholdPercent /etc/kubernetes/kubelet/kubelet-config.json;
then
    sed -i '/"imageGCHigh*/a \ \ "imageGCLowThresholdPercent": 50,' /etc/kubernetes/kubelet/kubelet-config.json
fi

/etc/eks/bootstrap.sh foo-eks-cluster \
  --b64-cluster-ca $B64_CLUSTER_CA \
  --apiserver-endpoint $APISERVER_ENDPOINT \
  --container-runtime containerd

▼ EC2ワーカーNodeのGraceful Shutdown

デフォルトでは、EC2ワーカーNodeは新しいPodのスケジューリングを禁止した後、Podの退避を待たずに停止してしまう。

kubeletを使用してEC2ワーカーNodeの停止を待機し、Podが終了する (ワーカーNodeから退避させる) までの時間を稼ぐ。

ワーカーNodeの停止までの待機中に終了できたPodは、Failedステータスとなる。

KubeletConfigurationの--shutdown-grace-periodオプション (shutdownGracePeriod) で、ワーカーNodeの停止を待機する期間を設定する。

また--shutdown-grace-period-critical-podsオプション (shutdownGracePeriodCriticalPods) で、特に重要なPodの終了のために待機する時間を設定する。

InhibitDelayMaxSecには、--shutdown-grace-periodオプションと同じ秒数 (単位は不要) を設定する。

注意点として、この時間が長すぎると、ワーカーNodeの停止の全体時間が長くなるため、結果的にローリングアップグレードでNodeの所要時間も長くなってしまう。

*実装例*

ワーカーNodeの停止を6分だけ待機し、その後に停止を始める。

6分のうち後半2分を重要なPodのために停止に割り当てる。

#!/bin/bash

# ユーザーデータファイル

set -o xtrace

# --shutdown-grace-periodオプションに値が既に設定されていなければ、設定を挿入する。
if ! grep -q shutdownGracePeriod /etc/kubernetes/kubelet/kubelet-config.json;
then
    sed -i '/"apiVersion*/a \ \ "shutdownGracePeriod": "360s",' /etc/kubernetes/kubelet/kubelet-config.json
fi

# --shutdown-grace-period-critical-podsオプションに値が既に設定されていなければ、設定を挿入する。
if ! grep -q shutdownGracePeriodCriticalPods /etc/kubernetes/kubelet/kubelet-config.json;
then
    sed -i '/"shutdownGracePeriod*/a \ \ "shutdownGracePeriodCriticalPods": "120s",' /etc/kubernetes/kubelet/kubelet-config.json
fi

mkdir -p /etc/systemd/logind.conf.d
cat <<EOF > /etc/systemd/logind.conf.d/50-max-delay.conf
[Login]
InhibitDelayMaxSec=360
EOF

sudo systemctl restart systemd-logind

/etc/eks/bootstrap.sh foo-eks-cluster \
  --b64-cluster-ca $B64_CLUSTER_CA \
  --apiserver-endpoint $APISERVER_ENDPOINT \
  --container-runtime containerd

FailedステータスなPodはそのままでは削除できない。

そのため、FailedステータスなPodを自動で削除してくれるツール (例:descheduler) や、以下のような削除コマンドを持つCronJobを作成するとよい。

for ns in $(kubectl get namespace -o name | cut -d / -f 2); do
  echo $ns
  kubectl get pod -n $ns -o json \
    | jq -r '.items[] | select(.status.phase == "Failed") | select(.status.reason == "Shutdown" or .status.reason == "NodeShutdown" or .status.reason == "Terminated") | .metadata.name' \
    | xargs --no-run-if-empty --max-args=100 --verbose kubectl delete pod -n $ns
done


04-04. セットアップ

コンソール画面の場合

▼ マネージドNodeグループの場合

起動テンプレートを使用し、EC2ワーカーNodeを作成する。

起動テンプレートのタグ付け機能を使用してEC2にタグ付けでき、これは任意である。

▼ セルフマネージドNodeグループの場合

任意のAutoScalingにて、起動テンプレートを使用してEC2ワーカーNodeを作成する。

AutoScalingのタグ付け機能を使用して、kubernetes.io/cluster/<EKS Cluster名>タグ (値はowned) をつけ、Nodeグループに明示的に参加させる必要がある。

なお、起動テンプレートも合わせて使用でき、これは任意である。


Terraformの場合

▼ マネージドNodeグループの場合

起動テンプレートを使用し、EC2ワーカーNodeを作成する。

# Nodeグループ
resource "aws_eks_node_group" "foo" {

  ...

  # Nodeグループの種類だけ、起動テンプレートを設定する
  launch_template {
    id      = aws_launch_template.foo1.id
    version = "$Latest"
  }

  launch_template {
    id      = aws_launch_template.foo2.id
    version = "$Latest"
  }

  ...
}

# 起動テンプレート
resource "aws_launch_template" "foo" {

  # タグ付けは任意である
  tag_specifications {
    tags = {
      Env  = var.environment
    }
  }

  ...
}

# Nodeグループのタグ
resource "aws_autoscaling_group_tag" "foo" {
  for_each = local.tags

  autoscaling_group_name = aws_eks_node_group.foo.name

  # Nodeグループに設定する全てのタグに対して適用する
  tag {
    key                 = each.key
    value               = each.value
    # 実装時点 (2023/06/06) で、マネージドNodeグループは自身の作成するAutoScalingグループにタグ付けできない
    # そのままではterraform planのたびに、AutoScalingグループにタグ付けしようとする差分がでてしまうため、Nodeグループ外からAutoScalingグループのタグ付けを有効化する
    # @see
    # https://github.com/aws/containers-roadmap/issues/608
    # https://github.com/terraform-aws-modules/terraform-aws-eks/issues/1558#issuecomment-1030633280
    propagate_at_launch = true
  }
}

▼ セルフマネージドNodeグループの場合

任意のAutoScalingにて、起動テンプレートを使用してEC2ワーカーNodeを作成する。

resource "aws_autoscaling_group" "foo" {

  ...

  tag {
    key   = "Name"
    value = "foo-instance"
  }

  # AutoScalingのタグに kubernetes.io/cluster/<EKS Cluster名> をつける必要がある
  tag {
    key   = "kubernetes.io/cluster/<EKS Cluster名>"
    value = "owned"
  }

  # 起動テンプレートは任意である
  launch_template {
    id      = aws_launch_template.foo.id
    version = "$Latest"
  }

  ...
}


05. on Fargate (FargateワーカーNode)

on Fargate (FargateワーカーNode) とは

記入中...


監視

▼ メトリクス収集

FargateワーカーNode内のメトリクスのデータポイントを収集する上で、FargateワーカーNodeはDaemonSetに非対応である。

そのため、メトリクス収集コンテナをサイドカーコンテナとして配置する必要がある。

収集ツールとして、OpenTelemetryをサポートしている。

▼ ログ収集

FargateワーカーNode内のログを転送する上で、FargateはDaemonSetに非対応のため、ログ転送コンテナをサイドカーコンテナとして配置する必要がある。

ロググーティングツールとして、FluentBitをサポートしている。

(1)

ログ転送コンテナのためのNamespaceを作成する。

名前は、必ずaws-observabilityとする。

apiVersion: v1
kind: Namespace
metadata:
  name: aws-observability
  labels:
    aws-observability: enabled
(2)

aws-observability内でaws-loggingという名前のConfigMapを作成する。

これより、ログ転送コンテナとしてFluentBitコンテナが作成され、PodからCloudWatchログにログを送信できるようになる。

名前は、必ずaws-loggingとする。

$ kubectl apply -f config-map.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-logging
  namespace: aws-observability
data:
  output.conf: |
    [OUTPUT]
        Name cloudwatch
        Match *
        region ap-northeast-1
        log_group_name fluent-bit-cloudwatch
        log_stream_prefix from-fluent-bit-
        auto_create_group true
(3)

FargateワーカーNodeにECRやCloudWatchへの認可スコープを持つポッド実行ロールを付与しておく。

これにより、KubernetesリソースにAWSへの認可スコープが付与され、ServiceAccountやSecretを作成せずとも、PodがECRからコンテナイメージをプルできる様になる。

一方で、Pod内のコンテナには認可スコープが付与されない。

そのため、Podが作成された後に必要な認可スコープ (例:コンテナがRDSにリクエストを送信する認可スコープなど) に関しては、ServiceAccountとIAMロールの紐付けが必要である。



05-02. セットアップ

コンソール画面の場合

▼ EC2ワーカーNodeとの比較

EC2ワーカーNodeと比較して、使用できない機能については、以下のリンクを参考にせよ。


FargateワーカーNode

▼ FargateワーカーNodeとは

eks_on_fargate

Fargate上で稼働するKubernetesのホストのこと。

KubernetesのワーカーNodeに相当する。

EC2ワーカーNodeと比べてカスタマイズ性が低く、ワーカーNode当たりで稼働するPod数はAWSが管理する。

一方で、各EC2のハードウェアリソースの消費量をユーザーが管理しなくてもよいため、Kubernetesのホストの管理が楽である。

▼ FargateワーカーNodeを使用できない場合

以下の場合は、EC2ワーカーNodeを使用する。

  • FargateワーカーNodeでは、DaemonSetが使えない。サイドカーを配置する必要がある。
  • Fargateで設定可能な最大スペックを超えたスペックが必要である。
  • EmptyDir Volume以外が必要である。
  • FargateワーカーNodeでは、サービスメッシュにAppMeshしか使えない。もし、AppMeshを使いたくない場合は、EC2ワーカーNodeを使用する。

▼ Fargateプロファイル

Fargateを設定する。

コンポーネント名 説明 補足
Pod実行ロール kubeletがAWSリソースにリクエストを送信できるように、Podにロールを設定する。 ・実行ポリシー (AmazonEKSFargatePodExecutionRolePolicy) には、ECRへの認可スコープのみが付与されている。
・信頼されたエンティティでは、eks-fargate-pods.amazonaws.comを設定する必要がある。
https://docs.aws.amazon.com/eks/latest/userguide/pod-execution-role.html
サブネット EKS FargateワーカーNodeが起動するサブネットIDを設定する。 プライベートサブネットを設定する必要がある。
ポッドセレクタ (Namespace) EKS FargateワーカーNodeにスケジューリングさせるPodを固定できるように、PodのNamespaceの値を設定する。 kube-systemdefaultを指定するKubernetesリソースが稼働できるように、ポッドセレクタにこれを追加する必要がある。
・IstioやArgoCDを、それ専用のNamespaceで稼働させる場合は、そのNamespaceのためのプロファイルを作成しておく必要がある。
ポッドセレクタ (Label) EKS FargateワーカーNodeにスケジューリングさせるPodを固定できるように、Podの任意のlabelキーの値を設定する。


05-02. Nodeグループ (on Fargate)

記入中...


06. アップグレード

アップグレードとは

EKS Clusterにて、コントロールプレーンとデータプレーンをローリング方式でアップグレードする。

AWSはIaaSのため、AMIを指定すれば、NodeのOSのアップグレードも実施してくれる。

執筆時点 (2022/01/28) では、AWSのAPIを介してupdateConfig値を設定すれば、アップグレード時のサージ数を設定できる。


アップグレードの仕組み

▼ データプレーンの場合

EKS Clusterのアップグレード時、以下の仕組みでデータプレーンのワーカーNodeをローリングアップグレードする。

また、Nodeグループに紐づくAutoScalingグループのAZリバランシングの仕組みによって、既存のワーカーNodeと同じAZでワーカーNodeを再作成する。

(1)

Nodeグループ単位でローリングアップグレードできるように、EKS ClusterのワーカーNode数の設定 (Node希望数、Node最大数) を自動的に増加させる。

(2)

旧ワーカーNodeを残して、新しいAMIを使用したワーカーNodeを作成する。

旧ワーカーNodeが稼働しているAZで新ワーカーNodeを作成する。

旧ワーカーNodeを残せるのは、あらかじめEKS ClusterのワーカーNode数の設定 (Node希望数、Node最大数) を増加させているためである。

(3)

各AZで新ワーカーNodeを正しく作成できることを検証する。

(4)

AZリバランシングが成功すれば、旧ワーカーNodeでDrainが開始され、Podのスケジューリングが無効化される。

(5)

新ワーカーNode上でPodをスケジューリングさせ直し、旧ワーカーNodeを削除する。

(6)

最終的に、アップグレード前のワーカーNode数 (Node希望数) に戻る。

手順

EKS Clusterはおおよそ以下の方法でアップグレードする。

(1)

コントロールプレーンNodeをアップグレードする。

(2)

ワーカーNodeをアップグレードする。

コントロールプレーン上のkube-apiserverのバージョンに応じた新しいAMIを使用して、ワーカーNodeを再作成する。

(3)

ワーカーNode上のAWS EKSアドオン (例:aws-eks-codednsアドオン、aws-eks-kube-proxyアドオン、aws-eks-vpc-cniアドオン、など) をアップグレードする。