Docker, Kubernetes, DCOS 不谈信仰谈技术

  看来容器编排系统的争夺已经白热化了,乱花渐欲迷人眼,最近老是有各种文章比较这三个框架,这篇文章不谈信仰,不对比优劣,只谈技术,甚至会谈如果从一个平台转向另一个平台,都要了解些啥。

  一、架构

  啥都不说,先上三个架构图

  Docker Swarm Mode

  

  DCOS

  

  这张图主要显示了一些组件,还是上一张Mesos的图

  

  最后是Kubernetes

  

  这三个架构都很复杂,但是还是能够一眼看出是一个老大,多个干活的这种结构,基本上所有的分布式系统都是这样,但是里面的组件名称就纷繁复杂,我们来一一解析。

  二、元数据存储与集群维护

  作为一个集群系统,总要有一个统一的地方维护整个集群以及任务的元数据。而且作为集群系统的控制节点,为了高可用性,往往存在多个Master,在多个Master中间,总要有一个Leader。

  在Docker Swarm Mode里面,多个Manager之间需要选出一个Leader,而且整个集群的状态也需要在一个统一的地方存储,从而任何一个Manager挂了之后,其他的Manager能够马上接替上,Swarm Node通过Raft协议,自己实现了一个内部的统一存储和集群一致性管理系统。在传统的Swarm里面,推荐的使用consul,在Swarm Mode里面则自己实现了。

  在docker swarm init的参数里面有--advertise-addr声明swarm manager会通过这个地址和端口让其他组件来连接。

  在DCOS里面,Mesos的多个进程也需要选择一个Leader,容器的编排多通过Marathon进行,Marathon需要一个地方存储所有Task的信息,在DCOS里面,多通过Zookeeper来实现。

  在Mesos Master的启动有参数--zk=VALUE。

  当然也能看到熟悉的--advertise_ip=VALUE和--advertise_port=VALUE。

  Marathon启动的时候,也有参数--zk zk://1.2.3.4:2181,2.3.4.5:2181,3.4.5.6:2181/marathon。

  在Kubernetes里面,统一的存储使用etcd来保存,Leader的选举也是通过etcd进行,因而有apiserver有参数--etcd-servers,controller和scheduler都有参数--master string指向apiserver,并且有参数--leader-elect选举出Leader,也会有熟悉的--address ip。

  三、API层与命令行

  作为一个分布式系统,每一层都会有自己的API,但是对外往往需要一个统一的API接口层,一般除了酷酷的界面之外,为了自动化,往往会有一个命令行可以执行操作,其实命令里面封装的也是对API的调用。

  对于Docker Swarm Mode来讲,API层是集成在Manager里面的,而命令行其实就是Docker的命令行,只不过调用的时候,原来是Docker Daemon本地把事情做了,现在Manager需要让Work去做事情。

  这一点也是Docker的优势所在,也即使用本地的Docker和使用Swarm Mode集群,不需要学习成本,一样的命令,同样的味道。

  对于DCOS来讲,API层是有一个单独的组件,叫做Admin Router,后端的很多API都是通过Admin Router经过封装暴露给外面的。

  对于命令行,有一个dcos cli,可以调用admin router暴露出来的api进行操作。

  dcos命令行可以有一些子命令,例如marathon子命令,就是用来创建容器的,node可以管理节点。

  dcos里面很有特色的一点就是可以安装package,这源于mesos是一个双层调度系统,上面可以跑多个framework,例如spark,cassandra等,都可以通过package进行安装,这点会另外一节说明。

  对于Kubernetes,API层是一个单独的进程apiserver提供,认证和鉴权也是在这一层实现的,所有对于kubernetes的管理平台的访问都是通过apiserver这一层进行的。

  对于命令行,kubernetes是kubectl,通过向apiserver调用执行操作,例如pod,service,deployment等。

  kubernetes也有自己的类似package的管理,Kubernetes Helm,但是命令就变成了helm了。

  四、调度

  当运行一个容器的时候,放在哪台节点上,这个过程是调度。

  Swarm Mode 的调度的默认规则是spread,也即尽量让容器平均分配到整个集群当中。

  当然也可以设置一些调度策略,例如使用constraint,每个节点可以配置一些label,并在创建容器的时候通过指定constraint,来使得容器运行或者不运行在某些节点上。

  docker node update --label-add 'com.acme.server=db' node-03

  docker service create --name redis --constraint 'node.labels.com.acme.server==db' redis

  也可以使用placement-pref,使得容器优先调度在某些节点上。

  docker service create --name nginx --placement-pref 'spread=node.labels.com.acme.zone' --replicas 12 nginx

  对于DCOS来讲,Mesos的调度是双层调度,首先一层是Mesos Master的Allocator将节点资源提供给框架,例如Marathon,第二层是Marathon里面也有一个调度器,真正分配某个容器放在某个节点上。

  Mesos的调度策略参考文章号称了解mesos双层调度的你,先来回答下面这五个问题!

  Marathon的调度也可以有constraints。

  "constraints": [["hostname", "UNIQUE"]]表示每个节点只能跑一个。

  "constraints": [["rack_id", "CLUSTER", "rack-1"]]容器跑着有attribute为rack_id并且值为rack-1的节点上。

  "constraints": [["rack_id", "GROUP_BY", "3"]]将容器分布在三个rack上以实现高可用。

  "constraints": [["rack_id", "LIKE", "rack-[1-3]"]]和"constraints": [["rack_id", "UNLIKE", "rack-[7-9]"]]表示容器要跑在哪些节点上和不能跑在哪些节点上。

  "constraints": [["rack_id", "MAX_PER", "2"]]表示每个rack最多能跑两个容器。

  对于Kubernetes,调度是由一个单独的进程scheduler负责的。

  Kubernetes也支持通过对Node设置Label,从而将pod放在某些节点上。

  kubectl label nodes <your-node-name> disktype=ssd

  apiVersion: v1kind: Podmetadata:

  name: nginx

  labels:

  env: testspec:

  containers:

  - name: nginx

  image: nginx

  imagePullPolicy: IfNotPresent

  nodeSelector:

  disktype: ssd

  另外kubernetes还有NodeAffinity:

  RequiredDuringSchedulingRequiredDuringExecution:在调度的时候必须部署到某些节点,运行期如果条件不满足则重新调度

  RequiredDuringSchedulingIgnoredDuringExecution :在调度的时候必须部署到某些节点,运行期就算了。

  PreferredDuringSchedulingIgnoredDuringExecution :在调度的时候最好部署到某些节点,运行期就算了。

  五、副本与弹性伸缩

  容器如果部署无状态服务,一个好处就是可以多副本,并且可以弹性伸缩。

  在Swarm Mode里面,可以通过scale数字指定副本数目。

  docker service scale frontend=50

  在DCOS里面,通过instances指定副本的数目。

  {

  "id": "nginx",

  "container": {

  "type": "DOCKER",

  "docker": {

  "image": "mesosphere/simple-docker",

  "network": "BRIDGE",

  "portMappings": [

  { "hostPort": 80, "containerPort": 80, "protocol": "tcp"}

  ]

  }

  },

  "acceptedResourceRoles": ["slave_public"],

  "instances": 1,

  "cpus": 0.1,

  "mem": 64

  }

  修改数目的时候使用以下的命令

  dcos marathon app update basic-0 instances=6

  在最新版本的DCOS中,已经支持的pod的概念了。

  {

  "containers": [

  {

  "artifacts": [],

  "endpoints": [],

  "environment": {},

  "exec": {

  "command": {

  "shell": "sleep 1000"

  }

  },

  "healthCheck": null,

  "image": null,

  "labels": {},

  "lifecycle": null,

  "name": "sleep1",

  "resources": {

  "cpus": 0.1,

  "disk": 0,

  "gpus": 0,

  "mem": 32

  },

  "user": null,

  "volumeMounts": []

  }

  ],

  "environment": {},

  "id": "/simplepod2",

  "labels": {},

  "networks": [

  {

  "labels": {},

  "mode": "host",

  "name": null

  }

  ],

  "scaling": {

  "instances": 2,

  "kind": "fixed",

  "maxInstances": null

  },

  "scheduling": {

  "backoff": {

  "backoff": 1,

  "backoffFactor": 1.15,

  "maxLaunchDelay": 3600

  },

  "placement": {

  "acceptedResourceRoles": [],

  "constraints": []

  },

  "upgrade": {

  "maximumOverCapacity": 1,

  "minimumHealthCapacity": 1

  }

  },

  "secrets": {},

  "user": null,

  "volumes": []

  }

  在DCOS里面可以实现自动弹性伸缩,通过使用marathon-lb-autoscale,通过监控marathon-lb的情况进行弹性伸缩。

  在Kubernetes里面,副本数目是以pod为单位的,由controller进程控制,可以通过创建一个Deployment来控制副本数。

  apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1

  kind: Deployment

  metadata:

  name: nginx-deployment

  spec:

  replicas: 3

  template:

  metadata:

  labels:

  app: nginx

  spec:

  containers:

  - name: nginx

  image: nginx:1.7.9

  ports:

  - containerPort: 80

  Kubernetes也可以实现autoscaling。

  有一个组件Horizontal Pod Autoscaling,可以通过监控CPU的使用情况动态调整Pod的数量。

  六、编排

  为了能够通过编排文件一键创建整个应用,需要有编排功能。

  Swarm Mode的编排

  docker stack deploy --compose-file docker-compose.yml vossibility

  version: "2"

  services:

  foo:

  image: foo

  volumes_from: ["bar"]

  network_mode: "service:baz"

  environment:

  - "constraint:node==node-1"

  bar:

  image: bar

  environment:

  - "constraint:node==node-1"

  baz:

  image: baz

  environment:

  - "constraint:node==node-1"

  Marathon的编排是基于json文件

  {

  "id": "/product",

  "groups": [

  {

  "id": "/product/database",

  "apps": [

  { "id": "/product/database/mongo", ... },

  { "id": "/product/database/mysql", ... }

  ]

  },{

  "id": "/product/service",

  "dependencies": ["/product/database"],

  "apps": [

  { "id": "/product/service/rails-app", ... },

  { "id": "/product/service/play-app", ... }

  ]

  }

  ]

  }

  Kubernetes的编排是基于yml文件

  为redis-master服务新建一个名为redis-master-controller.yaml的RC定义文件

  apiVersion: v1

  kind: ReplicationController

  metadata:

  name: redis-master

  labels:

  name: redis-master

  spec:

  replicas: 1

  selector:

  name: redis-master

  template:

  metadata:

  labels:

  name: redis-master

  spec:

  containers:

  - name: master

  image: kubeguide/redis-master

  ports:

  - containerPort: 6379

  创建一个Service

  apiVersion: v1

  kind: Service

  metadata:

  name: redis-master

  labels:

  name: redis-master

  spec:

  ports:

  - port: 6379

  targetPort: 6379

  selector:

  name: redis-master

  七、服务发现与DNS

  容器平台的一个重要的功能是服务发现,也即当容器的地址改变的时候,可以自动进行服务之间的关联。

  一般的服务发现首先要通过DNS将服务名和应用关联起来,可以基于DNS对一个服务的多个应用进行内部负载均衡,也有直接加一个内部负载均衡器来做这件事情。

  Swarm Mode有一个内置的DNS组件,并且负载均衡也是根据DNS名来做的。

  DCOS的DNS组件是通过Mesos-DNS实现的,负载均衡有两种方式,一种是直接通过Mesos-DNS根据域名进行负载均衡。另一种方式是将DNS转化为VIP,然后有个内置的负载均衡器,DCOS有个组件minuteman是做这个事情的。

  Kubernetes的DNS组件是通过skyDNS实现的,负载均衡是通过将DNS转化为VIP,有个内置的负载均衡器kube-proxy来完成这件事情。

  八、容器

  Swarm Mode通过runC运行容器

  

  DCOS对于多种容器的支持Unified Container,可以支持Docker容器和Mesos容器。

  

  Kubernetes也是支持多种容器格式的。

  

  

  九、网络

  容器的网络配置两种:

  Docker Libnetwork Container Network Model(CNM)阵营

  ● Docker Swarm overlay

  ● Macvlan & IP network drivers

  ● Calico

  ● Contiv(from Cisco)

  Docker Libnetwork的优势就是原生,而且和Docker容器生命周期结合紧密;缺点也可以理解为是原生,被Docker“绑架”。

  Container Network Interface(CNI)阵营

  ● Kubernetes

  ● Weave

  ● Macvlan

  ● Flannel

  ● Calico

  ● Contiv

  ● Mesos CNI

  CNI的优势是兼容其他容器技术(e.g. rkt)及上层编排系统(Kuberneres & Mesos),而且社区活跃势头迅猛,缺点是非Docker原生。

  十、存储

  Swarm Mode的存储是通过Volume Plugin,可以在集群中接入外部的统一存储,可以支持Ceph,NFS,GlusterFS等。

  DCOS可以创建External Persistent Volumes,dvdi driver其实使用的也是Docker的volume driver,目前支持的是rexray,可以接入EC2,OpenStack等。

  Kubernetes可以创建Persistent Volumes,支持GCE,AWS,NFS,GlusterFS,Ceph等。

  十一、监控

  无论是Swarm Mode,还是Mesos,还是Kubernetes,容器的监控中Prometheus +cadvisor都是主流的方案,而cadvisor来自Kubernetes的一个组件。

  十二、大数据与包管理

  跑大数据是Mesos的强项,Spark就有一个依赖于Mesos部署,让Mesos作为调度器的方案。

  

  对于Swarm Mode和Kubernetes来讲,不会用自己的Scheduler来做大数据调用。

  但是Swarm Mode和Kubernetes是可以部署大数据框架的,但是大数据框架之间的任务的调度和通信,就与Swarm Mode和Kubernetes无关了。

  在kubernetes里面部署大数据可以参考https://github.com/kubernetes/examples

  十三、负载均衡

  这里的负载均衡指的是外部负载均衡。

  在Swarm Mode中,swarm manager通过ingress负载均衡,通过published port将服务端口暴露在Node上面,如果有外部云平台的负载均衡器,通过连接Node上的端口,可以对服务进行外部负载均衡。

  在DCOS中,外部负载均衡通过marathon-lb来实现。

  

  在kubernetes中,外部负载均衡器是通过一个ingress controller根据请求进行创建,如果在云平台例如GCE,可创建云平台的负载均衡器,云平台的负载均衡器可通过NodePort连接到后端的Service。

  https://github.com/kubernetes/ingress

  

  可以通过service连接后端的Pod.

  

  也可以不用service直接连接。

  十四、节点

  Swarm Mode的Node上面部署的是Swarm的worker,其实还是Docker Daemon,相对保持一致性。

  DCOS的Node上面干活的是Mesos-Agent,其实它还不是直接干活的,还有一层Executor真正的干活。

  kubernetes的Node上跑的是kubelet。

  十五、升级与回滚

  所有的容器平台对于容器多副本的升级全部都是要滚动升级。

  在Swarm Node里面可以配置rolling update策略

  docker service create --name=my_redis

  --replicas=5

  --rollback-parallelism=2

  --rollback-monitor=20s

  --rollback-max-failure-ratio=.2

  redis:latest

  在DCOS里面,rolling update也是默认的行为。

  在Kubernetes里面,同样有对rolling update的支持。

  kubectl rolling-update foo [foo-v2] --image=myimage:v2

  总而言之:三大平台的区别,大概相当于麦当劳和肯德基的区别,看你的口味,掌控能力,社区热度了。

  本文经过授权转载自订阅号“刘超的通俗云计算”(ID:popsuper1982)

  作者:刘超 网易云解决方案首席架构师

声明:本文由入驻搜狐公众平台的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
推荐阅读