前言:
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 文件
创建完成
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 中最后的字符串,如下所示
然后,运行下列命令创建 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 文件
运行结果
最后,运行下列命令为 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 名称
运行结果
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
运行结果
查看新建的 sa
kubectl describe sa/efs-csi-controller-sa -n kube-system
2. 部署 Amazon EFS CSI driver
在EKS 1.26+以上的版本,EKS的控制台插件已经支持EFS CSI driver插件,我们只需要勾选上就可以在EKS上完成安装了。
3. 创建 EFS
创建EFS需要记住,在单可用区中,选择可用区1a的作为efs的可用区,不然在pod连接efs的pvc时可能会出现问题。然后网络选择跟EKS一样的vpc,选择内网连接,然后安全组2049端口记得对EKS的内部网络开放权限。
创建好之后,记下 EFS 的 ID “fs-f6f6e842”
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
运行结果
运行以下命令,查看 pv 创建进度,当 STATUS 为 Bound 时,ctl+c 退出
kubectl get pv -w
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
运行结果
注意:
如果 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
说明:如果出现这种情况,那就是说明 EKS 到 EFS 的网络不通。
那就需要在efs里面用的安全组中将2049端口给EKS的内部网络放行
我们的 EFS 的网络如下,在同样的子网内有 mount point,但 Sg 为 sg-1ef4085c
在 VPC 或者 EC2 界面中,选择 Security Groups,勾选 EFS 所在的 SG “sg-1ef4085c”,点击“Edit inbound rules”
这里可以放行EKS的安全组,也可以给EKS的内部网络,自行选择即可。
再次查看 Pod1,Pod2,可以看到已经正常运行了
运行以下命令,可以在 app1 容器中看到/data/out1.txt 和//data/out2.txt 文件中的内容
kubectl exec -ti app1 -- tail /data/out1.txt
kubectl exec -ti app1 -- tail /data/out2.txt
说明:EFS 同时映射到了 app1 和 app2 的容器内部,所以在 app1 容器里就可以看到 out2.txt 文件.EKS集群部署EFS卷就完成了。
评论区