原文: https://kubernetes.io/docs/concepts/storage/volumes/
容器中的文件是短暫存在的,這會導致一定的問題。首先,當容器掛掉之后,kubelete會重啟他,但是文件會丟失掉;其次,在一個pod中運行的各個容器經常需要共享文件。kubernetes的volume就是用來解決這些問題的。
背景
docker也有volume的概念,但是有點松散和缺乏管理。在Docker里,一個volume簡單來說就是磁盤上或者另外一個容器中的目錄,沒有生命周期管理,而且直到最近也只支持本地磁盤的volume。Docker能支持volume driver,但是實用性很受限(docker 1.7 每個容器只支持一種volume driver,而且不能給volume傳遞參數)。
一個kubernetes的volume,有非常明確的跟Pod一樣的生命周期。因此,一個volume比同一個pod中的所有容器都活得長,而且數據是不受容器重啟影響的。當然,pod沒了,volume也就沒了。可能比這更重要的是,kubernetes支持多種類型的volumes,而且一個pod可以同時使用多種voluems。
本質上來說,一個vlomue就是一個目錄,可能在里面放了一些數據,這個目錄可以被pod里的容器訪問。致于這個目錄哪兒來的,他背后是什么設備,他的內容是啥,這就要看具體是哪種類型的volume了。
要使用一個volume,需要pod聲明提供什么volume(使用spec.volumes字段) 和掛載到哪些容器中 (使用spec.containers.volumeMounts字段).
容器里的進程看到的文件系統,是由docker鏡像和volumes組合起來的。Docker鏡像是文件系統的root,而其他volumes都是掛載在某個具體的目錄上。volumes不能掛載到其他volumes中,也不能有指向其他volume的hard link. Pod中的每個容器必須單獨制定掛載那個volume。
TL;DR:
k8s的volume就是好就是好就是好.
Volume類型
kubernets支持這些volume類型:
- emptyDir
- hostPath
- gcePresistentDisk
- awsElasticBlockStore
- nfs
- iscsi
- flocker
- glusterfs
- rbd
- cephfs
- gitRepo
- secret
- persistentVolumeClaim
- downwardAPI
- azureFileVolume
- azureDisk
- vsphereVolume
- Quobyte
- PortworxVolume
- ScaleIO
歡迎你們貢獻其他的類型。
emptyDir
emptyDir volume是在Pod被分配到一個Node上之后,最先創建出來的,而且一只存在到Pod不在這個node上了為止。 看名字就看得出來,他是一個空目錄。該pod中的容器都可以在emptyDir volume中讀寫到相同的文件,盡管這個volume可能被掛載在不同容器的不同目錄。 當一個Pod不管什么原因被從所在的Node上移除了,emptyDir里的數據也就被永久刪除了。 NOTE: 如果僅僅是容器掛掉了,不會導致pod被從node上移除,所以enmptyDir中的數據還是安全的。
一些常見的用途:
- scratch space, such as for a disk-based merge sort
- 長時間計算的檢查點用來從crash中恢復
- holding files that a content-manager container fetches while a webserver container serves the data
默認來說,emptyDir volume存儲在哪兒是看你的機器的,可能是普通磁盤,可能是SSD,也可能是網絡存儲,主要看你的環境。但是,你也可以通過把 emptryDir.medium 的值改成 “Memory”, 這樣kubernets就會給你掛個tmpfs (基于RAM的文件系統)。雖然tmpfs很快,但是不像磁盤,當機器重啟之后,就沒了,而且你消耗的空間還要算在容器的內存限制里。
Example Pod
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 volume 掛載一個宿主機上的目錄到你的Pod里。 這可能不是大多是Pod需要用到的,但是他為某些應用提供了一個途徑。
舉個例子,可以這么用:
- 運行一個容器可能要訪問docker內部的什么東西,可以把/var/lib/docker掛進去
- 在一個容器里運行cAdvisor, 把/dev/cgroups掛進去
注意點:
相同配置的pod(必須用podTemplate創建出來的)可能在不同node上的行為不一樣,因為不同node上的同一目錄上中文件內容不一樣。當kubernetes在做調度的時候,如果需要考慮資源情況的話,是管不到hostPath里使用的資源的宿主機上的root用戶創建的目錄只能被root用戶操作。你可能需要在容器里也用root用戶運行,或者在宿主機上修改對應目錄的權限。
ExamplePod
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
-image: [gcr.io/google_containers/test-webserver](http://gcr.io/google_containers/test-webserver)
name: test-container
volumeMounts:
-mountPath: /test-pd
name: test-volume
volumes:
-name: test-volume
hostPath: # directory location on host
path: /data
gcePersistentDisk
gcePersistentDisk volume掛載一個Goole Compute Engine(GCE)的 PersistentDisk 到你的pod中。
反正用不到,先不管了。
awsElasticBlockStore
反正也用不到,先不管了
nfs
nfs volume允許一個NFS掛載到你的pods里。不像emptyDir一樣會在Pod移除時被擦除掉,nfs volume的內容是受保護的,不會被干掉,只是被unmount掉而已。這就是說,一個NFS volume可以預填充數據,而且這些數據可以在不同pod之間使用。NFS可以同時被多個writer掛載。
有點意思,看個例子:
https://github.com/kubernetes/kubernetes/tree/master/examples/volumes/nfs
iscsi, flocker,glusterfs,rbd,cephfs都用不到,先不管了
gitRepo
gitRepo volume是一個用來展示volume插件能力的例子.他會掛載一個空目錄,并且clone一個git庫進來供pod使用。在不遠的將來,這樣的volume們可能會改成更解耦的模型,而不是擴展kubernets的API。
來看個例子:
apiVersion: v1
kind: Pod
metadata:
name: server
spec:
containers:
-image: nginxname:nginx
volumeMounts:
-mountPath: /mypath
name: git-volume
volumes:
-name: git-volume
gitRepo:
repository: "git@somewhere:me/my-git-repository.git"
revision: "22f1d8406d464b0c0874075539c1f2e96c253775"
secret
secret volume是用來給pod傳遞敏感信息的,比如密碼。你可以用kubernets API存儲秘密信息,然后他們當成文件掛載到需要使用他們的Pod中,這樣就可以避免直接跟kubernets發生聯系。secret volumes是基于tmpfs的,所以它們永遠不會被寫到持久化存儲上。
提示: 你需要在使用之前先通過kubernets API創建一個secret
persistentVolumeClaim
persistentVolumeClaim volume是用來掛載一個PersitentVolume到pod中的。PersistentVolume是一種讓用戶在不需要關心具體細節的情況下申請耐用存儲(比如GCE PersistentDisk, 或者 ISCSI volume)的方式。
downwardAPi, FlexVolume, AzureFileVolume, AzureDiskVolum, vsphereVolume, Quobyte, PortworxVolume, ScaleIO 先不管了
使用子路徑
有些時候,在一個pod中的一個volume可能有多種用途。volumeMounts.subPath 屬性可以用來指定一個volume的子路徑而不是他的根目錄。
來看個例子, 這個例子是一個運行LAMP的pod,使用了一個共享的volume. 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