EKS Auto Mode中的 StorageClass 定义了当应用程序请求持久存储时,EBS 卷如何自动创建。通过配置 StorageClass,我们可以为 EBS 卷指定默认设置,包括卷类型、加密、IOPS 和其他存储参数。我们还可以配置 StorageClass 使用 AWS KMS 密钥进行加密管理。
catalog 和 order 微服务各自使用在集群中单独的pod中运行的SQL数据库。
catalog
微服务使用在集群中的pod中运行的MySQL数据库。我们可以检查MySQL数据库pod以查看其当前卷配置:
kubectl describe statefulset catalog-mysql
我们应该看到类似于以下的输出:
我们可以得出以下观察结果:
StatefulSet
。mysql
容器,带有类型为emptyDir
的data
卷。同样,_orders_微服务使用PostgreSQL数据库。我们可以检查PostgreSQL数据库pod以查看其当前卷配置:
kubectl describe statefulset orders-postgresql
我们应该看到类似于以下的输出:
我们可以看到PostgreSQL数据库被部署为具有单个副本的StatefulSet
,并使用类型为emptyDir
的data
卷。
emptyDir
的临时性质当Pod被分配到节点时,首先创建emptyDir
卷,并且只要该Pod在该节点上运行,该卷就存在。顾名思义,emptyDir
卷最初是空的。Pod中的所有容器都可以读取和写入emptyDir
卷中的相同文件,尽管该卷可以在每个容器中挂载在相同或不同的路径上。当pod因任何原因从节点中移除时,emptyDir
中的数据将被永久删除。因此,emptyDir
不适合我们的SQL数据库。
我们可以通过在PostgreSQL容器内启动shell会话并创建测试文件来演示emptyDir
的临时性质。之后,我们将删除在StatefulSet中运行的pod。因为pod使用的是emptyDir
而不是PV,所以文件在pod重启后将不会保留。
➤ 首先,让我们在PostgreSQL容器内运行一个命令,在/data/pgdata
路径(PostgreSQL保存数据库文件的地方)创建一个文件:
kubectl exec orders-postgresql-0 -- bash -c "echo 123 > /data/pgdata/test.txt"
➤ 现在,让我们验证我们的test.txt
文件是否已在/data/pgdata
目录中创建:
kubectl exec orders-postgresql-0 -- cat /data/pgdata/test.txt
我们应该看到我们创建的文件内容:
➤ 现在,让我们删除当前的orders-postgresql
pod,强制StatefulSet
控制器自动重新创建一个新的orders-postgresql
pod:
kubectl delete pod orders-postgresql-0
➤ 等待pod重新创建:
kubectl wait --for=condition=Ready pod orders-postgresql-0 --timeout=30s
几秒钟后,我们应该看到:
➤ 验证pod是否正在运行:
kubectl get pod orders-postgresql-0
输出应类似于以下内容:
~/kongpingfan > kubectl get pod orders-postgresql-0 kube casual-indie-sheepdog
NAME READY STATUS RESTARTS AGE
orders-postgresql-0 1/1 Running 0 35s
➤ 检查/data/pgdata
目录中是否存在test.txt
:
kubectl exec orders-postgresql-0 -- cat /data/pgdata/test.txt
输出如下:
cat: /data/pgdata/test.txt: No such file or directory
command terminated with exit code 1
我们可以看到,由于emptyDir
卷是临时的,test.txt
文件不再存在。
接下来,我们定义一个默认的StorageClass
,并使用它为_catalog_ MySQL数据库创建持久卷。
➤ 首先,按如下方式创建 KMS 密钥:
KEY_ID=$(aws kms create-key --query 'KeyMetadata.KeyId' --output text)
KEY_ARN=$(aws kms describe-key --key-id $KEY_ID --query 'KeyMetadata.Arn' --output text)
echo "Key Id:" $KEY_ID
echo "Key Arn:" $KEY_ARN
➤ 接下来,为 KMS 密钥创建一个 IAM 资源策略 JSON 文档,该文档允许在 EC2 托管实例上运行的 CSI 服务assume该角色,以加密和解密写入 EBS 卷的数据:
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
AWS_REGION=$(aws configure list | grep region | awk '{print $2}')
cat >key-policy.json <<EOF
{
"Version": "2012-10-17",
"Id": "key-auto-policy-3",
"Statement": [
{
"Sid": "iam-kms",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${AWS_ACCOUNT_ID}:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "ec2-kms",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:CreateGrant",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:CallerAccount": "${AWS_ACCOUNT_ID}",
"kms:ViaService": "ec2.$AWS_REGION.amazonaws.com"
}
}
}
]
}
EOF
➤ 将此策略文档附加到 KMS 密钥:
aws kms put-key-policy --key-id $KEY_ID --policy file://key-policy.json
➤ 最后,使用 KMS 密钥创建一个新的存储类:
cat >ebs-kms-sc.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: eks-auto-ebs-kms-sc
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.eks.amazonaws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
type: gp3
encrypted: "true"
kmsKeyId: ${KEY_ID}
EOF
kubectl apply -f ebs-kms-sc.yaml
➤ 检查我们刚刚创建的 StorageClass
:
kubectl describe storageclass eks-auto-ebs-kms-sc
这应该产生以下输出:
eks-auto-ebs-kms-sc
被配置为默认存储类。ebs.csi.eks.amazonaws.com
。gp3
(默认为 3000 IOPS)。Delete
,这意味着当关联的 PVC 被删除时,这将导致 Kubernetes 中的 PV 对象以及外部基础设施中的相关存储资产都被删除。catalog
MySQL 数据库 pod现在我们已经有了一个默认的 StorageClass
,让我们更新 catalog
服务以使用它。由于 StatefulSet 的许多字段(包括 volumeClaimTemplates)无法修改,我们将删除 catalog
组件,然后重新安装它,以便我们可以将卷类型从 emptyDir 更新为持久卷。
➤ 首先,删除当前的 catalog
statefulset:
kubectl delete statefulset catalog-mysql
创建一个新的yaml catalog-mysql.yaml
:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: catalog-mysql
labels:
helm.sh/chart: catalog-1.0.0
app.kubernetes.io/name: catalog
app.kubernetes.io/instance: catalog
app.kubernetes.io/component: mysql
app.kubernetes.io/owner: retail-store-sample
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
serviceName: catalog-mysql
selector:
matchLabels:
app.kubernetes.io/name: catalog
app.kubernetes.io/instance: catalog
app.kubernetes.io/component: mysql
app.kubernetes.io/owner: retail-store-sample
template:
metadata:
labels:
app.kubernetes.io/name: catalog
app.kubernetes.io/instance: catalog
app.kubernetes.io/component: mysql
app.kubernetes.io/owner: retail-store-sample
spec:
containers:
- name: mysql
image: "public.ecr.aws/docker/library/mysql:8.0"
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_ROOT_PASSWORD
value: my-secret-pw
- name: MYSQL_DATABASE
value: catalog
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: catalog-db
key: username # 根据实例secret中的keys进行替换,因为这个retail app在github上有几个版本
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: catalog-db
key: password # 根据实例secret中的keys进行替换,因为这个retail app在github上有几个版本
volumeMounts:
- name: data
mountPath: /var/lib/mysql
ports:
- name: mysql
containerPort: 3306
protocol: TCP
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 30Gi
部署:
kubectl apply -f catalog-mysql.yaml
重新启动的 catalog
服务现在应该有一个关联的 PersistentVolumeClaim
。
➤ 我们可以通过运行以下命令查看:
kubectl describe statefulset catalog-mysql
这次输出显示:
让我们检查 PVC 资源。要列出所有 PVC,请使用:
kubectl get pvc
我们应该看到:
这是为 MySQL 数据库创建的 PVC。
➤ 使用以下命令检查它:
kubectl describe pvc data-catalog-mysql-0
产生以下输出:
从输出中可以看到,PVC 绑定到特定的 PV,容量为 30Gi
catalog
MySQL 数据库的 EBS 卷是否已正确创建按如下方式获取底层 Amazon EBS 卷 ID:
MYSQL_PV_NAME=$(kubectl get pvc data-catalog-mysql-0 -o jsonpath="{.spec.volumeName}")
MYSQL_EBS_VOL_ID=$(kubectl get pv $MYSQL_PV_NAME -o jsonpath="{.spec.csi.volumeHandle}")
echo EBS Volume ID: $MYSQL_EBS_VOL_ID
显示 EBS 卷的详细信息:
aws ec2 describe-volumes --volume-ids $MYSQL_EBS_VOL_ID
注意输出的以下部分,证明已启用 KMS 加密并使用了正确的密钥:
~/kongpingfan > aws ec2 describe-volumes --volume-ids $MYSQL_EBS_VOL_ID |jq
{
"Volumes": [
{
"Iops": 3000,
"Tags": [
{
"Key": "kubernetes.io/created-for/pvc/namespace",
"Value": "default"
},
{
"Key": "CSIVolumeName",
"Value": "pvc-92946947-aa1c-4927-bba6-f238b63cbb91"
},
{
"Key": "Name",
"Value": "casual-indie-sheepdog-dynamic-pvc-92946947-aa1c-4927-bba6-f238b63cbb91"
},
{
"Key": "kubernetes.io/created-for/pvc/name",
"Value": "data-catalog-mysql-0"
},
{
"Key": "ebs.csi.eks.amazonaws.com/cluster",
"Value": "true"
},
{
"Key": "eks:eks-cluster-name",
"Value": "casual-indie-sheepdog"
},
{
"Key": "kubernetes.io/cluster/casual-indie-sheepdog",
"Value": "owned"
},
{
"Key": "KubernetesCluster",
"Value": "casual-indie-sheepdog"
},
{
"Key": "kubernetes.io/created-for/pv/name",
"Value": "pvc-92946947-aa1c-4927-bba6-f238b63cbb91"
}
],
"VolumeType": "gp3",
"MultiAttachEnabled": false,
"Throughput": 125,
"Operator": {
"Managed": false
},
"VolumeId": "vol-0d082c7bdae57b1bf",
"Size": 30,
"SnapshotId": "",
"AvailabilityZone": "us-west-2b",
"State": "in-use",
"CreateTime": "2025-02-28T11:50:08.586000+00:00",
"Attachments": [
{
"DeleteOnTermination": false,
"VolumeId": "vol-0d082c7bdae57b1bf",
"InstanceId": "i-0b3f9eb336642e97f",
"Device": "/dev/xvdaa",
"State": "attached",
"AttachTime": "2025-02-28T11:50:12+00:00"
}
],
"Encrypted": true,
"KmsKeyId": "arn:aws:kms:us-west-2:145197526627:key/c9355090-957a-4157-89ce-da820bc9827d"
}
]
}
在本节中,我们执行了以下步骤:
StorageClass
,配置为使用此密钥进行加密,并使用标准的 gp3
卷。catalog
服务的配置,以使用默认的 StorageClass
创建持久卷。