概述
由於容器本身是非持久化的,因此需要解決在容器中運行應用程序遇到的一些問題。首先,當容器崩潰時,kubelet將重新啟動容器,但是寫入容器的文件將會丟失,容器將會以鏡像的初始狀態重新開始;第二,在通過一個Pod中一起運行的容器,通常需要共享容器之間一些文件。Kubernetes通過存儲卷解決上述的兩個問題。
在Docker有存儲卷的概念卷,但Docker中存儲卷只是磁盤的或另一個容器中的目錄,並沒有對其生命周期進行管理。Kubernetes的存儲卷有自己的生命周期,它的生命周期與使用的它Pod生命周期一致。因此,相比於在Pod中運行的容器來說,存儲卷的存在時間會比的其中的任何容器都長,並且在容器重新啟動時會保留數據。當然,當Pod停止存在時,存儲卷也將不再存在。在Kubernetes支持多種類型的卷,而Pod可以同時使用各種類型和任意數量的存儲卷。
在Pod中通過指定下面的字段來使用存儲卷:
- spec.volumes:通過此字段提供指定的存儲卷
- spec.containers.volumeMounts:通過此字段將存儲卷掛接到容器中
存儲卷類型
emptryDir (本地數據卷)
emptyDir類型的Volume在Pod分配到Node上時被創建,Kubernetes會在Node上自動分配一個目錄,因此無需指定宿主機Node上對應的目錄文件。 這個目錄的初始內容為空,當Pod從Node上移除時,emptyDir中的數據會被永久刪除。
emptyDir Volume主要用於某些應用程序無需永久保存的臨時目錄,多個容器的共享目錄等。
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
hostPath (本地數據卷)
hostPath類型的存儲卷用於將宿主機的文件系統的文件或目錄掛接到Pod中,除了需要指定path字段之外,在使用hostPath類型的存儲卷時,也可以設置type,type支持的枚舉值由下表。另外在使用hostPath時,
需要注意下面的事項:
- 具有相同配置的Pod(例如:從同一個podTemplate創建的),可能會由於Node的文件不同,而行為不同。
- 在宿主機上創建的文件或目錄,只有root用戶具寫入的權限。您要么在容器中以root身份運行進程,要么在主機上修改的文件或目錄的權限,以便具備寫入內容到hostPath的存儲卷中。
值 | 行為 |
---|---|
空字符串(默認)是用於向后兼容,這意味着在掛接主機路徑存儲卷之前不執行任何檢查。 | |
DirectoryOrCreate |
如果path指定目錄不存在,則會在宿主機上創建一個新的目錄,並設置目錄權限為0755,此目錄與kubelet擁有一樣的組和擁有者。 |
Directory |
path指定的目標必需存在 |
FileOrCreate |
如果path指定的文件不存在,則會在宿主機上創建一個空的文件,設置權限為0644,此文件與kubelet擁有一樣的組和擁有者。 |
File |
path指定的文件必需存在 |
Socket |
path指定的UNIX socket必需存在 |
CharDevice |
path指定的字符設備必需存在 |
BlockDevice |
在path給定路徑上必須存在塊設備。 |
下面是使用hostPath作為存儲卷的YAML文件,此YAML文件定義了一個名稱為test-pd的Pod資源。它通過hostPath類型的存儲卷,將Pod宿主機上的/data掛接到容器中的/teset-pd目錄。
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
# this field is optional
type: Directory
nfs (網絡數據卷)
在Kubernetes中,可以通過nfs類型的存儲卷將現有的NFS(網絡文件系統)到的掛接到Pod中。在移除Pod時,NFS存儲卷中的內容被不會被刪除,只是將存儲卷卸載而已。這意味着在NFS存儲卷總可以預先填充數據,並且可以在Pod之間共享數據。NFS可以被同時掛接到多個Pod中,並能同時進行寫入。需要注意的是:在使用nfs存儲卷之前,必須已正確部署和運行NFS服務器,並已經設置了共享目錄。
下面是一個redis部署的YAML配置文件,redis在容器中的持久化數據保存在/data目錄下;存儲卷使用nfs,nfs的服務地址為:192.168.8.150,存儲路徑為:/k8s-nfs/redis/data。容器通過volumeMounts.name的值確定所使用的存儲卷
# for versions before 1.9.0 use apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
selector:
matchLabels:
app: redis
revisionHistoryLimit: 2
template:
metadata:
labels:
app: redis
spec:
containers:
# 應用的鏡像
- image: redis
name: redis
imagePullPolicy: IfNotPresent
# 應用的內部端口
ports:
- containerPort: 6379
name: redis6379
env:
- name: ALLOW_EMPTY_PASSWORD
value: "yes"
- name: REDIS_PASSWORD
value: "redis"
# 持久化掛接位置,在docker中
volumeMounts:
- name: redis-persistent-storage
mountPath: /data
volumes:
# 宿主機上的目錄
- name: redis-persistent-storage
nfs:
path: /k8s-nfs/redis/data
server: 192.168.8.150
persistentVolumeClaim
persistentVolumeClaim類型存儲卷將PersistentVolume掛接到Pod中作為存儲卷。使用此類型的存儲卷,用戶並不知道存儲卷的詳細信息。
此處定義名為busybox-deployment的部署YAML配置文件,使用的鏡像為busybox。基於busybox鏡像的容器需要對/mnt目錄下的數據進行持久化,在YAML文件指定使用名稱為nfs的PersistenVolumeClaim對容器的數據進行持久化。
# This mounts the nfs volume claim into /mnt and continuously
# overwrites /mnt/index.html with the time and hostname of the pod.
apiVersion: v1
kind: Deployment
metadata:
name: busybox-deployment
spec:
replicas: 2
selector:
name: busybox-deployment
template:
metadata:
labels:
name: busybox-deployment
spec:
containers:
- image: busybox
command:
- sh
- -c
- 'while true; do date > /mnt/index.html; hostname >> /mnt/index.html; sleep $(($RANDOM % 5 + 5)); done'
imagePullPolicy: IfNotPresent
name: busybox
volumeMounts:
# name must match the volume name below
- name: nfs
mountPath: "/mnt"
volumes:
- name: nfs
persistentVolumeClaim:
claimName: nfs-pvc
subPath
有時,可以在一個pod中,將同一個卷共享,使其有多個用處。volumeMounts.subPath
特性可以用來指定卷中的一個子目錄,而不是直接使用卷的根目錄。
這里有一個使用LAMP棧(Linux Apache Mysql PHP)的pod示例,該pod使用了一個共享的卷。HTML內容映射在它的html子目錄,而數據庫則保存在它的mysql目錄
apiVersion: v1
kind: Pod
metadata:
name: my-lamp-site
spec:
containers:
- name: mysql
image: mysql
volumeMounts:
- mountPath: /var/lib/mysql
name: site-data
subPath: mysql
- name: php
image: php
volumeMounts:
- mountPath: /var/www/html
name: site-data
subPath: html
volumes:
- name: site-data
persistentVolumeClaim:
claimName: my-lamp-site-data
secret(信息數據卷)
Kubemetes提供了Secret來處理敏感數據,比如密碼、Token和密鑰,相比於直接將敏感數據配置在Pod的定義或者鏡像中,Secret提供了更加安全的機制(Base64加密),防止數據泄露。Secret的創建是獨立於Pod的,以數據卷的形式掛載到Pod中,Secret的數據將以文件的形式保存,容器通過讀取文件可以獲取需要的數據。
yaml示例如下:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: emhlbnl1
password: eWFvZGlkaWFv
--
apiVersion: v1
kind: Pod
metadata:
labels:
name: test-secret
role: master
name: test-secret
spec:
containers:
- name: test-secret
image: registry:5000/back_demon:1.0
volumeMounts:
- name: secret
mountPath: /home/laizy/secret
readOnly: true
command:
- /run.sh
volumes:
- name: secret
secret:
secretName: mysecret