云平台

到目前为止,假设我们的应用已经从DevOps平台上构建好了,准备部署,那么,我们就需要一个平台,利用它的能力,把应用或微服务部署到合适的主机上运行并监控起来。那么这个平台需要的最基本的功能有:

  • 资源管理 : 管理所有分散的主机,形成一个应用可用的机器集群
  • 调度编排 : 把应用/容器/服务部署到合适的资源节点并进行监控

把所有资源管理起来就形成了“云”,调度编排目前的最佳实践是以容器镜像为标准的,所以,对容器进行调度的云也叫容器云。我们需要的就是这样一个云平台,进行微服务的调度。

目前业界的主流是 Google的Kubernetes(K8S),提供构建“容器调度编排的云平台”,作为开源软件捐献给了CNCF;大部分第三方云服务提供商提供Kubernetes服务,这意味Kubernetes让应用程序在云平台之间可移植或替换,那么,这篇文章就主要以Kubernetes为主,进行实践和总结。

名词解释

  • 云 由很多机器组成,通过网络提供计算,存储,软件等服务
  • 容器云 可以对容器进行调度编排的云
  • 公有云 第三方云服务商提供
  • 私有云 自建的或使用第三方托管
  • 混合云 私有云和公有云,一起搭建起来的云
  • IAAS: 云的基础设施层,提供计算,存储,网络等服务
  • PAAS: 云的平台层,提供公共的分布式软件服务
  • SASS: 云的软件服务层,提供个性化软件,产品服务
  • 云原生:微服务部署运行在云平台上,并使用它的各种功能

K8S

kubernetes架构

master节点做为集群大脑, node节点用于承载部署的容器应用

Master

典型的master-slave架构, master是cluster的大脑,运行着apiserver、controller-manager、scheduler它的主要职责是对资源管理、调度,还有弹性伸缩、安全认证等。

组件 功能描述
etcd 保存集群的状态
apiserver 资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制;
controller manager 维护集群的状态,比如故障检测、自动扩展、滚动更新等;
scheduler 资源的调度,按照预定的调度策略将Pod调度到相应的机器上

Node

Node是kubernetes集群的工作节点,可以是物理机,虚拟机或云主机。

组件 功能描述
kubelet 维护容器的生命周期,同时也负责Volume(CSI)和网络(CNI)的管理
Container runtime 镜像管理以及Pod和容器的真正运行(CRI)
kube-proxy 为Service提供cluster内部的服务发现和负载均衡

其它一些组件:

组件 功能描述
kube-dns 域名解析服务
Ingress Controller 服务提供外网入口
Heapster 资源监控
Dashboard 控制台
Federation 跨可用区的集群

资源管理

资源对象

kubernetes 中的 Object,将它们简单的分类为以下几种资源对象:

类别 名称
配置对象 Node、Namespace、Service、Secret、ConfigMap、Ingress、Label、ThirdPartyResource、 ServiceAccount
资源对象 Pod、ReplicaSet、ReplicationController、Deployment、StatefulSet、DaemonSet、Job、CronJob、HorizontalPodAutoscaling
存储对象 Volume、Persistent Volume
策略对象 SecurityContext、ResourceQuota、LimitRange

集群资源管理

组件 功能描述
Node 集群的工作节点
Namespace namespace创建多个“虚拟集群”,这些namespace之间可以完全隔离,也可以通过某种方式共享服务
Label 以key/value键值对的形式附加到各种对象上,建立资源之间的关联
Annotation 将资源对象关联到任意的非标识性元数据,存放对象更多的配置信息

Pod

Pod是kubernetes中可以创建的最小部署单元,它由一个或者多个容器组成,它们共享容器存储、网络和容器运行配置项。Pod中的容器总是被同时调度,有共同的运行环境。
Pod 的生命周期

类别 描述
挂起(Pending) Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。
运行中(Running) 该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
成功(Succeeded) Pod 中的所有容器都被成功终止,并且不会再重启。
失败(Failed) Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
未知(Unknown) 因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。

控制器

Kubernetes中内建了很多controller(控制器),用来调度和控制资源对对象。

类别 名称
Deployment 部署,为 Pod 和 ReplicaSet 提供声明式更新
StatefulSet 作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序。解决有状态服务的问题
DaemonSet 确保全部Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod
ReplicaSet 确保容器应用的副本数始终保持在用户定义的副本数
Job 批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束
CronJob 管理基于时间的 Job
Horizontal Pod Autoscaling Pod水平自动缩放

Deployment

Deployment为Pod和Replica Set(下一代Replication Controller)提供声明式更新。典型的应用场景包括:

  • 定义Deployment来创建Pod和ReplicaSet
    创建:
    kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml –record

  • 滚动升级和回滚应用
    滚动升级:
    kubectl rolling-update my-rcName-v1 -f my-rcName-v2-rc.yaml –update-period=10s
    回滚:
    kubectl rollout undo deployment/nginx-deployment

  • 扩容和缩容
    扩容:
    kubectl scale deployment nginx-deployment –replicas 10
    自动伸缩:
    kubectl autoscale deployment nginx-deployment –min=10 –max=15 –cpu-percent=80

  • 暂停和继续Deployment

Kubernetes YML配置中,apiVersion,kind和metadata是必须配置项,其中编写 Deployment Spec的属性如下:

类别 名称
Pod Template .spec.template 是 pod template. 它跟 Pod有一模一样的schema,除了它是嵌套的并且不需要apiVersion 和 kind字段
Replicas 指定期望的pod数量,默认是1
Selector 用来指定 label selector ,圈定Deployment管理的pod范围
Strategy 指定新的Pod替换旧的Pod的策略:”Recreate”或者是 “RollingUpdate”。”RollingUpdate”是默认值。
Recreate Deployment 创建出新的Pod之前会先杀掉所有已存在的Pod
Rolling Update Deployment 滚动更新,可以指定maxUnavailable 和 maxSurge 来控制 rolling update 进程
Max Unavailable 用来指定在升级过程中不可用Pod的最大数量
Max Surge 指定可以超过期望的Pod数量的最大个数
Progress Deadline Seconds 指定在系统报告Deployment的failed前等待的秒数
Min Ready Seconds 指定没有任何容器crash的Pod并被认为是可用状态的最小秒数
Rollback To 配置Deployment回退的配置。设置该参数将触发回退操作,每次回退完成后,该值就会被清除。
Revision 指定回退到的revision。默认是0,意味着回退到上一个revision。
Revision History Limit 指定可以保留的旧的ReplicaSet数量
Paused 指定暂停和恢复Deployment,对paused deployment中的PodTemplateSpec的修改都不会触发新的rollout,默认是非paused。

StatefulSet

StatefulSet 作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序。
StatefulSet 适用于有以下某个或多个需求的应用:

  • 稳定,唯一的网络标志。
  • 稳定,持久化存储。
  • 有序,优雅地部署和 scale。
  • 有序,优雅地删除和终止。
  • 有序,自动的滚动升级。

比如有状态的数据库,各种中间件,zookeeper,等应用。

ReplicationController和ReplicaSet

ReplicationController用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代。

Horizontal Pod Autoscaling

自动化弹性伸缩,根据Pod的CPU利用率,内存和用户自定义的metric扩缩容。自定义指标的HPA,例如QPS,并且,可以对接Prometheus。

负载均衡

  • Service
    应用的负载均衡,为Service 分配一个虚拟ip,并使用Label Selector与一组 Pod 绑定, 实现通过 Service 负载均衡访问到Pod

发布服务 — 服务类型

Kubernetes ServiceTypes 允许指定一个需要的类型的 Service,默认是 ClusterIP 类型。Type 的取值以及行为如下:

  • ClusterIP:通过集群的内部IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。
  • NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 :,可以从集群的外部访问一个 NodePort 服务。
  • LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
  • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。

  • Ingress
    Ingress,是一种HTTP方式的负载均衡 路由转发机制,并暴露集群内服务的工具。由实现Ingress 的Ingress Controller, HTTP代理服务器组成。kubernetes当前支持并维护GCE和nginx两种controller。Ingress Controller实时监控Kubernetes API,实时更新HTTP代理服务器的转发规则。
    其它方案还有,F5,Kong ,Traefik 等实现的Ingress Controller。

负载均衡 : VIP 和 Service 代理

VIP

在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。kube-proxy 负责为 Service 实现了一种 VIP(虚拟 IP)的形式, 来捕获到达该 Service 的虚拟 IP和端口的请求 。

转发

然后将请求重定向到 Service 绑定的一组Pod backend 上面。Kubernetes v1.2 起,默认使用 iptables 代理,转发Server请求到backend。

而实现 service 这一功能的关键,就是 kube-proxy。

kube-proxy

运行在每个节点上,监听 API Server 中服务对象的变化,通过管理 更新iptables ,实现random转发。

kube-proxy 有两种实现 service 的方案:userspace 和 iptables

  • userspace: service 转发到 kube-proxy iptables,所以效率不高
  • iptables: iptables安装在 service,实现监听和转发,是目前默认的方式,效率很高

服务发现

Kubernetes 支持2种基本的服务发现模式 : 环境变量 和 DNS

  • 环境变量
    当 Pod 运行在 Node 上,kubelet 会为每个活跃的 Service 添加一组环境变量。
  • DNS
    DNS 服务器监视着创建新 Service 的 Kubernetes API,从而为每一个 Service 创建一组 DNS 记录。

其它

Endpoints 与 Service 同名, 维护了 Service 与 Pod 的映射关系。

调度与编排

调度

Kubernetes中有一个叫做kube-scheduler的组件,监听kube-apiserver中的调度命令,通过资源类型Deployment、DaemonSet、StatefulSet等定义的一些默认调度策略,和标签,将Pod调度到节点上。

  • 在特定节点上运行所有pod,指定节点名称
  • 节点标签进行调度:指定节点标签, 亲和性
  • 容器标签进行调度:将容器调度到具有特定标签的容器的主机
  • 基于资源的调度:指定工作负载pod所需的内存和CPU资源
  • 仅给主机调度特定服务:主机上指定容器标签,添加节点taints(如主机标签)并使用容差”
  • 全局服务: DaemonSet,调度到所有节点上

编排

kubernetes 通过使用YAML文件,来编排描述要创建的资源

一些简化编排的工具:

  • 模拟命令执行
    kubectl中很多命令支持 –dry-run 和 -o yaml 参数,可以方便地模拟命令执行,并输出yaml格式
  • 导出资源描述
    kubectl get –export -o yaml 命令会以Yaml格式导出系统中已有资源
  • Kompose转换工具
    将docker-compose.yml编排文件 转换为Kubernetes YAML编排文件。
  • Helm
    Helm把Kubernetes资源(比如deployments、services或 ingress等) 打包到一个chart中,而chart被保存到chart仓库。通过chart仓库可用来存储和分享chart。Helm使发布可配置,支持发布应用配置的版本管理,简化了Kubernetes部署应用的版本控制、打包、发布、删除、更新等操作。

身份与权限认证

  • Service Account
    为Pod中的进程提供身份信息

  • RBAC
    基于角色的访问控制

  • Network Policy
    Pod 之间是如何被允许互相通信,以及如何与其它网络 Endpoint 进行通信。

存储

Secret

Secret解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。Secret可以以Volume或者环境变量的方式使用。
Secret有三种类型:

  • Service Account :用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中;
  • Opaque :base64编码格式的Secret,用来存储密码、密钥等;
  • kubernetes.io/dockerconfigjson :用来存储私有docker registry的认证信息。

ConfigMap

解决应用程序会从配置文件、命令行参数或环境变量中读取配置信息,这些配置信息与docker image解耦。ConfigMaps可以被用来:

  • 设置环境变量的值
  • 在容器里设置命令行参数
  • 在数据卷里面创建config文件

Volume

Pod下挂的目录,Pod每次重启可以共享该目录的数据。卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当 Pod 不再存在时,卷也将不复存在。

Persistent Volume

持久化卷

  • PersistentVolume(PV)
    是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统。

  • PersistentVolumeClaim(PVC)
    是用户存储的请求。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。

  • StorageClass
    StorageClass 为管理员提供了描述存储 “class(类)” 的方法。 不同的 class 可能会映射到不同的服务质量等级或备份策略,或由群集管理员确定的任意策略。管理员可以为没有申请绑定到特定 class 的 PVC 指定一个默认的 StorageClass。

  • 本地持久化存储
    本地持久化卷允许用户通过标准 PVC 接口以简单便携的方式访问本地存储。

网络

Kubernetes本身并不提供网络功能,只是把网络接口开放出来,通过插件的形式实现。
Kubernetes管理的是集群,Kubernetes中的网络要解决的核心问题就是每台主机的IP地址网段划分,以及单个容器的IP地址分配。概括为:

  • 保证每个Pod拥有一个集群内唯一的IP地址
  • 保证不同节点的IP地址划分不会重复
  • 保证跨节点的Pod可以互相通信
  • 保证不同节点的Pod可以与跨节点的主机互相通信
  • 为了解决该问题,出现了一系列开源的Kubernetes中的网络插件与方案,如:
    flannel,calico,contiv,weave net,kube-router,cilium,canal

只要实现Kubernetes官方的设计的CNI - Container Network Interface(容器网络接口)就可以自己写一个网络插件,最常用的时flannel和calico插件。

flannel

Kubernetes集群内部存在三类IP,分别是:

  • Node IP:宿主机的IP地址
  • Pod IP:使用网络插件创建的IP(如flannel),使跨主机的Pod可以互通
  • Cluster IP:Service 虚拟IP,通过iptables规则访问服务

在安装node节点的时候,节点上的进程是按照flannel -> docker -> kubelet -> kube-proxy的顺序启动的。
Flannel是作为一个二进制文件的方式部署在每个node上,主要实现两个功能:

  • 为每个node分配subnet,容器将自动从该子网中获取IP地址
  • 当有node加入到网络中时,为每个node增加路由配置

calico

Calico 创建和管理一个扁平的三层网络(不需要overlay),每个容器会分配一个可路由的ip。由于通信时不需要解包和封包,网络性能损耗小,易于排查,且易于水平扩展。

以上更详细请参考:
https://jimmysong.io/kubernetes-handbook/
http://kubernetes.kansea.com/docs/

云平台

上面介绍了用Kubernetes构建基于容器调度的云平台,在这个平台上我们可以添加和管理集群的机器,安装基础的分布式软件,最后部署我们的应用程序-微服务。

  • 云的通用基础设施
    因为它的抽象与通用性,已经成为云的通用基础设施,通用的云平台。

  • 分布式应用的管理平台
    利用它的编排调度与容器管理,可以轻松快捷的创建和管理分布式应用服务。

  • 微服务的运行时平台
    提供了负载均衡,服务发现等微服务必须的组件,也随着Service Mesh - istio , FAAS等技术的慢慢成熟,将提供一个让微服务更加简单,快捷的落地方案与最佳实践,也将是一个成熟的微服务运行时平台。