k8s 掛載卷介紹(四)

kubernetes關於pod掛載卷的知識
首先要知道卷是pod資源的屬性,pv,pvc是單獨的資源。pod 資源的volumes屬性有多種type,其中就包含有掛載pvc的類型。這也幫我理清了之間的關係。
pv通常是系統管理員作的
pvc 是通常k8s用戶聲明的,大概意思就是說我須要一個 什麼權限的,多少存儲空間的卷,而後k8s api收到這個請求就去找pv資源對象,若是二者相匹配,那麼pv就和pvc綁定了。
從這裏咱們也想到了,pv若是是手動建立的話,那就麻煩大了。幾個,幾十個還好說,上萬個,管理員該如何建立這麼多。因此纔有了動態建立pv的需求。這就引出另一個資源 storageClass ,這個資源聲明後端掛載什麼樣的存儲服務,好比nfs,chef等,有了這個通常用戶在定義pvc的時候,在提出存儲空間和讀寫權限的同時聲明用那個storageClass了,
以下:

apiVersion: v1
kind: PersistentVolumeClaim
metadata: mysql-pvc
spec:
  accessModes:
      - ReadWriteMany
  storageClassName: managed-nfs-storage  (注意這裏)
  resources:
     requests:
        storage: 5Gi
以上即是pvc使用storageClass資源對象建立pv,pvc的綁定了
api收到對storageClass聲明後,就會調用這個storageClass的生產者進行生產。
咱們就會想到,在建立storageClass資源對象的時候確定會指定生產者。
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: example-nfs
provisioner: example.com/nfs  這裏指定生產者,其中example.com/nfs只是一個標籤,你在deploymend裏定義什麼這裏就寫什麼。
mountOptions:
  - vers=4.1
那麼問題又來了。在k8s中生產者組件不支持nfs,因此纔會安裝第三方組件。第三方組件的安裝就須要建立相關的rbac的角色和帳戶。第三方組件是用deploymend的資源託管相關組件pod的。
那麼經過deploy部署的pod怎麼就是provisioner了?這個我不清楚,後面學習後在總結吧。
 
 
回到正題上。
volumes 的4種
1. emptyDir
2. gitRepo
3. hostpath
4.PersistentVolumeClaim
5.configMap,secret
6. 各類雲平臺的存儲磁盤卷如google的gce,aws的ebs,azure的azureDisk
其實4只是一個歸納,nfs,chef 這些網絡存儲統統能夠單獨來使用。但我以爲實際使用中仍是講這些網絡存儲轉化成pv,pvc
 
從簡單開始學習
emptyDir 兩種應用場景: 1. 同一個pod中,各個容器間共享文件。 2. 當程序對大數據處理時內存空間不夠時臨時寫入文件(固然也可使用宿主主機的內存)
例子:
apiVersion: v1
kind: Pod
metadata:
    name: fortune
spec:
    containers:
    -   image: luksa/fortune
         name: html-generator
         volumeMounts:
         -   name: html
             mountPath: /var/htdocs
    -   image: nginx:alpine
         name: web-server
         volumeMounts:
         -   name: html
              mountPaht: /usr/share/nginx/html
              readOnly: true
         ports:
         -   containerPort: 80
              protocol: TCP
      volumes:
      -  name: html
          emptyDir: {}     (爲{}表示使用節點服務器的文件系統)
      -  name: html-2
          emptyDir:
               medium: Memory   (使用節點服務器的內存)
以上就是emptyDir的用法。gitRepo實際上是依賴於emptyDir的,你能夠把它理解成,聲明瞭一個emptyDir而後在把gitrepo下載填充到emptyDir
例子:
apiVersion: v1
kind: Pod
metadata:
    name: gitrepo-volume-pod
spec:
    containers:
    -   image: nginx: alpine
         name: web-nginx
         volumeMounts:
         -   name: html
              mountPath: /usr/share/nginx/html
              readOnly: true
          ports:
          -   containerPort: 80
               protocol: TCP
     volumes:
     -   name: html
          gitRepo:
              repository: https://github.com/luksa/kubia-website-example.git
              revision: master
              directory: .   (這個.很重要,表示在當前emptyDir目錄下否則就會建立一個kubia-website-example目錄)
以上就是gitRepo的用法,其中有個問題就是pod中的gitrepo並不會及時更新。若是想要及時更新須要用到sidecar ,加入到pod中,在Docker Hub搜索 「git ryc」獲取相關鏡像。
還有一個狀況不得不使用sidecar container 。gitrepo 不支持鏈接私有庫,也就是不能是ssh密鑰鏈接,也不能夠有用戶名和密碼。這時候就須要使用支持驗證鏈接的sidecar container來實現了。具體怎麼使用,用到的時候在研究吧.
至此gitRepo卷類型算是簡單介紹了,下面學習hostpath
 
大多數時候pod應該忽略他們的主機節點,所以他們也不須要訪問節點文件系統上的文件。可是某些系統級別的pod(一般由DaemonSet管理)確實須要讀取節點的文件或使用節點文件系統來訪問節設備,這時候就須要用到hostPath
hostPath 算是第一個持久化存儲捲了,可是這個不多用到,由於這個卷只能在某一單一節點上,pod重啓後極可能在另一個節點上。固然可使用NodeSelector但這樣看起來也不高明。因此建議使用網絡存儲。hostPath過
 
接下來是網絡存儲和雲平臺提供的存儲磁盤卷。這兩種在用到的時候找相關的屬性進行配置便可。也沒什麼要注意的,實際應用場景用到最多的持久存儲是pv,pvc,storageClass
 
 
configmap
kubectl create configmap fortune-config --from-literal=sleep-interval=25
 
通常configmap包含多個映射條目因此建立時能夠屢次使用--from-literal參數
kubectl create conigmap fortune-config --from-literal=foo=bar --from-literal=bar=baz --from-literal=one=two
 
kubectl get configmap fortune-config -o yaml
 
configmap一樣能夠存儲粗力度的配置數據,好比完整的配置文件。kubectl create configmap 命令支持從硬盤上讀取文件,並將文件內容單獨存儲爲ConfigMap中的條目:
kubectl create configmap my-config --from-file=config-file.conf
運行此命令,kubectl 會在當前目錄下找config-file.conf文件,並將文件內容存儲在configmap中以config-file.conf 爲鍵名的條目下。固然也能夠手動指定鍵名
kubectl create configmap my-config --from-file=customkey=config-file.conf
 
kubectl create configmap my-config --from-file=/path/to/dir
這時候,kubectl會爲文件中每一個文件單首創建條目,僅限文件名可做爲合法ConfigMap鍵名的文件。
 
當讓也能夠將上面的參數混合使用
 
configmap設置完成了,如何將映射的值傳遞給pod的容器?三種方法
一,設置環境變量,例子以下:
apiVersion: v1
kind: Pod
metadata:
    name: fortune-env-from-configmap
spec:
    containers:
    -   image: luksa/fortune:env
        env:
        -   name: INTERVAL
             valueFrom:
                 configMapKeyRef:
                     name: fortune-config
                     key: sleep-interval
很好奇當pod 容器中引用不存在的configmap會發生什麼?
pod會嘗試運行全部容器,只有這個容器啓動失敗,其餘正常(假若有多個容器),當你過後建立處這個configmap,無需重啓pod,容器就會成功。固然也能夠引用爲可選的,設置configMapKeyRef.optional: true便可,這樣即便ConfigMap不存在,容器也能正常啓動。
 
若是configmap中條目不少,用env屬性列出麻煩且容易出錯。那麼有沒有辦法一次導入呢。用envFrom, 例如configmap中有三個條目FOO、BAR和FOO-BAR
spec:
    containers:
    -   image: some-image
         envFrom:
         -   prefix: CONFIG_  全部環境變量均包含前綴CONFIG_  ,不設置就將引用configmap中的鍵名
              configMapRef:
                  name: my-config-map
如此,容器中多出兩個變量 CONFIG_FOO 、CONFIG_BAR
爲何是兩個,由於另一個FOO-BAR包含破折號,不是一個合法的環境變量名稱。被忽略了,因此咱們應該注意建立configmap時 不要使用-
 
上面咱們學習瞭如何將configmap中的條目以變量的形式傳入到容器中
那麼如何將configmap中的條目做爲容器運行的參數args呢?例子:
apiVersion: v1
kind: Pod
metadata:
    name: fortune-env-from-configmap
spec:
    containers:
    -   image: luksa/fortune:env
        env:
        -   name: INTERVAL
             valueFrom:
                 configMapKeyRef:
                     name: fortune-config
                     key: sleep-interval
        args: ["$(INTERVAL)"]
環境變量和參數都適合於變量值較短的場景。configmap是能夠包含完整配置文件內容的,當你想要將其暴露給容器時,可使用上一章中提到的卷的類型。configmap卷會將ConfigMap中的每一個條目均暴露成一個文件。運行在容器的進程經過讀取文件內容得到對應的條目值。
configmap-files爲一個目錄
kubectl create configmap fortune-config --from-file=configmap-files
例子:
apiVersion: v1
kind: Pod
metadata:
    name: fortune-configmap-volume
spec:
    containers:
    - image: nginx:alpine
       name: web-server
       volumeMounts:
       ...
       - name: config
          mountPaht: /etc/nginx/config.d
          readOnly: true
       ....
   volumes:
   ...
   - name: config
      configMap:
           name: fortune-config
   ...
一種特殊狀況,當你只想暴露configmap-files目錄下的某一個配置文件,該如何作:
volumes:
-   name: config
     configmap:
         name: fortune-config
         items:
             - key: my-nginx-config.conf
                path: gzip.conf
這樣配置後,掛載fortune-config 卷後,就只有my-nginx-config.conf 而且掛載後的名稱爲gzip.conf
 
另外一種特殊狀況,咱們經過上述掛載configmap卷後會發現,被掛載的目錄以前的文件都被隱藏掉了。那麼若是你需求不想隱藏以前的文件,該如何作:
spec:
    containers:
    -   image: some/image
         volumeMounts:
         -   name: myvolume
              mountPath: /etc/someconfig.conf 掛載到指定的某一個文件,而不是某個文件夾
              subPath: myconfig.conf 掛載指定的條目,而不是完整的卷
爲configMap卷中的文件設置權限
volumes:
-   name: config
    configmap:
        name: fortune-config
        defaultMode: "6600"
更新應用配置且不重啓應用程序
使用環境變量或命令行參數做爲配置源的弊端在於沒法在進程運行時更新配置。將ConfigMap暴露爲卷能夠達到配置熱更新的效果,無需從新建立pod或重啓容器。
ConfigMap被更新後,卷中引用它的文件也會相應更新,進程發現文件被改變後進行重載。kubernetes一樣支持文件更新後手動通知容器。但要注意的是,更新configmap以後對應文件的更新會至關耗時。
咱們使用kubectl edit configmap fortune-config 來更改某一個值。
而後執行
kubectl exec fortune-configmap-volume -c web-server -- cat /etc/nginx/config.d/my-nginx-config.conf
查看文件是否是被修改了,若是沒有稍等一會再查看。在確認更改後,咱們來手動通知容器進行重載。
kubectl exec fortune-configmap-volume -c web-server -- nginx -s reload
 
你可能會疑惑 Kubernetes更新完configmap卷中的全部文件以前(全部的文件被更新而不是一部分),應用是否會監聽到文件編號並主動進行重載。答案是不會,會在全部的文件更新後,一次性更新到pod容器中。kubernetes經過富豪連接作到這一點的。
kubectl exec -ti fortune-configmap-volume -c web-server -- ls -lA /etc/nginx/config.d
..4989_09_04_15_06.028485
..data -> ..4989_09_04_15_06.028485
my-nginx-config.conf -> ..data/my-nginx-config.conf
sleep-interval -> ..data/sleep-interval
能夠看到,被掛載configMap卷中的文件是..data文件夾中文件的符號連接,而..data又是鏈接到 ..4989的符號連接,每當ConfigMap被更新後,Kubernetes 會建立一個這樣的文件夾,卸任全部文件並從新將符號..data連接至新文件夾,經過這種方式能夠一次性修改全部文件。
 
若是掛載configmap中的某一個文件,而不是文件夾,configmap更新以後對應的文件不會被更新。若是如今你須要掛載單個文件且在修改Configmap後想自動更新,能夠將該卷掛載到其餘文件夾,而後作一個軟連接。
至於如何實現應用重載配置 ,須要應用本身實現了。
 
configmap都是以名文存儲的,有些信息比較敏感,就須要用祕文存儲了。
這就須要使用kubernetes 的secret資源了。
首先有一個狀況咱們須要瞭解
使用kubectl describe pod pod-id 查看任何一個pod你都會發現默認有掛載一個secret卷。
Volumes:
  default-token-ps7ff:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-ps7ff
    Optional:    false
這個卷裏的內容咱們可使用kubectl describe secrets查看
#  kubectl describe secrets default-token-ps7ff
Name:         default-token-ps7ff
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: default
              kubernetes.io/service-account.uid: 6efa7f7c-6a61-11e9-bfdb-0a382f97318e

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1359 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtp...
能夠看出這個Secret包含是哪一個條目ca.crt 、namespace與token
包含了從pod內部安全訪問Kubernetes API服務器所需的所有信息。儘管咱們但願作到應用對kubernetes無感知,可是直連Kubernetes沒有其餘方法,你只能使用secret卷提供的文件來訪問kubernetes API。
使用kubectl describe pod命令顯示secret卷北掛載的位置:
mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-ps7ff (ro)
 
注意: default-token Secret默認會被掛載至每一個容器。能夠經過設置pod定義中的automountServiceAccountToken字段爲false,或者設置pod使用的服務帳戶中的相同字段爲false來關閉這種默認行爲。
 
查看容器中掛載了哪些條目
# kubectl exec nginx-dnm9n -- ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token
 
建立Secret
openssl genrsa -out https.key 2048
openssl req -new -x509 -key https.key -out https.cert -days 3650 -subj /CN=www.kubia-example.com
# kubectl create secret generic fortune-https --from-file=https.key --from-file=https.cert --from-file=foo
secret/fortune-https created
也可使用 --from-file=fortune-https 囊括這個文件夾中的文件
# kubectl get secret fortune-https -o yaml
# kubectl describe secret fortune-https
 
對比configmap與secret
secret與configMap有比較大的區別,這也是爲什麼kubernetes開發者們在支持了Secret一段時間以後會選擇建立ConfigMap。建立的Secret的YAML格式定義顯示
# kubectl get secret fortune-https -o yaml
apiVersion: v1
data:
  foo: YmFyCg==
  https.cert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURFekNDQWZ1Z0F3SUJBZ0lKQU96Y00rNzI3RWJHTUEwR0NTcUdTSWIzRFFFQkN3VUFNQ0F4SGpBY0JnTlYKQkF
  https.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBeFYvUVJiazJiRm8zRmdZdWpaTWxPVGg3MUxpY3AyUS9pL2pib2E1SExlUlpSTDBi
kind: Secret
. . .
將其與CoinfigMap的Yaml格式定義作對比
apiVersion: v1
data:
  bar: baz
  foo: bar
  one: two
kind: ConfigMap
注意到Secret條目的內容會被以Base64格式編譯,而ConfigMap直接以純文本展現。這種區別致使在處理YAML和JSON格式的Secret時會稍許有些麻煩,須要在設置和讀取相關條目時對內容進行編解碼。
這個具體使用中是這樣的,
好比你如今想把一個配置文件加入到Secret中,那麼你首先將配置文件中的內容經過BASE64進行編碼後才能做爲條目。
固然你會問難道kubernetes不提供base64編碼?提供,只能對字符串,不能接受文件。以下:
kund: Secret
apiVersion: v1
stringData:
    foo: plain text
data:
    https.cert: lksjkaldjldasjladgjsjl...
    https.key: lsiodjsdlfjahcdo...
建立後使用kubectl get secret -o yaml會看到stringData字段中的全部條目會被Base64編碼後展現在data字段下。因此stringData字段是隻寫不可讀的。
如何在pod中使用Secret
apiVersion:  v1
kind: Pod
metadata:
    name: fortune-https
spec:
    containers:
    -   image: luksa/fortune:env
         name: html-generator
         env:
         -   name: INTERVAL
              valueFrom:
              configMapKeyRef:
                  name: fortune-config
                  key: sleep-interval
          volumeMounts:
          -   name: html
               mountPaht: /var/htdocs
    -   image: nginx:alpine
        name: web-server
        volumeMounts:
        -   name: html
             mountPath: /usr/share/nginx/html
             readOnly: true
        -   name: config
             mountPath: /etc/nginx/conf.d
             readOnly: true
        -   name: certs
             mountPath: /etc/nginx/certs/
             readOnly: true
        ports:
        - containerPort: 80
        - containerPort: 443
    volumes:
    -   name:  html
         emptyDir: {}
    -   name: config
         configmap:
             name: fortune-config
             items:
             -   key: my-nginx-config.conf
                  path: https.conf
    -   name: certs
         secret:
             secretname: fortune-https

 

簡單點的實例:

apiVersion:  v1
kind: Pod
metadata:
    name: fortune-https
spec:
    containers:
    - image: nginx:alpine
      name: web-server
      volumeMounts:
      - name: certs
        mountPath: /etc/nginx/certs/
        readOnly: true
      ports:
      - containerPort: 80
      - containerPort: 443
    volumes:
    - name: certs
      secret:
        secretName: fortune-https
固然也能夠將secret條目暴露爲環境變量。但不建議這麼作,應用一般會在錯誤報告時轉儲環境變量,或者是啓動時打印在應用日誌中,無心中就暴露Secret信息。另外,子進程會繼承父進程的全部環境變量,若是是經過第三方二進制程序啓動應用,你並不知道它使用敏感數據作了什麼。因此不建議用環境變量,建議使用secret卷的形式掛載到pod.
env:
- name: FOO_SECRET
   valueFrom:
       secretKeyRef:
           name: fortune-https
           key: foo
學會了secret,接下來就有一個比較經常使用的secret實際應用,dockerhub
kubectl create secret docker-registry mydockerhubsecret --docker-username=myusername --docker-password=mypassword --docker-email= my.email@provider.com
 
使用:
apiVersion: v1
kind: Pod
metadata:
    name: private-pod
spec:
    imagePullSecrets:
    - name: mydockerhubsecret
    containers:
    - image: username/private:tag
       name: main

 

假設系統一般運行大量Pod,你可能會好奇是否須要爲每一個Pod都添加相同的鏡像拉取Secret.並非,能夠經過添加Secret至ServiceAccount 使全部pod都能自動添加上鏡像拉取的Secret.
相關文章
相關標籤/搜索