Skip to content

Node ライフサイクル管理

サポートされるバージョン: EKS 1.29+, EKS Auto Mode GA 最終更新: July 3, 2026

このガイドでは、expiration policy、AMI 管理、drift detection、Node freshness monitoring を含む、EKS Auto Mode における Node ライフサイクル管理について説明します。


Node Expiration Policies (expireAfter)

expireAfter フィールドは、Node が自動的に置き換えられるまで実行できる期間を制御します。

expireAfter の仕組み

yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: with-expiration
spec:
  template:
    spec:
      requirements:
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["m", "c"]
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
      # Set maximum node lifetime
      expireAfter: 168h  # Auto-replace after 7 days

Expiration プロセス

  1. Node が expireAfter の age に達する
  2. Controller が Node を置き換え対象としてマークする
  3. 新しい Node が最新の設定でプロビジョニングされる
  4. PDBs を尊重しながら workload が移行される
  5. 古い Node が drain され、terminate される

Auto Mode の 21 日間の最大 Node Lifetime

EKS Auto Mode は Karpenter ベースの expireAfter default を使用し、Node は作成後の最大 age である 21 days (504h) に達すると自動的に置き換えられます。より頻繁に置き換えるために expireAfter を 21 日未満に設定できますが、21 日より長く設定しても効果はありません — Auto Mode は 21 日をハードな上限として強制します。managed node group や self-managed Karpenter とは異なり、Node を無期限に保持することはできません。

長期間 state を保持する workload(cache warm-up に時間がかかる service、local storage に依存する stateful workload など)を実行する場合は、この 21 日の上限を前提として、Pod の rescheduling と data rebalancing 手順を事前に計画してください。

推奨される expireAfter 値

ユースケースexpireAfter根拠
Security-critical24h - 72h頻繁な patching、compliance requirements
Standard production168h (7 days)freshness と stability のバランス
Cost-sensitive336h (14 days)replacement overhead を最小化(21 日の上限内)
Development/Test504h (21 days, maximum)Node reuse を最大化。この値が強制される上限
Compliance (PCI/HIPAA)72h - 168haudit requirements を満たす

expireAfter 設定例

yaml
# Security-first configuration
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: security-critical
spec:
  template:
    spec:
      expireAfter: 72h  # 3 days for security compliance
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["on-demand"]
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: secure-nodeclass
---
# Cost-optimized configuration
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: cost-optimized
spec:
  template:
    spec:
      expireAfter: 336h  # 14 days for cost efficiency
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot"]
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default

AMI 管理戦略

Auto Mode が AMI を選択する仕組み

EKS Auto Mode は、NodeClass 設定に基づいて AMI を自動的に選択し、管理します。

yaml
apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
  name: ami-managed
spec:
  # AMI family selection
  amiFamily: AL2023  # or Bottlerocket

AMI Family 比較

機能AL2023Bottlerocket
Base OSAmazon Linux 2023container 専用に構築された OS
Boot time~40-60 seconds~20-40 seconds
Attack surfaceStandardMinimal (read-only root)
CustomizationFull (userData)Limited (settings API)
Package managerdnfなし(immutable)
Security updatesStandard patchingAtomic updates
Use case一般的な workloadsecurity-focused workload

AMI Family 選択ガイドライン

Workload TypeRecommended AMIRationale
General web servicesAL2023柔軟性、なじみのある tooling
Security-criticalBottlerocket最小限の attack surface
Compliance (PCI/SOC2)Bottlerocketimmutable infrastructure
GPU workloadsAL2023NVIDIA driver support
Custom kernel modulesAL2023OS への完全な access
Fast scalingBottlerocketより高速な boot times

Custom AMI 設定

yaml
# For specific AMI requirements
apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
  name: custom-ami
spec:
  amiFamily: AL2023

  # AMI selection by tags (if using custom AMIs)
  amiSelectorTerms:
    - tags:
        Name: my-custom-eks-ami
        Environment: production

AMI 更新と Drift Detection

AMI 更新が Drift をトリガーする仕組み

AWS が新しい AMI をリリースした場合、または NodeClass を更新した場合:

  1. AMI Release: AWS が新しい EKS-optimized AMI を公開する
  2. Drift Detection: Controller が AMI version mismatch を検出する
  3. Node Marking: 既存の Node が "drifted" としてマークされる
  4. Replacement: disruption settings に基づいて Node が置き換えられる

Drift Detection トリガー

変更Drift をトリガーReplacement Speed
New AMI versionYesdisruption budget に基づく
NodeClass AMI family changeYesimmediate scheduling
Security patch AMIYesdisruption budget に基づく
NodePool requirement changeYesconsolidation に基づく
NodeClass block device changeYes新しい Node のみ

Drift Status の監視

bash
# Check for drifted nodes
kubectl get nodes -o custom-columns=\
NAME:.metadata.name,\
NODEPOOL:.metadata.labels.karpenter\\.sh/nodepool,\
AGE:.metadata.creationTimestamp,\
DRIFT:.metadata.annotations.karpenter\\.sh/drift-hash

# Check NodeClaim drift status
kubectl get nodeclaims -o wide

# Watch for drift events
kubectl get events --sort-by='.lastTimestamp' | grep -i drift

Drift Replacement の制御

yaml
# Slow drift replacement for stability
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: controlled-drift
spec:
  template:
    spec:
      expireAfter: 168h
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 10m
    budgets:
      # Slow, controlled replacement
      - nodes: "1"
      # No replacement during business hours
      - nodes: "0"
        schedule: "0 9-17 * * mon-fri"
        duration: 8h

Node Freshness Policies と Security Patching

Node Freshness が重要な理由

懸念影響Mitigation
Security patchespatch されていない vulnerabilities短い expireAfter
AMI updates不足している features/fixesdrift replacement を有効化
Configuration drift一貫性のない behavior定期的な Node rotation
Complianceaudit findings文書化された rotation policy

Security Patching 戦略

yaml
# Security-focused NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: security-patched
spec:
  template:
    spec:
      # Maximum node age for security compliance
      expireAfter: 72h  # 3 days
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: secure-nodeclass
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 5m
    budgets:
      # Allow faster replacement for security patches
      - nodes: "20%"
---
apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
  name: secure-nodeclass
spec:
  amiFamily: Bottlerocket  # Security-hardened OS

  metadataOptions:
    httpTokens: required  # IMDSv2 only
    httpPutResponseHopLimit: 1

  blockDeviceMappings:
    - deviceName: /dev/xvda
      ebs:
        encrypted: true
        volumeType: gp3

Consolidation と Expiration のトレードオフ

それぞれが適用されるタイミング

MechanismTriggerPurposePriority
ConsolidationUnderutilizationcost optimization低い
ExpirationAge thresholdsecurity/freshness高い
DriftConfiguration changeconsistency最高

Mechanism 間の相互作用

Node Lifecycle Priority:
1. Drift (immediate) - Configuration mismatch
2. Expiration (scheduled) - Age threshold reached
3. Consolidation (opportunistic) - Underutilization detected

優先度ごとの設定

yaml
# Cost-priority (consolidation aggressive, expiration relaxed)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: cost-priority
spec:
  template:
    spec:
      expireAfter: 336h  # 14 days - relaxed
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 1m  # Aggressive consolidation
---
# Security-priority (expiration aggressive, consolidation relaxed)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: security-priority
spec:
  template:
    spec:
      expireAfter: 72h  # 3 days - aggressive
  disruption:
    consolidationPolicy: WhenEmpty  # Relaxed consolidation
    consolidateAfter: 10m

Node Age Distribution の監視

kubectl ベースの監視

bash
# List nodes with age
kubectl get nodes --sort-by='.metadata.creationTimestamp' \
  -o custom-columns=\
NAME:.metadata.name,\
NODEPOOL:.metadata.labels.karpenter\\.sh/nodepool,\
INSTANCE:.metadata.labels.node\\.kubernetes\\.io/instance-type,\
CREATED:.metadata.creationTimestamp,\
AGE:.metadata.creationTimestamp

# Calculate node ages in days
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.creationTimestamp}{"\n"}{end}' | \
while read name created; do
  age_seconds=$(($(date +%s) - $(date -d "$created" +%s)))
  age_days=$((age_seconds / 86400))
  age_hours=$(((age_seconds % 86400) / 3600))
  echo "$name: ${age_days}d ${age_hours}h"
done

Prometheus/Grafana 監視

Node age に関する主要な Prometheus queries:

promql
# Node age in days
(time() - kube_node_created) / 86400

# Nodes older than 7 days
count(((time() - kube_node_created) / 86400) > 7)

# Average node age by NodePool
avg((time() - kube_node_created) / 86400) by (label_karpenter_sh_nodepool)

# Node age distribution histogram
histogram_quantile(0.50,
  sum(rate(kube_node_created_bucket[24h])) by (le)
)

Alerting Rules

yaml
# Prometheus alerting rules for node age
groups:
  - name: node-lifecycle
    rules:
      - alert: NodeTooOld
        expr: (time() - kube_node_created) / 86400 > 10
        for: 1h
        labels:
          severity: warning
        annotations:
          summary: "Node {{ $labels.node }} is older than 10 days"

      - alert: NodeAgeDistributionSkewed
        expr: stddev((time() - kube_node_created) / 86400) > 3
        for: 4h
        labels:
          severity: info
        annotations:
          summary: "Node ages are highly variable, check rotation"

Node Age Dashboard

次の内容を含む Grafana dashboard を作成します:

PanelQueryVisualization
Node count by age bucketNode age の histogramBar chart
Average age by NodePoolavg by (nodepool)Stat panel
Oldest nodesage による Top NTable
Nodes expiring soonexpireAfter に近い ageAlert list
Replacement rate作成/終了された NodeClaimsTime series

Node Lifecycle Best Practices

PracticeRecommendation
Set expireAfter常に設定、default は 7 日
Use Bottlerocket for security最小限の attack surface
Monitor node agesexpected age を超えた Node に alert
Respect PDBsgraceful workload migration を確保
Stagger replacementsdisruption budgets を使用
Track AMI versionssecurity patches を監視

< 前へ: Cost Management | 目次 | 次へ: Workload Optimization >