kubernetes已经成为容器编排领域的王者。是一个基于容器的集群编排引擎,具有扩展集群、滚动升级回滚、弹性伸缩、自动修复、服务发现等特性能力。本文将带你快速了解kubernetes,理解当我们谈论kubernetes时我们在谈论什么。kubernetes架构从宏观上看kubernetes的整体架构,包括Master、Node、Etcd。Master是主节点,负责控制整个kubernetes集群。它包括ApiServer、Scheduler、Controller等组件。它们都需要与Etcd交互来存储数据。ApiServer:主要提供资源操作的统一入口,从而屏蔽与Etcd的直接交互。功能包括安全性、注册和发现等。Scheduler:负责按照一定的调度规则将Pod调度到Nodes上。Controller:资源控制中心,确保资源处于预期的工作状态。Node是工作节点,为整个集群提供计算能力,是容器真正运行的地方,包括运行容器、kubelet、kube-proxy。kubelet:主要任务包括管理容器的生命周期、使用cAdvisor进行监控、健康检查、定期报告节点状态。kube-proxy:主要使用service来提供集群内的服务发现和负载均衡,同时监控service/endpoints变化和刷新负载均衡。从创建Deployment开始Deployment是用于编排Pod的控制器资源,我们将在后面介绍。这里我们以部署为例,看看架构中的各个组件在创建部署资源的过程中做了什么。首先,kubectl发起创建部署的请求。apiserver接收到创建部署的请求,将相关资源写入etcd。之后所有组件与apiserver/etcd的交互类似于deploymentcontrollerlist/watch资源变化发起创建replicaSet请求replicaSetcontrollerlist/watch资源变化发起pod创建请求。调度器检测未绑定的Pod资源,并通过一系列匹配和过滤选择合适的节点进行绑定。kubelet发现需要在自己节点上创建新的pod,负责pod的创建和后续的生命周期管理kube-proxy负责初始化服务相关的资源,包括服务发现、负载均衡等网络规则.至此,通过kubenetes各组件的分工协作,完成了从创建部署请求到各个pod正常运行的全过程。Pod在kubernetes众多的API资源中,pod是最重要也是最基础的,也是最小的部署单元。我们要考虑的第一个问题是为什么我们需要Pod?Pod可以说是一种容器设计模式,是为那些“超级贴心”的容器而设计的。我们可以想象一下servelet容器部署war包、日志收集等场景。这些容器往往需要共享网络、共享存储、共享配置,所以才有了pod的概念。对于pod来说,不同的容器通过infra容器统一标识外网空间,挂载同一个volume,存储自然就可以共享,比如对应宿主机上的一个目录。容器编排容器编排是kubernetes的看家本领,所以我们需要了解一下。kubernetes中有很多编排相关的控制资源,比如无状态应用的deployment,有状态应用的statefulset,daemonsets的daemonset,离线服务的job/cronjob等,我们拿最广泛使用的deployment作为一个例子。deployment、replicatset、pod之间是层层控制的关系。简单来说,replicaset控制了pod的数量,deployment控制了replicaset的version属性。这种设计模式还为两个最基本的编排动作提供了基础,即具有数量控制的水平缩放和具有版本属性控制的更新/回滚。水平缩放水平缩放非常容易理解。我们只需要修改replicaset控制的pod副本数,比如从2修改为3,那么水平伸缩的动作就完成了,反之就是水平收缩。Update/rollbackupdate/rollback反映了replicaset对象的必要性。比如我们需要把3个实例的版本从v1改成v2,那么v1版本的replicaset控制的pod副本数会逐渐从3变成0,而v2版本的replicaset控制的pod数量会逐渐变化从0变为3。当deployment完成了只存在于v2版本的replicaset的时变更新。回滚的动作则相反。可以找到滚动更新。在上面的例子中,当我们更新应用时,pod总是一个一个升级,最少有2个pod可用,最多有4个pod提供服务。这种“滚动更新”的好处是显而易见的。一旦新版本有bug,剩下的两个pod依然可以提供服务,方便快速回滚。在实际应用中,我们可以通过配置RollingUpdateStrategy来控制滚动更新策略。maxSurge表示部署控制器可以创建多少个新的Pod;maxUnavailable指的是DeploymentController可以删除多少旧的Pod。kubernetes中的网络我们了解了容器编排是怎么做到的,那么容器是如何通信的呢?说到网络通信,kubernetes首先要有一个“三通”的基础:节点可以和pod通信,节点pod可以和不同节点通信,不同节点之间的pod可以通信。简单的说,不同的pod可以通过cni0/docker0网桥实现通信,节点通过cni0/docker0网桥通信访问pod。不同节点之间的pod通信有很多实现方案,包括现在比较常见的flannel的vxlan/hostgw方式。flannel通过etcd学习其他节点的网络信息,并为本节点创建路由表,最终实现不同节点之间的跨主机通信。Microservice—service在了解接下来的内容之前,我们首先要了解一个非常重要的资源对象:service。我们为什么需要服务?在微服务中,一个pod可以对应一个实例,一个服务对应一个微服务。在服务调用的过程中,service的出现解决了两个问题:pod的ip不固定,使用不固定的ip进行网络调用是不现实的。服务调用需要不同pod的负载均衡。Service通过labelselector选择合适的pod,构建一个endpoints,即pod负载均衡列表。在实践中,我们通常会为同一个微服务的pod实例打上app=xxx这样的标签,并为该微服务创建一个标签选择器为app=xxx的服务。kubernetes中的服务发现和网络调用有了上述的“三通”网络基础之后,我们就可以开始在kubernetes中如何实现微服务架构中的网络调用了。这部分内容其实是在讲Kubernetes是如何实现服务发现的。已经解释清楚了。更多详细信息,您可以参考上述文章。这里简单介绍一下。服务间调用首先是东西向流量调用,即服务间调用。这部分主要包括两种调用方式,分别是clusterIp方式和dns方式。clusterIp是一种服务。在这种模式下,kube-proxy通过iptables/ipvs实现了一种VIP(virtualip)的形式来提供服务。只需要访问VIP,就可以负载均衡的方式访问服务后面的pod。上图是clusterIp的一个实现,还包括userSpace代理模式(基本不用),ipvs模式(性能更好)。dns模式很容易理解。对于clusterIp方式的服务,它有一条A记录service-name.namespace-name.svc.cluster.local,指向clusterIp地址。所以在一般的使用中,我们可以直接调用service-name。服务外访问南北向流量,即外部请求访问kubernetes集群,主要包括三个方法:nodePort、loadbalancer、ingress。nodePort也是一种服务。通过iptables,赋予了调用宿主机特定端口访问其背后服务的能力。负载均衡器是另一种服务,通过公有云提供的负载均衡器实现。我们可能需要创建100个nodePort/loadbalancers来访问100个服务。我们希望通过一个统一的外部访问层来访问内部的kubernetes集群,这就是ingress的作用。Ingress提供统一的接入层,通过不同的路由规则匹配不同的后端服务。Ingress可以看作是“服务的服务”。Ingress的实现往往结合nodePort和loadbalancer来完成功能。至此,我们已经简单了解了kubernetes的相关概念,大致是如何工作的,以及微服务在kubernetes中是如何运行的。所以当我们听到别人讨论kubernetes时,我们可以知道他们在说什么。作者:fredalxin地址:https://fredal.xin/what-is-ku...
