在 AWS 使用 Kubernetes 的持久化存储

挂载 EBS 磁盘

  在 AWS 中,我们可以将 EBS 磁盘挂载到 Kubernetes 的 Pod 中。由于 EBS 是云磁盘,所以就算 Pod 被调度到其它宿主机,也仍然可以访问 EBS 中的数据。
  在挂载磁盘之前,需要先创建 EBS 磁盘:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ aws ec2 create-volume \
--size 20 \
--region ap-northeast-1 \
--availability-zone ap-northeast-1b \
--volume-type gp2
{
"AvailabilityZone": "ap-northeast-1b",
"Encrypted": false,
"VolumeType": "gp2",
"VolumeId": "vol-0988ae4c8ead9dece",
"State": "creating",
"Iops": 100,
"SnapshotId": "",
"CreateTime": "2018-01-12T07:16:01.002Z",
"Size": 20
}

  注意,如果 Kubernetes 集群是通过 kops 1.8.0 版本安装的,那么在挂载之前,需要先为磁盘打上标签,否则会挂载失败:

1
2
3
4
5
$ export NAME=cluster.k8s.local # 集群的名称
$ VOLUME_ID = vol-0988ae4c8ead9dece
$ aws ec2 create-tags \
--resources ${VOLUME_ID} \
--tags Key=KubernetesCluster,Value=${NAME}

  挂载磁盘很简单,例如,我们可以将磁盘挂载到 Nginx Pod 的/data目录下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ cat nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- name: aws-ebs-volumes
mountPath: /data
volumes:
- name: aws-ebs-volumes
awsElasticBlockStore:
volumeID: vol-0988ae4c8ead9dece
$ kubectl apply -f nginx-pod.yaml

  通过这种方式挂载磁盘,有几个问题需要注意,首先,要保证 EBS 磁盘和 EC2 实例在同一个 AZ 里面,其次,EBS 磁盘只能挂载到一个 EC2 实例上。

自动管理 EBS 磁盘

  上文介绍的挂载磁盘方式比较落后:

  • 每次挂载 EBS 磁盘之前,都需要手动创建 EBS 磁盘。
  • 当 Pod 被删除之后,还需要手动删除 EBS 磁盘。

  更好的做法是使用 Kubernetes 提供的 StorageClass 和 PersistentVolumeClaim 来帮我们自动管理磁盘。其中,StorageClass 可以理解为存储模板,例如,我们可以定制一个叫做standard的模板,规定 EBS 磁盘类型为gp2,AZ 为ap-northeast-1b,回收策略为Delete

1
2
3
4
5
6
7
8
9
10
11
$ cat standard-storageclass.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
zone: ap-northeast-1b
reclaimPolicy: Delete # 在删除 Pod 的同时,也删除 EBS 磁盘
$ kubectl apply -f standard-storageclass.yaml

  回收策略除了可以是Delete之外,也可以是Retain,这表示当删除 PersistentVolumeClaim 时,仍然保留 EBS 磁盘。


  有了模板之后,就可以根据这个模板,向 Kubernetes 申请磁盘。可以使用 PersistentVolumeClaim 向 Kubernetes 申请磁盘,例如,可以申请一个 20GB 的磁盘:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ cat nginx-pv-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-pv-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: standard
$ kubectl apply -f nginx-pv-claim.yaml

  执行这个命令之后,在 AWS 后台就会自动创建一个 20GB 的磁盘。接着就可以将磁盘挂载到 Pod 上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ cat nginx-pv-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pv
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- name: nginx-pv-claim
mountPath: /data
volumes:
- name: nginx-pv-claim
persistentVolumeClaim:
claimName: nginx-pv-claim
$ kubectl apply -f nginx-pv-pod.yaml

  删除磁盘也很容易,在删除 Pod 之后,再删除 PersistentVolumeClaim 就可以了:

1
2
3
4
$ kubectl delete -f nginx-pv-pod.yaml
pod "nginx-pv" deleted
$ kubectl delete -f nginx-pv-claim.yaml
persistentvolumeclaim "nginx-pv-claim" deleted

参考资料