Kubernetes应用部署模型解析(原理篇)


十多年来Google一直在生产环境中使用容器运行业务,负责管理其容器集群的系统就是Kubernetes的前身Borg。其实现在很多工作在Kubernetes项目上的Google开发者先前就在Borg这个项目上工作。多数Kubernetes的应用部署模型的思想都起源于Borg,了解这些模型是掌握Kubernetes的关键。Kubernetes的API版本目前是v1,本文以代码0.18.2版为基础来介绍它的应用部署模型,最后我们用一个简单的用例来说明部署过程。在部署结束后,阐述了它是如何用Iptables规则来实现各种类型Service的。

Kubernetes架构

Kubernetes集群包括Kubernetes代理(agents )Kubernetes服务(master node)两种角色,代理角色的组件包括Kube-proxy Kubelet,它们同时部署在一个节点上,这个节点也就是代理节点。服务角色的组件包括kube-apiserverkube-schedulerkube-controller-manager,它们可以任意布属,它们可以部署在同一个节点上,也可以部署在不同的节点上(目前版本好像不行)。Kubernetes集群依赖的第三方组件目前有etcddocker两个。前者提供状态存储,二者用来管理容器。集群还可以使用分布式存储给容器提供存储空间。下图显示了目前系统的组成部分:

Kubernetes代理节点Kubelet和Kube-proxy运行在代理节点上。他们监听服务节点的信息来启动容器和实现Kubernetes网络和其它业务模型,比如Service、Pod等。当然每个代理节点都运行Docker。Docker负责下载容器镜像和运行容器。

Kubelet

Kubelet组件管理Pods和它们的容器,镜像和卷等信息。

Kube-ProxyKube-proxy是一个简单的网络代理和负载均衡器。它具体实现Service模型,每个Service都会在所有的Kube-proxy节点上体现。根据Serviceselector所覆盖的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中的应用容器同享同一个上下文:

  • PID 名字空间。但是在docker中不支持
  • 网络名字空间,在同一Pod中的多个容器访问同一个IP和端口空间。
  • IPC名字空间,同一个Pod中的应用能够使用SystemV IPC和POSIX消息队列进行通信。
  • UTS名字空间,同一个Pod中的应用共享一个主机名。
  • Pod中的各个容器应用还可以访问Pod级别定义的共享卷。
从生命周期来说,Pod应该是短暂的而不是长久的应用。
Pods被调度到节点,保持在这个节点上直到被销毁。当节点死亡时,分配到这个节点的Pods将会被删掉。将来可能会实现Pod的迁移特性。在实际使用时,我们一般不直接创建Pods,
我们通过replication
controller来负责Pods的创建,复制,监控和销毁。一个Pod可以包括多个容器,他们直接往往相互协作完成一个应用功能。

Replication controller复制控制器确保Pod的一定数量的份数(replica)在运行。如果超过这个数量,控制器会杀死一些,如果少了,控制器会启动一些。控制器也会在节点失效、维护的时候来保证这个数量。所以强烈建议即使我们的份数是1,也要使用复制控制器,而不是直接创建Pod。

在生命周期上讲,复制控制器自己不会终止,但是跨度不会比Service强。Service能够横跨多个复制控制器管理的Pods。而且在一个Service的生命周期内,复制控制器能被删除和创建。Service和客户端程序是不知道复制控制器的存在的。
复制控制器创建的Pods应该是可以互相替换的和语义上相同的,这个对无状态服务特别合适。
Pod是临时性的对象,被创建和销毁,而且不会恢复。复制器动态地创建和销毁Pod。虽然Pod会分配到IP地址,但是这个IP地址都不是持久的。这样就产生了一个疑问:外部如何消费Pod提供的服务呢?

ServiceService定义了一个Pod的逻辑集合和访问这个集合的策略。集合是通过定义Service时提供的Label选择器完成的。举个例子,我们假定有3个Pod的备份来完成一个图像处理的后端。这些后端备份逻辑上是相同的,前端不关心哪个后端在给它提供服务。虽然组成这个后端的实际Pod可能变化,前端客户端不会意识到这个变化,也不会跟踪后端。Service就是用来实现这种分离的抽象。

对于Service,我们还可以定义Endpoint,Endpoint把Service和Pod动态地连接起来。

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。

注意:在0.18以前的版本中Cluster IP叫PortalNet IP。

内部使用者的服务发现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容器:

REDIS_MASTER_SERVICE_HOST= 10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR= 10.0.0.11
注意,只有在某个Service后创建的Pod才会有这个Service的环境变量。

DNS一个可选的Kubernetes附件(强烈建议用户使用)是DNS服务。它跟踪集群中Service对象,为每个Service对象创建DNS记录。这样所有的Pod就可以通过DNS访问服务了。

比如说我们在Kubernetes
名字空间"my-ns"中有个叫my-service的服务,DNS服务会创建一条"my-service.my-ns"的DNS记录。同在这个命名空间的Pod就可以通过"my-service"来得到这个Service分配到的Cluster
IP,在其它命名空间的Pod则可以用全限定名"my-service.my-ns"来获得这个Service的地址。

Pod IP and Service Cluster IPPod IP
地址是实际存在于某个网卡(可以是虚拟设备)上的,但Service Cluster
IP就不一样了,没有网络设备为这个地址负责。它是由kube-proxy使用Iptables规则重新定向到其本地端口,再均衡到后端Pod的。我们前面说的Service环境变量和DNS都使用Service的Cluster
IP和端口。

就拿上面我们提到的图像处理程序为例。当我们的Service被创建时,Kubernetes给它分配一个地址10.0.0.1。这个地址从我们启动API的service-cluster-ip-range参数(旧版本为portal_net参数)指定的地址池中分配,比如--service-cluster-ip-range=10.0.0.0/16。假设这个Service的端口是1234。集群内的所有kube-proxy都会注意到这个Service。当proxy发现一个新的service后,它会在本地节点打开一个任意端口,建相应的iptables规则,重定向服务的IP和port到这个新建的端口,开始接受到达这个服务的连接。
当一个客户端访问这个service时,这些iptable规则就开始起作用,客户端的流量被重定向到kube-proxy为这个service打开的端口上,kube-proxy随机选择一个后端pod来服务客户。这个流程如下图所示:
根据Kubernetes的网络模型,使用Service Cluster IP和Port访问Service的客户端可以坐落在任意代理节点上。外部要访问Service,我们就需要给Service外部访问IP。

外部访问ServiceService对象在Cluster IP range池中分配到的IP只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个Service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP了。

外部访问者是访问集群代理节点的访问者。为这些访问者提供服务,我们可以在定义Service时指定其spec.publicIPs,一般情况下publicIP
是代理节点的物理IP地址。和先前的Cluster IP
range上分配到的虚拟的IP一样,kube-proxy同样会为这些publicIP提供Iptables
重定向规则,把流量转发到后端的Pod上。有了publicIP,我们就可以使用load
balancer等常用的互联网技术来组织外部对服务的访问了。
spec.publicIPs在新的版本中标记为过时了,代替它的是spec.type=NodePort,这个类型的service,系统会给它在集群的各个代理节点上分配一个节点级别的端口,能访问到代理节点的客户端都能访问这个端口,从而访问到服务。

Label和Label selectorLabel标签在Kubernetes模型中占着非常重要的作用。Label表现为key/value对,附加到Kubernetes管理的对象上,典型的就是Pods。它们定义了这些对象的识别属性,用来组织和选择这些对象。Label可以在对象创建时附加在对象上,也可以对象存在时通过API管理对象的Label。

在定义了对象的Label后,其它模型可以用Label 选择器(selector)来定义其作用的对象。
Label选择器有两种,分别是Equality-basedSet-based
比如如下Equality-based选择器样例:

environment = productiontier != frontendenvironment = production,tier != frontend

对于上面的选择器,第一条匹配Label具有environment key且等于production的对象,第二条匹配具有tier key,但是值不等于frontend的对象。由于kubernetes使用AND逻辑,第三条匹配production但不是frontend的对象。
Set-based选择器样例:

environment in (production, qa)tier notin (frontend, backend)partition

第一条选择具有environment key,而且值是production或者qalabel附加的对象。第二条选择具有tier key,但是其值不是frontendbackend。第三条选则具有partition key的对象,不对value进行校验。
replication controller复制控制器和Service都用labellabel selctor来动态地配备作用对象。复制控制器在定义的时候就指定了其要创建PodLabel和自己要匹配这个PodselectorAPI服务器应该校验这个定义。我们可以动态地修改replication controller创建的PodLabel用于调式,数据恢复等。一旦某个Pod由于Label改变replication controller移出来后,replication controller会马上启动一个新的Pod来确保复制池子中的份数。对于ServiceLabel selector可以用来选择一个Service的后端Pods

一个简单的应用

讲了这么多的原理和概念,本章我们就部署一个简单应用来感受一下Kubernetes的部署模型。

部署Kubernetes集群

kubernetes github站点上有数十种针对各种环境的部署文档,本文选择基于ubuntu的集群部署方案。在没有使用本地docker镜像的情况下,在部署过程中需要确保能够访问站点gcr.io。
基于 Ubuntu的集群部署方案文档写得比较详细,按照它的步骤几乎不会出错。在进行真正的部署之前,一定要确保:
  • 所有的节点安装了docker version 1.2+ 和 bridge-utils
  • 如果没有本地的docker registry, 要确保节点能访问互联网gcr.io
  • 确保管理节点能够ssh 访问所有节点。比如ssh gongysh@192.168.0.201 ls
这里我们集群将采用下图显示的结构。我们将在管理节点上运行集群管理命令。我们将有一个服务和代理混合的节点,还有两个纯的代理节点。
首先我们要下载kubernetes的代码到管理节点上:

$ git clone https://github.com/GoogleCloudPlatform/kubernetes.git

然后进行本地构建:

cd kubernetes./build/run.sh hack/build-do.sh

修改config-default.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应用
我们以下面的图来安装一个简单的静态内容的nginx应用:
首先,我们用复制器启动一个2个备份的nginx Pod。然后在前面挂Service,一个service只能被集群内部访问,一个能被集群外的节点访问。下面所有的命令都是在管理节点上运行的。

部署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

我们定义了一个nginx pod复制器,复制份数为2,我们使用nginx docker镜像。
执行下面的操作创建nginx pod复制器:

$  kubectl -s http://192.168.0.201:8080 create -f nginx-rc.yaml

由于kubernetes要去gcr.io下载gcr.io/google_containers/pause镜像,然后下载nginx镜像,所以所创建的Pod需要等待一些时间才能处于running状态。

$  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

我们可以使用describe 命令查看pod所分到的节点:

$  $ 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

从上表可以看出,这个复制器启动了两个Pod,分别运行在192.168.0.201和203代理节点主机上。

部署节点内部可访问的nginx service

Service的type有ClusterIP和NodePort之分,缺省是ClusterIP,这种类型的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

执行下面的命令创建service:

$ 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

验证service的可访问性:
上面的输出告诉我们这个Service的Cluster IP是192.168.3.91,端口是8001。下面我们验证这个PortalNet IP的工作情况:

$ 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 Pod运行在201和203节点上。上面我们特意从202代理节点上访问我们的服务来体现Service Cluster IP在所有集群代理节点的可到达性。

部署外部可访问的nginx service

下面我们创建NodePort类型的Service,这种类型的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

执行下面的命令创建service:

$ 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

使用下面的命令获得这个service的节点级别的端口:

$ kubectl -s http://192.168.0.201:8080
describe service nginx-service-nodeport 2>/dev/null | grep
NodePortType:                        NodePortNodePort:               
<unnamed>        32606/TCP

验证service的可访问性:
上面的输出告诉我们这个Service的节点级别端口是32606。下面我们验证这个Service的工作情况:

$ 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规则解析

下面的图是IPTables中流量经过的table和chain。
可以看出,Kubernetes在nat表中插入了下面四条chain:
1.  KUBE-PORTALS-CONTAINER
这个chain主要是处理所有service对象的cluster IP和port到kube-proxy本地端口的映射。比如下面规则:

-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

就是为nginx-service-nodeport服务的Cluster
IP准备的。其中192.168.3.84/32是该服务获得的Cluster
IP,端口8000是其在定义文件中指定的spec.ports.port。43981则是kube-proxy为这个service分配的本地端口。规则的意思是到192.168.3.84:8000的流量重定向到43981。
2.  KUBE-NODEPORT-CONTAINER
这条chain上则串连着类型为NodePort的service的NodePort规则。比如下面规则:

-A
KUBE-NODEPORT-CONTAINER -p tcp -m comment --comment
"default/nginx-service-nodeport:" -m tcp --dport 32606 -j REDIRECT
--to-ports 43981

就是为nginx-service-nodeport服务的NodePort 32606准备的。意思是访问本地32606端口的流量重新定向到43981,后者是kube-proxy为这个service分配的本地端口。
3.  KUBE-PORTALS-HOST
这条chain上也关联着各个service的Cluster IP和Port的规则,比如:

-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

这条规则是和KUBE-PORTALS-CONTAINER类似的,只不过流量来自于本地进程。
4.  KUBE-NODEPORT-HOST
这条chain上则关联着类型为NodePort的service的NodePort规则。比如下面规则:

-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

这条规则是和KUBE-NODEPORT-CONTAINER类似的,只不过流量来自于本地进程。

总结

笔者认为Docker已经不是仅代表容器本身,而是一组以应用部署为中心的技术,产品和最佳实践生态系统。Kubernetes以其出身,文档的成熟度,社区的支持在这个生态系统中表现得比较突出。在部署Kubernetes时,我们首先要理解Kubernetes的组件结构,它们有哪些角色,各个角色的作用是什么和它们之接的通信。在应用部署时,了解Kubernetes的应用模型是非常重要的。笔者认为复制器和Service的概念是Kubernetes模型的核心,复制器和Service共同完成了应用的高可用性要求。最后本文以一个简单的nginx服务来展示了复制器和Service的使用,特别通过对Service的cluster
IP和NodePort的分析,使得读者能够了解这个模型中的网络特性。
最后就是容器技术的选型,本文使用Docker作为容器,其实Kubernetes也支持CoreOS的rkt容器。kubelet的参数--container_runtime用于选择使用的容器技术。(责编/周建丁)
作者简介:龚永生,九州云架构师。多年Linux系统开发,J2EE产品和云计算相关技术研发经验。目前活跃在OpenStack社区的各个项目上,主要技术方向是虚拟网络项目Neutron,是Neutron项目早期的主要贡献者之一。

kubernetes应用部署原理的更多相关文章

  1. Kubernetes一键部署利器:kubeadm

    要真正发挥容器技术的实力,你就不能仅仅局限于对 Linux 容器本身的钻研和使用. 这些知识更适合作为你的技术储备,以便在需要的时候可以帮你更快的定位问题,并解决问题. 而更深入的学习容器技术的关键在 ...

  2. Docker Kubernetes 服务发现原理详解

    Docker Kubernetes  服务发现原理详解 服务发现支持Service环境变量和DNS两种模式: 一.环境变量 (默认) 当一个Pod运行到Node,kubelet会为每个容器添加一组环境 ...

  3. Kubernetes 应用部署实战

    Kubernetes 应用部署实战 2018-08-08 19:44:56 wuxiangping2017 阅读数 3084  收藏 更多 分类专栏: linux运维与架构师   简介 伙计们,请搬好 ...

  4. 浅析Kubernetes的工作原理

    先放一张Kubernetes的架构图: 整体来看,是一个老大,多个干活的这种结构,基本上所有的分布式系统都是这样,但是里面的组件名称就纷繁复杂,下面将一一解析. 1.元数据存储与集群维护 作为一个集群 ...

  5. 简化kubernetes应用部署工具之Helm应用部署

    介绍 微服务和容器化给复杂应用部署与管理带来了极大的挑战.Helm是目前Kubernetes服务编排领域的唯一开源子项目,做为Kubernetes应用的一个包管理工具,可理解为Kubernetes的a ...

  6. [原]CentOS7安装Rancher2.1并部署kubernetes (二)---部署kubernetes

    ##################    Rancher v2.1.7  +    Kubernetes 1.13.4  ################ ##################### ...

  7. [原]CentOS7安装Rancher2.1并部署kubernetes (一)---部署Rancher

    ##################    Rancher v2.1.7  +    Kubernetes 1.13.4  ################ ##################### ...

  8. [译]Kubernetes 分布式应用部署和人脸识别 app 实例

    原文地址:KUBERNETES DISTRIBUTED APPLICATION DEPLOYMENT WITH SAMPLE FACE RECOGNITION APP 原文作者:skarlso 译文出 ...

  9. Centos下Kubernetes+Flannel部署(新)

    一.准备工作 1) 三台centos主机 k8s master: 10.11.151.97  tc-151-97 k8s node1: 10.11.151.100  tc-151-100 k8s no ...

随机推荐

  1. Java多线程框架Executor详解

       原文链接  http://www.imooc.com/article/14377 为什么引入Executor线程池框架new Thread()的缺点 每次new Thread()耗费性能调用ne ...

  2. mysql 8.0给数据库添加用户和赋权

    -- 使用mysql 数据库 USE mysql -- 为mysql创建用户:case_dev 密码为:pass123 CREATE USER case_dev IDENTIFIED BY 'pass ...

  3. 大家来找茬:富连网今天中午抢购二手iPhone时网站无法访问的问题

    前几天在新闻区看到富士康卖二手iPhone的新闻,今天又看到说今天中午12点开抢.一大早就发现富连网无法访问了.前几天刚看到新闻的时候注册了个账号进去看了看,发现页面加载速度非常慢,今天中午基本无法打 ...

  4. tensorflow中使用Batch Normalization

    在深度学习中为了提高训练速度,经常会使用一些正正则化方法,如L2.dropout,后来Sergey Ioffe 等人提出Batch Normalization方法,可以防止数据分布的变化,影响神经网络 ...

  5. 微服务,ApiGateway 与 Kong

    一. 微服务 二. Api Gateway 三. Kong 的使用 一. 微服务 对于一些传统的 大型项目,传统的方式会有一些缺陷,比如说 新人熟悉系统成本高(因为整个系统作为一个整体,彼此会有一定的 ...

  6. rpx

    rpx(responsive pixel): 可以根据屏幕宽度进行自适应.规定屏幕宽为750rpx.如在iPhone6上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = ...

  7. [nginx]站点目录及文件访问控制

    nginx.conf配置文件 http ->多个server -> 多个location ->可限制目录和文件访问(根据i扩展名限制或者rewrite.) 根据目录或扩展名,禁止用户 ...

  8. 根据第三方提供的webservice地址获取文件信息

    import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.en ...

  9. (原创)拨开迷雾见月明-剖析asio中的proactor模式(二)

    在上一篇博文中我们提到异步请求是从上层开始,一层一层转发到最下面的服务层的对象win_iocp_socket_service,由它将请求转发到操作系统(调用windows api),操作系统处理完异步 ...

  10. 腾讯云主机安装登录mysql失败--解决方案[重置root密码并实现远程连接]

    登录MySQL时报错:Access denied for user 'root'@'localhost' (using password: YES) 解决步骤: 1.使用ssh工具连接主机,使用mys ...