Kubernetes應用部署模型解析(原理篇)
html
Kubernetes架構
前端
Kubernetes代理節點Kubelet和Kube-proxy運行在代理節點上。他們監聽服務節點的信息來啓動容器和實現Kubernetes網絡和其它業務模型,好比Service、Pod等。固然每一個代理節點都運行Docker。Docker負責下載容器鏡像和運行容器。
Kubelet
node
Kube-ProxyKube-proxy是一個簡單的網絡代理和負載均衡器。它具體實現Service模型,每一個Service都會在全部的Kube-proxy節點上體現。根據Service的selector所覆蓋的Pods, Kube-proxy會對這些Pods作負載均衡來服務於Service的訪問者。
Kubernetes服務節點Kubernetes服務組件造成了Kubernetes的控制平面,目前他們運行在單一節點上,可是未來會分開來部署,以支持高可用性。
etcd全部的持久性狀態都保存在etcd中。Etcd同時支持watch,這樣組件很容易獲得系統狀態的變化,從而快速響應和協調工做。
Kubernetes API Server這個組件提供對API的支持,響應REST操做,驗證API模型和更新etcd中的相應對象。
Scheduler經過訪問Kubernetes中/binding API, Scheduler負責Pods在各個節點上的分配。Scheduler是插件式的,Kubernetes未來能夠支持用戶自定義的scheduler。
Kubernetes Controller Manager ServerController Manager Server負責全部其它的功能,好比endpoints控制器負責Endpoints對象的建立,更新。node控制器負責節點的發現,管理和監控。未來可能會把這些控制器拆分而且提供插件式的實現。
Kubernetes模型Kubernetes的偉大之處就在於它的應用部署模型,主要包括Pod、Replication controller、Label和Service。
PodKubernetes的最小部署單元是Pod而不是容器。做爲First class API公民,Pods能被建立,調度和管理。簡單地來講,像一個豌豆莢中的豌豆同樣,一個Pod中的應用容器同享同一個上下文:
nginx
Replication controller複製控制器確保Pod的必定數量的份數(replica)在運行。若是超過這個數量,控制器會殺死一些,若是少了,控制器會啓動一些。控制器也會在節點失效、維護的時候來保證這個數量。因此強烈建議即便咱們的份數是1,也要使用複製控制器,而不是直接建立Pod。
git
ServiceService定義了一個Pod的邏輯集合和訪問這個集合的策略。集合是經過定義Service時提供的Label選擇器完成的。舉個例子,咱們假定有3個Pod的備份來完成一個圖像處理的後端。這些後端備份邏輯上是相同的,前端不關心哪一個後端在給它提供服務。雖然組成這個後端的實際Pod可能變化,前端客戶端不會意識到這個變化,也不會跟蹤後端。Service就是用來實現這種分離的抽象。
github
Service Cluster IP和 kuber proxy每一個代理節點都運行了一個kube-proxy進程。這個進程從服務進程那邊拿到Service和Endpoint對象的變化。 對每個Service, 它在本地打開一個端口。 到這個端口的任意鏈接都會代理到後端Pod集合中的一個Pod IP和端口。在建立了服務後,服務Endpoint模型會體現後端Pod的 IP和端口列表,kube-proxy就是從這個endpoint維護的列表中選擇服務後端的。另外Service對象的sessionAffinity屬性也會幫助kube-proxy來選擇哪一個具體的後端。缺省狀況下,後端Pod的選擇是隨機的。能夠設置service.spec.sessionAffinity 成"ClientIP"來指定同一個ClientIP的流量代理到同一個後端。在實現上,kube-proxy會用IPtables規則把訪問Service的Cluster IP和端口的流量重定向到這個本地端口。下面的部分會講什麼是service的Cluster IP。
web
內部使用者的服務發現Kubernetes在一個集羣內建立的對象或者在代理集羣節點上發出訪問的客戶端咱們稱之爲內部使用者。要把服務暴露給內部使用者,Kubernetes支持兩種方式:環境變量和DNS。
環境變量當kubelet在某個節點上啓動一個Pod時,它會給這個Pod的容器爲當前運行的Service設置一系列環境變量,這樣Pod就能夠訪問這些Service了。通常地狀況是{SVCNAME}_SERVICE_HOSTh和{SVCNAME}_SERVICE_PORT變量, 其中{SVCNAME}是Service名字變成大寫,中劃線變成下劃線。好比Service "Redis-master",它的端口是 TCP 6379,分配到的Cluster IP地址是 10.0.0.11,kubelet可能會產生下面的變量給新建立的Pod容器:
docker
DNS一個可選的Kubernetes附件(強烈建議用戶使用)是DNS服務。它跟蹤集羣中Service對象,爲每一個Service對象建立DNS記錄。這樣全部的Pod就能夠經過DNS訪問服務了。
ubuntu
Pod IP and Service Cluster IPPod IP 地址是實際存在於某個網卡(能夠是虛擬設備)上的,但Service Cluster IP就不同了,沒有網絡設備爲這個地址負責。它是由kube-proxy使用Iptables規則從新定向到其本地端口,再均衡到後端Pod的。咱們前面說的Service環境變量和DNS都使用Service的Cluster IP和端口。
後端
外部訪問ServiceService對象在Cluster IP range池中分配到的IP只能在內部訪問,若是服務做爲一個應用程序內部的層次,仍是很合適的。若是這個Service做爲前端服務,準備爲集羣外的客戶提供業務,咱們就須要給這個服務提供公共IP了。
Label和Label selectorLabel標籤在Kubernetes模型中佔着很是重要的做用。Label表現爲key/value對,附加到Kubernetes管理的對象上,典型的就是Pods。它們定義了這些對象的識別屬性,用來組織和選擇這些對象。Label能夠在對象建立時附加在對象上,也能夠對象存在時經過API管理對象的Label。
environment = productiontier != frontendenvironment = production,tier != frontend
environment in (production, qa)tier notin (frontend, backend)partition
一個簡單的應用
部署Kubernetes集羣
$ git clone https://github.com/GoogleCloudPlatform/kubernetes.git
cd kubernetes./build/run.sh hack/build-do.sh
gongysh@fedora20:~/git/kubernetes/cluster/ubuntu$ cat config-default.sh#!/bin/bash# Define all your cluster nodes, MASTER node comes first"# And separated with blank space like <user_1@ip_1> <user_2@ip_2> <user_3@ip_3>export nodes="gongysh@192.168.0.201 gongysh@192.168.0.202 gongysh@192.168.0.203"# Define all your nodes role: a(master) or i(minion) or ai(both master and minion), must be the order sameexport roles=("ai" "i" "i")# Define minion numbersexport NUM_MINIONS=${NUM_MINIONS:-3}# define the IP range used for service portal.# according to rfc 1918 ref: https://tools.ietf.org/html/rfc1918 choose a private ip range here.export SERVICE_CLUSTER_IP_RANGE=192.168.3.0/24# define the IP range used for flannel overlay network, should not conflict with above SERVICE_CLUSTER_IP_RANGE rangeexport FLANNEL_NET=172.16.0.0/16....
$ cd cluster$ KUBERNETES_PROVIDER=ubuntu ./kube-up.sh
Kubernetes cluster is running. The master is running at: http://192.168.0.201 ... calling validate-cluster Found 3 nodes. 1 NAME LABELS STATUS 2 192.168.0.201 <none> Ready 3 192.168.0.202 <none> Ready 4 192.168.0.203 <none> Ready Validate output: Cluster validation succeeded Done, listing cluster services: Kubernetes master is running at http://192.168.0.201:8080
部署nginx pod 和複製器
$ cat nginx-rc.yaml apiVersion: v1 kind: ReplicationController metadata: name: nginx-controller spec: replicas: 2 selector: name: nginx template: metadata: labels: name: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80
$ kubectl -s http://192.168.0.201:8080 create -f nginx-rc.yaml
$ kubectl -s http://192.168.0.201:8080 get podsNAME READY REASON RESTARTS AGEnginx-controller-6zr34 1/1 Running 0 48mnginx-controller-njlgt 1/1 Running 0 48m
$ $ kubectl -s http://192.168.0.201:8080 describe pod nginx-controller-6zr34 2>/dev/null | grep Node:Node: 192.168.0.203/192.168.0.203$ kubectl -s http://192.168.0.201:8080 describe pod nginx-controller-njlgt 2>/dev/null | grep Node:Node: 192.168.0.201/192.168.0.201
部署節點內部可訪問的nginx service
$ cat nginx-service-clusterip.yaml apiVersion: v1 kind: Service metadata: name: nginx-service-clusterip spec: ports: - port: 8001 targetPort: 80 protocol: TCP selector: name: nginx
$ kubectl -s http://192.168.0.201:8080 create -f ./nginx-service-clusterip.yaml services/nginx-service $ kubectl -s http://192.168.0.201:8080 get serviceNAME LABELS SELECTOR IP(S) PORT(S)kubernetes component=apiserver,provider=kubernetes <none> 192.168.3.1 443/TCPnginx-service-clusterip <none> name=nginx 192.168.3.91 8001/TCP
$ ssh 192.168.0.202 curl -s 192.168.3.91:8001 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
部署外部可訪問的nginx service
$ cat nginx-service-nodeport.yaml apiVersion: v1 kind: Service metadata: name: nginx-service-nodeport spec: ports: - port: 8000 targetPort: 80 protocol: TCP type: NodePort selector: name: nginx
$ kubectl -s http://192.168.0.201:8080 create -f ./nginx-service-nodeport.yaml services/nginx-service-nodeport $ kubectl -s http://192.168.0.201:8080 get serviceNAME LABELS SELECTOR IP(S) PORT(S)kubernetes component=apiserver,provider=kubernetes <none> 192.168.3.1 443/TCPnginx-service-clusterip <none> name=nginx 192.168.3.91 8001/TCPnginx-service-nodeport <none> name=nginx 192.168.3.84 8000/TCP
$ kubectl -s http://192.168.0.201:8080 describe service nginx-service-nodeport 2>/dev/null | grep NodePortType: NodePortNodePort: <unnamed> 32606/TCP
$ curl 192.168.0.201:32606 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
代理節點上的IP tables規則解析
-A KUBE-PORTALS-CONTAINER -d 192.168.3.84/32 -p tcp -m comment --comment "default/nginx-service-nodeport:" -m tcp --dport 8000 -j REDIRECT --to-ports 43981
-A KUBE-NODEPORT-CONTAINER -p tcp -m comment --comment "default/nginx-service-nodeport:" -m tcp --dport 32606 -j REDIRECT --to-ports 43981
-A KUBE-PORTALS-HOST -d 192.168.3.84/32 -p tcp -m comment --comment "default/nginx-service-nodeport:" -m tcp --dport 8000 -j DNAT --to-destination 192.168.0.201:43981
-A KUBE-NODEPORT-HOST -p tcp -m comment --comment "default/nginx-service-nodeport:" -m tcp --dport 30975 -j DNAT --to-destination 192.168.0.201:43981
總結