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

店家小二發表於2018-12-17

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

Docker

DockerK8S

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

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

Docker基礎

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

# 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程式:

/ # 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 images|grep busybox
docker.io/busybox latest 8ac48589692a 5 weeks ago 1.146 MB

​ 通過本節,我們瞭解了3個Docker基本要素:映象倉庫(Registry)中儲存了映象(Image),而映象(Image)包含了程式執行所需的軟體環境,當部署容器(Container)時,映象(Image)通過網路被拉取到Doker主機(Node)

Kubernetes

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

Pod

K8SPod為最小單位來排程並管理Docker容器(Container),其中1個Pod可含多個容器,且相同Pod裡的容器共享本地網路,容器間可通過localhost地址互訪,即容器如同部署在相同的主機上,而以Pod為最小單元來排程則表明:Pod內的容器被排程到相同的Docker節點上。

​ 如下所示,建立一名為myhttpPod,其包含一個使用httpd映象部署的容器,容器名為myhttp

# 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


相關文章