通常指的是构造真实的虚拟版本,其中VMware和Docker是氨虚拟化技术中最具代表性的两种设计:
- 隔离(Isolation):在实体机上的所有虚拟机实例不能互相影响
- 仿真(Simulation):能够像在实体机上运行软件一样,包括开关机、以及各种各样的硬件设备
- 高效(Efficient):目标是减少虚拟机对CPU、硬件资源的占用
容器的设计
虚拟机虚拟的是计算机,而容器虚拟的是执行环境,和虚拟机有一个最大区别就是:容器时直接跑在操作系统之上,容器内部是应用,应用执行起来就是进程。这个进程和操作系统上的其他进程也没有本质区别,但这个架构设计没有了虚拟机监控系统。当然,容器有一个更轻量级的管理程序,用户可以从网络上下载镜像,启动起来就是容器。容器中预装了一些程序,比如说一个 Python 开发环境中,还会预装 Web 服务器和数据库。因为没有了虚拟机管理程序在中间的开销,因而性能会更高。而且因为不需要安装操作系统,因此容器安装速度更快,可以达到 ms 级别
容器以来操作系统的能力直接实现,比如:
- Linux 的 Cgroups(Linux Control Groups)能力,可以用来限制某组进程使用的 CPU 资源和内存资源,控制进程的资源能使用
- 另外Linux 的 Namespace 能力,可以设置每个容器能看到能够使用的目录和文件
容器编排技术(利用k8s和Docker Swarm管理微服务)
实际上讨论的就是如果管理海量的容器,如何构造一个高可用且扩展能力强的集群微服务
上图中的微服务 C 因为只有一个实例存在单点风险,可能会引发单点故障。因此需要为微服务 C 增加副本,通常情况下,我们必须保证每个微服务至少有一个副本,这样才能保证可用性
上述架构的核心就是要解决两个问题:
- 减少 downtime(就是减少服务不可用的时间)
- 支持扩容(随时都可以针对某个微服务增加容器)
因此,我们需要容器编排技术。容器编排技术指自动化地对容器进行部署、管理、扩容、迁移、保证安全,以及针对网络负载进行优化等一系列技术的综合体。Kubernetes 和 Docker Swarm 都是出色的容器编排方案
Kubernetes
节点
- Master节点时集群管理者
- Worker时工作节点
在我们为一个微服务扩容的时候,首选并不是去增加 Worker 节点。可以增加这个微服务的容器数量,也可以提升每个容器占用的 CPU、内存存储资源。只有当整个集群的资源不够用的时候,才会考虑增加机器、添加节点
Master 节点至少需要 2 个,但并不是越多越好。Master 节点主要是管理集群的状态数据,不需要很大的内存和存储空间。Worker 节点根据集群的整体负载决定,一些大型网站还有弹性扩容的手段,也可以通过 K8s 实现
单点架构
Pod 是 K8s 对容器的一个轻量级的封装,每个 Pod 有自己独立的、随机分配的 IP 地址。Pod 内部是容器,可以 1 个或多个容器。目前,Pod 内部的容器主要是 Docker,但是今后可能还会有其他的容器被大家使用,主要原因是 K8s 和 Docker 的生态也存在着竞争关系。总的来说,如下图所示,kubelet 管理 Pod,Pod 管理容器。当用户创建一个容器的时候,实际上在创建 Pod
虽然 K8s 允许同样的应用程序(比如微服务),在一个节点上创建多个 Pod。但是为了保证可用性,通常我们会考虑将微服务分散到不同的节点中去。如下图所示,如果其中一个节点宕机了,微服务 A,微服务 B 还能正常工作。当然,有一些微服务。因为程序架构或者编程语言的原因,只能使用单进程。这个时候,我们也可能会在单一的节点上部署多个相同的服务,去利用更多的 CPU 资源
负载均衡
Pod 的 IP 地址是动态的,如果要将 Pod 作为内部或者外部的服务,那么就需要一个能拥有静态 IP 地址的节点,这种节点我们称为服务(Service),服务不是一个虚拟机节点,而是一个虚拟的概念——或者理解成一段程序、一个组件。请求先到达服务,然后再到达 Pod,服务在这之间还提供负载均衡。当有新的 Pod 加入或者旧的 Pod 被删除,服务可以捕捉到这些状态,这样就大大降低了分布式应用架构的复杂度。当我们要提供服务给外部使用时,对安全的考虑、对性能的考量是超过内部服务的。 K8s 解决方案:在服务的上方再提供薄薄的一层控制程序,为外部提供服务——这就是 Ingress
思考总结
对于容器编排这样的设计,用户只需要指定哪些容器开多少个副本,容器编排引擎自动就会在工作节点之中复制这些容器。而服务是容器的分组,多个容器共享一个服务。容器自动被创建,用户在维护的时候不需要维护到容器创建级别,只需要指定容器数目,并指定这类型的容器对应着哪个服务。至于之后,哪一个容器中的程序执行出错,编排引擎就会杀死这个出错的容器,并且重启一个新的容器。
在这样的设计当中,容器最好是无状态的,所以容器中最好不要用来运行 MySQL 这样的数据库。对于 MySQL 数据库,并不是多个实例都可以通过负载均衡来使用。有的实例只可以读,有的实例只可以写,中间还有 Binlog 同步。因此,虽然 K8s 提供了状态管理组件,但是使用起来可能不如虚拟机划算。
也是因为这种原因,我们现在倾向于进行无状态服务的开发。所有的状态都是存储在远程,应用本身并没有状态。当然,在开发测试环境,用容器来管理数据库是一个非常好的方案。这样可以帮助我们快速搭建、切换开发测试环境,并且可以做到一人一环境,互不影响,也可以做到开发环境、测试环境和线上环境统一
如何利用K8s和Docker Swarm管理微服务?
这两个容器编排引擎都可以用来管理微服务。K8s 和 Docker Swarm 在使用微服务的时候有许多共性的步骤:
- 制作容器镜像:我们就是要先制作容器,如果使用 Docker 作为容器,那就要写 DockerFile,然后生成容器镜像
- 上传镜像:制作好容器之后,我们往往会将容器上传到容器的托管平台。很多公司内部有自己的容器托管平台,这样下载容器的速度会非常快
- 搭建集群:再接下来,我们要搭建一个 K8s 或者 Docker Swarm 的集群,将节点添加进去
- 添加微服务 Pod/Task:然后我们要在集群中添加 Pod 的或者 Task,可以通过命令行工具,也可以通过书写配置文件
- 设置服务:为 Pod/Task 设置服务,之后都通过服务来访问容器内的应用