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
总结