共计 16358 个字符,预计需要花费 41 分钟才能阅读完成。
Docker 是一个相对较新且发展非常快速的项目,可用来创建非常轻量的“虚拟机”。注意这里的引号非常重要,Docker 创建的并非真正的虚拟机,而更像是打了激素的 chroot,嗯,是大量的激素。
在我们继续之前,我先说下,截至目前(2015 年 1 月 4 日)为止,Docker 只能在 Linux 上工作,暂不支持 Windows 或 OSX(译者注:不直接支持)。我稍后会讲到 Docker 的架构,你会明白其中的原因。所以,如果想在非 Linux 平台上使用 Docker,你需要在虚拟机里运行 Linux。
本教程有三个目标:说明 Docker 解决的问题、说明它如何解决这个问题、以及说明它使用了哪些技术来解决这个问题。这不是一篇教你怎么运行安装 Docker 的教程,Docker 此类教程已经有很多,包括 Docker 作者的在线互动教程。本文最后有一个步骤说明,目的是用一个明确的现实世界的例子来串联文章中所有的理论,但不会太过详细。
CentOS 6/ 7 系列安装 Docker http://www.linuxidc.com/Linux/2014-07/104768.htm
Docker 的搭建 Gitlab CI 全过程详解 http://www.linuxidc.com/Linux/2013-12/93537.htm
Docker 安装应用 (CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm
在 Docker 中使用 MySQL http://www.linuxidc.com/Linux/2014-01/95354.htm
在 Ubuntu Trusty 14.04 (LTS) (64-bit) 安装 Docker http://www.linuxidc.com/Linux/2014-10/108184.htm
Docker 安装应用 (CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm
Ubuntu 14.04 安装 Docker http://www.linuxidc.com/linux/2014-08/105656.htm
阿里云 CentOS 6.5 模板上安装 Docker http://www.linuxidc.com/Linux/2014-11/109107.htm
Docker 能做什么?
Docker 可以解决虚拟机能够解决的问题,同时也能够解决虚拟机由于资源要求过高而无法解决的问题。Docker 能处理的事情包括:
- 隔离应用依赖
- 创建应用镜像并进行复制
- 创建容易分发的即启即用的应用
- 允许实例简单、快速地扩展
- 测试应用并随后销毁它们
Docker 背后的想法是创建软件程序可移植的轻量级容器,让其可以在任何安装了 Docker 的机器上运行,而不用关心底层操作系统,类似船舶使用的集装箱,野心勃勃的他们成功了!
Docker 究竟做了什么?
这一节我不会说明 Docker 使用了哪些技术来完成它的工作,或有什么具体的命令可用,这些放在了最后一节,这里我将说明的是 Docker 提供的资源和抽象。
Docker 两个最重要的概念是镜像和容器。除此之外,链接和数据卷也很重要。我们先从镜像入手。
镜像
Docker 的镜像类似虚拟机的快照,但更轻量,非常非常轻量(下节细说)。
创建 Docker 镜像有几种方式,多数是在一个现有镜像基础上创建新镜像,因为几乎你需要的任何东西都有了公共镜像,包括所有主流 Linux 发行版,你应该不会找不到你需要的镜像。不过,就算你想从头构建一个镜像,也有好几种方法。
要创建一个镜像,你可以拿一个已有的镜像,对它进行修改来创建它的子镜像。实现的方式有两种:在一个文件中指定一个基础镜像及需要完成的修改;或通过“运行”一个镜像,对其进行修改并提交。不同方式各有优点,不过一般会使用第一种的文件方式来指定所做的变化。
镜像拥有唯一 ID,以及一个供人阅读的名字和标签对。镜像可以命名为类似 ubuntu:latest、ubuntu:precise、django:1.6、django:1.7 等等。
容器
现在说容器了。你可以从镜像中创建容器,这等同于从快照中创建虚拟机,不过更轻量。应用是由容器运行的。
举个例子,你可以下载一个 Ubuntu 的镜像(有个叫 docker registry 的镜像公共仓库),做一些修改:安装 Gunicorn 和你的 Django 应用及其依赖;然后从该镜像中创建一个容器,在它启动后运行你的应用。
容器与虚拟机一样,是隔离的(有一点要注意,我稍后会讨论到)。它们也拥有一个唯一 ID 和唯一的供人阅读的名字。容器有必要对外暴露服务,因此 Docker 允许暴露容器的特定端口。
容器与虚拟机相比有两个主要差异。第一个是:它们被设计成运行单进程,无法很好地模拟一个完整的环境(如果那是你需要的,请看看 LXC)。你可能会尝试运行 runit 或 supervisord 实例来启动多个进程,但(以我的愚见)这真的没有必要。
单进程与多进程之争非常精彩。你应该知道的是,Docker 设计者极力推崇“一个容器一个进程的方式”,如果你要选择在一个容器中运行多个进程,那唯一情况是:出于调试目的,运行类似 ssh 的东西来访问运行中的容器,不过 docker exec 命令解决了这个问题。
容器和虚拟机的第二个巨大差异是:当你停止一个虚拟机时,可能除了一些临时文件,没有文件会被删除;当你停止一个 Docker 容器,对初始状态(创建容器所用的镜像的状态)做的所有变化都会丢失。这是使用 Docker 时必须做出的最大思维变化之一: 容器是短暂和一次性的 。
数据卷
如果你的电子商务网站刚收到客户支付的 3 万元,内核崩溃了,所有数据库变化都丢失了……对你或 Docker 来说都不是一件好事,不过不要担心。Docker 允许你定义数据卷——用于保存持久数据的空间。Docker 强制你定义应用部分和数据部分,并要求你将它们分开。
卷是针对容器的,你可以使用同一个镜像创建多个容器并定义不同的卷。卷保存在运行 Docker 的宿主文件系统上,你可以指定卷存放的目录,或让 Docker 保存在默认位置。保存在其他类型文件系统上的都不是一个卷,稍后再具体说。
链接
链接是 Docker 的另一个重要部分。
容器启动时,将被分配一个随机的私有 IP,其它容器可以使用这个 IP 地址与其进行通讯。这点非常重要,原因有二:一是它提供了容器间相互通信的渠道,二是容器们将共享一个本地网络。我曾经碰到一个问题,在同一台机器上为两个客户启动两个 elasticsearch 容器,但保留集群名称为默认设置,结果这两台 elasticsearch 服务器立马变成了一个自主集群。
要开启容器间通讯,Docker 允许你在创建一个新容器时引用其它现存容器,在你刚创建的容器里被引用的容器将获得一个(你指定的)别名。我们就说,这两个容器链接在了一起。
因此,如果 DB 容器已经在运行,我可以创建 web 服务器容器,并在创建时引用这个 DB 容器,给它一个别名,比如 dbapp。在这个新建的 web 服务器容器里,我可以在任何时候使用主机名 dbapp 与 DB 容器进行通讯。
Docker 更进一步,要求你声明容器在被链接时要开放哪些端口给其他容器,否则将没有端口可用。
Docker 镜像的可移植性
在创建镜像时有一点要注意。Docker 允许你在一个镜像中指定卷和端口。从这个镜像创建的容器继承了这些设置。但是,Docker 不允许你在镜像上指定任何不可移植的内容。
例如,你可以在镜像里定义卷,只要它们被保存在 Docker 使用的默认位置。这是因为如果你在宿主文件系统里指定了一个特定目录来保存卷,其他使用这个镜像的宿主无法保证这个目录是存在的。
你可以定义要暴露的端口,但仅限那些在创建链接时暴露给其他容器的端口,你不能指定暴露给宿主的端口,因为你无从知晓使用那个镜像的宿主有哪些端口可用。
你也不能在镜像上定义链接。使用链接要求通过名字引用其他容器,但你无法预知每个使用那个镜像的宿主如何命名容器。
镜像必须完全可移植,Docker 不允许例外。
以上就是主要的部分,创建镜像、用它们创建容器,在需要时暴露端口和创造卷、通过链接将几个容器连接在一起。不过,这一切如何能在不引起额外开销条件下达成?
更多详情见请继续阅读下一页的精彩内容 :http://www.linuxidc.com/Linux/2015-01/111631p2.htm
Docker 如何完成它需要完成的东西?
两个词:cgroups 和 union 文件系统。Docker 使用 cgroup 来提供容器隔离,而 union 文件系统用于保存镜像并使容器变得短暂。
Cgroups
这是 Linux 内核功能,它让两件事情变成可能:
- 限制 Linux 进程组的资源占用(内存、CPU)
- 为进程组制作 PID、UTS、IPC、网络、用户及装载命名空间
这里的关键词是命名空间。比如说,一个 PID 命名空间允许它里面的进程使用隔离的 PID,并与主 PID 命名空间独立开来,因此你可以在一个 PID 命名空间里拥有自己的 PID 为 1 的初始化进程。其他命名空间与此类似。然后你可以使用 cgroup 创建一个环境,进程可以在其中运行,并与操作系统的其他进程隔离开,但这里的关键点是这个环境上的进程使用的是已经加载和运行的内核,因此额外开销与运行其他进程几乎是一样的。Chroot 之于 cgroup 就好像我之于绿巨人(The Hulk)、贝恩(Bane)和毒液(Venom)的组合(译者注:本文作者非常瘦弱,后三者都非常强壮)。
Union 文件系统
Union 文件系统允许通过 union 装载变化的分层叠加。在 union 文件系统里,文件系统可以被装载在其他文件系统之上,其结果就是一个变化的分层集合。每个装载的文件系统表示前一个文件系统之后的变化集合,就像是一个 diff。
当你下载一个镜像,修改它,然后保存成新版本,你只是创建了加载在包裹基础镜像的初始层上的一个新的 union 文件系统。这使得 Docker 镜像非常轻,比如:你的 DB、Nginx 和 Syslog 镜像都可以共享同一个 Ubuntu 基础,每一个镜像保存的只是在基础之上工作需要的变化。
截至 2015 年 1 月 4 日,Docker 允许在 union 文件系统中使用 aufs、btrfs 或设备映射(device mapper)。
镜像
我们来看一下 postgresql 的一个镜像:
[{"AppArmorProfile": "","Args": [
"postgres"],"Config": {
"AttachStderr": true,
"AttachStdin": false,
"AttachStdout": true,
"Cmd": [
"postgres"
],
"CpuShares": 0,
"Cpuset": "",
"Domainname": "",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"Env": [
"PATH=/usr/lib/postgresql/9.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"LANG=en_US.utf8",
"PG_MAJOR=9.3",
"PG_VERSION=9.3.5-1.pgdg70 1",
"PGDATA=/var/lib/postgresql/data"
],
"ExposedPorts": {
"5432/tcp": {}
},
"Hostname": "6334a2022f21",
"Image": "postgres",
"MacAddress": "",
"Memory": 0,
"MemorySwap": 0,
"NetworkDisabled": false,
"OnBuild": null,
"OpenStdin": false,
"PortSpecs": null,
"StdinOnce": false,
"Tty": false,
"User": "",
"Volumes": {
"/var/lib/postgresql/data": {}
},
"WorkingDir": ""},"Created": "2015-01-03T23:56:12.354896658Z","Driver": "devicemapper","ExecDriver": "native-0.2","HostConfig": {
"Binds": null,
"CapAdd": null,
"CapDrop": null,
"ContainerIDFile": "",
"Devices": null,
"Dns": null,
"DnsSearch": null,
"ExtraHosts": null,
"IpcMode": "",
"Links": null,
"LxcConf": null,
"NetworkMode": "",
"PortBindings": null,
"Privileged": false,
"PublishAllPorts": false,
"RestartPolicy": {
"MaximumRetryCount": 0,
"Name": ""
},
"SecurityOpt": null,
"VolumesFrom": [
"bestwebappever.dev.db-data"
]},"HostnamePath": "/mnt/docker/containers/6334a2022f213f9534b45df33c64437081a38d50c7f462692b019185b8cbc6da/hostname","HostsPath": "/mnt/docker/containers/6334a2022f213f9534b45df33c64437081a38d50c7f462692b019185b8cbc6da/hosts","Id": "6334a2022f213f9534b45df33c64437081a38d50c7f462692b019185b8cbc6da","Image": "aaab661c1e3e8da2d9fc6872986cbd7b9ec835dcd3886d37722f1133baa3d2db","MountLabel": "","Name": "/bestwebappever.dev.db","NetworkSettings": {
"Bridge": "docker0",
"Gateway": "172.17.42.1",
"IPAddress": "172.17.0.176",
"IPPrefixLen": 16,
"MacAddress": "02:42:ac:11:00:b0",
"PortMapping": null,
"Ports": {
"5432/tcp": null
}},"Path": "/docker-entrypoint.sh","ProcessLabel": "","ResolvConfPath": "/mnt/docker/containers/6334a2022f213f9534b45df33c64437081a38d50c7f462692b019185b8cbc6da/resolv.conf","State": {
"Error": "",
"ExitCode": 0,
"FinishedAt": "0001-01-01T00:00:00Z",
"OOMKilled": false,
"Paused": false,
"Pid": 21654,
"Restarting": false,
"Running": true,
"StartedAt": "2015-01-03T23:56:42.003405983Z"},"Volumes": {
"/var/lib/postgresql/data": "/mnt/docker/vfs/dir/5ac73c52ca86600a82e61279346dac0cb3e173b067ba9b219ea044023ca67561",
"postgresql_data": "/mnt/docker/vfs/dir/abace588b890e9f4adb604f633c280b9b5bed7d20285aac9cc81a84a2f556034"},"VolumesRW": {
"/var/lib/postgresql/data": true,
"postgresql_data": true}}]
就是这样,镜像只是一个 json,它指定了从该镜像运行的容器的特性,union 装载点保存在哪里,要暴露什么端口等等。每个镜像与一个 union 文件系统相关联,每个 Docker 上的 union 文件系统都有一个上层,就像是计算机科技树(不像其他树有一大堆的家族)。如果它看起来有点吓人或有些东西串不起来,不要担心,这只是出于教学目的,你并不需要直接处理这些文件。
容器
容器之所以是短暂的,是因为当你从镜像上创建一个容器,Docker 会创建一个空白的 union 文件系统加载在与该镜像关联的 union 文件系统之上。
由于 union 文件系统是空白的,这意味着没有变化会被应用到镜像的文件系统上,你创建的变化会得到体现,但是当容器停止,该容器的 union 文件系统会被丢弃,留下的是你启动时的原始镜像文件系统。除非你创建一个新的镜像,或制作一个卷,你所做的变化在容器停止时都会消失。
卷所做的是在容器内指定一个目录,以便在 union 文件系统之外保存它。
这是一个 bestwebappever 的容器:
[{"AppArmorProfile": "","Args": [],"Config": {
"AttachStderr": true,
"AttachStdin": false,
"AttachStdout": true,
"Cmd": [
"/sbin/my_init"
],
"CpuShares": 0,
"Cpuset": "",
"Domainname": "",
"Entrypoint": null,
"Env": [
"DJANGO_CONFIGURATION=Local",
"HOME=/root",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TALPOR_ENVIRONMENT=local",
"TALPOR_DIR=/opt/bestwebappever"
],
"ExposedPorts": {
"80/tcp": {}
},
"Hostname": "44a87fdaf870",
"Image": "talpor/bestwebappever:dev",
"MacAddress": "",
"Memory": 0,
"MemorySwap": 0,
"NetworkDisabled": false,
"OnBuild": null,
"OpenStdin": false,
"PortSpecs": null,
"StdinOnce": false,
"Tty": false,
"User": "",
"Volumes": {
"/opt/bestwebappever": {}
},
"WorkingDir": "/opt/bestwebappever"},"Created": "2015-01-03T23:56:15.378511619Z","Driver": "devicemapper","ExecDriver": "native-0.2","HostConfig": {
"Binds": [
"/home/german/bestwebappever/:/opt/bestwebappever:rw"
],
"CapAdd": null,
"CapDrop": null,
"ContainerIDFile": "",
"Devices": null,
"Dns": null,
"DnsSearch": null,
"ExtraHosts": null,
"IpcMode": "",
"Links": [
"/bestwebappever.dev.db:/bestwebappever.dev.app/db",
"/bestwebappever.dev.Redis:/bestwebappever.dev.app/redis"
],
"LxcConf": null,
"NetworkMode": "",
"PortBindings": {
"80/tcp": [
{
"HostIp": "",
"HostPort": "8887"
}
]
},
"Privileged": false,
"PublishAllPorts": false,
"RestartPolicy": {
"MaximumRetryCount": 0,
"Name": ""
},
"SecurityOpt": null,
"VolumesFrom": [
"bestwebappever.dev.requirements-data"
]},"HostnamePath": "/mnt/docker/containers/44a87fdaf870281e86160e9e844b8987cfefd771448887675fed99460de491c4/hostname","HostsPath": "/mnt/docker/containers/44a87fdaf870281e86160e9e844b8987cfefd771448887675fed99460de491c4/hosts","Id": "44a87fdaf870281e86160e9e844b8987cfefd771448887675fed99460de491c4","Image": "b84804fac17b61fe8f344359285186f1a63cd8c0017930897a078cd09d61bb60","MountLabel": "","Name": "/bestwebappever.dev.app","NetworkSettings": {
"Bridge": "docker0",
"Gateway": "172.17.42.1",
"IPAddress": "172.17.0.179",
"IPPrefixLen": 16,
"MacAddress": "02:42:ac:11:00:b3",
"PortMapping": null,
"Ports": {
"80/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "8887"
}
]
}},"Path": "/sbin/my_init","ProcessLabel": "","ResolvConfPath": "/mnt/docker/containers/44a87fdaf870281e86160e9e844b8987cfefd771448887675fed99460de491c4/resolv.conf","State": {
"Error": "",
"ExitCode": 0,
"FinishedAt": "0001-01-01T00:00:00Z",
"OOMKilled": false,
"Paused": false,
"Pid": 21796,
"Restarting": false,
"Running": true,
"StartedAt": "2015-01-03T23:56:47.537259546Z"},"Volumes": {
"/opt/bestwebappever": "/home/german/bestwebappever",
"requirements_data": "/mnt/docker/vfs/dir/bc14bec26ca311d5ed9f2a83eebef872a879c9e2f1d932470e0fd853fe8be336"},"VolumesRW": {
"/opt/bestwebappever": true,
"requirements_data": true}}]
基本上与镜像相同,不过现在还指定了一些暴露给宿主的端口,也声明了卷位于宿主的位置,容器状态是从现在直到结束,等等。与前面一样,如果它看起来让人生畏,不要担心,你不需要直接处理这些 json。
Docker 是一个相对较新且发展非常快速的项目,可用来创建非常轻量的“虚拟机”。注意这里的引号非常重要,Docker 创建的并非真正的虚拟机,而更像是打了激素的 chroot,嗯,是大量的激素。
在我们继续之前,我先说下,截至目前(2015 年 1 月 4 日)为止,Docker 只能在 Linux 上工作,暂不支持 Windows 或 OSX(译者注:不直接支持)。我稍后会讲到 Docker 的架构,你会明白其中的原因。所以,如果想在非 Linux 平台上使用 Docker,你需要在虚拟机里运行 Linux。
本教程有三个目标:说明 Docker 解决的问题、说明它如何解决这个问题、以及说明它使用了哪些技术来解决这个问题。这不是一篇教你怎么运行安装 Docker 的教程,Docker 此类教程已经有很多,包括 Docker 作者的在线互动教程。本文最后有一个步骤说明,目的是用一个明确的现实世界的例子来串联文章中所有的理论,但不会太过详细。
CentOS 6/ 7 系列安装 Docker http://www.linuxidc.com/Linux/2014-07/104768.htm
Docker 的搭建 Gitlab CI 全过程详解 http://www.linuxidc.com/Linux/2013-12/93537.htm
Docker 安装应用 (CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm
在 Docker 中使用 MySQL http://www.linuxidc.com/Linux/2014-01/95354.htm
在 Ubuntu Trusty 14.04 (LTS) (64-bit) 安装 Docker http://www.linuxidc.com/Linux/2014-10/108184.htm
Docker 安装应用 (CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm
Ubuntu 14.04 安装 Docker http://www.linuxidc.com/linux/2014-08/105656.htm
阿里云 CentOS 6.5 模板上安装 Docker http://www.linuxidc.com/Linux/2014-11/109107.htm
Docker 能做什么?
Docker 可以解决虚拟机能够解决的问题,同时也能够解决虚拟机由于资源要求过高而无法解决的问题。Docker 能处理的事情包括:
- 隔离应用依赖
- 创建应用镜像并进行复制
- 创建容易分发的即启即用的应用
- 允许实例简单、快速地扩展
- 测试应用并随后销毁它们
Docker 背后的想法是创建软件程序可移植的轻量级容器,让其可以在任何安装了 Docker 的机器上运行,而不用关心底层操作系统,类似船舶使用的集装箱,野心勃勃的他们成功了!
Docker 究竟做了什么?
这一节我不会说明 Docker 使用了哪些技术来完成它的工作,或有什么具体的命令可用,这些放在了最后一节,这里我将说明的是 Docker 提供的资源和抽象。
Docker 两个最重要的概念是镜像和容器。除此之外,链接和数据卷也很重要。我们先从镜像入手。
镜像
Docker 的镜像类似虚拟机的快照,但更轻量,非常非常轻量(下节细说)。
创建 Docker 镜像有几种方式,多数是在一个现有镜像基础上创建新镜像,因为几乎你需要的任何东西都有了公共镜像,包括所有主流 Linux 发行版,你应该不会找不到你需要的镜像。不过,就算你想从头构建一个镜像,也有好几种方法。
要创建一个镜像,你可以拿一个已有的镜像,对它进行修改来创建它的子镜像。实现的方式有两种:在一个文件中指定一个基础镜像及需要完成的修改;或通过“运行”一个镜像,对其进行修改并提交。不同方式各有优点,不过一般会使用第一种的文件方式来指定所做的变化。
镜像拥有唯一 ID,以及一个供人阅读的名字和标签对。镜像可以命名为类似 ubuntu:latest、ubuntu:precise、django:1.6、django:1.7 等等。
容器
现在说容器了。你可以从镜像中创建容器,这等同于从快照中创建虚拟机,不过更轻量。应用是由容器运行的。
举个例子,你可以下载一个 Ubuntu 的镜像(有个叫 docker registry 的镜像公共仓库),做一些修改:安装 Gunicorn 和你的 Django 应用及其依赖;然后从该镜像中创建一个容器,在它启动后运行你的应用。
容器与虚拟机一样,是隔离的(有一点要注意,我稍后会讨论到)。它们也拥有一个唯一 ID 和唯一的供人阅读的名字。容器有必要对外暴露服务,因此 Docker 允许暴露容器的特定端口。
容器与虚拟机相比有两个主要差异。第一个是:它们被设计成运行单进程,无法很好地模拟一个完整的环境(如果那是你需要的,请看看 LXC)。你可能会尝试运行 runit 或 supervisord 实例来启动多个进程,但(以我的愚见)这真的没有必要。
单进程与多进程之争非常精彩。你应该知道的是,Docker 设计者极力推崇“一个容器一个进程的方式”,如果你要选择在一个容器中运行多个进程,那唯一情况是:出于调试目的,运行类似 ssh 的东西来访问运行中的容器,不过 docker exec 命令解决了这个问题。
容器和虚拟机的第二个巨大差异是:当你停止一个虚拟机时,可能除了一些临时文件,没有文件会被删除;当你停止一个 Docker 容器,对初始状态(创建容器所用的镜像的状态)做的所有变化都会丢失。这是使用 Docker 时必须做出的最大思维变化之一: 容器是短暂和一次性的 。
数据卷
如果你的电子商务网站刚收到客户支付的 3 万元,内核崩溃了,所有数据库变化都丢失了……对你或 Docker 来说都不是一件好事,不过不要担心。Docker 允许你定义数据卷——用于保存持久数据的空间。Docker 强制你定义应用部分和数据部分,并要求你将它们分开。
卷是针对容器的,你可以使用同一个镜像创建多个容器并定义不同的卷。卷保存在运行 Docker 的宿主文件系统上,你可以指定卷存放的目录,或让 Docker 保存在默认位置。保存在其他类型文件系统上的都不是一个卷,稍后再具体说。
链接
链接是 Docker 的另一个重要部分。
容器启动时,将被分配一个随机的私有 IP,其它容器可以使用这个 IP 地址与其进行通讯。这点非常重要,原因有二:一是它提供了容器间相互通信的渠道,二是容器们将共享一个本地网络。我曾经碰到一个问题,在同一台机器上为两个客户启动两个 elasticsearch 容器,但保留集群名称为默认设置,结果这两台 elasticsearch 服务器立马变成了一个自主集群。
要开启容器间通讯,Docker 允许你在创建一个新容器时引用其它现存容器,在你刚创建的容器里被引用的容器将获得一个(你指定的)别名。我们就说,这两个容器链接在了一起。
因此,如果 DB 容器已经在运行,我可以创建 web 服务器容器,并在创建时引用这个 DB 容器,给它一个别名,比如 dbapp。在这个新建的 web 服务器容器里,我可以在任何时候使用主机名 dbapp 与 DB 容器进行通讯。
Docker 更进一步,要求你声明容器在被链接时要开放哪些端口给其他容器,否则将没有端口可用。
Docker 镜像的可移植性
在创建镜像时有一点要注意。Docker 允许你在一个镜像中指定卷和端口。从这个镜像创建的容器继承了这些设置。但是,Docker 不允许你在镜像上指定任何不可移植的内容。
例如,你可以在镜像里定义卷,只要它们被保存在 Docker 使用的默认位置。这是因为如果你在宿主文件系统里指定了一个特定目录来保存卷,其他使用这个镜像的宿主无法保证这个目录是存在的。
你可以定义要暴露的端口,但仅限那些在创建链接时暴露给其他容器的端口,你不能指定暴露给宿主的端口,因为你无从知晓使用那个镜像的宿主有哪些端口可用。
你也不能在镜像上定义链接。使用链接要求通过名字引用其他容器,但你无法预知每个使用那个镜像的宿主如何命名容器。
镜像必须完全可移植,Docker 不允许例外。
以上就是主要的部分,创建镜像、用它们创建容器,在需要时暴露端口和创造卷、通过链接将几个容器连接在一起。不过,这一切如何能在不引起额外开销条件下达成?
更多详情见请继续阅读下一页的精彩内容 :http://www.linuxidc.com/Linux/2015-01/111631p2.htm
超级、无比简单的步骤说明
第一步
安装 Docker。
Docker 命令工具需要 root 权限才能工作。你可以将你的用户放入 docker 组来避免每次都要使用 sudo。
第二步
使用以下命令从公共 registry 下载一个镜像:
$> docker pull Ubuntu:latest
ubuntu:latest: The image you are pulling has been verified
3b363fd9d7da: Pull complete
.....<bunch of downloading-stuff output>.....8eaa4ff06b53: Pull complete
Status: Downloaded newer image for ubuntu:latest
$>
这个公共 registry 上有你需要的几乎所有东西的镜像:Ubuntu、Fedora、Postgresql、MySQL、Jenkins、Elasticsearch、Redis 等等。Docker 开发人员在这个公共 registry 里维护着数个镜像,不过你能从上面拉取大量来自用户发布的自建镜像。
也许你需要或想要一个私有的 registry(用于开发应用之类的容器),你可以先看看这个。现在,有好几个方式可以设置你自己的私有 registry。你也可以买一个。
第三步
列出你的镜像:
$> docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu latest 8eaa4ff06b53 4 days ago 192.7 MB
第四步
从该镜像上创建一个容器。
$> docker run --rm -ti ubuntu /bin/bash
root@4638a40c2fbb:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root......
root@4638a40c2fbb:/# exit
上一条命令的简要说明:
- –rm:告诉 Docker 一旦运行的进程退出就删除容器。这在进行测试时非常有用,可免除杂乱
- -ti:告诉 Docker 分配一个伪终端并进入交互模式。这将进入到容器内,对于快速原型开发或尝试很有用,但不要在生产容器中打开这些标志
- ubuntu:这是容器所基于的镜像
- /bin/bash:要运行的命令,因为我们以交互模式启动,它将显示一个容器的提示符
在运行 run 命令时,你可指定链接、卷、端口、窗口名称(如果你没提供,Docker 将分配一个默认名称)等等。
现在,我们在后台运行一个容器:
$> docker run -d ubuntu ping 8.8.8.831c68e9c09a0d632caae40debe13da3d6e612364198e2ef21f842762df4f987f
$>
输出的是分配的 ID,因为是随机的,你的将有所不同。我们来检查一下容器是否起来了:
$> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
31c68e9c09a0 ubuntu:latest "ping 8.8.8.8" 2 minutes ago Up 2 minutes loving_mcclintock
就在那,它被自动分配了一个叫 loving_mcclintock 的名称。我们看看容器里正在发生什么:
$> docker exec -ti loving_mcclintock /bin/bash
root@31c68e9c09a0:/# ps -aux|grep ping
root 1 0.0 0.0 6504 636 ? Ss 20:46 0:00 ping 8.8.8.8
root@31c68e9c09a0:/# exit
我们所做的是在容器里运行程序,这里的程序是 /bin/bash。-ti 标志与 docker run 的作用相同,将我们放置到容器的控制台里。
结尾
差不多就是这样了。有太多的东西可以讲,但那超出了本文的范围。
不过我会提供一些我认为非常重要或有趣的链接和延伸阅读材料。
Docker 的基本结构:
- https://docs.docker.com/introd … cker/
- http://blog.docker.com/2014/03 … iner/
延伸阅读:
- Dockerfiles:允许你使用一个文本文件定义镜像,这非常重要
- 我说过 dockerfiles 非常重要吧?
- 你真应该看看 dockerfiles
- docker build:你需要这个来构建你的 dockerfiles
- docker push/docker pull
- docker create/docker run
- docker rm/docker rmi
- docker start/docker stop
- docker exec
- docker inspect
- docker tag
- Links
- Volumes
有趣的链接:
- ANNOUNCING DOCKER MACHINE, SWARM, AND COMPOSE FOR ORCHESTRATING DISTRIBUTED APPS
- Docker at Shopify: How we built containers that power over 100,000 online shops
- Why CoreOS is a game-changer in the data center and cloud
- Docker Misconceptions
- Microservices – Not a Free Lunch!
- Feature Preview: Docker-Based Development Environments
- How to compile Docker on Windows (感谢 reddit 的 computermedic 提供)
有用的项目和链接
- Phusion Docker baseimage
- Shipyard
- DockerUI
- CoreOS
- Decking
- Docker-py
- Docker-map
- Docker-fabric
Docker 的详细介绍 :请点这里
Docker 的下载地址 :请点这里