0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ROSA で AWS EFS CSI Driver Operator を使う

Last updated at Posted at 2024-10-10

0.前提

ROSA HCP クラスターは、こちらの Qiita記事にある方法で作成済みの環境を使用します。

作成された ROSA HCP クラスターを使って、Red Hat の Black Belt チームで作成されたこちらの手順と、KB でリリースされている こちらの情報を参照しながら作成しました。

1.環境変数の準備

ROSA Cluster に oc login 後、

oc login <API Server Endpoint> --username cluster-admin --password <password>

rosa login

は済ましておいてください。

以下を実行してセットアップに必要な環境変数を準備します。

AWS_REGION をセットします。ap-northeast-1 (東京リージョン) にしてますが、環境に合わせて変更してください。

export AWS_REGION="ap-northeast-1"

ClUSTER_NAME は rosa cluster が環境内に一つの時だけ正しく値が取得できるようになっています。

export CLUSTER_NAME=$(rosa list clusters -o json | jq '.[0].name' | sed 's/"//g') 
export OIDC_PROVIDER=$(oc get authentication.config.openshift.io cluster -o json \
| jq -r .spec.serviceAccountIssuer| sed -e "s/^https:\/\///")
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export SCRATCH_DIR=/tmp/scratch
export AWS_PAGER=""
mkdir -p $SCRATCH_DIR

2. IAM Policy の準備

(1) IAM Policy の元ネタになる jsonファイルを作成します。

cat << EOF > $SCRATCH_DIR/efs-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "elasticfilesystem:DescribeAccessPoints",
        "elasticfilesystem:DescribeFileSystems",
        "elasticfilesystem:DescribeMountTargets",
        "elasticfilesystem:TagResource",
        "ec2:DescribeAvailabilityZones"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "elasticfilesystem:CreateAccessPoint"
      ],
      "Resource": "*",
      "Condition": {
        "StringLike": {
          "aws:RequestTag/efs.csi.aws.com/cluster": "true"
        }
      }
    },
    {
      "Effect": "Allow",
      "Action": "elasticfilesystem:DeleteAccessPoint",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:ResourceTag/efs.csi.aws.com/cluster": "true"
        }
      }
    }
  ]
}
EOF

(2) json ファイルから IAM Policy を作成します。

POLICY=$(aws iam create-policy --policy-name "${CLUSTER_NAME}-rosa-efs-csi" \
   --policy-document file://$SCRATCH_DIR/efs-policy.json \
   --query 'Policy.Arn' --output text) || \
   POLICY=$(aws iam list-policies \
   --query 'Policies[?PolicyName==`rosa-efs-csi`].Arn' \
   --output text)
echo $POLICY

(3) Trust Policy を作成します。
この Policy は、この後作成する IAM Role の中で使用します。

cat <<EOF > $SCRATCH_DIR/TrustPolicy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${OIDC_PROVIDER}:sub": [
            "system:serviceaccount:openshift-cluster-csi-drivers:aws-efs-csi-driver-operator",
            "system:serviceaccount:openshift-cluster-csi-drivers:aws-efs-csi-driver-controller-sa"
          ]
        }
      }
    }
  ]
}
EOF

(4) EFS CSI Driver Operator に使う IAM Role を (3)で作成した Trust Policy を使って作成します。

ROLE=$(aws iam create-role \
  --role-name "${CLUSTER_NAME}-aws-efs-csi-operator" \
  --assume-role-policy-document file://$SCRATCH_DIR/TrustPolicy.json \
  --query "Role.Arn" --output text)
echo $ROLE

(5) 上記で作成した IAM RoleIAM Policy をアタッチします。

aws iam attach-role-policy \
   --role-name "${CLUSTER_NAME}-aws-efs-csi-operator" \
   --policy-arn $POLICY

3. AWS EFS CSI Driver Operator の インストール

EFS CSI Driver Operator をインストールします。

image.png

Operator Hub の GUIからインストールしても良いのですが、この手順では CLIEFS CSI Driver Operator をインストールしてしまいます。(GUIインストールでも一部、CLI作業が発生します)

(1) AWS EFS CSI Driver Operator で使用する IAM RoleARN を入れた Secretを作成します。

cat << EOF | oc apply -f -
apiVersion: v1
kind: Secret
metadata:
 name: aws-efs-cloud-credentials
 namespace: openshift-cluster-csi-drivers
stringData:
  credentials: |-
    [default]
    role_arn = $ROLE
    web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
EOF

(2) AWS EFS CSI Driver Operator をインストールします。

cat <<EOF | oc create -f -
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  generateName: openshift-cluster-csi-drivers-
  namespace: openshift-cluster-csi-drivers
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  labels:
    operators.coreos.com/aws-efs-csi-driver-operator.openshift-cluster-csi-drivers: ""
  name: aws-efs-csi-driver-operator
  namespace: openshift-cluster-csi-drivers
spec:
  channel: stable
  installPlanApproval: Automatic
  name: aws-efs-csi-driver-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace
EOF

(3) Operator のインストールが完了するまで待ちます。

watch oc get deployment aws-efs-csi-driver-operator -n openshift-cluster-csi-drivers

以下でも確認できます。

oc get pods -n openshift-cluster-csi-drivers | grep efs

(4) ClusterCSIDriver CRD を作成します。

これで各 NodeCSI DriverPod が作成されます。

cat <<EOF | oc apply -f -
apiVersion: operator.openshift.io/v1
kind: ClusterCSIDriver
metadata:
    name: efs.csi.aws.com
spec:
  managementState: Managed
EOF

(5) CSI Driver のインストールの完了を待ちます。

watch oc get daemonset aws-efs-csi-driver-node -n openshift-cluster-csi-drivers

4. EFS の作成の準備

(1) 以下のコマンドを実行して環境変数を準備します。

NODE=$(oc get nodes --selector=node-role.kubernetes.io/worker \
  -o jsonpath='{.items[0].metadata.name}')
VPC=$(aws ec2 describe-instances \
  --filters "Name=private-dns-name,Values=$NODE" \
  --query 'Reservations[*].Instances[*].{VpcId:VpcId}' \
  --region $AWS_REGION \
  | jq -r '.[0][0].VpcId')
CIDR=$(aws ec2 describe-vpcs \
  --filters "Name=vpc-id,Values=$VPC" \
  --query 'Vpcs[*].CidrBlock' \
  --region $AWS_REGION \
  | jq -r '.[0]')
SG=$(aws ec2 describe-instances --filters \
  "Name=private-dns-name,Values=$NODE" \
  --query 'Reservations[*].Instances[*].{SecurityGroups:SecurityGroups}' \
  --region $AWS_REGION \
  | jq -r '.[0][0].SecurityGroups[0].GroupId')
echo "CIDR - $CIDR,  SG - $SG"

(2) EFS volume をマウントできるように、Security Group を Update します。

この Security GroupROSAWorker Node 用の Security Group で、ROSAVPC に割り当てたアドレスレンジ($CIDR) から、EFSTCP Port 2049 へのアクセスを可能にするものです。

aws ec2 authorize-security-group-ingress \
 --group-id $SG \
 --protocol tcp \
 --port 2049 \
 --cidr $CIDR | jq .

5. EFS を作成する。

EFS には、RegionalSingle AZ の2種類の EFS があります。

Regional は、AZ障害に対応できます。一方、Single AZは、AZ障害に対応できませんが、コストを安く済ます事ができます。テスト環境やデータアナリシスなどで一時的なデータを吐き出すのはこちらが良いでしょう。

この手順では、EFSを使用するStorageClass は一つしか作らないので、どちらか一つだけを選択して作成してください。

この手順では Cluster がインストールされている Private Subnet を

A) Regional の EFS を作成する場合

(1) EFS を作成します。

EFS=$(aws efs create-file-system --creation-token efs-token-1 \
   --region ${AWS_REGION} \
   --encrypted | jq -r '.FileSystemId')
echo $EFS

AWS Console の EFS の項目には以下のような FileSystem が作成されます。(Availability ZoneRegional になっている事に注目します)
image.png

(2) EFSMount Targetを作成します。Mount Target Id を取得して、$MOUNT_TARGET に格納します。

for  SUBNET in $(rosa list machinepools -c $CLUSTER_NAME  -o json | jq  -r '.[].subnet'); do \
    MOUNT_TARGET=$(aws efs create-mount-target --file-system-id $EFS \
       --subnet-id $SUBNET --security-groups $SG \
       --region $AWS_REGION \
       | jq -r '.MountTargetId'); \
    echo $MOUNT_TARGET; \
 done

この例では、各 Zone 毎に一つの Mount Target を作成しています。こちらによると、各AZ毎に作成できる Mount Target は最大一つです)

B) Single AZ の EFS を作成する場合

(1) EFS をマウントするための AZ を一つ選びます。

ここでは、サブネットを適当に一つ取り出して、そのサブネットの AZEFS に接続する AZ とする事にします。

SUBNET=$(rosa list machinepools -c $CLUSTER_NAME  -o json | jq  -r '.[0].subnet')
AWS_ZONE=$(aws ec2 describe-subnets --filters Name=subnet-id,Values=$SUBNET \
  --region $AWS_REGION | jq -r '.Subnets[0].AvailabilityZone')

(2) EFS を作成します。
AWS Console の EFS の項目には以下のような FileSystem が作成されます。(Availability Zoneがこの例ではap-northeast-1c で、一つの AZ だけになっている事に注目します)

EFS=$(aws efs create-file-system --creation-token efs-token-1 \
   --availability-zone-name $AWS_ZONE \
   --region $AWS_REGION \
   --encrypted | jq -r '.FileSystemId')
echo $EFS

image.png

(3) EFSMount Targetを作成します。 Mount Target Id を取得して、$MOUNT_TARGET に格納します。

MOUNT_TARGET=$(aws efs create-mount-target --file-system-id $EFS \
  --subnet-id $SUBNET --security-groups $SG \
  --region $AWS_REGION \
  | jq -r '.MountTargetId')
echo $MOUNT_TARGET

6. EFS 用の Storage Class の作成

EFS Volume 用の StorageClass を作成します。
この StorageClass を使って EFS Volume が作成できるようになります。

cat <<EOF | oc apply -f -
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  fileSystemId: $EFS
  directoryPerms: "700"
  gidRangeStart: "1000"
  gidRangeEnd: "2000"
  basePath: "/dynamic_provisioning"
EOF

7. 実際に Pod をデプロイして EFS Volume の動作を確認

(1) 実験用の namespace を作成します。

oc new-project efs-demo

(2) PVC を作成します。
中では、先ほど作成した EFS Volume 用の StorageClass を使用しています。

cat <<EOF | oc apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-efs-volume
spec:
  storageClassName: efs-sc
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
EOF

(3) PVCが作成されるのを待ちます。2分程度で、 RWX の PVC のデプロイが完了するはずです。

watch oc get pvc

(4) EFS Volume にメッセージを書き込むテスト用の Pod を作成します。

5秒起きに、作成した EFS Volume 上のファイルに hello efs と書き出します。

cat <<EOF | oc apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: test-efs
spec:
 volumes:
   - name: efs-storage-vol
     persistentVolumeClaim:
       claimName: pvc-efs-volume
 containers:
   - name: test-efs
     image: centos:latest
     command: [ "/bin/bash", "-c", "--" ]
     args: [ "while true; do echo 'hello efs' | tee -a /mnt/efs-data/verify-efs && sleep 5; done;" ]
     volumeMounts:
       - mountPath: "/mnt/efs-data"
         name: efs-storage-vol
EOF

(5) Test 用の Pod がデプロイされるのを待ちます。

watch oc get pod test-efs

(6) 次に、EFS Volume 上のファイルを読み込む別のPodを作成します。

先ほど作成した EFS Volume 上のファイルを tail します。

cat <<EOF | oc apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: test-efs-read
spec:
 volumes:
   - name: efs-storage-vol
     persistentVolumeClaim:
       claimName: pvc-efs-volume
 containers:
   - name: test-efs-read
     image: centos:latest
     command: [ "/bin/bash", "-c", "--" ]
     args: [ "tail -f /mnt/efs-data/verify-efs" ]
     volumeMounts:
       - mountPath: "/mnt/efs-data"
         name: efs-storage-vol
EOF

(7) ファイルをtail している Pod のログを確認します。

tail は標準出力に吐かれているので、oc logstail の結果が確認できます。

oc logs test-efs-read

以下のような出力が確認できるはずです。

hello efs
hello efs
hello efs
hello efs
hello efs
hello efs
hello efs
hello efs
hello efs
hello efs

8. 環境の削除

(1) デプロイした Test 用の Podを削除します。

oc delete pod -n efs-demo test-efs test-efs-read

(2) デプロイした EFS Volume を削除します。

oc delete -n efs-demo pvc pvc-efs-volume

(3) 作成した Namespace を削除します。

oc delete project efs-demo

(4) 作成した Storage Class を削除します。

oc delete storageclass efs-sc

(5) EFS File System を削除します。

Mount Target を削除します。

for MOUNT_TARGET in $(aws efs describe-mount-targets --file-system-id $EFS \
	--region $AWS_REGION \
	 | jq -r '.MountTargets[].MountTargetId'); do \
	echo $MOUNT_TARGET; \
	aws efs delete-mount-target --mount-target-id $MOUNT_TARGET --region $AWS_REGION; \
done

FileSystem を削除します。(Mount Target を削除してから数十秒時間を置く必要があります)

aws efs delete-file-system --file-system-id $EFS --region $AWS_REGION

(6) IAM Policy と IAM Role をデタッチします。
アタッチしたままだと削除できないので、デタッチします。

aws iam detach-role-policy \
   --role-name "${CLUSTER_NAME}-aws-efs-csi-operator" \
   --policy-arn $POLICY

(7) 作成したIAM Role を削除します。

aws iam delete-role --role-name \
   ${CLUSTER_NAME}-aws-efs-csi-operator

(8) 作成した IAM Policy を削除します。

aws iam delete-policy --policy-arn \
   $POLICY

9.[おまけ] NodeからEFSへのアクセス経路を少し深掘り

Regional の EFS を使用した場合に、各 Node から EFS がどのように見えるのか確認してみます。

各AZ の Compute Node 上から EFS の DNS 名を解決するとどのような IPが返ってくるか確認してみます。

環境の EFS の DNS 名は、AWS Console から確認するとfs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.comとなっていました。これを各 Node 上で名前解決してみます。
image.png

尚、この手順の5番で作成した各 AZ (の Private Subnet) の Mount Target は以下の通りで、各AZ内の Private IP が割り振られています。

image.png

各 AZに配置された、Node で debug pod を起動して EFS の DNS名fs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.comを解決してみます。

$ oc get nodes
NAME                                            STATUS   ROLES    AGE   VERSION
ip-10-0-1-244.ap-northeast-1.compute.internal   Ready    worker   13m   v1.29.6+aba1e8d
ip-10-0-2-214.ap-northeast-1.compute.internal   Ready    worker   23m   v1.29.6+aba1e8d
ip-10-0-3-103.ap-northeast-1.compute.internal   Ready    worker   22m   v1.29.6+aba1e8d
$

$ oc debug node/ip-10-0-2-214.ap-northeast-1.compute.internal
Temporary namespace openshift-debug-47hcg is created for debugging node...
Starting pod/ip-10-0-2-214ap-northeast-1computeinternal-debug-ddjdm ...
To use host binaries, run `chroot /host`
Pod IP: 10.0.2.214
If you don't see a command prompt, try pressing enter.
sh-5.1# dig +short fs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.com
10.0.2.133
sh-5.1#

$ oc debug node/ip-10-0-1-244.ap-northeast-1.compute.internal
Temporary namespace openshift-debug-94mp9 is created for debugging node...
Starting pod/ip-10-0-1-244ap-northeast-1computeinternal-debug-r5gft ...
To use host binaries, run `chroot /host`
Pod IP: 10.0.1.244
If you don't see a command prompt, try pressing enter.
sh-5.1# dig +short fs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.com
10.0.1.154
sh-5.1# 

$ oc debug node/ip-10-0-3-103.ap-northeast-1.compute.internal
Temporary namespace openshift-debug-mnzsh is created for debugging node...
Starting pod/ip-10-0-3-103ap-northeast-1computeinternal-debug-l4n7p ...
To use host binaries, run `chroot /host`                
If you don't see a command prompt, try pressing enter.
sh-5.1# dig +short fs-01e64ba4bc876e58c.efs.ap-northeast-1.amazonaws.com
10.0.3.72
sh-5.1# 

同じDNS名が、それぞれのAZにある Mount Target のIP に解決されていました。

各 Nodeからの EFS へのアクセスは、各 Node が存在する AZ 内の Mount Target (ENI)のIP経由でアクセスが行われるようです。

環境の構成を図にまとめると以下の通りです。

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?