diff --git a/README.md b/README.md index dea3856..a0e5876 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Docker — 从入门到实践 +[![](https://img.shields.io/github/stars/yeasy/docker_practice.svg?style=social&label=Stars)](https://github.com/yeasy/docker_practice) [![](https://img.shields.io/docker/pulls/yeasy/docker_practice.svg)](https://store.docker.com/community/images/yeasy/docker_practice) [![](https://img.shields.io/github/release/yeasy/docker_practice/all.svg)](https://github.com/yeasy/docker_practice/releases) + 0.9-rc1(2017-11-30) *修订说明:本书内容将基于 Docker CE v17.x 进行重新修订,计划 2017 年底发布 0.9.0 版本。旧版本(Docker 1.13-)内容,请阅读 [docker-legacy](https://github.com/yeasy/docker_practice/tree/docker-legacy) 分支的内容。* diff --git a/SUMMARY.md b/SUMMARY.md index bc393d6..57a6da5 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -99,7 +99,7 @@ * [CoreOS 项目](coreos/README.md) * [简介](coreos/intro.md) * [工具](coreos/intro_tools.md) - * [快速搭建CoreOS集群](coreos/quickstart.md) + * [快速搭建 CoreOS 集群](coreos/quickstart.md) * [Kubernetes 项目](kubernetes/README.md) * [简介](kubernetes/intro.md) * [快速上手](kubernetes/quickstart.md) @@ -123,9 +123,8 @@ * [实战案例-操作系统](cases/os/README.md) * [Busybox](cases/os/busybox.md) * [Alpine](cases/os/alpine.md) - * [Debian\/Ubuntu](cases/os/debian.md) - * [CentOS\/Fedora](cases/os/centos.md) - * [CoreOS](cases/os/coreos.md) + * [Debian Ubuntu](cases/os/debian.md) + * [CentOS Fedora](cases/os/centos.md) * [本章小结](cases/os/summary.md) * [附录](appendix/README.md) * [附录一:常见问题总结](appendix/faq/README.md) diff --git a/advanced_network/dns.md b/advanced_network/dns.md index 208a47d..2f16d0d 100644 --- a/advanced_network/dns.md +++ b/advanced_network/dns.md @@ -1,4 +1,5 @@ ## 配置 DNS + Docker 没有为每个容器专门定制镜像,那么怎么自定义配置容器的主机名和 DNS 配置呢? 秘诀就是它利用虚拟文件来挂载到来容器的 3 个相关配置文件。 @@ -11,16 +12,34 @@ $ mount tmpfs on /etc/resolv.conf type tmpfs ... ... ``` -这种机制可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 dns 配置通过 `/etc/resolv.conf` 文件立刻得到更新。 + +这种机制可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 DNS 配置通过 `/etc/resolv.conf` 文件立刻得到更新。 + +配置全部容器的 DNS ,也可以在 `/etc/docker/daemon.json` 文件中增加以下内容来设置。 + +```json +{ + "dns" : [ + "114.114.114.114", + "8.8.8.8" + ] +} +``` + +这样每次启动的容器 DNS 自动配置为 `114.114.114.114` 和 `8.8.8.8`。使用以下命令来证明其已经生效。 + +```bash +$ docker run -it --rm ubuntu:17.10 cat etc/resolv.conf + +nameserver 114.114.114.114 +nameserver 8.8.8.8 +``` 如果用户想要手动指定容器的配置,可以利用下面的选项。 `-h HOSTNAME or --hostname=HOSTNAME` 设定容器的主机名,它会被写到容器内的 `/etc/hostname` 和 `/etc/hosts`。但它在容器外部看不到,既不会在 `docker ps` 中显示,也不会在其他的容器的 `/etc/hosts` 看到。 -`--link=CONTAINER_NAME:ALIAS` -选项会在创建容器的时候,添加一个其他容器的主机名到 `/etc/hosts` 文件中,让新容器的进程可以使用主机名 ALIAS 就可以连接它。 - `--dns=IP_ADDRESS` 添加 DNS 服务器到容器的 `/etc/resolv.conf` 中,让容器用这个服务器来解析所有不在 `/etc/hosts` 中的主机名。 diff --git a/cases/os/README.md b/cases/os/README.md index f3c4e95..09b6545 100644 --- a/cases/os/README.md +++ b/cases/os/README.md @@ -2,8 +2,8 @@ 目前常用的 Linux 发行版主要包括 Debian/Ubuntu 系列和 CentOS/Fedora 系列。 -前者以自带软件包版本较新而出名;后者则宣称运行更稳定一些。选择哪个操作系统取决于读者的具体需求。同时,社区还推出了完全基于 Docker 的 Linux 发行版 CoreOS。 +前者以自带软件包版本较新而出名;后者则宣称运行更稳定一些。选择哪个操作系统取决于读者的具体需求。 -使用 Docker,读者只需要一个命令就能快速获取一个 linux 发行版镜像,这是以往包括各种虚拟化技术都难以实现的。这些镜像一般都很精简,但是可以支持完整 linux 系统的大部分功能。 +使用 Docker,读者只需要一个命令就能快速获取一个 Linux 发行版镜像,这是以往包括各种虚拟化技术都难以实现的。这些镜像一般都很精简,但是可以支持完整 Linux 系统的大部分功能。 -本章将介绍如何使用 Docker 安装和使用 Busybox、Alphine、Debian/Ubuntu、CentOS/Fedora、CoreOS 等操作系统。 +本章将介绍如何使用 Docker 安装和使用 Busybox、Alphine、Debian/Ubuntu、CentOS/Fedora 等操作系统。 diff --git a/cases/os/coreos.md b/cases/os/coreos.md deleted file mode 100644 index e706e25..0000000 --- a/cases/os/coreos.md +++ /dev/null @@ -1,115 +0,0 @@ -## CoreOS - -### 简介 - -![CoreOS - 容器化操作系统](_images/coreos-logo.jpg) - -CoreOS 是一个轻量级容器化 Linux 发行版,专为数据中心场景而设计,旨在通过轻量的系统架构和灵活的应用程序部署能力简化数据中心的维护成本和复杂度。CoreOS 作为 Docker 生态圈中的重要一员,日益得到各大云服务商的重视。CoreOS 于 2014 年 7 月首次发布了稳定版本。 - -与其他历史悠久、使用广泛的 Linux 操作系统相比,CoreOS 拥有下面几个优点。 - -* CoreOS 通过容器化(Containerized)的运算环境向应用程序提供运算资源。 - -传统类 Unix 系统往往提供包管理工具。随着系统安装更多的程序,而程序的依赖要求各不相同,这就容易出现“依赖地狱”(Dependency Hell),系统的更新和安装会非常痛苦。 - -CoreOS 的应用程序通过 Docker 运行在容器中,彼此之间共享系统内核和资源,同时互不可见。这种方式使得操作系统、应用程序及运行环境之间的耦合度大大降低。相对于传统的部署方式而言,运维可以更加灵活便捷的在 CoreOS 集群中部署应用程序,同时各运行环境之间的干扰更少,操作系统自身的维护也更加容易。 - -* CoreOS 采用双系统分区(Dual Root Partition)设计。 - -CoreOs 的两个分区在系统运行期间各司其职,它们分别被设置成主动模式和被动模式。主动分区负责系统运行,被动分区负责系统升级。一旦 CoreOS 发布了新版系统,运维只需下载一个完整的系统安装文件至被动分区,然后设置系统下一次重启时从新版本分区启动,将主、被动分区的职能进行调换即可。在 CoreOS 系统运行期间,系统分区被设置成只读状态,这样也确保了 CoreOS 的安全性。CoreOS 的升级过程在默认条件下将自动完成,并且通过 cgroup 对升级过程中使用到的网络和磁盘资源进行限制,这将系统升级所带来的影响降至最低。 - -* CoreOS 使用 Systemd 取代 SysV 作为系统和服务的管理工具。 - -与 SysV 相比,Systemd 不仅可以更好的追踪系统进程,还具备优秀的并行化处理能力。Systemd 将自己的按需启动的特性与 Docker 的快速启动能力相结合,在 CoreOS 集群中大规模部署 Docker Containers 的业务中优势明显。Systemd 引入了“target”的概念,每个 target 应用于一个特定的服务,并且可以通过继承一个已有的 target 来扩展额外的功能,即操作系统对系统上运行的服务拥有更好的控制力。 - -CoreOS 团队还推出了很多有益的工具,包括 etcd, fleet, flannel 等。 - -安装 CoreOS 有几种方法,笔者推荐初学者使用 VMware Workstation 虚拟机方式来运行 CoreOS。VMware Workstation 工具则可以前往其官网`http://www.vmware.com/products/workstation/` 下载获取。 - -### 使用官方镜像 - -#### 获取虚拟机镜像 -从官方网站下载 CoreOS 镜像,地址为 [https:\/\/coreos.com\/releases\/](http://alpha.release.core-os.net/amd64-usr/current/coreos_production_vmware_insecure.zip)。 - -如果读者已经安装 VMware Workstation,则解压镜像包后双击`vmx` 文件: -![虚拟机镜像文件](_images/coreos_list.png)! - -双击`vmx` 文件后,即可启动 CoreOS 虚拟机,如下图所示: - -![启动 CoreOS 虚拟机](_images/vmware_coreos.png) - -*注意:使用免费版 VMware Player 运行 CoreOS 官方镜像时,可能出现无法通过 DHCP 自动获取 IP 地址的问题,读者可配置静态地址或使用 VMware Workstation 来运行 `vmx` 文件。* - -#### 获取地址信息 - -此时CoreOS 系统已经在 VMware Station 中启动,显示登录提示: - -![登录 CoreOS](_images/coreos-login.png) - -直接按回车键,获取当前系统的 IP 地址,如下图所示: - -![获取 IP 地址](_images/coreos_run_ip.png) - -如上图所示,查看此时 CoreOS 的 IP地址是:`192.168.66.128`。 - -#### 使用 SSH 客户端访问镜像 - -笔者以 Windows 环境为例,使用 SecureCRT 工具进行连接。此处读者需要确定: - -* CoreOS 虚拟机的 IP地址 -* CoreOS 虚拟机的文件目录下含有 `insecure_ssh_key` 公钥文件 - -打开 SecureCRT,建立新的 SSH 连接,如下图示: - -![使用 SecureCRT 访问 CoreOS](_images/coreos_crt.png) - -点击 ` 属性` 按钮添加 `insecure_ssh_key` 公钥文件后,即可点击 `连接`。 - -如果连接成功,则读者可以看到命令行页面,读者在命令行中查看 Docker 的版本信息: - -```bash -$ docker version -``` - -结果如下图示: - -![查看 Docker 版本信息](_images/docker_version.png) - -此时,CoreOS 虚拟机已经成功运行,并且读者可以使用 SSH 客户端方便的操作 CoreOS 虚拟机。 Docker 已经内置于 CoreOS 中,读者可以进行各种 Docker 操作,如下图示: - -![使用 Docker 命令](_images/php_pulling.png) - -如果读者的本机环境是 Linux 系统,读者可以使用 SSH 公钥(在解压后的根目录下),直接使用 `ssh` 命令连接 CoreOS 虚拟机,并使用 `ip a` 命令查看 IP 地址信息。 - -如下所示: - -```bash -$ ssh -i ~/insecure_ssh_key core@192.168.6.153 -CoreOS (alpha) -core@localhost ~ $ ls -core@localhost ~ $ docker ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -core@localhost ~ $ ip a -1: lo: mtu 65536 qdisc noqueue state UNKNOWN - link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 - inet 127.0.0.1/8 scope host lo - valid_lft forever preferred_lft forever - inet6 ::1/128 scope host - valid_lft forever preferred_lft forever -2: enp0s17: mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000 - link/ether 00:0c:29:ff:73:46 brd ff:ff:ff:ff:ff:ff - inet 192.168.6.153/20 brd 192.168.15.255 scope global dynamic enp0s17 - valid_lft 604500sec preferred_lft 604500sec - inet6 fe80::20c:29ff:feff:7346/64 scope link - valid_lft forever preferred_lft forever -3: docker0: mtu 1500 qdisc noqueue state DOWN - link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff - inet 172.17.42.1/16 scope global docker0 - valid_lft forever preferred_lft forever -core@localhost ~ $ -``` - -### 相关资源 - -* `CoreOS` 官网:`https://coreos.com/` -* `CoreOS` 官方仓库:`https://github.com/coreos/` diff --git a/cases/os/summary.md b/cases/os/summary.md index d3abdc9..d7ed5dc 100644 --- a/cases/os/summary.md +++ b/cases/os/summary.md @@ -1,12 +1,13 @@ # 本章小结 + 本章讲解了典型操作系统镜像的下载和使用。 -除了官方的镜像外,在 DockerHub 上还有许多第三方组织或个人上传的 Docker 镜像。 +除了官方的镜像外,在 Docker Hub 上还有许多第三方组织或个人上传的 Docker 镜像。 读者可以根据具体情况来选择。一般来说: * 官方镜像体积都比较小,只带有一些基本的组件。 精简的系统有利于安全、稳定和高效的运行,也适合进行定制化。 -* 个别第三方(如 tutum,已被 Docker 收购)镜像质量也非常高。这些镜像通常针对某个具体应用进行配置,比如:包含 LAMP 组件的 Ubuntu 镜像。 -* 处于安全考虑,几乎所有官方制作的镜像都没有安装 SSH 服务,无法使用用户名和密码直接登录。 + +* 出于安全考虑,几乎所有官方制作的镜像都没有安装 SSH 服务,无法通过用户名和密码直接登录到容器中。 后续章节中,笔者将介绍如何创建一个带 SSH 服务的 Docker 镜像。 diff --git a/compose/commands.md b/compose/commands.md index e386d80..15e9bd1 100644 --- a/compose/commands.md +++ b/compose/commands.md @@ -28,6 +28,7 @@ docker-compose [-f=...] [options] [COMMAND] [ARGS...] ### 命令使用说明 #### `build` + 格式为 `docker-compose build [options] [SERVICE...]`。 构建(重新构建)项目中的服务容器。 @@ -44,10 +45,26 @@ docker-compose [-f=...] [options] [COMMAND] [ARGS...] * `--pull` 始终尝试通过 pull 来获取更新版本的镜像。 +#### `config` + +验证 Compose 文件格式是否正确,若正确则显示配置,若格式错误显示错误原因。 + +#### `down` + +此命令将会停止 `up` 命令所启动的容器,并移除网络 + +#### `exec` + +进入指定的容器。 + #### `help` 获得一个命令的帮助。 +#### `images` + +列出 Compose 文件中包含的镜像。 + #### `kill` 格式为 `docker-compose kill [options] [SERVICE...]`。 @@ -100,6 +117,10 @@ $ docker-compose kill -s SIGINT * `--ignore-pull-failures` 忽略拉取镜像过程中的错误。 +#### `push` + +推送服务依赖的镜像到 Docker 镜像仓库。 + #### `restart` 格式为 `docker-compose restart [options] [SERVICE...]`。 @@ -206,6 +227,10 @@ $ docker-compose scale web=3 db=2 * `-t, --timeout TIMEOUT` 停止容器时候的超时(默认为 10 秒)。 +#### `top` + +查看各个服务容器内运行的进程。 + #### `unpause` 格式为 `docker-compose unpause [SERVICE...]`。 @@ -244,15 +269,6 @@ $ docker-compose scale web=3 db=2 * `-t, --timeout TIMEOUT` 停止容器时候的超时(默认为 10 秒)。 -#### `migrate-to-labels` -格式为 `docker-compose migrate-to-labels`。 - -重新创建容器,并添加 label。 - -主要用于升级 1.2 及更早版本中创建的容器,添加缺失的容器标签。 - -实际上,最彻底的办法当然是删除项目,然后重新创建。 - #### `version` 格式为 `docker-compose version`。 diff --git a/compose/yaml_file.md b/compose/yaml_file.md index 4c9c6a9..b179789 100644 --- a/compose/yaml_file.md +++ b/compose/yaml_file.md @@ -31,6 +31,7 @@ build: /path/to/build/dir ``` ### `cap_add, cap_drop` + 指定容器的内核能力(capacity)分配。 例如,让容器拥有所有能力可以指定为: @@ -55,7 +56,12 @@ cap_drop: command: echo "hello world" ``` +### `configs` + +仅用于 `Swarm mode`,详细内容请查看 [`Swarm mode`](../swarm_mode/) 一节。 + ### `cgroup_parent` + 指定父 `cgroup` 组,意味着将继承该组的资源限制。 例如,创建了一个 cgroup 组名称为 `cgroups_1`。 @@ -65,6 +71,7 @@ cgroup_parent: cgroups_1 ``` ### `container_name` + 指定容器名称。默认将会使用 `项目名称_服务名称_序号` 这样的格式。 ```yaml @@ -73,7 +80,12 @@ container_name: docker-web-container 需要注意,指定容器名称后,该服务将无法进行扩展(scale),因为 Docker 不允许多个容器具有相同的名称。 +### `deploy` + +仅用于 `Swarm mode`,详细内容请查看 [`Swarm mode`](../swarm_mode/) 一节 + ### `devices` + 指定设备映射关系。 ```yaml @@ -83,15 +95,32 @@ devices: ### `depends_on` +解决容器的依赖、启动先后的问题。以下例子中会先启动 `redis` `db` 再启动 `web` + +```yaml +version: '3' + +services: + web: + build: . + depends_on: + - db + - redis + + redis: + image: redis + + db: + image: postgres +``` + ### `dns` 自定义 `DNS` 服务器。可以是一个值,也可以是一个列表。 ```yaml dns: 8.8.8.8 -``` -```yaml dns: - 8.8.8.8 - 114.114.114.114 @@ -103,15 +132,25 @@ dns: ```yaml dns_search: example.com -``` -```yaml dns_search: - domain1.example.com - domain2.example.com ``` +### `tmpfs` + +挂载一个 tmpfs 文件系统到容器。 + +```yaml +tmpfs: /run +tmpfs: + - /run + - /tmp +``` + ### `env_file` + 从文件中获取环境变量,可以为单独的文件路径或列表。 如果通过 `docker-compose -f FILE` 方式来指定 Compose 模板文件,则 `env_file` 中变量的路径会基于模板文件路径。 @@ -144,9 +183,7 @@ PROG_ENV=development environment: RACK_ENV: development SESSION_SECRET: -``` -```yaml environment: - RACK_ENV=development - SESSION_SECRET @@ -173,7 +210,8 @@ expose: ``` ### `external_links` -链接到 docker-compose.yml 外部的容器,甚至 并非 `Compose` 管理的外部容器。参数格式跟 `links` 类似。 + +链接到 docker-compose.yml 外部的容器,甚至并非 `Compose` 管理的外部容器。参数格式跟 `links` 类似。 ```yaml external_links: @@ -183,6 +221,7 @@ external_links: ``` ### `extra_hosts` + 类似 Docker 中的 `--add-host` 参数,指定额外的 host 名称映射信息。 ```yaml @@ -200,11 +239,20 @@ extra_hosts: ### `healthcheck` +通过命令检查容器是否健康运行。 + +```yaml +healthcheck: + test: ["CMD", "curl", "-f", "http://localhost"] + interval: 1m30s + timeout: 10s + retries: 3 +``` + ### `image` 指定为镜像名称或镜像 ID。如果镜像在本地不存在,`Compose` 将会尝试拉去这个镜像。 -例如: ```yaml image: ubuntu image: orchardup/postgresql @@ -212,7 +260,9 @@ image: a4bc65fd ``` ### `labels` + 为容器添加 Docker 元数据(metadata)信息。例如可以为容器添加辅助说明信息。 + ```yaml labels: com.startupteam.description: "webapp for a startup team" @@ -242,44 +292,70 @@ links: 被链接容器中相应的环境变量也将被创建。 ### `logging` -类似 Docker 中的 `--log-driver` 参数,指定日志驱动类型。 + +配置日志选项。 + +```yaml +logging: + driver: syslog + options: + syslog-address: "tcp://192.168.0.42:123" +``` 目前支持三种日志驱动类型。 ```yaml -log_driver: "json-file" -log_driver: "syslog" -log_driver: "none" +driver: "json-file" +driver: "syslog" +driver: "none" ``` -### `log_opt` -日志驱动的相关参数。 +`options` 配置日志驱动的相关参数。 ```yaml -log_driver: "syslog" -log_opt: - syslog-address: "tcp://192.168.0.42:123" +options: + max-size: "200k" + max-file: "10" ``` -### `networks` +### `network_mode` 设置网络模式。使用和 `docker run` 的 `--net` 参数一样的值。 ```yaml -net: "bridge" -net: "none" -net: "container:[name or id]" -net: "host" +network_mode: "bridge" +network_mode: "host" +network_mode: "none" +network_mode: "service:[service name]" +network_mode: "container:[container name/id]" +``` + +### `networks` + +配置容器连接的网络。 + +```yaml +version: "3" +services: + + some-service: + networks: + - some-network + - other-network + +networks: + some-network: + other-network: ``` ### `pid` + 跟主机系统共享进程命名空间。打开该选项的容器之间,以及容器和宿主机系统之间可以通过进程 ID 来相互访问和操作。 ```yaml pid: "host" ``` - ### `ports` 暴露端口信息。 @@ -296,18 +372,44 @@ ports: *注意:当使用 `HOST:CONTAINER` 格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 `YAML` 会自动解析 `xx:yy` 这种数字格式为 60 进制。为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式。* +### `secrets` + +仅用于 `Swarm mode`,详细内容请查看 [`Swarm mode`](../swarm_mode/) 一节。 + ### `security_opt` -指定容器模板标签(label)机制的默认属性(用户、角色、类型、级别等)。 +指定容器模板标签(label)机制的默认属性(用户、角色、类型、级别等)。例如配置标签的用户名和角色名。 -例如配置标签的用户名和角色名。 ```yaml security_opt: - label:user:USER - label:role:ROLE ``` +### `stop_signal` + +设置另一个信号来停止容器。在默认情况下使用的是 SIGTERM 停止容器。 + +```yaml +stop_signal: SIGUSR1 +``` + +### `sysctls` + +配置容器内核参数。 + +```yaml +sysctls: + net.core.somaxconn: 1024 + net.ipv4.tcp_syncookies: 0 + +sysctls: + - net.core.somaxconn=1024 + - net.ipv4.tcp_syncookies=0 +``` + ### `ulimits` + 指定容器的 ulimits 限制值。 例如,指定最大进程数为 65535,指定文件句柄数为 20000(软限制,应用可以随时修改,不能超过硬限制) 和 40000(系统硬限制,只能 root 用户提高)。 @@ -338,21 +440,25 @@ volumes: 此外,还有包括 `domainname, entrypoint, hostname, ipc, mac_address, privileged, read_only, shm_size, restart, stdin_open, tty, user, working_dir` 等指令,基本跟 `docker run` 中对应参数的功能一致。 指定服务容器启动后执行的入口文件。 + ```yaml entrypoint: /code/entrypoint.sh ``` 指定容器中运行应用的用户名。 + ```yaml user: nginx ``` 指定容器中工作目录。 + ```yaml working_dir: /code ``` 指定容器中搜索域名、主机名、mac 地址等。 + ```yaml domainname: your_website.com hostname: test @@ -360,31 +466,37 @@ mac_address: 08-00-27-00-0C-0A ``` 指定容器中 + ```yaml ipc: host ``` 允许容器中运行一些特权命令。 + ```yaml privileged: true ``` 指定容器退出后的重启策略为始终重启。该命令对保持服务始终运行十分有效,在生产环境中推荐配置为 `always` 或者 `unless-stopped`。 + ```yaml restart: always ``` 以只读模式挂载容器的 root 文件系统,意味着不能对容器内容进行修改。 + ```yaml read_only: true ``` 打开标准输入,可以接受外部输入。 + ```yaml stdin_open: true ``` 模拟一个假的远程控制台。 + ```yaml tty: true ``` diff --git a/container/enter.md b/container/enter.md index 9ac9da6..3b77c36 100644 --- a/container/enter.md +++ b/container/enter.md @@ -1,86 +1,56 @@ ## 进入容器 + 在使用 `-d` 参数时,容器启动后会进入后台。 -某些时候需要进入容器进行操作,有很多种方法,包括使用 `docker attach` 命令或 `nsenter` 工具等。 -### attach 命令 + +某些时候需要进入容器进行操作,包括使用 `docker attach` 命令或 `docker exec` 命令,推荐大家使用 `docker exec` 命令,原因会在下面说明。 + +### `attach` 命令 + `docker attach` 是 Docker 自带的命令。下面示例如何使用该命令。 ```bash -$ docker run -idt ubuntu +$ docker run -dit ubuntu 243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550 + $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 243c32535da7 ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds nostalgic_hypatia -$ docker attach nostalgic_hypatia + +$ docker attach 243c root@243c32535da7:/# ``` -但是使用 `attach` 命令有时候并不方便。当多个窗口同时 attach 到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执行操作了。 +*注意:* 如果从这个 stdin 中 exit,会导致容器的停止。 -### nsenter 命令 -#### 安装 -`nsenter` 工具在 util-linux 包2.23版本后包含。 -如果系统中 util-linux 包没有该命令,可以按照下面的方法从源码安装。 -```bash -$ cd /tmp; curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-; cd util-linux-2.24; -$ ./configure --without-ncurses -$ make nsenter && sudo cp nsenter /usr/local/bin -``` +### `exec` 命令 -#### 使用 -`nsenter` 启动一个新的shell进程(默认是/bin/bash), 同时会把这个新进程切换到和目标(target)进程相同的命名空间,这样就相当于进入了容器内部。nsenter 要正常工作需要有 root 权限。 -很不幸,Ubuntu 14.04 仍然使用的是 util-linux 2.20。安装最新版本的 util-linux(2.29)版,请按照以下步骤: +#### -i -t 参数 + +`docker exec` 后边可以跟多个参数,这里主要说明 `-i` `-t` 参数。 + +只用 `-i` 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。 + +当 `-i` `-t` 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。 ```bash -$ wget https://www.kernel.org/pub/linux/utils/util-linux/v2.29/util-linux-2.29.tar.xz; tar xJvf util-linux-2.29.tar.xz -$ cd util-linux-2.29 -$ ./configure --without-ncurses && make nsenter -$ sudo cp nsenter /usr/local/bin -``` +$ docker run -dit ubuntu +69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6 -为了连接到容器,你还需要找到容器的第一个进程的 PID,可以通过下面的命令获取。 - -```bash -PID=$(docker inspect --format "{{ .State.Pid }}" ) -``` - -通过这个 PID,就可以连接到这个容器: - -```bash -$ nsenter --target $PID --mount --uts --ipc --net --pid -``` - -如果无法通过以上命令连接到这个容器,有可能是因为宿主的默认shell在容器中并不存在,比如zsh,可以使用如下命令显式地使用bash。 - -```bash -$ nsenter --target $pid --mount --uts --ipc --net --pid -- /usr/bin/env \ ---ignore-environment HOME=/root /bin/bash --login -``` - -下面给出一个完整的例子。 - -```bash -$ docker run -idt ubuntu -243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -243c32535da7 ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds nostalgic_hypatia -$ PID=$(docker-pid 243c32535da7) -10981 -$ sudo nsenter --target 10981 --mount --uts --ipc --net --pid -root@243c32535da7:/# +69d137adef7a ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds zealous_swirles + +$ docker exec -i 69d1 bash +ls +bin +boot +dev +... + +$ docker exec -it 69d1 bash +root@69d137adef7a:/# ``` -更简单的,建议大家下载 -[.bashrc_docker](https://github.com/yeasy/docker_practice/raw/master/_local/.bashrc_docker),并将内容放到 .bashrc 中。 +如果从这个 stdin 中 exit,不会导致容器的停止。这就是为什么推荐大家使用 `docker exec` 的原因。 -```bash -$ wget -P ~ https://github.com/yeasy/docker_practice/raw/master/_local/.bashrc_docker; -$ echo "[ -f ~/.bashrc_docker ] && . ~/.bashrc_docker" >> ~/.bashrc; source ~/.bashrc -``` - -这个文件中定义了很多方便使用 Docker 的命令,例如 `docker-pid` 可以获取某个容器的 PID;而 `docker-enter` 可以进入容器或直接在容器内执行命令。 - -```bash -$ echo $(docker-pid ) -$ docker-enter ls -``` +更多参数说明请使用 `docker exec --help` 查看。 diff --git a/data_management/bind-mounts.md b/data_management/bind-mounts.md index ffcfdbe..45d9827 100644 --- a/data_management/bind-mounts.md +++ b/data_management/bind-mounts.md @@ -2,7 +2,7 @@ ### 选择 -v 还是 -–mount 参数 -Docker 新用户应该选择 `--mount` 参数,经验丰富的 Dcoker 使用者对 `-v` 或者 `--volume` 已经很熟悉了,但是推荐使用 `--volume` 参数。 +Docker 新用户应该选择 `--mount` 参数,经验丰富的 Docker 使用者对 `-v` 或者 `--volume` 已经很熟悉了,但是推荐使用 `--mount` 参数。 ### 挂载一个主机目录作为数据卷 diff --git a/data_management/volume.md b/data_management/volume.md index 63e6aa6..5491d3d 100644 --- a/data_management/volume.md +++ b/data_management/volume.md @@ -14,7 +14,7 @@ ### 选择 -v 还是 -–mount 参数 -Docker 新用户应该选择 `--mount` 参数,经验丰富的 Dcoker 使用者对 `-v` 或者 `--volume` 已经很熟悉了,但是推荐使用 `--volume` 参数。 +Docker 新用户应该选择 `--mount` 参数,经验丰富的 Docker 使用者对 `-v` 或者 `--volume` 已经很熟悉了,但是推荐使用 `--mount` 参数。 ### 创建一个数据卷 diff --git a/image/dockerfile/workdir.md b/image/dockerfile/workdir.md index 243b1b6..6422812 100644 --- a/image/dockerfile/workdir.md +++ b/image/dockerfile/workdir.md @@ -6,12 +6,12 @@ 之前提到一些初学者常犯的错误是把 `Dockerfile` 等同于 Shell 脚本来书写,这种错误的理解还可能会导致出现下面这样的错误: -```Dockerfile +```docker RUN cd /app RUN echo "hello" > world.txt ``` -如果将这个 Dockerfile 进行构建镜像运行后,会发现找不到 `/app/world.txt` 文件,或者其内容不是 `hello`。原因其实很简单,在 Shell 中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 Dockerfile 中,这两行 `RUN` 命令的执行环境根本不同,是两个完全不同的容器。这就是对 Dokerfile 构建分层存储的概念不了解所导致的错误。 +如果将这个 `Dockerfile` 进行构建镜像运行后,会发现找不到 `/app/world.txt` 文件,或者其内容不是 `hello`。原因其实很简单,在 Shell 中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 `Dockerfile` 中,这两行 `RUN` 命令的执行环境根本不同,是两个完全不同的容器。这就是对 `Dockerfile` 构建分层存储的概念不了解所导致的错误。 之前说过每一个 `RUN` 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 `RUN cd /app` 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。 diff --git a/revision.md b/revision.md index 64adcee..8632642 100644 --- a/revision.md +++ b/revision.md @@ -13,7 +13,8 @@ * 0.9-rc1: 2017-11-30 * 根据最新版本(v17.09)修订内容 - * 增加 Dockerfile `multistage builds` 多阶段构建 `Dcoker 17.05` 新增特性 + * 增加 Dockerfile `multistage builds` 多阶段构建 `Docker 17.05` 新增特性 + * 增加 `docker exec` 子命令介绍 * 更新 `Docker 网络` 一节 * 更新 `Docker Machine` 基于 0.13.0 版本 * 更新 `Docker Compose` 基于 3 文件格式