コンテンツにスキップ

AWS EBS CSIドライバー@AWS EKSアドオン

はじめに

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


01. AWS EBS CSIドライバー

アーキテクチャ

PersistentVolumeにAWS EBSを紐付け、PodがAWS EBSをPersistentVolumeとして使用できるようにする。

ステートレスなアプリケーションでは、AWS EBSにデータを永続化する必要はないため、AWS EBS CSIドライバーは不要である。

storage_class


02. セットアップ

EKSアドオンとして

▼ Terraformの場合

Terraformを使用する。

Terraformのaws_eks_addonでEKSアドオンをインストールし、AWS EBS CSIドライバーに関するKubernetesリソースを作成する。

# AWS EKSアドオンをインストールする。
resource "aws_eks_addon" "aws_ebs_csi_driver" {

  cluster_name                = data.aws_eks_cluster.cluster.name
  addon_name                  = "aws-ebs-csi-driver"
  addon_version               = "<バージョン>"
  service_account_role_arn    = module.iam_assumable_role_ebs_csi_driver[0].iam_role_arn
  # Terraformで設定を上書きできるようにする
  resolve_conflicts_on_update = "OVERWRITE"
}
module "iam_assumable_role_with_oidc_ebs_csi_driver" {

  source                        = "terraform-aws-modules/iam/aws//modules/iam-assumable-role-with-oidc"

  version                       = "<バージョン>"

  # AWS EBS CSIコントローラーのPodに紐付けるIAMロール
  create_role                   = true
  role_name                     = "foo-ebs-csi-driver"

  # AWS EKS ClusterのOIDCプロバイダーURLからhttpsプロトコルを除いたもの
  # ArgoCDは、デプロイ専用のAWS EKS Cluster上で稼働している
  provider_url                  = replace(module.eks.cluster_oidc_issuer_url, "https://", "")

  # AWS IAMロールに紐付けるIAMポリシー
  role_policy_arns              = [
    "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
  ]

  # AWS EBS CSIコントローラーのPodのServiceAccount名
  # ServiceAccountは、Terraformではなく、マニフェストで定義した方が良い
  oidc_fully_qualified_subjects = [
    "system:serviceaccount:kube-system:foo-ebs-csi-controller"
  ]
}

また、StorageClassを定義する必要があるが、これはTerraformでもマニフェストでもどちらでもよい。

# KubernetesのStorageClassをTerraformで作成する。
# マニフェストとして定義しても良い。
resource "kubernetes_storage_class" "gp3_encrypted" {

  metadata {
    name = "gp3-encrypted"
    annotations = {
      "storageclass.kubernetes.io/is-default-class" = "true"
    }
  }

  # AWS EBS CSIドライバーをプロビジョナーに設定する
  storage_provisioner = "ebs.csi.aws.com"

  parameters = {
    encrypted = "true"
    fsType    = "ext4"
    type      = "gp3"
  }

  reclaim_policy      = "Delete"
  volume_binding_mode = "WaitForFirstConsumer"
}

別途、AWS EBS CSIドライバーのPodに紐付けるServiceAccountを作成し、IAMロールのARNを設定する。

ServiceAccountは、Terraformではなくマニフェストで定義した方が良い。

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: <IAMロールのARN>
  name: foo-ebs-csi-controller
  namespace: kube-system

IRSAにより、ServiceAccountを介してPodとAWS IAMロールが紐づく。

▼ Helmの場合

Helmを使用する。

KubernetesよりもAWSに依存している要素が多いため、Terraformによるセットアップの方が個人的にはおすすめである。

$ helm repo add <チャートリポジトリ名> https://kubernetes-sigs.github.io/aws-ebs-csi-driver

$ helm repo update

$ helm install <Helmリリース名> <リポジトリ名>/aws-ebs-csi-driver -n kube-system --version=<バージョンタグ>


02-02. マニフェスト

マニフェストの種類

AWS EBS CSIドライバーは、Deployment (ebs-csi-controller) 、ServiceAccount、などのマニフェストから構成される。


Deployment配下のPod

記入中...


ServiceAccount

IRSAの仕組みで、PodとIAMロールを紐付ける。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: foo-foo-ebs-csi-controller
  namespace: kube-system
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<アカウントID>:role/foo-ebs-csi-controller-role
secrets:
  - name: foo-ebs-csi-controller-token


03. プロビジョニング

静的プロビジョニング

▼ AWS EBS

AWS EBSを手動で作成する必要がある。

▼ PersistentVolume

*実装例*

apiVersion: v1
kind: PersistentVolume
metadata:
  name: foo-persistent-volume
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  csi:
    # AWS EBS CSIドライバーをプロビジョナーに設定する
    driver: ebs.csi.aws.com
    # 手動で作成したAWS EBSのIDを設定する。
    volumeHandle: vol-*****

▼ PersistentVolumeClaim

PersistentVolumeClaimでVolumeを要求する。

PersistentVolumeClaimでVolumeを要求すると、AWS EBS CSIドライバーは、PersistentVolumeとそれに紐づくAWS EBSを自動的に作成する。

Podの.spec.nodeSelectorキーも不要である。

*実装例*

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: foo-persistent-volume-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  # デフォルトの動的プロビジョニングを確実に無効化する
  storageClassName: ""
apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: foo
  template:
    metadata:
      labels:
        app: foo
    spec:
      containers:
        - name: foo
          image: busybox
          command:
            - /bin/bash
            - -c
            - sleep 10000
          volumeMounts:
            - mountPath: /app/data
              name: data
      nodeSelector:
        topology.ebs.csi.aws.com/zone: ap-northeast-1a
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: foo-persistent-volume-claim


動的プロビジョニング

▼ AWS EBS

AWS EBSは、AWS EBS CSIドライバーが自動で作成するため、作成は不要である。

▼ StorageClass

動的プロビジョニングの場合、StorageClassが必要である。

要求するAWS EBSのタイプをStorageClassで指定する。

reclaimPolicyDeleteになっているPersistentVolumeClaimを削除すれば、StorageClassがEBSもよしなに削除してくれる。

*実装例*

マニフェストまたはTerraformで定義する。

# マニフェストで定義した場合
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: foo-storage-class
parameters:
  type: gp3
provisioner: ebs.csi.aws.com
# PersistentVolumeClaimが削除された時に、AWS EBSも自動的に削除できるようにする
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
# Terraformで定義した場合
resource "kubernetes_storage_class" "gp3_encrypted" {

  metadata {
    name = "foo-storage-class"
  }

  # AWS EBS CSIドライバーをプロビジョナーに設定する
  storage_provisioner = "ebs.csi.aws.com"

  parameters = {
    encrypted = "true"
    fsType    = "ext4"
    type      = "gp3"
  }

  volume_binding_mode = "WaitForFirstConsumer"
}

▼ PersistentVolumeClaim

PersistentVolumeClaimでStorageClassを指定し、外部サービスが提供するVolumeを要求する。

StorageClassが指定されたPersistentVolumeClaimでVolumeを要求すると、AWS EBS CSIドライバーは、PersistentVolumeとそれに紐づくAWS EBSを自動的に作成する。

Podの.spec.nodeSelectorキーも不要である。

*実装例*

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: foo-persistent-volume-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  # AWS EBS CSIドライバーがプロビジョナーに指定されたStorageClassを要求する
  storageClassName: foo-storage-class
apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: foo
  template:
    metadata:
      labels:
        app: foo
    spec:
      containers:
        - name: foo
          image: busybox
          command:
            - /bin/bash
            - -c
            - sleep 10000
          volumeMounts:
            - mountPath: /app/data
              name: data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: foo-persistent-volume-claim