k8s系列---存儲卷pv/pvc。configMap/secert

    由於pod是有生命週期的,pod一重啓,裏面的數據就沒了。因此咱們須要數據持久化存儲。 css

    在k8s中,存儲卷不屬於容器,而是屬於pod。也就是說同一個pod中的容器能夠共享一個存儲卷。 html

    存儲卷能夠是宿主機上的目錄,也能夠是掛載在宿主機上的外部設備。 node

存儲卷類型

     emptyDIR存儲卷 :pod一重啓,存儲卷也刪除,這叫emptyDir存儲卷。通常用於當作臨時空間或緩存關係 python

     hostPath存儲卷 :宿主機上目錄做爲存儲卷,這種也不是真正意義實現了數據持久性。 mysql

     SAN(iscsi)或NAS(nfs、cifs): 網絡存儲設備 nginx

     分佈式存儲(ceph,glusterfs,cephfs,rbd) : web

     雲存儲(亞馬遜的EBS,Azure Disk,阿里雲): 這種通常k8s也在雲上部署的。 sql

    關鍵數據必定要有異地備份,不然數據一刪,多少個副本都沒用。docker

[root@master ingress]# kubectl explain pods.spec.volumes

  

hostPath

功能:使用宿主機上目錄做爲存儲卷,這種也不是真正意義實現了數據持久性。api

[root@master ~]# kubectl explain pods.spec.volumes.hostPath.type
KIND:     Pod
VERSION:  v1
FIELD:    type <string>
DESCRIPTION:
     Type for HostPath Volume Defaults to "" More info:
     https://kubernetes.io/docs/concepts/storage/volumes#hostpath

  

查看幫助: https://kubernetes.io/docs/concepts/storage/volumes#hostpath

hostPath.type的類型說明:

DirectoryOrCreate:意思是咱們要掛載的路徑在宿主機上是個已經存在的目錄,不存在就建立一個新的目錄。

Directory:宿主機上必須實現存在目錄,若是不存在就報錯

FileOrCreate:表示掛載的是文件,若是不存在就掛載一個文件。文件也能夠當作存儲掛載的。

File:表示要掛載的文件必須事先存在,不然就報錯。 

Socket:表示必須是一個Socket類型的文件。

CharDevice:表示是一個字符類型的設備文件。

BlockDevice:表示的是一個塊類型的設備文件。

例子:

[root@master volumes]# cat pod-hostpath-vol.yaml 

apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-hostpath
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html #存儲卷的名字叫html
      mountPath: /usr/share/nginx/html/ #掛載路徑
  volumes:
  - name: html
    hostPath:
      path: /data/pod/volume1
      type: DirectoryOrCreate

  

[root@master volumes]# kubectl apply -f pod-hostpath-vol.yaml 
pod/pod-vol-hostpath created

  

 而後到node1節點上能夠看到/data/pod/volume1目錄已經建立出來了。

[root@master volumes]# kubectl get pods -o wide
NAME                             READY     STATUS             RESTARTS   AGE       IP             NODE
client                           0/1       Error              0          15d       10.244.2.4     node2
pod-vol-hostpath                 1/1       Running            0          4m        10.244.1.105   node1

  

 當node1節點宕機後,pod就飄到node2節點上,並使用node2節點上的/data/pod/volume1目錄。這就有問題了,由於node2節點上的目錄並無同步node1節點上目錄的數據,因此出現數據不一致。

    解決這個問題的方法就是使用相似nfs方法,讓兩個node節點共享一個存儲。 

使用nfs作共享存儲

    我這裏爲了方便,把master節點當作nfs存儲。 

[root@master ~]# yum -y install nfs-utils

  

[root@master ~]# mkdir /data/volumes

  

[root@master ~]# cat /etc/exports
#no_root_squash:登入 NFS 主機使用分享目錄的使用者,若是是 root 的話,那麼對於這個分享的目錄來講,他就具備 root 的權限!這個項目『極不安全』,不建議使用! 
#root_squash:在登入 NFS 主機使用分享之目錄的使用者若是是 root 時,那麼這個使用者的權限將被壓縮成爲匿名使用者,一般他的 UID 與 GID 都會變成 nobody 那個系統帳號的身份;
/data/volumes 172.16.0.0/16(rw,no_root_squash)

  

[root@master ~]# systemctl start nfs

  

在node1和node2上也安裝nfs-utils包 

[root@node1 ~]# yum -y install nfs-utils

  

    在node1和node2上掛載: 

[root@node1 ~]# mount -t nfs 172.16.1.100:/data/volumes /mnt

  

在master上

[root@master ~]# kubectl explain pods.spec.volumes.nfs

  

[root@master volumes]# cat pod-vol-nfs.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-nfs
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html #存儲卷的名字叫html
      mountPath: /usr/share/nginx/html/ #掛載路徑,myapp容器裏面的路徑
  volumes:
  - name: html
    nfs:
      path: /data/volumes
      server: 172.16.1.100 #nfs server ip

  

[root@master volumes]# kubectl apply -f pod-vol-nfs.yaml

  

[root@master volumes]# kubectl get pods -o wide
NAME                             READY     STATUS             RESTARTS   AGE       IP             NODE
pod-vol-nfs                      1/1       Running            0          1m        10.244.1.106   node1

  

[root@master volumes]# cat /data/volumes/index.html
hello world

  

[root@master volumes]# curl  10.244.1.106 #容器的ip
hello world

  

  可見容器使用的是nfs提供的共享存儲。 

     不過,nfs自身沒有冗餘能力,因此若是nfs宕機了,數據也丟了。所以,咱們通常用glusterfs或者cephfs分佈式存儲。 

pvc和pv 

    用戶只須要掛載pvc到容器中而不須要關注存儲卷採用何種技術實現。pvc和pv的關係與pod和node關係相似,前者消耗後者的資源。pvc能夠向pv申請指定大小的存儲資源並設置訪問模式。

    在定義pod時,咱們只須要說明咱們要一個多大的存儲卷就好了。pvc存儲卷必須與當前namespace的pvc創建直接綁定關係。pvc必須與pv創建綁定關係。而pv是真正的某個存儲設備上的空間。 

[root@master volumes]# kubectl explain pods.spec.volumes.persistentVolumeClaim

  

[root@master volumes]# kubectl explain pvc

 

 一個pvc和pv是一一對應關係,一旦一個pv被一個pvc綁定了,那麼這個pv就不能被其餘pvc綁定了。 

     一個pvc是能夠被多個pod所訪問的。 

    在存儲機器上創建以下幾個目錄(這裏我以master節點作存儲,生產中能夠單獨拿出 一個機器作存儲):

[root@master volumes]# mkdir v{1,2,3,4,5}

  

[root@master volumes]# cat  /etc/exports
#no_root_squash:登入 NFS 主機使用分享目錄的使用者,若是是 root 的話,那麼對於這個分享的目錄來講,他就具備 root 的權限!這個項目『極不安全』,不建議使用! 
#root_squash:在登入 NFS 主機使用分享之目錄的使用者若是是 root 時,那麼這個使用者的權限將被壓縮成爲匿名使用者,一般他的 UID 與 GID 都會變成 nobody 那個系統帳號的身份;
/data/volumes/v1 172.16.0.0/16(rw,no_root_squash) 
/data/volumes/v2 172.16.0.0/16(rw,no_root_squash) 
/data/volumes/v3 172.16.0.0/16(rw,no_root_squash) 
/data/volumes/v4 172.16.0.0/16(rw,no_root_squash) 
/data/volumes/v5 172.16.0.0/16(rw,no_root_squash)

  

[root@master volumes]# exportfs  -arv #不用重啓nfs服務,配置文件就會生效
exporting 172.16.0.0/16:/data/volumes/v5
exporting 172.16.0.0/16:/data/volumes/v4
exporting 172.16.0.0/16:/data/volumes/v3
exporting 172.16.0.0/16:/data/volumes/v2
exporting 172.16.0.0/16:/data/volumes/v1

  

[root@master volumes]# showmount -e
Export list for master:
/data/volumes/v5 172.16.0.0/16
/data/volumes/v4 172.16.0.0/16
/data/volumes/v3 172.16.0.0/16
/data/volumes/v2 172.16.0.0/16
/data/volumes/v1 172.16.0.0/16

  

[root@master volumes]# kubectl explain pv.spec.nfs

  

[root@master ~]# kubectl explain pv.spec
FIELDS:
   accessModes<[]string>
     AccessModes contains all ways the volume can be mounted. More info:
     https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes

  

訪問  https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes看幫助。

accessModes模式有:

ReadWriteOnce:單路讀寫,能夠簡寫爲RWO

ReadOnlyMany:多路只讀,能夠簡寫爲ROX

ReadWriteMany :多路讀寫,能夠簡寫爲RWX

不一樣類型的存儲卷支持的accessModes也不一樣。

[root@master volumes]# cat pv-demo.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001 #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
  labels:
    name: pv001
spec:
  nfs:
    path: /data/volumes/v1
    server: 172.16.1.100
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity: #分配磁盤空間大小
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002 #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
  labels:
    name: pv002
spec:
  nfs:
    path: /data/volumes/v2
    server: 172.16.1.100
  accessModes: ["ReadWriteOnce"]
  capacity: #分配磁盤空間大小
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003 #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
  labels:
    name: pv003
spec:
  nfs:
    path: /data/volumes/v3
    server: 172.16.1.100
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity: #分配磁盤空間大小
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004 #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
  labels:
    name: pv004
spec:
  nfs:
    path: /data/volumes/v4
    server: 172.16.1.100
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity: #分配磁盤空間大小
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005 #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
  labels:
    name: pv005
spec:
  nfs:
    path: /data/volumes/v5
    server: 172.16.1.100
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity: #分配磁盤空間大小
    storage: 1Gi

  

[root@master volumes]# kubectl apply -f pv-demo.yaml 
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created

  

[root@master volumes]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
pv001     1Gi        RWO,RWX        Retain           Available                                      2m
pv002     2Gi        RWO            Retain           Available                                      2m
pv003     1Gi        RWO,RWX        Retain           Available                                      2m
pv004     1Gi        RWO,RWX        Retain           Available                                      2m
pv005     1Gi        RWO,RWX        Retain           Available                                      2m

  

 回收策略 :若是某個pvc在pv裏面存數據了,後來pvc刪了,那麼 pv裏面的數據怎麼處理呢。有以下幾種策略: 

    reclaim_policy:即pvc刪了,可是pv裏面的數據不擅長,還保留着。 

    recycle:即pvc刪了,那麼就把pv裏面的數據也刪了。 

    delete:即pvc刪了,那麼就把pv也刪了。 

    下面咱們再建立pvc的清單文件。 

[root@master ~]# kubectl explain pvc.spec
[root@master ~]# kubectl explain pods.spec.volumes.persistentVolumeClaim
[root@master volumes]# cat pod-vol-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim #簡稱pvc
metadata:
  name: mypvc
  namespace: default #pvc和pod是在同一個名稱空間
spec:
  accessModes: ["ReadWriteMany"] #必定是pv策略的子集
  resources:
    requests:
      storage: 1Gi #表示我要pvc 爲1G的空間
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-pvc
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html #存儲卷的名字叫html
      mountPath: /usr/share/nginx/html/ #掛載路徑
  volumes:
  - name: html
    persistentVolumeClaim:
      claimName: mypvc #表示我要使用哪一個pvc

  

[root@master volumes]# kubectl apply -f pod-vol-pvc.yaml 
persistentvolumeclaim/mypvc created
pod/pod-vol-pvc created

  

[root@master volumes]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM           STORAGECLASS   REASON    AGE
pv001     1Gi        RWO,RWX        Retain           Available                                            7h
pv002     2Gi        RWO            Retain           Available                                            7h
pv003     1Gi        RWO,RWX        Retain           Available                                            7h
pv004     1Gi        RWO,RWX        Retain           Bound       default/mypvc                            7h
pv005     1Gi        RWO,RWX        Retain           Available               

  

  上面看到pv004被default名稱空間的mypvc綁定了。 

[root@master volumes]# kubectl get pvc
NAME      STATUS    VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc     Bound     pv004     1Gi        RWO,RWX                       33m
[root@master volumes]# kubectl get pods 
NAME                             READY     STATUS             RESTARTS   AGE
client                           0/1       Error              0          16d
pod-vol-pvc                      1/1       Running            0          35m

  

 生產上,pv並不屬於node節點,而是獨立於node節點的。因此,node節點壞了,pv裏面的數據還在。另外,pod纔是屬於node節點的。 

    在k8s 1.10以後,不能手工從底層刪除pv,這樣作很安全。 

 StorageClass(存儲類)

    Kubernetes集羣管理員經過提供不一樣的存儲類,能夠知足用戶不一樣的服務質量級別、備份策略和任意策略要求的存儲需求。動態存儲卷供應使用StorageClass進行實現,其容許存儲卷按需被建立。若是沒有動態存儲供應,Kubernetes集羣的管理員將不得不經過手工的方式類建立新的存儲卷。經過動態存儲卷,Kubernetes將可以按照用戶的須要,自動建立其須要的存儲。

    storageclass底層能夠是glusterfs,cephfs等不一樣的集羣。 

configmap   

    configmap和secret是兩種特殊的存儲卷,它們不是給pod提供存儲空間用的,而是給咱們的管理員或者用戶提供了從外部向pod內部注入信息的方式。

     configmap :把配置文件放在配置中心上,而後多個pod讀取配置中心的配置文件。不過,configmap中的配置信息都是明文的,因此不安全。 

      secret: 功能和configmap同樣,只不過配置中心存儲的配置文件不是明文的。

    configmap和secret也是專屬於某個名稱空間的。 

[root@master ~]# kubectl explain configmap
[root@master ~]# kubectl explain cm #簡寫
[root@master ~]# kubectl create configmap --help

  

簡單的咱們能夠用命令行來建立configmap。 

[root@master ~]# kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-literal=server_name=myapp.zhixin.com
configmap/nginx-config created

  

[root@master ~]# kubectl get cm
NAME           DATA      AGE
nginx-config   2         3m

  

[root@master ~]# kubectl describe cm nginx-config
Name:         nginx-config
Namespace:    default
Labels:       <none>
Annotations:  <none>
Data
====
nginx_port:
----
80
server_name:
----
myapp.zhixin.com

  

下面咱們用配置清單的方式來建立configmap:

[root@master configmap]# cat www.conf 
server {
      server_name myapp.zhixin.com;
      listen 80;
      root /data/web/html;
}

  

[root@master configmap]# kubectl create configmap nginx-www --from-file=www.conf
configmap/nginx-www created

  

[root@master configmap]# kubectl get cm
NAME           DATA      AGE
nginx-config   2         3m
nginx-www      1         7s

  

[root@master configmap]# kubectl describe cm nginx-www 
Name:         nginx-www
Namespace:    default
Labels:       <none>
Annotations:  <none>
Data
====
www.conf:
----
server {
      server_name myapp.zhixin.com;
      listen 80;
      root /data/web/html;
}

  

   咱們建立的configmap,可用ENV等方式注入到Pod中。 

    咱們用ENV方式來把configmap注入到pod中去。 

[root@master configmap]# cat pod-configmap.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-1
  namespace: default
  labels:
    app: myapp  #kv格式的,也能夠用花括號表示
    tier: frontend #定義所屬的層次
  annotations:
    chenzx.com/created-by: "cluster-admin" #這是註解的鍵值對
spec:
  containers: 
  - name: myapp  #前面的-號表示這是一個列表格式的,也能夠用中括號表示
    image: tomcat 
    ports:
    - name: http
      containerPort: 80
    env: #這是一個容器的屬性
    - name: NGINX_SERVER_PORT
      valueFrom: #kubectl explain pods.spec.containers.env.valueFrom
        configMapKeyRef: #表示咱們要引用一個configmap來獲取數據
          name: nginx-config #這是configmap的名字,也就是經過kubectl get cm獲取的名字
          key: nginx_port #經過kubectl describe cm nginx-config的鍵
     #下面開始引用第二個環境變量
    - name: NGINX_SERVER_NAME
      valueFrom:
        configMapKeyRef:
          name: nginx-config
          key: server_name

  

[root@master configmap]# kubectl apply -f pod-configmap.yaml 
pod/pod-cm-1 created

  

    這樣,咱們就創建了一個pod-cm-1的pod,而且這個pod的配置文件來自於configmap。 

 

[root@master configmap]# kubectl get pods
NAME                             READY     STATUS                       RESTARTS   AGE
pod-cm-1                         0/1       Running   0          15m

  

[root@master configmap]# kubectl exec -it pod-cm-1 -- /bin/sh
# printenv
NGINX_SERVER_PORT=80
NGINX_SERVER_NAME=myapp.zhixin.com

  

[root@master configmap]# kubectl edit cm nginx-config
configmap/nginx-config edited

  

    經過edit方式編輯的配置文件,在Pod裏面不會當即理解生效,須要重啓pod才能生效。 

 

[root@master configmap]# kubectl delete -f pod-configmap.yaml 
pod "pod-cm-1" deleted

  

    下面咱們用配置mount存儲卷的方法把configmap注入到pod中。

[root@master configmap]# cat pod-configmap2.ymal 
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-2
  namespace: default
  labels:
    app: myapp  #kv格式的,也能夠用花括號表示
    tier: frontend #定義所屬的層次
  annotations:
    chenzx.com/created-by: "cluster-admin" #這是註解的鍵值對
spec:
  containers: 
  - name: myapp  #前面的-號表示這是一個列表格式的,也能夠用中括號表示
    image: ikubernetes/myapp:v1 
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: nginxconf
      mountPath: /etc/nginx/conf.d/
      readOnly: true
  volumes:
  - name: nginxconf
    configMap:
      name: nginx-config

  

[root@master configmap]# kubectl apply -f pod-configmap2.ymal 
pod/pod-cm-2 created

  

[root@master configmap]# kubectl get pods
NAME                             READY     STATUS             RESTARTS   AGE
pod-cm-2                         1/1       Running            0          1m

  

[root@master configmap]# kubectl exec -it pod-cm-2 -- /bin/sh
/ # cd /etc/nginx/conf.d/
/etc/nginx/conf.d # ls
nginx_port   server_name
/etc/nginx/conf.d # ls -l
total 0
lrwxrwxrwx    1 root     root            17 Sep 27 05:07 nginx_port -> ..data/nginx_port
lrwxrwxrwx    1 root     root            18 Sep 27 05:07 server_name -> ..data/server_name
/etc/nginx/conf.d # cat nginx_port
8080

  

下面咱們再把前面咱們建立的www.conf文件注入到pod中:

[root@master configmap]# cat pod-configmap3.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-3
  namespace: default
  labels:
    app: myapp  #kv格式的,也能夠用花括號表示
    tier: frontend #定義所屬的層次
  annotations:
    chenzx.com/created-by: "cluster-admin" #這是註解的鍵值對
spec:
  containers: 
  - name: myapp  #前面的-號表示這是一個列表格式的,也能夠用中括號表示
    image: ikubernetes/myapp:v1 
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: nginxconf
      mountPath: /etc/nginx/conf.d/
      readOnly: true
  volumes:
  - name: nginxconf
    configMap:
      name: nginx-www

  

[root@master configmap]# kubectl apply -f pod-configmap3.yaml 
pod/pod-cm-3 created

  

[root@master configmap]# 
[root@master configmap]# kubectl get pods
NAME                             READY     STATUS             RESTARTS   AGE
client                           0/1       Error              0          16d
pod-cm-3       

  

[root@master configmap]# kubectl exec -it pod-cm-3 -- /bin/sh
/ # cd /etc/nginx/conf.d/
/etc/nginx/conf.d # ls
www.conf
/etc/nginx/conf.d # cat www.conf 
server {
      server_name myapp.zhixin.com;
      listen 80;
      root /data/web/html;
}

  

  經過上面的例子,你們看到咱們已經把 www.conf中的內容注入到了pod  myapp中。 

[root@master configmap]# kubectl edit cm nginx-www

  

    改個端口,而後再到pod裏面,多等一會就會看到剛纔修改的在pod裏面生效了。 

[root@master configmap]# kubectl exec -it pod-cm-3 -- /bin/sh
/ # cd /etc/nginx/conf.d/
/etc/nginx/conf.d # cat www.conf 
server {
      server_name myapp.zhixin.com;
      listen 8081;
      root /data/web/html;
[root@master configmap]# /etc/init.d/nginx reload #重載nginx使8081端口生效

  

    若是咱們指望只注入部分,而非全部,該怎麼作呢?

[root@master configmap]# kubectl explain pods.spec.volumes.configMap.items
[root@master configmap]# kubectl create secret generic --help

  

經過items來注入部分,這裏面就不演示了,請讀者自行解決。 

secret 

    功能和configmap同樣,只不過secret配置中心存儲的配置文件不是明文的。

[root@master configmap]# kubectl create secret --help
 generic:保存密碼用的類型
 tls:保存證書用的類型
 docker-registry:保存docker認證信息用的類型,好比從私有docker倉庫拉鏡像時,就用這個類型。
 備註:k8s拖鏡像的進程是kublete

  

[root@master configmap]# kubectl explain pods.spec.imagePullSecrets
若是是從私有倉庫拉鏡像,就用imagePullSecrets存登陸驗證的信息

  

例子:

[root@master configmap]# kubectl create secret generic mysql-root-password --from-literal=password=123456
secret/mysql-root-password created

  

[root@master configmap]# kubectl get secret
NAME                    TYPE                                  DATA      AGE
default-token-5r85r     kubernetes.io/service-account-token   3         19d
mysql-root-password     Opaque                                1         40s
tomcat-ingress-secret   kubernetes.io/tls                     2         2d

  

[root@master configmap]# kubectl describe secret mysql-root-password
Name:         mysql-root-password
Namespace:    default
Labels:       <none>
Annotations:  <none>
Type:  Opaque
Data
====
password:  6 bytes

  

看到password的內容就是base64加密的形式了。

[root@master configmap]# kubectl get secret mysql-root-password -o yaml
apiVersion: v1
data:
  password: MTIzNDU2
kind: Secret
metadata:
  creationTimestamp: 2018-09-27T06:01:24Z
  name: mysql-root-password
  namespace: default
  resourceVersion: "2482795"
  selfLink: /api/v1/namespaces/default/secrets/mysql-root-password
  uid: c3d3e8ec-c21a-11e8-bb35-005056a24ecb
type: Opaque

  

 能夠用命令base64命令進行明文解碼: 

[root@master configmap]# echo MTIzNDU2 |base64 -d
123456

  

  可見secret是防君子不防小人,是個僞加密,哈哈。 

    下面咱們把secret經過env的方式注入到pod裏面。 

[root@master configmap]# cat  pod-secret-1.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret-1
  namespace: default
  labels:
    app: myapp  #kv格式的,也能夠用花括號表示
    tier: frontend #定義所屬的層次
  annotations:
    chenzx.com/created-by: "cluster-admin" #這是註解的鍵值對
spec:
  containers: 
  - name: myapp  #前面的-號表示這是一個列表格式的,也能夠用中括號表示
    image: tomcat 
    ports:
    - name: http
      containerPort: 80
    env: #這是一個容器的屬性
    - name: MYSQL_ROOT_PASSWORD
      valueFrom: #kubectl explain pods.spec.containers.env.valueFrom
        secretKeyRef: #表示咱們要引用一個configmap來獲取數據
          name: mysql-root-password  #這是configmap的名字,也就是經過kubectl get secret獲取的名字
          key: password #經過kubectl describe secret mysql-root-password的鍵
     #下面開始引用第二個環境變量
    - name: NGINX_SERVER_NAME
      valueFrom:
        configMapKeyRef:
          name: nginx-config
          key: server_name

  

[root@master configmap]# kubectl apply -f pod-secret-1.yaml 
pod/pod-secret-1 created

  

[root@master configmap]# kubectl get pods
NAME                             READY     STATUS             RESTARTS   AGE
pod-secret-1                     1/1       Running            0          1m

  

[root@master configmap]# kubectl exec -it pod-secret-1 -- /bin/sh
# printenv
MYSQL_ROOT_PASSWORD=123456

  

 看到secret經過env的方式,是以明文注入到pod裏面的。 

    另外,secret還能夠用mount的方式注入pod中,這部分略,如須要請參考本小節的configmap的相關例子。 

 

 

 

  由於pod是有生命週期的,pod一重啓,裏面的數據就沒了。因此咱們須要數據持久化存儲。 

    在k8s中,存儲卷不屬於容器,而是屬於pod。也就是說同一個pod中的容器能夠共享一個存儲卷。 

    存儲卷能夠是宿主機上的目錄,也能夠是掛載在宿主機上的外部設備。 

存儲卷類型

     emptyDIR存儲卷 :pod一重啓,存儲卷也刪除,這叫emptyDir存儲卷。通常用於當作臨時空間或緩存關係 

     hostPath存儲卷 :宿主機上目錄做爲存儲卷,這種也不是真正意義實現了數據持久性。 

     SAN(iscsi)或NAS(nfs、cifs): 網絡存儲設備 

     分佈式存儲(ceph,glusterfs,cephfs,rbd) : 

     雲存儲(亞馬遜的EBS,Azure Disk,阿里雲): 這種通常k8s也在雲上部署的。 

    關鍵數據必定要有異地備份,不然數據一刪,多少個副本都沒用。

1
[root@master ingress]# kubectl explain pods.spec.volumes

 hostPath

功能:使用宿主機上目錄做爲存儲卷,這種也不是真正意義實現了數據持久性。

1
2
3
4
5
6
7
[root@master ~]# kubectl explain pods.spec.volumes.hostPath.type
KIND:     Pod
VERSION:  v 1
FIELD:    type <string>
DESCRIPTION:
      Type for HostPath Volume Defaults to  ""  More info:
      https://kubernetes.io/docs/concepts/storage/volumes#hostpath

查看幫助: https://kubernetes.io/docs/concepts/storage/volumes#hostpath

hostPath.type的類型說明:

DirectoryOrCreate:意思是咱們要掛載的路徑在宿主機上是個已經存在的目錄,不存在就建立一個新的目錄。

Directory:宿主機上必須實現存在目錄,若是不存在就報錯

FileOrCreate:表示掛載的是文件,若是不存在就掛載一個文件。文件也能夠當作存儲掛載的。

File:表示要掛載的文件必須事先存在,不然就報錯。 

Socket:表示必須是一個Socket類型的文件。

CharDevice:表示是一個字符類型的設備文件。

BlockDevice:表示的是一個塊類型的設備文件。

例子:

[root@master volumes]# cat pod-hostpath-vol.yaml 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v 1
kind: Pod
metadata:
   name: pod-vol-hostpath
   namespace:  default
spec:
   containers:
   - name: myapp
     image: ikubernetes/myapp:v 1
     volumeMounts:
     - name: html #存儲卷的名字叫html
       mountPath: /usr/share/nginx/html/ #掛載路徑
   volumes:
   - name: html
     hostPath:
       path: /data/pod/volume 1
       type: DirectoryOrCreate
1
2
[root@master volumes]# kubectl apply -f pod-hostpath-vol.yaml 
pod/pod-vol-hostpath created

    而後到node1節點上能夠看到/data/pod/volume1目錄已經建立出來了。

1
2
3
4
[root@master volumes]# kubectl get pods -o wide
NAME                             READY     STATUS             RESTARTS   AGE       IP             NODE
client                            0 / 1        Error               0           15 d        10.244 . 2.4      node 2
pod-vol-hostpath                  1 / 1        Running             0           4 m         10.244 . 1.105    node 1

    當node1節點宕機後,pod就飄到node2節點上,並使用node2節點上的/data/pod/volume1目錄。這就有問題了,由於node2節點上的目錄並無同步node1節點上目錄的數據,因此出現數據不一致。

    解決這個問題的方法就是使用相似nfs方法,讓兩個node節點共享一個存儲。 

使用nfs作共享存儲

    我這裏爲了方便,把master節點當作nfs存儲。 

1
[root@master ~]# yum -y install nfs-utils
1
[root@master ~]# mkdir /data/volumes
1
2
3
4
[root@master ~]# cat /etc/exports
#no_root_squash:登入 NFS 主機使用分享目錄的使用者,若是是 root 的話,那麼對於這個分享的目錄來講,他就具備 root 的權限!這個項目『極不安全』,不建議使用! 
#root_squash:在登入 NFS 主機使用分享之目錄的使用者若是是 root 時,那麼這個使用者的權限將被壓縮成爲匿名使用者,一般他的 UID 與 GID 都會變成 nobody 那個系統帳號的身份;
/data/volumes  172.16 . 0.0 / 16 (rw,no_root_squash)
1
[root@master ~]# systemctl start nfs

    在node1和node2上也安裝nfs-utils包 

1
[root@node 1  ~]# yum -y install nfs-utils

    在node1和node2上掛載: 

1
[root@node 1  ~]# mount -t nfs  172.16 . 1.100: /data/volumes /mnt

    在master上: 

1
[root@master ~]# kubectl explain pods.spec.volumes.nfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@master volumes]# cat pod-vol-nfs.yaml 
apiVersion: v 1
kind: Pod
metadata:
   name: pod-vol-nfs
   namespace:  default
spec:
   containers:
   - name: myapp
     image: ikubernetes/myapp:v 1
     volumeMounts:
     - name: html #存儲卷的名字叫html
       mountPath: /usr/share/nginx/html/ #掛載路徑,myapp容器裏面的路徑
   volumes:
   - name: html
     nfs:
       path: /data/volumes
       server:  172.16 . 1.100  #nfs server ip
1
[root@master volumes]# kubectl apply -f pod-vol-nfs.yaml
1
2
3
[root@master volumes]# kubectl get pods -o wide
NAME                             READY     STATUS             RESTARTS   AGE       IP             NODE
pod-vol-nfs                       1 / 1        Running             0           1 m         10.244 . 1.106    node 1
1
2
[root@master volumes]# cat /data/volumes/index.html
hello world
1
2
[root@master volumes]# curl   10.244 . 1.106  #容器的ip
hello world

    可見容器使用的是nfs提供的共享存儲。 

     不過,nfs自身沒有冗餘能力,因此若是nfs宕機了,數據也丟了。所以,咱們通常用glusterfs或者cephfs分佈式存儲。 

pvc和pv 

    用戶只須要掛載pvc到容器中而不須要關注存儲卷採用何種技術實現。pvc和pv的關係與pod和node關係相似,前者消耗後者的資源。pvc能夠向pv申請指定大小的存儲資源並設置訪問模式。

    在定義pod時,咱們只須要說明咱們要一個多大的存儲卷就好了。pvc存儲卷必須與當前namespace的pvc創建直接綁定關係。pvc必須與pv創建綁定關係。而pv是真正的某個存儲設備上的空間。 

1
[root@master volumes]# kubectl explain pods.spec.volumes.persistentVolumeClaim
1
[root@master volumes]# kubectl explain pvc

     一個pvc和pv是一一對應關係,一旦一個pv被一個pvc綁定了,那麼這個pv就不能被其餘pvc綁定了。 

     一個pvc是能夠被多個pod所訪問的。 

    在存儲機器上創建以下幾個目錄(這裏我以master節點作存儲,生產中能夠單獨拿出 一個機器作存儲):

1
[root@master volumes]# mkdir v{ 1 , 2 , 3 , 4 , 5 }
1
2
3
4
5
6
7
8
[root@master volumes]# cat  /etc/exports
#no_root_squash:登入 NFS 主機使用分享目錄的使用者,若是是 root 的話,那麼對於這個分享的目錄來講,他就具備 root 的權限!這個項目『極不安全』,不建議使用! 
#root_squash:在登入 NFS 主機使用分享之目錄的使用者若是是 root 時,那麼這個使用者的權限將被壓縮成爲匿名使用者,一般他的 UID 與 GID 都會變成 nobody 那個系統帳號的身份;
/data/volumes/v 1  172.16 . 0.0 / 16 (rw,no_root_squash) 
/data/volumes/v 2  172.16 . 0.0 / 16 (rw,no_root_squash) 
/data/volumes/v 3  172.16 . 0.0 / 16 (rw,no_root_squash) 
/data/volumes/v 4  172.16 . 0.0 / 16 (rw,no_root_squash) 
/data/volumes/v 5  172.16 . 0.0 / 16 (rw,no_root_squash)
1
2
3
4
5
6
[root@master volumes]# exportfs  -arv #不用重啓nfs服務,配置文件就會生效
exporting  172.16 . 0.0 / 16: /data/volumes/v 5
exporting  172.16 . 0.0 / 16: /data/volumes/v 4
exporting  172.16 . 0.0 / 16: /data/volumes/v 3
exporting  172.16 . 0.0 / 16: /data/volumes/v 2
exporting  172.16 . 0.0 / 16: /data/volumes/v 1
1
2
3
4
5
6
7
[root@master volumes]# showmount -e
Export list for master:
/data/volumes/v 5  172.16 . 0.0 / 16
/data/volumes/v 4  172.16 . 0.0 / 16
/data/volumes/v 3  172.16 . 0.0 / 16
/data/volumes/v 2  172.16 . 0.0 / 16
/data/volumes/v 1  172.16 . 0.0 / 16
1
[root@master volumes]# kubectl explain pv.spec.nfs
1
2
3
4
5
[root@master ~]# kubectl explain pv.spec
FIELDS:
    accessModes<[]string>
      AccessModes contains  all  ways the volume can be mounted. More info:
      https://kubernetes.io/docs/concepts/storage/persistent-volumes #acce ss-modes

訪問  https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes看幫助。

accessModes模式有:

ReadWriteOnce:單路讀寫,能夠簡寫爲RWO

ReadOnlyMany:多路只讀,能夠簡寫爲ROX

ReadWriteMany :多路讀寫,能夠簡寫爲RWX

不一樣類型的存儲卷支持的accessModes也不一樣。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
[root@master volumes]# cat pv-demo.yaml 
apiVersion: v 1
kind: PersistentVolume
metadata:
   name: pv 001  #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
   labels:
     name: pv 001
spec:
   nfs:
     path: /data/volumes/v 1
     server:  172.16 . 1.100
   accessModes: [ "ReadWriteMany" , "ReadWriteOnce" ]
   capacity: #分配磁盤空間大小
     storage:  1 Gi
---
apiVersion: v 1
kind: PersistentVolume
metadata:
   name: pv 002  #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
   labels:
     name: pv 002
spec:
   nfs:
     path: /data/volumes/v 2
     server:  172.16 . 1.100
   accessModes: [ "ReadWriteOnce" ]
   capacity: #分配磁盤空間大小
     storage:  2 Gi
---
apiVersion: v 1
kind: PersistentVolume
metadata:
   name: pv 003  #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
   labels:
     name: pv 003
spec:
   nfs:
     path: /data/volumes/v 3
     server:  172.16 . 1.100
   accessModes: [ "ReadWriteMany" , "ReadWriteOnce" ]
   capacity: #分配磁盤空間大小
     storage:  1 Gi
---
apiVersion: v 1
kind: PersistentVolume
metadata:
   name: pv 004  #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
   labels:
     name: pv 004
spec:
   nfs:
     path: /data/volumes/v 4
     server:  172.16 . 1.100
   accessModes: [ "ReadWriteMany" , "ReadWriteOnce" ]
   capacity: #分配磁盤空間大小
     storage:  1 Gi
---
apiVersion: v 1
kind: PersistentVolume
metadata:
   name: pv 005  #注意,定義pv時必定不要加名稱空間,由於pv是屬於整個集羣,而不是屬於某個名稱空間。但pvc是屬於某個名稱空間的
   labels:
     name: pv 005
spec:
   nfs:
     path: /data/volumes/v 5
     server:  172.16 . 1.100
   accessModes: [ "ReadWriteMany" , "ReadWriteOnce" ]
   capacity: #分配磁盤空間大小
     storage:  1 Gi
1
2
3
4
5
6
[root@master volumes]# kubectl apply -f pv-demo.yaml 
persistentvolume/pv 001  created
persistentvolume/pv 002  created
persistentvolume/pv 003  created
persistentvolume/pv 004  created
persistentvolume/pv 005  created
1
2
3
4
5
6
7
[root@master volumes]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
pv 001      1 Gi        RWO,RWX        Retain           Available                                       2 m
pv 002      2 Gi        RWO            Retain           Available                                       2 m
pv 003      1 Gi        RWO,RWX        Retain           Available                                       2 m
pv 004      1 Gi        RWO,RWX        Retain           Available                                       2 m
pv 005      1 Gi        RWO,RWX        Retain           Available                                       2 m

     回收策略 :若是某個pvc在pv裏面存數據了,後來pvc刪了,那麼 pv裏面的數據怎麼處理呢。有以下幾種策略: 

    reclaim_policy:即pvc刪了,可是pv裏面的數據不擅長,還保留着。 

    recycle:即pvc刪了,那麼就把pv裏面的數據也刪了。 

    delete:即pvc刪了,那麼就把pv也刪了。 

    下面咱們再建立pvc的清單文件。 

1
[root@master ~]# kubectl explain pvc.spec
1
[root@master ~]# kubectl explain pods.spec.volumes.persistentVolumeClaim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@master volumes]# cat pod-vol-pvc.yaml 
apiVersion: v 1
kind: PersistentVolumeClaim #簡稱pvc
metadata:
   name: mypvc
   namespace:  default  #pvc和pod是在同一個名稱空間
spec:
   accessModes: [ "ReadWriteMany" ] #必定是pv策略的子集
   resources:
     requests:
       storage:  1 Gi #表示我要pvc 爲 1 G的空間
---
apiVersion: v 1
kind: Pod
metadata:
   name: pod-vol-pvc
   namespace:  default
spec:
   containers:
   - name: myapp
     image: ikubernetes/myapp:v 1
     volumeMounts:
     - name: html #存儲卷的名字叫html
       mountPath: /usr/share/nginx/html/ #掛載路徑
   volumes:
   - name: html
     persistentVolumeClaim:
       claimName: mypvc #表示我要使用哪一個pvc
1
2
3
[root@master volumes]# kubectl apply -f pod-vol-pvc.yaml 
persistentvolumeclaim/mypvc created
pod/pod-vol-pvc created
1
2
3
4
5
6
7
[root@master volumes]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM           STORAGECLASS   REASON    AGE
pv 001      1 Gi        RWO,RWX        Retain           Available                                             7 h
pv 002      2 Gi        RWO            Retain           Available                                             7 h
pv 003      1 Gi        RWO,RWX        Retain           Available                                             7 h
pv 004      1 Gi        RWO,RWX        Retain           Bound        default /mypvc                             7 h
pv 005      1 Gi        RWO,RWX        Retain           Available                                             7 h

    上面看到pv004被default名稱空間的mypvc綁定了。 

1
2
3
[root@master volumes]# kubectl get pvc
NAME      STATUS    VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc     Bound     pv 004      1 Gi        RWO,RWX                        33 m
1
2
3
4
[root@master volumes]# kubectl get pods 
NAME                             READY     STATUS             RESTARTS   AGE
client                            0 / 1        Error               0           16 d
pod-vol-pvc                       1 / 1        Running             0           35 m

    生產上,pv並不屬於node節點,而是獨立於node節點的。因此,node節點壞了,pv裏面的數據還在。另外,pod纔是屬於node節點的。 

    在k8s 1.10以後,不能手工從底層刪除pv,這樣作很安全。 

 StorageClass(存儲類)

    Kubernetes集羣管理員經過提供不一樣的存儲類,能夠知足用戶不一樣的服務質量級別、備份策略和任意策略要求的存儲需求。動態存儲卷供應使用StorageClass進行實現,其容許存儲卷按需被建立。若是沒有動態存儲供應,Kubernetes集羣的管理員將不得不經過手工的方式類建立新的存儲卷。經過動態存儲卷,Kubernetes將可以按照用戶的須要,自動建立其須要的存儲。

    storageclass底層能夠是glusterfs,cephfs等不一樣的集羣。 

configmap   

    configmap和secret是兩種特殊的存儲卷,它們不是給pod提供存儲空間用的,而是給咱們的管理員或者用戶提供了從外部向pod內部注入信息的方式。

     configmap :把配置文件放在配置中心上,而後多個pod讀取配置中心的配置文件。不過,configmap中的配置信息都是明文的,因此不安全。 

      secret: 功能和configmap同樣,只不過配置中心存儲的配置文件不是明文的。

    configmap和secret也是專屬於某個名稱空間的。 

1
2
3
[root@master ~]# kubectl explain configmap
[root@master ~]# kubectl explain cm #簡寫
[root@master ~]# kubectl create configmap -- help

    簡單的咱們能夠用命令行來建立configmap。 

1
2
[root@master ~]# kubectl create configmap nginx-config --from-literal=nginx_port= 80  --from-literal=server_name=myapp.zhixin.com
configmap/nginx-config created
1
2
3
[root@master ~]# kubectl get cm
NAME           DATA      AGE
nginx-config    2          3 m
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@master ~]# kubectl describe cm nginx-config
Name:         nginx-config
Namespace:     default
Labels:       < none >
Annotations:  < none >
Data
====
nginx_port:
----
80
server_name:
----
myapp.zhixin.com

    下面咱們用配置清單的方式來建立configmap: 

1
2
3
4
5
6
[root@master configmap]# cat www.conf 
server {
       server_name myapp.zhixin.com;
       listen 
相關文章
相關標籤/搜索