- Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。
- Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。用户可以创建 Secret,同时系统也创建了一些 Secret。
Service Account:
用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的 /run/secrets/kubernetes.io/serviceaccount 目录中。
Opaque:base64编码格式的Secret,用来存储密码、秘钥等。
kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。
要使用 Secret,Pod 需要引用 Secret。 Pod 可以用三种方式之一来使用 Secret:
- 作为挂载到一个或多个容器上的 卷 中的文件。(volume进行挂载)
- 作为容器的环境变量(envFrom字段引用)
- 由 kubelet 在为 Pod 拉取镜像时使用(此时Secret是docker-registry类型的)
Secret 对象的名称必须是合法的 DNS 子域名。 在为创建 Secret 编写配置文件时,你可以设置 data 与/或 stringData 字段。 data 和 stringData 字段都是可选的。data 字段中所有键值都必须是 base64 编码的字符串。如果不希望执行这种 base64 字符串的转换操作,你可以选择设置 stringData 字段,其中可以使用任何字符串作为其取值。
实验: 创建Secret:1.generic类型:
## 命令行 #### 1、使用基本字符串 kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B*d$zDsb=' ### 或者打印出yaml文件 kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B*d$zDsb=' --dry-run=client -oyaml
apiVersion: v1 data: password: UyFCXCpkJHpEc2I9 ## base64编码了一下 username: ZGV2dXNlcg== kind: Secret metadata: name: dev-db-secret
#### 2、使用文件内容 echo -n 'admin' > ./username.txt echo -n '1f2d1e2e67df' > ./password.txt kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt # 默认密钥名称是文件名。 你可以选择使用 --from-file=[key=]source 来设置密钥名称。如下 kubectl create secret generic db-user-pass-02 --from-file=un=./username.txt --from-file=pd=./password.txt #查看所有的secret kubectl get secret #查看secret kubectl describe secret dev-db-secret #查看精确值 kubectl get secret dev-db-secret -oyaml使用Secret:
1. 环境变量引用:
apiVersion: v1
kind: Pod
metadata:
name: "pod-secret"
namespace: default
labels:
app: "pod-secret"
spec:
containers:
- name: pod-secret
image: "busybox"
command: ["/bin/sh","-c","sleep 3600"]
resources:
limits:
cpu: 10m
requests:
cpu: 5m
env:
- name: MY_USER #容器中环境变量里面的名字
valueFrom: ## secret的内容
secretKeyRef: # 指定secret名字
name: dev-db-secret
key: username
- name: POD_NAME
valueFrom:
fieldRef: # 属性引用
fieldPath: metadata.name # 取出资源对象信息
- name: POD_LIMIT_MEM
valueFrom:
resourceFieldRef: # 资源引用
containerName: pod-secret
resource: limits.cpu
环境变量引用的方式不会被自动更新
2.卷挂载
apiVersion: v1
kind: Pod
metadata:
name: "pod-secret-volume"
namespace: default
labels:
app: "pod-secret-volume"
spec:
volumes: # 指定挂载详情
- name: app
secret:
defaultMode: 0777 #修改默认的权限模式
secretName: db-user-pass #secret 里面所有的key全部挂出来
items:
- key: password.txt # db-user-pass 里面的password.txt 这个key的内容挂出来
path: pwd.md # 默认secret里面的数据的key是作为文件名的,path相当于我们自己修改了文件名
containers:
- name: pod-secret-volume
image: "busybox"
volumeMounts:
- mountPath: /app
readOnly: false #关闭可读模式
name: app
command: ["/bin/sh","-c","sleep 3600"]
resources:
limits:
cpu: 10m
requests:
cpu: 5m
如果secret以挂载的方式给容器
secret里面的所有的key都是文件名,内容就是文件内容
在pod外部修改secret则容器内挂载的方式会自动更新文件内容
挂载的方式是只读的,pod里面的文件时不能就行反向修改
ConfigMap:- ConfigMap 来将你的配置数据和应用程序代码分开。
- ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
data:
# 类属性键;每一个键都映射到一个简单的值
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# 类文件键
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
你可以使用四种方式来使用 ConfigMap 配置 Pod 中的容器:
- 在容器命令和参数内
- 容器的环境变量
- 在只读卷里面添加一个文件,让应用来读取
- 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap
apiVersion: v1
kind: Pod
metadata:
name: configmap-demo-pod
spec:
containers:
- name: demo
image: alpine
command: ["sleep", "3600"]
env:
# 定义环境变量
- name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
valueFrom:
configMapKeyRef:
name: game-demo # 这个值来自 ConfigMap
key: player_initial_lives # 需要取值的键
- name: UI_PROPERTIES_FILE_NAME
valueFrom:
configMapKeyRef:
name: game-demo
key: ui_properties_file_name
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
volumes:
# 你可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
- name: config
configMap:
# 提供你想要挂载的 ConfigMap 的名字
name: game-demo
# 来自 ConfigMap 的一组键,将被创建为文件
items:
- key: "game.properties"
path: "game.properties"
- key: "user-interface.properties"
path: "user-interface.properties"
使用挂载configMap
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
configMap:
name: myconfigmap
configMap的修改,可以触发挂载文件的自动更新
configMap和secret使用子路径的话就不会进行热更新
临时存储:几种临时存储:
- emptyDir: Pod 启动时为空,存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存
- configMap、 downwardAPI、 secret: 将不同类型的 Kubernetes 数据注入到 Pod 中
- CSI 临时卷: 类似于前面的卷类型,但由专门支持此特性 的指定 CSI 驱动程序提供
- 通用临时卷: 它可以由所有支持持久卷的存储驱动程序提供
- 当 Pod 分派到某个 Node 上时,emptyDir 卷会被创建
- 在 Pod 在该节点上运行期间,卷一直存在。
- 卷最初是空的。
- 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir 卷中相同的文件。
- 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。
- 存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存
apiVersion: v1
kind: Pod
metadata:
name: "multi-container-pod"
namespace: default
labels:
app: "multi-container-pod"
spec:
volumes: ### 以后见到的所有名字 都应该是一个合法的域名方式
- name: nginx-vol
emptyDir: {} ### docker匿名挂载,外部创建一个位置 /abc
containers: ## kubectl exec -it podName -c nginx-container(容器名)-- /bin/sh
- name: nginx-container
image: "nginx"
volumeMounts: #声明卷挂载 -v
- name: nginx-vol
mountPath: /usr/share/nginx/html
- name: content-container
image: "alpine"
command: ["/bin/sh","-c","while true;do sleep 1; date > /app/index.html;done;"]
volumeMounts:
- name: nginx-vol
mountPath: /app
扩展-hostPath:
https://kubernetes.io/zh/docs/concepts/storage/volumes/#hostpath
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:
# 宿主上目录位置
path: /data
# 此字段为可选
type: Directory
apiVersion: v1
kind: Pod
metadata:
name: test-webserver
spec:
containers:
- name: test-webserver
image: k8s.gcr.io/test-webserver:latest
volumeMounts:
- mountPath: /var/local/aaa
name: mydir
- mountPath: /var/local/aaa/1.txt
name: myfile
volumes:
- name: mydir
hostPath:
# 确保文件所在目录成功创建。
path: /var/local/aaa
type: DirectoryOrCreate
- name: myfile
hostPath:
path: /var/local/aaa/1.txt
type: FileOrCreate
典型应用
解决容器时间问题
apiVersion: v1
kind: Pod
metadata:
name: busy-box-test
namespace: default
spec:
restartPolicy: OnFailure
containers:
- name: busy-box-test
image: busybox
imagePullPolicy: IfNotPresent
volumeMounts:
- name: date-config
mountPath: /etc/localtime
command: ["sleep", "60000"]
volumes:
- name: date-config
hostPath:
path: /etc/localtime
持久化:
VOLUME:
- Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型
- 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长
- 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;
- Kubernetes 不会销毁 持久卷。
- 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
- 使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。
有时,在单个 Pod 中共享卷以供多方使用是很有用的。 volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径。
使用NFS: 1安装NFS:# 在任意机器 yum install -y nfs-utils #执行命令 vi /etc/exports,创建 exports 文件,文件内容如下: echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports #/nfs/data 172.26.248.0/20(rw,no_root_squash) # 执行以下命令,启动 nfs 服务;创建共享目录 mkdir -p /nfs/data systemctl enable rpcbind systemctl enable nfs-server systemctl start rpcbind systemctl start nfs-server exportfs -r #检查配置是否生效 exportfs # 输出结果如下所示 /nfs/data /nfs/data2VOLUME进行挂载测试
#测试Pod直接挂载NFS了
apiVersion: v1
kind: Pod
metadata:
name: vol-nfs
namespace: default
spec:
containers:
- name: myapp
image: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
nfs:
path: /nfs/data/nginx/ #1000G nginx文件夹需要重新提前创建
server: 172.31.9.67 #自己的nfs服务器地址
3、扩展-NFS文件同步
#服务器端防火墙开放111、662、875、892、2049的 tcp / udp 允许,否则远端客户无法连接。 #安装客户端工具 yum install -y nfs-utils #执行以下命令检查 nfs 服务器端是否有设置共享目录 # showmount -e $(nfs服务器的IP) showmount -e 172.31.9.67 # 输出结果如下所示 Export list for 172.31.9.67 /nfs/data * #执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount mkdir /root/nfsmount # mount -t nfs $(nfs服务器的IP):/root/nfs_root /root/nfsmount #高可用备份的方式 mount -t nfs 172.31.9.67:/nfs/data /root/nfsmount # 写入一个测试文件 echo "hello nfs server" > /root/nfsmount/test.txt #在 nfs 服务器上执行以下命令,验证文件写入成功 cat /root/nfsmount/test.txtPV&PVC&StorageClass 基础概念:
存储的管理是一个与计算实例的管理完全不同的问题。
- PersistentVolume 子系统为用户 和管理员提供了一组 API,将存储如何供应的细节从其如何被使用中抽象出来。
- 为了实现这点,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。
持久卷(PersistentVolume ):
- 持久卷(PersistentVolume,PV)是集群中的一块存储,可以由管理员事先供应,或者 使用存储类(Storage Class)来动态供应。
- 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样,也是使用 卷插件来实现的,只是它们拥有独立于使用他们的Pod的生命周期。
- 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。
持久卷申请(PersistentVolumeClaim,PVC):
- 表达的是用户对存储的请求
- 概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。
- Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载,参见访问模式)。
存储类(Storage Class):
- 尽管 PersistentVolumeClaim 允许用户消耗抽象的存储资源,常见的情况是针对不同的 问题用户需要的是具有不同属性(如,性能)的 PersistentVolume 卷。
- 集群管理员需要能够提供不同性质的 PersistentVolume,并且这些 PV 卷之间的差别不 仅限于卷大小和访问模式,同时又不能将卷是如何实现的这些细节暴露给用户。
- 为了满足这类需求,就有了 存储类(StorageClass) 资源。
创建三个PV:
提前创建好三个需要使用的文件夹:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-volume-10m
labels:
type: local
spec:
storageClassName: my-pv-volume-10m
capacity:
storage: 10m
accessModes:
- ReadWriteOnce
nfs:
path: /nfs/data/10M #10M
server: 172.31.9.67 #自己的nfs服务器地址
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-volume-200m
labels:
type: local
spec:
storageClassName: my-pv-volume-200m
capacity:
storage: 200m
accessModes:
- ReadWriteOnce
nfs:
path: /nfs/data/200M #10M
server: 172.31.9.67 #自己的nfs服务器地址
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-volume-1000m
labels:
type: local
spec:
storageClassName: my-pv-volume-1000m
capacity:
storage: 1000m
accessModes:
- ReadWriteOnce
nfs:
path: /nfs/data/1000M #10M
server: 172.31.9.67 #自己的nfs服务器地址
创建完成查询:
编写申请书:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
labels:
app: nginx-pvc
spec:
storageClassName: my-pv-volume-1000m #存储类的名字
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 900m
pod引用申请书:
apiVersion: v1
kind: Pod
metadata:
name: "nginx-pvc"
labels:
app: "nginx-pvc"
spec:
containers:
- name: "nginx-pvc"
image: nginx
ports:
- containerPort: 80
name: http
volumeMounts:
- mountPath: /usr/share/nginx/html
name: html
volumes:
- name: html
persistentVolumeClaim:
claimName: nginx-pvc # 申请书的名字
restartPolicy: Always
变成绑定状态:
修改nginx的访问页面验证是否成功,访问返回1111则验证成功
及时删除pod pvc还在则还在绑定状态,只有删除pvc则才会被别的pod绑定
只要PVC有:
PVC显示Pending
PV被创建以后,正好是PV可用的,PVC自动绑定到这个PV卷
PVC可以被提前创建并和PV绑定,以后Pod只需要关联PVC即可
Pod删除,PVC还在吗?
PVC并不会受影响,手动删除pvc
按照以前的原则,同一个资源的所有关联东西应该写在一个文件中。
PVC删除会不会影响PV?
要看pv的回收策略,比如nfs,回收策略是Recycle. pv不会删除,内容会被清空,pv重新变为可用。
目前的回收策略有:
1.Retain – (默认规则)手动回收 pv相关的内容,自己删除(pvc删除,pv分文不动,自己手动控制)
即使pod删除以及PVC删除,但是PV会记住上次和哪个绑定关系
2.Recycle – 基本擦除 (rm -rf /thevolume/*) 清除卷里面的内容
3.Delete – 诸如 AWS EBS、GCE PD、Azure Disk 或 OpenStack Cinder 卷这类关联存储资产也被删除
目前,仅 NFS 和 HostPath 支持回收(Recycle)。 AWS EBS、GCE PD、Azure Disk 和 Cinder 卷都支持删除(Delete)。
PV阶段:每个卷会处于以下阶段(Phase)之一:
1.Available(可用)-- 卷是一个空闲资源,尚未绑定到任何申领; 任意人都能继续使用
2.Bound(已绑定)-- 该卷已经绑定到某申领; 别人不能再用
3.Released(已释放)-- 所绑定的申领已被删除,但是资源尚未被集群回收;pvc被删除了,pv没有被回收,需要自己删除pv
4.Failed(失败)-- 卷的自动回收操作失败。
绑定了POD的PVC而且POD正在运行,PVC是不能删除的。PVC会一直等待POD删除以后才能删除
命令行接口能够显示绑定到某 PV 卷的 PVC 对象。
ReadWriteOnce
卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式也允许运行在同一节点上的多个 Pod 访问卷。
ReadOnlyMany
卷可以被多个节点以只读方式挂载。
ReadWriteMany
卷可以被多个节点以读写方式挂载。
ReadWriteOncePod
卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本。
静态供应:
- 集群管理员创建若干 PV 卷。这些卷对象带有真实存储的细节信息,并且对集群 用户可用(可见)。PV 卷对象存在于 Kubernetes API 中,可供用户消费(使用)
动态供应:
- 集群自动根据PVC创建出对应PV进行使用
https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
部署nfs-subdir-external-provisioner
注意替换自己的nfs服务器IP地址:
注意:
annotations:
storageclass.kubernetes.io/is-default-class: "true" #动态供应设置为默认驱动
## 创建了一个存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
#provisioner指定一个供应商的名字。
#必须匹配 k8s-deployment 的 env PROVISIONER_NAME的值
parameters:
archiveOnDelete: "true" ## 删除pv的时候,pv的内容是否要备份
#### 这里可以调整供应商能力。
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2
# resources:
# limits:
# cpu: 10m
# requests:
# cpu: 10m
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 172.31.9.67 ## 指定自己nfs服务器地址
- name: NFS_PATH
value: /nfs/data ## nfs服务器共享的目录
volumes:
- name: nfs-client-root
nfs:
server: 172.31.9.67
path: /nfs/data
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
部署pod加上pvc申请书进行测试:
apiVersion: v1
kind: Pod
metadata:
name: "nginx-pvc-999"
labels:
app: "nginx-pvc-999"
spec:
containers:
- name: "nginx-pvc-999"
image: nginx
ports:
- containerPort: 80
name: http
volumeMounts:
- mountPath: /usr/share/nginx/html
name: html
volumes:
- name: html
persistentVolumeClaim:
claimName: nginx-pvc-999 # 申请书的名字
restartPolicy: Always
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc-999
labels:
app: nginx-pvc-999
spec:
storageClassName: managed-nfs-storage #存储类的名字
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 900m
在这里插入图片描述



