为了管理存储,Kubernetes提供了Secret用于管理敏感信息,ConfigMap存储配置,Volume、PV、PVC、StorageClass等用来管理存储卷。
一、Secret
Secret有三种类型:
- Service Account :用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的
/run/secrets/kubernetes.io/serviceaccount
目录中; - Opaque :base64编码格式的Secret,用来存储密码、密钥等;
- kubernetes.io/dockerconfigjson :用来存储私有docker registry的认证信息。
Opaque Secret
Opaque类型的数据是一个map类型,要求value是base64编码格式:
获取base64
1 2 3 4 5 |
$ echo -n "admin" | base64 YWRtaW4= $ echo -n "1f2d1e2e67df" | base64 MWYyZDFlMmU2N2Rm |
创建Opaque Secret
1 2 3 4 5 6 7 8 9 10 11 12 |
kubectl create -f secrets.yaml # secrets.yaml apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: password: MWYyZDFlMmU2N2Rm username: YWRtaW4= |
使用secret的方式有两种:
- 以Volume方式
- 以环境变量方式
将Secret挂载到Volume中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
apiVersion: v1 kind: Pod metadata: labels: name: db name: db spec: volumes: - name: secrets secret: secretName: mysecret containers: - image: gcr.io/my_project_id/pg:v1 name: db volumeMounts: - name: secrets mountPath: "/etc/secrets" readOnly: true ports: - name: cp containerPort: 5432 hostPort: 5432 |
将Secret导出到环境变量中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: wordpress-deployment spec: replicas: 2 strategy: type: RollingUpdate template: metadata: labels: app: wordpress visualize: "true" spec: containers: - name: "wordpress" image: "wordpress" ports: - containerPort: 80 env: - name: WORDPRESS_DB_USER valueFrom: secretKeyRef: name: mysecret key: username - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: mysecret key: password |
Service Account
Service Account用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount
目录中。
1 2 3 4 5 6 7 8 9 10 |
$ kubectl run nginx --image nginx deployment "nginx" created $ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-3137573019-md1u2 1/1 Running 0 13s $ kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount ca.crt namespace token |
二、ConfigMap
ConfigMap API资源用来保存key-value pair配置数据,这个数据可以在pods里使用,或者被用来为像controller一样的系统组件存储配置数据。
创建ConfigMap的方式有三种:
- 使用目录创建
- 使用文件创建
- 使用字面值创建
使用目录创建
比如我们已经有了一些配置文件,其中包含了我们想要设置的ConfigMap的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 查看目录下文件 $ ls /data/configmap/ game.properties ui.properties # game.properties 文件内容 enemies=aliens lives=3 enemies.cheat=true enemies.cheat.level=noGoodRotten secret.code.passphrase=UUDDLRLRBABAS secret.code.allowed=true secret.code.lives=30 # ui.properties 文件内容 color.good=purple color.bad=yellow allow.textmode=true how.nice.to.look=fairlyNice |
使用下面的命令可以创建一个包含目录中所有文件的ConfigMap。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# 创建 $ kubectl create configmap game-config --from-file=/data/configmap/ # 查看信息 $ kubectl describe configmaps game-config Name: game-config Namespace: default Labels: <none> Annotations: <none> Data ==== game.properties: 158 bytes ui.properties: 83 bytes # 输出详情 $ kubectl get configmaps game-config -o yaml apiVersion: v1 data: game.properties: | enemies=aliens lives=3 enemies.cheat=true enemies.cheat.level=noGoodRotten secret.code.passphrase=UUDDLRLRBABAS secret.code.allowed=true secret.code.lives=30 ui.properties: | color.good=purple color.bad=yellow allow.textmode=true how.nice.to.look=fairlyNice kind: ConfigMap metadata: creationTimestamp: 2020-01-18T18:34:05Z name: game-config namespace: default resourceVersion: "407" selfLink: /api/v1/namespaces/default/configmaps/game-config uid: 30944725-d66e-11e5-8cd0-68f728db1985 |
使用文件创建
刚才使用目录创建的时候我们—from-file指定的是一个目录,只要指定为一个文件就可以从单个文件中创建ConfigMap。
1 2 3 4 5 6 |
# 创建 $ kubectl create configmap game-config-2 --from-file=docs/data/configmap/game.properties # 输出内容 $ kubectl get configmaps game-config-2 -o yaml |
使用字面值创建
使用文字值创建,利用—from-literal参数传递配置信息,该参数可以使用多次,格式如下;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 创建 $ kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm # 输出内容 $ kubectl get configmaps special-config -o yaml apiVersion: v1 data: special.how: very special.type: charm kind: ConfigMap metadata: creationTimestamp: 2020-01-18T19:14:38Z name: special-config namespace: default resourceVersion: "651" selfLink: /api/v1/namespaces/default/configmaps/special-config uid: dadce046-d673-11e5-8cd0-68f728db1985 |
Pod中使用ConfigMap
其实与Secret类似
使用ConfigMap来替代环境变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# configmap apiVersion: v1 kind: ConfigMap metadata: name: special-config namespace: default data: special.how: very special.type: charm apiVersion: v1 kind: ConfigMap metadata: name: env-config namespace: default data: log_level: INFO # pod apiVersion: v1 kind: Pod metadata: name: dapi-test-pod spec: containers: - name: test-container image: gcr.io/google_containers/busybox command: [ "/bin/sh", "-c", "env" ] env: - name: SPECIAL_LEVEL_KEY valueFrom: configMapKeyRef: name: special-config key: special.how - name: SPECIAL_TYPE_KEY valueFrom: configMapKeyRef: name: special-config key: special.type envFrom: - configMapRef: name: env-config restartPolicy: Never |
创建后输出内容:
1 2 3 4 |
SPECIAL_LEVEL_KEY=very SPECIAL_TYPE_KEY=charm log_level=INFO |
用ConfigMap设置命令行参数
基于上述的ConfigMap,在command中进行输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
apiVersion: v1 kind: Pod metadata: name: dapi-test-pod spec: containers: - name: test-container image: gcr.io/google_containers/busybox command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ] env: - name: SPECIAL_LEVEL_KEY valueFrom: configMapKeyRef: name: special-config key: special.how - name: SPECIAL_TYPE_KEY valueFrom: configMapKeyRef: name: special-config key: special.type restartPolicy: Never |
输出内容
1 2 |
very charm |
通过数据卷插件使用ConfigMap
在数据卷里面使用这个ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
apiVersion: v1 kind: Pod metadata: name: dapi-test-pod spec: containers: - name: test-container image: gcr.io/google_containers/busybox command: [ "/bin/sh", "-c", "cat /etc/config/special.how" ] volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: special-config restartPolicy: Never |
我们也可以在ConfigMap值被映射的数据卷里控制路径。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
apiVersion: v1 kind: Pod metadata: name: dapi-test-pod spec: containers: - name: test-container image: gcr.io/google_containers/busybox command: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ] volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: special-config items: - key: special.how path: path/to/special-key restartPolicy: Never |
三、Volume、 Persistent Volume
首先要区分docker volume和k8s volume的区别。
对于无状态的Docker容器,容器重启时容器数据会自动清除。对于数据库、日志文件等可以实时变化的数据我们需要使用Volume。
Kubernetes底层支持Docker的容器运行引擎,为了不绑定在特定的容器技术上,Kubernetes没有使用Docker的Volume机制,而是重新制定了自己的通用数据卷插件规范,以配合不同的容器运行时来使用(如Docker和rkt)。
可以参考这个链接:https://zhuanlan.zhihu.com/p/62908569
Volume
Volume 分为本地数据卷 和 网络数据卷。
本地数据卷
1、 emptyDir,是一个匿名的空目录, 由k8s在创建pod的时候创建,销毁的时候一起销毁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
apiVersion: v1 kind: Pod metadata: name: test-pd spec: containers: - image: k8s.gcr.io/test-webserver name: test-container volumeMounts: - mountPath: /cache name: cache-volume volumes: - name: cache-volume emptyDir: {} |
2、 hostPath, 与emptyDir的区别是,它在Pod之外独立存在,由用户指定路径名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
apiVersion: v1 kind: Pod metadata: name: test-pd spec: containers: - image: k8s.gcr.io/test-webserver name: test-container volumeMounts: - mountPath: /test-pd name: test-volume volumes: - name: test-volume hostPath: # directory location on host path: /data # this field is optional type: Directory |
网络数据卷
这种存储卷不和某个具体的K8S节点绑定,而是独立于K8S节点存在的,整个存储集群和K8S集群是两个集群,相互独立。
Kubernetes 支持以下类型的卷:
- awsElasticBlockStore
- azureDisk
- azureFile
- cephfs
- csi
- downwardAPI
- fc
- flocker
- gcePersistentDisk
- gitRepo
- glusterfs
- iscsi
- local
- nfs
- persistentVolumeClaim
- projected
- portworxVolume
- quobyte
- rbd
- scaleIO
- secret
- storageos
- vsphereVolume
等等。
如果已有的存储不能满足要求,还可以开发自己的Volume插件,只需要实现Volume.go 里定义的接口。
参考:https://github.com/kubernetes/kubernetes/blob/master/pkg/volume/volume.go
Persistent Volume
普通Volume和使用它的Pod之间是一种静态绑定关系,在定义Pod的文件里,同时定义了它使用的Volume。Volume 是Pod的附属品,我们无法单独创建一个Volume,因为它不是一个独立的K8S资源对象。
而Persistent Volume 简称PV是一个K8S资源对象,所以我们可以单独创建一个PV。它不和Pod直接发生关系,而是通过Persistent Volume Claim,简称PVC来实现动态绑定。Pod定义里指定的是PVC,然后PVC会根据Pod的要求去自动绑定合适的PV给Pod使用。
PV的访问模式
- ReadWriteOnce(RWO):是最基本的方式,可读可写,但只支持被单个Pod挂载。
- ReadOnlyMany(ROX):可以以只读的方式被多个Pod挂载。
- ReadWriteMany(RWX):这种存储可以以读写的方式被多个Pod共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是NFS。在PVC绑定PV时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。
配置方式
静态配置,是管理员手动创建一堆PV,组成一个PV池,供PVC来绑定。
动态配置,是指在现有PV不满足PVC的请求时,可以使用存储分类(StorageClass),
描述具体过程为:PV先创建分类,PVC请求已创建的某个类(StorageClass)的资源,这样就达到动态配置的效果。即通过一个叫 Storage Class的对象由存储系统根据PVC的要求自动创建。
回收策略
- Retain – 手动重新使用
- Recycle – 基本的删除操作 (“rm -rf /thevolume/*”)
- Delete – 关联的后端存储卷一起删除,后端存储例如AWS EBS, GCE PD或OpenStack Cinder
卷的状态
- Available –闲置状态,没有被绑定到PVC
- Bound – 绑定到PVC
- Released – PVC被删掉,资源没有被在利用
- Failed – 自动回收失败
持久卷的声明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
apiVersion: v1 kind: PersistentVolume metadata: name: pv0003 spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: slow mountOptions: - hard - nfsvers=4.1 nfs: path: /tmp server: 172.17.0.2 |
PersistentVolumeClaim
访问模式
在请求具有特定访问模式的存储时,声明使用与卷相同的约定。
卷模式
声明使用与卷相同的约定,指示将卷作为文件系统或块设备使用。
资源
像 pod 一样,声明可以请求特定数量的资源。在这种情况下,请求是用于存储的。相同的资源模型适用于卷和声明。
选择器
声明可以指定一个标签选择器来进一步过滤该组卷。只有标签与选择器匹配的卷可以绑定到声明。选择器由两个字段组成:
- matchLabels:volume 必须有具有该值的标签
- matchExpressions:这是一个要求列表,通过指定关键字,值列表以及与关键字和值相关的运算符组成。有效的运算符包括 In、NotIn、Exists 和 DoesNotExist。
所有来自 matchLabels 和 matchExpressions 的要求都被“与”在一起——它们必须全部满足才能匹配。
类
声明可以通过使用属性 storageClassName 指定 StorageClass 的名称来请求特定的类。只有所请求的类与 PVC 具有相同 storageClassName 的 PV 才能绑定到 PVC。
PVC 不一定要请求类。其 storageClassName 设置为 “” 的 PVC 始终被解释为没有请求类的 PV,因此只能绑定到没有类的 PV(没有注解或 “”)。
PVC的声明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: myclaim spec: accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 8Gi storageClassName: slow selector: matchLabels: release: "stable" matchExpressions: - {key: environment, operator: In, values: [dev]} |