云计算核心技术之容器技术
一、容器技术
1.1、为什么需要容器
在使用虚拟化一段时间后,发现它存在一些问题:不同的用户,有时候只是希望运行各自的一些简单程序,跑一个小进程。为了不相互影响,就要建立虚拟机。如果建虚拟机,显然浪费就会有点大,而且操作也比较复杂,花费时间也会比较长。而且,有的时候,想要迁移自己的服务程序,就要迁移整个虚拟机。显然,迁移过程也会很复杂。有没有办法更灵活快速一些呢?有,这就引入了“容器(Container)” 。
1.2、容器和虚拟机的区别
容器也是虚拟化,但是属于“轻量级”的虚拟化。它的目的和虚拟机一样,都是为了创造“隔离环境”。但是,它又和虚拟机有很大的不同——虚拟机是操作系统级别的资源隔离,而容器本质上是进程级的资源隔离。
虚拟机通常包括整个操作系统和应用程序。它们还需要一个与它们一起运行的管理程序来控制虚拟机。由于它们包括操作系统,因此它们的大小为几千兆字节。使用虚拟机的一个缺点是,它们需要花费几分钟来启动操作系统,并初始化它们所承载的应用程序。同时,这些容器是轻量级的,并且大部分在兆字节大小范围内。与虚拟机相比,容器的性能要好得多,几乎可以立即启动。
1.3、容器的优缺点
容器技术主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用容器可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其它机器上。 | ||
序号 | 容器的优点 | 容器的缺点 |
1 | 敏捷环境 (容器创建实例比虚拟机要快非常多,容器轻量级的脚本可以从性能和大小两个方面减小开销) | 复杂性增加 (随着容器和应用数量的增加,同时也伴随着复杂性的增加;在生产环境中管理如此多的容器是一个极具挑战性的任务,虽然说可以使用K8s等编排工具去管理这些容器,但是随着服务和应用的增加,管理的难度也会随之增加) |
2 | 提高生产力 (容器可以移除跨服务依赖和冲突提高开发者的生产能力;每个容器都可以看作是一个不同微服务,因此可以独立升级,而不用担心同步) | 原生Linux支持 (大多数的容器技术(如Docker)最初都是基于Linux容器来进行开发和实现的,相比于在原生Linux中运行的容器,在Windows环境中使用容器就会显得很笨拙,并且日常的使用也会带来一些复杂性。也就是说容器在Linux下支持很好,但是在Windows环境下支持会很差) |
3 | 版本控制 (每个容器的镜像都有版本控制,这样就可以追踪不同版本的容器,监控版本之间的差异等) | 不太成熟 (这也是相对的,随着技术的发展会逐渐成熟;容器技术在目前的市场上是相对较新的技术,是需要时间来适应市场;开发者可用的资源也是有限的(如:若开发者遇到问题需要花费更多的时间去解决)) |
4 | 运行环境可移植 (容器封装了所有应用程序所必须得相关细节(如:应用程序所依赖的一些软件包以及操作系统)这就使得镜像从一个环境移植到另外一个环境变得非常灵活以及高效(如:同一个镜像既可以在Windows或Linux进行开发测试,然后也可以在其他环境下之间去运行)) | |
5 | 标准化 (大多数的容器是基于开放的标准,可以运行在所有主流的Linux发行版本、Windows平台等) | |
6 | 安全 (容器之间的进程是互相隔离的,其中的基础设施也是如此,这样其中一个容器的升级、变化时不会影响到其他容器】) |
1.4、容器的分类
常见的容器有【操作系统容器】和【应用系统容器】 | ||
序号 | 操作系统容器 | 应用程序容器 |
1 | 操作系统容器是一种操作系统级别的虚拟化,操作系统内核是允许存在多个独立的用户空间实例的;从程序运行的角度来看这些实例一般都会被称为容器虚拟化引擎【操作系统容器中,可以运行多个服务和进程】 | 应用程序虚拟化是一种软件技术,它从执行它的底层操作系统中封装计算机程序;一个完全虚拟化的应用程序并不是传统意义上的安装,尽管它仍然像以前一样去正常运行。 那么应用程序在运行时的行为就像它直接与原始操作系统以及由它管理的所有资源一样,但可以不同程度的隔离或沙盒化,因此我们说应用容器的设计就是将【服务打包并作为单个进程运行】 (如:Docker、Rocket容器就是应用程序容器,当我们启动Docker容器时会运行一个进程,但为应用程序创建容器时这个过程通常是会运行应用程序的一个进程,这与传统的操作系统容器是不同的【因为在传统操作系统容器中,一个操作系统容器会运行多个服务】)。 |
2 | 操作系统容器是共享主机操作系统内核,但提供用户空间的隔离,可以安装配置不同的应用程序。就和在主机上运行程序一样;同样分配给容器的资源,仅仅对该容器可见。任何来宾用户的系统镜像都无法访问其他来宾系统的资源。 由于操作系统容器提供的虚拟环境与相互隔离的用户空间共享内核的方法去实现;因此操作系统容器是非常适合运行同一应用不同版本的需求,对于相同版本更是容易。但大多数情况下容器是以模板或镜像的方式创建的,那么这些模板或镜像决定了容器的结构和内容,并且去创建普通环境的容器也是十分方便的。 | 当需要将应用程序打包并作为组件分发时,应用程序容器是个很好的选择。 |
3 | 如果只想要一个可以安装不同库、语言、数据库的操作系统,那么操作系统容器更适合。 |
1.5、容器的主要应用场景
容器技术的诞生其实主要解决了PAAS的层的技术实现。像OpenStack、 Cloudstack这样的技术是解决IAAS层的问题。 IAAS层和PAAS层前面已经做过介绍,关于它们的区别和特性我这里不在描述。那么容器技术主要应用在哪些场景呢?目前主流的有以下几种:
序号 | 容器主要应用场景 | 说明 |
1 | 容器化传统应用 | 容器不仅可以提高现有应用的安全性和可一致性还能节省成本;每个企业的环境中都有一套较旧的应用来服务于客户或自动执行业务流程; 即使是大规模的单体应用,通过容器隔离的增强安全性以及可移植性的特点,也能从Docker中获得收益,从而降低成本。一旦容器化之后,这些应用可以扩展额外的服务,或者转变为微服务架构 |
2 | 持续集成和持续部署 (CI/CD) | 通过Docker可以加速应用管道自动化和应用部署,交付的速度至少要提高十几倍; 现在开发流程非常快,需要持续且具备自动执行的能力,最终是要开发出更可靠的软件,那么通过持续集成和持续部署,每次开发人员迁入代码并顺利测试之后,IT团队都能够去集成新的代码;作为运维开发方向的基础CI/CD创造了一种实时反馈的回路机制,持续的传输小型迭代更改,从而加速更改,提高质量。 CI环境通常是完全自动化的,通过Git推送命令触发测试,测试成功后,会自动构建新镜像,然后推送到Docker镜像仓库,通过后续的自动化和脚本,可以将新镜像的容器部署到预演环境,从而进一步进行测试。 |
3 | 微服务 | 通过微服务可以加速应用架构现代化的进度,应用架构正在从采用瀑布模式开发的方法,然后转变为独立开发和部署的松耦合的服务模式,那么成千上万的服务相互连接起来就形成了一个应用。 Docker是允许开发人员,选择最适合于哪种服务的技术栈,隔离服务可以消除潜在的冲突,从而避免地狱式的矩阵依赖,那么这些容器可以独立于应用的其他服务组件,轻松的共享、部署、更新和瞬间扩展。 Docker的端到端的安全功能,可以让团队能够构建和运行最低权限的微服务模型,服务所需的一些资源( 如:应用、生命信息、计算资源等)会实时的被创建并被访问。 |
4 | IT 基础设施优化 | Docker和容器是有助于优化IT基础设施,它的成本利用率;优化不仅仅是削减成本,还能确保在适当的时候有效地使用适当的资源。 容器是一种轻量级的打包和隔离应用工具,所以Docker允许在同一物理或虚拟服务器上,毫不冲突的运行多个项目的工作;企业可以整合数据中心,将并购而来的IT资源进行整合,从而获得像云端的可迁移性;同时减少操作系统和服务器的一些维护工作。 |
二、容器引擎
2.1、Docker引擎
多数技术人员在谈到Docker时,主要是指Docker引擎。Docker引擎是用于运行和编排容器的基础设施工具。开源后的Docker在2013年突然一炮而红,Docker几乎已经成为了容器技术的代名词;但容器技术其实早就已经存在了,之所以传统的容器技术没有成为主流的原因,是因为它没有能够提供标准化的应用运行环境。而基于容器技术的Docker是一开始就以提供标准化运行时环境为目标的,它真正做到了构建一次,到处运行的理念,所以Docker就火起来了。相比传统的虚拟机Docker的优势十分明显:《1》启动时间很快是秒级甚至毫秒级;《2》对资源的利用率很高(一台主机上可以同时运行几十上百上千个容器都是可以的);《3》占用空间很小(一般占用几十兆几百兆)。
Docker引擎是运行容器的核心容器运行时。其他 Docker公司或第三方的产品都是围绕Docker引擎进行开发和集成的。
2.2、Docker核心技术
Docker的核心技术包括【docker镜像】【docker容器】和【docker仓库】。
2.2.1、Docker镜像
Docker镜像是一个特殊的文件系统,它提供了容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等) 。镜像不包含任何动态数据,其内容在构建之后也不会被改变(只读属性)。镜像结构如下图所示:
序号 | 镜像内容 | 说明 |
1 | 可写容器(container) | 【可写】 |
2 | 镜像(tomcat) | 【不可写】 |
3 | 镜像(jdk) | 【不可写】 |
4 | rootfs基础镜像(Centos/Ubuntu) | 是典型的Linux文件系统,主要包含目录系统(如:dev、etc、bin、proc等)这些内容都是Linux系统标准的目录和文件【是操作系统的基础镜像】【不可写】 |
5 | bootfs | 是典型的Linux文件系统,主要包含启动引导、内核程序;这个启动引导主要是加载内核,当内核加载到内存之后,这个bootfs就会被卸载掉【是操作系统的基础镜像】【不可写】 |
2.2.2、Docker容器
序号 | 说明 |
1 | 镜像(Image)和容器(Container)有紧密的关系,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。 |
2 | 容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。因此容器可以拥有自己的root文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。 |
3 | 容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机 |
4 | 容器也是与镜像一样分层存储,每次容器运行时,是以镜像为基础层在其之上创建当前容器的存储层(称之为容器运行时); 为读写而准备的存储层称之为容器存储层(容器存储层的生命周期和容器是一样的,容器消亡时容器存储层也随之消亡,任何存保存存储层的数据信息都会随着容器的删除而删除【所以容器中的存储层是不应该写入任何数据进行存储的,容器存储层应该保持一个无状态变化,所有的文件写入操作都应该使用【数据卷】或者【绑定宿主机目录】(也就是把数据写入到宿主机目录中)】数据卷的生命周期是独立于容器的(即与容器无关))。 |
2.2.3、Docker仓库
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务, Docker Registry 就是这样的服务。
一个 Docker Registry 中可以包含多个仓库(Repository),每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本:
《1》我们可以通过【仓库名:标签】的格式来指定具体这个软件是哪个版本的镜像;
《2》若不给标签则以【latest】为默认的标签。
仓库可以分为【公共仓库】【私有仓库】:
《1》公共仓库:主要提供公开的服务,允许用户免费的去下载镜像、上传镜像(最大的仓库就是Docker的Docker Hub、国内可以使用阿里云镜像仓库);
《2》私有仓库:适用于内部数据和机密数据的镜像场景(可用于构建本地私有仓库的知名软件有:VMware Harbor 、Nexus Repository)。
三、容器编排工具
3.1、容器编排工具Kubernetes
容器编排工具Kubernetes,中文意思是舵手或导航员。 Kubernetes这个单词很长不好记,所以大家把K到S中间8个字母缩写成8,就成了K8S。
Kubernetes是谷歌开源的容器管理系统,在Docker基础之上为容器化的应用提供了【部署运行】【资源调度】【服务发现】【动态伸缩】等一系列的完整编排功能,提高了大规模容器集群管理的便捷性。K8S的主要设计思想是从更宏观的角度,以统一的方式来定义任务之间的各种关系,并且为将来支持更多种类的任务留下足够的余地。
K8S擅长的就是按照用户的意愿和整体的系统规则完全自动化的去处理好容器之间的各种关系,这种功能就是我们经常说到的编排。K8S的本质就是【为用户提供一个具有普遍意义的容器编排工具】。【K8S是对Docker容器的编排】【OpenStack是对KVM虚拟化的编排】。
K8S是一个容器集群管理系统,主要职责是容器编排(Container Orchestration) ——启动容器,自动化部署、扩展和管理容器应用,还有回收容器。简单来说, K8S有点像容器的保姆。它负责管理容器在哪个机器上运行,监控容器是否存在问题,控制容器和外界的通信等等。
3.2、Kubernetes的重要概念
序号 | Kubernetes重要概念 | 说明 |
1 | Cluster | 是计算存储和网络资源的集合;K8S就是利用这些资源进行各种基于容器的应用 |
2 | Master | 是Cluster的大脑,主要职责是调度,是用来决定将应用放到哪里去运行【是K8S中的管理者角色,可以有多个】。 Master是运行在Linux操作系统中,这个系统可以是物理机或者虚拟机,为了实现高可用性,我们在实际的生产环境当中,会把Master做成多个,实现高可靠性【K8S是支持多Master架构】 |
3 | Node | Node的职责是运行容器应用【负责监控、汇报容器状态】,是由Master管理(Node同时可以根据Master的要求去管理应用的生命周期)。 Node也是运行在Linux操作系统中,这个系统可以是物理机或者虚拟机。 |
4 | Pod | Pod是K8S中最小的工作单元,每个Pod可以包含一个或者多个容器; Pod中的容器会被看作是一个整体被Master调度到一个Node中去运行,Pod有两种使用方式: 《1》一个Pod运行单一的容器(运行单一容器是K8S最常见的模型,即便只有一个容器,K8S管理的也是一个Pod,不会直接管理容器); 《2》一个Pod运行多个容器(Pod中运行多个容器的话,哪些容器应该放到一个Pod中呢?【答案是这些容器联系必须非常紧密,而且需要共享资源的时候,才需要把多个容器放到一个Pod里面】); |
5 | Controller | K8S不会直接创建Pod,而是通过Controller来管理Pod; Controller定义了Pod的部署特性(如:Pod有几个副本、在什么样的Node去运行)为了满足不同的业务场景,K8S提供了多种Controller(如: 《1》Replicat Controller【简称RC】(是K8S集群中最早保证Pod高可用的API对象,通过监控运行中的Pod来保证集群中运行指定数目的Pod副本,指定的数目可以是一个也可以是多个,少于指定数目时RC就会启动运行新的Pod副本;多于指定数目时,RC就会杀死多余的Pod副本;即使在指定Pod数目为一的情况,通过RC运行Pod也比直接运行Pod明智,因为RC可以发挥它高可用的能力,永远保证有指定数目的Pod副本在运行)【只适用于长期伺服型的业务类型(如:提供高可用的Web服务等),目前已经很少使用了】。 《2》Replica Set【简称RS】、 《3》Deployment【部署】、 《4》Daemonset【后台支撑型服务】、 《5》Job等)。 |
6 | Replica Set (RS) | Replica Set【简称RS】是新一代的RC(或者是RC的升级版)同样提供了高可用的能力,区别在于:RS后来居上,能够支持更多种类的匹配模式。 RS对象一般不单独使用,而是作为Deployment这样的资源一块配合使用;使用Deployment的时候,Deployment会自动创建RS,也就是说Deployment是通过RS来管理Pod的多个副本的;我们通常是不用直接去使用RS。 |
7 | deployment(部署) | deployment表示用户对K8S集群的一次更新操作,它是一个比RS业务模式更广的API对象;它可以创建一个新的服务、更新一个新的服务、也可以滚动升级一个服务。 以K8S的发展方向来说,未来对所有长期伺服型的业务管理,都会去通过deployment来进行管理实现 |
8 | daemonset (后台支撑型服务) | 长期伺服型和批处理型服务的核心,在业务应用:可能有些节点在运行多个同类业务的Pod,有些节点又没有这类业务在运行;而后台支撑型服务的核心的关注点是在K8S中每个节点,它要保证每个节点上都有一个此Pod在运行,节点可能是所有集群节点选定的一些特定节点。 典型的后台支撑性服务节点包括:【存储】【日志】【监控】等在每个节点上支持K8S集群运行的服务 |
9 | Service | Service的用途首先要从deployment来说,deployment可以部署多个Pod副本,每个Pod都有自己的IP地址,那么这个时候外界是如何去访问这些副本呢?【答案就是Service】。 K8S的Service定义了外界访问一组特定的Pod的方法方式,Service也有自己的IP和端口,并且Service为Pod服务提供了一个负载均衡;K8S运行容器Pod与访问容器这两项任务分别是由Controller和Service来执行的。 |
10 | namespace | 可以将一个物理的Cluster集群逻辑上划分为多个虚拟的集群,那么每个集群就是一个namespace;不同的namespace的资源是完全隔离的,K8S默认创建了两个namespace: 《1》其中一个是default(这个是创建资源池如果不指定就会把资源放到这个namespace里面来)、 《2》另外一个是系统自动创建的kube-system(K8S自己创建的系统资源都会放到这个namespace当中)。 |
3.3、Kubernetes运行架构
Kubernetes属于主从分布式架构,主要由Master Node和Worker Node(一般叫做Node节点)成,以及包括客户端命令行工具kubectl和其它附加项来组成。基本架构如下图所示:
![]() | ||
序号 | Master节点运行的服务 | 说明 |
1 | kube-apiserver | 是K8S的前端接口;各种客户端工具,以及K8S的其他组件都可以通过kube-apiserver来管理集群中的各种资源【是K8S管理集群的入口】 |
2 | kube-scheduler | 是负责决定将Pod放到哪个Node上去运行;另外kube-scheduler在调度时它也会充分考虑集群的架构、当前各个节点的负载、以及应用对高可用系统的性能、数据亲和性等的需求 |
3 | kube-controller-manager | 主要是用来维护集群的状态(如:故障检测、自动扩展、滚动更新等);不同的Controller管理的资源是不同的。 |
4 | Etcd | Etcd是负责保存K8S集群的配置信息和各种集群的状态信息; K8S中所有服务节点的信息和服务数据(包括:配置数据)都是存储在Etcd中;当数据发生变化的时候,Etcd会快速的通知K8S的相关组件 |
5 | pod网络(flannel ) 等 | Pod要能够互相通信,K8S集群必须要能够掌握Pod网络;Pod网络我们使用比较多的就是flannel(是K8S集群网络互联的一个可选方案) |
![]() | ||
序号 | Node节点运行的服务 | 说明 |
1 | Kubelet | 是Node的Agent(当kube-scheduler去确定在某个Node上进行Pod后,会将Pod的具体配置信息发送给改节点的Kubelet,Kubelet会根据这些信息去创建和运行容器,并向Master报告运行的状态信息) |
2 | kube-proxy | 要了解Kube-proxy就需要先说一下Service,Service在逻辑上是代表了K8S后端的多个Pod,那么外界通过Service访问Pod,Service接受到这个请求信息后是如何转发到这个Pod上的呢?【这个就是Kube-proxy要完成的工作】。 Kube-proxy是配合Service实现从Pod到Service,以及从外部Node到Service访问的一个流程,每个Node上都会运行Kube-proxy服务,它负责将访问Service的TCP、UDP的数据流转发到后端的容器上;如果有多个副本,那么Kube-proxy还可以实现负载均衡。 |
3 | pod网络(flannel ) | Pod和Pod之间(也就是不同Node之间多个Pod)要实现相互通信,那么K8S集群必须要部署Pod网络,也是选用flannel(可以实现不同主机上、不同Pod之间的相互通信) |