Docker Swarm原理大解密
来源:互联网 发布:淘宝店铺图标大全 编辑:程序博客网 时间:2024/06/03 19:56
Docker Swarm原理大解密
Docker Swarm是docker公司2014年出品的基于docker的集群管理调度工具,官方文档地址:https://docs.docker.com/swarm/overview/。Swarm能够把多台主机构建成一个docker的集群,用户可以只和swarm api操作来管理多个主机上的docker,再结合上Overlay的网络实现简单的容器调度和互访。
Docker Swarm在设计上遵从了可插拔的设计思想,安装集群只需要启动几个docker就可以完成,安装过程可以参考这里:http://www.tuicool.com/articles/UJJJFjU。
总结下Swarm的特性:
1.工作节点的注册和发现
2.管理节点收集集群中所有的信息
3.管理节点支持HA
4.管理节点能感知集群的变化,在节点挂掉后重新调度上面的container
5.提供filter和scheduler的调度策略调度集群里的容器
下面,本文会从源码层面解密Swarm是如何实现上面的特性的。
首先上一张整体的架构图。
来自daocloud的架构图。
http://blog.daocloud.io/wp-content/uploads/2015/01/swarmarchitecture.jpg
工作节点的注册和发现
在工作节点启动时会在后端的kvstore上注册一个节点,路径是etcd://ip:2376/docker/swarm/nodeip,Worker会把当前集群的eth0
的ip注册上etcd,然后设置上一个ttl时间,比如3秒。然后启一个for循环每隔2秒(配置heartbeat)注册一次,这样,如果etcd上这个节点没了就说明这个worker已经挂了。
for { log.WithFields(log.Fields{"addr": addr, "discovery": dflag}).Infof("Registering on the discovery service every %s...", hb) if err := d.Register(addr); err != nil { log.Error(err) } time.Sleep(hb) }
Manager的leader会启动一个go router watch后端的kvstore上注册上来的ip,如果是新节点注册上来就把节点加入到manager的内存中,开始收集数据,如果是节点挂了就删除
discoveryCh, errCh := cluster.discovery.Watch(nil)go cluster.monitorDiscovery(discoveryCh, errCh)go cluster.monitorPendingEngines()for { select { case entries := <-ch: added, removed := currentEntries.Diff(entries) currentEntries = entries // Remove engines first. `addEngine` will refuse to add an engine // if there's already an engine with the same ID. If an engine // changes address, we have to first remove it then add it back. for _, entry := range removed { c.removeEngine(entry.String()) } for _, entry := range added { c.addEngine(entry.String()) } case err := <-errCh: log.Errorf("Discovery error: %v", err) } }
管理节点收集集群中所有的信息
管理节点会收集集群中所有主机的信息放到内存中。当一个主机加入到Swarm中时,首先会对节点上所有的信息都收集一把到内存中,然后会建立一个docker client长链接,通过event API获取这个主机上的更新。
加入主机时的代码,首先做主机的全同步,然后启动eventMonitor,监控主机上的event:
e.eventsMonitor = NewEventsMonitor(e.apiClient, e.handler)// Fetch the engine labels.if err := e.updateSpecs(); err != nil { return err}e.StartMonitorEvents()// Force a state update before returning.if err := e.RefreshContainers(true); err != nil { return err}if err := e.RefreshImages(); err != nil { return err}// Do not check error as older daemon doesn't support this call.e.RefreshVolumes()e.RefreshNetworks()
Event的Handler,会根据event的类别更新对应类型的数据。这里由于考虑docker event的兼容性有点长,我就只贴一段:
switch msg.Type {case "network": e.refreshNetwork(msg.Actor.ID)case "volume": e.refreshVolume(msg.Actor.ID)case "image": e.RefreshImages()case "container": action := msg.Action // healthcheck events are like 'health_status: unhealthy' if strings.HasPrefix(action, "health_status") { action = "health_status" } switch action { case "commit": // commit a container will generate a new image e.RefreshImages() case "die", "kill", "oom", "pause", "start", "restart", "stop", "unpause", "rename", "update", "health_status": e.refreshContainer(msg.ID, true) case "top", "resize", "export", "exec_create", "exec_start", "exec_detach", "attach", "detach", "extract-to-dir", "copy", "archive-path": // no action needed default: e.refreshContainer(msg.ID, false)
管理节点支持HA
同其他很多的分布式的项目一样,Docker Swarm也是利用了raft里选举算法做的HA,我们来看下它的实现。
首先创建好candidata和follower,顺便说下leader election的path是docker/swarm/leader
client := kvDiscovery.Store()p := path.Join(kvDiscovery.Prefix(), leaderElectionPath)candidate := leadership.NewCandidate(client, p, addr, leaderTTL)follower := leadership.NewFollower(client, p)
然后启两个协程,一个进行选举,如果成功了则成为leader,一个监听选举成功的消息,如果监听到别的manager成为leader则把自己设置成candidate,如果API请求到candidate会proxy到真正的manager。
primary := api.NewPrimary(cluster, tlsConfig, &statusHandler{cluster, candidate, follower}, c.GlobalBool("debug"), c.Bool("cors"))replica := api.NewReplica(primary, tlsConfig)go func() { for { run(cluster, candidate, server, primary, replica) time.Sleep(defaultRecoverTime) }}()go func() { for { follow(follower, replica, addr) time.Sleep(defaultRecoverTime) }}()server.SetHandler(primary)
管理节点能感知集群的变化,在节点挂掉后重新调度上面的container
由于worker会loop往kvstore上发送消息,因此如果节点挂掉时manager能立刻感知到变化,并触发removeEngine的动作,把container重新调度到其他节点上就很容易做到了。
提供filter和scheduler的调度策略调度集群里的容器
其实有了所有集群里的所有节点的信息,调度容器就变得比较简单了。Swarm提供了Filter和scheduler来让用户定义调度的策略。
调度本质上是让用户可以定义Container分配到集群中的策略。
Filter指定了如果满足这样的条件的节点不会(会)被分配上。
Scheduler指定了满足Filter后的节点按照怎样的优先级排序,排在前面的会被有限分配上Container。
Filter和Scheduler的种类我就不赘述了,可以参考官方文档:https://docs.docker.com/swarm/scheduler/rescheduling/#rescheduling-policies (貌似最近又有了新的策略 rescheduler)
调度的代码如下:
accepted, err := filter.ApplyFilters(s.filters, config, nodes, soft)if err != nil { return nil, err}if len(accepted) == 0 { return nil, errNoNodeAvailable}return s.strategy.RankAndSort(config, accepted)
在使用Docker Swarm的时候大家其实可以发现,Swarm的设计还是有一些缺陷的,这会导致Swarm的一些局限性,比如:
1.worker的行为过于简单。只是往kvstore上同步状态,就启动一个Container,不做任何实际的工作,把所有活都交给Manager干,颇为浪费。
2.由于worker”啥也不干“,Manager必须保持所有节点的tcp长链接,扩展性很差。
3.没有加入副本控制。
总结下,Swarm作为一代的Docker调度工具提供了基本的调度能力,可以满足一些内部的CI/CD系统使用,但是由于扩展性较差和没有副本控制,不能直接拿来部署线上系统,这是有的遗憾的。
- Docker Swarm原理大解密
- Docker Swarm
- Docker Swarm
- docker swarm
- Docker Swarm
- 数人云|关于Docker Swarm&K8S,几大要素免踩坑
- [docker]swarm初探
- docker swarm集群搭建
- 1.0.4、Docker Swarm
- Docker Swarm Overview
- Docker Swarm学习教程
- Docker swarm cluster 搭建
- Docker Swarm学习教程
- Docker Swarm入门教程
- Docker-Swarm调度策略
- Docker Swarm学习教程
- Docker Swarm主机发现
- Docker Swarm项目
- BZOJ 4300: 绝世好题 DP
- 2.8. Aspect Oriented Programming
- Fedora 是一款非常流行且非常广泛的 Linux 发行版之一!它基于 Fedora Project(由 Red Hat 资助支持),并由全球范围的社区志愿者和开发人员构建和维护。
- Set 、List 和 Map的区别及使用建议
- 如何查看Linux是32位还是64位
- Docker Swarm原理大解密
- iOS
- 2.9. Threading Model
- pycharm快捷键
- 分类器学习(三)
- Java面试题全集(8)
- 深入理解ajax系列第三篇——响应解码
- 决策树分类器(ID3、C4.5 Java实现)
- 大数据学习——数据挖掘理论基础