邁入Docker、Kubernetes容器世界的大門

說明

​ 本文經過簡單的示例,帶領初學者快速邁入DockerKubernetes(K8S)容器世界的大門。假設,你已擁有一個K8S集羣,不然,可經過minikubeminishift快速搭建一實驗環境。html

Docker

DockerK8S

Docker本質上是一種虛擬化技術,相似於KVMXENVMWARE,但其更輕量化,且將Docker部署在Linux環境時,其依賴於Linux容器技術(LXC)。Docker較傳統KVM等虛擬化技術的一個區別是無內核,即多個Docker虛擬機共享宿主機內核,簡而言之,可把Docker看做是無內核的虛擬機,每Docker虛擬機有本身的軟件環境,相互獨立。node

K8SDocker之間的關係,如同Openstack之於KVMVSphere之於VMWAREK8S是容器集羣管理系統,底層容器虛擬化可以使用Docker技術,應用人員無需與底層Docker節點直接打交道,經過K8S統籌管理便可。linux

Docker基礎

​ 以下所示,運行docker run -it --name test-docker busybox /bin/sh命令,觀察其輸出,可發現docker先在本地查找名爲busybox鏡像(Image)1,若本地無鏡像,則從docker.io官方鏡像庫(Registry)下載鏡像後保存到本地,接着以此鏡像構建一個名爲test-docker虛擬機,其Docker官方術語命名爲容器(Container)nginx

# docker run -it --name test-docker busybox /bin/sh
Unable to find image 'busybox:latest' locally
Trying to pull repository docker.io/library/busybox ... 
latest: Pulling from docker.io/library/busybox
f70adabe43c0: Pull complete 
Digest: sha256:186694df7e479d2b8bf075d9e1b1d7a884c6de60470006d572350573bfa6dcd2
/ #

Docker較傳統KVMVMware虛擬機更輕量,以下所示,test-docker容器不會運行額外的系統與內核進程,其僅運行docker run命令提供的/bin/sh進程:web

/ # ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
    7 root      0:00 ps -ef

​ 如在Openstack中建立虛擬機,首先需在Glance鏡像庫中存儲虛擬機鏡像,然後才能選擇鏡像以建立虛擬機。Docker同理,且官方提供一共享的鏡像倉庫(Registry),其中存儲了各式各樣的鏡像(Image)。如本例用busybox鏡像建立容器,其鏡像被拉(pull)到了本地,可執行以下命令檢查發現其僅1MB左右,至關輕量。docker

# docker images|grep busybox
docker.io/busybox         latest              8ac48589692a        5 weeks ago         1.146 MB

​ 經過本節,咱們瞭解了3個Docker基本要素:鏡像倉庫(Registry)中存儲了鏡像(Image),而鏡像(Image)包含了程序運行所需的軟件環境,當部署容器(Container)時,鏡像(Image)經過網絡被拉取到Doker主機(Node)shell

Kubernetes

K8SGoogle開源容器集羣管理系統,其源於Google內部管理系統Borg,如下將經過一個個簡單連貫的示例,帶領初學者熟悉K8S集羣。apache

Pod

K8SPod爲最小單位來調度並管理Docker容器(Container),其中1個Pod可含多個容器,且相同Pod裏的容器共享本地網絡,容器間可經過localhost地址互訪,即容器如同部署在相同的主機上,而以Pod爲最小單元來調度則代表:Pod內的容器被調度到相同的Docker節點上。後端

​ 以下所示,建立一名爲myhttpPod,其包含一個使用httpd鏡像部署的容器,容器名爲myhttpcentos

# cat > /tmp/myhttpd.pod <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: myhttp
  labels:
    app: myhttp
spec:
  containers:
  - name: myhttp
    image: httpd
EOF
% kubectl create -f /tmp/myhttpd.pod

​ 執行kubectl get pod命令觀察Pod運行成功後,接着驗證容器能提供web服務:

# kubectl get pod
NAME         READY     STATUS    RESTARTS   AGE
myhttp       1/1       Running   0          1h
# kubectl describe pod myhttp|grep IP
IP:           10.129.0.232
# curl 10.129.0.232
<html><body><h1>It works!</h1></body></html>

Deployment

​ 將應用直接以Pod形式部署不多見,主因是:Pod沒法提供彈性伸縮,且節點故障時K8S沒法將其調度到倖存節點上,缺乏自愈能力。鑑於此,應用常使用「鏡像(Rc)/部署(Deployment)」部署,且在K8S新版本中,官方推薦用Deployment替代Rc部署無狀態(Stateless)應用。

​ 執行kubectl delete pod myhttp刪除pod後,換成以Deployment部署:

# cat > myhttp.yaml <<EOF 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: myhttp
  name: myhttp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myhttp
  template:
    metadata:
      labels:
        app: myhttp
    spec:
      containers:
      - image: httpd
        name: myhttp
EOF
# kubectl create -f /tmp/myhttp.yaml

Deployment中的.spec.replicas代表部署多少個Pod,如本例當前僅含一Pod

# kubectl get deploy,pod
NAME            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/myhttp   1         1         1            1           2m

NAME                         READY     STATUS    RESTARTS   AGE
po/myhttp-7bc6d8b87c-gzlkq   1/1       Running   0          2m

​ 執行kubectl delete pod <pod_name>刪除Pod後,可發現deployment將自動重建pod,其將確保擁有.spec.replicaspod數量,即意味着,當pod異常時,deployment具有自愈特性。

# kubectl delete pod myhttp-7bc6d8b87c-gzlkq

# kubectl get pod -w
NAME                      READY     STATUS              RESTARTS   AGE
myhttp-7bc6d8b87c-dhmtz   0/1       ContainerCreating   0          2s
myhttp-7bc6d8b87c-dhmtz   1/1       Running             0          8s
myhttp-7bc6d8b87c-gzlkq   1/1       Terminating         0          8m

​ 當需伸縮或擴展應用時,若以Pod形式部署,則需刪除或建立Pod,而若使用Deployment部署,則咱們僅需調整.spec.replicas,然後K8S鏡像控制器將自動調整Pod數量。以下所示,擴展http應用爲2服務:

# kubectl scale deploy/myhttp --replicas=2

# kubectl get pod -w
NAME                      READY     STATUS              RESTARTS   AGE
myhttp-7bc6d8b87c-cj4g8   0/1       ContainerCreating   0          3s
myhttp-7bc6d8b87c-zsbcc   1/1       Running             0          8m
myhttp-7bc6d8b87c-cj4g8   1/1       Running   0         18s

# kubectl get deploy
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
myhttp    2         2         2            2           21m

​ 執行kubectl delete pod <pod_name>刪除Pod後,可發現Pod名(即容器主機名)及IP是隨機分配的,那麼,咱們該如何訪問應用?

# kubectl get pod
# kubectl describe pod myhttp-7bc6d8b87c-cj4g8|grep IP
IP:             10.129.3.28

Service

Service服務相似於傳統的F5A10等硬件負載均衡,但其在K8S中經過軟件實現,且當伸縮應用時可實時跟蹤後端Server,無需人爲調整。

內部訪問


咱們將對上節部署的myhttp應用建立一個Service服務,但在此前,先建立一個Pod做爲集羣內部客戶端以用於後續Service驗證。因下面驗證Svc將使用curl工具,而官方centos鏡像包含此工具,故用此鏡像建立Pod,且爲保證Pod一直運行不退出,使用了command在前臺執行了無限循環命令。

# kubectl create -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: myclient
  labels:
    app: myclient
spec:
  containers:
  - name: myclient
    image: centos
    command: ['sh','-c','while true; do sleep 3600; done;']
EOF

​ 執行以下命令爲myhttp應用建立一個myhttp-int的服務:

# kubectl expose deployment myhttp --port=8080 --target-port=80 --name=myhttp-int
service "myhttp-int" exposed

​ 上面命令等價於使用下面的Yaml文件手動建立Service:建立名爲myhttp-int的服務,其8080端口指向後端服務的80端口,然後端服務是經過selector選擇label(標籤)app:myhttpPod,觀察myhttp Deployment,可發現.spec.template.metadata.labels定義的標籤就是app:myhttp,故而,經過myhttp-int:8080便可訪問myhttp服務。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: myhttp
  name: myhttp-int
spec:
  clusterIP:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 80
  selector:
    app: myhttp
  sessionAffinity: None

​ 在測試容器中經過myhttp-int:8080訪問Service,可發現將負載均衡到後端的兩pod上:

# kubectl get pod
NAME                      READY     STATUS    RESTARTS   AGE
myclient                  1/1       Running   0          1h
myhttp-7bc6d8b87c-cj4g8   1/1       Running   0          1d
myhttp-7bc6d8b87c-zsbcc   1/1       Running   0          1d

# 重置web主頁,輸出每Pod名稱以便後續觀察
# kubectl exec myhttp-7bc6d8b87c-cj4g8 -it -- sh -c "hostname>htdocs/index.html"
# kubectl exec myhttp-7bc6d8b87c-zsbcc -it -- sh -c "hostname>htdocs/index.html"

# kubectl exec -it myclient -- curl myhttp-int:8080
myhttp-7bc6d8b87c-cj4g8
# kubectl exec -it myclient -- curl myhttp-int:8080
myhttp-7bc6d8b87c-zsbcc

​ 當伸縮Pod時,咱們可經過以下命令觀察到Service將動態跟蹤後端(Endpoints)服務:

# kubectl get endpoints myhttp-int
NAME         ENDPOINTS                        AGE
myhttp-int   10.129.0.237:80,10.129.3.28:80   1h

# kubectl scale deploy myhttp --replicas=3
# kubectl get endpoints myhttp-int
NAME         ENDPOINTS                                        AGE
myhttp-int   10.129.0.237:80,10.129.3.28:80,10.131.0.194:80   1h

外部訪問


​ 若應用需向K8S集羣外提供服務,則可建立類型爲NodePortService,此時K8S集羣上全部節點均監聽nodePort指定的端口,故外部應用可經過集羣中任一節點訪問集羣內部提供的服務。

# kubectl create -f - <<EOF 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: myhttp
  name: myhttp-pub
spec:
  type: NodePort
  ports:
  - port: 8080
    nodePort: 30001
    protocol: TCP
    targetPort: 80
  selector:
    app: myhttp
  sessionAffinity: None
EOF

​ 執行以下命令檢查服務,發現一個爲ClusterIP類型,一個爲NodePort類型,但二者均分配了ClusterIP地址:

# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
myhttp-int   ClusterIP   172.30.37.43   <none>        8080/TCP         1h
myhttp-pub   NodePort    172.30.6.69    <none>        8080:30001/TCP   3m

myhttp-pub服務經過nodePort打開了集羣各節點的主機端口,此時可經過集羣任何節點訪問服務:

# curl 192.168.220.21:30001
myhttp-7bc6d8b87c-zsbcc
# curl 192.168.230.21:30001
myhttp-7bc6d8b87c-zsbcc
# curl 192.168.240.21:30001
myhttp-7bc6d8b87c-cj4g8

​ 經過NodePort類型的Service雖可將服務暴露到集羣外部,但問題是:端口數量有限(限制爲30000-32767)、節點故障後,經過此節點訪問服務將失敗。鑑於此緣由,NodePort類型的Service不經常使用,而是換成使用Ingress的技術來暴露服務到集羣外部,但爲簡單考慮,本文再也不講解Ingress

Configmap

​ 當容器異常時,鏡像控制器用Image重建Container,此時對容器的修改會丟失,故而,若需自定義httpd鏡像的httpd.conf文件,咱們不該直接登陸各容器修改配置,而應考慮使用K8S提供的Configmap2技術,其做爲中央存儲配置庫所建立的文件將Pod共享。

​ 以下所示,爲簡單考慮,咱們隨意建立一文件並掛載到Deployment中,修改Configmap,擴展Deployment,用此來說解Configmap做用。

建立一名爲my-configcm3


# kubectl create -f  - <<EOF
apiVersion: v1
metadata:
  name: my-config
data:
  hosts: |
       127.0.0.1   localhost localhost.localdomain
       #::1        localhost localhost.localdomain
kind: ConfigMap
EOF

執行kubectl edit deploy myhttp修改Deployment,將cm掛載到/etc/myhosts目錄中。完整Yaml文件以下(PS:添加volumeMountsvolume):


apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: myhttp
  name: myhttp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myhttp
  template:
    metadata:
      labels:
        app: myhttp
    spec:
      containers:
      - image: httpd
        name: myhttp
        volumeMounts:
        - name: config-hosts
          mountPath: /etc/myhosts
      volumes:
      - name: config-hosts
        configMap:
          name: my-config

​ 修改Deploy後,可發現Pod將自動重建,然後檢查每Pod可發現目錄中含有cmhosts文件:

# kubectl get pod
NAME                      READY     STATUS    RESTARTS   AGE
myhttp-774ffbb989-gz6bd   1/1       Running   0          11m
myhttp-774ffbb989-k8m4b   1/1       Running   0          11m
myhttp-774ffbb989-t74nk   1/1       Running   0          11m

# kubectl exec -it myhttp-774ffbb989-gz6bd  -- ls /etc/myhosts
hosts
# kubectl exec -it myhttp-774ffbb989-gz6bd  -- cat /etc/myhosts/hosts
127.0.0.1   localhost localhost.localdomain
#::1        localhost localhost.localdomain

修改cm,幾分鐘後,可發現pod中的配置被自動更新:


# kubectl edit cm my-config
...
data:
  hosts: |
    127.0.0.1   localhost localhost.localdomain
    ::1        localhost localhost.localdomain
...

# kubectl exec -it myhttp-774ffbb989-gz6bd  -- cat /etc/myhosts/hosts
127.0.0.1   localhost localhost.localdomain
::1        localhost localhost.localdomain

擴展應用,繼而檢查新的Pod,發現其包含cm內容:


# kubectl scale deploy myhttp --replicas=4
# kubectl get pod
myhttp-774ffbb989-gz6bd   1/1       Running   0          15h
myhttp-774ffbb989-k8m4b   1/1       Running   0          15h
myhttp-774ffbb989-t74nk   1/1       Running   0          15h
myhttp-774ffbb989-z5d6h   1/1       Running   0          21s

# kubectl exec -it myhttp-774ffbb989-z5d6h  -- cat /etc/myhosts/hosts
127.0.0.1   localhost localhost.localdomain
::1        localhost localhost.localdomain

Secret

​ 相較於Configmap用於保存明文,那麼Secret則保存密文,如用戶密碼等銘感數據,可以使用Secret加密保存。以下所示,咱們建立一個Secret加密用戶與密碼,然後提供給容器使用。

OpaqueSecret數據是一個map類型,要求valuebase64編碼格式。加密用戶與密碼:


# echo -n root | base64
cm9vdA==
# echo -n Changeme | base64
Q2hhbmdlbWU=

建立名爲userpwd-secretSecret,其包含用戶與密碼:


#  kubectl create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: userpwd-secret
type: Opaque
data:
  username: cm9vdA==
  password: Q2hhbmdlbWU=
EOF

更新deployment,將secretvolume方式掛載到容器中:


# kubectl edit deployment myhttp
...
spec:
...
    spec:
      containers:
      - image: httpd
      ...
        volumeMounts:
        - name: userpwd
          mountPath: /etc/mysecret
      ...
      volumes:
      - name: userpwd
        secret:
          secretName: userpwd-secret
...

登陸容器可發現secret中的key被保存爲文件,其內容爲value,但在容器內已被正確解密:


# kubectl exec -it myhttp-64575c77c-kqdj9 -- ls -l /etc/mysecret
lrwxrwxrwx. 1 root root 15 May 17 07:01 password -> ..data/password
lrwxrwxrwx. 1 root root 15 May 17 07:01 username -> ..data/username

# kubectl exec -it myhttp-64575c77c-kqdj9 -- cat /etc/mysecret/username
root

Storage

​ 咱們將web應用保存到外部存儲中,然後掛載到Pod上,這樣,不管pod是否重建亦或伸縮,咱們發佈的應用都不會丟失。

配置NFS存儲

爲簡單考慮,本例採用NFS做爲共享存儲:

nfs服務器安裝軟件:

# yum install nfs-utils

配置共享目錄:

# mkdir -p /exports/httpd
# chmod 0777 /exports/*
# chown nfsnobody:nfsnobody /exports/*
# cat > /etc/exports.d/k8s.exports <<EOF
/exports/httpd *(rw,root_squash)
EOF

配置防火牆,放行nfs端口:

# firewall-cmd --add-port=2049/tcp
# firewall-cmd --permanent --add-port=2049/tcp

配置Selinux以容許Docker寫數據到nfs

# getsebool -a|grep virt_use_nfs
# setsebool -P virt_use_nfs=true

啓動nfs服務:

# systemctl restart nfs-config
# systemctl restart nfs-server
# systemctl enable nfs-server

K8S集羣使用存儲

K8S集羣每節點安裝nfs客戶端軟件,並設置Selinux權限:

# yum install nfs-utils
# setsebool -P virt_use_nfs=true

建立一類型爲nfs的持久化卷:PersistentVolume(PV),其指向nfs後端存儲:

# kubectl create -f - <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
  name: httpd
spec:
  accessModes:
  - ReadWriteMany
  capacity:
    storage: 1Gi
  nfs:
    path: /exports/httpd
    server: 192.168.240.11
  persistentVolumeReclaimPolicy: Retain
EOF

建立一持久化卷聲明PersistentVolumeClaim(PVC)指向上一步建立的PV

# kubectl create -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: httpd
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  volumeName: httpd
EOF

檢查可發現pvc/httpd綁定到pv/httpd

# oc get pv,pvc
NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM   ...   
pv/httpd     1Gi        RWX            Retain           Bound    demo/httpd  ...

NAME         STATUS    VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc/httpd    Bound     httpd     1Gi        RWX                           53s

重建deployment,添加volumemount掛載點:

# kubectl delete deploy myhttp
# kubectl create -f - <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: myhttp
  name: myhttp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myhttp
  template:
    metadata:
      labels:
        app: myhttp
    spec:
      containers:
      - image: httpd
        name: myhttp
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: config-hosts
          mountPath: /etc/myhosts
        - name: userpwd
          mountPath: /etc/mysecret
        - name: httpd-htdocs
          mountPath: /usr/local/apache2/htdocs
      volumes:
      - name: config-hosts
        configMap:
          name: my-config
      - name: userpwd
        secret:
          secretName: userpwd-secret
      - name: httpd-htdocs
        persistentVolumeClaim:
          claimName: httpd
EOF

Pod生成後,檢查發現nfs目錄被掛載到容器內:

# kubectl get pod
# kubectl exec -it myhttp-8699b7d498-dlzrm -- df -h
Filesystem                       Size  Used Avail Use% Mounted on
...
192.168.240.11:/exports/httpd    37G   17G   21G  44% /usr/local/apache2/htdocs               ...
# kubectl exec -it myhttp-8699b7d498-dlzrm -- ls htdocs       # 當前目錄爲空

登陸任何一個容器,將web應用發佈到htdocs目錄:

# kubectl exec -it myhttp-8699b7d498-dlzrm -- /bin/sh
# echo "this is a test of pv" > htdocs/index.html             # 容器內

然後,咱們刪除容器亦或擴展容器,均會發現容器中的htdocs包含所發佈的應用:

# kubectl delete pod -l app=myhttp                            # 刪除全部myhttp pod
# kubectl get pod                                             # 等待pod重建完畢
# kubectl exec -it myhttp-8699b7d498-6q8tv -- cat htdocs/index.html
this is a test of pv

Satefulset

​ 如上面用Deplyment建立的myhttp應用,其是無狀態(stateless)的,主機名是隨機動態分配的,且全部Pod可共享掛載相同的存儲(volume),但如KafakaZookeeper集羣,其是有狀態的,須要主機名肯定爲一,且各自掛載存儲,鑑於此,K8S提供了Satefulset技術來知足此類應用需求。

​ 以下所示,咱們使用nginx鏡像建立一個有狀態的集羣,用此來說解Statefulset用法。

不一樣於Deployment,咱們必須先建立一個ClusterIP: NoneService服務:

# kubectl create -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: web
  labels:
    app: nginx-web
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx-web
EOF

ServiceClusterIP,也即咱們沒法直接經過此Servcie訪問後端服務。

# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
web          ClusterIP   None           <none>        80/TCP           3s

建立名爲nginx的有狀態服務,鏡像數爲2,且注意ServiceName配置爲上步建立的Svc

# kubectl create -f - <<EOF
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: nginx
spec:
  serviceName: web
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx-web
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web
EOF

觀察pod啓動,可發現pod名稱爲nginx-n格式4,此名稱是固定惟一的,且可發現pod是順序啓動的,即容器nginx-nnginx-<n-1>後啓動。

# kubectl get pod -w
NAME                     READY     STATUS              RESTARTS   AGE
nginx-0                  0/1       ContainerCreating   0          7s
nginx-0                  1/1       Running             0          10s
nginx-1                  0/1       Pending             0          0s
nginx-1                  0/1       Pending              0          0s
nginx-1                   0/1       ContainerCreating   0          1s
nginx-1                    1/1       Running             0          13s

建立的servicestatefulset用在dns上以跟蹤pod名稱:

# kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
# 以下操做均在剛建立的dns-test pod中進行:

# nslookup web                            # 查找web服務,可發現後端有兩pod
...

Name:      web
Address 1: 10.129.0.248 nginx-0.web.demo.svc.cluster.local
Address 2: 10.131.0.200 nginx-1.web.demo.svc.cluster.local

# nslookup nginx-0.web                    # 驗證pod名稱對應的IP地址
...
Name:      nginx-0.web.demo.svc.cluster.local
Address 1: 10.129.0.248 nginx-0.web.demo.svc.cluster.local

# nslookup nginx-1.web
...
Name:      nginx-1.web.demo.svc.cluster.local
Address 1: 10.131.0.200 nginx-1.web.demo.svc.cluster.local

配置satefulset掛載volume

# kubectl delete statefulset nginx        # 爲簡單起見,刪除以上建立的statefulset
# kubectl create -f - <<EOF
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: nginx
spec:
  serviceName: web
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx-web
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: glusterfs-raid0
      resources:
        requests:
          storage: 10Mi
EOF

注意:在volumeClaimTemplates.spec中添加的storageClassName,其指定了名爲glusterfs-raid0的存儲,這樣,當pod生成時,k8s會使用動態提供5建立PVC、PV並自動從存儲池glusterfs-raid0中動態分配volume。固然,若使用Storage一節中配置的nfs存儲,則此處需刪除storageClassName,然後手動建立存儲、pv、pvc

檢查:

# 以下卷是k8s使用動態提供自動從glusterfs建立的:
# kubectl get pvc
NAME          STATUS    VOLUME                CAPACITY   ACCESS MODES   STORAGECLASS      AGE
www-nginx-0   Bound     pvc-4a76e4a9...       1Gi        RWO            glusterfs-raid0   22h
www-nginx-1   Bound     pvc-536e8980...       1Gi        RWO            glusterfs-raid0   22h

# kubectl get statefulset,pod
NAME                 DESIRED   CURRENT   AGE
statefulsets/nginx   2         2         22h

NAME                        READY     STATUS    RESTARTS   AGE
po/nginx-0                  1/1       Running   0          22h
po/nginx-1                  1/1       Running   0          22h

# 兩Pod掛載各自的卷:
# kubectl exec -it nginx-0 -- df -h
Filesystem                         Size  Used Avail Use% Mounted on              
192.168.220.21:vol_e6858...       1016M   33M  983M   4% /usr/share/nginx/html

# kubectl exec -it nginx-1 -- df -h
Filesystem                         Size  Used Avail Use% Mounted on              
192.168.220.21:vol_c659cc...       1016M   33M  983M   4% /usr/share/nginx/html

Namespace

​ 細心的讀者會在Storage一節中看到demo/httpd,此demo就是做者所使用的Namespace/Project6。如同Openstack雲計算平臺提供了多租戶用途,其每租戶可建立本身的Project(項目)K8S一樣提供多租戶功能,咱們可建立不一樣的Namespace(命名空間),並將以上所示的PodServiceConfigmap等限制在Namespace中。

​ 剛搭建的K8S集羣,默認有以下兩Namespace

# kubectl get namespace
NAME                                DISPLAY NAME   STATUS
default                                            Active         # 默認命名空間
kube-system                                        Active         # k8s自身使用的命名空間

​ 咱們可執行以下命令建立命名空間:

# kubectl create namespace demo
namespace "demo" created

​ 然後,執行kubectl命令時可附帶」-n <namespace>「參數。以下所示,查詢Pod

# kubectl get pod -n demo
NAME                     READY     STATUS    RESTARTS   AGE
nginx-0                  1/1       Running   0          23h
nginx-1                  1/1       Running   0          23h

​ 最後,對於Openshift平臺,咱們可執行以下命令登陸到Namespace中,這樣,咱們就無需每次附帶「-n <namespace>」了。

# oc project demo
# oc get pod
NAME                     READY     STATUS    RESTARTS   AGE
nginx-0                  1/1       Running   0          23h
nginx-1                  1/1       Running   0          23h

結束語

​ 經過本文,咱們學習了DockerK8S核心知識,我相信讀者應徹底能夠熟練使用K8S平臺了。


  1. 鏡像格式爲:<image_name>:<image_tag>,若不寫image_tag,則默認爲latest tag
  2. 參考官方文檔:Configure a Pod to Use a ConfigMap
  3. 內容爲key:value格式,且一個cm可包含多個
  4. statefulset名稱的生成規則是固定的:<statefulset-name>-n
  5. 存儲必須支持動態提供,如glusterfs存儲,要支持動態提供,必須配置heketi
  6. Openshift平臺,其Project即爲K8SNamespace
相關文章
相關標籤/搜索