【自学Docker】Docker入门

Docker入门

Docker简介

Docker 是 Docker.Lnc 公司开源的一个基于 LXC 技术之上搭建的 Container 容器引擎,Docker 源代码托管在 Github上,Docker 是基于 Go 语言开发的并遵从 Apache2.0 协议开源。

Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。

Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版),学习仅使用社区版就可以了。

Docker Logo

【自学Docker】Docker入门_第1张图片

Docker 的思想源于集装箱,集装箱解决了什么问题呢?在早期运输货物需要不同分类的船,例如运输水果的船,运输生活用品的船,有了集装箱后,在大船上,可以把货物分类到不同的集装箱中,水果一个集装箱,生活用品一个集装箱,它们之间互不影响,只要把货物封装好集装箱里,就可以把不同类的货物一起运走。

通过 Docker logo 也可以看出所以然来,这是一只鲸鱼,它托着许多集装箱。我们可以把宿主机可当做这只鲸鱼,把相互隔离的容器可看成集装箱,每个集装箱中都包含自己的应用程序。

Docker概念

Docker 是开发人员和系统管理员使用容器开发、部署和运行应用程序的平台。使用 Linux 容器来部署应用程序称为集装箱化。

集装箱化的优点:

特点 描述
灵活 即使是复杂的应用程序也可封装。
轻量级 容器利用并共享主机内核。
便携式 您可以在本地构建,部署到云上并在任何地方运行。
可扩展性 您可以增加和自动分发容器副本。
可堆叠 您可以垂直堆叠服务并及时并及时堆叠服务。

Docker特点

  • Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。

  • 总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。

  • Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

  • Docker容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。

Docker的优点

轻量级

  • 所有容器在一台机器上共享同一个操作系统内核,这样他们立即开始,并更有效地利用内存。Image 是从分层文件系统的构建,这样他们能够共享公共文件,使得磁盘使用率和 Image 的下载更加高效。

开放

  • Docker 容器是基于开发的标准,允许容器运行在主流的 Linux 发布版和 Microsoft 操作系统作为所有的基础设施。

安全

  • 容器使得应用程序彼此隔离,而基础架构同时为应用程序提供了额外的保护层。

Docker目标

Docker 是一个轻量级的操作系统虚拟化解决方案。

Docker的主要目标,用官网的概括来说就是 “Build,Ship and Run Any App,Anywhere”:编译,装载任何App,在任何地方都可以运行,我们大概理解就是一个容器,实现了对应用的封装,部署,运行等生命周期管理,只要在glibc的环境下,到处都可以运行。这点在企业的云服务部署是有非常广泛的应用前景。


Docker与虚拟机

Docker概述

Docker 是基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。

由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 LXC,从 0.7 版本以后开始去除 LXC,转而使用自行开发的 libcontainer,从 1.11 开始,则进一步演进为使用 runC 和 containerd。

Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。

虚拟机

传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程。

而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

架构

虚拟机架构

【自学Docker】Docker入门_第2张图片

每个虚拟机都包括应用程序、必要的二进制文件和库以及一个完整的客户操作系统(Guest OS),尽管它们被分离,它们共享并利用主机的硬件资源,将近需要十几个 GB 的大小。

容器架构

【自学Docker】Docker入门_第3张图片

容器包括应用程序及其所有的依赖,但与其他容器共享内核。它们以独立的用户空间进程形式运行在主机操作系统上。他们也不依赖于任何特定的基础设施,Docker容器 可以运行在任何计算机上,任何基础设施和任何云上。

Docker 的容器利用了 LXC,管理利用了 namespaces 来做权限的控制和隔离,cgroups 来进行资源的配置,并且还通过 aufs 来进一步提高文件系统的资源利用率,而这些技术都不是 Docker 独创。

Docker与虚拟机对比

作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。

更高效的利用系统资源

由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。

无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。

更快速的启动时间

传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。

一致的运行环境

开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker镜像 提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。

持续交付和部署

对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。

使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合持续部署(Continuous Delivery/Deployment) 系统进行自动部署。

而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。

更轻松的迁移

由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。

更轻松的维护和扩展

Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。

Docker与虚拟机对比总结

特性 Docker 虚拟机
启动 秒级 分钟级
硬盘使用 一般为 MB 一般为 GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般几十个

Docker应用场景

Docker 是一个开源的容器引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者和系统管理员在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括 VMs(虚拟机)、bare metal、OpenStack 集群、云端、数据中心和其他的基础应用平台。

容器是完全使用沙箱机制,相互之间不会有任何接口。

Docker 这些特性的确解决了企业IT基础架构很多问题,合理的利用这些特点将更健壮和强大您的IT基础架构。也是为什么越来越多的企业拥抱它的原因!

Docker应用案例

1. 简化配置

这是 Docker 公司宣传的 Docker 的主要使用场景。虚拟机的最大好处是能在你的硬件设施上运行各种配置不一样的平台(软件、系统),Docker 在降低额外开销的情况下提供了同样的功能。

它能让你将运行环境和配置放在代码中然后部署,同一个 Docker 的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。

2. 搭建环境

如果你希望构建源码,但发现没有准备好合适的环境。那么使用 Docker 是一个值得考虑的方案。毕竟如果使用传统的方法一个一个地安装软件,一大堆软件安装下来确实十分费时间,使用容器技术省时省力,何乐而不为?

它能让你将运行环境和配置放在代码中然后部署,同一个 Docker 的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。

3. 微服务

微服务是近几年来IT圈内谈论比较多的一个名词,意义也很简单:尽可能细粒度拆分业务程序架构,由多个独立服务组成业务系统。

Docker 的容器设计原则:一个容器一个服务,容器之间相互隔离,不妨试想一下,如果容器作为这些独立服务的部署单元,是不是有点恰到好处呢?

4. 弹性伸缩

Docker 通过创建另一个容器来帮助你轻松地进行水平扩展。如果遇到巨大的高峰流量,Docker 可以帮助你解决问题 —— 只需添加更多的机器并增加负载均衡器背后运行的容器数量。

5. 持续部署

都说 Docker 天生适合持续集成/持续部署,在部署中使用 Docker,持续部署将变得非常简单,并会在进入新的镜像后重新开始。

关于这个部分的自动化工作,现在已经有许多方案以供选择,Kubernetes 就是一个耳熟能详的名字。Kubernetes 是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。

6. 多租户环境

Docker 有意思的一个使用场景是在多租户的应用中,它可以避免关键应用的重写。如果你将应用程序服务公开给多个租户(租户指一组用户,例如组织),使用单租户方案设计的应用程序如果用上了 sub-domain + docker 可以快速获得提供多租户的服务。

关于这个场景的一个例子是为物联网的应用开发一个快速、易用的多租户环境。这种多租户的基本代码非常复杂,很难处理,重新规划这样一个应用不但消耗时间,也浪费金钱。使用 Docker,可以为每一个租户的应用层的多个实例创建隔离的环境,这不仅简单而且成本低廉,当然这一切得益于 Docker 环境的启动速度和其高效的 diff 命令。


Docker 镜像 容器 仓库

Docker 有三个基本概念,Docker镜像(Images)Docker容器(Container)Docker仓库(Registry)

Docker镜像(Images)

Docker镜像(Images) 是一个用于创建 Docker容器(Container) 的静态模板。一个 Docker镜像(Images) 可以创建很多 Docker容器(Container)。

比如,一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 apache 或用户需要的其他应用程序。

Docker 提供了一个很简单的机制来创建 Docker镜像(Images) 或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。

Docker容器(Container)

Docker容器(Container) 是独立运行的一个或一组应用,是从 Docker镜像(Images) 创建的运行实例,它可以被启动、开始、停止、 删除。

每个Docker容器(Container) 都是相互隔离的、保证安全的平台。我们可以把 Docker容器(Container) 看做是一个简易版的 Linux 环境(包括 root 用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

如果使用面向对象的思想来比喻 Docker镜像(Images) 和 Docker容器(Container) ,那么 Docker镜像(Images) 就相当于面向对象中的类,而 Docker容器(Container) 相当于类实例化出来的对象。

注:Docker镜像(Images) 是只读的,Docker容器(Container) 在启动的时候创建一层可写层作为最上层。

Docker仓库(Registry)

Docker仓库(Registry) 用来保存 Docker镜像(Images),是集中存放 Docker镜像(Images) 文件的场所。

Docker仓库(Registry) 分为公开仓库(Public)和私有仓库(Private)两种形式。最大的公开仓库是 Docker Hub, 存放了数量庞大的镜像供用户下载。国内的公开仓库包括 Docker Pool 等,可以提供大陆用户更稳定快速的访问。

当然,用户也可以在本地网络内创建一个私有仓库。当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。

注:Docker 仓库(Registry) 的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。


Docker架构

Docker 对使用者来讲是一个 C/S 模式的架构,而 Docker 的后端是一个非常松耦合的架构,模块各司其职,并有机组合,支撑 Docker 的运行。

Docker架构图

【自学Docker】Docker入门_第4张图片

Docker架构分解

【自学Docker】Docker入门_第5张图片

从上图可以看出,用户是使用 Docker Client 与 Docker Daemon 建立通信,并发送请求给后者。

而 Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Server 的功能使其可以接受 Docker Client 的请求;而后 Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。

Job 的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,并通过镜像管理驱动 graphdriver 将下载镜像以 Graph 的形式存储;当需要为 Docker 创建网络环境时,通过网络管理驱动 networkdriver 创建并配置 Docker 容器网络环境;当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 execdriver 来完成。

而 libcontainer 是一项独立的容器管理包,networkdriver 以及 execdriver 都是通过 libcontainer 来实现具体对容器进行的操作。当执行完运行容器的命令后,一个实际的 Docker 容器就处于运行状态,该容器拥有独立的文件系统,独立并且安全的运行环境等。

Docker架构模块

1. Docker Client

Docker Client 是 Docker 架构中用户用来和 Docker Daemon 建立通信的客户端。用户使用的可执行文件为 docker,通过 docker 命令行工具可以发起众多管理 container 的请求。

Docker Client 可以通过以下三种方式和 Docker Daemon 建立通信:

  • tcp://host:port
  • unix://path_to_socket
  • fd://socketfd

Docker Client 发送容器管理请求后,由 Docker Daemon 接受并处理请求,当Docker Client 接收到返回的请求相应并简单处理后,Docker Client 一次完整的生命周期就结束了。当需要继续发送容器管理请求时,用户必须再次通过docker 可执行文件创建 Docker Client。

2. Docker Daemon

Docker Daemon 是 Docker 架构中一个常驻在后台的系统进程,功能是:接受并处理 Docker Client 发送的请求。该守护进程在后台启动了一个 Server,Server 负责接受 Docker Client 发送的请求;接受请求后,Server 通过路由与分发调度,找到相应的 Handler 来执行请求。

Docker Daemon 启动所使用的可执行文件也为 docker,与 Docker Client 启动所使用的可执行文件 docker 相同。在 docker 命令执行时,通过传入的参数来判别 Docker Daemon 与 Docker Client。

Docker Daemon 的架构,大致可以分为以下三部分:Docker Server、Engine和 Job。Docker Daemon 架构如下图。

【自学Docker】Docker入门_第6张图片

3. Docker Server

Docker Server 在 Docker 架构中是专门服务于 Docker Client 的 server。该server 的功能是:接受并调度分发 Docker Client 发送的请求。

在 Docker 的启动过程中,通过包 gorilla/mux,创建了一个 mux.Router,提供请求的路由功能。在 Golang 中,gorilla/mux 是一个强大的 URL 路由器以及调度分发器。该 mux.Router 中添加了众多的路由项,每一个路由项由 HTTP 请求方法(PUT、POST、GET或DELETE)、URL、Handler 三部分组成。

若 Docker Client 通过 HTTP 的形式访问 Docker Daemon,创建完 mux.Router 之后,Docker 将 Server 的监听地址以及 mux.Router 作为参数,创建一个 httpSrv=http.Server{},最终执行 httpSrv.Serve() 为请求服务。

在 Server 的服务过程中,Server 在 listener 上接受 Docker Client 的访问请求,并创建一个全新的 goroutine 来服务该请求。在 goroutine 中,首先读取请求内容,然后做解析工作,接着找到相应的路由项,随后调用相应的 Handler 来处理该请求,最后 Handler 处理完请求之后回复该请求。

需要注意的是:Docker Server 的运行在 Docker 的启动过程中,是靠一个名为 serveapi 的 job 的运行来完成的。原则上,Docker Server 的运行是众多 job 中的一个,但是为了强调 Docker Server 的重要性以及为后续 job 服务的重要特性,将该 serveapi 的 job 单独抽离出来分析,理解为 Docker Server。

4. Engine

Engine 是 Docker 架构中的运行引擎,同时也是 Docker 运行的核心模块。它扮演 Docker container 存储仓库的角色,并且通过执行 job 的方式来操纵管理这些容器。

在 Engine 数据结构的设计与实现过程中,有一个 handler 对象。该 handler 对象存储的都是关于众多特定 job 的 handler 处理访问。

5. Job

一个 Job 可以认为是 Docker 架构中 Engine 内部最基本的工作执行单元。 Docker 可以做的每一项工作,都可以抽象为一个 job 。例如:在容器内部运行一个进程,这是一个 job;创建一个新的容器,这是一个job,从 Internet 上下载一个文档,这是一个 job;包括之前在 Docker Server 部分说过的,创建 Server 服务于 HTTP 的 API,这也是一个 job,等等。

Job 的设计者,把 Job 设计得与 Unix 进程相仿。比如说:Job 有一个名称,有参数,有环境变量,有标准的输入输出,有错误处理,有返回状态等。

6. Docker Registry

Docker Registry 是一个存储容器镜像的仓库。而容器镜像是在容器被创建时,被加载用来初始化容器的文件架构与目录。

在 Docker 的运行过程中,Docker Daemon 会与 Docker Registry 通信,并实现搜索镜像、下载镜像、上传镜像三个功能,这三个功能对应的 job 名称分别为 ”search”,”pull” 与 “push”。

其中,在 Docker 架构中,Docker 可以使用公有的 Docker Registry,即大家熟知的 Docker Hub,如此一来,Docker 获取容器镜像文件时,必须通过互联网访问 Docker Hub;同时 Docker 也允许用户构建本地私有的 Docker Registry,这样可以保证容器镜像的获取在内网完成。

7. Graph

Graph 在 Docker 架构中扮演已下载容器镜像的保管者,以及已下载容器镜像之间关系的记录者。一方面,Graph 存储着本地具有版本信息的文件系统镜像,另一方面也通过 GraphDB 记录着所有文件系统镜像彼此之间的关系。Graph 的架构如下图。

【自学Docker】Docker入门_第7张图片

其中,GraphDB 是一个构建在 SQLite 之上的小型图数据库,实现了节点的命名以及节点之间关联关系的记录。它仅仅实现了大多数图数据库所拥有的一个小的子集,但是提供了简单的接口表示节点之间的关系。

同时在 Graph 的本地目录中,关于每一个的容器镜像,具体存储的信息有:该容器镜像的元数据,容器镜像的大小信息,以及该容器镜像所代表的具体 rootfs。

8. Driver

Driver 是 Docker 架构中的驱动模块。通过 Driver 驱动,Docker 可以实现对 Docker 容器执行环境的定制。由于 Docker 运行的生命周期中,并非用户所有的操作都是针对 Docker 容器的管理,另外还有关于 Docker 运行信息的获取,Graph 的存储与记录等。因此,为了将 Docker 容器的管理从 Docker Daemon 内部业务逻辑中区分开来,设计了 Driver 层驱动来接管所有这部分请求。

在 Docker Driver 的实现中,可以分为以下三类驱动:graphdriver、networkdriver 和 execdriver。

graphdriver 主要用于完成容器镜像的管理,包括存储与获取。即当用户需要下载指定的容器镜像时,graphdriver 将容器镜像存储在本地的指定目录;同时当用户需要使用指定的容器镜像来创建容器的 rootfs 时,graphdriver 从本地镜像存储目录中获取指定的容器镜像。

在 graphdriver 的初始化过程之前,有 4 种文件系统或类文件系统在其内部注册,它们分别是 aufs、btrfs、vfs 和 devmapper。而 Docker 在初始化之时,通过获取系统环境变量 ”DOCKER_DRIVER” 来提取所使用 driver 的指定类型。而之后所有的 graph 操作,都使用该 driver 来执行。

graphdriver 的架构如图:

【自学Docker】Docker入门_第8张图片

networkdriver 的用途是完成 Docker 容器网络环境的配置,其中包括 Docker 启动时为 Docker 环境创建网桥;Docker 容器创建时为其创建专属虚拟网卡设备;以及为 Docker 容器分配 IP、端口并与宿主机做端口映射,设置容器防火墙策略等。networkdriver 的架构如下图。

【自学Docker】Docker入门_第9张图片

execdriver 作为 Docker 容器的执行驱动,负责创建容器运行命名空间,负责容器资源使用的统计与限制,负责容器内部进程的真正运行等。在 execdriver 的实现过程中,原先可以使用 LXC 驱动调用 LXC 的接口,来操纵容器的配置以及生命周期,而现在 execdriver 默认使用 native 驱动,不依赖于 LXC。具体体现在 Daemon 启动过程中加载的 ExecDriverflag 参数,该参数在配置文件已经被设为 ”native”。这可以认为是 Docker 在 1.2 版本上一个很大的改变,或者说 Docker 实现跨平台的一个先兆。 execdriver 架构如下图:

【自学Docker】Docker入门_第10张图片

9. libcontainer

libcontainer 是 Docker 架构中一个使用 Go 语言设计实现的库,设计初衷是希望该库可以不依靠任何依赖,直接访问内核中与容器相关的 API。

正是由于 libcontainer 的存在,Docker 可以直接调用 libcontainer,而最终操纵容器的 namespace、cgroups、apparmor、网络设备以及防火墙规则等。这一系列操作的完成都不需要依赖 LXC 或者其他包。libcontainer 架构如下图:

【自学Docker】Docker入门_第11张图片

另外,libcontainer 提供了一整套标准的接口来满足上层对容器管理的需求。或者说,libcontainer 屏蔽了 Docker 上层对容器的直接管理。又由于 libcontainer 使用 Go 这种跨平台的语言开发实现,且本身又可以被上层多种不同的编程语言访问,因此很难说,未来的 Docker 就一定会紧紧地和 Linux 捆绑在一起。而于此同时,Microsoft 在其著名云计算平台 Azure 中,也添加了对 Docker 的支持,可见 Docker 的开放程度与业界的火热度。

10. Docker container

Docker container(Docker容器)是 Docker 架构中服务交付的最终体现形式。

Docker 按照用户的需求与指令,订制相应的 Docker容器。

用户通过指定容器镜像,使得 Docker 容器可以自定义 rootfs 等文件系统; 用户通过指定计算资源的配额,使得 Docker 容器使用指定的计算资源; 用户通过配置网络及其安全策略,使得 Docker 容器拥有独立且安全的网络环境; 用户通过指定运行的命令,使得 Docker 容器执行指定的工作。

【自学Docker】Docker入门_第12张图片

你可能感兴趣的:(Docker教程,docker,运维,容器)