diff --git a/.vuepress/config.js b/.vuepress/config.js
index af5b281..ce4a000 100644
--- a/.vuepress/config.js
+++ b/.vuepress/config.js
@@ -312,12 +312,11 @@ module.exports = {
'opensource/linuxkit',
],
},
+ 'appendix/faq/',
{
- title: "附录",
- collapsable:false,
+ title: "热门镜像介绍",
+ collapsable: false,
children: [
- 'appendix/',
- 'appendix/faq/',
'appendix/repo/',
'appendix/repo/ubuntu',
'appendix/repo/centos',
@@ -328,19 +327,13 @@ module.exports = {
'appendix/repo/wordpress',
'appendix/repo/mongodb',
'appendix/repo/redis',
- 'appendix/command/',
- 'appendix/best_practices',
- 'appendix/debug',
- 'appendix/resources'
- ],
- },
- {
- title: "归档",
- collapsable: false,
- children: [
- 'archive/',
],
},
+ 'appendix/command/',
+ 'appendix/best_practices',
+ 'appendix/debug',
+ 'appendix/resources',
+ 'archive/',
{
title: "Docker Machine",
collapsable: false,
diff --git a/advanced_network/access_control.md b/advanced_network/access_control.md
index e9fff71..c382b5d 100644
--- a/advanced_network/access_control.md
+++ b/advanced_network/access_control.md
@@ -1,7 +1,7 @@
-## 容器访问控制
+# 容器访问控制
容器的访问控制,主要通过 Linux 上的 `iptables` 防火墙来进行管理和实现。`iptables` 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。
-### 容器访问外部网络
+## 容器访问外部网络
容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。
```bash
@@ -14,17 +14,17 @@ $sysctl -w net.ipv4.ip_forward=1
```
如果在启动 Docker 服务的时候设定 `--ip-forward=true`, Docker 就会自动设定系统的 `ip_forward` 参数为 1。
-### 容器之间访问
+## 容器之间访问
容器之间相互访问,需要两方面的支持。
* 容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到 `docker0` 网桥上。
* 本地系统的防火墙软件 -- `iptables` 是否允许通过。
-#### 访问所有端口
+### 访问所有端口
当启动 Docker 服务(即 dockerd)的时候,默认会添加一条转发策略到本地主机 iptables 的 FORWARD 链上。策略为通过(`ACCEPT`)还是禁止(`DROP`)取决于配置`--icc=true`(缺省值)还是 `--icc=false`。当然,如果手动指定 `--iptables=false` 则不会添加 `iptables` 规则。
可见,默认情况下,不同容器之间是允许网络互通的。如果为了安全考虑,可以在 `/etc/docker/daemon.json` 文件中配置 `{"icc": false}` 来禁止它。
-#### 访问指定端口
+### 访问指定端口
在通过 `-icc=false` 关闭网络访问后,还可以通过 `--link=CONTAINER_NAME:ALIAS` 选项来访问容器的开放端口。
例如,在启动 Docker 服务时,可以同时使用 `icc=false --iptables=true` 参数来关闭允许相互的网络访问,并让 Docker 可以修改系统中的 `iptables` 规则。
diff --git a/advanced_network/bridge.md b/advanced_network/bridge.md
index 31e24b1..0ce6a52 100644
--- a/advanced_network/bridge.md
+++ b/advanced_network/bridge.md
@@ -1,4 +1,4 @@
-## 自定义网桥
+# 自定义网桥
除了默认的 `docker0` 网桥,用户也可以指定网桥来连接各个容器。
diff --git a/advanced_network/config_file.md b/advanced_network/config_file.md
index 43733b8..b084c79 100644
--- a/advanced_network/config_file.md
+++ b/advanced_network/config_file.md
@@ -1,4 +1,4 @@
-## 编辑网络配置文件
+# 编辑网络配置文件
Docker 1.2.0 开始支持在运行中的容器里编辑 `/etc/hosts`, `/etc/hostname` 和 `/etc/resolv.conf` 文件。
diff --git a/advanced_network/docker0.md b/advanced_network/docker0.md
index 99e5785..c21ce8b 100644
--- a/advanced_network/docker0.md
+++ b/advanced_network/docker0.md
@@ -1,4 +1,4 @@
-## 配置 docker0 网桥
+# 配置 docker0 网桥
Docker 服务默认会创建一个 `docker0` 网桥(其上有一个 `docker0` 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
diff --git a/advanced_network/example.md b/advanced_network/example.md
index 23ac7af..f7ca843 100644
--- a/advanced_network/example.md
+++ b/advanced_network/example.md
@@ -1,8 +1,8 @@
-## 工具和示例
+# 工具和示例
在介绍自定义网络拓扑之前,你可能会对一些外部工具和例子感兴趣:
-### pipework
+## pipework
Jérôme Petazzoni 编写了一个叫 [pipework](https://github.com/jpetazzo/pipework) 的 shell 脚本,可以帮助用户在比较复杂的场景中完成容器的连接。
-### playground
+## playground
Brandon Rhodes 创建了一个提供完整的 Docker 容器网络拓扑管理的 [Python库](https://github.com/brandon-rhodes/fopnp/tree/m/playground),包括路由、NAT 防火墙;以及一些提供 `HTTP` `SMTP` `POP` `IMAP` `Telnet` `SSH` `FTP` 的服务器。
diff --git a/advanced_network/port_mapping.md b/advanced_network/port_mapping.md
index 8625e3a..dc6f92d 100644
--- a/advanced_network/port_mapping.md
+++ b/advanced_network/port_mapping.md
@@ -1,8 +1,8 @@
-## 映射容器端口到宿主主机的实现
+# 映射容器端口到宿主主机的实现
默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。
-### 容器访问外部实现
+## 容器访问外部实现
容器所有到外部网络的连接,源地址都会被 NAT 成本地系统的 IP 地址。这是使用 `iptables` 的源地址伪装操作实现的。
@@ -19,7 +19,7 @@ MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16
其中,上述规则将所有源地址在 `172.17.0.0/16` 网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址。
-### 外部访问容器实现
+## 外部访问容器实现
容器允许外部访问,可以在 `docker run` 时候通过 `-p` 或 `-P` 参数来启用。
diff --git a/advanced_network/ptp.md b/advanced_network/ptp.md
index 438f6f1..738a751 100644
--- a/advanced_network/ptp.md
+++ b/advanced_network/ptp.md
@@ -1,4 +1,4 @@
-## 示例:创建一个点到点连接
+# 示例:创建一个点到点连接
默认情况下,Docker 会将所有容器连接到由 `docker0` 提供的虚拟子网中。
用户有时候需要两个容器之间可以直连通信,而不用通过主机网桥进行桥接。
diff --git a/advanced_network/quick_guide.md b/advanced_network/quick_guide.md
index e326418..455a818 100644
--- a/advanced_network/quick_guide.md
+++ b/advanced_network/quick_guide.md
@@ -1,4 +1,4 @@
-## 快速配置指南
+# 快速配置指南
下面是一个跟 Docker 网络相关的命令列表。
diff --git a/appendix/repo/centos.md b/appendix/repo/centos.md
index 3ef727f..5ebaf20 100644
--- a/appendix/repo/centos.md
+++ b/appendix/repo/centos.md
@@ -1,12 +1,12 @@
-## [CentOS](https://hub.docker.com/_/centos)
+# [CentOS](https://hub.docker.com/_/centos)
-### 基本信息
+## 基本信息
[CentOS](https://en.wikipedia.org/wiki/CentOS) 是流行的 Linux 发行版,其软件包大多跟 RedHat 系列保持一致。
该仓库位于 `https://hub.docker.com/_/centos` ,提供了 CentOS 从 5 ~ 8 各个版本的镜像。
-### 使用方法
+## 使用方法
默认会启动一个最小化的 CentOS 环境。
@@ -15,6 +15,6 @@ $ docker run --name centos -it centos bash
bash-4.2#
```
-### Dockerfile
+## Dockerfile
请到 https://github.com/docker-library/docs/tree/master/centos 查看。
diff --git a/appendix/repo/mongodb.md b/appendix/repo/mongodb.md
index fc7025a..129e908 100644
--- a/appendix/repo/mongodb.md
+++ b/appendix/repo/mongodb.md
@@ -1,12 +1,12 @@
-## [MongoDB](https://hub.docker.com/_/mongo/)
+# [MongoDB](https://hub.docker.com/_/mongo/)
-### 基本信息
+## 基本信息
[MongoDB](https://en.wikipedia.org/wiki/MongoDB) 是开源的 NoSQL 数据库实现。
该仓库位于 `https://hub.docker.com/_/mongo/` ,提供了 MongoDB 2.x ~ 4.x 各个版本的镜像。
-### 使用方法
+## 使用方法
默认会在 `27017` 端口启动数据库。
@@ -29,6 +29,6 @@ $ docker run -it --rm \
sh -c 'exec mongo "$MONGO_PORT_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/test"'
```
-### Dockerfile
+## Dockerfile
请到 https://github.com/docker-library/docs/tree/master/mongo 查看。
diff --git a/appendix/repo/mysql.md b/appendix/repo/mysql.md
index eef26d5..1a38c9d 100644
--- a/appendix/repo/mysql.md
+++ b/appendix/repo/mysql.md
@@ -1,12 +1,12 @@
-## [MySQL](https://hub.docker.com/_/mysql/)
+# [MySQL](https://hub.docker.com/_/mysql/)
-### 基本信息
+## 基本信息
[MySQL](https://en.wikipedia.org/wiki/MySQL) 是开源的关系数据库实现。
该仓库位于 `https://hub.docker.com/_/mysql/` ,提供了 MySQL 5.5 ~ 8.x 各个版本的镜像。
-### 使用方法
+## 使用方法
默认会在 `3306` 端口启动数据库。
@@ -29,6 +29,6 @@ $ docker run -it --rm \
sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"'
```
-### Dockerfile
+## Dockerfile
请到 https://github.com/docker-library/docs/tree/master/mysql 查看
diff --git a/appendix/repo/nginx.md b/appendix/repo/nginx.md
index b649a31..36b11c0 100644
--- a/appendix/repo/nginx.md
+++ b/appendix/repo/nginx.md
@@ -1,12 +1,12 @@
-## [Nginx](https://hub.docker.com/_/nginx/)
+# [Nginx](https://hub.docker.com/_/nginx/)
-### 基本信息
+## 基本信息
[Nginx](https://en.wikipedia.org/wiki/Nginx) 是开源的高效的 Web 服务器实现,支持 HTTP、HTTPS、SMTP、POP3、IMAP 等协议。
该仓库位于 `https://hub.docker.com/_/nginx/` ,提供了 Nginx 1.0 ~ 1.17.x 各个版本的镜像。
-### 使用方法
+## 使用方法
下面的命令将作为一个静态页面服务器启动。
@@ -43,6 +43,6 @@ $ docker run -d \
nginx
```
-### Dockerfile
+## Dockerfile
请到 https://github.com/docker-library/docs/tree/master/nginx 查看。
diff --git a/appendix/repo/nodejs.md b/appendix/repo/nodejs.md
index 38503a9..ffe4267 100644
--- a/appendix/repo/nodejs.md
+++ b/appendix/repo/nodejs.md
@@ -1,12 +1,12 @@
-## [Node.js](https://hub.docker.com/_/node/)
+# [Node.js](https://hub.docker.com/_/node/)
-### 基本信息
+## 基本信息
[Node.js](https://en.wikipedia.org/wiki/Node.js) 是基于 JavaScript 的可扩展服务端和网络软件开发平台。
该仓库位于 `https://hub.docker.com/_/node/` ,提供了 Node.js 0.10 ~ 12.x 各个版本的镜像。
-### 使用方法
+## 使用方法
在项目中创建一个 Dockerfile。
@@ -35,6 +35,6 @@ $ docker run -it --rm \
node your-daemon-or-script.js
```
-### Dockerfile
+## Dockerfile
请到 https://github.com/docker-library/docs/tree/master/node 查看。
diff --git a/appendix/repo/php.md b/appendix/repo/php.md
index cf62af6..7edbb85 100644
--- a/appendix/repo/php.md
+++ b/appendix/repo/php.md
@@ -1,12 +1,12 @@
-## [PHP](https://hub.docker.com/_/php/)
+# [PHP](https://hub.docker.com/_/php/)
-### 基本信息
+## 基本信息
[PHP](https://en.wikipedia.org/wiki/php)(Hypertext Preprocessor 超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言,它可嵌入到 HTML 中,尤其适合 web 开发。
该仓库位于 `https://hub.docker.com/_/php/` ,提供了 PHP 5.x ~ 7.x 各个版本的镜像。
-### 使用方法
+## 使用方法
下面的命令将运行一个已有的 PHP 脚本。
@@ -14,6 +14,6 @@
$ docker run -it --rm -v "$PWD":/app -w /app php:alpine php your-script.php
```
-### Dockerfile
+## Dockerfile
请到 https://github.com/docker-library/docs/tree/master/php 查看。
diff --git a/appendix/repo/redis.md b/appendix/repo/redis.md
index 92eb53f..9f06ded 100644
--- a/appendix/repo/redis.md
+++ b/appendix/repo/redis.md
@@ -1,12 +1,12 @@
-## [Redis](https://hub.docker.com/_/redis/)
+# [Redis](https://hub.docker.com/_/redis/)
-### 基本信息
+## 基本信息
[Redis](https://en.wikipedia.org/wiki/Redis) 是开源的内存 Key-Value 数据库实现。
该仓库位于 `https://hub.docker.com/_/redis/` ,提供了 Redis 3.x ~ 5.x 各个版本的镜像。
-### 使用方法
+## 使用方法
默认会在 `6379` 端口启动数据库。
@@ -37,6 +37,6 @@ $ docker run -it --rm \
sh -c 'exec redis-cli -h "$REDIS_PORT_6379_TCP_ADDR" -p "$REDIS_PORT_6379_TCP_PORT"'
```
-### Dockerfile
+## Dockerfile
请到 https://github.com/docker-library/docs/tree/master/redis 查看。
diff --git a/appendix/repo/ubuntu.md b/appendix/repo/ubuntu.md
index 20aea1d..c904d99 100644
--- a/appendix/repo/ubuntu.md
+++ b/appendix/repo/ubuntu.md
@@ -1,12 +1,12 @@
-## [Ubuntu](https://hub.docker.com/_/ubuntu/)
+# [Ubuntu](https://hub.docker.com/_/ubuntu/)
-### 基本信息
+## 基本信息
[Ubuntu](https://en.wikipedia.org/wiki/Ubuntu) 是流行的 Linux 发行版,其自带软件版本往往较新一些。
该仓库位于 `https://hub.docker.com/_/ubuntu/` ,提供了 Ubuntu 从 12.04 ~ 19.04 各个版本的镜像。
-### 使用方法
+## 使用方法
默认会启动一个最小化的 Ubuntu 环境。
@@ -15,6 +15,6 @@ $ docker run --name some-ubuntu -it ubuntu:18.04
root@523c70904d54:/#
```
-### Dockerfile
+## Dockerfile
请到 https://github.com/docker-library/docs/tree/master/ubuntu 查看。
diff --git a/appendix/repo/wordpress.md b/appendix/repo/wordpress.md
index b6cace1..2e571c4 100644
--- a/appendix/repo/wordpress.md
+++ b/appendix/repo/wordpress.md
@@ -1,12 +1,12 @@
-## [WordPress](https://hub.docker.com/_/wordpress/)
+# [WordPress](https://hub.docker.com/_/wordpress/)
-### 基本信息
+## 基本信息
[WordPress](https://en.wikipedia.org/wiki/WordPress) 是开源的 Blog 和内容管理系统框架,它基于 PHP 和 MySQL。
该仓库位于 `https://hub.docker.com/_/wordpress/` ,提供了 WordPress 4.x ~ 5.x 版本的镜像。
-### 使用方法
+## 使用方法
启动容器需要 MySQL 的支持,默认端口为 `80`。
@@ -20,6 +20,6 @@ $ docker run --name some-wordpress --link some-mysql:mysql -d wordpress
* `WORDPRESS_DB_PASSWORD` 缺省为连接 mysql 容器的环境变量 `MYSQL_ROOT_PASSWORD` 的值
* `WORDPRESS_DB_NAME` 缺省为 `wordpress`
-### Dockerfile
+## Dockerfile
请到 https://github.com/docker-library/docs/tree/master/wordpress 查看。
diff --git a/cases/os/centos.md b/cases/os/centos.md
index 10ed744..b331e04 100644
--- a/cases/os/centos.md
+++ b/cases/os/centos.md
@@ -1,6 +1,6 @@
-## CentOS/Fedora
+# CentOS/Fedora
-### CentOS 系统简介
+## CentOS 系统简介
`CentOS` 和 `Fedora` 都是基于 `Redhat` 的常见 Linux 分支。`CentOS` 是目前企业级服务器的常用操作系统;`Fedora` 则主要面向个人桌面用户。
@@ -8,7 +8,7 @@
CentOS(Community Enterprise Operating System,中文意思是:社区企业操作系统),它是基于 `Red Hat Enterprise Linux` 源代码编译而成。由于 `CentOS` 与 `Redhat Linux` 源于相同的代码基础,所以很多成本敏感且需要高稳定性的公司就使用 `CentOS` 来替代商业版 `Red Hat Enterprise Linux`。`CentOS` 自身不包含闭源软件。
-#### 使用 CentOS 官方镜像
+### 使用 CentOS 官方镜像
首先使用 `docker search` 命令来搜索标星至少为 `25` 的 `CentOS` 相关镜像。
@@ -32,13 +32,13 @@ Status: Downloaded newer image for centos:latest
CentOS Linux release 7.2.1511 (Core)
```
-### Fedora 系统简介
+## Fedora 系统简介

`Fedora` 由 `Fedora Project` 社区开发,红帽公司赞助的 `Linux` 发行版。它的目标是创建一套新颖、多功能并且自由和开源的操作系统。`Fedora` 的功能对于用户而言,它是一套功能完备的,可以更新的免费操作系统,而对赞助商 `Red Hat` 而言,它是许多新技术的测试平台。被认为可用的技术最终会加入到 `Red Hat Enterprise Linux` 中。
-#### 使用 Fedora 官方镜像
+### 使用 Fedora 官方镜像
首先使用 `docker search` 命令来搜索标星至少为 `2` 的 `Fedora` 相关镜像,结果如下。
@@ -64,7 +64,7 @@ Status: Downloaded newer image for fedora:latest
Fedora release 24 (Twenty Four)
```
-### 相关资源
+## 相关资源
* `Fedora` 官网:https://getfedora.org/
* `Fedora` 官方仓库:https://github.com/fedora-infra
diff --git a/container/attach_exec.md b/container/attach_exec.md
index 0feb134..3c342cd 100644
--- a/container/attach_exec.md
+++ b/container/attach_exec.md
@@ -1,10 +1,10 @@
-## 进入容器
+# 进入容器
在使用 `-d` 参数时,容器启动后会进入后台。
某些时候需要进入容器进行操作,包括使用 `docker attach` 命令或 `docker exec` 命令,推荐大家使用 `docker exec` 命令,原因会在下面说明。
-### `attach` 命令
+## `attach` 命令
下面示例如何使用 `docker attach` 命令。
@@ -22,9 +22,9 @@ root@243c32535da7:/#
*注意:* 如果从这个 stdin 中 exit,会导致容器的停止。
-### `exec` 命令
+## `exec` 命令
-#### -i -t 参数
+### -i -t 参数
`docker exec` 后边可以跟多个参数,这里主要说明 `-i` `-t` 参数。
diff --git a/container/daemon.md b/container/daemon.md
index 5175c35..37840af 100644
--- a/container/daemon.md
+++ b/container/daemon.md
@@ -1,4 +1,4 @@
-## 后台运行
+# 后台运行
更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 `-d` 参数来实现。
diff --git a/container/import_export.md b/container/import_export.md
index c2a76a2..7f88763 100644
--- a/container/import_export.md
+++ b/container/import_export.md
@@ -1,6 +1,6 @@
-## 导出和导入容器
+# 导出和导入容器
-### 导出容器
+## 导出容器
如果要导出本地某个容器,可以使用 `docker export` 命令。
```bash
@@ -12,7 +12,7 @@ $ docker export 7691a814370e > ubuntu.tar
这样将导出容器快照到本地文件。
-### 导入容器快照
+## 导入容器快照
可以使用 `docker import` 从容器快照文件中再导入为镜像,例如
diff --git a/container/rm.md b/container/rm.md
index 4de8504..5fce0fe 100644
--- a/container/rm.md
+++ b/container/rm.md
@@ -1,4 +1,4 @@
-## 删除容器
+# 删除容器
可以使用 `docker container rm` 来删除一个处于终止状态的容器。例如
@@ -9,7 +9,7 @@ trusting_newton
如果要删除一个运行中的容器,可以添加 `-f` 参数。Docker 会发送 `SIGKILL` 信号给容器。
-## 清理所有处于终止状态的容器
+# 清理所有处于终止状态的容器
用 `docker container ls -a` 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。
diff --git a/container/run.md b/container/run.md
index 9dfd596..a58697e 100644
--- a/container/run.md
+++ b/container/run.md
@@ -1,10 +1,10 @@
-## 启动容器
+# 启动容器
启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(`stopped`)的容器重新启动。
因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。
-### 新建并启动
+## 新建并启动
所需要的命令主要为 `docker run`。
@@ -45,7 +45,7 @@ bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr
* 执行用户指定的应用程序
* 执行完毕后容器被终止
-### 启动已终止容器
+## 启动已终止容器
可以利用 `docker container start` 命令,直接将一个已经终止的容器启动运行。
diff --git a/container/stop.md b/container/stop.md
index 31853a5..77dd732 100644
--- a/container/stop.md
+++ b/container/stop.md
@@ -1,4 +1,4 @@
-## 终止容器
+# 终止容器
可以使用 `docker container stop` 来终止一个运行中的容器。
diff --git a/data_management/bind-mounts.md b/data_management/bind-mounts.md
index 6d0bef7..8c9ac30 100644
--- a/data_management/bind-mounts.md
+++ b/data_management/bind-mounts.md
@@ -1,6 +1,6 @@
-## 挂载主机目录
+# 挂载主机目录
-### 挂载一个主机目录作为数据卷
+## 挂载一个主机目录作为数据卷
使用 `--mount` 标记可以指定挂载一个本地主机的目录到容器中去。
@@ -33,7 +33,7 @@ $ docker run -d -P \
touch: new.txt: Read-only file system
```
-### 查看数据卷的具体信息
+## 查看数据卷的具体信息
在主机里使用以下命令可以查看 `web` 容器的信息
@@ -56,7 +56,7 @@ $ docker inspect web
],
```
-### 挂载一个本地主机文件作为数据卷
+## 挂载一个本地主机文件作为数据卷
`--mount` 标记也可以从主机挂载单个文件到容器中
diff --git a/data_management/volume.md b/data_management/volume.md
index b96b624..5fc3193 100644
--- a/data_management/volume.md
+++ b/data_management/volume.md
@@ -1,4 +1,4 @@
-## 数据卷
+# 数据卷
`数据卷` 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
@@ -12,7 +12,7 @@
>注意:`数据卷` 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的 `数据卷`。
-### 创建一个数据卷
+## 创建一个数据卷
```bash
$ docker volume create my-vol
@@ -42,7 +42,7 @@ $ docker volume inspect my-vol
]
```
-### 启动一个挂载数据卷的容器
+## 启动一个挂载数据卷的容器
在用 `docker run` 命令的时候,使用 `--mount` 标记来将 `数据卷` 挂载到容器里。在一次 `docker run` 中可以挂载多个 `数据卷`。
@@ -57,7 +57,7 @@ $ docker run -d -P \
python app.py
```
-### 查看数据卷的具体信息
+## 查看数据卷的具体信息
在主机里使用以下命令可以查看 `web` 容器的信息
@@ -82,7 +82,7 @@ $ docker inspect web
],
```
-### 删除数据卷
+## 删除数据卷
```bash
$ docker volume rm my-vol
diff --git a/etcd/cluster.md b/etcd/cluster.md
index dc39d33..305e78e 100644
--- a/etcd/cluster.md
+++ b/etcd/cluster.md
@@ -1,4 +1,4 @@
-## etcd 集群
+# etcd 集群
下面我们使用 [Docker Compose](../compose/) 模拟启动一个 3 节点的 `etcd` 集群。
diff --git a/etcd/etcdctl-v2.md b/etcd/etcdctl-v2.md
index 6e66a9f..d37e4ce 100644
--- a/etcd/etcdctl-v2.md
+++ b/etcd/etcdctl-v2.md
@@ -1,4 +1,4 @@
-## 使用 etcdctl v2
+# 使用 etcdctl v2
`etcdctl` 是一个命令行客户端,它能提供一些简洁的命令,供用户直接跟 `etcd` 服务打交道,而无需基于 `HTTP API` 方式。这在某些情况下将很方便,例如用户对服务进行测试或者手动修改数据库内容。我们也推荐在刚接触 `etcd` 时通过 `etcdctl` 命令来熟悉相关的操作,这些操作跟 `HTTP API` 实际上是对应的。
@@ -46,14 +46,14 @@ GLOBAL OPTIONS:
--version, -v print the version
```
-### 数据库操作
+## 数据库操作
数据库操作围绕对键值和目录的 CRUD (符合 REST 风格的一套操作:Create)完整生命周期的管理。
etcd 在键的组织上采用了层次化的空间结构(类似于文件系统中目录的概念),用户指定的键可以为单独的名字,如 `testkey`,此时实际上放在根目录 `/` 下面,也可以为指定目录结构,如 `cluster1/node2/testkey`,则将创建相应的目录结构。
*注:CRUD 即 Create, Read, Update, Delete,是符合 REST 风格的一套 API 操作。*
-#### set
+### set
指定某个键的值。例如
```bash
$ etcdctl set /testdir/testkey "Hello world"
@@ -66,7 +66,7 @@ Hello world
--swap-with-index '0' 若该键现在的索引值是指定索引,则进行设置操作
```
-#### get
+### get
获取指定键的值。例如
```bash
$ etcdctl set testkey hello
@@ -87,7 +87,7 @@ Error: 100: Key not found (/testkey2) [1]
--consistent 将请求发给主节点,保证获取内容的一致性
```
-#### update
+### update
当键存在时,更新值内容。例如
```bash
$ etcdctl set testkey hello
@@ -107,7 +107,7 @@ Error: 100: Key not found (/testkey2) [1]
--ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时
```
-#### rm
+### rm
删除某个键值。例如
```bash
$ etcdctl rm testkey
@@ -127,7 +127,7 @@ Error: 100: Key not found (/testkey2) [8]
--with-index '0' 检查现有的 index 是否匹配
```
-#### mk
+### mk
如果给定的键不存在,则创建一个新的键值。例如
```bash
$ etcdctl mk /testdir/testkey "Hello world"
@@ -146,7 +146,7 @@ Error: 105: Key already exists (/testkey) [2]
--ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时
```
-#### mkdir
+### mkdir
如果给定的键目录不存在,则创建一个新的键目录。例如
```bash
$ etcdctl mkdir testdir
@@ -162,7 +162,7 @@ Error: 105: Key already exists (/testdir) [7]
--ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时
```
-#### setdir
+### setdir
创建一个键目录,无论存在与否。
@@ -171,14 +171,14 @@ Error: 105: Key already exists (/testdir) [7]
--ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时
```
-#### updatedir
+### updatedir
更新一个已经存在的目录。
支持的选项为
```bash
--ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时
```
-#### rmdir
+### rmdir
删除一个空目录,或者键值对。
若目录不空,会报错
@@ -189,7 +189,7 @@ $ etcdctl rmdir /dir
Error: 108: Directory not empty (/dir) [13]
```
-#### ls
+### ls
列出目录(默认为根目录)下的键或者子目录,默认不显示子目录中内容。
例如
@@ -212,9 +212,9 @@ $ ./etcdctl ls dir
-p 对于输出为目录,在最后添加 `/` 进行区分
```
-### 非数据库操作
+## 非数据库操作
-#### backup
+### backup
备份 etcd 的数据。
支持的选项包括
@@ -222,7 +222,7 @@ $ ./etcdctl ls dir
--data-dir etcd 的数据目录
--backup-dir 备份到指定路径
```
-#### watch
+### watch
监测一个键值的变化,一旦键值发生更新,就会输出最新的值并退出。
例如,用户更新 testkey 键值为 Hello world。
@@ -237,7 +237,7 @@ Hello world
--after-index '0' 在指定 index 之前一直监测
--recursive 返回所有的键值和子键值
```
-#### exec-watch
+### exec-watch
监测一个键值的变化,一旦键值发生更新,就执行给定命令。
例如,用户更新 testkey 键值。
@@ -258,7 +258,7 @@ README.md
--recursive 返回所有的键值和子键值
```
-#### member
+### member
通过 list、add、remove 命令列出、添加、删除 etcd 实例到 etcd 集群中。
@@ -269,7 +269,7 @@ $ etcdctl member list
ce2a822cea30bfca: name=default peerURLs=http://localhost:2380,http://localhost:7001 clientURLs=http://localhost:2379,http://localhost:4001
```
-### 命令选项
+## 命令选项
* `--debug` 输出 cURL 命令,显示执行命令的时候发起的请求
* `--no-sync` 发出请求之前不同步集群信息
* `--output, -o 'simple'` 输出内容的格式 (`simple` 为原始信息,`json` 为进行json格式解码,易读性好一些)
diff --git a/etcd/etcdctl.md b/etcd/etcdctl.md
index e9d398a..29c0f0d 100644
--- a/etcd/etcdctl.md
+++ b/etcd/etcdctl.md
@@ -1,4 +1,4 @@
-## 使用 etcdctl
+# 使用 etcdctl
`etcdctl` 是一个命令行客户端,它能提供一些简洁的命令,供用户直接跟 `etcd` 服务打交道,而无需基于 `HTTP API` 方式。这在某些情况下将很方便,例如用户对服务进行测试或者手动修改数据库内容。我们也推荐在刚接触 `etcd` 时通过 `etcdctl` 命令来熟悉相关的操作,这些操作跟 `HTTP API` 实际上是对应的。
@@ -81,7 +81,7 @@ OPTIONS:
-w, --write-out="simple" set the output format (fields, json, protobuf, simple, table)
```
-### 数据库操作
+## 数据库操作
数据库操作围绕对键值和目录的 CRUD (符合 REST 风格的一套操作:Create)完整生命周期的管理。
@@ -89,14 +89,14 @@ etcd 在键的组织上采用了层次化的空间结构(类似于文件系统
>注:CRUD 即 Create, Read, Update, Delete,是符合 REST 风格的一套 API 操作。
-#### put
+### put
```bash
$ etcdctl put /testdir/testkey "Hello world"
OK
```
-#### get
+### get
获取指定键的值。例如
@@ -114,7 +114,7 @@ hello
`--consistent` 将请求发给主节点,保证获取内容的一致性
-#### del
+### del
删除某个键值。例如
@@ -123,9 +123,9 @@ $ etcdctl del testkey
1
```
-### 非数据库操作
+## 非数据库操作
-#### watch
+### watch
监测一个键值的变化,一旦键值发生更新,就会输出最新的值。
@@ -138,7 +138,7 @@ testkey
2
```
-#### member
+### member
通过 `list`、`add`、`update`、`remove` 命令列出、添加、更新、删除 etcd 实例到 etcd 集群中。
diff --git a/etcd/install.md b/etcd/install.md
index 472865d..d188f5e 100644
--- a/etcd/install.md
+++ b/etcd/install.md
@@ -1,10 +1,10 @@
-## 安装
+# 安装
`etcd` 基于 `Go` 语言实现,因此,用户可以从 [项目主页](https://github.com/etcd-io/etcd) 下载源代码自行编译,也可以下载编译好的二进制文件,甚至直接使用制作好的 `Docker` 镜像文件来体验。
>注意:本章节内容基于 etcd `3.4.x` 版本
-### 二进制文件方式下载
+## 二进制文件方式下载
编译好的二进制文件都在 [github.com/etcd-io/etcd/releases](https://github.com/etcd-io/etcd/releases/) 页面,用户可以选择需要的版本,或通过下载工具下载。
@@ -56,7 +56,7 @@ hello world
说明 etcd 服务已经成功启动了。
-### Docker 镜像方式运行
+## Docker 镜像方式运行
镜像名称为 `quay.io/coreos/etcd`,可以通过下面的命令启动 `etcd` 服务监听到 `2379` 和 `2380` 端口。
@@ -84,7 +84,7 @@ quay.io/coreos/etcd:v3.4.0 \
打开新的终端按照上一步的方法测试 `etcd` 是否成功启动。
-### macOS 中运行
+## macOS 中运行
```bash
$ brew install etcd
diff --git a/etcd/intro.md b/etcd/intro.md
index 1862091..19f98b1 100644
--- a/etcd/intro.md
+++ b/etcd/intro.md
@@ -1,4 +1,4 @@
-## 什么是 etcd
+# 什么是 etcd

diff --git a/image/build.md b/image/build.md
index 135207d..6fde477 100644
--- a/image/build.md
+++ b/image/build.md
@@ -1,4 +1,4 @@
-## 使用 Dockerfile 定制镜像
+# 使用 Dockerfile 定制镜像
从刚才的 `docker commit` 的学习中,我们可以了解到,镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
@@ -23,7 +23,7 @@ RUN echo '
Hello, Docker!
' > /usr/share/nginx/html/index.html
这个 Dockerfile 很简单,一共就两行。涉及到了两条指令,`FROM` 和 `RUN`。
-### FROM 指定基础镜像
+## FROM 指定基础镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 `nginx` 镜像的容器,再进行修改一样,基础镜像是必须指定的。而 `FROM` 就是指定 **基础镜像**,因此一个 `Dockerfile` 中 `FROM` 是必备的指令,并且必须是第一条指令。
@@ -42,7 +42,7 @@ FROM scratch
不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如 [`swarm`](https://hub.docker.com/_/swarm/)、[`etcd`](https://quay.io/repository/coreos/etcd)。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 `FROM scratch` 会让镜像体积更加小巧。使用 [Go 语言](https://golang.org/) 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。
-### RUN 执行命令
+## RUN 执行命令
`RUN` 指令是用来执行命令行命令的。由于命令行的强大能力,`RUN` 指令在定制镜像时是最常用的指令之一。其格式有两种:
@@ -102,7 +102,7 @@ RUN buildDeps='gcc libc6-dev make wget' \
很多人初学 Docker 制作出了很臃肿的镜像的原因之一,就是忘记了每一层构建的最后一定要清理掉无关文件。
-### 构建镜像
+## 构建镜像
好了,让我们再回到之前定制的 nginx 镜像的 Dockerfile 来。现在我们明白了这个 Dockerfile 的内容,那么让我们来构建这个镜像吧。
@@ -130,7 +130,7 @@ docker build [选项] <上下文路径/URL/->
在这里我们指定了最终镜像的名称 `-t nginx:v3`,构建成功后,我们可以像之前运行 `nginx:v2` 那样来运行这个镜像,其结果会和 `nginx:v2` 一样。
-### 镜像构建上下文(Context)
+## 镜像构建上下文(Context)
如果注意,会看到 `docker build` 命令最后有一个 `.`。`.` 表示当前目录,而 `Dockerfile` 就在当前目录,因此不少初学者以为这个路径是在指定 `Dockerfile` 所在路径,这么理解其实是不准确的。如果对应上面的命令格式,你可能会发现,这是在指定 **上下文路径**。那么什么是上下文呢?
@@ -170,9 +170,9 @@ Sending build context to Docker daemon 2.048 kB
当然,一般大家习惯性的会使用默认的文件名 `Dockerfile`,以及会将其置于镜像构建上下文目录中。
-### 其它 `docker build` 的用法
+## 其它 `docker build` 的用法
-#### 直接用 Git repo 进行构建
+### 直接用 Git repo 进行构建
或许你已经注意到了,`docker build` 还支持从 URL 构建,比如可以直接从 Git repo 中构建:
@@ -189,7 +189,7 @@ aed15891ba52: Already exists
这行命令指定了构建所需的 Git repo,并且指定默认的 `master` 分支,构建目录为 `/11.1/`,然后 Docker 就会自己去 `git clone` 这个项目、切换到指定分支、并进入到指定目录后开始构建。
-#### 用给定的 tar 压缩包构建
+### 用给定的 tar 压缩包构建
```bash
$ docker build http://server/context.tar.gz
@@ -197,7 +197,7 @@ $ docker build http://server/context.tar.gz
如果所给出的 URL 不是个 Git repo,而是个 `tar` 压缩包,那么 Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。
-#### 从标准输入中读取 Dockerfile 进行构建
+### 从标准输入中读取 Dockerfile 进行构建
```bash
docker build - < Dockerfile
@@ -211,7 +211,7 @@ cat Dockerfile | docker build -
如果标准输入传入的是文本文件,则将其视为 `Dockerfile`,并开始构建。这种形式由于直接从标准输入中读取 Dockerfile 的内容,它没有上下文,因此不可以像其他方法那样可以将本地文件 `COPY` 进镜像之类的事情。
-#### 从标准输入中读取上下文压缩包进行构建
+### 从标准输入中读取上下文压缩包进行构建
```bash
$ docker build - < context.tar.gz
diff --git a/image/commit.md b/image/commit.md
index 6f921e5..01ca002 100644
--- a/image/commit.md
+++ b/image/commit.md
@@ -1,8 +1,7 @@
+# 利用 commit 理解镜像构成
>注意:如果您是初学者,您可以暂时跳过后面的内容,直接学习 [容器](../container) 一节。
-## 利用 commit 理解镜像构成
-
注意: `docker commit` 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现场等。但是,不要使用 `docker commit` 定制镜像,定制镜像应该使用 `Dockerfile` 来完成。如果你想要定制镜像请查看下一小节。
镜像是容器的基础,每次执行 `docker run` 的时候都会指定哪个镜像作为容器运行的基础。在之前的例子中,我们所使用的都是来自于 Docker Hub 的镜像。直接使用这些镜像是可以满足一定的需求,而当这些镜像无法直接满足需求时,我们就需要定制这些镜像。接下来的几节就将讲解如何定制镜像。
@@ -120,7 +119,7 @@ docker run --name web2 -d -p 81:80 nginx:v2
至此,我们第一次完成了定制镜像,使用的是 `docker commit` 命令,手动操作给旧的镜像添加了新的一层,形成新的镜像,对镜像多层存储应该有了更直观的感觉。
-### 慎用 `docker commit`
+## 慎用 `docker commit`
使用 `docker commit` 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用。
diff --git a/image/dockerfile/README.md b/image/dockerfile/README.md
index fa4d01f..15f5d4f 100644
--- a/image/dockerfile/README.md
+++ b/image/dockerfile/README.md
@@ -1,3 +1,3 @@
-## Dockerfile 指令详解
+# Dockerfile 指令详解
我们已经介绍了 `FROM`,`RUN`,还提及了 `COPY`, `ADD`,其实 `Dockerfile` 功能很强大,它提供了十多个指令。下面我们继续讲解其他的指令。
diff --git a/image/internal.md b/image/internal.md
index 8cb7ccf..f22123b 100644
--- a/image/internal.md
+++ b/image/internal.md
@@ -1,4 +1,4 @@
-## 镜像的实现原理
+# 镜像的实现原理
Docker 镜像是怎么实现增量的修改和维护的?
diff --git a/image/list.md b/image/list.md
index d3f60b2..107c36d 100644
--- a/image/list.md
+++ b/image/list.md
@@ -1,4 +1,4 @@
-## 列出镜像
+# 列出镜像
要想列出已经下载下来的镜像,可以使用 `docker image ls` 命令。
@@ -17,7 +17,7 @@ ubuntu latest f753707788c5 4 weeks ago
其中仓库名、标签在之前的基础概念章节已经介绍过了。**镜像 ID** 则是镜像的唯一标识,一个镜像可以对应多个 **标签**。因此,在上面的例子中,我们可以看到 `ubuntu:18.04` 和 `ubuntu:latest` 拥有相同的 ID,因为它们对应的是同一个镜像。
-### 镜像体积
+## 镜像体积
如果仔细观察,会注意到,这里标识的所占用空间和在 Docker Hub 上看到的镜像大小不同。比如,`ubuntu:18.04` 镜像大小,在这里是 `127 MB`,但是在 [Docker Hub](https://hub.docker.com/r/library/ubuntu/tags/) 显示的却是 `50 MB`。这是因为 Docker Hub 中显示的体积是压缩后的体积。在镜像下载和上传过程中镜像是保持着压缩状态的,因此 Docker Hub 所显示的大小是网络传输中更关心的流量大小。而 `docker image ls` 显示的是镜像下载到本地后,展开的大小,准确说,是展开后的各层所占空间的总和,因为镜像到本地后,查看空间的时候,更关心的是本地磁盘空间占用的大小。
@@ -35,7 +35,7 @@ Local Volumes 9 0 652.2MB
Build Cache 0B 0B
```
-### 虚悬镜像
+## 虚悬镜像
上面的镜像列表中,还可以看到一个特殊的镜像,这个镜像既没有仓库名,也没有标签,均为 ``。:
@@ -57,7 +57,7 @@ REPOSITORY TAG IMAGE ID CREATED
$ docker image prune
```
-### 中间层镜像
+## 中间层镜像
为了加速镜像构建、重复利用资源,Docker 会利用 **中间层镜像**。所以在使用一段时间后,可能会看到一些依赖的中间层镜像。默认的 `docker image ls` 列表中只会显示顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加 `-a` 参数。
@@ -67,7 +67,7 @@ $ docker image ls -a
这样会看到很多无标签的镜像,与之前的虚悬镜像不同,这些无标签的镜像很多都是中间层镜像,是其它镜像所依赖的镜像。这些无标签镜像不应该删除,否则会导致上层镜像因为依赖丢失而出错。实际上,这些镜像也没必要删除,因为之前说过,相同的层只会存一遍,而这些镜像是别的镜像的依赖,因此并不会因为它们被列出来而多存了一份,无论如何你也会需要它们。只要删除那些依赖它们的镜像后,这些依赖的中间层镜像也会被连带删除。
-### 列出部分镜像
+## 列出部分镜像
不加任何参数的情况下,`docker image ls` 会列出所有顶层镜像,但是有时候我们只希望列出部分镜像。`docker image ls` 有好几个参数可以帮助做到这个事情。
@@ -106,7 +106,7 @@ $ docker image ls -f label=com.example.version=0.1
...
```
-### 以特定格式显示
+## 以特定格式显示
默认情况下,`docker image ls` 会输出一个完整的表格,但是我们并非所有时候都会需要这些内容。比如,刚才删除虚悬镜像的时候,我们需要利用 `docker image ls` 把所有的虚悬镜像的 ID 列出来,然后才可以交给 `docker image rm` 命令作为参数来删除指定的这些镜像,这个时候就用到了 `-q` 参数。
diff --git a/image/manifest.md b/image/manifest.md
index 3783303..78dd128 100644
--- a/image/manifest.md
+++ b/image/manifest.md
@@ -1,4 +1,4 @@
-## 构建多种系统架构支持的 Docker 镜像 -- docker manifest 命令详解
+# 构建多种系统架构支持的 Docker 镜像 -- docker manifest 命令详解
我们知道使用镜像创建一个容器,该镜像必须与 Docker 宿主机系统架构一致,例如 `Linux x86_64` 架构的系统中只能使用 `Linux x86_64` 的镜像创建容器。
@@ -109,11 +109,11 @@ $ docker manifest inspect golang:alpine
下面介绍如何使用 `$ docker manifest` 命令创建并推送 `manifest` 列表到 Docker Hub。
-### 构建镜像
+## 构建镜像
首先在 `Linux x86_64` 构建 `username/x8664-test` 镜像。并在 `Linux arm64v8` 中构建 `username/arm64v8-test` 镜像,构建好之后推送到 Docker Hub。
-### 创建 `manifest` 列表
+## 创建 `manifest` 列表
```bash
# $ docker manifest create MANIFEST_LIST MANIFEST [MANIFEST...]
@@ -124,7 +124,7 @@ $ docker manifest create username/test \
当要修改一个 `manifest` 列表时,可以加入 `-a,--amend` 参数。
-### 设置 `manifest` 列表
+## 设置 `manifest` 列表
```bash
# $ docker manifest annotate [OPTIONS] MANIFEST_LIST MANIFEST
@@ -139,13 +139,13 @@ $ docker manifest annotate username/test \
这样就配置好了 `manifest` 列表。
-### 查看 `manifest` 列表
+## 查看 `manifest` 列表
```bash
$ docker manifest inspect username/test
```
-### 推送 `manifest` 列表
+## 推送 `manifest` 列表
最后我们可以将其推送到 Docker Hub。
@@ -153,11 +153,11 @@ $ docker manifest inspect username/test
$ docker manifest push username/test
```
-### 测试
+## 测试
我们在 `Linux x86_64` `Linux arm64v8` 中分别执行 `$ docker run -it --rm username/test` 命令,发现可以正确的执行。
-### 官方博客
+## 官方博客
详细了解 `manifest` 可以阅读官方博客。
diff --git a/image/multistage-builds/README.md b/image/multistage-builds/README.md
index 97a6161..f924cd2 100644
--- a/image/multistage-builds/README.md
+++ b/image/multistage-builds/README.md
@@ -1,10 +1,10 @@
-## 多阶段构建
+# 多阶段构建
-### 之前的做法
+## 之前的做法
在 Docker 17.05 版本之前,我们构建 Docker 镜像时,通常会采用两种方式:
-#### 全部放入一个 Dockerfile
+### 全部放入一个 Dockerfile
一种方式是将所有的构建过程编包含在一个 `Dockerfile` 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题:
@@ -50,7 +50,7 @@ CMD ["./app"]
$ docker build -t go/helloworld:1 -f Dockerfile.one .
```
-#### 分散到多个 Dockerfile
+### 分散到多个 Dockerfile
另一种方式,就是我们事先在一个 `Dockerfile` 将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 `Dockerfile` 和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。
@@ -119,7 +119,7 @@ go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB
go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
```
-### 使用多阶段构建
+## 使用多阶段构建
为解决以上问题,Docker v17.05 开始支持多阶段构建 (`multistage builds`)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 `Dockerfile`:
@@ -168,7 +168,7 @@ go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。
-#### 只构建某一阶段的镜像
+### 只构建某一阶段的镜像
我们可以使用 `as` 来为某一阶段命名,例如
@@ -182,7 +182,7 @@ FROM golang:1.9-alpine as builder
$ docker build --target builder -t username/imagename:tag .
```
-#### 构建时从其他镜像复制文件
+### 构建时从其他镜像复制文件
上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件,我们也可以复制任意镜像中的文件。
diff --git a/image/multistage-builds/laravel.md b/image/multistage-builds/laravel.md
index 5d7a44b..da14fdb 100644
--- a/image/multistage-builds/laravel.md
+++ b/image/multistage-builds/laravel.md
@@ -1,8 +1,8 @@
-## 实战多阶段构建 Laravel 镜像
+# 实战多阶段构建 Laravel 镜像
> 本节适用于 PHP 开发者阅读。
-### 准备
+## 准备
新建一个 `Laravel` 项目或在已有的 `Laravel` 项目根目录下新建 `Dockerfile` `.dockerignore` `laravel.conf` 文件。
@@ -46,7 +46,7 @@ server {
}
```
-### 前端构建
+## 前端构建
第一阶段进行前端构建。
@@ -65,7 +65,7 @@ RUN cd /app \
&& npm run production
```
-### 安装 Composer 依赖
+## 安装 Composer 依赖
第二阶段安装 Composer 依赖。
@@ -85,7 +85,7 @@ RUN cd /app \
--prefer-dist
```
-### 整合以上阶段所生成的文件
+## 整合以上阶段所生成的文件
第三阶段对以上阶段生成的文件进行整合。
@@ -111,7 +111,7 @@ RUN cd ${LARAVEL_PATH} \
&& chmod -R 777 storage
```
-### 最后一个阶段构建 NGINX 镜像
+## 最后一个阶段构建 NGINX 镜像
```docker
FROM nginx:alpine as nginx
@@ -122,7 +122,7 @@ COPY laravel.conf /etc/nginx/conf.d/
COPY --from=laravel ${LARAVEL_PATH}/public ${LARAVEL_PATH}/public
```
-### 构建 Laravel 及 Nginx 镜像
+## 构建 Laravel 及 Nginx 镜像
使用 `docker build` 命令构建镜像。
@@ -132,7 +132,7 @@ $ docker build -t my/laravel --target=laravel .
$ docker build -t my/nginx --target=nginx .
```
-### 启动容器并测试
+## 启动容器并测试
新建 Docker 网络
@@ -156,11 +156,11 @@ $ docker run -it --rm --network=laravel -p 8080:80 my/nginx
> 也许 Laravel 项目依赖其他外部服务,例如 redis、MySQL,请自行启动这些服务之后再进行测试,本小节不再赘述。
-### 生产环境优化
+## 生产环境优化
本小节内容为了方便测试,将配置文件直接放到了镜像中,实际在使用时 **建议** 将配置文件作为 `config` 或 `secret` 挂载到容器中,请读者自行学习 `Swarm mode` 或 `Kubernetes` 的相关内容。
-### 附录
+## 附录
完整的 `Dockerfile` 文件如下。
diff --git a/image/other.md b/image/other.md
index 8a94147..4d4dd13 100644
--- a/image/other.md
+++ b/image/other.md
@@ -1,8 +1,8 @@
-## 其它制作镜像的方式
+# 其它制作镜像的方式
除了标准的使用 `Dockerfile` 生成镜像的方法外,由于各种特殊需求和历史原因,还提供了一些其它方法用以生成镜像。
-### 从 rootfs 压缩包导入
+## 从 rootfs 压缩包导入
格式:`docker import [选项] <文件>||- [<仓库名>[:<标签>]]`
@@ -37,11 +37,11 @@ IMAGE CREATED CREATED BY SIZE
f477a6e18e98 About a minute ago 214.9 MB Imported from http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz
```
-### `docker save` 和 `docker load`
+## `docker save` 和 `docker load`
Docker 还提供了 `docker save` 和 `docker load` 命令,用以将镜像保存为一个文件,然后传输到另一个位置上,再加载进来。这是在没有 Docker Registry 时的做法,现在已经不推荐,镜像迁移应该直接使用 Docker Registry,无论是直接使用 Docker Hub 还是使用内网私有 Registry 都可以。
-#### 保存镜像
+### 保存镜像
使用 `docker save` 命令可以将镜像保存为归档文件。
diff --git a/image/pull.md b/image/pull.md
index 7733f70..51c47c9 100644
--- a/image/pull.md
+++ b/image/pull.md
@@ -1,4 +1,4 @@
-## 获取镜像
+# 获取镜像
之前提到过,[Docker Hub](https://hub.docker.com/explore/) 上有大量的高质量的镜像可以用,这里我们就说一下怎么获取这些镜像。
@@ -35,7 +35,7 @@ Status: Downloaded newer image for ubuntu:18.04
*如果从 Docker Hub 下载镜像非常缓慢,可以参照 [镜像加速器](/install/mirror.md) 一节配置加速器。*
-### 运行
+## 运行
有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 `ubuntu:18.04` 为例,如果我们打算启动里面的 `bash` 并且进行交互式操作的话,可以执行下面的命令。
diff --git a/image/rm.md b/image/rm.md
index d0870be..07b0f19 100644
--- a/image/rm.md
+++ b/image/rm.md
@@ -1,4 +1,4 @@
-## 删除本地镜像
+# 删除本地镜像
如果要删除本地的镜像,可以使用 `docker image rm` 命令,其格式为:
@@ -6,7 +6,7 @@
$ docker image rm [选项] <镜像1> [<镜像2> ...]
```
-### 用 ID、镜像名、摘要删除镜像
+## 用 ID、镜像名、摘要删除镜像
其中,`<镜像>` 可以是 `镜像短 ID`、`镜像长 ID`、`镜像名` 或者 `镜像摘要`。
@@ -58,7 +58,7 @@ $ docker image rm node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235
Untagged: node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
```
-### Untagged 和 Deleted
+## Untagged 和 Deleted
如果观察上面这几个命令的运行输出信息的话,你会注意到删除行为分为两类,一类是 `Untagged`,另一类是 `Deleted`。我们之前介绍过,镜像的唯一标识是其 ID 和摘要,而一个镜像可以有多个标签。
@@ -68,7 +68,7 @@ Untagged: node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b16442
除了镜像依赖以外,还需要注意的是容器对镜像的依赖。如果有用这个镜像启动的容器存在(即使容器没有运行),那么同样不可以删除这个镜像。之前讲过,容器是以镜像为基础,再加一层容器存储层,组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的,那么删除必然会导致故障。如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像。
-### 用 docker image ls 命令来配合
+## 用 docker image ls 命令来配合
像其它可以承接多个实体的命令一样,可以使用 `docker image ls -q` 来配合使用 `docker image rm`,这样可以成批的删除希望删除的镜像。我们在“镜像列表”章节介绍过很多过滤镜像列表的方式都可以拿过来使用。
@@ -86,7 +86,7 @@ $ docker image rm $(docker image ls -q -f before=mongo:3.2)
充分利用你的想象力和 Linux 命令行的强大,你可以完成很多非常赞的功能。
-### CentOS/RHEL 的用户需要注意的事项
+## CentOS/RHEL 的用户需要注意的事项
> 以下内容仅适用于 Docker CE 18.09 以下版本,在 Docker CE 18.09 版本中默认使用的是 `overlay2` 驱动。
diff --git a/network/dns.md b/network/dns.md
index a84f90e..f13bbb7 100644
--- a/network/dns.md
+++ b/network/dns.md
@@ -1,4 +1,4 @@
-## 配置 DNS
+# 配置 DNS
如何自定义配置容器的主机名和 DNS 呢?秘诀就是 Docker 利用虚拟文件来挂载容器的 3 个相关配置文件。
diff --git a/network/linking.md b/network/linking.md
index a4319a5..e24ebd9 100644
--- a/network/linking.md
+++ b/network/linking.md
@@ -1,10 +1,10 @@
-## 容器互联
+# 容器互联
如果你之前有 `Docker` 使用经验,你可能已经习惯了使用 `--link` 参数来使容器互联。
随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 `--link` 参数。
-### 新建网络
+## 新建网络
下面先创建一个新的 Docker 网络。
@@ -14,7 +14,7 @@ $ docker network create -d bridge my-net
`-d` 参数指定 Docker 网络类型,有 `bridge` `overlay`。其中 `overlay` 网络类型用于 [Swarm mode](../swarm_mode/),在本小节中你可以忽略它。
-### 连接容器
+## 连接容器
运行一个容器并连接到新建的 `my-net` 网络
@@ -62,6 +62,6 @@ PING busybox1 (172.19.0.2): 56 data bytes
这样,`busybox1` 容器和 `busybox2` 容器建立了互联关系。
-### Docker Compose
+## Docker Compose
如果你有多个容器之间需要互相连接,推荐使用 [Docker Compose](../compose)。
diff --git a/network/port_mapping.md b/network/port_mapping.md
index 59b0690..ef42475 100644
--- a/network/port_mapping.md
+++ b/network/port_mapping.md
@@ -1,4 +1,4 @@
-## 外部访问容器
+# 外部访问容器
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 `-P` 或 `-p` 参数来指定端口映射。
@@ -25,7 +25,7 @@ $ docker logs -f nostalgic_morse
`-p` 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 `ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort`。
-### 映射所有接口地址
+## 映射所有接口地址
使用 `hostPort:containerPort` 格式本地的 5000 端口映射到容器的 5000 端口,可以执行
@@ -35,7 +35,7 @@ $ docker run -d -p 5000:5000 training/webapp python app.py
此时默认会绑定本地所有接口上的所有地址。
-### 映射到指定地址的指定端口
+## 映射到指定地址的指定端口
可以使用 `ip:hostPort:containerPort` 格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1
@@ -43,7 +43,7 @@ $ docker run -d -p 5000:5000 training/webapp python app.py
$ docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
```
-### 映射到指定地址的任意端口
+## 映射到指定地址的任意端口
使用 `ip::containerPort` 绑定 localhost 的任意端口到容器的 5000 端口,本地主机会自动分配一个端口。
@@ -57,7 +57,7 @@ $ docker run -d -p 127.0.0.1::5000 training/webapp python app.py
$ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
```
-### 查看映射端口配置
+## 查看映射端口配置
使用 `docker port` 来查看当前映射的端口配置,也可以查看到绑定的地址
diff --git a/opensource/linuxkit.md b/opensource/linuxkit.md
index a4513c0..ee491eb 100644
--- a/opensource/linuxkit.md
+++ b/opensource/linuxkit.md
@@ -1,10 +1,10 @@
-## LinuxKit
+# LinuxKit
`LinuxKit` 这个工具可以将多个 Docker 镜像组成一个最小化、可自由定制的 Linux 系统,最后的生成的系统只有几十 M 大小,可以很方便的在云端进行部署。
下面我们在 macOS 上通过实例,来编译并运行一个全部由 Docker 镜像组成的包含 nginx 服务的 Linux 系统。
-### 安装 Linuxkit
+## 安装 Linuxkit
```bash
$ brew tap linuxkit/linuxkit
@@ -12,7 +12,7 @@ $ brew tap linuxkit/linuxkit
$ brew install --HEAD linuxkit
```
-### 克隆源代码
+## 克隆源代码
```bash
$ git clone -b master --depth=1 https://github.com/linuxkit/linuxkit.git
@@ -20,7 +20,7 @@ $ git clone -b master --depth=1 https://github.com/linuxkit/linuxkit.git
$ cd linuxkit
```
-### 编译 Linux 系统
+## 编译 Linux 系统
LinuxKit 通过 `yaml` 文件配置。
@@ -40,7 +40,7 @@ LinuxKit 通过 `yaml` 文件配置。
$ linuxkit build linuxkit.yml
```
-### 启动 Linux 系统
+## 启动 Linux 系统
编译成功后,接下来启动这个 Linux 系统。
diff --git a/security/control_group.md b/security/control_group.md
index 0940a30..cd2bd39 100644
--- a/security/control_group.md
+++ b/security/control_group.md
@@ -1,4 +1,4 @@
-## 控制组
+# 控制组
控制组是 Linux 容器机制的另外一个关键组件,负责实现资源的审计和限制。
它提供了很多有用的特性;以及确保各个容器可以公平地分享主机的内存、CPU、磁盘 IO 等资源;当然,更重要的是,控制组确保了当容器内的资源使用产生压力时不会连累主机系统。
diff --git a/security/daemon_sec.md b/security/daemon_sec.md
index c1b4057..7389ffb 100644
--- a/security/daemon_sec.md
+++ b/security/daemon_sec.md
@@ -1,4 +1,4 @@
-## Docker服务端的防护
+# Docker服务端的防护
运行一个容器或应用程序的核心是通过 Docker 服务端。Docker 服务的运行目前需要 root 权限,因此其安全性十分关键。
首先,确保只有可信的用户才可以访问 Docker 服务。Docker 允许用户在主机和容器间共享文件夹,同时不需要限制容器的访问权限,这就容易让容器突破资源限制。例如,恶意用户启动容器的时候将主机的根目录`/`映射到容器的 `/host` 目录中,那么容器理论上就可以对主机的文件系统进行任意修改了。这听起来很疯狂?但是事实上几乎所有虚拟化系统都允许类似的资源共享,而没法禁止用户共享主机根文件系统到虚拟机系统。
diff --git a/security/kernel_capability.md b/security/kernel_capability.md
index bbe3a52..4ebc9ea 100644
--- a/security/kernel_capability.md
+++ b/security/kernel_capability.md
@@ -1,4 +1,4 @@
-## 内核能力机制
+# 内核能力机制
能力机制(Capability)是 Linux 内核一个强大的特性,可以提供细粒度的权限访问控制。
Linux 内核自 2.2 版本起就支持能力机制,它将权限划分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上。
diff --git a/security/kernel_ns.md b/security/kernel_ns.md
index 1ce607c..18e070b 100644
--- a/security/kernel_ns.md
+++ b/security/kernel_ns.md
@@ -1,4 +1,4 @@
-## 内核命名空间
+# 内核命名空间
Docker 容器和 LXC 容器很相似,所提供的安全特性也差不多。当用 `docker run` 启动一个容器时,在后台 Docker 为容器创建了一个独立的命名空间和控制组集合。
命名空间提供了最基础也是最直接的隔离,在容器中运行的进程不会被运行在主机上的进程和其它容器发现和作用。
diff --git a/security/other_feature.md b/security/other_feature.md
index 5b70b5f..3a288c9 100644
--- a/security/other_feature.md
+++ b/security/other_feature.md
@@ -1,4 +1,4 @@
-## 其它安全特性
+# 其它安全特性
除了能力机制之外,还可以利用一些现有的安全机制来增强使用 Docker 的安全性,例如 TOMOYO, AppArmor, SELinux, GRSEC 等。
Docker 当前默认只启用了能力机制。用户可以采用多种方案来加强 Docker 主机的安全,例如:
diff --git a/security/summary.md b/security/summary.md
index 0b2b528..90d144b 100644
--- a/security/summary.md
+++ b/security/summary.md
@@ -1,4 +1,4 @@
-## 总结
+# 总结
总体来看,Docker 容器还是十分安全的,特别是在容器内不使用 root 权限来运行进程的话。
另外,用户可以使用现有工具,比如 Apparmor, SELinux, GRSEC 来增强安全性;甚至自己在内核中实现更复杂的安全机制。
diff --git a/swarm_mode/config.md b/swarm_mode/config.md
index 484e943..a18e5a1 100644
--- a/swarm_mode/config.md
+++ b/swarm_mode/config.md
@@ -1,4 +1,4 @@
-## 在 Swarm 集群中管理配置数据
+# 在 Swarm 集群中管理配置数据
在动态的、大规模的分布式集群上,管理和分发配置文件也是很重要的工作。传统的配置文件分发方式(如配置文件放入镜像中,设置环境变量,volume 动态挂载等)都降低了镜像的通用性。
@@ -8,7 +8,7 @@
这里我们以在 Swarm 集群中部署 `redis` 服务为例。
-### 创建 config
+## 创建 config
新建 `redis.conf` 文件
@@ -24,7 +24,7 @@ port 6380
$ docker config create redis.conf redis.conf
```
-### 查看 config
+## 查看 config
使用 `docker config ls` 命令来查看 `config`
@@ -35,7 +35,7 @@ ID NAME CREATED UPDATED
yod8fx8iiqtoo84jgwadp86yk redis.conf 4 seconds ago 4 seconds ago
```
-### 创建 redis 服务
+## 创建 redis 服务
```bash
$ docker service create \
diff --git a/swarm_mode/create.md b/swarm_mode/create.md
index a64fb5c..9139124 100644
--- a/swarm_mode/create.md
+++ b/swarm_mode/create.md
@@ -1,8 +1,8 @@
-## 创建 Swarm 集群
+# 创建 Swarm 集群
阅读 [基本概念](overview.md) 一节我们知道 `Swarm` 集群由 **管理节点** 和 **工作节点** 组成。本节我们来创建一个包含一个管理节点和两个工作节点的最小 `Swarm` 集群。
-### 初始化集群
+## 初始化集群
在 [`Docker Machine`](../machine) 一节中我们了解到 `Docker Machine` 可以在数秒内创建一个虚拟的 Docker 主机,下面我们使用它来创建三个 Docker 主机,并加入到集群中。
@@ -33,7 +33,7 @@ To add a manager to this swarm, run 'docker swarm join-token manager' and follow
> 执行 `docker swarm init` 命令的节点自动成为管理节点。
-### 增加工作节点
+## 增加工作节点
上一步我们初始化了一个 `Swarm` 集群,拥有了一个管理节点,下面我们继续创建两个 Docker 主机作为工作节点,并加入到集群中。
@@ -63,7 +63,7 @@ This node joined a swarm as a worker.
>注意:一些细心的读者可能通过 `docker-machine create --help` 查看到 `--swarm*` 等一系列参数。该参数是用于旧的 `Docker Swarm`,与本章所讲的 `Swarm mode` 没有关系。
-### 查看集群
+## 查看集群
经过上边的两步,我们已经拥有了一个最小的 `Swarm` 集群,包含一个管理节点和两个工作节点。
diff --git a/swarm_mode/deploy.md b/swarm_mode/deploy.md
index 91a84ff..2c22679 100644
--- a/swarm_mode/deploy.md
+++ b/swarm_mode/deploy.md
@@ -1,8 +1,8 @@
-## 部署服务
+# 部署服务
我们使用 `docker service` 命令来管理 `Swarm` 集群中的服务,该命令只能在管理节点运行。
-### 新建服务
+## 新建服务
现在我们在上一节创建的 `Swarm` 集群中运行一个名为 `nginx` 服务。
@@ -12,7 +12,7 @@ $ docker service create --replicas 3 -p 80:80 --name nginx nginx:1.13.7-alpine
现在我们使用浏览器,输入任意节点 IP ,即可看到 nginx 默认页面。
-### 查看服务
+## 查看服务
使用 `docker service ls` 来查看当前 `Swarm` 集群运行的服务。
@@ -44,7 +44,7 @@ nginx.1.pjfzd39buzlt@swarm2 | 10.255.0.2 - - [25/Nov/2017:02:10:27 +0000] "GE
nginx.1.pjfzd39buzlt@swarm2 | 2017/11/25 02:10:27 [error] 5#5: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.255.0.2, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.99.101"
```
-### 服务伸缩
+## 服务伸缩
我们可以使用 `docker service scale` 对一个服务运行的容器数量进行伸缩。
@@ -60,7 +60,7 @@ $ docker service scale nginx=5
$ docker service scale nginx=2
```
-### 删除服务
+## 删除服务
使用 `docker service rm` 来从 `Swarm` 集群移除某个服务。
diff --git a/swarm_mode/overview.md b/swarm_mode/overview.md
index d3f5264..cd853af 100644
--- a/swarm_mode/overview.md
+++ b/swarm_mode/overview.md
@@ -1,10 +1,10 @@
-## 基本概念
+# 基本概念
`Swarm` 是使用 [`SwarmKit`](https://github.com/docker/swarmkit/) 构建的 Docker 引擎内置(原生)的集群管理和编排工具。
使用 `Swarm` 集群之前需要了解以下几个概念。
-### 节点
+## 节点
运行 Docker 的主机可以主动初始化一个 `Swarm` 集群或者加入一个已存在的 `Swarm` 集群,这样这个运行 Docker 的主机就成为一个 `Swarm` 集群的节点 (`node`) 。
@@ -18,7 +18,7 @@

-### 服务和任务
+## 服务和任务
任务 (`Task`)是 `Swarm` 中的最小的调度单位,目前来说就是一个单一的容器。
diff --git a/swarm_mode/rolling_update.md b/swarm_mode/rolling_update.md
index 767be20..560b0ae 100644
--- a/swarm_mode/rolling_update.md
+++ b/swarm_mode/rolling_update.md
@@ -1,4 +1,4 @@
-## SWarm mode 与滚动升级
+# SWarm mode 与滚动升级
在 [部署服务](deploy.md) 一节中我们使用 `nginx:1.13.7-alpine` 镜像部署了一个名为 `nginx` 的服务。
@@ -24,7 +24,7 @@ $ docker service update \
更多选项可以通过 `docker service update -h` 命令查看。
-### 服务回退
+## 服务回退
现在假设我们发现 `nginx` 服务的镜像升级到 `nginx:1.13.12-alpine` 出现了一些问题,我们可以使用命令一键回退。
diff --git a/swarm_mode/secret.md b/swarm_mode/secret.md
index 4d84765..28981d5 100644
--- a/swarm_mode/secret.md
+++ b/swarm_mode/secret.md
@@ -1,4 +1,4 @@
-## 在 Swarm 集群中管理敏感数据
+# 在 Swarm 集群中管理敏感数据
在动态的、大规模的分布式集群上,管理和分发 `密码`、`证书` 等敏感信息是极其重要的工作。传统的密钥分发方式(如密钥放入镜像中,设置环境变量,volume 动态挂载等)都存在着潜在的巨大的安全风险。
@@ -10,7 +10,7 @@ Docker 目前已经提供了 `secrets` 管理功能,用户可以在 Swarm 集
这里我们以在 Swarm 集群中部署 `mysql` 和 `wordpress` 服务为例。
-### 创建 secret
+## 创建 secret
我们使用 `docker secret create` 命令以管道符的形式创建 `secret`
@@ -20,7 +20,7 @@ $ openssl rand -base64 20 | docker secret create mysql_password -
$ openssl rand -base64 20 | docker secret create mysql_root_password -
```
-### 查看 secret
+## 查看 secret
使用 `docker secret ls` 命令来查看 `secret`
@@ -32,7 +32,7 @@ l1vinzevzhj4goakjap5ya409 mysql_password 41 seconds ago 41 seconds
yvsczlx9votfw3l0nz5rlidig mysql_root_password 12 seconds ago 12 seconds ago
```
-### 创建 MySQL 服务
+## 创建 MySQL 服务
创建服务相关命令已经在前边章节进行了介绍,这里直接列出命令。
diff --git a/swarm_mode/stack.md b/swarm_mode/stack.md
index 66561f4..a7d1ebd 100644
--- a/swarm_mode/stack.md
+++ b/swarm_mode/stack.md
@@ -1,4 +1,4 @@
-## 在 Swarm 集群中使用 compose 文件
+# 在 Swarm 集群中使用 compose 文件
正如之前使用 `docker-compose.yml` 来一次配置、启动多个容器,在 `Swarm` 集群中也可以使用 `compose` 文件 (`docker-compose.yml`) 来配置、启动多个服务。
@@ -60,7 +60,7 @@ networks:
在 `Swarm` 集群中使用 `docker-compose.yml` 我们用 `docker stack` 命令,下面我们对该命令进行详细讲解。
-### 部署服务
+## 部署服务
部署服务使用 `docker stack deploy`,其中 `-c` 参数指定 compose 文件名。
@@ -74,7 +74,7 @@ $ docker stack deploy -c docker-compose.yml wordpress
在浏览器新的标签页输入 `任一节点IP` 即可看到 `WordPress` 安装界面,安装完成之后,输入 `任一节点IP` 即可看到 `WordPress` 页面。
-### 查看服务
+## 查看服务
```bash
$ docker stack ls
@@ -82,7 +82,7 @@ NAME SERVICES
wordpress 3
```
-### 移除服务
+## 移除服务
要移除服务,使用 `docker stack down`