概念
docker是什么
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。Docker容器目前强依赖unix系统内核,它借助unix系统内核的cgroup、namespace隔离机制,使相互之间的容器不会有任何影响。
docker架构
Docker使用客户端 - 服务器架构。Docker 客户端与Docker 守护进程通信,后者负责构建,运行和分发Docker容器。Docker客户端和守护程序可以 在同一系统上运行,也可以将Docker客户端连接到远程Docker守护程序。Docker客户端和守护程序使用REST API,通过UNIX套接字或网络接口进行通信。
docker守护进程
Docker守护程序(dockerd)监听Docker API请求并管理Docker对象,如镜像,容器,网络和卷。守护程序还可以与其他守护程序通信以管理Docker服务。
docker客户端
Docker client(docker)是许多Docker用户与Docker交互的主要方式。当您使用诸如此类的命令时docker run,客户端会将这些命令发送给它们dockerd,然后执行这些命令。该docker命令使用Docker API。Docker客户端可以与多个守护进程通信。
docker注册表(私服)
Docker 注册表存储Docker镜像。Docker Hub是任何人都可以使用的公共注册中心,Docker配置为默认在Docker Hub上查找镜像。您甚至可以运行自己的私人注册表。
使用docker pull或docker run命令时,将从配置的注册表中提取所需的镜像。使用该docker push命令时,镜像将被推送到配置的注册表。
docker对象
使用Docker时,您正在创建和使用镜像,容器,网络,卷,插件和其他对象。本节简要介绍其中一些对象。
镜像(IMAGES)
镜像是只读的,用于创建一个容器的指令模板。通常,镜像基于另一个镜像,并带有一些额外的自定义。例如,您可以构建基于镜像的ubuntu 镜像,在ubuntu进行基础上安装Apache Web服务器和应用程序,以及运行应用程序所需的配置详细信息。
您可以创建自己的镜像,也可以只使用其他人创建的镜像并在注册表中发布。要构建自己的镜像,可以 使用简单的语法创建Dockerfile文件,以定义创建镜像和运行镜像所需的步骤。Dockerfile中的每条指令都在镜像中创建一个图层。更改Dockerfile并重建镜像时,仅重建已更改的那些层。与其他虚拟化技术相比,这是使镜像如此轻量,小巧和快速的部分原因。
容器(CONTAINERS)
容器是镜像的可运行实例。您可以使用Docker API或CLI创建,启动,停止,移动或删除容器。您可以将容器连接到一个或多个网络,将存储连接到它,甚至可以根据其当前状态创建新镜像。
默认情况下,容器与其他容器及其主机相对隔离。您可以控制容器的网络,存储或其他基础子系统与其他容器或主机的隔离程度。
容器由其镜像以及您在创建或启动时为其提供的任何配置选项定义。删除容器后,对其状态的任何未存储在持久存储中的更改都将消失。
docker容器的特点:
1、灵活:即使是最复杂的应用也可以集装箱化。
2、轻量级:容器利用并共享主机内核。
3、可互换:您可以即时部署更新和升级。
4、便携式:您可以在本地构建,部署到云,并在任何地方运行。
5、可扩展:您可以增加并自动分发容器副本。
6、可堆叠:您可以垂直和即时堆叠服务。
通过运行镜像启动容器。一个镜像是一个可执行的包,其中包括运行应用程序所需的所有内容-的代码,运行时,库,环境变量,和配置文件。一个容器中运行原生 Linux和共享主机与其它容器的内核。它运行一个独立的进程,不占用任何其他可执行文件的内存,使其轻量级。
相比之下,虚拟机(VM)运行一个完整的“客户”操作系统,通过虚拟机管理程序对主机资源进行虚拟访问。通常,VM提供的环境比大多数应用程序需要的资源更多。
以下命令运行ubuntu容器,以交互方式附加到本地命令行会话,然后运行/bin/bash。
docker run -i -t ubuntu /bin/bash
运行此命令时,会发生以下情况(假设您使用的是默认注册表配置):
a、如果您没有ubuntu本地镜像,Docker会从您配置的注册表中提取镜像,就好像您手动执行docker pull ubuntu运行一样。
b、Docker创建一个新容器,就像您手动执行docker container create 运行命令一样。
c、Docker将读写文件系统分配给容器,作为其最后一层。这允许正在运行的容器在其本地文件系统中创建或修改文件和目录。
d、Docker创建了一个网络接口,用于将容器连接到默认网络,因为您没有指定任何网络选项。这包括为容器分配IP地址。默认情况下,容器可以使用主机的网络连接连接到外部网络。
e、Docker启动容器并执行/bin/bash。由于容器以交互方式运行并连接到终端(由于-i和-t 标志),因此您可以使用键盘提供输入,同时将输出记录到终端。
f、键入exit以终止/bin/bash命令时,容器会停止但不会被删除。您可以重新启动它或将其删除。
服务(SERVICE)
Docker Engine支持Docker 1.12及更高版本中的swarm模式。
服务允许您跨多个Docker守护程序扩展容器,这些守护程序一起作为具有多个管理器和工作程序的群组一起工作。swarm的每个成员都是Docker守护程序,守护进程都使用Docker API进行通信。服务允许您定义所需的状态,例如在任何给定时间必须可用的服务的副本数。默认情况下,服务在所有工作节点之间进行负载平衡。对于消费者来说,Docker服务似乎是一个单独的应用程序。
基础技术
Docker核心解决的问题是利用LXC来实现类似VM的功能,从而利用更加节省的硬件资源提供给用户更多的计算资源。同VM的方式不同, LXC 其并不是一套硬件虚拟化方法 - 无法归属到全虚拟化、部分虚拟化和半虚拟化中的任意一个,而是一个操作系统级虚拟化方法, 理解起来可能并不像VM那样直观。
虚拟化尤其是硬件虚拟化需要其解决的主要是以下4个问题:
隔离性 - 每个用户实例之间相互隔离, 互不影响。 硬件虚拟化方法给出的方法是VM, LXC给出的方法是container,更细一点是kernel namespace
可配额/可度量 - 每个用户实例可以按需提供其计算资源,所使用的资源可以被计量。硬件虚拟化方法因为虚拟了CPU, memory可以方便实现, LXC则主要是利用cgroups来控制资源
移动性 - 用户的实例可以很方便地复制、移动和重建。硬件虚拟化方法提供snapshot和image来实现,docker(主要)利用AUFS实现
安全性 - 这个话题比较大,这里强调是host主机的角度尽量保护container。硬件虚拟化的方法因为虚拟化的水平比较高,用户进程都是在KVM等虚拟机容器中翻译运行的, 然而对于LXC, 用户的进程是lxc-start进程的子进程, 只是在Kernel的namespace中隔离的, 因此需要一些kernel的patch来保证用户的运行环境不会受到来自host主机的恶意入侵, dotcloud(主要是)利用kernel grsec patch解决的.
下面我们详细介绍Docker中每个容器都使用哪些技术手段类实现隔离的。
命名空间(Namespaces)
Docker使用一种被称为namespaces提供隔离工作空间的技术来称为容器。运行容器时,Docker会为该容器创建一组 名称空间。这些命名空间提供了一层隔离。容器的每个方面都在一个单独的命名空间中运行,其访问权限仅限于该命名空间。
Docker Engine在Linux上使用以下命名空间:
pid命名空间:
1、空间内的PID 是独立分配的,每个namespace中的pid是有自己的pid=1的进程
2、每个namespace中的进程只能影响自己的同一个namespace或子namespace中的进程
3、/proc目录只能看到自己namespace中的进程
net命名空间:
1、有了 pid namespace, 每个namespace中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过netnamespace实现的
2、每个net namespace有独立的 network devices, IP addresses, IP routing tables, /proc/net 目录。这样每个container的网络就能隔离开来
3、LXC在此基础上有5种网络类型,docker默认采用veth的方式将container中的虚拟网卡同host上的一个docker bridge连接在一起
ipc命名空间:
只有在同一个Namespace下的进程才能相互通信
mnt命名空间:
允许不同namespace的进程看到的文件结构不同
uts命名空间:
UTS(“UNIX Time-sharing System”) namespace允许每个container拥有独立的hostname和domain name, 使其在网络上可以被视作一个独立的节点而非Host上的一个进程
user namespace
每个container可以有不同的 user 和 group id, 也就是说每个容器进程指定相同的用户,指定的用户之间互不相干,如mysql进行指定用户为mysql,用户组为mysql,这个用户和用户组只在当前容器中有效,在其它容器看不到该用户和用户组。
控制组(Cgroups)
cgroups 实现了对资源的配额和度量。 cgroups 的使用非常简单,提供类似文件的接口,在 /cgroup目录下新建一个文件夹即可新建一个group,在此文件夹中新建task文件,并将pid写入该文件,即可实现对该进程的资源控制。具体的资源配置选项可以在该文件夹中新建子 subsystem ,{子系统前缀}.{资源项} 是典型的配置方法,
如memory.usage_in_bytes 就定义了该group 在subsystem memory中的一个内存限制选项。
另外,cgroups中的 subsystem可以随意组合,一个subsystem可以在不同的group中,也可以一个group包含多个subsystem - 也就是说一个 subsystem。
文件系统(Union file systems)
Union file systems通过创建层来操作的文件系统,使它们非常轻量和快速。Docker Engine使用UnionFS为容器提供构建块。Docker Engine可以使用多种UnionFS变体,包括AUFS,btrfs,vfs和DeviceMapper。
容器格式(Container format)
Docker Engine将命名空间,控制组和UnionFS组合成一个称为容器格式的包装器。默认容器格式是libcontainer。将来,Docker可以通过与BSD Jails或Solaris Zones等技术集成来支持其他容器格式。
docker版本
Docker有两个版本:
社区版(CE)
Docker Community Edition(CE)非常适合希望开始使用Docker并尝试使用基于容器的应用程序的个人开发人员和小型团队。该版本目前免费
企业版(EE)
Docker企业版(EE)专为企业开发和IT团队而设计,他们在生产中大规模构建,发布和运行业务关键型应用程序。该版本目前收费
该文档教程主要针对docker CE社区版进行讲解。