Docker介绍
Docker容器技术
7.2.1 Docker简介
Docker最初是DotCloud公司创始人Solomon Hykes在法国期间发起的一个公司内部项目。它是基于DotCloud公司多年云服务技术的一次革新,并于2013年3月以Apache 2.0授权协议开源,主要项目代码在GitHub上进行维护,Docker项目后来还加入了Linux基金会,并成立推动开放容器联盟。
1. Docker引擎架构
Docker引擎是C/S的架构,Docker客户端与Docker Daemon(守护进程)进行交互,Daemon负责构建、运行和发布Docker容器。客户端可以和服务端运行在同一个系统中,也可以连接远程的Daemon。Docker的客户端与Daemon通过RESTful API进行Socket通信。
(1)Namespace(命名空间)
命名空间是Linux内核一个强大的特性。每个容器都有自己独立的命名空间,运行在其中的应用像是在独立的操作系统中运行一样,命名空间保证了容器之间彼此互不影响。Docker实际上是一个进程容器,它通过Namespace实现了进程和进程之间所使用的资源隔离,使不同进程之间彼此不可见。Docker用到的命名空间有:
l PID命名空间:用于隔离进程,容器都有自己独立的进程ID;
l NET命名空间:用于管理网络,容器有自己独立的Network Info;
l IPC命名空间:用于访问IPC(Inter Process Communication)资源;
l MNT命名空间:用于管理挂载点,每个容器都有自己唯一的目录挂载;
l UTS命名空间:用于隔离内核和版本标识(UTC:Unix TimeProcess System),每个容器都有自己独立的Hostname和Domain。
(2)Cgroup(控制组)
Cgroup是Linux内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免当多个容器同时运行时,对系统资源的竞争。控制组技术最早是由Google的程序员2006年起提出,Linux内核自2.6.24开始支持。控制组可以提供对容器的内存、CPU、磁盘IO等资源的限制和审计管理。
(3)UnionFS(联合文件系统)
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础,镜像可以通过分层来进行继承,同时加上自己独有的改动层,大大提高了存储的效率。
2. Docker核心概念
(1)Image(镜像)
镜像是一个只读模板,由Dockerfile文本描述镜像的内容。镜像定义类似面向对象的类,从一个基础镜像(Base Image)开始。构建一个镜像实际就是安装、配置和运行的过程。镜像可以用来创建Docker容器,一个镜像可以创建很多容器。Docker镜像基于UnionFS把以上过程进行分层(Layer)存储,这样更新镜像可以只更新变化的层。Docker的描述文件为Dockerfile,Dockerfile是一个文本文件,基本指令如下:
① FROM:定义基础镜像;
② MAINTAINER:作者或者维护者;
③ RUN:运行的Linux命令;
④ ADD:增加文件或目录;
⑤ ENV:定义环境变量;
⑥ CMD:运行进程。
(2)容器
容器是一个镜像的运行实例,容器由镜像创建,运行用户指定的指令或者Dockerfile定义的运行指令,可以将其启动、停止、删除,而这些容器都是相互隔离(独立进程),互不可见的。比如,运行Ubuntu操作系统镜像,-i前台交互模型,-t分配一个伪终端,运行命令为/bin/bash,代码如下:
[root@docker ~]# docker run -i -t ubuntu /bin/bash
运行过程如下:
① 拉取(Pull)镜像,Docker Engine检查Ubuntu镜像是否本地存在,如果本地已经存在,则使用该镜像创建容器;如果不存在,则Docker Engine则会从镜像仓库拉取镜像至本地;
② 使用该镜像创建新容器;
③ 分配文件系统,挂载一个读写层,在读写层加载镜像;
④ 分配网络/网桥接口,创建一个网络接口,让容器和主机通信;
⑤ 从可用的IP池选择IP地址,分配给容器;
⑥ 执行命令/bin/bash;
⑦ 捕获和提供执行结果。
(3)仓库(Registry)
Docker仓库是Docker镜像库,有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(Tag)。Docker Registry也是一个容器,仓库分为公开仓库(Public)和私有仓库(Private)两种形式。最大的公开仓库是Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括时速云、网易云等,可以提供大陆用户更稳定快速地访问。当然,用户也可以在本地网络内创建一个私有仓库。
当用户创建了自己的镜像之后,就可以使用Push命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上Pull下来就可以了。Docker仓库的概念跟Git类似,注册服务器可以理解为GitHub这样的托管服务。Docker Registry与容器、镜像之间的关系如图7-2-2所示。
Docker仓库
1. Docker仓库简介
镜像构建完成后,可以很容易地在当前宿主机上运行。但是,如果需要在其他服务器上使用这个镜像,就需要一个集中的存储、分发镜像的服务器。Docker Registry(镜像注册)就是这样的服务。一个Docker Registry中可以包含多个仓库(Registry);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。
通常,一个仓库会包含一个软件不同版本的镜像,标签常用于对应该软件的各个版本。开发者可以通过“<仓库名>:<标签>”的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,则以Latest作为默认标签。
仓库名经常以两段式路径形式出现,如james/php_web,前者往往是Docker Registry多用户环境下的用户名,后者则往往是对应的软件名。但这并非是绝对的,取决于所使用的具体Docker Registry的软件或服务。
Docker Registry服务可以分为两种。一种为公开并开放给所有的用户使用,包含用户的搜索、拉取,镜像提交时更新,还可以免费保管用户镜像数据。这类服务受制于网络带宽的限制,并不能及时、快速地获取所需要的资源,但是优点是可以获取大部分并可以立即使用的镜像,减少镜像的制作时间。另外一种服务是在一定范围对特定的用户提供Registry服务,一般存在于学校内部、企业内部的服务管理和研发等环境,这在一定程度上保证了镜像拉取的速度,对内部核心镜像数据有保护作用,但是也存在镜像内容不丰富的问题。
2. 私有仓库
(1)私有仓库特点
仓库(Registry)是集中存放镜像的地方,在上节内容已经说明了Docker仓库分为公有仓库和私有仓库,然而公有仓库在某些情况下并不适用于公司内部传输。通过对比两种仓库的特点,大致可以得出私有仓库有以下优点:
① 节省带宽;
② 传输速度快;
③ 方便存储。
(2)Docker Registry工作方式
Docker Registry是Image的仓库,当开发者编译完成一个Image时,就可以推送到公共的Registry,如Docker Hub,也可以推送到自己的私有Registry。使用Docker Client,开发者可以搜索已经发布的Image,从中拉去Image到本地,并在容器中运行。
Docker Hub提供了公有和私有的Registry。所有人都可以搜索和下载公共镜像,私有仓库只有私有用户才能查询和下载。
容器编排技术
1. 容器编排简介
什么是Docker容器编排?容器编排是指对单独组件和应用层的工作进行组织的流程。应用一般由单独容器化的组件(通常称为微服务)组成,且必须按顺序在网络级别进行组织,以使其能够按照计划运行。这种方法对多个容器进行组织的流程即称为容器编排。在现代开发当中,整体式的应用早已成为过去时,如今的应用由数十乃至数百个松散结合的容器式组件构成,而这些组件需要通过相互间的协同合作,才能使既定的应用按照设计运作。
所有的容器编排引擎均可让用户控制容器启动和停止的时间、将其分组合到群集中,以及协调应用组合的流程。容器编排工具允许用户指导容器部署与自动更新、运行状况监控以及故障转移等步骤。
Docker Swarm是Docker官方提供的一款集群管理工具,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机上的各种Docker资源。Docker Swarm和Kubernetes比较类似,但是更加轻便,具有的功能也较Kubernetes更少一些。Kubernetes和Docker Swarm两者都各有利弊,可根据应用要求进行选择。
2. Docker Swarm
(1)Docker Swarm架构
一个标准的Docker Swarm集群结构,它可能对应了一到多台的实际服务器。每台服务器上都装有Docker并且开启了基于HTTP的Docker API。
Swarm Manager的管理者,用来管理集群中的容器资源。管理者的管理对象不是服务器层面而是集群层面的,也就是说通过Manager,只能笼统地向集群发出指令而不能具体到某台具体的服务器上要干什么(这也是Swarm的根本所在)。至于具体的管理实现方式,Manager向外暴露了一个HTTP接口,外部用户通过这个HTTP接口来实现对集群的管理。对于稍微大一点的集群,最好是使用一台实际的服务器作为专门的管理者,作为学习而言,也可以把管理者和被管理者放在一台服务器上。
Swarm Node节点是运行实际应用服务的容器所在的地方。理论上,一个Manager节点也能同时成为Node节点,但在生产环境中,不建议这样做。Node节点之间,通过Control Plane进行通信,这种通信使用GOSSIP协议,并且是异步的。
(2)Stacks、 Services和 Tasks之间关系
Swarm Service是一个抽象的概念,它只是一个对运行在Swarm集群上的应用服务,是对所期望状态的描述。它就像一个描述了下面物品的清单列表一样:
l 服务名称;
l 使用哪个镜像来创建容器;
l 要运行多少个副本;
l 服务的容器要连接到哪个网络上;
l 应该映射哪些端口。
在Docker Swarm中,Task是一个部署的最小单元,Task与容器是一对一的关系。Stack是描述一系列相关Services的集合。通常通过在一个Yaml文件中来定义一个Stack。
(3)Docker Swarm特点
① Docker Engine集成集群管理
使用Docker Engine CLI创建一个Docker Engine的Swarm模式,在集群中部署应用程序服务。Swarm角色分为Manager和Worker节点,Manager节点故障不影响应用使用。
② 扩容缩容
可以声明每个服务运行的容器数量,通过添加或删除容器数自动调整期望的状态。
③ 状态动态协调及负载均衡
Swarm Manager节点不断监视集群状态,并调整当前状态与期望状态之间的差异。例如,设置一个服务运行10个副本容器,如果两个副本的服务器节点崩溃,Manager将创建两个新的副本替代崩溃的副本,并将新的副本分配到可用的Worker节点,实现服务副本负载均衡,提供入口访问。也可以将服务入口暴露给外部负载均衡器再次负载均衡。
④ 多主机网络及服务发现
可以为服务指定overlay网络。当初始化或更新应用程序时,Swarm Manager会自动为overlay网络上的容器分配IP地址。Swarm Manager节点为集群中的每个服务分配唯一的DNS记录和负载均衡VIP。可以通过Swarm内置的DNS服务器查询集群中每个运行的容器。
⑤ 容器资源隔离
Docker Swarm注意每个容器与其他容器隔离并拥有自己的资源。可以部署各种容器以在不同堆栈中运行单独的应用程序。除此之外,当每个应用程序在自己的容器上运行时,Docker Swarm会重置该应用程序。如果不再需要该应用程序,则可以删除其容器。它不会在用户的主机操作系统上留下任何临时或配置文件。
3. Docker Compose
(1)Docker Compose架构
Docker Compose是 Docker容器进行编排的工具,定义和运行多容器的应用,可以一条命令启动多个容器,使用Docker Compose不再需要使用Shell脚本来启动容器。
Docker Compose通过一个配置文件来管理多个Docker容器,在配置文件中,所有的容器通过Services来定义,然后使用Docker-Compose脚本来启动、停止、重启应用和应用中的服务以及所有依赖服务的容器,非常适合组合使用多个容器进行开发的场景。Docker-Compose默认的模板文件是Docker-Compose.yml,其中定义的每个服务都必须通过 Image指令指定镜像或 Build 指令(需要Dockerfile)来自动构建。其它大部分指令都跟Docker Run中的类似。如果使用Build指令,在Dockerfile中设置的选项(例如CMD、EXPOSE、VOLUME、ENV等)将会自动被获取,无需在 Docker-Compose.yml中再次设置。
Docker-Compose的使用基本上是分为3个步骤:
① 使用Dockerfile定义应用程序的环境,以便在任何地方进行复制。
② 在Docker-Compose.yml中定义组成应用程序的服务,以便它们可以在隔离的环境中一起运行。
③ 运行dcoker-compose up命令,Compose将启动并运行整个应用程序。
Docker-Compose调用过程
① 用户执行的 docker-compose up指令调用了命令行中的启动方法。功能很简单明了,一个docker-compose.yml定义了一个Docker-Compose的project,Docker-Compose操作提供的命令行参数则作为这个project的启动参数,交由project模块去处理。
② 如果当前宿主机已经存在与该应用对应的容器,Docker-Compose将进行行为逻辑判断。如果用户指定可以重新启动已有服务,Docker-Compose就会执行service模块的容器重启方法,否则就将直接启动已有容器。这两种操作的区别在于前者会停止旧的容器,创建启动新的容器,并把旧容器移除掉。在这个过程中创建容器的各项定义参数都是从docker-compose up指令和docker-compose.yml中传入的。
③ 启动容器的方法也很简洁,这个方法中完成了一个Docker容器启动所需的主要参数的封装,并在container模块执行启动。
④ container模块会调用docker-py客户端执行向Docker Daemon发起创建容器的POST请求,再往后就是Docker处理的范畴了。
(2)Docker-Compose.yml文件
Yml是一种简洁的非标记语言。Yaml以数据为中心,使用空白、缩进、分行组织数据,从而使得表示更加简洁易读。Docker-Compose.Yml常用的配置项如下所示:
① build:定义镜像生成,可以指定Dockerfile文件所在的目录路径,支持绝对路径和相对路径;
② image:从指定的镜像中启动容器,可以是存储仓库、标签以及镜像ID,如果镜像不存在,Compose会自动拉取镜像;
③ environment:定义环境变量和配置;
④ ports:定义端口映射,比如将容器上的公开端口80转接到主机上的外部端口9000;
⑤ depends_on:定义依赖关系。此定义会让当前服务处于等待状态,直到这些依赖服务启动。比如某个服务依赖数据库服务,那么通过此配置解决了服务的启动顺序的问题;
⑥volumes:挂载一个目录或者一个已存在的数据卷容器,可以直接使用 HOST:CONTAINER这样的格式,或者使用HOST:CONTAINER:RO这样的格式,后者对于容器来说,数据卷是只读的,这样可以有效保护宿主机的文件系统;
⑦ context:指定Dockerfile的文件路径,也可以是到链接到Git仓库的URL;
⑧ args:指定构建参数,这些参数只能在构建过程中访问;
⑨ target:定义构建指定的阶段Dockerfile,比如,针对不同阶段使用不同的DockerFile,开发阶段使用支持编译调试的Dockerfile;而生产环境,则使用轻量级的Dockerfile;
⑩ command:使用command命令可以覆盖容器启动后默认执行的命令;
11 container_name:指定自定义容器名称,而不是生成的默认名称。
例如,定义如下Docker-Compose.yml文件:
version: '3' # docker当前对应的Compose版本
services: # 容器组
web: # 镜像容器服务标识
build: . # 根据当前目录中Dockerfile文件镜像,“.”当前目录
ports: # 映射容器的端口
- "8888:80"
上述Docker-Compose.yml中使用的Dockerfile文件如下,执行yml文件中build时,首先构件下述镜像文件,基于此镜像启动容器。
FROM centos:7 # 启动镜像centos:6
MAINTAINER CETC55 # 备注维护人员
RUN yum install -y httpd php php-gd php-mysql # 执行如下命令:安装相关软件
RUN echo "<?php phpinfo()?>" > /var/www/html/index.php # 执行如下命令:修改测试页面
CMD ["/usr/sbin/httpd","-D","FOREGROUND"] # 执行命令:启动服务
(3)Docker-Compose常用命令
可以使用docker-compose –help命令进行查询帮助,查看命令的使用方法,下面列举几个常用的命令。
l docker-compose up -d nginx:构建建启动Nignx容器。
l docker-compose exec nginx bash:登录到Nginx容器中。
l docker-compose down:删除所有Nginx容器、镜像。
l docker-compose ps:显示所有容器。
l docker-compose restart nginx:重新启动Nginx容器。
l docker-compose rm nginx:删除容器(删除前必须关闭容器)。
l docker-compose stop nginx:停止Nignx容器。
l docker-compose start nginx:启动Nignx容器。
浙公网安备 33010602011771号