# Amazon EKSとEFSのセットアップ

Dynamic Engineおよびその環境をデプロイする前に、共有ストレージのバックエンドとしてAmazon Elastic File System (EFS)を使用するAmazon EKSクラスターをセットアップします。

## 始める前に

* 必要なIAM権限が付与されたAWSアカウントが必要です。完全なリストについては、[Amazon EKSをDynamic Engineデプロイ用に設定する](https://help.qlik.com/talend/ja-JP/dynamic-engine-configuration-guide/Cloud/deploying-dynamic-engine-on-aws-eks "Dynamic Engineは、EKSネイティブのストレージシステムを使用してAmazon Elastic Kubernetes Service(EKS)上にデプロイできます。")を参照してください。

## このタスクについて

情報メモ重要: Amazon EKS Auto Modeでは、まず[マネージドKubernetes 運用モード](https://help.qlik.com/talend/ja-JP/dynamic-engine-configuration-guide/Cloud/prerequisites-to-use-dynamic-engines)で設定されているマネージドモードの構成を適用することをお勧めします。

この手順では、専用の仮想プライベートクラウド(Amazon VPC)内に新しいEKSクラスターを作成し、複数のアベイラビリティーゾーンにまたがるEFSマウントターゲットを設定した上で、EFS CSI (Container Storage Interface)ドライバーをインストールします。また、この手順では、ユーザーのEFSファイルシステムを参照し、アクセスポイントを使用して永続ボリュームを動的にプロビジョニングするストレージクラスも作成します。

## 手順

1. AWS EKSおよびEFSのデプロイメントの環境変数を設定します。
   ### 例
   ```
   export AWS_REGION=<your-aws-region>
   export EKS_CLUSTER_NAME=<your-eks-cluster-name>
   export EFS_NAME=<your-efs-filesystem-name>
   ```
2. Dynamic Engine環境に最適化されたインフラストラクチャ構成でEKSクラスターをデプロイするための、EKSクラスター設定ファイルを作成します。
   ```
   cat <<EOF > eks-config.yaml
   apiVersion: eksctl.io/v1alpha5
   kind: ClusterConfig

   metadata:
     name: ${EKS_CLUSTER_NAME}
     region: ${AWS_REGION}
     version: "1.34"

   addonsConfig:
     autoApplyPodIdentityAssociations: true

   addons:
     - name: eks-pod-identity-agent
     - name: aws-efs-csi-driver
       
   vpc:
     cidr: 10.10.0.0/16
     autoAllocateIPv6: false
     hostnameType: resource-name
     clusterEndpoints:
       publicAccess: true
       privateAccess: true
     nat:
       gateway: HighlyAvailable

   managedNodeGroups:
     - name: ng-amd64
       amiFamily: AmazonLinux2023 # (default) or Bottlerocket
       minSize: 2
       maxSize: 4
       desiredCapacity: 2
       instanceSelector:
         vCPUs: 4
         memory: 16GiB
         cpuArchitecture: amd64
       privateNetworking: true
       
       
   EOF
   ```

   次を設定します。
   * リージョン、EKSクラスター名、使用するKubernetesのバージョン(この例では1.34)を指定します。
   * Dynamic EngineがEFS上で稼働するために必要となる、2つのアドオンをインストールします。EFSボリュームをポッドに安全にマウントするaws-efs-csi-driverと、ハードコードされた認証情報を使用することなく、Dynamic EngineポッドがEFSへのアクセスに必要なIAMロールを引き受けられるようにするeks-pod-identity-agentです。
   * VPCを作成し、すべてのノードをプライベートサブネットに配置します(privateNetworking: true)。これはDynamic Engineによって要求されます。ノードは、Dynamic Engineコンテナイメージを取得するために、NATゲートウェイ経由でのみインターネットにアクセスします。クラスターのエンドポイントは、ローカルマシンおよびVPC内の両方から引き続きアクセスできます。
   * Dynamic Engineワークロード向けにサイジングされたプロビジョニングノード各ノードは、4つのvCPUと16 GiBのRAMを搭載しています。Dynamic EngineコンテナイメージはAMD64専用に構築されているため、AMD64アーキテクチャ(cpuArchitecture: amd64)が必須となります。
3. EKSクラスターを作成し、ローカルのkubectlツールをそのEKSクラスターに接続して、クラスターへの接続性を確認します。
   ```
   eksctl create cluster -f eks-config.yaml
   aws eks update-kubeconfig --region "$AWS_REGION" --name "$EKS_CLUSTER_NAME"
   kubectl get nodes
   ```

   すべてのノードが[Ready] (準備完了)ステータスになるまで待機してから、次の手順に進んでください。
4. このスクリプトを実行して、VPC IDとサブネットIDを取得します。
   ```
   VPC_ID=$(aws eks describe-cluster \
     --region "$AWS_REGION" \
     --name ${EKS_CLUSTER_NAME} \
     --output text \
     --query "cluster.resourcesVpcConfig.vpcId")
   echo "VPC_ID=$VPC_ID"

   SUBNET_IDS_PRIVATE=$(aws ec2 describe-subnets \
     --region "$AWS_REGION" \
     --filters Name=vpc-id,Values="$VPC_ID" Name=tag:kubernetes.io/role/internal-elb,Values=1 \
     --query "Subnets[*].SubnetId" \
     --output text | sed 's/\t/ /g')
   echo "SUBNET_IDS_PRIVATE=$SUBNET_IDS_PRIVATE"
   ```
5. EKSノードからアクセス可能なEFSセキュリティグループを作成します。
   1. EKSノードのセキュリティグループのIDを取得します。
      ```
      NODE_SG_ID=$(aws eks describe-cluster \
         --region "$AWS_REGION" \
         --name "$EKS_CLUSTER_NAME" \
         --query "cluster.resourcesVpcConfig.clusterSecurityGroupId" \
         --output text)
      echo "NODE_SG_ID=$NODE_SG_ID"
      ```
   2. EFSセキュリティグループを作成します。
      ```
      EFS_SG_ID=$(aws ec2 create-security-group \
        --region "$AWS_REGION" \
        --group-name "${EKS_CLUSTER_NAME}-efs-sg" \
        --description "EFS access from EKS" \
        --vpc-id "$VPC_ID" \
        --query "GroupId" \
        --output text)
      ```
   3. ノードのセキュリティグループに、EFSセキュリティグループへのアクセス権を付与します。
      ```
      aws ec2 authorize-security-group-ingress \
        --region "$AWS_REGION" \
        --group-id "$EFS_SG_ID" \
        --protocol tcp \
        --port 2049 \
        --source-group "$NODE_SG_ID"
      ```
6. EFSファイルシステムを作成します。
   ```
   EFS_ID=$(aws efs create-file-system \
     --region "$AWS_REGION" \
     --creation-token "${EKS_CLUSTER_NAME}-efs" \
     --encrypted \
     --tags Key=Name,Value="${EFS_NAME}" \
     --query "FileSystemId" \
     --output text)

   echo "EFS_ID=$EFS_ID"
   ```
7. 各プライベートサブネットにマウントターゲットを作成します。
   ```
   for subnet in $(echo "$SUBNET_IDS_PRIVATE" | tr ' ' '\n'); do
     aws efs create-mount-target \
     --region "$AWS_REGION" \
     --file-system-id "$EFS_ID" \
     --subnet-id "$subnet" \
     --security-groups "$EFS_SG_ID"
   done
   ```

   マウントターゲットが利用可能になるまで待機します。ステータスを確認します。
   ```
   aws efs describe-mount-targets \
     --region "$AWS_REGION" \
     --file-system-id "$EFS_ID"
   ```

   各サブネット内のマウントターゲットにより、そのサブネット内のノードからEFSへのアクセスが可能になります。
8. Dynamic EngineがEFSボリュームを動的にプロビジョニングできるようにするストレージクラスを作成します。
   1. ストレージクラスの設定ファイルを作成します。
      ## 例
      ```
      cat <<EOF > efs-storageclass.yaml
      apiVersion: storage.k8s.io/v1
      kind: StorageClass
      metadata:
        name: dyn-engine
      provisioner: efs.csi.aws.com
      parameters:
        provisioningMode: efs-ap
        fileSystemId: $EFS_ID
        directoryPerms: "700"
        gidRangeStart: "1000"
        gidRangeEnd: "65534"  
      mountOptions:
        - tls
      reclaimPolicy: Delete
      volumeBindingMode: Immediate

      EOF
      ```
      * provisioningMode: efs-ap: EFSアクセスポイントモードを有効にします。各PersistentVolumeClaimは専用のEFSアクセスポイントによって支えられており、これによりPOSIX所有権が適用され、ボリュームごとにディレクトリへのアクセスが分離されます。
      * fileSystemId: ${EFS\_ID}: この値は、ステップ[6](https://help.qlik.com/talend/ja-JP/dynamic-engine-configuration-guide/Cloud/install-dynamic-engine-eks-with-efs#efs-filesystem-creation)で作成されたEFSファイルシステムIDと一致する必要があります。
      * gidRangeStart: "1000"およびgidRangeEnd: "65534" - このグループIDの範囲は、どのPOSIXグループがEFSボリュームへのアクセスを許可されるかを制御します。Dynamic EngineはデフォルトでグループID 61000を使用して実行されますが、このIDは範囲内(1000～65534)に収まっている必要があります。グループIDがこの範囲外にある場合、ポッドがEFSボリュームにアクセスしようとした際に権限拒否のエラーが発生します。

        情報メモ重要: PodがEFSボリュームのマウントに失敗し、権限拒否のエラーが発生する場合は、Dynamic EngineポッドのグループID(61000)がgidRangeの設定範囲内であることを確認してください。詳細な診断ステップについては、[Amazon EKS上のポッドからEFSボリュームにアクセスする際の権限エラーのトラブルシューティング](https://help.qlik.com/talend/ja-JP/dynamic-engine-configuration-guide/Cloud/troubleshooting-eks-efs-access-permissions "Amazon EKS上で、ポッドがマウントされたEFSボリュームへの読み取りまたは書き込みに失敗した際の、権限拒否エラーを解決します。")を参照してください。

      Kubernetesのストレージクラスに関する詳細については、[AWS EFS](https://kubernetes.io/docs/concepts/storage/storage-classes/#aws-efs)を参照してください。
   2. ストレージクラスを作成します。
      ```
      kubectl apply -f efs-storageclass.yaml
      ```
9. ストレージクラスをテストします。
   1. このテスト用に、PVCとポッドを作成します。
      ## 例

      PVCはdyn-engineストレージクラスを用いてストレージを要求し、ポッドはテストデータを書き込む前にそのボリュームをマウントします。
      ```
      cat <<EOF > efs-pvc-pod.yaml
      ---
      apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: efs-pvc
      spec:
        accessModes:
          - ReadWriteMany
        storageClassName: dyn-engine
        resources:
          requests:
            storage: 100Gi
      ---
      apiVersion: v1
      kind: Pod
      metadata:
        name: efs-app
      spec:
        securityContext:
          fsGroup: 61000
          runAsNonRoot: true
          runAsUser: 61000
          runAsGroup: 61000
          seccompProfile:
            type: RuntimeDefault
        containers:
          - name: app
            image: ghcr.io/talend/kube-base:5.3.0
            command: ["/bin/sh"]
            args: ["-c", "while true; do echo $(date -u) >> /data/out; sleep 5; done"]
            securityContext:
              allowPrivilegeEscalation: false
            volumeMounts:
              - name: persistent-storage
                mountPath: /data
        volumes:
          - name: persistent-storage
            persistentVolumeClaim:
              claimName: efs-pvc
      ```
   2. ファイルを適用します。
      ```
      kubectl apply -f efs-pvc-pod.yaml
      ```

   /data/outファイルが作成され、UTCタイムスタンプが含まれます。

## タスクの結果

EKSクラスターおよびそのEFSストレージクラスは、Dynamic Engineおよびその環境向けに準備が整いました。

## 次のタスク

この手順で構成したEKSクラスターにDynamic Engineおよびその環境をデプロイし、この手順で作成したストレージクラスを指定します。。

詳細な手順については、[Dynamic Engine環境サービス専用のストレージクラスをプロビジョニング](https://help.qlik.com/talend/ja-JP/dynamic-engine-configuration-guide/Cloud/deploy-dynamic-engine-with-specific-storageclass "デフォルトのKubernetesストレージクラスを使用する代わりに、Dynamic Engine環境サービス専用のストレージクラスを設定します。")を参照してください。これらの手順は、Amazon EKS、Google GKE、オンプレミスのKubernetesを含む、サポート対象のすべてのプラットフォームに適用されます。

情報メモヒント:

テストインフラストラクチャをクリーンアップするには、次の順序でリソースを削除します。

1. EKSクラスターを削除します。
   ```
   eksctl delete cluster --name "$EKS_CLUSTER_NAME" --region "$AWS_REGION"
   ```
2. ファイルシステムおよびそのセキュリティグループを削除する前に、EFSマウントターゲットを削除します。
   ```
   MT_IDS=$(aws efs describe-mount-targets \
     --region "$AWS_REGION" \
     --file-system-id "$EFS_ID" \
     --query "MountTargets[].MountTargetId" \
     --output text)
   for mt in $(echo "$MT_IDS" | tr ' ' '\n'); do
     aws efs delete-mount-target --region "$AWS_REGION" --mount-target-id "$mt"
   done
   aws efs delete-file-system --region "$AWS_REGION" --file-system-id "$EFS_ID"
   aws ec2 delete-security-group --region "$AWS_REGION" --group-id "$EFS_SG_ID"
   ```

この情報は参考情報として提供されており、Amazon側の都合により内容が変更される場合があります。EKSおよびEFSの削除に関する詳細については、Amazonのドキュメントを参照してください。