本地目录实现持久化存储
容器是无状态的,每次重启都是新的进程,但是我们需要将一些状态数据如配置、用户数据等存到本地来方便新的容器可以拿到历史状态。先创建一个目录来存放数据,并且挂载到minikube虚拟机内(不是pod里面)。注意要新开一个终端来调用,这个命令会阻塞,不能中断。
=> mkdir storage
=> minikube mount storage:/data
可以测试一下是否成功了
=> echo aaa > storage/test.txt
=> minikube ssh 'cat /data/test.txt'
aaa
然后创建一个持久化存储卷(PersistentVolume)的配置,挂载本机目录,注意是minikube虚拟机的目录,所以是/data
apiVersion: v1 # 版本信息
kind: PersistentVolume # 这个是一个持久化存储卷
metadata:name: test-local-pv # 元数据定义名称
spec:capacity:storage: 1Ki # 定义容量1KB,定义不定义都一样,因为目录挂载的方式取决于原始目录的容量storageClassName: local # 定义这个为了和pvc匹配,否则会绑定不了persistentVolumeReclaimPolicy: Retain # pvc被删除时,pv的回收策略,retain为保留pv,手动清理accessModes:- ReadWriteMany # 表示该卷可以被多个节点以读写的方式挂载。这意味着多个 Pod 可以同时访问这个卷并进行读写操作。hostPath:path: /data
pv是不能直接给pod访问和挂载使用的,需要使用pvc才能给到pod使用,所以写一个pvc的配置
apiVersion: v1 # 版本
kind: PersistentVolumeClaim # pvc类型,请求持久化存储卷
metadata:name: test-local-pvc
spec:accessModes:- ReadWriteMany # 这个模式表示多个节点可以同时读写这个存储。resources:requests:storage: 1Ki # 要和pv匹配,不然会无法绑定volumeName: test-local-pv # 指定要绑定的pv的名字storageClassName: local # 同样要和pv一致
启动pv和pvc,要看一下是否启动和绑定成功
kubectl apply -f test-pv.yaml
kubectl apply -f test-pvc.yaml
pv和pvc的绑定关系使用describe看起来会更清晰一点
=> kubectl describe pv test-local-pv
Name: test-local-pv
Labels: <none>
Annotations: pv.kubernetes.io/bound-by-controller: yes
Finalizers: [kubernetes.io/pv-protection]
StorageClass: local
Status: Bound
Claim: default/test-local-pvc
Reclaim Policy: Retain
Access Modes: RWX
VolumeMode: Filesystem
Capacity: 1Ki
Node Affinity: <none>
Message:
Source:Type: HostPath (bare host directory volume)Path: /dataHostPathType:
Events: <none>=> kubectl describe pvc test-local-pvc
Name: test-local-pvc
Namespace: default
StorageClass: local
Status: Bound
Volume: test-local-pv
Labels: <none>
Annotations: pv.kubernetes.io/bind-completed: yes
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 1Ki
Access Modes: RWX
VolumeMode: Filesystem
Used By: <none>
Events: <none>
可以看到pv和pvc绑定成功
下面要修改一下test.go,让我们的服务端可以读取和写入存储的一个文件
package mainimport ("fmt""io/ioutil""net/http""os"
)func main() {fmt.Println("start main")hostName := os.Getenv("HOSTNAME")// 正常请求根目录读取这个文件返回内容http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {contentBytes, err := ioutil.ReadFile("/data/test.txt")outStr := ""if err != nil {outStr = err.Error()} else {outStr = string(contentBytes)}fmt.Fprintf(w, "hello, world, %s, txt: '%s'\n", hostName, outStr)})// 保存文件,取xxx:xxx/save?content=xxx来存入http.HandleFunc("/save", func(w http.ResponseWriter, r *http.Request) {r.ParseForm()tmp := r.Form["content"]inputText := ""if len(tmp) > 0 {inputText = tmp[0]}ioutil.WriteFile("/data/test.txt", []byte(inputText), 0644)fmt.Fprintf(w, "%s", inputText)})http.HandleFunc("/exit", func(w http.ResponseWriter, r *http.Request) {fmt.Println("recieve exit, bye!")os.Exit(0)})err := http.ListenAndServe(":7878", nil)if err != nil {panic(err)}os.Exit(0)
}
修改完重新做一个镜像加载到minikube中,然后要修改一下deployment的配置来让pod使用pvc作为存储
apiVersion: apps/v1 # 版本,虽然不知道为什么,但是要写apps/v1
kind: Deployment # 选deployment
metadata:name: test-dep # 给deployment定义名字,创建的pod会以此为前缀
spec: # deployment的要求strategy:type: RollingUpdate # 策略为滚动更新rollingUpdate:maxUnavailable: 1 # 最多只能停止1个podmaxSurge: 1 # 在更新过程中,最多可以多创建多少个 Pod,本身停止了1个,创建1个,这里设置1会停1个创建2个replicas: 3 # pods启动3个selector: # 定义deployment管理的pod选择器matchLabels: # 要跟下面的template中一样,不一样会报错app: testtemplate: # 定义deployment管理的podmetadata:labels: # 定义标签,要和deployment中一样app: testspec: # pod的定义volumes: # 定义要求的存储卷- name: test-volume # 起个名字给pod使用persistentVolumeClaim: # 对应的pvcclaimName: test-local-pvccontainers:- name: testimage: test-con:latestimagePullPolicy: Never # 使用本地镜像,不从远端拉取command: ["go"]args: ["run", "/root/test.go"]volumeMounts: # 挂载到当前容器- mountPath: /data # 挂载目录name: test-volume # 使用的volumes,是上面定义的名字readinessProbe: # 就绪探针,什么时候可以开始接收流量,不会重启podhttpGet:path: /port: 7878timeoutSeconds: 1 # 探测超时时间5sinitialDelaySeconds: 5 # 第一次探测的等待时间periodSeconds: 5 # 探测周期livenessProbe: # 存活探针,什么时候需要杀掉这个pod,如果启动一直失败就会杀掉pod重启一个httpGet:path: /port: 7878timeoutSeconds: 1 # 探测超时时间5sinitialDelaySeconds: 20 # 第一次探测的等待时间periodSeconds: 5 # 探测周期failureThreshold: 10 # 错误阈值,超过这个阈值将会重启pod
生效一下这个配置文件,查看pod的pvc使用情况
kubectl apply -f test-dep.yaml
查看pvc里面更能看出来挂载情况
=> kubectl describe pvc test-local-pvc
Name: test-local-pvc
Namespace: default
StorageClass: local
Status: Bound
Volume: test-local-pv
Labels: <none>
Annotations: pv.kubernetes.io/bind-completed: yes
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 1Ki
Access Modes: RWX
VolumeMode: Filesystem
Used By: test-dep-6dc4bdc5bd-7mf7wtest-dep-6dc4bdc5bd-ftv24test-dep-6dc4bdc5bd-w8zxf
Events: <none>