kubernetes內部組件工作原理 http://dockone.io/article/5108
Master
Master是整個集群的控制中心,kubernetes的所有控制指令都是發(fā)給master,它負責具體的執(zhí)行過程。一般我們會把master獨立于一臺物理機或者一臺虛擬機,它的重要性不言而喻。
master上有這些關鍵的進程:
Kubernetes API Server(kube-apiserver),提供了HTTP Rest接口關鍵服務進程,是所有資源增、刪、改、查等操作的唯一入口,也是集群控制的入口進程。
Kubernetes Controller Manager(kube-controlker-manager),是所有資源對象的自動化控制中心,可以理解為資源對象的大總管。
Kubernetes Scheduler(kube-scheduler),負責資源調度(pod調度)的進程,相當于公交公司的“調度室”。 etcd Server,kubernetes里所有資源對象的數據都是存儲在etcd中的。
Node
除了Master,Kubernetes集群中其他機器被稱為Node,早期版本叫做Minion。Node可以是物理機也可以是虛擬機,每個 Node上會被分配一些工作負載(即,docker容器),當Node宕機后,其上面跑的應用會被轉移到其他Node上。
Node上有這些關鍵進程: kubelet:負責Pod對應容器的創(chuàng)建、啟停等任務,同時與Master節(jié)點密切協作,實現集群管理的基本功能。 kube-proxy:實現Kubernetes Service的通信與負載均衡機制的重要組件。 Docker Engine(docker):Docker引擎,負責本機容器的創(chuàng)建和管理。
kubectl get nodes #查看集群中有多少個node kubectl describe node
Pod
查看pod命令: kubectl get pods 查看容器命令: docker ps
可以看到容器和pod是有對應關系的,在我們做過的實驗中,每個pod對應兩個容器,一個是Pause容器,一個是rc里面定義的容器(實際上,每個pod里可以有多個應用容器)。這個Pause容器叫做“根容器”,只有當Pause容器“死亡”才會認為該 pod“死亡”。Pause容器的IP以及其掛載的Volume資源會共享給該pod下的其他容器。
pod定義示例:
apiVersion: v1 kind: pod metadata: name: myweb labels: name: myweb spec: containers: - name: myweb image: kubeguide/tomcat-app:v1 ports: - containerPort: 8080 env: - name: MYSQL_SERVICE_HOST value: 'mysql' - name: MYSQL_SERVICE_PORT value: '3306'
每個pod都可以對其能使用的服務器上的硬件資源進行限制(CPU、內存)。CPU限定的最小單位是1/1000個cpu,用m表示,如100m,就是0.1個cpu。內存限定的最小單位是字節(jié),可以用Mi(兆) 表示,如128Mi就是128M。
在kubernetes里,一個計算資源進行配額限定需要設定兩個參數:
1) requests:該資源的最小申請量
2) Limits:該資源允許的最大使用量。
資源限定示例: spec:
spec: containers: - name: db image: mysql resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m"
Label
Label是一個鍵值對,其中鍵和值都由用戶自定義,Label可以附加在各種資源對象上,如Node、Pod、Service、RC等。一個資
源對象可以定義多個Label,同一個Label也可以被添加到任意數量的資源對象上。Label可以在定義對象時定義,也可以在對象創(chuàng)建完后動態(tài)添加或刪除。
Label示例:
"release":"stable", "environment":"dev", "tier":"backend"等等。
RC
RC是kubernetes中核心概念之一,簡單說它定義了一個期望的場景,即聲明某種pod的副本數量在任意時刻都符合某個預期值,RC定義了如下幾個部分:
1) pod期待的副本數
2) 用于篩選目標pod的Label Selector
3) 創(chuàng)建pod副本的模板(template)
RC一旦被提交到kubernetes集群后,Master節(jié)點上的Controller Manager組件就會接收到該通知,它會定期巡檢集群中存活的 pod,并確保pod數量符合RC的定義值。可以說通過RC,kubernetes實現了用戶應用集群的高可用性,并且大大減少了管理員在傳統(tǒng)IT環(huán)境中不得不做的諸多手工運維工作,比如編寫主機監(jiān)控腳本、應用監(jiān)控腳本、故障恢復處理腳本等
RC工作流程(假如,集群中有3個Node):
1) RC定義2個pod副本
2) 假設系統(tǒng)會在2個Node上(Node1和Node2)創(chuàng)建pod
3) 如果Node2上的pod(pod2)意外終止,這很有可能是因為Node2宕機
4) 則會創(chuàng)建一個新的pod,假設會在Node3上創(chuàng)建pod3,當然也有可能在Node1上創(chuàng)建pod3
RC中動態(tài)修改pod副本數量:
kubectl scale rc
利用動態(tài)修改pod的副本數,可以實現應用的動態(tài)升級(滾動升級):
1) 以新版本的鏡像定義新的RC,但pod要和舊版本保持一致(由Label決定)
2) 新版本每增加1個pod,舊版本就減少一個pod,始終保持固定的值
3) 最終舊版本pod數為0,全部為新版本
刪除RC
kubectl delete rc
刪除RC后,RC對應的pod也會被刪除掉
Deployment
在1.2版本引入的概念,目的是為了解決pod編排問題,在內部使用了Replica Set,它和RC比較,相似度為90%以上,可以認為是RC的升級版。 跟RC比較,最大的一個特點是可以知道pod部署的進度。
Deployment示例:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: frontend spec: replicas: 1 selector: matchLabels: tier: frontend matchExpressions: - {key: tier, operator: In, values: [frontend]} template: metadata: labels: app: app-demo tier: frontend spec: containers: - name: tomcat-demo image: tomcat imagePullPolicy: IfNotPresent ports: - containerPort: 8080
kubectl create -f tomcat-deployment.yaml kubectl get deployment
HPA(Horizontail Pod Autoscaler)
在1.1版本,kubernetes官方發(fā)布了HPA,實現pod的動態(tài)擴容、縮容,它屬于一種kubernetes的資源對象。它通過追蹤分析 RC控制的所有目標pod的負載變化情況,來決定是否需要針對性地調整目標Pod的副本數,這是HPA的實現原理。
pod負載度量指標:
1) CpuUtilizationPercentage
目標pod所有副本自身的cpu利用率平用均值。一個pod自身的cpu利用率=該pod當前cpu的使用量/pod Request值。如果某一個時刻,CPUUtilizationPercentage的值超過了80%,則判定當前的pod已經不夠支撐業(yè)務,需要增加pod。
2) 應用程序自定義的度量指標,比如服務每秒內的請求數(TPS或QPS)
HPA示例:
apiVerion: autosacling/v1 kind: HorizontalPodAutoscaler metadata: name: php-apache namespace: default spec: maxReplicas: 10 minReplicas: 1 scaleTargetRef: kind: Deployment name: php-apache targetCPUUtilizationPercentage: 90
說明:HPA控制的目標對象是一個名叫php-apache的Deployment里的pod副本,當cpu平均值超過90%時就會擴容,pod副本 數控制范圍是1-10.
除了以上的xml文件定義HPA外,也可以用命令行的方式來定義:
kubectl autoscale deployment php-apache --cpu-percent=90 --min=1 --max=10
Service
Service是kubernetes中最核心的資源對象之一,Service可以理解成是微服務架構中的一個“微服務”,pod、RC、 Deployment都是為Service提供嫁衣的。
簡單講一個service本質上是一組pod組成的一個集群,前面我們說過service和pod之間是通過Label來串起來的,相同Service的 pod的Label一樣。同一個service下的所有pod是通過kube-proxy實現負載均衡,而每個service都會分配一個全局唯一的虛擬 ip,也叫做cluster ip。在該service整個生命周期內,cluster ip是不會改變的,而在kubernetes中還有一個dns服務,它把 service的name和cluster ip映射起來。
service示例:(文件名tomcat-service.yaml)
apiVersion: v1 kind: Service metadata: name: tomcat-service spec: ports: - port: 8080 selector: tier: frontend
kubectl create -f tomcat-service.yaml kubectl get endpoints //查看pod的IP地址以及端口 kubectl get svc tomcat-service -o yaml //查看service分配的cluster ip
多端口的service
apiVersion: v1 kind: Service metadata: name: tomcat-service spec: ports: - port: 8080 name: service-port - port: 8005 name: shutdown-port selector: tier: frontend
對于cluster ip有如下限制:
1) Cluster ip無法被ping通,因為沒有實體網絡來響應
2) Cluster ip和Service port組成了一個具體的通信端口,單獨的Cluster ip不具備TCP/IP通信基礎,它們屬于一個封閉的空間。
3) 在kubernetes集群中,Node ip、pod ip、cluster ip之間的通信,采用的是kubernetes自己設計的一套編程方式的特殊路由規(guī)則。
要想直接和service通信,需要一個Nodeport,在service的yaml文件中定義:
apiVersion: v1 kind: Service metadata: name: tomcat-service spec: ports: - port: 8080 nodeport: 31002 selector: tier: frontend
它實質上是把cluster ip的port映射到了node ip的nodeport上了
Volume(存儲卷)
Volume是pod中能夠被多個容器訪問的共享目錄,kubernetes中的volume和docker中的volume不一樣,主要有以下幾個方 面: 1)kubernetes的volume定義在pod上,然后被一個pod里的多個容器掛載到具體的目錄下 2)kubernetes的volume與pod生命周期相同,但與容器的生命周期沒關系,當容器終止或者重啟時,volume中的數據并不會 丟失 3)kubernetes支持多種類型的volume,如glusterfs,ceph等先進的分布式文件系統(tǒng)
如何定義并使用volume呢?只需要在定義pod的yaml配置文件中指定volume相關配置即可:
template: metadata: labels: app: app-demo tier: frontend spec: volumes: - name: datavol emptyDir: {} containers: - name: tomcat-demo image: tomcat volumeMounts: - mountPath: /mydata-data name: datavol imagePullPolicy: IfNotPresent
說明: volume名字是datavol,類型是emptyDir,將volume掛載到容器的/mydata-data目錄下
volume的類型:
1)emptyDir 是在pod分配到node時創(chuàng)建的,初始內容為空,不需要關心它將會在宿主機(node)上的哪個目錄下,因為這是kubernetes自 動分配的一個目錄,當pod從node上移除,emptyDir上的數據也會消失。所以,這種類型的volume不適合存儲永久數據,適合 存放臨時文件。
2)hostPath hostPath指定宿主機(node)上的目錄路徑,然后pod里的容器掛載該共享目錄。這樣有一個問題,如果是多個node,雖然目 錄一樣,但是數據不能做到一致,所以這個類型適合一個node的情況。
配置示例:
volumes: - name: "persistent-storage" hostPath: path: "/data"
3)gcePersistentDisk 使用Google公有云GCE提供的永久磁盤(PD)存儲volume數據。毫無疑問,使用gcePersistentDisk的前提是kubernetes的 node是基于GCE的。
配置示例:
volumes: - name: test-volume gcePersistentDisk: pdName: my-data-disk fsType: ext4
4)awsElasticBlockStore
與GCE類似,該類型使用亞馬遜公有云提供的EBS Volume存儲數據,使用它的前提是Node必須是aws EC2。
5) NFS使用NFS作為volume載體。
示例:
volumes: - name: "NFS" NFS: server: ip地址 path: "/"
6) 其他類型
iscsi flocker glusterfs
rbd
gitRepo: 從git倉庫clone一個git項目,以供pod使用 secret: 用于為pod提供加密的信息
persistent volume(PV)
PV可以理解成kubernetes集群中某個網絡存儲中對應的一塊存儲,它與volume類似,但有如下區(qū)別:
1) PV只能是網絡存儲,不屬于任何Node,但可以在每個Node上訪問到
2) PV并不是定義在pod上,而是獨立于pod之外定義
3) PV目前只有幾種類型:GCE Persistent Disk、NFS、RBD、iSCSCI、AWS ElasticBlockStore、GlusterFS
如下是NFS類型的PV定義:
apiVersion: v1 kind: PersistentVolumemetadata: name: pv0003 spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce nfs: path: /somepath server: ip
其中accessModes是一個重要的屬性,目前有以下類型:
ReadWriteOnce: 讀寫權限,并且只能被單個Node掛載
eadOnlyMany: 只讀權限,允許被多個Node掛載
ReadWriteMany:讀寫權限,允許被多個Node掛載如果某個pod想申請某種條件的PV,首先需要定義一個PersistentVolumeClaim(PVC)對象:
kind: persistentVolumeClaim apiVersion: v1 metadata: name: myclaim spec: accessModes: - ReadWriteOnce resources: requests: storage: 8Gi
然后在pod的vomume定義中引用上面的PVC:
volumes: - name: mypd persistentVolumeClaim: ClaimName: myclaim
Namespace(命名空間)
當kubernetes集群中存在多租戶的情況下,就需要有一種機制實現每個租戶的資源隔離。而namespace的目的就是為了實現資源隔離。
kubectl get namespace //查看集群所有的namespace
定義namespace:
apiVersion: v1 kind: Namespace metadata: name: dev
kubectl create -f dev-namespace.yaml //創(chuàng)建dev namespace
apiVersion: v1 kind: Pod metadata: name: busybox namespace: dev spec: containers: - image: busybox command: - sleep - "500" name: busybox
然后再定義pod,指定namespace 查看某個namespace下的pod:
kubectl get pod --namespace=dev