diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 6a9c360..8997279 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -11,7 +11,7 @@ * [ ] CoreOS * [ ] Debian 8 * [ ] Debian 9 -* [ ] MacOS +* [ ] macOS * [ ] Windows 10 * [ ] Others (Pls describe below) diff --git a/SUMMARY.md b/SUMMARY.md index 820dd43..0416aa8 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -98,7 +98,7 @@ * [基本概念](swarm_mode/overview.md) * [创建 Swarm 集群](swarm_mode/create.md) * [在 Swarm 集群部署服务](swarm_mode/deploy.md) - * [在 Swarm 集群中使用 docker-compose.yml](swarm_mode/stack.md) + * [在 Swarm 集群中使用 compose 文件](swarm_mode/stack.md) * [Etcd 项目](etcd/README.md) * [简介](etcd/intro.md) * [安装](etcd/install.md) diff --git a/advanced_network/dns.md b/advanced_network/dns.md index 2f16d0d..94c5b4a 100644 --- a/advanced_network/dns.md +++ b/advanced_network/dns.md @@ -1,16 +1,14 @@ ## 配置 DNS -Docker 没有为每个容器专门定制镜像,那么怎么自定义配置容器的主机名和 DNS 配置呢? -秘诀就是它利用虚拟文件来挂载到来容器的 3 个相关配置文件。 +如何自定义配置容器的主机名和 DNS 呢?秘诀就是 Docker 利用虚拟文件来挂载容器的 3 个相关配置文件。 + +在容器中使用 `mount` 命令可以看到挂载信息: -在容器中使用 mount 命令可以看到挂载信息: ```bash $ mount -... /dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ... /dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ... tmpfs on /etc/resolv.conf type tmpfs ... -... ``` 这种机制可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 DNS 配置通过 `/etc/resolv.conf` 文件立刻得到更新。 @@ -37,12 +35,10 @@ nameserver 8.8.8.8 如果用户想要手动指定容器的配置,可以利用下面的选项。 -`-h HOSTNAME or --hostname=HOSTNAME` -设定容器的主机名,它会被写到容器内的 `/etc/hostname` 和 `/etc/hosts`。但它在容器外部看不到,既不会在 `docker ps` 中显示,也不会在其他的容器的 `/etc/hosts` 看到。 +`-h HOSTNAME` 或者 `--hostname=HOSTNAME` 设定容器的主机名,它会被写到容器内的 `/etc/hostname` 和 `/etc/hosts`。但它在容器外部看不到,既不会在 `docker ps` 中显示,也不会在其他的容器的 `/etc/hosts` 看到。 -`--dns=IP_ADDRESS` -添加 DNS 服务器到容器的 `/etc/resolv.conf` 中,让容器用这个服务器来解析所有不在 `/etc/hosts` 中的主机名。 +`--dns=IP_ADDRESS` 添加 DNS 服务器到容器的 `/etc/resolv.conf` 中,让容器用这个服务器来解析所有不在 `/etc/hosts` 中的主机名。 -`--dns-search=DOMAIN` -设定容器的搜索域,当设定搜索域为 `.example.com` 时,在搜索一个名为 host 的主机时,DNS 不仅搜索host,还会搜索 `host.example.com`。 -注意:如果没有上述最后 2 个选项,Docker 会默认用主机上的 `/etc/resolv.conf` 来配置容器。 +`--dns-search=DOMAIN` 设定容器的搜索域,当设定搜索域为 `.example.com` 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 `host.example.com`。 + +*注意:*如果没有上述最后 2 个选项,Docker 会默认用主机上的 `/etc/resolv.conf` 来配置容器。 diff --git a/advanced_network/port_mapping.md b/advanced_network/port_mapping.md index b29162b..ab03c84 100644 --- a/advanced_network/port_mapping.md +++ b/advanced_network/port_mapping.md @@ -1,10 +1,13 @@ ## 映射容器端口到宿主主机的实现 默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。 + ### 容器访问外部实现 -容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址。这是使用 `iptables` 的源地址伪装操作实现的。 + +容器所有到外部网络的连接,源地址都会被 NAT 成本地系统的 IP 地址。这是使用 `iptables` 的源地址伪装操作实现的。 查看主机的 NAT 规则。 + ```bash $ sudo iptables -t nat -nL ... @@ -13,6 +16,7 @@ target prot opt source destination MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16 ... ``` + 其中,上述规则将所有源地址在 `172.17.0.0/16` 网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址。 ### 外部访问容器实现 @@ -22,6 +26,7 @@ MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16 不管用那种办法,其实也是在本地的 `iptable` 的 nat 表中添加相应的规则。 使用 `-P` 时: + ```bash $ iptables -t nat -nL ... @@ -31,13 +36,17 @@ DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:1 ``` 使用 `-p 80:80` 时: + ```bash $ iptables -t nat -nL Chain DOCKER (2 references) target prot opt source destination DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80 ``` + 注意: + * 这里的规则映射了 0.0.0.0,意味着将接受主机来自所有接口的流量。用户可以通过 `-p IP:host_port:container_port` 或 `-p IP::port` 来指定允许访问容器的主机上的 IP、接口等,以制定更严格的规则。 + * 如果希望永久绑定到某个固定的 IP 地址,可以在 Docker 配置文件 `/etc/default/docker` 中指定 `DOCKER_OPTS="--ip=IP_ADDRESS"`,之后重启 Docker 服务即可生效。 diff --git a/basic_concept/container.md b/basic_concept/container.md index f4f0b68..281c555 100644 --- a/basic_concept/container.md +++ b/basic_concept/container.md @@ -2,7 +2,7 @@ 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的`类`和`实例`一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。 -容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 [命名空间](https://en.wikipedia.org/wiki/Linux_namespaces)。因此容器可以拥有自己的 `root` 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会把容器和虚拟机搞混。 +容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 [命名空间](https://en.wikipedia.org/wiki/Linux_namespaces)。因此容器可以拥有自己的 `root` 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。 前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为**容器存储层**。 @@ -10,4 +10,4 @@ 按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 [数据卷(Volume)](../data_management/volume.md)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。 -数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器可以随意删除、重新 `run`,数据却不会丢失。 +数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器可以随意删除、重新运行,数据却不会丢失。 diff --git a/basic_concept/repository.md b/basic_concept/repository.md index b938e89..ef7a348 100644 --- a/basic_concept/repository.md +++ b/basic_concept/repository.md @@ -1,12 +1,12 @@ ## Docker Registry -镜像构建完成后,可以很容易的在当前宿主上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,[Docker Registry](https://docs.docker.com/registry/) 就是这样的服务。 +镜像构建完成后,可以很容易的在当前宿主上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,[Docker Registry](../repository/registry/) 就是这样的服务。 一个 **Docker Registry** 中可以包含多个**仓库**(Repository);每个仓库可以包含多个**标签**(Tag);每个标签对应一个镜像。 通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 `<仓库名>:<标签>` 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 `latest` 作为默认标签。 -以 [Ubuntu 镜像](https://hub.docker.com/_/ubuntu/) 为例,`ubuntu` 是仓库的名字,其内包含有不同的版本标签,如,`14.04`, `16.04`。我们可以通过 `ubuntu:14.04`,或者 `ubuntu:16.04` 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 `ubuntu`,那将视为 `ubuntu:latest`。 +以 [Ubuntu 镜像](https://store.docker.com/images/ubuntu) 为例,`ubuntu` 是仓库的名字,其内包含有不同的版本标签,如,`14.04`, `16.04`。我们可以通过 `ubuntu:14.04`,或者 `ubuntu:16.04` 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 `ubuntu`,那将视为 `ubuntu:latest`。 仓库名经常以 *两段式路径* 形式出现,比如 `jwilder/nginx-proxy`,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。 @@ -22,7 +22,7 @@ Docker Registry 公开服务是开放给用户使用、允许用户管理镜像 ### 私有 Docker Registry -除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 [Docker Registry 镜像](https://hub.docker.com/_/registry/),可以直接使用做为私有 Registry 服务。在 [私有仓库](../repository/registry.md) 一节中,会有进一步的搭建私有 Registry 服务的讲解。 +除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 [Docker Registry 镜像](https://store.docker.com/images/registry/),可以直接使用做为私有 Registry 服务。在 [私有仓库](../repository/registry.md) 一节中,会有进一步的搭建私有 Registry 服务的讲解。 开源的 Docker Registry 镜像只提供了 [Docker Registry API](https://docs.docker.com/registry/spec/api/) 的服务端实现,足以支持 `docker` 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。在官方的商业化版本 [Docker Trusted Registry](https://docs.docker.com/datacenter/dtr/2.0/) 中,提供了这些高级功能。 diff --git a/image/commit.md b/image/commit.md index 378e6c8..074c5c1 100644 --- a/image/commit.md +++ b/image/commit.md @@ -1,6 +1,6 @@ ## 利用 commit 理解镜像构成 -注意: `docker commit` 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现场等。但是,不要使用 `docker commit` 定制镜像,定制镜像应该使用 `Dockerfile` 来完成。如果你想要定制镜像请查看下一章节。 +注意: `docker commit` 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现场等。但是,不要使用 `docker commit` 定制镜像,定制镜像应该使用 `Dockerfile` 来完成。如果你想要定制镜像请查看下一小节。 镜像是容器的基础,每次执行 `docker run` 的时候都会指定哪个镜像作为容器运行的基础。在之前的例子中,我们所使用的都是来自于 Docker Hub 的镜像。直接使用这些镜像是可以满足一定的需求,而当这些镜像无法直接满足需求时,我们就需要定制这些镜像。接下来的几节就将讲解如何定制镜像。 diff --git a/image/dockerfile/README.md b/image/dockerfile/README.md index 4265815..fa4d01f 100644 --- a/image/dockerfile/README.md +++ b/image/dockerfile/README.md @@ -1,3 +1,3 @@ ## Dockerfile 指令详解 -我们已经介绍了 `FROM`,`RUN`,还提及了 `COPY`, `ADD`,其实 `Dockerfile` 功能很强大,它提供了十多个指令。这里我们继续讲解剩下的指令。 +我们已经介绍了 `FROM`,`RUN`,还提及了 `COPY`, `ADD`,其实 `Dockerfile` 功能很强大,它提供了十多个指令。下面我们继续讲解其他的指令。 diff --git a/image/list.md b/image/list.md index 336180a..4a825fc 100644 --- a/image/list.md +++ b/image/list.md @@ -24,7 +24,7 @@ ubuntu 14.04 1e0c3dd64ccd 4 weeks ago 另外一个需要注意的问题是,`docker images` 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。 -在 Docker 1.13+ 版本中可以你可以通过以下命令来便捷的查看镜像、容器、数据卷所占用的空间。 +你可以通过以下命令来便捷的查看镜像、容器、数据卷所占用的空间。 ```bash $ docker system df @@ -54,12 +54,6 @@ REPOSITORY TAG IMAGE ID CREATED 一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的命令删除。 -```bash -$ docker rmi $(docker images -q -f dangling=true) -``` - -在 Docker 1.13+ 版本中你可以便捷的使用以下命令来删除虚悬镜像。 - ```bash $ docker image prune ``` diff --git a/introduction/what.md b/introduction/what.md index f664f0a..db2fc0e 100644 --- a/introduction/what.md +++ b/introduction/what.md @@ -4,7 +4,7 @@ Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的 Docker 自开源后受到广泛的关注和讨论,至今其 GitHub 项目已经超过 4 万 6 千个星标和一万多个 fork。甚至由于 Docker 项目的火爆,在 2013 年底,[dotCloud 公司决定改名为 Docker](https://blog.docker.com/2013/10/dotcloud-is-becoming-docker-inc/)。Docker 最初是在 Ubuntu 12.04 上开发实现的;Red Hat 则从 RHEL 6.5 开始对 Docker 进行支持;Google 也在其 PaaS 产品中广泛应用 Docker。 -Docker 使用 Google 公司推出的 [Go 语言](https://golang.org/) 进行开发实现,基于 Linux 内核的 [cgroup](https://zh.wikipedia.org/wiki/Cgroups),[namespace](https://en.wikipedia.org/wiki/Linux_namespaces),以及 [AUFS](https://en.wikipedia.org/wiki/Aufs) 类的 [Union FS](https://en.wikipedia.org/wiki/Union_mount) 等技术,对进程进行封装隔离,属于 [操作系统层面的虚拟化技术](https://en.wikipedia.org/wiki/Operating-system-level_virtualization)。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 [LXC](https://linuxcontainers.org/lxc/introduction/),从 0.7 版本以后开始去除 LXC,转而使用自行开发的 [libcontainer](https://github.com/docker/libcontainer),从 1.11 开始,则进一步演进为使用 [runC](https://github.com/opencontainers/runc) 和 [containerd](https://containerd.tools/)。 +Docker 使用 Google 公司推出的 [Go 语言](https://golang.org/) 进行开发实现,基于 Linux 内核的 [cgroup](https://zh.wikipedia.org/wiki/Cgroups),[namespace](https://en.wikipedia.org/wiki/Linux_namespaces),以及 [AUFS](https://en.wikipedia.org/wiki/Aufs) 类的 [Union FS](https://en.wikipedia.org/wiki/Union_mount) 等技术,对进程进行封装隔离,属于 [操作系统层面的虚拟化技术](https://en.wikipedia.org/wiki/Operating-system-level_virtualization)。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 [LXC](https://linuxcontainers.org/lxc/introduction/),从 0.7 版本以后开始去除 LXC,转而使用自行开发的 [libcontainer](https://github.com/docker/libcontainer),从 1.11 开始,则进一步演进为使用 [runC](https://github.com/opencontainers/runc) 和 [containerd](https://github.com/containerd/containerd)。 Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。 diff --git a/revision.md b/revision.md index ef8dd1d..cdc8fa1 100644 --- a/revision.md +++ b/revision.md @@ -7,7 +7,7 @@ * 0.9-rc2: 2017-12-10 * 更新 `CoreOS` 章节 - + * 0.9-rc1: 2017-11-30 * 根据最新版本(v17.09)修订内容 @@ -16,6 +16,7 @@ * 增加 `docker exec` 子命令介绍 * 增加 `docker` 管理子命令 `container` `image` `network` `volume` 介绍 * 增加 `树莓派单片电脑` 安装 Docker + * 增加 Docker 存储驱动 `OverlayFS` 相关内容 * 更新 `Docker CE` `v17.x` 安装说明 * 更新 `Docker 网络` 一节 diff --git a/underly/ufs.md b/underly/ufs.md index 094086b..e64bef5 100644 --- a/underly/ufs.md +++ b/underly/ufs.md @@ -9,3 +9,14 @@ Docker 中使用的 AUFS(AnotherUnionFS)就是一种联合文件系统。 `AUFS` 支持为每一个成员目录(类似 Git 的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限, 同时 `AUFS` 里有一个类似分层的概念, 对只读权限的分支可以逻辑上进行增量地修改(不影响只读部分的)。 Docker 目前支持的联合文件系统包括 `OverlayFS`, `AUFS`, `Btrfs`, `VFS`, `ZFS` 和 `Device Mapper`。 + +各 Linux 发行版 Docker 推荐使用的存储驱动如下表。 + +|Linux 发行版 | Docker 推荐使用的存储驱动 | +| :-- | :-- | +|Docker CE on Ubuntu | `aufs`, `devicemapper`, `overlay2` (Ubuntu 14.04.4 +, 16.04 +), `overlay`, `zfs`, `vfs` | +|Docker CE on Debian | `aufs`, `devicemapper`, `overlay2` (Debian Stretch), `overlay`, `vfs` | +|Docker CE on CentOS | `devicemapper`, `vfs` | +|Docker CE on Fedora | `devicemapper`, `overlay2` (Fedora 26 +), `overlay` (实验性支持), `vfs` | + +在可能的情况下,推荐使用 `overlay2` 存储驱动,`overlay2` 是目前 Docker 默认的存储驱动,以前则是 `aufs`。你可以通过配置来使用以上提到的其他类型的存储驱动。