侧边栏壁纸
  • 累计撰写 208 篇文章
  • 累计创建 16 个标签
  • 累计收到 5 条评论

目 录CONTENT

文章目录

AWS-EKS集群部署存储卷 EFS

Wake
2024-02-19 / 0 评论 / 2 点赞 / 1,481 阅读 / 2,103 字

前言:

EKS 中的 Pod 的无状态的,也就是说 Pod 可能被重建,而 Pod 里面的内容则会丢失。当运行在 EKS 中的应用需要持久化保存文件时,我们可以选择 S3 或者 EFS。
S3 做为对象存储,价格便宜使用也比较方便,但需要修改应用的代码。
EFS 价格相比 S3 贵一些,但使用起来更方便,只需要把 EFS 当成一般硬盘使用即可,不需要修改应用代码。

实战步骤:

1.创建 service account(sa)

我们先要在 EKS 中创建一个 service account(sa),Amazon EFS driver 容器会利用 service account 访问 EFS 资源。

在创建 service account 之前,我们先创建赋给 sa 的 IAM policy 和 Role

1-1.创建 IAM Policy

我们用 AWS CLI 来创建 Policy 和 Role,创建“iam-policy-example.json”文件,并粘贴以下内容

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "elasticfilesystem:DescribeAccessPoints",
        "elasticfilesystem:DescribeFileSystems"
      ],
      "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"
        }
      }
    }
  ]
}

说明:这个 policy 提供访问 EFS 的相关权限

保存好之后,运行以下命令创建 Policy

aws iam create-policy \
    --policy-name AmazonEKS_EFS_CSI_Driver_Policy \
    --policy-document file://iam-policy-example.json

说明:

  • policy-name:我们自定义的 policy 名称
  • policy-document:指定本地 policy 文件

创建完成
image-1708326434553

1-2.创建 IAM Role

IAM Role 中包括 IAM policy 和 trust relationship 两部分,我们用 json 文件来定义 trust relationship 部分内容。

创建“trust-policy.json”文件,并粘贴并修改以下内容

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::252557384592:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EE037BDA75FA79D4F8DCE5771A4642E5"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.us-east-1.amazonaws.com/id/EE037BDA75FA79D4F8DCE5771A4642E5:sub": "system:serviceaccount:kube-system:efs-csi-controller-sa"
        }
      }
    }
  ]
}

说明:

  • trust-policy.json 在创建 Role 时,指定“Trust relationships”中的内容
  • 修改“252557384592”为自己的 AWS Account
  • 修改“us-east-1”为自己的 Region
  • 修改“EE037BDA75FA79D4F8DCE5771A4642E5”为自己 EKS 的 OpenID Connect provider URL 中最后的字符串,如下所示

image-1708326794357
然后,运行下列命令创建 IAM Role

aws iam create-role \
  --role-name AmazonEKS_EFS_CSI_DriverRole \
  --assume-role-policy-document file://"trust-policy.json"

说明:

  • role-name:自定义 Role 的名称
  • assume-role-policy-document:指定本地 trust-policy 文件

运行结果
image-1708326889676

最后,运行下列命令为 Role 添加我们在第一步中创建的 Policy

aws iam attach-role-policy \
  --policy-arn arn:aws:iam::252557384592:policy/AmazonEKS_EFS_CSI_Driver_Policy \
  --role-name AmazonEKS_EFS_CSI_DriverRole

说明:

  • policy-arn:指定要绑定的 Policy 的 ARN
  • role-name:指定 Role 名称

运行结果
image-1708329593973

1-3.service account

下面我们在 EKS(K8s)中创建 service account 并指定 IAM Role

创建“efs-service-account.yaml”文件,并粘贴并修改以下内容

apiVersion: v1
kind: ServiceAccount
metadata:
  name: efs-csi-controller-sa
  namespace: kube-system
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::252557384592:role/AmazonEKS_EFS_CSI_DriverRole

说明:我们在 kube-system 空间创建一个 service account “efs-csi-controller-sa”,注意在 annotations 部分指定我们创建的 IAM Role。需要将案例中的role-arn替换中我们实际创建的role

运行以下命令创建 sa

kubectl apply -f efs-service-account.yaml

运行结果
image-1708329727878
查看新建的 sa

kubectl describe sa/efs-csi-controller-sa -n kube-system

image-1708329768985

2. 部署 Amazon EFS CSI driver

在EKS 1.26+以上的版本,EKS的控制台插件已经支持EFS CSI driver插件,我们只需要勾选上就可以在EKS上完成安装了。
image-1708329993390

image-1708330059307

3. 创建 EFS

创建EFS需要记住,在单可用区中,选择可用区1a的作为efs的可用区,不然在pod连接efs的pvc时可能会出现问题。然后网络选择跟EKS一样的vpc,选择内网连接,然后安全组2049端口记得对EKS的内部网络开放权限。
创建好之后,记下 EFS 的 ID “fs-f6f6e842”
image-1708330303360

4.部署测试应用

Amazon EFS driver 和 EFS 准备好之后,下面就可以在 Pod 中使用 EFS 了。
首先,要创建 pv,pvclaim 和 storageclass 三个 K8s 对象。在 pv 中我们把 EFS 引入 K8s 环境。

4-1.创建 pv,pvclaim 和 storageclass

创建 pv.yaml 文件,并粘贴以下内容

apiVersion: v1
kind: PersistentVolume
metadata:
  name: efs-pv
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: efs-sc
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-f6f6e842 #这里需要修改实际的efs ID号

说明:创建 pv “efs-pv”,以 EFS 为存储载体

  • .spec.csi.volumeHandle 中指定我们上面创建的 EFS 的 ID
  • .spec.capacity.storage 中指定使用空间为 5G,但 EFS 并没有容量限制。指定这个参数只是满足 K8s 本身的要求

创建 claim.yaml 文件,并粘贴以下内容

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 5Gi

说明:创建 PersistentVolumeClaim,在下面测试 Pod 中我们指定的是 PersistentVolumeClaim 并不是 PV

最后,创建 storageclass.yaml 文件,并粘贴以下内容

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com

说明:storageclass,把 pv 和 PersistentVolumeClaim 关联到一起
运行以下命令创建以上存储相关对象

kubectl apply -f storageclass.yaml
kubectl apply -f pv.yaml
kubectl apply -f claim.yaml

运行结果
image-1708330596365

运行以下命令,查看 pv 创建进度,当 STATUS 为 Bound 时,ctl+c 退出

kubectl get pv -w

image-1708330629196

4-2.部署应用

创建 pod1.yaml 文件,并粘贴以下内容

apiVersion: v1
kind: Pod
metadata:
  name: app1
spec:
  containers:
  - name: app1
    image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo $(date -u) >> /data/out1.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: efs-claim

说明:

  • 我们用 busybox 生成容器,并在容器启动后每隔 5 秒,输出当前时间到/data/out1.txt 文件中
  • 我们定义了底层为 persistentVolumeClaim 的 volume,并把这个 volume 映射到容器的/data 路径下,这样此路径下的文件就保存到了 EFS 上
    我们再创建 pod2.yaml 文件,并粘贴以下内容
apiVersion: v1
kind: Pod
metadata:
  name: app2
spec:
  containers:
  - name: app2
    image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo $(date -u) >> /data/out2.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: efs-claim

说明:

  • Pod2 与 Pod1 的不同只是容器的名称不同和输出文件的名子不同
  • 通过 volume,我们把同样的 EFS 也 mount 到了 Pod2 中
    运行下列命令生成 Pod1 和 Pod2
kubectl apply -f pod1.yaml
kubectl apply -f pod2.yaml

运行结果
image-1708330763104

注意:
image-1708330810322
如果 pods 长时间(2-3 分钟)处于“ContainerCreating”状态,那我们要检查一下,是不是有问题。

运行以下语句查看 Pod

kubectl describe pod app1

运行结果

Warning  FailedMount  31s kubelet Unable to attach or mount volumes: unmounted volumes=[persistent-storage], unattached volumes=[persistent-storage kube-api-access-m4mkq]: timed out waiting for the condition

image-1708330854710
说明:如果出现这种情况,那就是说明 EKS 到 EFS 的网络不通。
那就需要在efs里面用的安全组中将2049端口给EKS的内部网络放行

我们的 EFS 的网络如下,在同样的子网内有 mount point,但 Sg 为 sg-1ef4085c
image-1708330995166
在 VPC 或者 EC2 界面中,选择 Security Groups,勾选 EFS 所在的 SG “sg-1ef4085c”,点击“Edit inbound rules”
image-1708331141220
这里可以放行EKS的安全组,也可以给EKS的内部网络,自行选择即可。
再次查看 Pod1,Pod2,可以看到已经正常运行了
image-1708331188190

运行以下命令,可以在 app1 容器中看到/data/out1.txt 和//data/out2.txt 文件中的内容

kubectl exec -ti app1 -- tail /data/out1.txt
kubectl exec -ti app1 -- tail /data/out2.txt

image-1708331487730
说明:EFS 同时映射到了 app1 和 app2 的容器内部,所以在 app1 容器里就可以看到 out2.txt 文件.EKS集群部署EFS卷就完成了。

2

评论区