基本概念
Docker 是什么
Docker 起初是 dotCloud 公司创始人 Solomon Hykes 在法国的时候发起的一项公司内部项目,Docker 是基于 dotCloud 公司多年云服务技术的一次革新,在 2013 年 3 月以 Apache 2.0 授权协议进行开源,其项目主要代码在 GitHub 上进行维护,自从 Docker 开源之后,就一直受到了广泛讨论和关注。
Docker 进行开发实现使用的是 Google 公司推出的 Go 语言,对进程进行封装隔离是基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,这属于操作系统层面的虚拟化技术。因为隔离的进程独立于宿主与其它隔离的进程,所以也称其为容器(后文会对“容器”的概念进行详细介绍)。Docker 在容器的基础上,进行了进一步的封装,从网络互联、文件系统到进程隔离等,大大地简化了容器的创建和维护,让 Docker 技术比虚拟机技术更加轻便、快捷。
以下两张图片对比了 Docker 与传统虚拟化方式的不同之处。Docker 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,没有进行硬件虚拟;而传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程。因此容器要比传统虚拟机更为轻便。
图为 传统虚拟化
图为 Docker
为什么要使用 Docker?
Docker 是一种新兴的虚拟化方式,跟传统的虚拟化方式相比具有众多优势。
- 系统资源利用更高效
因为容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,所以 Docker 对系统资源的利用率更高。
- 启动时间更快速
Docker 容器应用由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。极大地节省了开发、测试,部署的时间。
- 运行环境一致性
开发过程中比较常见的问题就是环境一致性问题。因为开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 “这段代码在我机器上没问题啊!”这类问题。
- 持续交付与部署
对开发和运维人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合持续集成(Continuous Integration)系统进行集成测试,而运维人员则可以直接在各种环境中快速部署该镜像,甚至结合持续部署(Continuous Delivery/Deployment) 系统进行自动部署。
而且使用 Dockerfile 使镜像构建透明化,不仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好地在生产环境中部署该镜像。
- 迁移更轻松
由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻松地将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境变化导致应用无法正常运行的情况。
- 维护和扩展更轻松
Docker 使用的分层存储以及镜像技术,使得应用重复部分的复用更为容易,也使得应用的维护更新和基于基础镜像进一步扩展镜像变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大降低了应用服务的镜像制作成本。
Docker 的镜像和容器
Docker 的口号是“Build, Ship and Run Any App, Anywhere.”,大意是编译好一个应用后,可以在任何地方运行,不会像传统的程序一样,一旦换了运行环境,往往就会出现缺这个库,少那个包的问题。那么 Docker 是怎么做到这点的呢?
简单说就是它在编译应用的时候把这个应用依赖的所有东西都构建到镜像里面(有点像程序的静态编译——只是像而已)。我们把这个编译构建好的东西叫 Docker 镜像(Image),然后当 Docker deamon(Docker 的守护进程/服务进程)运行这个镜像的时候,我们称其为 Docker 容器(Container)。可以简单理解 Docker 镜像和 Docker 容器的关系就像是程序和进程的关系一样(当然实质是不一样的)。
Images 和 Layers
每个 Docker 镜像(Image)都引用了一些只读的(read-only)层(layer),不同的文件系统 layer 也不同。这些 layer 堆叠在一起构成了容器(Container)的根文件系统(root filesystem)。下图是 Ubuntu 15.04 的镜像,共由 4 个镜像层(image layer)组成:
Container 和 Layers
容器和镜像的主要区别就是顶部的那个可写层(即之前说的那个“container layer”)。容器运行时做的所有操作都会写到这个可写层里面,当容器删除的时候,这个可写层也会被删掉,但底层的镜像依旧保持不变。所以,不同的容器都有自己的可写层,但可以共享同一个底层镜像。下图展示了多个容器共享同一个 Ubuntu 15.04 镜像。
Docker 的 storage driver 负责管理只读的镜像层和可写的容器层,当然不同的 driver 实现的方式也不同,但其后都有两项关键技术:可堆叠的镜像层(stackable image layer)和写时拷贝技术(copy-on-write, CoW)。
Docker 数据持久化
刚开始的时候,Docker 一般只适用于无状态的计算场景使用。但随着发展,Docker 通过 data volume 技术也可以做到数据持久化了。Data volume 就是我们将主机的某个目录挂载到容器里面,这个 data volume 不受 storage driver 的控制,所有对这个 data volume 的操作会绕过 storage driver 直接其操作,其性能也只受本地主机的限制。而且我们可以挂载任意多个 data volume 到容器中,不同容器也可以共享同一个 data volume。
下图展示了一个 Docker 主机上面运行着两个容器.每一个容器在主机上面都有着自己的地址空间(/var/lib/docker/…),除此以外,它们还共享着主机上面的同一个/data 目录。
Kubernetes 简介
Kubernetes 是谷歌开源的容器集群管理系统,是 Google 多年大规模容器管理技术 Borg 的开源版本,主要功能包括:
- 于容器的应用部署、维护和滚动升级
- 负载均衡和服务发现
- 跨机器和跨地区的集群调度
- 自动伸缩
- 无状态服务和有状态服务
- 广泛的 Volume 支持
- 插件机制保证扩展性
Kubernetes 发展非常迅速,已经成为容器编排领域的领导者。
Kubernetes 是什么
Kubernetes 提供了很多的功能,它可以简化应用程序的工作流,加快开发速度。通常,一个成功的应用编排系统需要有较强的自动化能力,这也是为什么 Kubernetes 被设计作为构建组件和工具的生态系统平台,以便更轻松地部署、扩展和管理应用程序。
用户可以使用 Label 以自己的方式组织管理资源,还可以使用 Annotation 来自定义资源的描述信息,比如为管理工具提供状态检查等。
此外,Kubernetes 控制器也是构建在跟开发人员和用户使用的相同的 API 之上。用户可以编写自己的控制器和调度器,也可以通过各种插件机制扩展系统的功能。这种设计使得用户可以方便地在 Kubernetes 之上构建各种应用系统。
Kubernetes 不是什么
Kubernetes 不是一个传统意义上,包罗万象的 PaaS (平台即服务) 系统。它给用户预留了选择的*。
- 不限制支持的应用程序类型,它不插手应用程序框架, 也不限制支持的语言 (如 Java, Python, Ruby 等),Kubernetes 旨在支持极其多样化的工作负载,包括无状态、有状态和数据处理工作负载。只要应用可以在容器中运行,那么它就可以很好地在 Kubernetes 上运行。
- 不提供内置的中间件 (如消息中间件)、数据处理框架 (如 Spark)、数据库 (如 mysql) 或集群存储系统 (如 Ceph) 等。这些应用直接运行在 Kubernetes 之上。
- 不提供点击即部署的服务市场。
- 不直接部署代码,也不会构建用户的应用程序,但用户可以在 Kubernetes 之上构建需要的持续集成 (CI) 工作流。
- 允许用户选择自己的日志、监控和告警系统。
- 不提供应用程序配置语言或系统 (如 jsonnet)。
- 不提供机器配置、维护、管理或自愈系统。
另外,已经有很多 PaaS 系统运行在 Kubernetes 之上,如 Openshift, Deis 和 Eldarion 等。 你也可以构建自己的 PaaS 系统,或者只使用 Kubernetes 管理你的容器应用。
当然了,Kubernetes 不仅仅是一个 “编排系统”,它消除了编排的需要。Kubernetes 通过声明式的 API 和一系列独立、可组合的控制器保证了应用总是在期望的状态,而用户并不需要关心中间状态是如何转换的。这使得整个系统更容易使用,而且更强大、更可靠、更具弹性和可扩展性。
基本组件
核心组件
Kubernetes 主要由以下几个核心组件组成:
- etcd:保存了整个集群的状态;
- apiserver:提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;
- controller manager:负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;
- scheduler:负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;
- kubelet:负责维护容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;
- Container runtime:负责镜像管理以及 Pod 和容器的真正运行(CRI);
- kube-proxy:负责为 Service 提供 cluster 内部的服务发现和负载均衡
除了核心组件,还有一些推荐的 Add-ons:
- kube-dns:负责为整个集群提供 DNS 服务
- Ingress Controller:为服务提供外网入口
- Heapster:提供资源监控
- Dashboard:提供 GUI
- Federation:提供跨可用区的集群
- Fluentd-elasticsearch:提供集群日志采集、存储与查询
组件详细介绍
Etcd
Etcd 是 CoreOS 基于 Raft 开发的分布式 key-value 存储,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)。
Etcd 主要功能:
- 基本的 key-value 存储
- 监听机制
- key 的过期及续约机制,用于监控和服务发现
- 原子 CAS 和 CAD,用于分布式锁和 leader 选举
kube-apiserver
kube-apiserver 是 Kubernetes 最重要的核心组件之一,主要提供以下的功能:
- 提供集群管理的 REST API 接口,包括认证授权、数据校验以及集群状态变更等
- 提供其他模块之间的数据交互和通信的枢纽(其他模块通过 API Server 查询或修改数据,只有 API Server 才直接操作 etcd)
kube-controller-manager
Controller Manager 由 kube-controller-manager 和 cloud-controller-manager 组成,是 Kubernetes 的大脑,它通过 apiserver 监控整个集群的状态,并确保集群处于预期的工作状态。
kube-controller-manager 由一系列的控制器组成
- Replication Controller
- Node Controller
- CronJob Controller
- Daemon Controller
- Deployment Controller
- Endpoint Controller
- Garbage Collector
- Namespace Controller
- Job Controller
- Pod AutoScaler
- RelicaSet
- Service Controller
- ServiceAccount Controller
- StatefulSet Controller
- Volume Controller
- Resource quota Controller
cloud-controller-manager
在 Kubernetes 启用 Cloud Provider 的时候才需要,用来配合云服务提供商的控制,也包括一系列的控制器,如:
- Node Controller
- Route Controller
- Service Controller
kube-scheduler
kube-scheduler 负责分配调度 Pod 到集群内的节点上,它监听 kube-apiserver,查询还未分配 Node 的 Pod,然后根据调度策略为这些 Pod 分配节点(更新 Pod 的 NodeName 字段)。
调度器需要充分考虑诸多的因素:
- 公平调度
- 资源高效利用
- QoS
- affinity 和 anti-affinity
- 数据本地化(data locality)
- 内部负载干扰(inter-workload interference)
- deadlines
Kubelet
每个节点上都运行一个 kubelet 服务进程,默认监听 10250 端口,接收并执行 master 发来的指令,管理 Pod 及 Pod 中的容器。每个 kubelet 进程会在 API Server 上注册节点自身信息,定期向 master 节点汇报节点的资源使用情况,并通过 cAdvisor 监控节点和容器的资源。
Container runtime
容器运行时(Container Runtime)是 Kubernetes 最重要的组件之一,负责真正管理镜像和容器的生命周期。Kubelet 通过 Container Runtime Interface (CRI) 与容器运行时交互,以管理镜像和容器。
kube-proxy
每台机器上都运行一个 kube-proxy 服务,它监听 API server 中 service 和 endpoint 的变化情况,并通过 iptables 等来为服务配置负载均衡(仅支持 TCP 和 UDP)。
kube-proxy 可以直接运行在物理机上,也可以以 static pod 或者 daemonset 的方式运行。
kube-proxy 当前支持一下几种实现:
- userspace:最早的负载均衡方案,它在用户空间监听一个端口,所有服务通过 iptables 转发到这个端口,然后在其内部负载均衡到实际的 Pod。该方式最主要的问题是效率低,有明显的性能瓶颈。
- iptables:目前推荐的方案,完全以 iptables 规则的方式来实现 service 负载均衡。该方式最主要的问题是在服务多的时候产生太多的 iptables 规则,非增量式更新会引入一定的时延,大规模情况下有明显的性能问题
- ipvs:为解决 iptables 模式的性能问题,v1.8 新增了 ipvs 模式,采用增量式更新,并可以保证 service 更新期间连接保持不断开
- winuserspace:同 userspace,但仅工作在 windows 上。
Kubernetes 架构
K8s 设置由几个部分组成,其中一些是可选的,一些是整个系统运行所必需的。下面是 k8s 的全局架构图:
Kubernetes 有两个不同的部分构成,一个是 Master,一个是 Node。Master 负责调度资源和为客户端提供 API,客户端可以是 UI 界面或者 CLI 工具,在 Kubernetes 中 CLI 工具通常为 kubectl。 Kubernetes Master 接受使用 YAML 定义的配置文件,根据配置文件中相关信息将容器分配到其中一个 Node 上。另外,镜像库在 Kubernetes 中也起到一个很重要的角色,Kubernetes 需要从镜像库中拉取镜像基于这个镜像的容器才能成功启动。常用的镜像库有 dockerhub、阿里云镜像库等。下面图片为 Master 的架构图:
Master 有三个组件:API Server、Scheduler、Controller。API Server 提供了友好易用的 API 供外部调用,同时有很多强大的工具使得 API 调用更加简单,如 kubectl 封装了大量 API 调用,使得部署、配置更加简单。Kubernetes-dashboard 可以让用户在界面上操作 Kubernetes,而无需手动输入各个 API 的调用地址参数等信息。
当 API Server 收到部署请求后,Scheduler 会根据所需的资源,判断各节点的资源占用情况分配合适的 Node 给新的容器。判断依据包括内存、CPU、磁盘等。
Controller 负责整个集群的整体协调和健康,保证每个组件以正确的方式运行。
在图的最下边是 ETCD 数据库。如前文所述 ETCD 是分布式存储数据库,其作为 Kubernetes 的*数据库,存储了集群的状态,组件可以通过查询 ETCD 了解集群的状态。
Kubernetes Master 分配容器到 Node 执行,Node 将会承受压力,通常情况下新容器不会运行在 Master 上。或者说 Master 是不可调度的,但是你也可以选择把 Master 同时也作为 Node,但是这并不是地道的用法。下面的为 Node 的架构图:
Kube-proxy 在 Node 中管理网络,其左右至关重要。Kube-proxy 通过管理 iptables 等方式使得 pod 到 pod 之间,和 pod 到 node 之间网络能够互通。实质上在跨主机的 pod 之间网络也能够互通。
Kubelet 负责向 api server 报告信息,并把健康状态、指标和节点状态信息存入 ETCD 中。
Docker 上文已详细介绍这里就不多做阐述。
Supervisord 保证 Docker 和 kubelet 一直在运行中,supervisord 并不是必须组件,可以使用其他类似组件替换。
Pod 是可以在 Kubernetes 中创建和管理的最小可部署计算单元。一个 POD 中可以包含多个容器,但 Kubernetes 仅管理 pod。如果多个容器运行在一个 POD 中,就相当于这些容器运行在同一台主机中,需要注意端口占用问题。
参考资料
https://yeasy.gitbooks.io/docker_practice/content/introduction/what.html
https://yeasy.gitbooks.io/docker_practice/content/introduction/why.html
https://docs.docker.com/storage/storagedriver/
https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/
https://www.youtube.com/watch?v=zeS6OyDoy78
本文由猪齿鱼技术团队原创,转载请注明出处:猪齿鱼官网
关于猪齿鱼
猪齿鱼Choerodon全场景效能平台,提供体系化方法论和协作、测试、DevOps及容器工具,帮助企业拉通需求、设计、开发、部署、测试和运营流程,一站式提高管理效率和质量。从团队协同到DevOps工具链、从平台工具到体系化方法论,猪齿鱼全面满足协同管理与工程效率需求,贯穿端到端全流程,助力团队效能更快更强更稳定。