├── book.json ├── kubernetes ├── practice.md ├── qdvanced.md ├── README.md ├── intro.md ├── design.md ├── kubectl.md ├── quickstart.md └── concepts.md ├── machine ├── install.md ├── intro.md ├── usage.md └── README.md ├── advanced_network ├── how_connect.md ├── config_file.md ├── example.md ├── README.md ├── quick_guide.md ├── bridge.md ├── dns.md ├── ptp.md ├── port_mapping.md ├── docker0.md └── access_control.md ├── cases ├── README.md ├── environment.md ├── supervisor.md ├── tomcat.md └── container_connect.md ├── cover.jpg ├── dockerfile ├── README.md ├── build_image.md ├── basic_structure.md └── instructions.md ├── network ├── README.md ├── port_mapping.md └── linking.md ├── cover_small.jpg ├── _images ├── compose.png ├── cover.png ├── docker.png ├── network.png ├── swarm.png ├── cmd_logic.png ├── etcd_logo.png ├── docker_arch.png ├── kube-proxy.png ├── virtualization.png ├── enterprise_usage.png ├── fig-example-large.gif ├── k8s_architecture.png ├── kubernetes_design.jpg ├── fig-rails-screenshot.png ├── k8s-singlenode-docker.png ├── container_connect_topology.png └── cmd_logic.dot ├── docker_primer.png ├── etcd ├── README.md ├── intro.md ├── install.md └── etcdctl.md ├── _local ├── docker_manual_waitfish.pdf ├── pull_all.sh ├── push_all.sh ├── push_images.sh └── .bashrc_docker ├── introduction ├── README.md ├── what.md └── why.md ├── fig ├── README.md ├── env_ref.md ├── install.md ├── cli_ref.md ├── wordpress.md ├── django.md ├── yml_ref.md ├── rails.md └── intro.md ├── install ├── README.md ├── centos.md └── ubuntu.md ├── .gitignore ├── security ├── README.md ├── summary.md ├── control_group.md ├── other_feature.md ├── kernel_ns.md ├── daemon_sec.md └── kernel_capability.md ├── swarm ├── README.md ├── install.md ├── intro.md ├── filter.md ├── scheduling.md └── usage.md ├── appendix_repo ├── README.md ├── ubuntu.md ├── centos.md ├── mysql.md ├── wordpress.md ├── nodejs.md ├── mongodb.md ├── nginx.md └── redis.md ├── compose ├── README.md ├── intro.md ├── install.md ├── commands.md ├── yaml_file.md └── usage.md ├── data_management ├── README.md ├── management.md ├── container.md └── volume.md ├── basic_concept ├── README.md ├── image.md ├── container.md └── repository.md ├── container ├── README.md ├── rm.md ├── daemon.md ├── stop.md ├── import_export.md ├── run.md └── enter.md ├── underly ├── container_format.md ├── cgroups.md ├── arch.md ├── ufs.md ├── README.md ├── namespace.md └── network.md ├── image ├── README.md ├── internal.md ├── rmi.md ├── save_load.md ├── list.md ├── pull.md └── create.md ├── coreos └── README.md ├── repository ├── README.md ├── config.md ├── dockerhub.md └── local_repo.md ├── appendix_resources └── README.md ├── README.md ├── appendix_command └── README.md └── SUMMARY.md /book.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /kubernetes/practice.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kubernetes/qdvanced.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /machine/install.md: -------------------------------------------------------------------------------- 1 | ## 安装 2 | -------------------------------------------------------------------------------- /machine/intro.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | -------------------------------------------------------------------------------- /machine/usage.md: -------------------------------------------------------------------------------- 1 | ## 使用 2 | -------------------------------------------------------------------------------- /advanced_network/how_connect.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cases/README.md: -------------------------------------------------------------------------------- 1 | #实战案例 2 | 介绍一些典型的应用场景和案例。 3 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/cover.jpg -------------------------------------------------------------------------------- /dockerfile/README.md: -------------------------------------------------------------------------------- 1 | # Dockerfile 2 | 使用 Dockerfile 可以允许用户创建自定义的镜像。 3 | 4 | -------------------------------------------------------------------------------- /network/README.md: -------------------------------------------------------------------------------- 1 | # Docker 中的网络功能介绍 2 | Docker 允许通过外部访问容器或容器互联的方式来提供网络服务。 3 | -------------------------------------------------------------------------------- /cover_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/cover_small.jpg -------------------------------------------------------------------------------- /_images/compose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/compose.png -------------------------------------------------------------------------------- /_images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/cover.png -------------------------------------------------------------------------------- /_images/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/docker.png -------------------------------------------------------------------------------- /_images/network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/network.png -------------------------------------------------------------------------------- /_images/swarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/swarm.png -------------------------------------------------------------------------------- /docker_primer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/docker_primer.png -------------------------------------------------------------------------------- /_images/cmd_logic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/cmd_logic.png -------------------------------------------------------------------------------- /_images/etcd_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/etcd_logo.png -------------------------------------------------------------------------------- /_images/docker_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/docker_arch.png -------------------------------------------------------------------------------- /_images/kube-proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/kube-proxy.png -------------------------------------------------------------------------------- /_images/virtualization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/virtualization.png -------------------------------------------------------------------------------- /_images/enterprise_usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/enterprise_usage.png -------------------------------------------------------------------------------- /_images/fig-example-large.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/fig-example-large.gif -------------------------------------------------------------------------------- /_images/k8s_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/k8s_architecture.png -------------------------------------------------------------------------------- /_images/kubernetes_design.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/kubernetes_design.jpg -------------------------------------------------------------------------------- /etcd/README.md: -------------------------------------------------------------------------------- 1 | # etcd 2 | 3 | etcd 是 CoreOS 团队发起的一个管理配置信息和服务发现(service discovery)的项目,在这一章里面,我们将介绍该项目的目标,安装和使用,以及实现的技术。 4 | -------------------------------------------------------------------------------- /_images/fig-rails-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/fig-rails-screenshot.png -------------------------------------------------------------------------------- /_images/k8s-singlenode-docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/k8s-singlenode-docker.png -------------------------------------------------------------------------------- /_local/docker_manual_waitfish.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_local/docker_manual_waitfish.pdf -------------------------------------------------------------------------------- /introduction/README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 本章将带领你进入 Docker 的世界。 3 | 4 | 什么是 Docker? 5 | 6 | 用它会带来什么样的好处? 7 | 8 | 好吧,让我们带着问题开始这神奇之旅。 9 | -------------------------------------------------------------------------------- /fig/README.md: -------------------------------------------------------------------------------- 1 | #Fig 2 | 在你的应用里面添加一个 `fig.yml` 文件,并指定一些简单的内容,执行 `fig up` 它就能帮你快速建立起一个容器。目前已经正式更名为 [Compose](../compose/README.md)。 3 | -------------------------------------------------------------------------------- /install/README.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 官方网站上有各种环境下的 [安装指南](https://docs.docker.com/installation/#installation),这里主要介绍下Ubuntu和CentOS系列的安装。 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .gitignore support plugin (hsz.mobi) 2 | *.~ 3 | *.tmp 4 | .idea/ 5 | _book/ 6 | *.swp 7 | *.edx 8 | .DS_Store 9 | -------------------------------------------------------------------------------- /_images/container_connect_topology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biubiu/docker_practice/master/_images/container_connect_topology.png -------------------------------------------------------------------------------- /security/README.md: -------------------------------------------------------------------------------- 1 | # 安全 2 | 评估 Docker 的安全性时,主要考虑三个方面: 3 | * 由内核的名字空间和控制组机制提供的容器内在安全 4 | * Docker程序(特别是服务端)本身的抗攻击性 5 | * 内核安全性的加强机制对容器安全性的影响 6 | -------------------------------------------------------------------------------- /swarm/README.md: -------------------------------------------------------------------------------- 1 | # Docker Swarm 项目 2 | Docker Swarm 是 Docker 官方编排(Orchestration)项目之一,负责对 Docker 集群进行管理。 3 | 4 | 本章将介绍 Swarm 项目情况以及安装和使用。 5 | -------------------------------------------------------------------------------- /appendix_repo/README.md: -------------------------------------------------------------------------------- 1 | # 常见仓库介绍 2 | 本章将介绍常见的一些仓库和镜像的功能,使用方法和生成它们的 Dockerfile 等。包括 Ubuntu、CentOS、MySQL、MongoDB、Redis、Nginx、Wordpress、Node.js 等。 3 | -------------------------------------------------------------------------------- /compose/README.md: -------------------------------------------------------------------------------- 1 | # Docker Compose 项目 2 | Docker Compose 是 Docker 官方编排(Orchestration)项目之一,负责快速在集群中部署分布式应用。 3 | 4 | 本章将介绍 Compose 项目情况以及安装和使用。 5 | -------------------------------------------------------------------------------- /data_management/README.md: -------------------------------------------------------------------------------- 1 | # Docker 数据管理 2 | 这一章介绍如何在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式: 3 | * 数据卷(Data volumes) 4 | * 数据卷容器(Data volume containers) 5 | -------------------------------------------------------------------------------- /machine/README.md: -------------------------------------------------------------------------------- 1 | # Docker Machine 项目 2 | Docker Machine 是 Docker 官方编排(Orchestration)项目之一,负责在多种平台上快速安装 Docker 环境。 3 | 4 | 本章将介绍 Machine 项目情况以及安装和使用。 5 | -------------------------------------------------------------------------------- /basic_concept/README.md: -------------------------------------------------------------------------------- 1 | # 基本概念 2 | Docker 包括三个基本概念 3 | * 镜像(Image) 4 | * 容器(Container) 5 | * 仓库(Repository) 6 | 7 | 理解了这三个概念,就理解了 Docker 的整个生命周期。 8 | 9 | -------------------------------------------------------------------------------- /security/summary.md: -------------------------------------------------------------------------------- 1 | ## 总结 2 | 总体来看,Docker 容器还是十分安全的,特别是在容器内不使用 root 权限来运行进程的话。 3 | 4 | 另外,用户可以使用现有工具,比如 Apparmor, SELinux, GRSEC 来增强安全性;甚至自己在内核中实现更复杂的安全机制。 5 | -------------------------------------------------------------------------------- /container/README.md: -------------------------------------------------------------------------------- 1 | # Docker 容器 2 | 容器是 Docker 又一核心概念。 3 | 4 | 简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。 5 | 6 | 本章将具体介绍如何来管理一个容器,包括创建、启动和停止等。 7 | -------------------------------------------------------------------------------- /underly/container_format.md: -------------------------------------------------------------------------------- 1 | ## 容器格式 2 | 最初,Docker 采用了 LXC 中的容器格式。自 1.20 版本开始,Docker 也开始支持新的 [libcontainer](https://github.com/docker/libcontainer) 格式,并作为默认选项。 3 | 4 | 对更多容器格式的支持,还在进一步的发展中。 5 | -------------------------------------------------------------------------------- /advanced_network/config_file.md: -------------------------------------------------------------------------------- 1 | ## 编辑网络配置文件 2 | 3 | Docker 1.2.0 开始支持在运行中的容器里编辑 `/etc/hosts`, `/etc/hostname` 和 `/etc/resolve.conf` 文件。 4 | 5 | 但是这些修改是临时的,只在运行的容器中保留,容器终止或重启后并不会被保存下来。也不会被 `docker commit` 提交。 6 | -------------------------------------------------------------------------------- /container/rm.md: -------------------------------------------------------------------------------- 1 | ##删除容器 2 | 可以使用 `docker rm` 来删除一个处于终止状态的容器。 3 | 例如 4 | ``` 5 | $sudo docker rm trusting_newton 6 | trusting_newton 7 | ``` 8 | 如果要删除一个运行中的容器,可以添加 `-f` 参数。Docker 会发送 `SIGKILL` 信号给容器。 9 | 10 | -------------------------------------------------------------------------------- /basic_concept/image.md: -------------------------------------------------------------------------------- 1 | ## Docker 镜像 2 | Docker 镜像就是一个只读的模板。 3 | 4 | 例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。 5 | 6 | 镜像可以用来创建 Docker 容器。 7 | 8 | Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。 9 | -------------------------------------------------------------------------------- /basic_concept/container.md: -------------------------------------------------------------------------------- 1 | ## Docker 容器 2 | Docker 利用容器来运行应用。 3 | 4 | 容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。 5 | 6 | 可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。 7 | 8 | *注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。 9 | -------------------------------------------------------------------------------- /image/README.md: -------------------------------------------------------------------------------- 1 | # Docker 镜像 2 | 3 | 在之前的介绍中,我们知道镜像是 Docker 的三大组件之一。 4 | 5 | Docker 运行容器前需要本地存在对应的镜像,如果镜像不存在本地,Docker 会从镜像仓库下载(默认是 Docker Hub 公共注册服务器中的仓库)。 6 | 7 | 本章将介绍更多关于镜像的内容,包括: 8 | * 从仓库获取镜像; 9 | * 管理本地主机上的镜像; 10 | * 介绍镜像实现的基本原理。 11 | -------------------------------------------------------------------------------- /swarm/install.md: -------------------------------------------------------------------------------- 1 | ## 安装 2 | 安装swarm的最简单的方式是使用Docker官方的swarm镜像 3 | > $ sudo docker pull swarm 4 | 5 | 可以使用下面的命令来查看swarm是否成功安装。 6 | > $ sudo docker run --rm swarm -v 7 | 8 | 输出下面的形式则表示成功安装(具体输出根据swarm的版本变化) 9 | > swarm version 0.2.0 (48fd993) 10 | -------------------------------------------------------------------------------- /coreos/README.md: -------------------------------------------------------------------------------- 1 | #CoreOS 2 | 3 | CoreOS的设计是为你提供能够像谷歌一样的大型互联网公司一样的基础设施管理能力来动态扩展和管理的计算能力。 4 | 5 | CoreOS的安装文件和运行依赖非常小,它提供了精简的Linux系统。它使用Linux容器在更高的抽象层来管理你的服务,而不是通过常规的YUM和APT来安装包。 6 | 7 | 同时,CoreOS几乎可以运行在任何平台:Vagrant, Amazon EC2, QEMU/KVM, VMware 和 OpenStack 等等,甚至你所使用的硬件环境。 8 | 9 | -------------------------------------------------------------------------------- /underly/cgroups.md: -------------------------------------------------------------------------------- 1 | ## 控制组 2 | 3 | 控制组([cgroups](http://en.wikipedia.org/wiki/Cgroups))是 Linux 内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免当多个容器同时运行时的对系统资源的竞争。 4 | 5 | 控制组技术最早是由 Google 的程序员 2006 年起提出,Linux 内核自 2.6.24 开始支持。 6 | 7 | 控制组可以提供对容器的内存、CPU、磁盘 IO 等资源的限制和审计管理。 8 | 9 | 10 | -------------------------------------------------------------------------------- /repository/README.md: -------------------------------------------------------------------------------- 1 | # 仓库 2 | 3 | 仓库(Repository)是集中存放镜像的地方。 4 | 5 | 一个容易混淆的概念是注册服务器(Registry)。实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。从这方面来说,仓库可以被认为是一个具体的项目或目录。例如对于仓库地址 `dl.dockerpool.com/ubuntu` 来说,`dl.dockerpool.com` 是注册服务器地址,`ubuntu` 是仓库名。 6 | 7 | 大部分时候,并不需要严格区分这两者的概念。 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /image/internal.md: -------------------------------------------------------------------------------- 1 | ## 镜像的实现原理 2 | 3 | Docker 镜像是怎么实现增量的修改和维护的? 4 | 每个镜像都由很多层次构成,Docker 使用 [Union FS](http://en.wikipedia.org/wiki/UnionFS) 将这些不同的层结合到一个镜像中去。 5 | 6 | 通常 Union FS 有两个用途, 一方面可以实现不借助 LVM、RAID 将多个 disk 挂到同一个目录下,另一个更常用的就是将一个只读的分支和一个可写的分支联合在一起,Live CD 正是基于此方法可以允许在镜像不变的基础上允许用户在其上进行一些写操作。 7 | Docker 在 AUFS 上构建的容器也是利用了类似的原理。 8 | -------------------------------------------------------------------------------- /security/control_group.md: -------------------------------------------------------------------------------- 1 | ## 控制组 2 | 控制组是 Linux 容器机制的另外一个关键组件,负责实现资源的审计和限制。 3 | 4 | 它提供了很多有用的特性;以及确保各个容器可以公平地分享主机的内存、CPU、磁盘 IO 等资源;当然,更重要的是,控制组确保了当容器内的资源使用产生压力时不会连累主机系统。 5 | 6 | 尽管控制组不负责隔离容器之间相互访问、处理数据和进程,它在防止拒绝服务(DDOS)攻击方面是必不可少的。尤其是在多用户的平台(比如公有或私有的 PaaS)上,控制组十分重要。例如,当某些应用程序表现异常的时候,可以保证一致地正常运行和性能。 7 | 8 | 控制组机制始于 2006 年,内核从 2.6.24 版本开始被引入。 9 | -------------------------------------------------------------------------------- /underly/arch.md: -------------------------------------------------------------------------------- 1 | ## 基本架构 2 | Docker 采用了 C/S架构,包括客户端和服务端。 3 | Docker daemon 作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。 4 | 客户端和服务端既可以运行在一个机器上,也可通过 socket 或者 RESTful API 来进行通信。 5 | 6 | ![Docker 基本架构](../_images/docker_arch.png) 7 | 8 | 9 | Docker daemon 一般在宿主主机后台运行,等待接收来自客户端的消息。 10 | Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker daemon 交互。 11 | -------------------------------------------------------------------------------- /dockerfile/build_image.md: -------------------------------------------------------------------------------- 1 | ## 创建镜像 2 | 编写完成 Dockerfile 之后,可以通过 `docker build` 命令来创建镜像。 3 | 4 | 基本的格式为 `docker build [选项] 路径`,该命令将读取指定路径下(包括子目录)的 Dockerfile,并将该路径下所有内容发送给 Docker 服务端,由服务端来创建镜像。因此一般建议放置 Dockerfile 的目录为空目录。也可以通过 `.dockerignore` 文件(每一行添加一条匹配模式)来让 Docker 忽略路径下的目录和文件。 5 | 6 | 要指定镜像的标签信息,可以通过 `-t` 选项,例如 7 | ``` 8 | $ sudo docker build -t myrepo/myapp /tmp/test1/ 9 | ``` 10 | -------------------------------------------------------------------------------- /_local/pull_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script will update all local images 4 | # See: https://github.com/yeasy/docker_practice/blob/master/_local/pull_all.sh 5 | # Usage: pull_all 6 | # Author: yeasy@github 7 | # Create: 2014-09-23 8 | 9 | for image in `sudo docker images|grep -v "REPOSITORY"|grep -v ""|awk '{print $1":"$2}'` 10 | do 11 | sudo docker pull $image 12 | done 13 | 14 | -------------------------------------------------------------------------------- /advanced_network/example.md: -------------------------------------------------------------------------------- 1 | ## 工具和示例 2 | 在介绍自定义网络拓扑之前,你可能会对一些外部工具和例子感兴趣: 3 | 4 | ### pipework 5 | Jérôme Petazzoni 编写了一个叫 [pipework](https://github.com/jpetazzo/pipework) 的 shell 脚本,可以帮助用户在比较复杂的场景中完成容器的连接。 6 | 7 | ### playground 8 | Brandon Rhodes 创建了一个提供完整的 Docker 容器网络拓扑管理的 [Python库](https://github.com/brandon-rhodes/fopnp/tree/m/playground),包括路由、NAT 防火墙;以及一些提供 HTTP, SMTP, POP, IMAP, Telnet, SSH, FTP 的服务器。 9 | -------------------------------------------------------------------------------- /compose/intro.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | Compose 项目目前在 [Github](https://github.com/docker/compose) 上进行维护,目前最新版本是 1.2.0。 3 | 4 | Compose 定位是“defining and running complex applications with Docker”,前身是 Fig,兼容 Fig 的模板文件。 5 | 6 | Dockerfile 可以让用户管理一个单独的应用容器;而 Compose 则允许用户在一个模板(YAML 格式)中定义一组相关联的应用容器(被称为一个 `project`,即项目),例如一个 Web 服务容器再加上后端的数据库服务容器等。 7 | 8 | ![](../_images/compose.png) 9 | 10 | 该项目由 Python 编写,实际上调用了 Docker 提供的 API 来实现。 11 | -------------------------------------------------------------------------------- /appendix_resources/README.md: -------------------------------------------------------------------------------- 1 | # 资源链接 2 | * Docker 主站点: https://www.docker.io 3 | * Docker 注册中心API: http://docs.docker.com/reference/api/registry_api/ 4 | * Docker Hub API: http://docs.docker.com/reference/api/docker-io_api/ 5 | * Docker 远端应用API: http://docs.docker.com/reference/api/docker_remote_api/ 6 | * Dockerfile 参考:https://docs.docker.com/reference/builder/ 7 | * Dockerfile 最佳实践:https://docs.docker.com/articles/dockerfile_best-practices/ 8 | -------------------------------------------------------------------------------- /security/other_feature.md: -------------------------------------------------------------------------------- 1 | ## 其它安全特性 2 | 除了能力机制之外,还可以利用一些现有的安全机制来增强使用 Docker 的安全性,例如 TOMOYO, AppArmor, SELinux, GRSEC 等。 3 | 4 | Docker 当前默认只启用了能力机制。用户可以采用多种方案来加强 Docker 主机的安全,例如: 5 | * 在内核中启用 GRSEC 和 PAX,这将增加很多编译和运行时的安全检查;通过地址随机化避免恶意探测等。并且,启用该特性不需要 Docker 进行任何配置。 6 | * 使用一些有增强安全特性的容器模板,比如带 AppArmor 的模板和 Redhat 带 SELinux 策略的模板。这些模板提供了额外的安全特性。 7 | * 用户可以自定义访问控制机制来定制安全策略。 8 | 9 | 跟其它添加到 Docker 容器的第三方工具一样(比如网络拓扑和文件系统共享),有很多类似的机制,在不改变 Docker 内核情况下就可以加固现有的容器。 10 | -------------------------------------------------------------------------------- /image/rmi.md: -------------------------------------------------------------------------------- 1 | ## 移除本地镜像 2 | 如果要移除本地的镜像,可以使用 `docker rmi` 命令。注意 `docker rm` 命令是移除容器。 3 | ``` 4 | $ sudo docker rmi training/sinatra 5 | Untagged: training/sinatra:latest 6 | Deleted: 5bc342fa0b91cabf65246837015197eecfa24b2213ed6a51a8974ae250fedd8d 7 | Deleted: ed0fffdcdae5eb2c3a55549857a8be7fc8bc4241fb19ad714364cbfd7a56b22f 8 | Deleted: 5c58979d73ae448df5af1d8142436d81116187a7633082650549c52c3a2418f0 9 | ``` 10 | 11 | *注意:在删除镜像之前要先用 `docker rm` 删掉依赖于这个镜像的所有容器。 12 | -------------------------------------------------------------------------------- /_local/push_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This script will upload all local images to a registry server ($registry is the default value). 3 | # This script requires the push_images, which can be found at https://github.com/yeasy/docker_practice/blob/master/_local/push_images.sh 4 | # Usage: push_all 5 | # Author: yeasy@github 6 | # Create: 2014-09-23 7 | 8 | for image in `sudo docker images|grep -v "REPOSITORY"|grep -v ""|awk '{print $1":"$2}'` 9 | do 10 | push_images $image 11 | done 12 | 13 | -------------------------------------------------------------------------------- /kubernetes/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 2 | *注意:目前 Kubernetes 还处于 beta 状态,不推荐生产环境使用。部分概念和设计还可能会有后续调整。* 3 | 4 | Kubernetes 是 Google 团队发起并维护的基于Docker的开源容器集群管理系统,它不仅支持常见的云平台,而且支持内部数据中心。 5 | 6 | 建于 Docker 之上的 Kubernetes 可以构建一个容器的调度服务,其目的是让用户透过Kubernetes集群来进行云端容器集群的管理,而无需用户进行复杂的设置工作。系统会自动选取合适的工作节点来执行具体的容器集群调度处理工作。其核心概念是Container Pod(容器仓)。一个Pod是有一组工作于同一物理工作节点的容器构成的。这些组容器拥有相同的网络命名空间/IP以及存储配额,可以根据实际情况对每一个Pod进行端口映射。此外,Kubernetes工作节点会由主系统进行管理,节点包含了能够运行Docker容器所用到的服务。 7 | 8 | 本章将分为 5 节介绍 Kubernetes。包括 9 | * 项目简介 10 | * 快速入门 11 | * 基本概念 12 | * 实践例子 13 | * 架构分析等高级话题 14 | -------------------------------------------------------------------------------- /basic_concept/repository.md: -------------------------------------------------------------------------------- 1 | ## Docker 仓库 2 | 3 | 仓库是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。 4 | 5 | 仓库分为公开仓库(Public)和私有仓库(Private)两种形式。 6 | 7 | 最大的公开仓库是 [Docker Hub](https://hub.docker.com),存放了数量庞大的镜像供用户下载。 8 | 国内的公开仓库包括 [Docker Pool](http://www.dockerpool.com) 等,可以提供大陆用户更稳定快速的访问。 9 | 10 | 当然,用户也可以在本地网络内创建一个私有仓库。 11 | 12 | 当用户创建了自己的镜像之后就可以使用 `push` 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 `pull` 下来就可以了。 13 | 14 | *注:Docker 仓库的概念跟 [Git](http://git-scm.com) 类似,注册服务器可以理解为 GitHub 这样的托管服务。 15 | -------------------------------------------------------------------------------- /install/centos.md: -------------------------------------------------------------------------------- 1 | ## CentOS 系列安装 Docker 2 | 3 | Docker 支持 CentOS6 及以后的版本。 4 | 5 | ### CentOS6 6 | 对于 CentOS6,可以使用 [EPEL](https://fedoraproject.org/wiki/EPEL) 库安装 Docker,命令如下 7 | ``` 8 | $ sudo yum install http://mirrors.yun-idc.com/epel/6/i386/epel-release-6-8.noarch.rpm 9 | $ sudo yum install docker-io 10 | ``` 11 | 12 | ### CentOS7 13 | CentOS7 系统 `CentOS-Extras` 库中已带 Docker,可以直接安装: 14 | ``` 15 | $ sudo yum install docker 16 | ``` 17 | 18 | 安装之后启动 Docker 服务,并让它随系统启动自动加载。 19 | ``` 20 | $ sudo service docker start 21 | $ sudo chkconfig docker on 22 | ``` 23 | -------------------------------------------------------------------------------- /underly/ufs.md: -------------------------------------------------------------------------------- 1 | ## 联合文件系统 2 | 联合文件系统([UnionFS](http://en.wikipedia.org/wiki/UnionFS))是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。 3 | 4 | 联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。 5 | 6 | 另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。 7 | 8 | Docker 中使用的 AUFS(AnotherUnionFS)就是一种联合文件系统。 AUFS 支持为每一个成员目录(类似 Git 的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限, 同时 AUFS 里有一个类似分层的概念, 对只读权限的分支可以逻辑上进行增量地修改(不影响只读部分的)。 9 | 10 | Docker 目前支持的联合文件系统种类包括 AUFS, btrfs, vfs 和 DeviceMapper。 11 | -------------------------------------------------------------------------------- /image/save_load.md: -------------------------------------------------------------------------------- 1 | ## 存出和载入镜像 2 | 3 | ### 存出镜像 4 | 如果要导出镜像到本地文件,可以使用 `docker save` 命令。 5 | ``` 6 | $ sudo docker images 7 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 8 | ubuntu 14.04 c4ff7513909d 5 weeks ago 225.4 MB 9 | ... 10 | $sudo docker save -o ubuntu_14.04.tar ubuntu:14.04 11 | ``` 12 | 13 | ### 载入镜像 14 | 可以使用 `docker load` 从导出的本地文件中再导入到本地镜像库,例如 15 | ``` 16 | $ sudo docker load --input ubuntu_14.04.tar 17 | ``` 18 | 或 19 | ``` 20 | $ sudo docker load < ubuntu_14.04.tar 21 | ``` 22 | 这将导入镜像以及其相关的元数据信息(包括标签等)。 23 | -------------------------------------------------------------------------------- /cases/environment.md: -------------------------------------------------------------------------------- 1 | ## 标准化开发测试和生产环境 2 | 对于大部分企业来说,搭建 PaaS 既没有那个精力,也没那个必要,用 Docker 做个人的 sandbox 用处又小了点。 3 | 4 | 可以用 Docker 来标准化开发、测试、生产环境。 5 | 6 | 7 | ![企业应用结构](../_images/enterprise_usage.png) 8 | 9 | 10 | Docker 占用资源小,在一台 E5 128 G 内存的服务器上部署 100 个容器都绰绰有余,可以单独抽一个容器或者直接在宿主物理主机上部署 samba,利用 samba 的 home 分享方案将每个用户的 home 目录映射到开发中心和测试部门的 Windows 机器上。 11 | 12 | 针对某个项目组,由架构师搭建好一个标准的容器环境供项目组和测试部门使用,每个开发工程师可以拥有自己单独的容器,通过 `docker run -v` 将用户的 home 目录映射到容器中。需要提交测试时,只需要将代码移交给测试部门,然后分配一个容器使用 `-v` 加载测试部门的 home 目录启动即可。这样,在公司内部的开发、测试基本就统一了,不会出现开发部门提交的代码,测试部门部署不了的问题。 13 | 14 | 测试部门发布测试通过的报告后,架构师再一次检测容器环境,就可以直接交由部署工程师将代码和容器分别部署到生产环境中了。这种方式的部署横向性能的扩展性也极好。 15 | -------------------------------------------------------------------------------- /security/kernel_ns.md: -------------------------------------------------------------------------------- 1 | ## 内核名字空间 2 | Docker 容器和 LXC 容器很相似,所提供的安全特性也差不多。当用 `docker run` 启动一个容器时,在后台 Docker 为容器创建了一个独立的名字空间和控制组集合。 3 | 4 | 名字空间提供了最基础也是最直接的隔离,在容器中运行的进程不会被运行在主机上的进程和其它容器发现和作用。 5 | 6 | 每个容器都有自己独有的网络栈,意味着它们不能访问其他容器的 sockets 或接口。不过,如果主机系统上做了相应的设置,容器可以像跟主机交互一样的和其他容器交互。当指定公共端口或使用 links 来连接 2 个容器时,容器就可以相互通信了(可以根据配置来限制通信的策略)。 7 | 8 | 从网络架构的角度来看,所有的容器通过本地主机的网桥接口相互通信,就像物理机器通过物理交换机通信一样。 9 | 10 | 那么,内核中实现名字空间和私有网络的代码是否足够成熟? 11 | 12 | 内核名字空间从 2.6.15 版本(2008 年 7 月发布)之后被引入,数年间,这些机制的可靠性在诸多大型生产系统中被实践验证。 13 | 14 | 实际上,名字空间的想法和设计提出的时间要更早,最初是为了在内核中引入一种机制来实现 [OpenVZ](http://en.wikipedia.org/wiki/OpenVZ) 的特性。 15 | 而 OpenVZ 项目早在 2005 年就发布了,其设计和实现都已经十分成熟。 16 | -------------------------------------------------------------------------------- /kubernetes/intro.md: -------------------------------------------------------------------------------- 1 | # 项目简介 2 | 3 | ![](../_images/kubernetes_logo.svg) 4 | 5 | Kubernetes 是 Google 团队发起的开源项目,它的目标是管理跨多个主机的容器,提供基本的部署,维护以及运用伸缩,主要实现语言为Go语言。Kubernetes是: 6 | * 易学:轻量级,简单,容易理解 7 | * 便携:支持公有云,私有云,混合云,以及多种云平台 8 | * 可拓展:模块化,可插拔,支持钩子,可任意组合 9 | * 自修复:自动重调度,自动重启,自动复制 10 | 11 | Kubernetes构建于Google数十年经验,一大半来源于Google生产环境规模的经验。结合了社区最佳的想法和实践。 12 | 13 | 在分布式系统中,部署,调度,伸缩一直是最为重要的也最为基础的功能。Kubernets就是希望解决这一序列问题的。 14 | 15 | Kubernets 目前在[github.com/GoogleCloudPlatform/kubernetes](https://github.com/GoogleCloudPlatform/kubernetes)进行维护,截至定稿最新版本为 0.7.2 版本。 16 | 17 | ### Kubernetes 能够运行在任何地方! 18 | 19 | 虽然Kubernets最初是为GCE定制的,但是在后续版本中陆续增加了其他云平台的支持,以及本地数据中心的支持。 20 | -------------------------------------------------------------------------------- /data_management/management.md: -------------------------------------------------------------------------------- 1 | ## 利用数据卷容器来备份、恢复、迁移数据卷 2 | 可以利用数据卷对其中的数据进行进行备份、恢复和迁移。 3 | 4 | ### 备份 5 | 首先使用 `--volumes-from` 标记来创建一个加载 dbdata 容器卷的容器,并从本地主机挂载当前到容器的 /backup 目录。命令如下: 6 | ``` 7 | $ sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata 8 | ``` 9 | 容器启动后,使用了 `tar` 命令来将 dbdata 卷备份为本地的 `/backup/backup.tar`。 10 | 11 | 12 | ### 恢复 13 | 如果要恢复数据到一个容器,首先创建一个带有数据卷的容器 dbdata2。 14 | ``` 15 | $ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash 16 | ``` 17 | 然后创建另一个容器,挂载 dbdata2 的容器,并使用 `untar` 解压备份文件到挂载的容器卷中。 18 | ``` 19 | $ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf 20 | /backup/backup.tar 21 | ``` 22 | -------------------------------------------------------------------------------- /introduction/what.md: -------------------------------------------------------------------------------- 1 | ## 什么是 Docker 2 | Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 3 | 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 [GitHub](https://github.com/docker/docker) 上进行维护。 4 | 5 | Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用。 6 | 7 | Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 8 | Docker 的基础是 Linux 容器(LXC)等技术。 9 | 10 | 在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。 11 | 12 | 下面的图片比较了 Docker 和传统虚拟化方式的不同之处,可见容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。 13 | 14 | ![传统虚拟化](../_images/virtualization.png) 15 | 16 | ![Docker](../_images/docker.png) 17 | -------------------------------------------------------------------------------- /advanced_network/README.md: -------------------------------------------------------------------------------- 1 | # 高级网络配置 2 | 本章将介绍 Docker 的一些高级网络配置和选项。 3 | 4 | 当 Docker 启动时,会自动在主机上创建一个 `docker0` 虚拟网桥,实际上是 Linux 的一个 bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。 5 | 6 | 同时,Docker 随机分配一个本地未占用的私有网段(在 [RFC1918](http://tools.ietf.org/html/rfc1918) 中定义)中的一个地址给 `docker0` 接口。比如典型的 `172.17.42.1`,掩码为 `255.255.0.0`。此后启动的容器内的网口也会自动分配一个同一网段(`172.17.0.0/16`)的地址。 7 | 8 | 当创建一个 Docker 容器的时候,同时会创建了一对 `veth pair` 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 `eth0`;另一端在本地并被挂载到 `docker0` 网桥,名称以 `veth` 开头(例如 `vethAQI2QT`)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。 9 | 10 | ![Docker 网络](../_images/network.png) 11 | 12 | 接下来的部分将介绍在一些场景中,Docker 所有的网络定制配置。以及通过 Linux 命令来调整、补充、甚至替换 Docker 默认的网络配置。 13 | -------------------------------------------------------------------------------- /underly/README.md: -------------------------------------------------------------------------------- 1 | # 底层实现 2 | 3 | Docker 底层的核心技术包括 Linux 上的名字空间(Namespaces)、控制组(Control groups)、Union 文件系统(Union file systems)和容器格式(Container format)。 4 | 5 | 我们知道,传统的虚拟机通过在宿主主机中运行 hypervisor 来模拟一整套完整的硬件环境提供给虚拟机的操作系统。虚拟机系统看到的环境是可限制的,也是彼此隔离的。 6 | 这种直接的做法实现了对资源最完整的封装,但很多时候往往意味着系统资源的浪费。 7 | 例如,以宿主机和虚拟机系统都为 Linux 系统为例,虚拟机中运行的应用其实可以利用宿主机系统中的运行环境。 8 | 9 | 我们知道,在操作系统中,包括内核、文件系统、网络、PID、UID、IPC、内存、硬盘、CPU 等等,所有的资源都是应用进程直接共享的。 10 | 要想实现虚拟化,除了要实现对内存、CPU、网络IO、硬盘IO、存储空间等的限制外,还要实现文件系统、网络、PID、UID、IPC等等的相互隔离。 11 | 前者相对容易实现一些,后者则需要宿主机系统的深入支持。 12 | 13 | 随着 Linux 系统对于名字空间功能的完善实现,程序员已经可以实现上面的所有需求,让某些进程在彼此隔离的名字空间中运行。大家虽然都共用一个内核和某些运行时环境(例如一些系统命令和系统库),但是彼此却看不到,都以为系统中只有自己的存在。这种机制就是容器(Container),利用名字空间来做权限的隔离控制,利用 cgroups 来做资源分配。 14 | -------------------------------------------------------------------------------- /container/daemon.md: -------------------------------------------------------------------------------- 1 | ##守护态运行 2 | 3 | 更多的时候,需要让 Docker 容器在后台以守护态(Daemonized)形式运行。此时,可以通过添加 `-d` 参数来实现。 4 | 5 | 例如下面的命令会在后台运行容器。 6 | ``` 7 | $ sudo docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" 8 | 1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147 9 | ``` 10 | 11 | 容器启动后会返回一个唯一的 id,也可以通过 `docker ps` 命令来查看容器信息。 12 | ``` 13 | $ sudo docker ps 14 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 15 | 1e5535038e28 ubuntu:14.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute insane_babbage 16 | ``` 17 | 要获取容器的输出信息,可以通过 `docker logs` 命令。 18 | ``` 19 | $ sudo docker logs insane_babbage 20 | hello world 21 | hello world 22 | hello world 23 | . . . 24 | ``` 25 | -------------------------------------------------------------------------------- /appendix_repo/ubuntu.md: -------------------------------------------------------------------------------- 1 | ## [Ubuntu](https://registry.hub.docker.com/_/ubuntu/) 2 | 3 | ### 基本信息 4 | [Ubuntu](https://en.wikipedia.org/wiki/Ubuntu) 是流行的 Linux 发行版,其自带软件版本往往较新一些。 5 | 该仓库提供了 Ubuntu从12.04 ~ 14.10 各个版本的镜像。 6 | 7 | ### 使用方法 8 | 默认会启动一个最小化的 Ubuntu 环境。 9 | ``` 10 | $ sudo docker run --name some-ubuntu -i -t ubuntu 11 | root@523c70904d54:/# 12 | ``` 13 | 14 | ### Dockerfile 15 | * [12.04 版本](https://github.com/tianon/docker-brew-ubuntu-core/blob/2b105575647a7e2030ff344d427c3920b89e17a9/precise/Dockerfile) 16 | * [14.04 版本](https://github.com/tianon/docker-brew-ubuntu-core/blob/2b105575647a7e2030ff344d427c3920b89e17a9/trusty/Dockerfile) 17 | * [14.10 版本](https://github.com/tianon/docker-brew-ubuntu-core/blob/2b105575647a7e2030ff344d427c3920b89e17a9/utopic/Dockerfile) 18 | -------------------------------------------------------------------------------- /fig/env_ref.md: -------------------------------------------------------------------------------- 1 | ##环境变量参考 2 | 3 | *注意: 现在已经不推荐使用环境变量链接服务。替代方案是使用链接名称(默认就是被连接的服务名字)作为主机名来链接。详情查看 [fig.yml章节](./yml_ref.md)。 4 | 5 | Fig 使用 Docker 链接来暴露一个服务的容器给其它容器。每一个链接的容器会注入一组以容器名称的大写字母开头得环境变量。 6 | 7 | 查看一个服务有那些有效的环境变量可以执行 `fig run SERVICE env`。 8 | 9 | `name_PORT` 10 | 11 | 完整URL,例如: `DB_PORT=tcp://172.17.0.5:5432` 12 | 13 | `name_PORT_num_protocol` 14 | 15 | 完整URL,例如: `DB_PORT_5432_TCP=tcp://172.17.0.5:5432` 16 | 17 | `name_PORT_num_protocol_ADDR` 18 | 19 | 容器的IP地址,例如: `DB_PORT_5432_TCP_ADDR=172.17.0.5` 20 | 21 | `name_PORT_num_protocol_PORT` 22 | 23 | 暴露端口号,例如: `DB_PORT_5432_TCP_PORT=5432` 24 | 25 | `name_PORT_num_protocol_PROTO` 26 | 27 | 协议(tcp 或 udp),例如: `DB_PORT_5432_TCP_PROTO=tcp` 28 | 29 | `name_NAME` 30 | 31 | 完整合格的容器名称,例如: `DB_1_NAME=/myapp_web_1/myapp_db_1` 32 | -------------------------------------------------------------------------------- /swarm/intro.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | Swarm 是 Docker公司官方在 2014 年 12月初发布的一套管理 Docker 集群的工具。它将一群 Docker 宿主机变成一个单一的,虚拟的主机。 3 | 4 | Swarm 使用标准的 Docker API 接口作为其前端访问入口,换言之,各种形式的 Docker 工具比如 Dokku,Compose,Krane,Deis,docker-py,Docker 本身等都可以很容易的与 Swarm 进行集成。 5 | 6 | ![Swarm 结构图](../images/swarm.png) 7 | 8 | 在使用swarm管理docker集群时,会有一个swarm manager以及若干的swarm node,swarm manager上运行swarm daemon,用户只需要跟swarm manager通信,然后swarm manager再根据discovery service的信息选择一个swarm node来运行container。 9 | 10 | 值得注意的是swarm daemon只是一个任务调度器(scheduler)和路由器(router),它本身不运行容器,它只接受 Docker client 发送过来的请求,调度合适的 swarm node 来运行container。这意味着,即使 swarm daemon 由于某些原因挂掉了,已经运行起来的容器也不会有任何影响。 11 | 12 | 13 | 有以下两点需要注意: 14 | 15 | * 集群中的每台节点上面的 Docker 的版本都不能小于1.4 16 | * 为了让 swarm manager 能够跟每台 swarm node 进行通信,集群中的每台节点的 Docker daemon 都必须监听同一个网络接口。 17 | -------------------------------------------------------------------------------- /appendix_repo/centos.md: -------------------------------------------------------------------------------- 1 | ## [CentOS](https://registry.hub.docker.com/_/centos/) 2 | 3 | ### 基本信息 4 | [CentOS](https://en.wikipedia.org/wiki/CentOS) 是流行的 Linux 发行版,其软件包大多跟 RedHat 系列保持一致。 5 | 该仓库提供了 CentOS 从 5 ~ 7 各个版本的镜像。 6 | 7 | ### 使用方法 8 | 默认会启动一个最小化的 CentOS 环境。 9 | ``` 10 | $ sudo docker run --name some-centos -i -t centos bash 11 | bash-4.2# 12 | ``` 13 | 14 | ### Dockerfile 15 | * [CentOS 5 版本](https://github.com/CentOS/sig-cloud-instance-images/blob/2e5a9c4e8b7191b393822e4b9e98820db5638a77/docker/Dockerfile) 16 | * [CentOS 6 版本](https://github.com/CentOS/sig-cloud-instance-images/blob/8717e33ea5432ecb33d7ecefe8452a973715d037/docker/Dockerfile) 17 | * [CentOS 7 版本](https://github.com/CentOS/sig-cloud-instance-images/blob/af7a1b9f8f30744360a10fe44c53a1591bef26f9/docker/Dockerfile) 18 | -------------------------------------------------------------------------------- /container/stop.md: -------------------------------------------------------------------------------- 1 | ##终止容器 2 | 可以使用 `docker stop` 来终止一个运行中的容器。 3 | 4 | 此外,当Docker容器中指定的应用终结时,容器也自动终止。 5 | 例如对于上一章节中只启动了一个终端的容器,用户通过 `exit` 命令或 `Ctrl+d` 来退出终端时,所创建的容器立刻终止。 6 | 7 | 终止状态的容器可以用 `docker ps -a` 命令看到。例如 8 | ``` 9 | sudo docker ps -a 10 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 11 | ba267838cc1b ubuntu:14.04 "/bin/bash" 30 minutes ago Exited (0) About a minute ago trusting_newton 12 | 98e5efa7d997 training/webapp:latest "python app.py" About an hour ago Exited (0) 34 minutes ago backstabbing_pike 13 | ``` 14 | 15 | 处于终止状态的容器,可以通过 `docker start` 命令来重新启动。 16 | 17 | 此外,`docker restart` 命令会将一个运行态的容器终止,然后再重新启动它。 18 | -------------------------------------------------------------------------------- /data_management/container.md: -------------------------------------------------------------------------------- 1 | ## 数据卷容器 2 | 如果你有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。 3 | 4 | 数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。 5 | 6 | 首先,创建一个命名的数据卷容器 dbdata: 7 | ``` 8 | $ sudo docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres 9 | ``` 10 | 然后,在其他容器中使用 `--volumes-from` 来挂载 dbdata 容器中的数据卷。 11 | ``` 12 | $ sudo docker run -d --volumes-from dbdata --name db1 training/postgres 13 | $ sudo docker run -d --volumes-from dbdata --name db2 training/postgres 14 | ``` 15 | 还可以使用多个 `--volumes-from` 参数来从多个容器挂载多个数据卷。 16 | 也可以从其他已经挂载了数据卷的容器来挂载数据卷。 17 | ``` 18 | $ sudo docker run -d --name db3 --volumes-from db1 training/postgres 19 | ``` 20 | *注意:使用 `--volumes-from` 参数所挂载数据卷的容器自己并不需要保持在运行状态。 21 | 22 | 如果删除了挂载的容器(包括 dbdata、db1 和 db2),数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时使用 `docker rm -v` 命令来指定同时删除关联的容器。 23 | 这可以让用户在容器之间升级和移动数据卷。具体的操作将在下一节中进行讲解。 24 | -------------------------------------------------------------------------------- /fig/install.md: -------------------------------------------------------------------------------- 1 | ##安装 Fig 2 | 3 | 首先,安装 1.3 或者更新的 Docker 版本。 4 | 5 | 如果你的工作环境是 OS X ,可以通过查看 [Mac 安装指南(英文)](https://docs.docker.com/installation/mac/) ,完成安装 Docker 和 boot2docker 。一旦 boot2docker 运行后,执行以下指令设置一个环境变量,接着 Fig 就可以和它交互了。 6 | 7 | ``` 8 | $(boot2docker shellinit) 9 | ``` 10 | **如果想避免重启后重新设置,可以把上面的命令加到你的 ` ~/.bashrc` 文件里。* 11 | 12 | 关于 `Ubuntu` 还有 `其它的平台` 的安装,可以参照 [Ubuntu 安装指南(中文)](../install/ubuntu.md) 以及 [官方安装手册(英文)](https://docs.docker.com/installation/)。 13 | 14 | 15 | 下一步,安装 Fig : 16 | 17 | ``` 18 | curl -L https://github.com/docker/fig/releases/download/1.0.1/fig-`uname -s`-`uname -m` > /usr/local/bin/fig; chmod +x /usr/local/bin/fig 19 | ``` 20 | **如果你的 Docker 是管理员身份安装,以上命令可能也需要相同的身份。* 21 | 22 | 目前 Fig 的发行版本只支持 OSX 和 64 位的 Linux 系统。但因为它是用 Python 语言写的,所以对于其它平台上的用户,可以通过 Python 安装包来完成安装(支持的系统同样适用)。 23 | 24 | ``` 25 | $ sudo pip install -U fig 26 | ``` 27 | 到这里就已经完成了。 执行 `fig --version` ,确认能够正常运行。 28 | 29 | -------------------------------------------------------------------------------- /etcd/intro.md: -------------------------------------------------------------------------------- 1 | ## 什么是 etcd 2 | 3 | ![](../_images/etcd_logo.png) 4 | 5 | etcd 是 CoreOS 团队于 2013 年 6 月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库,基于 Go 语言实现。我们知道,在分布式系统中,各种服务的配置信息的管理分享,服务的发现是一个很基本同时也是很重要的问题。CoreOS 项目就希望基于 etcd 来解决这一问题。 6 | 7 | etcd 目前在 [github.com/coreos/etcd](https://github.com/coreos/etcd) 进行维护,即将发布 2.0.0 版本。 8 | 9 | 受到 [Apache ZooKeeper](http://zookeeper.apache.org/) 项目和 [doozer](https://github.com/ha/doozerd) 项目的启发,etcd 在设计的时候重点考虑了下面四个要素: 10 | * 简单:支持 REST 风格的 HTTP+JSON API 11 | * 安全:支持 HTTPS 方式的访问 12 | * 快速:支持并发 1k/s 的写操作 13 | * 可靠:支持分布式结构,基于 Raft 的一致性算法 14 | 15 | *注:Apache ZooKeeper 是一套知名的分布式系统中进行同步和一致性管理的工具。* 16 | *注:doozer 则是一个一致性分布式数据库。* 17 | *注:Raft 是一套通过选举主节点来实现分布式系统一致性的算法,相比于大名鼎鼎的 Paxos 算法,它的过程更容易被人理解,由 Stanford 大学的 Diego Ongaro 和 John Ousterhout 提出。更多细节可以参考 [raftconsensus.github.io](http://raftconsensus.github.io)。* 18 | 19 | 一般情况下,用户使用 etcd 可以在多个节点上启动多个实例,并添加它们为一个集群。同一个集群中的 etcd 实例将会保持彼此信息的一致性。 20 | -------------------------------------------------------------------------------- /appendix_repo/mysql.md: -------------------------------------------------------------------------------- 1 | ## [MySQL](https://registry.hub.docker.com/_/mysql/) 2 | 3 | ### 基本信息 4 | [MySQL](https://en.wikipedia.org/wiki/MySQL) 是开源的关系数据库实现。 5 | 该仓库提供了 MySQL 各个版本的镜像,包括 5.6 系列、5.7 系列等。 6 | 7 | ### 使用方法 8 | 默认会在 `3306` 端口启动数据库。 9 | ``` 10 | $ sudo docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=mysecretpassword -d mysql 11 | ``` 12 | 之后就可以使用其它应用来连接到该容器。 13 | ``` 14 | $ sudo docker run --name some-app --link some-mysql:mysql -d application-that-uses-mysql 15 | ``` 16 | 或者通过 `mysql`。 17 | ``` 18 | $ sudo docker run -it --link some-mysql:mysql --rm mysql sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"' 19 | ``` 20 | 21 | ### Dockerfile 22 | * [5.6 版本](https://github.com/docker-library/mysql/blob/7461a52b43f06839a4d8723ae8841f4cb616b3d0/5.6/Dockerfile) 23 | * [5.7 版本](https://github.com/docker-library/mysql/blob/7461a52b43f06839a4d8723ae8841f4cb616b3d0/5.7/Dockerfile) 24 | -------------------------------------------------------------------------------- /advanced_network/quick_guide.md: -------------------------------------------------------------------------------- 1 | ## 快速配置指南 2 | 3 | 下面是一个跟 Docker 网络相关的命令列表。 4 | 5 | 其中有些命令选项只有在 Docker 服务启动的时候才能配置,而且不能马上生效。 6 | * `-b BRIDGE or --bridge=BRIDGE` --指定容器挂载的网桥 7 | * `--bip=CIDR` --定制 docker0 的掩码 8 | * `-H SOCKET... or --host=SOCKET...` --Docker 服务端接收命令的通道 9 | * `--icc=true|false` --是否支持容器之间进行通信 10 | * `--ip-forward=true|false` --请看下文容器之间的通信 11 | * `--iptables=true|false` --禁止 Docker 添加 iptables 规则 12 | * `--mtu=BYTES` --容器网络中的 MTU 13 | 14 | 下面2个命令选项既可以在启动服务时指定,也可以 Docker 容器启动(`docker run`)时候指定。在 Docker 服务启动的时候指定则会成为默认值,后面执行 `docker run` 时可以覆盖设置的默认值。 15 | * `--dns=IP_ADDRESS...` --使用指定的DNS服务器 16 | * `--dns-search=DOMAIN...` --指定DNS搜索域 17 | 18 | 最后这些选项只有在 `docker run` 执行时使用,因为它是针对容器的特性内容。 19 | * `-h HOSTNAME or --hostname=HOSTNAME` --配置容器主机名 20 | * `--link=CONTAINER_NAME:ALIAS` --添加到另一个容器的连接 21 | * `--net=bridge|none|container:NAME_or_ID|host` --配置容器的桥接模式 22 | * `-p SPEC or --publish=SPEC` --映射容器端口到宿主主机 23 | * `-P or --publish-all=true|false` --映射容器所有端口到宿主主机 24 | -------------------------------------------------------------------------------- /image/list.md: -------------------------------------------------------------------------------- 1 | ## 列出本地镜像 2 | 使用 `docker images` 显示本地已有的镜像。 3 | ``` 4 | $ sudo docker images 5 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 6 | ubuntu 12.04 74fe38d11401 4 weeks ago 209.6 MB 7 | ubuntu precise 74fe38d11401 4 weeks ago 209.6 MB 8 | ubuntu 14.04 99ec81b80c55 4 weeks ago 266 MB 9 | ubuntu latest 99ec81b80c55 4 weeks ago 266 MB 10 | ubuntu trusty 99ec81b80c55 4 weeks ago 266 MB 11 | ... 12 | ``` 13 | 14 | 在列出信息中,可以看到几个字段信息 15 | 16 | * 来自于哪个仓库,比如 ubuntu 17 | * 镜像的标记,比如 14.04 18 | * 它的 `ID` 号(唯一) 19 | * 创建时间 20 | * 镜像大小 21 | 22 | 其中镜像的 `ID` 唯一标识了镜像,注意到 `ubuntu:14.04` 和 `ubuntu:trusty` 具有相同的镜像 `ID`,说明它们实际上是同一镜像。 23 | 24 | `TAG` 信息用来标记来自同一个仓库的不同镜像。例如 `ubuntu` 仓库中有多个镜像,通过 `TAG` 信息来区分发行版本,例如 `10.04`、`12.04`、`12.10`、`13.04`、`14.04` 等。例如下面的命令指定使用镜像 `ubuntu:14.04` 来启动一个容器。 25 | ``` 26 | $ sudo docker run -t -i ubuntu:14.04 /bin/bash 27 | ``` 28 | 29 | 如果不指定具体的标记,则默认使用 `latest` 标记信息。 30 | -------------------------------------------------------------------------------- /appendix_repo/wordpress.md: -------------------------------------------------------------------------------- 1 | ## [WordPress](https://registry.hub.docker.com/_/wordpress/) 2 | 3 | ### 基本信息 4 | [WordPress](https://en.wikipedia.org/wiki/WordPress) 是开源的 Blog 和内容管理系统框架,它基于 PhP 和 MySQL。 5 | 该仓库提供了 WordPress 4.0 版本的镜像。 6 | 7 | ### 使用方法 8 | 启动容器需要 MySQL 的支持,默认端口为 `80`。 9 | ``` 10 | $ sudo docker run --name some-wordpress --link some-mysql:mysql -d wordpress 11 | ``` 12 | 启动 WordPress 容器时可以指定的一些环境参数包括 13 | * `-e WORDPRESS_DB_USER=...` 缺省为 “root” 14 | * `-e WORDPRESS_DB_PASSWORD=...` 缺省为连接 mysql 容器的环境变量 `MYSQL_ROOT_PASSWORD` 的值 15 | * `-e WORDPRESS_DB_NAME=...` 缺省为 “wordpress” 16 | * `-e WORDPRESS_AUTH_KEY=...`, `-e WORDPRESS_SECURE_AUTH_KEY=...`, `-e WORDPRESS_LOGGED_IN_KEY=...`, `-e WORDPRESS_NONCE_KEY=...`, `-e WORDPRESS_AUTH_SALT=...`, `-e WORDPRESS_SECURE_AUTH_SALT=...`, `-e WORDPRESS_LOGGED_IN_SALT=...`, `-e WORDPRESS_NONCE_SALT=...` 缺省为随机 sha1 串 17 | 18 | ### Dockerfile 19 | * [4.0 版本](https://github.com/docker-library/wordpress/blob/aee00669e7c43f435f021cb02871bffd63d5677a/Dockerfile) 20 | -------------------------------------------------------------------------------- /advanced_network/bridge.md: -------------------------------------------------------------------------------- 1 | ## 自定义网桥 2 | 除了默认的 `docker0` 网桥,用户也可以指定网桥来连接各个容器。 3 | 4 | 在启动 Docker 服务的时候,使用 `-b BRIDGE`或`--bridge=BRIDGE` 来指定使用的网桥。 5 | 6 | 如果服务已经运行,那需要先停止服务,并删除旧的网桥。 7 | ``` 8 | $ sudo service docker stop 9 | $ sudo ip link set dev docker0 down 10 | $ sudo brctl delbr docker0 11 | ``` 12 | 然后创建一个网桥 `bridge0`。 13 | ``` 14 | $ sudo brctl addbr bridge0 15 | $ sudo ip addr add 192.168.5.1/24 dev bridge0 16 | $ sudo ip link set dev bridge0 up 17 | ``` 18 | 查看确认网桥创建并启动。 19 | ``` 20 | $ ip addr show bridge0 21 | 4: bridge0: mtu 1500 qdisc noop state UP group default 22 | link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff 23 | inet 192.168.5.1/24 scope global bridge0 24 | valid_lft forever preferred_lft forever 25 | ``` 26 | 配置 Docker 服务,默认桥接到创建的网桥上。 27 | ``` 28 | $ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker 29 | $ sudo service docker start 30 | ``` 31 | 启动 Docker 服务。 32 | 新建一个容器,可以看到它已经桥接到了 `bridge0` 上。 33 | 34 | 可以继续用 `brctl show` 命令查看桥接的信息。另外,在容器中可以使用 `ip addr` 和 `ip route` 命令来查看 IP 地址配置和路由信息。 35 | -------------------------------------------------------------------------------- /advanced_network/dns.md: -------------------------------------------------------------------------------- 1 | ## 配置 DNS 2 | Docker 没有为每个容器专门定制镜像,那么怎么自定义配置容器的主机名和 DNS 配置呢? 3 | 秘诀就是它利用虚拟文件来挂载到来容器的 3 个相关配置文件。 4 | 5 | 在容器中使用 mount 命令可以看到挂载信息: 6 | ``` 7 | $ mount 8 | ... 9 | /dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ... 10 | /dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ... 11 | tmpfs on /etc/resolv.conf type tmpfs ... 12 | ... 13 | ``` 14 | 这种机制可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 dns 配置通过 `/etc/resolv.conf` 文件立刻得到更新。 15 | 16 | 如果用户想要手动指定容器的配置,可以利用下面的选项。 17 | 18 | `-h HOSTNAME or --hostname=HOSTNAME` 19 | 设定容器的主机名,它会被写到容器内的 `/etc/hostname` 和 `/etc/hosts`。但它在容器外部看不到,既不会在 `docker ps` 中显示,也不会在其他的容器的 `/etc/hosts` 看到。 20 | 21 | `--link=CONTAINER_NAME:ALIAS` 22 | 选项会在创建容器的时候,添加一个其他容器的主机名到 `/etc/hosts` 文件中,让新容器的进程可以使用主机名 ALIAS 就可以连接它。 23 | 24 | `--dns=IP_ADDRESS` 25 | 添加 DNS 服务器到容器的 `/etc/resolv.conf` 中,让容器用这个服务器来解析所有不在 `/etc/hosts` 中的主机名。 26 | 27 | `--dns-search=DOMAIN` 28 | 设定容器的搜索域,当设定搜索域为 `.example.com` 时,在搜索一个名为 host 的主机时,DNS 不仅搜索host,还会搜索 `host.example.com`。 29 | 注意:如果没有上述最后 2 个选项,Docker 会默认用主机上的 `/etc/resolv.conf` 来配置容器。 30 | -------------------------------------------------------------------------------- /introduction/why.md: -------------------------------------------------------------------------------- 1 | ## 为什么要使用 Docker? 2 | 作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。 3 | 4 | 首先,Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 5 | 其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。 6 | 7 | 容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。 8 | 9 | 具体说来,Docker 在如下几个方面具有较大的优势。 10 | 11 | ### 更快速的交付和部署 12 | 对开发和运维(devop)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。 13 | 14 | 开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。 15 | Docker 可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。 16 | Docker 容器很轻很快!容器的启动时间是秒级的,大量地节约开发、测试、部署的时间。 17 | 18 | ### 更高效的虚拟化 19 | Docker 容器的运行不需要额外的 hypervisor 支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。 20 | 21 | ### 更轻松的迁移和扩展 22 | 23 | Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 24 | 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。 25 | 26 | ### 更简单的管理 27 | 使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。 28 | 29 | ### 对比传统虚拟机总结 30 | | 特性 | 容器 | 虚拟机 | 31 | | -- | -- | -- | 32 | | 启动 | 秒级 | 分钟级 | 33 | | 硬盘使用 | 一般为 MB | 一般为 GB | 34 | | 性能 | 接近原生 | 弱于 | 35 | | 系统支持量 | 单机支持上千个容器 | 一般几十个 | 36 | -------------------------------------------------------------------------------- /security/daemon_sec.md: -------------------------------------------------------------------------------- 1 | ## Docker服务端的防护 2 | 运行一个容器或应用程序的核心是通过 Docker 服务端。Docker 服务的运行目前需要 root 权限,因此其安全性十分关键。 3 | 4 | 首先,确保只有可信的用户才可以访问 Docker 服务。Docker 允许用户在主机和容器间共享文件夹,同时不需要限制容器的访问权限,这就容易让容器突破资源限制。例如,恶意用户启动容器的时候将主机的根目录`/`映射到容器的 `/host` 目录中,那么容器理论上就可以对主机的文件系统进行任意修改了。这听起来很疯狂?但是事实上几乎所有虚拟化系统都允许类似的资源共享,而没法禁止用户共享主机根文件系统到虚拟机系统。 5 | 6 | 这将会造成很严重的安全后果。因此,当提供容器创建服务时(例如通过一个 web 服务器),要更加注意进行参数的安全检查,防止恶意的用户用特定参数来创建一些破坏性的容器 7 | 8 | 为了加强对服务端的保护,Docker 的 REST API(客户端用来跟服务端通信)在 0.5.2 之后使用本地的 Unix 套接字机制替代了原先绑定在 127.0.0.1 上的 TCP 套接字,因为后者容易遭受跨站脚本攻击。现在用户使用 Unix 权限检查来加强套接字的访问安全。 9 | 10 | 用户仍可以利用 HTTP 提供 REST API 访问。建议使用安全机制,确保只有可信的网络或 VPN,或证书保护机制(例如受保护的 stunnel 和 ssl 认证)下的访问可以进行。此外,还可以使用 HTTPS 和证书来加强保护。 11 | 12 | 最近改进的 Linux 名字空间机制将可以实现使用非 root 用户来运行全功能的容器。这将从根本上解决了容器和主机之间共享文件系统而引起的安全问题。 13 | 14 | 终极目标是改进 2 个重要的安全特性: 15 | * 将容器的 root 用户映射到本地主机上的非 root 用户,减轻容器和主机之间因权限提升而引起的安全问题; 16 | * 允许 Docker 服务端在非 root 权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程将只允许在限定范围内进行操作,例如仅仅负责虚拟网络设定或文件系统管理、配置操作等。 17 | 18 | 最后,建议采用专用的服务器来运行 Docker 和相关的管理服务(例如管理服务比如 ssh 监控和进程监控、管理工具 nrpe、collectd 等)。其它的业务服务都放到容器中去运行。 19 | -------------------------------------------------------------------------------- /appendix_repo/nodejs.md: -------------------------------------------------------------------------------- 1 | ## [Node.js](https://registry.hub.docker.com/_/node/) 2 | 3 | ### 基本信息 4 | [Node.js](https://en.wikipedia.org/wiki/Node.js)是基于 JavaScript 的可扩展服务端和网络软件开发平台。 5 | 该仓库提供了 Node.js 0.8 ~ 0.11 各个版本的镜像。 6 | 7 | ### 使用方法 8 | 在项目中创建一个 Dockerfile。 9 | ``` 10 | FROM node:0.10-onbuild 11 | # replace this with your application's default port 12 | EXPOSE 8888 13 | ``` 14 | 然后创建镜像,并启动容器 15 | ``` 16 | $ sudo docker build -t my-nodejs-app 17 | $ sudo docker run -it --rm --name my-running-app my-nodejs-app 18 | ``` 19 | 20 | 也可以直接运行一个简单容器。 21 | ``` 22 | $ sudo docker run -it --rm --name my-running-script -v "$(pwd)":/usr/src/myapp -w /usr/src/myapp node:0.10 node your-daemon-or-script.js 23 | ``` 24 | 25 | ### Dockerfile 26 | * [0.8 版本](https://github.com/docker-library/node/blob/d017d679e92e84a810c580cdb29fcdbba23c2bb9/0.8/Dockerfile) 27 | * [0.10 版本](https://github.com/docker-library/node/blob/913a225f2fda34d6a811fac1466e4f09f075fcf6/0.10/Dockerfile) 28 | * [0.11 版本](https://github.com/docker-library/node/blob/d017d679e92e84a810c580cdb29fcdbba23c2bb9/0.11/Dockerfile) 29 | -------------------------------------------------------------------------------- /appendix_repo/mongodb.md: -------------------------------------------------------------------------------- 1 | ## [MongoDB](https://registry.hub.docker.com/_/mongo/) 2 | 3 | ### 基本信息 4 | [MongoDB](https://en.wikipedia.org/wiki/MongoDB) 是开源的 NoSQL 数据库实现。 5 | 该仓库提供了 MongoDB 2.2 ~ 2.7 各个版本的镜像。 6 | 7 | ### 使用方法 8 | 默认会在 `27017` 端口启动数据库。 9 | ``` 10 | $ sudo docker run --name some-mongo -d mongo 11 | ``` 12 | 13 | 使用其他应用连接到容器,可以用 14 | ``` 15 | $ sudo docker run --name some-app --link some-mongo:mongo -d application-that-uses-mongo 16 | ``` 17 | 或者通过 `mongo` 18 | ``` 19 | $ sudo docker run -it --link some-mongo:mongo --rm mongo sh -c 'exec mongo "$MONGO_PORT_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/test"' 20 | ``` 21 | 22 | ### Dockerfile 23 | * [2.2 版本](https://github.com/docker-library/mongo/blob/77c841472ccb6cc87fea1218269d097405edc6cb/2.2/Dockerfile) 24 | * [2.4 版本](https://github.com/docker-library/mongo/blob/807078cb7b5f0289f6dabf9f6875d5318122bc30/2.4/Dockerfile) 25 | * [2.6 版本](https://github.com/docker-library/mongo/blob/77c841472ccb6cc87fea1218269d097405edc6cb/2.6/Dockerfile) 26 | * [2.7 版本](https://github.com/docker-library/mongo/blob/807078cb7b5f0289f6dabf9f6875d5318122bc30/2.7/Dockerfile) 27 | -------------------------------------------------------------------------------- /appendix_repo/nginx.md: -------------------------------------------------------------------------------- 1 | ## [Nginx](https://registry.hub.docker.com/_/nginx/) 2 | 3 | ### 基本信息 4 | [Nginx](https://en.wikipedia.org/wiki/Nginx) 是开源的高效的 Web 服务器实现,支持 HTTP、HTTPS、SMTP、POP3、IMAP 等协议。 5 | 该仓库提供了 Nginx 1.0 ~ 1.7 各个版本的镜像。 6 | 7 | ### 使用方法 8 | 下面的命令将作为一个静态页面服务器启动。 9 | ``` 10 | $ sudo docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -d nginx 11 | ``` 12 | 用户也可以不使用这种映射方式,通过利用 Dockerfile 来直接将静态页面内容放到镜像中,内容为 13 | ``` 14 | FROM nginx 15 | COPY static-html-directory /usr/share/nginx/html 16 | ``` 17 | 之后生成新的镜像,并启动一个容器。 18 | ``` 19 | $ sudo docker build -t some-content-nginx . 20 | $ sudo docker run --name some-nginx -d some-content-nginx 21 | ``` 22 | 开放端口,并映射到本地的 `8080` 端口。 23 | ``` 24 | sudo docker run --name some-nginx -d -p 8080:80 some-content-nginx 25 | ``` 26 | 27 | Nginx的默认配置文件路径为 `/etc/nginx/nginx.conf`,可以通过映射它来使用本地的配置文件,例如 28 | ``` 29 | docker run --name some-nginx -v /some/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx 30 | ``` 31 | 使用配置文件时,为了在容器中正常运行,需要保持 `daemon off;`。 32 | 33 | ### Dockerfile 34 | * [1 ~ 1.7 版本](https://github.com/nginxinc/docker-nginx/blob/3713a0157083eb4776e71f5a5aef4b2a5bc03ab1/Dockerfile) 35 | -------------------------------------------------------------------------------- /container/import_export.md: -------------------------------------------------------------------------------- 1 | ##导出和导入容器 2 | 3 | ###导出容器 4 | 如果要导出本地某个容器,可以使用 `docker export` 命令。 5 | ``` 6 | $ sudo docker ps -a 7 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8 | 7691a814370e ubuntu:14.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test 9 | $ sudo docker export 7691a814370e > ubuntu.tar 10 | ``` 11 | 这样将导出容器快照到本地文件。 12 | 13 | ###导入容器快照 14 | 可以使用 `docker import` 从容器快照文件中再导入为镜像,例如 15 | ``` 16 | $ cat ubuntu.tar | sudo docker import - test/ubuntu:v1.0 17 | $ sudo docker images 18 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 19 | test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB 20 | ``` 21 | 此外,也可以通过指定 URL 或者某个目录来导入,例如 22 | ``` 23 | $sudo docker import http://example.com/exampleimage.tgz example/imagerepo 24 | ``` 25 | 26 | *注:用户既可以使用 `docker load` 来导入镜像存储文件到本地镜像库,也可以使用 `docker import` 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。 27 | 28 | 29 | -------------------------------------------------------------------------------- /appendix_repo/redis.md: -------------------------------------------------------------------------------- 1 | ## [Redis](https://registry.hub.docker.com/_/redis/) 2 | 3 | ### 基本信息 4 | [Redis](https://en.wikipedia.org/wiki/Redis) 是开源的内存 Key-Value 数据库实现。 5 | 该仓库提供了 Redis 2.6 ~ 2.8.9 各个版本的镜像。 6 | 7 | ### 使用方法 8 | 默认会在 `6379` 端口启动数据库。 9 | ``` 10 | $ sudo docker run --name some-redis -d redis 11 | ``` 12 | 另外还可以启用 [持久存储](http://redis.io/topics/persistence)。 13 | ``` 14 | $ sudo docker run --name some-redis -d redis redis-server --appendonly yes 15 | ``` 16 | 默认数据存储位置在 `VOLUME/data`。可以使用 `--volumes-from some-volume-container` 或 `-v /docker/host/dir:/data` 将数据存放到本地。 17 | 18 | 使用其他应用连接到容器,可以用 19 | ``` 20 | $ sudo docker run --name some-app --link some-redis:redis -d application-that-uses-redis 21 | ``` 22 | 或者通过 `redis-cli` 23 | ``` 24 | $ sudo docker run -it --link some-redis:redis --rm redis sh -c 'exec redis-cli -h "$REDIS_PORT_6379_TCP_ADDR" -p "$REDIS_PORT_6379_TCP_PORT"' 25 | ``` 26 | 27 | ### Dockerfile 28 | * [2.6 版本](https://github.com/docker-library/redis/blob/02d9cd887a4e0d50db4bb085eab7235115a6fe4a/2.6.17/Dockerfile) 29 | * [最新 2.8 版本](https://github.com/docker-library/redis/blob/d0665bb1bbddd4cc035dbc1fc774695fa534d648/2.8.13/Dockerfile) 30 | -------------------------------------------------------------------------------- /install/ubuntu.md: -------------------------------------------------------------------------------- 1 | ## Ubuntu 系列安装 Docker 2 | 3 | ### 通过系统自带包安装 4 | Ubuntu 14.04 版本系统中已经自带了 Docker 包,可以直接安装。 5 | ``` 6 | $ sudo apt-get update 7 | $ sudo apt-get install -y docker.io 8 | $ sudo ln -sf /usr/bin/docker.io /usr/local/bin/docker 9 | $ sudo sed -i '$acomplete -F _docker docker' /etc/bash_completion.d/docker.io 10 | ``` 11 | 12 | 如果使用操作系统自带包安装 Docker,目前安装的版本是比较旧的 0.9.1。 要安装更新的版本,可以通过使用 Docker 源的方式。 13 | 14 | ### 通过Docker源安装最新版本 15 | 要安装最新的 Docker 版本,首先需要安装 apt-transport-https 支持,之后通过添加源来安装。 16 | ``` 17 | $ sudo apt-get install apt-transport-https 18 | $ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 19 | $ sudo bash -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list" 20 | $ sudo apt-get update 21 | $ sudo apt-get install lxc-docker 22 | ``` 23 | 24 | ### 14.04 之前版本 25 | 如果是较低版本的 Ubuntu 系统,需要先更新内核。 26 | ``` 27 | $ sudo apt-get update 28 | $ sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring 29 | $ sudo reboot 30 | ``` 31 | 然后重复上面的步骤即可。 32 | 33 | 安装之后启动 Docker 服务。 34 | ``` 35 | $ sudo service docker start 36 | ``` 37 | -------------------------------------------------------------------------------- /security/kernel_capability.md: -------------------------------------------------------------------------------- 1 | ## 内核能力机制 2 | 3 | 能力机制(Capability)是 Linux 内核一个强大的特性,可以提供细粒度的权限访问控制。 4 | Linux 内核自 2.2 版本起就支持能力机制,它将权限划分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上。 5 | 6 | 例如,一个 Web 服务进程只需要绑定一个低于 1024 的端口的权限,并不需要 root 权限。那么它只需要被授权 `net_bind_service` 能力即可。此外,还有很多其他的类似能力来避免进程获取 root 权限。 7 | 8 | 默认情况下,Docker 启动的容器被严格限制只允许使用内核的一部分能力。 9 | 10 | 使用能力机制对加强 Docker 容器的安全有很多好处。通常,在服务器上会运行一堆需要特权权限的进程,包括有 ssh、cron、syslogd、硬件管理工具模块(例如负载模块)、网络配置工具等等。容器跟这些进程是不同的,因为几乎所有的特权进程都由容器以外的支持系统来进行管理。 11 | * ssh 访问被主机上ssh服务来管理; 12 | * cron 通常应该作为用户进程执行,权限交给使用它服务的应用来处理; 13 | * 日志系统可由 Docker 或第三方服务管理; 14 | * 硬件管理无关紧要,容器中也就无需执行 udevd 以及类似服务; 15 | * 网络管理也都在主机上设置,除非特殊需求,容器不需要对网络进行配置。 16 | 17 | 从上面的例子可以看出,大部分情况下,容器并不需要“真正的” root 权限,容器只需要少数的能力即可。为了加强安全,容器可以禁用一些没必要的权限。 18 | * 完全禁止任何 mount 操作; 19 | * 禁止直接访问本地主机的套接字; 20 | * 禁止访问一些文件系统的操作,比如创建新的设备、修改文件属性等; 21 | * 禁止模块加载。 22 | 23 | 这样,就算攻击者在容器中取得了 root 权限,也不能获得本地主机的较高权限,能进行的破坏也有限。 24 | 25 | 默认情况下,Docker采用 [白名单](https://github.com/docker/docker/blob/master/daemon/execdriver/native/template/default_template.go) 机制,禁用 [必需功能](https://github.com/docker/docker/blob/master/daemon/execdriver/native/template/default_template.go) 之外的其它权限。 26 | 当然,用户也可以根据自身需求来为 Docker 容器启用额外的权限。 27 | -------------------------------------------------------------------------------- /underly/namespace.md: -------------------------------------------------------------------------------- 1 | ## 名字空间 2 | 名字空间是 Linux 内核一个强大的特性。每个容器都有自己单独的名字空间,运行在其中的应用都像是在独立的操作系统中运行一样。名字空间保证了容器之间彼此互不影响。 3 | 4 | ### pid 名字空间 5 | 不同用户的进程就是通过 pid 名字空间隔离开的,且不同名字空间中可以有相同 pid。所有的 LXC 进程在 Docker 中的父进程为Docker进程,每个 LXC 进程具有不同的名字空间。同时由于允许嵌套,因此可以很方便的实现嵌套的 Docker 容器。 6 | 7 | ### net 名字空间 8 | 有了 pid 名字空间, 每个名字空间中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net 名字空间实现的, 每个 net 名字空间有独立的 网络设备, IP 地址, 路由表, /proc/net 目录。这样每个容器的网络就能隔离开来。Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一 个Docker 网桥 docker0 连接在一起。 9 | 10 | ### ipc 名字空间 11 | 容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication - IPC), 包括信号量、消息队列和共享内存等。然而同 VM 不同的是,容器的进程间交互实际上还是 host 上具有相同 pid 名字空间中的进程间交互,因此需要在 IPC 资源申请时加入名字空间信息,每个 IPC 资源有一个唯一的 32 位 id。 12 | 13 | ### mnt 名字空间 14 | 类似 chroot,将一个进程放到一个特定的目录执行。mnt 名字空间允许不同名字空间的进程看到的文件结构不同,这样每个名字空间 中的进程所看到的文件目录就被隔离开了。同 chroot 不同,每个名字空间中的容器在 /proc/mounts 的信息只包含所在名字空间的 mount point。 15 | 16 | ### uts 名字空间 17 | UTS("UNIX Time-sharing System") 名字空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 主机上的一个进程。 18 | 19 | ### user 名字空间 20 | 每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。 21 | 22 | *注:关于 Linux 上的名字空间,[这篇文章](http://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/) 介绍的很好。 23 | -------------------------------------------------------------------------------- /image/pull.md: -------------------------------------------------------------------------------- 1 | ## 获取镜像 2 | 3 | 可以使用 `docker pull` 命令来从仓库获取所需要的镜像。 4 | 5 | 下面的例子将从 Docker Hub 仓库下载一个 Ubuntu 12.04 操作系统的镜像。 6 | ``` 7 | $ sudo docker pull ubuntu:12.04 8 | Pulling repository ubuntu 9 | ab8e2728644c: Pulling dependent layers 10 | 511136ea3c5a: Download complete 11 | 5f0ffaa9455e: Download complete 12 | a300658979be: Download complete 13 | 904483ae0c30: Download complete 14 | ffdaafd1ca50: Download complete 15 | d047ae21eeaf: Download complete 16 | ``` 17 | 下载过程中,会输出获取镜像的每一层信息。 18 | 19 | 该命令实际上相当于 `$ sudo docker pull registry.hub.docker.com/ubuntu:12.04` 命令,即从注册服务器 `registry.hub.docker.com` 中的 `ubuntu` 仓库来下载标记为 `12.04` 的镜像。 20 | 21 | 有时候官方仓库注册服务器下载较慢,可以从其他仓库下载。 22 | 从其它仓库下载时需要指定完整的仓库注册服务器地址。例如 23 | ``` 24 | $ sudo docker pull dl.dockerpool.com:5000/ubuntu:12.04 25 | Pulling dl.dockerpool.com:5000/ubuntu 26 | ab8e2728644c: Pulling dependent layers 27 | 511136ea3c5a: Download complete 28 | 5f0ffaa9455e: Download complete 29 | a300658979be: Download complete 30 | 904483ae0c30: Download complete 31 | ffdaafd1ca50: Download complete 32 | d047ae21eeaf: Download complete 33 | ``` 34 | 35 | 完成后,即可随时使用该镜像了,例如创建一个容器,让其中运行 bash 应用。 36 | ``` 37 | $ sudo docker run -t -i ubuntu:12.04 /bin/bash 38 | root@fe7fc4bd8fc9:/# 39 | ``` 40 | -------------------------------------------------------------------------------- /_local/push_images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script will upload the given local images to a registry server ($registry is the default value). 4 | # See: https://github.com/yeasy/docker_practice/blob/master/_local/push_images.sh 5 | # Usage: push_images image1 [image2...] 6 | # Author: yeasy@github 7 | # Create: 2014-09-23 8 | 9 | #The registry server address where you want push the images into 10 | registry=127.0.0.1:5000 11 | 12 | ### DO NOT MODIFY THE FOLLOWING PART, UNLESS YOU KNOW WHAT IT MEANS ### 13 | echo_r () { 14 | [ $# -ne 1 ] && return 0 15 | echo -e "\033[31m$1\033[0m" 16 | } 17 | echo_g () { 18 | [ $# -ne 1 ] && return 0 19 | echo -e "\033[32m$1\033[0m" 20 | } 21 | echo_y () { 22 | [ $# -ne 1 ] && return 0 23 | echo -e "\033[33m$1\033[0m" 24 | } 25 | echo_b () { 26 | [ $# -ne 1 ] && return 0 27 | echo -e "\033[34m$1\033[0m" 28 | } 29 | 30 | usage() { 31 | sudo docker images 32 | echo "Usage: $0 registry1:tag1 [registry2:tag2...]" 33 | } 34 | 35 | [ $# -lt 1 ] && usage && exit 36 | 37 | echo_b "The registry server is $registry" 38 | 39 | 40 | for image in "$@" 41 | do 42 | echo_b "Uploading $image..." 43 | sudo docker tag $image $registry/$image 44 | sudo docker push $registry/$image 45 | sudo docker rmi $registry/$image 46 | echo_g "Done" 47 | done 48 | -------------------------------------------------------------------------------- /container/run.md: -------------------------------------------------------------------------------- 1 | ##启动容器 2 | 启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。 3 | 4 | 因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。 5 | 6 | ###新建并启动 7 | 所需要的命令主要为 `docker run`。 8 | 9 | 例如,下面的命令输出一个 “Hello World”,之后终止容器。 10 | ``` 11 | $ sudo docker run ubuntu:14.04 /bin/echo 'Hello world' 12 | Hello world 13 | ``` 14 | 这跟在本地直接执行 `/bin/echo 'hello world'` 几乎感觉不出任何区别。 15 | 16 | 下面的命令则启动一个 bash 终端,允许用户进行交互。 17 | ``` 18 | $ sudo docker run -t -i ubuntu:14.04 /bin/bash 19 | root@af8bae53bdd3:/# 20 | ``` 21 | 其中,`-t` 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, `-i` 则让容器的标准输入保持打开。 22 | 23 | 在交互模式下,用户可以通过所创建的终端来输入命令,例如 24 | ``` 25 | root@af8bae53bdd3:/# pwd 26 | / 27 | root@af8bae53bdd3:/# ls 28 | bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var 29 | ``` 30 | 31 | 当利用 `docker run` 来创建容器时,Docker 在后台运行的标准操作包括: 32 | 33 | * 检查本地是否存在指定的镜像,不存在就从公有仓库下载 34 | * 利用镜像创建并启动一个容器 35 | * 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层 36 | * 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去 37 | * 从地址池配置一个 ip 地址给容器 38 | * 执行用户指定的应用程序 39 | * 执行完毕后容器被终止 40 | 41 | ###启动已终止容器 42 | 可以利用 `docker start` 命令,直接将一个已经终止的容器启动运行。 43 | 44 | 容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。除此之外,并没有其它的资源。可以在伪终端中利用 `ps` 或 `top` 来查看进程信息。 45 | ``` 46 | root@ba267838cc1b:/# ps 47 | PID TTY TIME CMD 48 | 1 ? 00:00:00 bash 49 | 11 ? 00:00:00 ps 50 | ``` 51 | 可见,容器中仅运行了指定的 bash 应用。这种特点使得 Docker 对资源的利用率极高,是货真价实的轻量级虚拟化。 52 | -------------------------------------------------------------------------------- /kubernetes/design.md: -------------------------------------------------------------------------------- 1 | # 基本架构 2 | 3 | 任何优秀的项目都离不开优秀的架构设计。本小节将介绍 Kubernetes 在架构方面的设计考虑。 4 | 5 | ## 基本考虑 6 | 如果让我们自己从头设计一套容器管理平台,有如下几个方面是很容易想到的: 7 | * 分布式架构,保证扩展性; 8 | * 逻辑集中式的控制平面 + 物理分布式的运行平面; 9 | * 一套资源调度系统,管理哪个容器该分配到哪个节点上; 10 | * 一套对容器内服务进行抽象和 HA 的系统。 11 | 12 | ## 运行原理 13 | 14 | 下面这张图完整展示了 Kubernetes 的运行原理。 15 | 16 | ![Kubernetes 架构](../../_images/k8s_architecture.png) 17 | 18 | 可见,Kubernetes 首先是一套分布式系统,由多个节点组成,节点分为两类:一类是属于管理平面的主节点/控制节点(Master Node);一类是属于运行平面的工作节点(Worker Node)。 19 | 20 | 显然,复杂的工作肯定都交给控制节点去做了,工作节点负责提供稳定的操作接口和能力抽象即可。 21 | 22 | 从这张图上,我们没有能发现 Kubernetes 中对于控制平面的分布式实现,但是由于数据后端自身就是一套分布式的数据库(Etcd),因此可以很容易扩展到分布式实现。 23 | 24 | ## 控制平面 25 | ### 主节点服务 26 | 主节点上需要提供如下的管理服务: 27 | * apiserver 是整个系统的对外接口,提供一套 RESTful 的 [Kubernetes API](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/api.md),供客户端和其它组件调用; 28 | * scheduler 负责对资源进行调度,分配某个 pod 到某个节点上。是 pluggable的,意味着很容易选择其它实现方式; 29 | * controller-manager 负责管理控制器,包括 endpoint-controller(刷新服务和 pod 的关联信息)和 replication-controller(维护某个 pod 的复制为配置的数值)。 30 | 31 | ### Etcd 32 | 这里 Etcd 即作为数据后端,又作为消息中间件。 33 | 34 | 通过 Etcd 来存储所有的主节点上的状态信息,很容易实现主节点的分布式扩展。 35 | 36 | 组件可以自动的去侦测 Etcd 中的数值变化来获得通知,并且获得更新后的数据来执行相应的操作。 37 | 38 | ## 工作节点 39 | * kubelet 是工作节点执行操作的 agent,负责具体的容器生命周期管理,根据从数据库中获取的信息来管理容器,并上报 pod 运行状态等; 40 | * kube-proxy 是一个简单的网络访问代理,同时也是一个 Load Balancer。它负责将访问到某个服务的请求具体分配给工作节点上的 Pod(同一类标签)。 41 | 42 | ![Proxy 代理对服务的请求](../../_images/kube-proxy.png) 43 | -------------------------------------------------------------------------------- /advanced_network/ptp.md: -------------------------------------------------------------------------------- 1 | ## 示例:创建一个点到点连接 2 | 默认情况下,Docker 会将所有容器连接到由 `docker0` 提供的虚拟子网中。 3 | 4 | 用户有时候需要两个容器之间可以直连通信,而不用通过主机网桥进行桥接。 5 | 6 | 解决办法很简单:创建一对 `peer` 接口,分别放到两个容器中,配置成点到点链路类型即可。 7 | 8 | 首先启动 2 个容器: 9 | ``` 10 | $ sudo docker run -i -t --rm --net=none base /bin/bash 11 | root@1f1f4c1f931a:/# 12 | $ sudo docker run -i -t --rm --net=none base /bin/bash 13 | root@12e343489d2f:/# 14 | ``` 15 | 16 | 找到进程号,然后创建网络名字空间的跟踪文件。 17 | ``` 18 | $ sudo docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a 19 | 2989 20 | $ sudo docker inspect -f '{{.State.Pid}}' 12e343489d2f 21 | 3004 22 | $ sudo mkdir -p /var/run/netns 23 | $ sudo ln -s /proc/2989/ns/net /var/run/netns/2989 24 | $ sudo ln -s /proc/3004/ns/net /var/run/netns/3004 25 | ``` 26 | 27 | 创建一对 `peer` 接口,然后配置路由 28 | ``` 29 | $ sudo ip link add A type veth peer name B 30 | 31 | $ sudo ip link set A netns 2989 32 | $ sudo ip netns exec 2989 ip addr add 10.1.1.1/32 dev A 33 | $ sudo ip netns exec 2989 ip link set A up 34 | $ sudo ip netns exec 2989 ip route add 10.1.1.2/32 dev A 35 | 36 | $ sudo ip link set B netns 3004 37 | $ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B 38 | $ sudo ip netns exec 3004 ip link set B up 39 | $ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B 40 | ``` 41 | 现在这 2 个容器就可以相互 ping 通,并成功建立连接。点到点链路不需要子网和子网掩码。 42 | 43 | 此外,也可以不指定 `--net=none` 来创建点到点链路。这样容器还可以通过原先的网络来通信。 44 | 45 | 利用类似的办法,可以创建一个只跟主机通信的容器。但是一般情况下,更推荐使用 `--icc=false` 来关闭容器之间的通信。 46 | -------------------------------------------------------------------------------- /advanced_network/port_mapping.md: -------------------------------------------------------------------------------- 1 | ## 映射容器端口到宿主主机的实现 2 | 3 | 默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。 4 | ### 容器访问外部实现 5 | 容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址。这是使用 `iptables` 的源地址伪装操作实现的。 6 | 7 | 查看主机的 NAT 规则。 8 | ``` 9 | $ sudo iptables -t nat -nL 10 | ... 11 | Chain POSTROUTING (policy ACCEPT) 12 | target prot opt source destination 13 | MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16 14 | ... 15 | ``` 16 | 其中,上述规则将所有源地址在 `172.17.0.0/16` 网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址。 17 | 18 | ### 外部访问容器实现 19 | 20 | 容器允许外部访问,可以在 `docker run` 时候通过 `-p` 或 `-P` 参数来启用。 21 | 22 | 不管用那种办法,其实也是在本地的 `iptable` 的 nat 表中添加相应的规则。 23 | 24 | 使用 `-P` 时: 25 | ``` 26 | $ iptables -t nat -nL 27 | ... 28 | Chain DOCKER (2 references) 29 | target prot opt source destination 30 | DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:172.17.0.2:80 31 | ``` 32 | 33 | 使用 `-p 80:80` 时: 34 | ``` 35 | $ iptables -t nat -nL 36 | Chain DOCKER (2 references) 37 | target prot opt source destination 38 | DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80 39 | ``` 40 | 注意: 41 | * 这里的规则映射了 0.0.0.0,意味着将接受主机来自所有接口的流量。用户可以通过 `-p IP:host_port:container_port` 或 `-p 42 | IP::port` 来指定允许访问容器的主机上的 IP、接口等,以制定更严格的规则。 43 | * 如果希望永久绑定到某个固定的 IP 地址,可以在 Docker 配置文件 `/etc/default/docker` 中指定 `DOCKER_OPTS="--ip=IP_ADDRESS"`,之后重启 Docker 服务即可生效。 44 | -------------------------------------------------------------------------------- /data_management/volume.md: -------------------------------------------------------------------------------- 1 | ## 数据卷 2 | 数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性: 3 | * 数据卷可以在容器之间共享和重用 4 | * 对数据卷的修改会立马生效 5 | * 对数据卷的更新,不会影响镜像 6 | * 数据卷会一直存在,直到没有容器使用 7 | 8 | *注意:数据卷的使用,类似于 Linux 下对目录或文件进行 mount。 9 | 10 | 11 | ### 创建一个数据卷 12 | 在用 `docker run` 命令的时候,使用 `-v` 标记来创建一个数据卷并挂载到容器里。在一次 run 中多次使用可以挂载多个数据卷。 13 | 14 | 下面创建一个 web 容器,并加载一个数据卷到容器的 `/webapp` 目录。 15 | ``` 16 | $ sudo docker run -d -P --name web -v /webapp training/webapp python app.py 17 | ``` 18 | *注意:也可以在 Dockerfile 中使用 `VOLUME` 来添加一个或者多个新的卷到由该镜像创建的任意容器。 19 | 20 | ### 挂载一个主机目录作为数据卷 21 | 使用 `-v` 标记也可以指定挂载一个本地主机的目录到容器中去。 22 | ``` 23 | $ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py 24 | ``` 25 | 上面的命令加载主机的 `/src/webapp` 目录到容器的 `/opt/webapp` 26 | 目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动为你创建它。 27 | 28 | *注意:Dockerfile 中不支持这种用法,这是因为 Dockerfile 是为了移植和分享用的。然而,不同操作系统的路径格式不一样,所以目前还不能支持。 29 | 30 | Docker 挂载数据卷的默认权限是读写,用户也可以通过 `:ro` 指定为只读。 31 | ``` 32 | $ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp:ro 33 | training/webapp python app.py 34 | ``` 35 | 加了 `:ro` 之后,就挂载为只读了。 36 | 37 | ### 挂载一个本地主机文件作为数据卷 38 | `-v` 标记也可以从主机挂载单个文件到容器中 39 | ``` 40 | $ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash 41 | ``` 42 | 这样就可以记录在容器输入过的命令了。 43 | 44 | *注意:如果直接挂载一个文件,很多文件编辑工具,包括 `vi` 或者 `sed --in-place`,可能会造成文件 inode 的改变,从 Docker 1.1 45 | .0起,这会导致报错误信息。所以最简单的办法就直接挂载文件的父目录。 46 | -------------------------------------------------------------------------------- /advanced_network/docker0.md: -------------------------------------------------------------------------------- 1 | ## 配置 docker0 网桥 2 | Docker 服务默认会创建一个 `docker0` 网桥(其上有一个 `docker0` 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。 3 | 4 | Docker 默认指定了 `docker0` 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了 MTU(接口允许接收的最大传输单元),通常是 1500 Bytes,或宿主主机网络路由上支持的默认值。这些值都可以在服务启动的时候进行配置。 5 | * `--bip=CIDR` -- IP 地址加掩码格式,例如 192.168.1.5/24 6 | * `--mtu=BYTES` -- 覆盖默认的 Docker mtu 配置 7 | 8 | 也可以在配置文件中配置 DOCKER_OPTS,然后重启服务。 9 | 由于目前 Docker 网桥是 Linux 网桥,用户可以使用 `brctl show` 来查看网桥和端口连接信息。 10 | ``` 11 | $ sudo brctl show 12 | bridge name bridge id STP enabled interfaces 13 | docker0 8000.3a1d7362b4ee no veth65f9 14 | vethdda6 15 | ``` 16 | *注:`brctl` 命令在 Debian、Ubuntu 中可以使用 `sudo apt-get install bridge-utils` 来安装。 17 | 18 | 19 | 每次创建一个新容器的时候,Docker 从可用的地址段中选择一个空闲的 IP 地址分配给容器的 eth0 端口。使用本地主机上 `docker0` 接口的 IP 作为所有容器的默认网关。 20 | ``` 21 | $ sudo docker run -i -t --rm base /bin/bash 22 | $ ip addr show eth0 23 | 24: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 24 | link/ether 32:6f:e0:35:57:91 brd ff:ff:ff:ff:ff:ff 25 | inet 172.17.0.3/16 scope global eth0 26 | valid_lft forever preferred_lft forever 27 | inet6 fe80::306f:e0ff:fe35:5791/64 scope link 28 | valid_lft forever preferred_lft forever 29 | $ ip route 30 | default via 172.17.42.1 dev eth0 31 | 172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3 32 | $ exit 33 | ``` 34 | -------------------------------------------------------------------------------- /kubernetes/kubectl.md: -------------------------------------------------------------------------------- 1 | # kubectl 使用 2 | [kubectl](https://github.com/GoogleCloudPlatform/kubernetes) 是 Kubernetes 自带的客户端,可以用它来直接操作 Kubernetes。 3 | 4 | 使用格式有两种: 5 | ```sh 6 | kubectl [flags] 7 | kubectl [command] 8 | ``` 9 | 10 | ## get 11 | Display one or many resources 12 | ## describe 13 | Show details of a specific resource 14 | ## create 15 | Create a resource by filename or stdin 16 | ## update 17 | Update a resource by filename or stdin. 18 | ## delete 19 | Delete a resource by filename, stdin, resource and ID, or by resources and label selector. 20 | ## namespace 21 | SUPERCEDED: Set and view the current Kubernetes namespace 22 | ## log 23 | Print the logs for a container in a pod. 24 | ## rolling-update 25 | Perform a rolling update of the given ReplicationController. 26 | ## resize 27 | Set a new size for a Replication Controller. 28 | ## exec 29 | Execute a command in a container. 30 | ## port-forward 31 | Forward one or more local ports to a pod. 32 | ## proxy 33 | Run a proxy to the Kubernetes API server 34 | ## run-container 35 | Run a particular image on the cluster. 36 | ## stop 37 | Gracefully shut down a resource by id or filename. 38 | ## expose 39 | Take a replicated application and expose it as Kubernetes Service 40 | ## label 41 | Update the labels on a resource 42 | ## config 43 | config modifies kubeconfig files 44 | ## cluster-info 45 | Display cluster info 46 | ## api-versions 47 | Print available API versions. 48 | ## version 49 | Print the client and server version information. 50 | ## help 51 | Help about any command 52 | -------------------------------------------------------------------------------- /repository/config.md: -------------------------------------------------------------------------------- 1 | ## 仓库配置文件 2 | Docker 的 Registry 利用配置文件提供了一些仓库的模板(flavor),用户可以直接使用它们来进行开发或生产部署。 3 | 4 | ### 模板 5 | 在 `config_sample.yml` 文件中,可以看到一些现成的模板段: 6 | * `common`:基础配置 7 | * `local`:存储数据到本地文件系统 8 | * `s3`:存储数据到 AWS S3 中 9 | * `dev`:使用 `local` 模板的基本配置 10 | * `test`:单元测试使用 11 | * `prod`:生产环境配置(基本上跟s3配置类似) 12 | * `gcs`:存储数据到 Google 的云存储 13 | * `swift`:存储数据到 OpenStack Swift 服务 14 | * `glance`:存储数据到 OpenStack Glance 服务,本地文件系统为后备 15 | * `glance-swift`:存储数据到 OpenStack Glance 服务,Swift 为后备 16 | * `elliptics`:存储数据到 Elliptics key/value 存储 17 | 18 | 用户也可以添加自定义的模版段。 19 | 20 | 默认情况下使用的模板是 `dev`,要使用某个模板作为默认值,可以添加 `SETTINGS_FLAVOR` 到环境变量中,例如 21 | ``` 22 | export SETTINGS_FLAVOR=dev 23 | ``` 24 | 25 | 另外,配置文件中支持从环境变量中加载值,语法格式为 `_env:VARIABLENAME[:DEFAULT]`。 26 | 27 | ### 示例配置 28 | ``` 29 | common: 30 | loglevel: info 31 | search_backend: "_env:SEARCH_BACKEND:" 32 | sqlalchemy_index_database: 33 | "_env:SQLALCHEMY_INDEX_DATABASE:sqlite:////tmp/docker-registry.db" 34 | 35 | prod: 36 | loglevel: warn 37 | storage: s3 38 | s3_access_key: _env:AWS_S3_ACCESS_KEY 39 | s3_secret_key: _env:AWS_S3_SECRET_KEY 40 | s3_bucket: _env:AWS_S3_BUCKET 41 | boto_bucket: _env:AWS_S3_BUCKET 42 | storage_path: /srv/docker 43 | smtp_host: localhost 44 | from_addr: docker@myself.com 45 | to_addr: my@myself.com 46 | 47 | dev: 48 | loglevel: debug 49 | storage: local 50 | storage_path: /home/myself/docker 51 | 52 | test: 53 | storage: local 54 | storage_path: /tmp/tmpdockertmp 55 | ``` 56 | 57 | ### 选项 58 | -------------------------------------------------------------------------------- /compose/install.md: -------------------------------------------------------------------------------- 1 | ## 安装 2 | 3 | 安装 Compose 之前,要先安装 Docker,在此不再赘述。 4 | 5 | ### PIP 安装 6 | 这种方式最为推荐。 7 | 8 | 执行命令。 9 | ```sh 10 | $ sudo pip install -U docker-compose 11 | ``` 12 | 13 | 安装成功后,可以查看 `docker-compose` 命令的用法。 14 | ```sh 15 | $ docker-compose -h 16 | Fast, isolated development environments using Docker. 17 | 18 | Usage: 19 | docker-compose [options] [COMMAND] [ARGS...] 20 | docker-compose -h|--help 21 | 22 | Options: 23 | --verbose Show more output 24 | --version Print version and exit 25 | -f, --file FILE Specify an alternate compose file (default: docker-compose.yml) 26 | -p, --project-name NAME Specify an alternate project name (default: directory name) 27 | 28 | Commands: 29 | build Build or rebuild services 30 | help Get help on a command 31 | kill Kill containers 32 | logs View output from containers 33 | port Print the public port for a port binding 34 | ps List containers 35 | pull Pulls service images 36 | rm Remove stopped containers 37 | run Run a one-off command 38 | scale Set number of containers for a service 39 | start Start services 40 | stop Stop services 41 | restart Restart services 42 | up Create and start containers 43 | ``` 44 | 45 | 之后,可以添加 bash 补全命令。 46 | ```sh 47 | $ curl -L https://raw.githubusercontent.com/docker/compose/1.2.0/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose 48 | 49 | ``` 50 | 51 | ### 二进制包 52 | 发布的二进制包可以在 [https://github.com/docker/compose/releases](https://github.com/docker/compose/releases) 找到。 53 | 54 | 下载后直接放到执行路径即可。 55 | 56 | 例如,在常见的 Linux 平台上。 57 | 58 | ``` 59 | $ sudo curl -L https://github.com/docker/compose/releases/download/1.2.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose 60 | $ sudo chmod a+x /usr/local/bin/docker-compose 61 | ``` 62 | 63 | 64 | -------------------------------------------------------------------------------- /advanced_network/access_control.md: -------------------------------------------------------------------------------- 1 | ## 容器访问控制 2 | 容器的访问控制,主要通过 Linux 上的 `iptables` 防火墙来进行管理和实现。`iptables` 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。 3 | 4 | ### 容器访问外部网络 5 | 容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。 6 | 7 | ``` 8 | $sysctl net.ipv4.ip_forward 9 | net.ipv4.ip_forward = 1 10 | ``` 11 | 如果为 0,说明没有开启转发,则需要手动打开。 12 | ``` 13 | $sysctl -w net.ipv4.ip_forward=1 14 | ``` 15 | 如果在启动 Docker 服务的时候设定 `--ip-forward=true`, Docker 就会自动设定系统的 `ip_forward` 参数为 1。 16 | 17 | ### 容器之间访问 18 | 容器之间相互访问,需要两方面的支持。 19 | * 容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到 `docker0` 网桥上。 20 | * 本地系统的防火墙软件 -- `iptables` 是否允许通过。 21 | 22 | #### 访问所有端口 23 | 当启动 Docker 服务时候,默认会添加一条转发策略到 iptables 的 FORWARD 链上。策略为通过(`ACCEPT`)还是禁止(`DROP`)取决于配置`--icc=true`(缺省值)还是 `--icc=false`。当然,如果手动指定 `--iptables=false` 则不会添加 `iptables` 规则。 24 | 25 | 可见,默认情况下,不同容器之间是允许网络互通的。如果为了安全考虑,可以在 `/etc/default/docker` 文件中配置 `DOCKER_OPTS=--icc=false` 来禁止它。 26 | 27 | #### 访问指定端口 28 | 在通过 `-icc=false` 关闭网络访问后,还可以通过 `--link=CONTAINER_NAME:ALIAS` 选项来访问容器的开放端口。 29 | 30 | 例如,在启动 Docker 服务时,可以同时使用 `icc=false --iptables=true` 参数来关闭允许相互的网络访问,并让 Docker 可以修改系统中的 `iptables` 规则。 31 | 32 | 此时,系统中的 `iptables` 规则可能是类似 33 | ``` 34 | $ sudo iptables -nL 35 | ... 36 | Chain FORWARD (policy ACCEPT) 37 | target prot opt source destination 38 | DROP all -- 0.0.0.0/0 0.0.0.0/0 39 | ... 40 | ``` 41 | 42 | 之后,启动容器(`docker run`)时使用 `--link=CONTAINER_NAME:ALIAS` 选项。Docker 会在 `iptable` 中为 两个容器分别添加一条 `ACCEPT` 规则,允许相互访问开放的端口(取决于 Dockerfile 中的 EXPOSE 行)。 43 | 44 | 当添加了 `--link=CONTAINER_NAME:ALIAS` 选项后,添加了 `iptables` 规则。 45 | ``` 46 | $ sudo iptables -nL 47 | ... 48 | Chain FORWARD (policy ACCEPT) 49 | target prot opt source destination 50 | ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80 51 | ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80 52 | DROP all -- 0.0.0.0/0 0.0.0.0/0 53 | ``` 54 | 55 | 注意:`--link=CONTAINER_NAME:ALIAS` 中的 `CONTAINER_NAME` 目前必须是 Docker 分配的名字,或使用 `--name` 参数指定的名字。主机名则不会被识别。 56 | -------------------------------------------------------------------------------- /network/port_mapping.md: -------------------------------------------------------------------------------- 1 | ## 外部访问容器 2 | 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 `-P` 或 `-p` 参数来指定端口映射。 3 | 4 | 当使用 -P 标记时,Docker 会随机映射一个 `49000~49900` 的端口到内部容器开放的网络端口。 5 | 6 | 使用 `docker ps` 可以看到,本地主机的 49155 被映射到了容器的 5000 端口。此时访问本机的 49155 端口即可访问容器内 web 应用提供的界面。 7 | ``` 8 | $ sudo docker run -d -P training/webapp python app.py 9 | $ sudo docker ps -l 10 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 11 | bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse 12 | ``` 13 | 同样的,可以通过 `docker logs` 命令来查看应用的信息。 14 | ``` 15 | $ sudo docker logs -f nostalgic_morse 16 | * Running on http://0.0.0.0:5000/ 17 | 10.0.2.2 - - [23/May/2014 20:16:31] "GET / HTTP/1.1" 200 - 18 | 10.0.2.2 - - [23/May/2014 20:16:31] "GET /favicon.ico HTTP/1.1" 404 - 19 | ``` 20 | 21 | -p(小写的)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 `ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort`。 22 | 23 | ### 映射所有接口地址 24 | 使用 `hostPort:containerPort` 格式本地的 5000 端口映射到容器的 5000 端口,可以执行 25 | ``` 26 | $ sudo docker run -d -p 5000:5000 training/webapp python app.py 27 | ``` 28 | 此时默认会绑定本地所有接口上的所有地址。 29 | 30 | ### 映射到指定地址的指定端口 31 | 可以使用 `ip:hostPort:containerPort` 格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1 32 | ``` 33 | $ sudo docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py 34 | ``` 35 | ### 映射到指定地址的任意端口 36 | 使用 `ip::containerPort` 绑定 localhost 的任意端口到容器的 5000 端口,本地主机会自动分配一个端口。 37 | ``` 38 | $ sudo docker run -d -p 127.0.0.1::5000 training/webapp python app.py 39 | ``` 40 | 还可以使用 udp 标记来指定 udp 端口 41 | ``` 42 | $ sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py 43 | ``` 44 | ### 查看映射端口配置 45 | 使用 `docker port` 来查看当前映射的端口配置,也可以查看到绑定的地址 46 | ``` 47 | $ docker port nostalgic_morse 5000 48 | 127.0.0.1:49155. 49 | ``` 50 | 注意: 51 | * 容器有自己的内部网络和 ip 地址(使用 `docker inspect` 可以获取所有的变量,Docker 还可以有一个可变的网络配置。) 52 | * -p 标记可以多次使用来绑定多个端口 53 | 54 | 例如 55 | ``` 56 | $ sudo docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py 57 | ``` 58 | -------------------------------------------------------------------------------- /cases/supervisor.md: -------------------------------------------------------------------------------- 1 | ## 使用 Supervisor 来管理进程 2 | Docker 容器在启动的时候开启单个进程,比如,一个 ssh 或者 apache 的 daemon 服务。但我们经常需要在一个机器上开启多个服务,这可以有很多方法,最简单的就是把多个启动命令放到一个启动脚本里面,启动的时候直接启动这个脚本,另外就是安装进程管理工具。 3 | 4 | 本小节将使用进程管理工具 supervisor 来管理容器中的多个进程。使用 Supervisor 可以更好的控制、管理、重启我们希望运行的进程。在这里我们演示一下如何同时使用 ssh 和 apache 服务。 5 | 6 | ### 配置 7 | 首先创建一个 Dockerfile,内容和各部分的解释如下。 8 | ``` 9 | FROM ubuntu:13.04 10 | MAINTAINER examples@docker.com 11 | RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list 12 | RUN apt-get update 13 | RUN apt-get upgrade -y 14 | ``` 15 | 16 | ### 安装 ssh、apache 和 supervisor 17 | ``` 18 | RUN apt-get install -y openssh-server apache2 supervisor 19 | RUN mkdir -p /var/run/sshd 20 | RUN mkdir -p /var/log/supervisor 21 | ``` 22 | 23 | 这里安装 3 个软件,还创建了 2 个 ssh 和 supervisor 服务正常运行所需要的目录。 24 | ``` 25 | COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf 26 | ``` 27 | 添加 supervisord 的配置文件,并复制配置文件到对应目录下面。 28 | 29 | ``` 30 | EXPOSE 22 80 31 | CMD ["/usr/bin/supervisord"] 32 | ``` 33 | 这里我们映射了 22 和 80 端口,使用 supervisord 的可执行路径启动服务。 34 | 35 | 36 | ### supervisor配置文件内容 37 | ``` 38 | [supervisord] 39 | nodaemon=true 40 | [program:sshd] 41 | command=/usr/sbin/sshd -D 42 | 43 | [program:apache2] 44 | command=/bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2 -DFOREGROUND" 45 | ``` 46 | 配置文件包含目录和进程,第一段 supervsord 配置软件本身,使用 nodaemon 参数来运行。第二段包含要控制的 2 个服务。每一段包含一个服务的目录和启动这个服务的命令。 47 | 48 | ### 使用方法 49 | 创建镜像。 50 | ``` 51 | $ sudo docker build -t test/supervisord . 52 | ``` 53 | 启动 supervisor 容器。 54 | ``` 55 | $ sudo docker run -p 22 -p 80 -t -i test/supervisord 56 | 2013-11-25 18:53:22,312 CRIT Supervisor running as root (no user in config file) 57 | 2013-11-25 18:53:22,312 WARN Included extra file "/etc/supervisor/conf.d/supervisord.conf" during parsing 58 | 2013-11-25 18:53:22,342 INFO supervisord started with pid 1 59 | 2013-11-25 18:53:23,346 INFO spawned: 'sshd' with pid 6 60 | 2013-11-25 18:53:23,349 INFO spawned: 'apache2' with pid 7 61 | ``` 62 | 使用 `docker run` 来启动我们创建的容器。使用多个 `-p` 来映射多个端口,这样我们就能同时访问 ssh 和 apache 服务了。 63 | 64 | 可以使用这个方法创建一个只有 ssh 服务的基础镜像,之后创建镜像可以使用这个镜像为基础来创建 65 | -------------------------------------------------------------------------------- /_local/.bashrc_docker: -------------------------------------------------------------------------------- 1 | # Some useful commands to use docker. 2 | # Author: yeasy@github 3 | # Created:2014-09-25 4 | 5 | alias docker-pid="sudo docker inspect --format '{{.State.Pid}}'" 6 | alias docker-ip="sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}'" 7 | 8 | #the implementation refs from https://github.com/jpetazzo/nsenter/blob/master/docker-enter 9 | function docker-enter() { 10 | #if [ -e $(dirname "$0")/nsenter ]; then 11 | #Change for centos bash running 12 | if [ -e $(dirname '$0')/nsenter ]; then 13 | # with boot2docker, nsenter is not in the PATH but it is in the same folder 14 | NSENTER=$(dirname "$0")/nsenter 15 | else 16 | # if nsenter has already been installed with path notified, here will be clarified 17 | NSENTER=$(which nsenter) 18 | #NSENTER=nsenter 19 | fi 20 | [ -z "$NSENTER" ] && echo "WARN Cannot find nsenter" && return 21 | 22 | if [ -z "$1" ]; then 23 | echo "Usage: `basename "$0"` CONTAINER [COMMAND [ARG]...]" 24 | echo "" 25 | echo "Enters the Docker CONTAINER and executes the specified COMMAND." 26 | echo "If COMMAND is not specified, runs an interactive shell in CONTAINER." 27 | else 28 | PID=$(sudo docker inspect --format "{{.State.Pid}}" "$1") 29 | if [ -z "$PID" ]; then 30 | echo "WARN Cannot find the given container" 31 | return 32 | fi 33 | shift 34 | 35 | OPTS="--target $PID --mount --uts --ipc --net --pid" 36 | 37 | if [ -z "$1" ]; then 38 | # No command given. 39 | # Use su to clear all host environment variables except for TERM, 40 | # initialize the environment variables HOME, SHELL, USER, LOGNAME, PATH, 41 | # and start a login shell. 42 | #sudo $NSENTER "$OPTS" su - root 43 | sudo $NSENTER --target $PID --mount --uts --ipc --net --pid su - root 44 | else 45 | # Use env to clear all host environment variables. 46 | sudo $NSENTER --target $PID --mount --uts --ipc --net --pid env -i $@ 47 | fi 48 | fi 49 | } 50 | -------------------------------------------------------------------------------- /dockerfile/basic_structure.md: -------------------------------------------------------------------------------- 1 | ## 基本结构 2 | Dockerfile 由一行行命令语句组成,并且支持以 `#` 开头的注释行。 3 | 4 | 一般的,Dockerfile 分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。 5 | 6 | 例如 7 | ``` 8 | # This dockerfile uses the ubuntu image 9 | # VERSION 2 - EDITION 1 10 | # Author: docker_user 11 | # Command format: Instruction [arguments / command] .. 12 | 13 | # Base image to use, this must be set as the first line 14 | FROM ubuntu 15 | 16 | # Maintainer: docker_user (@docker_user) 17 | MAINTAINER docker_user docker_user@email.com 18 | 19 | # Commands to update the image 20 | RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list 21 | RUN apt-get update && apt-get install -y nginx 22 | RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf 23 | 24 | # Commands when creating a new container 25 | CMD /usr/sbin/nginx 26 | ``` 27 | 28 | 其中,一开始必须指明所基于的镜像名称,接下来推荐说明维护者信息。 29 | 30 | 后面则是镜像操作指令,例如 `RUN` 指令,`RUN` 指令将对镜像执行跟随的命令。每运行一条 `RUN` 指令,镜像添加新的一层,并提交。 31 | 32 | 最后是 `CMD` 指令,来指定运行容器时的操作命令。 33 | 34 | 下面是一个更复杂的例子 35 | ``` 36 | # Nginx 37 | # 38 | # VERSION 0.0.1 39 | 40 | FROM ubuntu 41 | MAINTAINER Victor Vieux 42 | 43 | RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server 44 | 45 | # Firefox over VNC 46 | # 47 | # VERSION 0.3 48 | 49 | FROM ubuntu 50 | 51 | # Install vnc, xvfb in order to create a 'fake' display and firefox 52 | RUN apt-get update && apt-get install -y x11vnc xvfb firefox 53 | RUN mkdir /.vnc 54 | # Setup a password 55 | RUN x11vnc -storepasswd 1234 ~/.vnc/passwd 56 | # Autostart firefox (might not be the best way, but it does the trick) 57 | RUN bash -c 'echo "firefox" >> /.bashrc' 58 | 59 | EXPOSE 5900 60 | CMD ["x11vnc", "-forever", "-usepw", "-create"] 61 | 62 | # Multiple images example 63 | # 64 | # VERSION 0.1 65 | 66 | FROM ubuntu 67 | RUN echo foo > bar 68 | # Will output something like ===> 907ad6c2736f 69 | 70 | FROM ubuntu 71 | RUN echo moo > oink 72 | # Will output something like ===> 695d7793cbe4 73 | 74 | # You᾿ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with 75 | # /oink. 76 | ``` 77 | -------------------------------------------------------------------------------- /_images/cmd_logic.dot: -------------------------------------------------------------------------------- 1 | //dot -Tpng xx.dot -o xx.png 2 | digraph G { 3 | rankdir=TB; 4 | fontname = "Microsoft YaHei"; 5 | fontsize = 14; 6 | penwidth = 3; 7 | compound=true; 8 | rankdir=LR; 9 | 10 | node [shape = record]; 11 | edge [fontname = "Arial", fontsize = 12, color="darkgreen" ]; 12 | 13 | image[label="Image",color=blue]; 14 | registry[label="Registry",color=blue]; 15 | tar[label="Tar files",color=blue]; 16 | 17 | subgraph cluster_container { 18 | label = "Container"; 19 | style = "bold"; 20 | color = blue; 21 | edge [fontname = "Arial", fontsize = 11, color="skyblue" ]; 22 | //node [style=filled]; 23 | run[label="Running",shape=circle, style=filled, fillcolor=green]; 24 | stop[label="Stopped",shape=circle, style=filled, fillcolor=red]; 25 | pause[label="Paused",shape=circle, style=filled, fillcolor=blue]; 26 | 27 | run->pause[label="pause"]; 28 | pause->run[label="unpause"]; 29 | run->run[label="restart"]; 30 | run->stop[label="kill"]; 31 | stop->run[label="start"]; 32 | } 33 | 34 | run->image[label="commit",ltail=cluster_container]; 35 | image->run[label="start"]; 36 | 37 | image->tar[label="export|save"]; 38 | tar->image[label="import"]; 39 | 40 | image->registry[label="push"]; 41 | registry->image[label="pull"]; 42 | 43 | //heat[label="heat commands",color=blue]; 44 | //heatshell[label="heatclient.shell.HeatShell",color=blue]; 45 | //shell[label="{heatclient.v1.shell|+do_stack_create\l+do_stack_show\l+do_stack_update\l...\l+do_event_list\l...\l+do_resource_list\l...\l+do_resource_type_show\l...\l+do_template_show\l...\l}",color=blue]; 46 | //heatclient[label="heatclient.client.Client",color=blue]; 47 | //client[label="heatclient.v1.client.Client",color=blue]; 48 | //httpclient[label="heatclient.common.http.HTTPClient",color=blue]; 49 | 50 | 51 | 52 | //openstackservices[label="{OpenStack Services|+Nova\l+Neutron\l+Keystone\l...}",color=blue]; 53 | 54 | //{rank=same; image cluster_container} 55 | //{rank=same; rpcproxy apimixin} 56 | } 57 | -------------------------------------------------------------------------------- /repository/dockerhub.md: -------------------------------------------------------------------------------- 1 | ## Docker Hub 2 | 目前 Docker 官方维护了一个公共仓库 [Docker Hub](https://hub.docker.com/),其中已经包括了超过 15,000 的镜像。大部分需求,都可以通过在 Docker Hub 中直接下载镜像来实现。 3 | 4 | ### 登录 5 | 可以通过执行 `docker login` 命令来输入用户名、密码和邮箱来完成注册和登录。 6 | 注册成功后,本地用户目录的 `.dockercfg` 中将保存用户的认证信息。 7 | 8 | ### 基本操作 9 | 用户无需登录即可通过 `docker search` 命令来查找官方仓库中的镜像,并利用 `docker pull` 命令来将它下载到本地。 10 | 11 | 例如以 centos 为关键词进行搜索: 12 | ``` 13 | $ sudo docker search centos 14 | NAME DESCRIPTION STARS OFFICIAL AUTOMATED 15 | centos The official build of CentOS. 465 [OK] 16 | tianon/centos CentOS 5 and 6, created using rinse instea... 28 17 | blalor/centos Bare-bones base CentOS 6.5 image 6 [OK] 18 | saltstack/centos-6-minimal 6 [OK] 19 | tutum/centos-6.4 DEPRECATED. Use tutum/centos:6.4 instead. ... 5 [OK] 20 | ... 21 | ``` 22 | 可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、星级(表示该镜像的受欢迎程度)、是否官方创建、是否自动创建。 23 | 官方的镜像说明是官方项目组创建和维护的,automated 资源允许用户验证镜像的来源和内容。 24 | 25 | 根据是否是官方提供,可将镜像资源分为两类。 26 | 一种是类似 centos 这样的基础镜像,被称为基础或根镜像。这些基础镜像是由 Docker 公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字。 27 | 还有一种类型,比如 `tianon/centos` 镜像,它是由 Docker 的用户创建并维护的,往往带有用户名称前缀。可以通过前缀 `user_name/` 来指定使用某个用户提供的镜像,比如 tianon 用户。 28 | 29 | 另外,在查找的时候通过 `-s N` 参数可以指定仅显示评价为 `N` 星以上的镜像。 30 | 31 | 下载官方 centos 镜像到本地。 32 | ``` 33 | $ sudo docker pull centos 34 | Pulling repository centos 35 | 0b443ba03958: Download complete 36 | 539c0211cd76: Download complete 37 | 511136ea3c5a: Download complete 38 | 7064731afe90: Download complete 39 | ``` 40 | 用户也可以在登录后通过 `docker push` 命令来将镜像推送到 Docker Hub。 41 | 42 | ### 自动创建 43 | 自动创建(Automated Builds)功能对于需要经常升级镜像内程序来说,十分方便。 44 | 有时候,用户创建了镜像,安装了某个软件,如果软件发布新版本则需要手动更新镜像。。 45 | 46 | 而自动创建允许用户通过 Docker Hub 指定跟踪一个目标网站(目前支持 [GitHub](github.org) 或 [BitBucket](bitbucket.org))上的项目,一旦项目发生新的提交,则自动执行创建。 47 | 48 | 要配置自动创建,包括如下的步骤: 49 | * 创建并登录 Docker Hub,以及目标网站; 50 | * 在目标网站中连接帐户到 Docker Hub; 51 | * 在 Docker Hub 中 [配置一个自动创建](https://registry.hub.docker.com/builds/add/); 52 | * 选取一个目标网站中的项目(需要含 Dockerfile)和分支; 53 | * 指定 Dockerfile 的位置,并提交创建。 54 | 55 | 之后,可以 在Docker Hub 的 [自动创建页面](https://registry.hub.docker.com/builds/) 中跟踪每次创建的状态。 56 | -------------------------------------------------------------------------------- /fig/cli_ref.md: -------------------------------------------------------------------------------- 1 | ##Fig客户端参考 2 | 3 | 大部分命令都可以运行在一个或多个服务上。如果没有特别的说明,这个命令则可以应用在所有的服务上。 4 | 5 | 执行 `fig [COMMAND] --help` 查看所有的使用说明。 6 | 7 | ###选项 8 | 9 | `--verbose` 10 | 11 | 显示更多信息。 12 | 13 | `--version` 14 | 15 | 打印版本并退出。 16 | 17 | `-f, --file FILE` 18 | 19 | 使用特定的Fig文件,默认使用fig.yml。 20 | 21 | `-p, --project-name NAME` 22 | 23 | 使用特定的项目名称,默认使用文件夹名称。 24 | 25 | ###命令 26 | 27 | `build` 28 | 29 | 构建或重新构建服务。 30 | 31 | 服务一旦构建后,将会标记为project_service,例如figtest_db。 32 | 如果修改服务的 `Dockerfile` 或构建目录信息,你可以运行 `fig build` 来重新构建。 33 | 34 | `help` 35 | 36 | 获得一个命令的帮助。 37 | 38 | `kill` 39 | 40 | 强制停止服务容器。 41 | 42 | `logs` 43 | 44 | 查看服务的输出。 45 | 46 | `port` 47 | 48 | 打印端口绑定的公共端口。 49 | 50 | `ps` 51 | 52 | 列出所有容器。 53 | 54 | `pull` 55 | 56 | 拉取服务镜像。 57 | 58 | `rm` 59 | 60 | 删除停止的服务容器。 61 | 62 | `run` 63 | 64 | 在一个服务上执行一个命令。 65 | 66 | 例如: 67 | 68 | ``` 69 | $ fig run web python manage.py shell 70 | ``` 71 | 72 | 默认情况下,链接的服务将会启动,除非这些服务已经在运行中。 73 | 74 | 一次性命令会在使用与服务的普通容器相同的配置的新容器中开始运行,然后卷、链接等等都将会按照期望创建。 75 | 与普通容器唯一的不同就是,这个命令将会覆盖原有的命令,如果端口有冲突则不会创建。 76 | 77 | 链接还可以在一次性命令和那个服务的其他容器间创建,然后你可以像下面一样进行一些操作: 78 | 79 | ``` 80 | $ fig run db psql -h db -U docker 81 | ``` 82 | 83 | 如果你不希望在执行一次性命令时启动链接的容器,可以指定--no-deps选项: 84 | 85 | ``` 86 | $ fig run --no-deps web python manage.py shell 87 | ``` 88 | 89 | `scale` 90 | 91 | 设置一个服务需要运行的容器个数。 92 | 93 | 通过service=num的参数来设置数量。例如: 94 | 95 | ``` 96 | $ fig scale web=2 worker=3 97 | ``` 98 | 99 | `start` 100 | 101 | 启动一个服务已经存在的容器. 102 | 103 | `stop` 104 | 105 | 停止一个已经运行的容器,但不删除它。通过 `fig start` 可以再次启动这些容器。 106 | 107 | `up` 108 | 109 | 构建,(重新)创建,启动,链接一个服务的容器。 110 | 111 | 链接的服务都将会启动,除非他们已经运行。 112 | 113 | 默认情况, `fig up` 将会聚合每个容器的输出,而且如果容器已经存在,所有容器将会停止。如果你运行 `fig up -d` ,将会在后台启动并运行所有的容器。 114 | 115 | 默认情况,如果这个服务的容器已经存在, `fig up` 将会停止并重新创建他们(保持使用volumes-from挂载的卷),以保证 `fig.yml` 的修改生效。如果你不想容器被停止并重新创建,可以使用 `fig up --no-recreate` 。如果需要的话,这样将会启动已经停止的容器。 116 | 117 | ###环境变量 118 | 119 | 环境变量可以用来配置Fig的行为。 120 | 121 | 变量以DOCKER_开头,它们和用来配置Docker命令行客户端的使用一样。如果你在使用 boot2docker , `$(boot2docker shellinit)` 将会设置它们为正确的值。 122 | 123 | `FIG_PROJECT_NAME` 124 | 125 | 设置通过Fig启动的每一个容器前添加的项目名称.默认是当前工作目录的名字。 126 | 127 | `FIG_FILE` 128 | 129 | 设置要使用的 `fig.yml` 的路径。默认路径是当前工作目录。 130 | 131 | `DOCKER_HOST` 132 | 133 | 设置docker进程的URL。默认docker client使用 `unix:///var/run/docker.sock` 。 134 | 135 | `DOCKER_TLS_VERIFY` 136 | 137 | 如果设置不为空的字符,允许和进程进行 TLS 通信。 138 | 139 | `DOCKER_CERT_PATH` 140 | 141 | 配置 `ca.pem` 的路径, `cert.pem` 和 `key.pem` 文件用来进行TLS验证.默认路径是 `~/.docker` 。 142 | -------------------------------------------------------------------------------- /underly/network.md: -------------------------------------------------------------------------------- 1 | ## Docker 网络实现 2 | 3 | Docker 的网络实现其实就是利用了 Linux 上的网络名字空间和虚拟网络设备(特别是 veth pair)。建议先熟悉了解这两部分的基本概念再阅读本章。 4 | 5 | ### 基本原理 6 | 首先,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包;此外,如果不同子网之间要进行通信,需要路由机制。 7 | 8 | Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势之一是转发效率较高。 9 | Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中。对于本地系统和容器内系统看来就像是一个正常的以太网卡,只是它不需要真正同外部网络设备通信,速度要快很多。 10 | 11 | Docker 容器网络就利用了这项技术。它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做 `veth pair`)。 12 | 13 | ### 创建网络参数 14 | Docker 创建一个容器的时候,会执行如下操作: 15 | * 创建一对虚拟接口,分别放到本地主机和新容器中; 16 | * 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9; 17 | * 容器一端放到新容器中,并修改名字作为 eth0,这个接口只在容器的名字空间可见; 18 | * 从网桥可用地址段中获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 veth65f9。 19 | 20 | 完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。 21 | 22 | 可以在 `docker run` 的时候通过 `--net` 参数来指定容器的网络配置,有4个可选值: 23 | * `--net=bridge` 这个是默认值,连接到默认的网桥。 24 | * `--net=host` 告诉 Docker 不要将容器网络放到隔离的名字空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机其它 root 进程一样可以打开低范围的端口,可以访问本地网络服务比如 D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用 `--privileged=true`,容器会被允许直接配置主机的网络堆栈。 25 | * `--net=container:NAME_or_ID` 让 Docker 将新建容器的进程放到一个已存在容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已存在的容器共享 IP 地址和端口等网络资源,两者进程可以直接通过 `lo` 环回接口通信。 26 | * `--net=none` 让 Docker 将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自己进行配置。 27 | 28 | ### 网络配置细节 29 | 用户使用 `--net=none` 后,可以自行配置网络,让容器达到跟平常一样具有访问网络的权限。通过这个过程,可以了解 Docker 配置网络的细节。 30 | 31 | 首先,启动一个 `/bin/bash` 容器,指定 `--net=none` 参数。 32 | ``` 33 | $ sudo docker run -i -t --rm --net=none base /bin/bash 34 | root@63f36fc01b5f:/# 35 | ``` 36 | 在本地主机查找容器的进程 id,并为它创建网络命名空间。 37 | ``` 38 | $ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f 39 | 2778 40 | $ pid=2778 41 | $ sudo mkdir -p /var/run/netns 42 | $ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid 43 | ``` 44 | 检查桥接网卡的 IP 和子网掩码信息。 45 | ``` 46 | $ ip addr show docker0 47 | 21: docker0: ... 48 | inet 172.17.42.1/16 scope global docker0 49 | ... 50 | ``` 51 | 创建一对 “veth pair” 接口 A 和 B,绑定 A 到网桥 `docker0`,并启用它 52 | ``` 53 | $ sudo ip link add A type veth peer name B 54 | $ sudo brctl addif docker0 A 55 | $ sudo ip link set A up 56 | ``` 57 | 将B放到容器的网络命名空间,命名为 eth0,启动它并配置一个可用 IP(桥接网段)和默认网关。 58 | ``` 59 | $ sudo ip link set B netns $pid 60 | $ sudo ip netns exec $pid ip link set dev B name eth0 61 | $ sudo ip netns exec $pid ip link set eth0 up 62 | $ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0 63 | $ sudo ip netns exec $pid ip route add default via 172.17.42.1 64 | ``` 65 | 以上,就是 Docker 配置网络的具体过程。 66 | 67 | 当容器结束后,Docker 会清空容器,容器内的 eth0 会随网络命名空间一起被清除,A 接口也被自动从 `docker0` 卸载。 68 | 69 | 此外,用户可以使用 `ip netns exec` 命令来在指定网络名字空间中进行配置,从而配置容器内的网络。 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Docker —— 从入门到实践 2 | =============== 3 | 4 | v0.4.2 5 | 6 | [Docker](docker.com) 是个伟大的项目,它彻底释放了虚拟化的威力,极大降低了云计算资源供应的成本,同时让应用的分发、测试、部署和分发都变得前所未有的高效和轻松! 7 | 8 | 本书既适用于具备基础 Linux 知识的 Docker 初学者,也希望可供理解原理和实现的高级用户参考。同时,书中给出的实践案例,可供在进行实际部署时借鉴。前六章为基础内容,供用户理解 Docker 的基本概念和操作;7 ~ 9 章介绍一些高级操作;第 10 章给出典型的应用场景和实践案例;11 ~ 13 章介绍关于 Docker 实现的相关技术。14 ~ 17章介绍相关的一些开源项目。 9 | 10 | 在线阅读:[GitBook](https://www.gitbook.io/book/yeasy/docker_practice) 或 [DockerPool](http://dockerpool.com/static/books/docker_practice/index.html)。 11 | 12 | 欢迎关注 DockerPool 社区微博 [@dockerpool](http://weibo.com/u/5345404432),或加入 DockerPool QQ 群(419042067),分享 Docker 资源,交流 Docker 技术。 13 | 14 | ![Docker 技术入门与实战](docker_primer.png) 15 | 16 | 《[Docker 技术入门与实战](http://item.jd.com/11598400.html)》一书已经正式出版,包含大量第一手实战案例,欢迎大家阅读使用。 17 | 18 | * [China-Pub](http://product.china-pub.com/3770833) 19 | * [京东图书](http://item.jd.com/11598400.html) 20 | * [当当图书](http://product.dangdang.com/23620853.html) 21 | * [亚马逊图书](http://www.amazon.cn/%E5%9B%BE%E4%B9%A6/dp/B00R5MYI7C/ref=lh_ni_t?ie=UTF8&psc=1&smid=A1AJ19PSB66TGU) 22 | 23 | ## 主要版本历史 24 | * 0.5: 2015-? 25 | * 添加 Compose 项目 26 | * 添加 Machine 项目 27 | * 添加 Swarm 项目 28 | * 完善 Kubernetes 项目内容 29 | * 0.4: 2015-05-08 30 | * 添加 Etcd 项目 31 | * 添加 Fig 项目 32 | * 添加 CoreOS 项目 33 | * 添加 Kubernetes 项目 34 | * 0.3: 2014-11-25 35 | * 完成仓库章节; 36 | * 重写安全章节; 37 | * 修正底层实现章节的架构、名字空间、控制组、文件系统、容器格式等内容; 38 | * 添加对常见仓库和镜像的介绍; 39 | * 添加 Dockerfile 的介绍; 40 | * 重新校订中英文混排格式。 41 | * 修订文字表达。 42 | * 发布繁体版本分支:zh-Hant。 43 | * 0.2: 2014-09-18 44 | * 对照官方文档重写介绍、基本概念、安装、镜像、容器、仓库、数据管理、网络等章节; 45 | * 添加底层实现章节; 46 | * 添加命令查询和资源链接章节; 47 | * 其它修正。 48 | * 0.1: 2014-09-05 49 | * 添加基本内容; 50 | * 修正错别字和表达不通顺的地方。 51 | 52 | 53 | 本书源码在 Github 上维护,欢迎参与:[https://github.com/yeasy/docker_practice](https://github.com/yeasy/docker_practice)。贡献者 [名单](https://github.com/yeasy/docker_practice/graphs/contributors)。 54 | 55 | ## 参加步骤 56 | * 在 GitHub 上 `fork` 到自己的仓库,如 `docker_user/docker_practice`,然后 `clone` 到本地,并设置用户信息。 57 | ``` 58 | $ git clone git@github.com:docker_user/docker_practice.git 59 | $ cd docker_practice 60 | $ git config user.name "yourname" 61 | $ git config user.email "your email" 62 | ``` 63 | * 修改代码后提交,并推送到自己的仓库。 64 | ``` 65 | $ #do some change on the content 66 | $ git commit -am "Fix issue #1: change helo to hello" 67 | $ git push 68 | ``` 69 | * 在 GitHub 网站上提交 pull request。 70 | * 定期使用项目仓库内容更新自己仓库内容。 71 | ``` 72 | $ git remote add upstream https://github.com/yeasy/docker_practice 73 | $ git fetch upstream 74 | $ git checkout master 75 | $ git rebase upstream/master 76 | $ git push -f origin master 77 | ``` 78 | -------------------------------------------------------------------------------- /cases/tomcat.md: -------------------------------------------------------------------------------- 1 | ## 创建 tomcat/weblogic 集群 2 | ### 安装 tomcat 镜像 3 | 准备好需要的 jdk、tomcat 等软件放到 home 目录下面,启动一个容器 4 | ``` 5 | docker run -t -i -v /home:/opt/data --name mk_tomcat ubuntu /bin/bash 6 | ``` 7 | 这条命令挂载本地 home 目录到容器的 /opt/data 目录,容器内目录若不存在,则会自动创建。接下来就是 tomcat 的基本配置,jdk 环境变量设置好之后,将 tomcat 程序放到 /opt/apache-tomcat 下面 8 | 编辑 /etc/supervisor/conf.d/supervisor.conf 文件,添加 tomcat 项 9 | ``` 10 | [supervisord] 11 | nodaemon=true 12 | 13 | [program:tomcat] 14 | command=/opt/apache-tomcat/bin/startup.sh 15 | 16 | [program:sshd] 17 | command=/usr/sbin/sshd -D 18 | ``` 19 | 20 | ``` 21 | docker commit ac6474aeb31d tomcat 22 | ``` 23 | 24 | 新建 tomcat 文件夹,新建 Dockerfile。 25 | ``` 26 | FROM mk_tomcat 27 | EXPOSE 22 8080 28 | CMD ["/usr/bin/supervisord"] 29 | ``` 30 | 根据 Dockerfile 创建镜像。 31 | ``` 32 | docker build tomcat tomcat 33 | ``` 34 | ### 安装 weblogic 镜像 35 | 36 | 步骤和 tomcat 基本一致,这里贴一下配置文件 37 | ``` 38 | supervisor.conf 39 | [supervisord] 40 | nodaemon=true 41 | 42 | 43 | [program:weblogic] 44 | command=/opt/Middleware/user_projects/domains/base_domain/bin/startWebLogic.sh 45 | 46 | [program:sshd] 47 | command=/usr/sbin/sshd -D 48 | dockerfile 49 | FROM weblogic 50 | EXPOSE 22 7001 51 | CMD ["/usr/bin/supervisord"] 52 | ``` 53 | 54 | ### tomcat/weblogic 镜像的使用 55 | #### 存储的使用 56 | 在启动的时候,使用 `-v` 参数 57 | 58 | -v, --volume=[] Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container) 59 | 60 | 将本地磁盘映射到容器内部,它在主机和容器之间是实时变化的,所以我们更新程序、上传代码只需要更新物理主机的目录就可以了 61 | 62 | #### tomcat 和 weblogic 集群的实现 63 | tomcat 只要开启多个容器即可 64 | ``` 65 | docker run -d -v -p 204:22 -p 7003:8080 -v /home/data:/opt/data --name tm1 tomcat /usr/bin/supervisord 66 | docker run -d -v -p 205:22 -p 7004:8080 -v /home/data:/opt/data --name tm2 tomcat /usr/bin/supervisord 67 | docker run -d -v -p 206:22 -p 7005:8080 -v /home/data:/opt/data --name tm3 tomcat /usr/bin/supervisord 68 | ``` 69 | 70 | 这里说一下 weblogic 的配置,大家知道 weblogic 有一个域的概念。如果要使用常规的 administrator +node 的方式部署,就需要在 supervisord 中分别写出 administartor server 和 node server 的启动脚本,这样做的优点是: 71 | * 可以使用 weblogic 的集群,同步等概念 72 | * 部署一个集群应用程序,只需要安装一次应用到集群上即可 73 | 74 | 缺点是: 75 | * Docker 配置复杂了 76 | * 没办法自动扩展集群的计算容量,如需添加节点,需要在 administrator 上先创建节点,然后再配置新的容器 supervisor 启动脚本,然后再启动容器 77 | 78 | 另外种方法是将所有的程序都安装在 adminiserver 上面,需要扩展的时候,启动多个节点即可,它的优点和缺点和上一种方法恰恰相反。(建议使用这种方式来部署开发和测试环境) 79 | ``` 80 | docker run -d -v -p 204:22 -p 7001:7001 -v /home/data:/opt/data --name node1 weblogic /usr/bin/supervisord 81 | docker run -d -v -p 205:22 -p 7002:7001 -v /home/data:/opt/data --name node2 weblogic /usr/bin/supervisord 82 | docker run -d -v -p 206:22 -p 7003:7001 -v /home/data:/opt/data --name node3 weblogic /usr/bin/supervisord 83 | ``` 84 | 85 | 这样在前端使用 nginx 来做负载均衡就可以完成配置了 86 | -------------------------------------------------------------------------------- /fig/wordpress.md: -------------------------------------------------------------------------------- 1 | ##使用 Wordpress 入门 Fig 2 | Fig 让 Wordpress 运行在一个独立的环境中很简易。 3 | [安装](install.md) Fig ,然后下载 Wordpress 到当前目录: 4 | 5 | ``` 6 | wordpress.org/latest.tar.gz | tar -xvzf - 7 | ``` 8 | 这将会创建一个叫 wordpress 目录,你也可以重命名成你想要的名字。在目录里面,创建一个 `Dockerfile` 文件,定义应用的运行环境: 9 | 10 | ``` 11 | FROM orchardup/php5 12 | ADD . /code 13 | ``` 14 | 以上内容告诉 Docker 创建一个包含 PHP 和 Wordpress 的镜像。更多关于如何编写 Dockerfile 文件的信息可以查看 [镜像创建](../image/create.md#利用 Dockerfile 来创建镜像) 和 [Dockerfile 使用](../dockerfile/README.md)。 15 | 16 | 17 | 下一步,`fig.yml` 文件将开启一个 web 服务和一个独立的 MySQL 实例: 18 | 19 | ``` 20 | web: 21 | build: . 22 | command: php -S 0.0.0.0:8000 -t /code 23 | ports: 24 | - "8000:8000" 25 | links: 26 | - db 27 | volumes: 28 | - .:/code 29 | db: 30 | image: orchardup/mysql 31 | environment: 32 | MYSQL_DATABASE: wordpress 33 | ``` 34 | 要让这个应用跑起来还需要两个文件。 35 | 第一个,`wp-config.php` ,它是一个标准的 Wordpress 配置文件,有一点需要修改的是把数据库的配置指向 `db` 容器。 36 | 37 | ``` 38 | ) 39 | ``` 40 | 通过这个 PID,就可以连接到这个容器: 41 | ``` 42 | $ nsenter --target $PID --mount --uts --ipc --net --pid 43 | ``` 44 | 下面给出一个完整的例子。 45 | ``` 46 | $ sudo docker run -idt ubuntu 47 | 243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550 48 | $ sudo docker ps 49 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 50 | 243c32535da7 ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds nostalgic_hypatia 51 | $ PID=$(docker-pid 243c32535da7) 52 | 10981 53 | $ sudo nsenter --target 10981 --mount --uts --ipc --net --pid 54 | root@243c32535da7:/# 55 | ``` 56 | 更简单的,建议大家下载 57 | [.bashrc_docker](https://github.com/yeasy/docker_practice/raw/master/_local/.bashrc_docker),并将内容放到 .bashrc 中。 58 | ``` 59 | $ wget -P ~ https://github.com/yeasy/docker_practice/raw/master/_local/.bashrc_docker; 60 | $ echo "[ -f ~/.bashrc_docker ] && . ~/.bashrc_docker" >> ~/.bashrc; source ~/.bashrc 61 | ``` 62 | 这个文件中定义了很多方便使用 Docker 的命令,例如 `docker-pid` 可以获取某个容器的 PID;而 `docker-enter` 可以进入容器或直接在容器内执行命令。 63 | ``` 64 | $ echo $(docker-pid ) 65 | $ docker-enter ls 66 | ``` 67 | -------------------------------------------------------------------------------- /fig/django.md: -------------------------------------------------------------------------------- 1 | ##使用 Django 入门 Fig 2 | 3 | 我们现在将使用 Fig 配置并运行一个 Django/PostgreSQL 应用。在此之前,先确保 Fig 已经 [安装](install.md)。 4 | 5 | 在一切工作开始前,需要先设置好三个必要的文件。 6 | 第一步,因为应用将要运行在一个满足所有环境依赖的 Docker 容器里面,那么我们可以通过编辑 `Dockerfile` 文件来指定 Docker 容器要安装内容。内容如下: 7 | 8 | ``` 9 | FROM python:2.7 10 | ENV PYTHONUNBUFFERED 1 11 | RUN mkdir /code 12 | WORKDIR /code 13 | ADD requirements.txt /code/ 14 | RUN pip install -r requirements.txt 15 | ADD . /code/ 16 | ``` 17 | 以上内容指定应用将使用安装了 Python 以及必要依赖包的镜像。更多关于如何编写 Dockerfile 文件的信息可以查看 [镜像创建](../image/create.md#利用 Dockerfile 来创建镜像) 和 [Dockerfile 使用](../dockerfile/README.md)。 18 | 19 | 第二步,在 `requirements.txt` 文件里面写明需要安装的具体依赖包名 。 20 | 21 | ``` 22 | Django 23 | psycopg2 24 | ``` 25 | 26 | 就是这么简单。 27 | 第三步,`fig.yml` 文件将把所有的东西关联起来。它描述了应用的构成(一个 web 服务和一个数据库)、使用的 Docker 镜像、镜像之间的连接、挂载到容器的卷,以及服务开放的端口。 28 | 29 | ``` 30 | db: 31 | image: postgres 32 | web: 33 | build: . 34 | command: python manage.py runserver 0.0.0.0:8000 35 | volumes: 36 | - .:/code 37 | ports: 38 | - "8000:8000" 39 | links: 40 | - db 41 | ``` 42 | 查看 [`fig.yml` 章节](yml_ref.md) 了解更多详细的工作机制。 43 | 44 | 现在我们就可以使用 `fig run` 命令启动一个 Django 应用了。 45 | 46 | ``` 47 | $ fig run web django-admin.py startproject figexample . 48 | ``` 49 | Fig 会先使用 `Dockerfile` 为 web 服务创建一个镜像,接着使用这个镜像在容器里运行 `django-admin.py startproject figexample . ` 指令。 50 | 51 | 这将在当前目录生成一个 Django 应用。 52 | 53 | ``` 54 | $ ls 55 | Dockerfile fig.yml figexample manage.py requirements.txt 56 | ``` 57 | 首先,我们要为应用设置好数据库的连接信息。用以下内容替换 `figexample/settings.py` 文件中 `DATABASES = ...` 定义的节点内容。 58 | 59 | ``` 60 | DATABASES = { 61 | 'default': { 62 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 63 | 'NAME': 'postgres', 64 | 'USER': 'postgres', 65 | 'HOST': 'db', 66 | 'PORT': 5432, 67 | } 68 | } 69 | ``` 70 | 这些信息是在 [postgres](https://registry.hub.docker.com/_/postgres/) Docker 镜像固定设置好的。 71 | 然后,运行 `fig up` : 72 | 73 | ``` 74 | Recreating myapp_db_1... 75 | Recreating myapp_web_1... 76 | Attaching to myapp_db_1, myapp_web_1 77 | myapp_db_1 | 78 | myapp_db_1 | PostgreSQL stand-alone backend 9.1.11 79 | myapp_db_1 | 2014-01-27 12:17:03 UTC LOG: database system is ready to accept connections 80 | myapp_db_1 | 2014-01-27 12:17:03 UTC LOG: autovacuum launcher started 81 | myapp_web_1 | Validating models... 82 | myapp_web_1 | 83 | myapp_web_1 | 0 errors found 84 | myapp_web_1 | January 27, 2014 - 12:12:40 85 | myapp_web_1 | Django version 1.6.1, using settings 'figexample.settings' 86 | myapp_web_1 | Starting development server at http://0.0.0.0:8000/ 87 | myapp_web_1 | Quit the server with CONTROL-C. 88 | ``` 89 | 这个 web 应用已经开始在你的 docker 守护进程里监听着 5000 端口了(如果你有使用 boot2docker ,执行 `boot2docker ip` ,就会看到它的地址)。 90 | 91 | 你还可以在 Docker 上运行其它的管理命令,例如对于同步数据库结构这种事,在运行完 `fig up` 后,在另外一个终端运行以下命令即可: 92 | 93 | ``` 94 | $ fig run web python manage.py syncdb 95 | ``` -------------------------------------------------------------------------------- /fig/yml_ref.md: -------------------------------------------------------------------------------- 1 | ##fig.yml 参考 2 | 3 | 每个在 `fig.yml` 定义的服务都需要指定一个镜像或镜像的构建内容。像 `docker run` 的命令行一样,其它内容是可选的。 4 | 5 | `docker run` 在 `Dockerfile` 中设置的选项(例如:`CMD`, `EXPOSE`, `VOLUME`, `ENV`) 作为已经提供的默认设置 - 你不需要在 `fig.yml` 中重新设置。 6 | 7 | `image` 8 | 9 | 这里可以设置为标签或镜像ID的一部分。它可以是本地的,也可以是远程的 - 如果镜像在本地不存在,`Fig` 将会尝试拉去这个镜像。 10 | 11 | ``` 12 | image: ubuntu 13 | image: orchardup/postgresql 14 | image: a4bc65fd 15 | ``` 16 | 17 | `build` 18 | 19 | 指定 `Dockerfile` 所在文件夹的路径。 `Fig` 将会构建这个镜像并给它生成一个名字,然后使用这个镜像。 20 | 21 | ``` 22 | build: /path/to/build/dir 23 | ``` 24 | 25 | `command` 26 | 27 | 覆盖默认的命令。 28 | 29 | ``` 30 | command: bundle exec thin -p 3000 31 | ``` 32 | 33 | `links` 34 | 35 | 在其它的服务中连接容器。使用服务名称(经常也作为别名)或服务名称加服务别名 `(SERVICE:ALIAS)` 都可以。 36 | 37 | ``` 38 | links: 39 | - db 40 | - db:database 41 | - redis 42 | ``` 43 | 44 | 可以在服务的容器中的 `/etc/hosts` 里创建别名。例如: 45 | 46 | ``` 47 | 172.17.2.186 db 48 | 172.17.2.186 database 49 | 172.17.2.187 redis 50 | ``` 51 | 52 | 环境变量也将被创建 - 细节查看环境变量参考章节。 53 | 54 | `ports` 55 | 56 | 暴露端口。使用宿主和容器 `(HOST:CONTAINER)` 或者仅仅容器的端口(宿主将会随机选择端口)都可以。 57 | 58 | 注:当使用 `HOST:CONTAINER` 格式来映射端口时,如果你使用的容器端口小于60你可能会得到错误得结果,因为 `YAML` 将会解析 `xx:yy` 这种数字格式为60进制。所以我们建议用字符指定你得端口映射。 59 | 60 | ``` 61 | ports: 62 | - "3000" 63 | - "8000:8000" 64 | - "49100:22" 65 | - "127.0.0.1:8001:8001" 66 | ``` 67 | 68 | `expose` 69 | 70 | 暴露不发布到宿主机的端口 - 它们只被连接的服务访问。仅仅内部的端口可以被指定。 71 | 72 | ``` 73 | expose: 74 | - "3000" 75 | - "8000" 76 | ``` 77 | 78 | `volumes` 79 | 80 | 卷挂载路径设置。可以设置宿主机路径 `(HOST:CONTAINER)` 或访问模式 `(HOST:CONTAINER:ro)` 。 81 | 82 | ``` 83 | volumes: 84 | - /var/lib/mysql 85 | - cache/:/tmp/cache 86 | - ~/configs:/etc/configs/:ro 87 | ``` 88 | 89 | `volumes_from` 90 | 91 | 从另一个服务或容器挂载所有卷。 92 | 93 | ``` 94 | volumes_from: 95 | - service_name 96 | - container_name 97 | ``` 98 | 99 | `environment` 100 | 101 | 设置环境变量。你可以使用数组或字典两种格式。 102 | 103 | 环境变量在运行 `Fig` 的机器上被解析成一个key。它有助于安全和指定的宿主值。 104 | 105 | ``` 106 | environment: 107 | RACK_ENV: development 108 | SESSION_SECRET: 109 | 110 | environment: 111 | - RACK_ENV=development 112 | - SESSION_SECRET 113 | ``` 114 | 115 | `net` 116 | 117 | 设置网络模式。使用和 `docker client` 的 `--net` 参数一样的值。 118 | 119 | ``` 120 | net: "bridge" 121 | net: "none" 122 | net: "container:[name or id]" 123 | net: "host" 124 | ``` 125 | 126 | `dns` 127 | 128 | 配置DNS服务器。它可以是一个值,也可以是一个列表。 129 | 130 | ``` 131 | dns: 8.8.8.8 132 | dns: 133 | - 8.8.8.8 134 | - 9.9.9.9 135 | ``` 136 | 137 | `working_dir, entrypoint, user, hostname, domainname, mem_limit, privileged` 138 | 139 | 这些都是和 `docker run` 对应的一个值。 140 | 141 | ``` 142 | working_dir: /code 143 | entrypoint: /code/entrypoint.sh 144 | user: postgresql 145 | 146 | hostname: foo 147 | domainname: foo.com 148 | 149 | mem_limit: 1000000000 150 | privileged: true 151 | ``` 152 | -------------------------------------------------------------------------------- /compose/commands.md: -------------------------------------------------------------------------------- 1 | ## Compose 命令说明 2 | 3 | 大部分命令都可以运行在一个或多个服务上。如果没有特别的说明,命令则应用在项目所有的服务上。 4 | 5 | 执行 `docker-compose [COMMAND] --help` 查看具体某个命令的使用说明。 6 | 7 | 基本的使用格式是 8 | ```sh 9 | docker-compose [options] [COMMAND] [ARGS...] 10 | ``` 11 | 12 | ## 选项 13 | 14 | * `--verbose` 输出更多调试信息。 15 | * `--version` 打印版本并退出。 16 | * `-f, --file FILE` 使用特定的 compose 模板文件,默认为 `docker-compose.yml`。 17 | * `-p, --project-name NAME` 指定项目名称,默认使用目录名称。 18 | 19 | ## 命令 20 | 21 | ### `build` 22 | 23 | 构建或重新构建服务。 24 | 25 | 服务一旦构建后,将会带上一个标记名,例如 web_db。 26 | 27 | 可以随时在项目目录下运行 `docker-compose build` 来重新构建服务。 28 | 29 | ### `help` 30 | 31 | 获得一个命令的帮助。 32 | 33 | ### `kill` 34 | 35 | 通过发送 `SIGKILL` 信号来强制停止服务容器。支持通过参数来指定发送的信号,例如 36 | ```sh 37 | $ docker-compose kill -s SIGINT 38 | ``` 39 | 40 | ### `logs` 41 | 42 | 查看服务的输出。 43 | 44 | ### `port` 45 | 46 | 打印绑定的公共端口。 47 | 48 | ### `ps` 49 | 50 | 列出所有容器。 51 | 52 | ### `pull` 53 | 54 | 拉取服务镜像。 55 | 56 | ### `rm` 57 | 58 | 删除停止的服务容器。 59 | 60 | ### `run` 61 | 62 | 在一个服务上执行一个命令。 63 | 64 | 例如: 65 | 66 | ``` 67 | $ docker-compose run ubuntu ping docker.com 68 | ``` 69 | 70 | 将会启动一个 ubuntu 服务,执行 `ping docker.com` 命令。 71 | 72 | 默认情况下,所有关联的服务将会自动被启动,除非这些服务已经在运行中。 73 | 74 | 该命令类似启动容器后运行指定的命令,相关卷、链接等等都将会按照期望创建。 75 | 76 | 两个不同点: 77 | * 给定命令将会覆盖原有的自动运行命令; 78 | * 不会自动创建端口,以避免冲突。 79 | 80 | 如果不希望自动启动关联的容器,可以使用 `--no-deps` 选项,例如 81 | 82 | ``` 83 | $ docker-compose run --no-deps web python manage.py shell 84 | ``` 85 | 86 | 将不会启动 web 容器所关联的其它容器。 87 | 88 | ### `scale` 89 | 90 | 设置同一个服务运行的容器个数。 91 | 92 | 通过 `service=num` 的参数来设置数量。例如: 93 | 94 | ``` 95 | $ docker-compose scale web=2 worker=3 96 | ``` 97 | 98 | ### `start` 99 | 100 | 启动一个已经存在的服务容器。 101 | 102 | ### `stop` 103 | 104 | 停止一个已经运行的容器,但不删除它。通过 `docker-compose start` 可以再次启动这些容器。 105 | 106 | ### `up` 107 | 108 | 构建,(重新)创建,启动,链接一个服务相关的容器。 109 | 110 | 链接的服务都将会启动,除非他们已经运行。 111 | 112 | 默认情况, `docker-compose up` 将会整合所有容器的输出,并且退出时,所有容器将会停止。 113 | 114 | 如果使用 `docker-compose up -d` ,将会在后台启动并运行所有的容器。 115 | 116 | 默认情况,如果该服务的容器已经存在, `docker-compose up` 将会停止并尝试重新创建他们(保持使用 `volumes-from` 挂载的卷),以保证 `docker-compose.yml` 的修改生效。如果你不想容器被停止并重新创建,可以使用 `docker-compose up --no-recreate`。如果需要的话,这样将会启动已经停止的容器。 117 | 118 | ## 环境变量 119 | 120 | 环境变量可以用来配置 Compose 的行为。 121 | 122 | 以`DOCKER_`开头的变量和用来配置 Docker 命令行客户端的使用一样。如果使用 boot2docker , `$(boot2docker shellinit)` 将会设置它们为正确的值。 123 | 124 | ### `COMPOSE_PROJECT_NAME` 125 | 126 | 设置通过 Compose 启动的每一个容器前添加的项目名称,默认是当前工作目录的名字。 127 | 128 | ### `COMPOSE_FILE` 129 | 130 | 设置要使用的 `docker-compose.yml` 的路径。默认路径是当前工作目录。 131 | 132 | ### `DOCKER_HOST` 133 | 134 | 设置 Docker daemon 的地址。默认使用 `unix:///var/run/docker.sock`,与 Docker 客户端采用的默认值一致。 135 | 136 | ### `DOCKER_TLS_VERIFY` 137 | 138 | 如果设置不为空,则与 Docker daemon 交互通过 TLS 进行。 139 | 140 | ### `DOCKER_CERT_PATH` 141 | 142 | 配置 TLS 通信所需要的验证(`ca.pem`、`cert.pem` 和 `key.pem`)文件的路径,默认是 `~/.docker` 。 143 | -------------------------------------------------------------------------------- /fig/rails.md: -------------------------------------------------------------------------------- 1 | ##使用 Rail 入门 Fig 2 | 3 | 我们现在将使用 Fig 配置并运行一个 Rails/PostgreSQL 应用。在开始之前,先确保 Fig 已经 [安装](install.md)。 4 | 5 | 6 | 在一切工作开始前,需要先设置好三个必要的文件。 7 | 首先,因为应用将要运行在一个满足所有环境依赖的 Docker 容器里面,那么我们可以通过编辑 `Dockerfile` 文件来指定 Docker 容器要安装内容。内容如下: 8 | 9 | ``` 10 | FROM ruby 11 | RUN apt-get update -qq && apt-get install -y build-essential libpq-dev 12 | RUN mkdir /myapp 13 | WORKDIR /myapp 14 | ADD Gemfile /myapp/Gemfile 15 | RUN bundle install 16 | ADD . /myapp 17 | ``` 18 | 以上内容指定应用将使用安装了 Ruby、Bundler 以及其依赖件的镜像。更多关于如何编写 Dockerfile 文件的信息可以查看 [镜像创建](../image/create.md#利用 Dockerfile 来创建镜像) 和 [Dockerfile 使用](../dockerfile/README.md)。 19 | 下一步,我们需要一个引导加载 Rails 的文件 `Gemfile` 。 等一会儿它还会被 `rails new` 命令覆盖重写。 20 | 21 | ``` 22 | source 'https://rubygems.org' 23 | gem 'rails', '4.0.2' 24 | ``` 25 | 最后,`fig.yml` 文件才是最神奇的地方。 `fig.yml` 文件将把所有的东西关联起来。它描述了应用的构成(一个 web 服务和一个数据库)、每个镜像的来源(数据库运行在使用预定义的 PostgreSQL 镜像,web 应用侧将从本地目录创建)、镜像之间的连接,以及服务开放的端口。 26 | 27 | ``` 28 | db: 29 | image: postgres 30 | ports: 31 | - "5432" 32 | web: 33 | build: . 34 | command: bundle exec rackup -p 3000 35 | volumes: 36 | - .:/myapp 37 | ports: 38 | - "3000:3000" 39 | links: 40 | - db 41 | ``` 42 | 所有文件就绪后,我们就可以通过使用 `fig run` 命令生成应用的骨架了。 43 | 44 | ``` 45 | $ fig run web rails new . --force --database=postgresql --skip-bundle 46 | ``` 47 | Fig 会先使用 `Dockerfile` 为 web 服务创建一个镜像,接着使用这个镜像在容器里运行 `rails new ` 和它之后的命令。一旦这个命令运行完后,应该就可以看一个崭新的应用已经生成了。 48 | 49 | ``` 50 | $ ls 51 | Dockerfile app fig.yml tmp 52 | Gemfile bin lib vendor 53 | Gemfile.lock config log 54 | README.rdoc config.ru public 55 | Rakefile db test 56 | ``` 57 | 在新的 `Gemfile` 文件去掉加载 `therubyracer` 的行的注释,这样我们便可以使用 Javascript 运行环境: 58 | 59 | ``` 60 | gem 'therubyracer', platforms: :ruby 61 | ``` 62 | 现在我们已经有一个新的 `Gemfile` 文件,需要再重新创建镜像。(这个会步骤会改变 Dockerfile 文件本身,仅仅需要重建一次)。 63 | 64 | ``` 65 | $ fig build 66 | ``` 67 | 应用现在就可以启动了,但配置还未完成。Rails 默认读取的数据库目标是 `localhost` ,我们需要手动指定容器的 `db` 。同样的,还需要把用户名修改成和 postgres 镜像预定的一致。 68 | 打开最新生成的 `database.yml` 文件。用以下内容替换: 69 | 70 | ``` 71 | development: &default 72 | adapter: postgresql 73 | encoding: unicode 74 | database: postgres 75 | pool: 5 76 | username: postgres 77 | password: 78 | host: db 79 | 80 | test: 81 | <<: *default 82 | database: myapp_test 83 | ``` 84 | 现在就可以启动应用了。 85 | 86 | ``` 87 | $ fig up 88 | ``` 89 | 如果一切正常,你应该可以看到 PostgreSQL 的输出,几秒后可以看到这样的重复信息: 90 | 91 | ``` 92 | myapp_web_1 | [2014-01-17 17:16:29] INFO WEBrick 1.3.1 93 | myapp_web_1 | [2014-01-17 17:16:29] INFO ruby 2.0.0 (2013-11-22) [x86_64-linux-gnu] 94 | myapp_web_1 | [2014-01-17 17:16:29] INFO WEBrick::HTTPServer#start: pid=1 port=3000 95 | ``` 96 | 最后, 我们需要做的是创建数据库,打开另一个终端,运行: 97 | 98 | ``` 99 | $ fig run web rake db:create 100 | ``` 101 | 这个 web 应用已经开始在你的 docker 守护进程里面监听着 3000 端口了(如果你有使用 boot2docker ,执行 `boot2docker ip` ,就会看到它的地址)。 102 | 103 | ![](../_images/fig-rails-screenshot.png) -------------------------------------------------------------------------------- /dockerfile/instructions.md: -------------------------------------------------------------------------------- 1 | ## 指令 2 | 指令的一般格式为 `INSTRUCTION arguments`,指令包括 `FROM`、`MAINTAINER`、`RUN` 等。 3 | 4 | ### FROM 5 | 格式为 `FROM `或`FROM :`。 6 | 7 | 第一条指令必须为 `FROM` 指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 `FROM` 指令(每个镜像一次)。 8 | 9 | ### MAINTAINER 10 | 格式为 `MAINTAINER `,指定维护者信息。 11 | 12 | ### RUN 13 | 格式为 `RUN ` 或 `RUN ["executable", "param1", "param2"]`。 14 | 15 | 前者将在 shell 终端中运行命令,即 `/bin/sh -c`;后者则使用 `exec` 执行。指定使用其它终端可以通过第二种方式实现,例如 `RUN ["/bin/bash", "-c", "echo hello"]`。 16 | 17 | 每条 `RUN` 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 `\` 来换行。 18 | 19 | ### CMD 20 | 支持三种格式 21 | * `CMD ["executable","param1","param2"]` 使用 `exec` 执行,推荐方式; 22 | * `CMD command param1 param2` 在 `/bin/sh` 中执行,提供给需要交互的应用; 23 | * `CMD ["param1","param2"]` 提供给 `ENTRYPOINT` 的默认参数; 24 | 25 | 26 | 指定启动容器时执行的命令,每个 Dockerfile 只能有一条 `CMD` 命令。如果指定了多条命令,只有最后一条会被执行。 27 | 28 | 如果用户启动容器时候指定了运行的命令,则会覆盖掉 `CMD` 指定的命令。 29 | 30 | ### EXPOSE 31 | 格式为 `EXPOSE [...]`。 32 | 33 | 告诉 Docker 服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过 -P,Docker 主机会自动分配一个端口转发到指定的端口。 34 | 35 | ### ENV 36 | 格式为 `ENV `。 37 | 指定一个环境变量,会被后续 `RUN` 指令使用,并在容器运行时保持。 38 | 39 | 例如 40 | ``` 41 | ENV PG_MAJOR 9.3 42 | ENV PG_VERSION 9.3.4 43 | RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && … 44 | ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH 45 | ``` 46 | 47 | ### ADD 48 | 格式为 `ADD `。 49 | 50 | 该命令将复制指定的 `` 到容器中的 ``。 51 | 其中 `` 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)。 52 | 53 | ### COPY 54 | 格式为 `COPY `。 55 | 56 | 复制本地主机的 ``(为 Dockerfile 所在目录的相对路径)到容器中的 ``。 57 | 58 | 当使用本地目录为源目录时,推荐使用 `COPY`。 59 | 60 | ### ENTRYPOINT 61 | 两种格式: 62 | * `ENTRYPOINT ["executable", "param1", "param2"]` 63 | * `ENTRYPOINT command param1 param2`(shell中执行)。 64 | 65 | 配置容器启动后执行的命令,并且不可被 `docker run` 提供的参数覆盖。 66 | 67 | 每个 Dockerfile 中只能有一个 `ENTRYPOINT`,当指定多个时,只有最后一个起效。 68 | 69 | ### VOLUME 70 | 格式为 `VOLUME ["/data"]`。 71 | 72 | 创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。 73 | 74 | ### USER 75 | 格式为 `USER daemon`。 76 | 77 | 指定运行容器时的用户名或 UID,后续的 `RUN` 也会使用指定用户。 78 | 79 | 当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:`RUN groupadd -r postgres && useradd -r -g postgres postgres`。要临时获取管理员权限可以使用 `gosu`,而不推荐 `sudo`。 80 | 81 | ### WORKDIR 82 | 格式为 `WORKDIR /path/to/workdir`。 83 | 84 | 为后续的 `RUN`、`CMD`、`ENTRYPOINT` 指令配置工作目录。 85 | 86 | 可以使用多个 `WORKDIR` 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如 87 | ``` 88 | WORKDIR /a 89 | WORKDIR b 90 | WORKDIR c 91 | RUN pwd 92 | ``` 93 | 则最终路径为 `/a/b/c`。 94 | 95 | ### ONBUILD 96 | 格式为 `ONBUILD [INSTRUCTION]`。 97 | 98 | 配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。 99 | 100 | 例如,Dockerfile 使用如下的内容创建了镜像 `image-A`。 101 | ``` 102 | [...] 103 | ONBUILD ADD . /app/src 104 | ONBUILD RUN /usr/local/bin/python-build --dir /app/src 105 | [...] 106 | ``` 107 | 108 | 如果基于 image-A 创建新的镜像时,新的Dockerfile中使用 `FROM image-A`指定基础镜像时,会自动执行 `ONBUILD` 指令内容,等价于在后面添加了两条指令。 109 | ``` 110 | FROM image-A 111 | 112 | #Automatically run the following 113 | ADD . /app/src 114 | RUN /usr/local/bin/python-build --dir /app/src 115 | ``` 116 | 117 | 使用 `ONBUILD` 指令的镜像,推荐在标签中注明,例如 `ruby:1.9-onbuild`。 118 | 119 | -------------------------------------------------------------------------------- /cases/container_connect.md: -------------------------------------------------------------------------------- 1 | ## 多台物理主机之间的容器互联(暴露容器到真实网络中) 2 | Docker 默认的桥接网卡是 docker0。它只会在本机桥接所有的容器网卡,举例来说容器的虚拟网卡在主机上看一般叫做 veth*** 而 Docker 只是把所有这些网卡桥接在一起,如下: 3 | ``` 4 | [root@opnvz ~]# brctl show 5 | bridge name bridge id STP enabled interfaces 6 | docker0 8000.56847afe9799 no veth0889 7 | veth3c7b 8 | veth4061 9 | ``` 10 | 在容器中看到的地址一般是像下面这样的地址: 11 | ``` 12 | root@ac6474aeb31d:~# ip a 13 | 1: lo: mtu 1500 qdisc noqueue state UNKNOWN group default 14 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 15 | inet 127.0.0.1/8 scope host lo 16 | valid_lft forever preferred_lft forever 17 | inet6 ::1/128 scope host 18 | valid_lft forever preferred_lft forever 19 | 11: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 20 | link/ether 4a:7d:68:da:09:cf brd ff:ff:ff:ff:ff:ff 21 | inet 172.17.0.3/16 scope global eth0 22 | valid_lft forever preferred_lft forever 23 | inet6 fe80::487d:68ff:feda:9cf/64 scope link 24 | valid_lft forever preferred_lft forever 25 | ``` 26 | 这样就可以把这个网络看成是一个私有的网络,通过 nat 连接外网,如果要让外网连接到容器中,就需要做端口映射,即 -p 参数。 27 | 28 | 如果在企业内部应用,或者做多个物理主机的集群,可能需要将多个物理主机的容器组到一个物理网络中来,那么就需要将这个网桥桥接到我们指定的网卡上。 29 | 30 | ### 拓扑图 31 | 主机 A 和主机 B 的网卡一都连着物理交换机的同一个 vlan 101,这样网桥一和网桥三就相当于在同一个物理网络中了,而容器一、容器三、容器四也在同一物理网络中了,他们之间可以相互通信,而且可以跟同一 vlan 中的其他物理机器互联。 32 | ![物理拓扑图](../_images/container_connect_topology.png) 33 | 34 | ### ubuntu 示例 35 | 下面以 ubuntu 为例创建多个主机的容器联网: 36 | 创建自己的网桥,编辑 /etc/network/interface 文件 37 | ``` 38 | auto br0 39 | iface br0 inet static 40 | address 192.168.7.31 41 | netmask 255.255.240.0 42 | gateway 192.168.7.254 43 | bridge_ports em1 44 | bridge_stp off 45 | dns-nameservers 8.8.8.8 192.168.6.1 46 | ``` 47 | 将 Docker 的默认网桥绑定到这个新建的 br0 上面,这样就将这台机器上容器绑定到 em1 这个网卡所对应的物理网络上了。 48 | 49 | ubuntu 修改 /etc/default/docker 文件,添加最后一行内容 50 | 51 | ``` 52 | # Docker Upstart and SysVinit configuration file 53 | # Customize location of Docker binary (especially for development testing). 54 | #DOCKER="/usr/local/bin/docker" 55 | # Use DOCKER_OPTS to modify the daemon startup options. 56 | #DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4" 57 | 58 | # If you need Docker to use an HTTP proxy, it can also be specified here. 59 | #export http_proxy="http://127.0.0.1:3128/" 60 | 61 | # This is also a handy place to tweak where Docker's temporary files go. 62 | #export TMPDIR="/mnt/bigdrive/docker-tmp" 63 | 64 | DOCKER_OPTS="-b=br0" 65 | ``` 66 | 67 | 在启动 Docker 的时候 使用 -b 参数 将容器绑定到物理网络上。重启 Docker 服务后,再进入容器可以看到它已经绑定到你的物理网络上了。 68 | 69 | ``` 70 | root@ubuntudocker:~# docker ps 71 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 72 | 58b043aa05eb desk_hz:v1 "/startup.sh" 5 days ago Up 2 seconds 5900/tcp, 6080/tcp, 22/tcp yanlx 73 | root@ubuntudocker:~# brctl show 74 | bridge name bridge id STP enabled interfaces 75 | br0 8000.7e6e617c8d53 no em1 76 | vethe6e5 77 | ``` 78 | 这样就直接把容器暴露到物理网络上了,多台物理主机的容器也可以相互联网了。需要注意的是,这样就需要自己来保证容器的网络安全了。 79 | -------------------------------------------------------------------------------- /network/linking.md: -------------------------------------------------------------------------------- 1 | ## 容器互联 2 | 容器的连接(linking)系统是除了端口映射外,另一种跟容器中应用交互的方式。 3 | 4 | 该系统会在源和接收容器之间创建一个隧道,接收容器可以看到源容器指定的信息。 5 | 6 | ### 自定义容器命名 7 | 连接系统依据容器的名称来执行。因此,首先需要自定义一个好记的容器命名。 8 | 9 | 虽然当创建容器的时候,系统默认会分配一个名字。自定义命名容器有2个好处: 10 | * 自定义的命名,比较好记,比如一个web应用容器我们可以给它起名叫web 11 | * 当要连接其他容器时候,可以作为一个有用的参考点,比如连接web容器到db容器 12 | 13 | 使用 `--name` 标记可以为容器自定义命名。 14 | ``` 15 | $ sudo docker run -d -P --name web training/webapp python app.py 16 | ``` 17 | 18 | 使用 `docker ps` 来验证设定的命名。 19 | ``` 20 | $ sudo docker ps -l 21 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 22 | aed84ee21bde training/webapp:latest python app.py 12 hours ago Up 2 seconds 0.0.0.0:49154->5000/tcp web 23 | ``` 24 | 也可以使用 `docker inspect` 来查看容器的名字 25 | ``` 26 | $ sudo docker inspect -f "{{ .Name }}" aed84ee21bde 27 | /web 28 | ``` 29 | 注意:容器的名称是唯一的。如果已经命名了一个叫 web 的容器,当你要再次使用 web 这个名称的时候,需要先用`docker rm` 来删除之前创建的同名容器。 30 | 31 | 在执行 `docker run` 的时候如果添加 `--rm` 标记,则容器在终止后会立刻删除。注意,`--rm` 和 `-d` 参数不能同时使用。 32 | 33 | ###容器互联 34 | 使用 `--link` 参数可以让容器之间安全的进行交互。 35 | 36 | 下面先创建一个新的数据库容器。 37 | ``` 38 | $ sudo docker run -d --name db training/postgres 39 | ``` 40 | 删除之前创建的 web 容器 41 | ``` 42 | $ docker rm -f web 43 | ``` 44 | 然后创建一个新的 web 容器,并将它连接到 db 容器 45 | ``` 46 | $ sudo docker run -d -P --name web --link db:db training/webapp python app.py 47 | ``` 48 | 此时,db 容器和 web 容器建立互联关系。 49 | 50 | `--link` 参数的格式为 `--link name:alias`,其中 `name` 是要链接的容器的名称,`alias` 是这个连接的别名。 51 | 52 | 使用 `docker ps` 来查看容器的连接 53 | ``` 54 | $ docker ps 55 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 56 | 349169744e49 training/postgres:latest su postgres -c '/usr About a minute ago Up About a minute 5432/tcp db, web/db 57 | aed84ee21bde training/webapp:latest python app.py 16 hours ago Up 2 minutes 0.0.0.0:49154->5000/tcp web 58 | ``` 59 | 可以看到自定义命名的容器,db 和 web,db 容器的 names 列有 db 也有 web/db。这表示 web 容器链接到 db 容器,web 容器将被允许访问 db 容器的信息。 60 | 61 | Docker 在两个互联的容器之间创建了一个安全隧道,而且不用映射它们的端口到宿主主机上。在启动 db 容器的时候并没有使用 `-p` 和 `-P` 标记,从而避免了暴露数据库端口到外部网络上。 62 | 63 | Docker 通过 2 种方式为容器公开连接信息: 64 | * 环境变量 65 | * 更新 `/etc/hosts` 文件 66 | 67 | 使用 `env` 命令来查看 web 容器的环境变量 68 | ``` 69 | $ sudo docker run --rm --name web2 --link db:db training/webapp env 70 | . . . 71 | DB_NAME=/web2/db 72 | DB_PORT=tcp://172.17.0.5:5432 73 | DB_PORT_5000_TCP=tcp://172.17.0.5:5432 74 | DB_PORT_5000_TCP_PROTO=tcp 75 | DB_PORT_5000_TCP_PORT=5432 76 | DB_PORT_5000_TCP_ADDR=172.17.0.5 77 | . . . 78 | ``` 79 | 其中 DB_ 开头的环境变量是供 web 容器连接 db 容器使用,前缀采用大写的连接别名。 80 | 81 | 除了环境变量,Docker 还添加 host 信息到父容器的 `/etc/hosts` 的文件。下面是父容器 web 的 hosts 文件 82 | ``` 83 | $ sudo docker run -t -i --rm --link db:db training/webapp /bin/bash 84 | root@aed84ee21bde:/opt/webapp# cat /etc/hosts 85 | 172.17.0.7 aed84ee21bde 86 | . . . 87 | 172.17.0.5 db 88 | ``` 89 | 这里有 2 个 hosts,第一个是 web 容器,web 容器用 id 作为他的主机名,第二个是 db 容器的 ip 和主机名。 90 | 可以在 web 容器中安装 ping 命令来测试跟db容器的连通。 91 | ``` 92 | root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping 93 | root@aed84ee21bde:/opt/webapp# ping db 94 | PING db (172.17.0.5): 48 data bytes 95 | 56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms 96 | 56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms 97 | 56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms 98 | ``` 99 | 用 ping 来测试db容器,它会解析成 `172.17.0.5`。 100 | *注意:官方的 ubuntu 镜像默认没有安装 ping,需要自行安装。 101 | 102 | 用户可以链接多个父容器到子容器,比如可以链接多个 web 到 db 容器上。 103 | -------------------------------------------------------------------------------- /etcd/install.md: -------------------------------------------------------------------------------- 1 | ## 安装 2 | 3 | etcd 基于 Go 语言实现,因此,用户可以从 [项目主页](https://github.com/coreos/etcd) 下载源代码自行编译,也可以下载编译好的二进制文件,甚至直接使用制作好的 Docker 镜像文件来体验。 4 | 5 | ### 二进制文件方式下载 6 | 7 | 编译好的二进制文件都在 [github.com/coreos/etcd/releases](https://github.com/coreos/etcd/releases/) 页面,用户可以选择需要的版本,或通过下载工具下载。 8 | 9 | 例如,下面的命令使用 curl 工具下载压缩包,并解压。 10 | 11 | ``` 12 | curl -L https://github.com/coreos/etcd/releases/download/v2.0.0-rc.1/etcd-v2.0.0-rc.1-linux-amd64.tar.gz -o etcd-v2.0.0-rc.1-linux-amd64.tar.gz 13 | tar xzvf etcd-v2.0.0-rc.1-linux-amd64.tar.gz 14 | cd etcd-v2.0.0-rc.1-linux-amd64 15 | ``` 16 | 17 | 解压后,可以看到文件包括 18 | ``` 19 | $ ls 20 | etcd etcdctl etcd-migrate README-etcdctl.md README.md 21 | ``` 22 | 23 | 其中 etcd 是服务主文件,etcdctl 是提供给用户的命令客户端,etcd-migrate 负责进行迁移。 24 | 25 | 推荐通过下面的命令将三个文件都放到系统可执行目录 `/usr/local/bin/` 或 `/usr/bin/`。 26 | 27 | ``` 28 | $ sudo cp etcd* /usr/local/bin/ 29 | ``` 30 | 31 | 运行 etcd,将默认组建一个两个节点的集群。数据库服务端默认监听在 2379 和 4001 端口,etcd 实例监听在 2380 和 7001 端口。显示类似如下的信息: 32 | ``` 33 | $ ./etcd 34 | 2014/12/31 14:52:09 no data-dir provided, using default data-dir ./default.etcd 35 | 2014/12/31 14:52:09 etcd: listening for peers on http://localhost:2380 36 | 2014/12/31 14:52:09 etcd: listening for peers on http://localhost:7001 37 | 2014/12/31 14:52:09 etcd: listening for client requests on http://localhost:2379 38 | 2014/12/31 14:52:09 etcd: listening for client requests on http://localhost:4001 39 | 2014/12/31 14:52:09 etcdserver: name = default 40 | 2014/12/31 14:52:09 etcdserver: data dir = default.etcd 41 | 2014/12/31 14:52:09 etcdserver: snapshot count = 10000 42 | 2014/12/31 14:52:09 etcdserver: advertise client URLs = http://localhost:2379,http://localhost:4001 43 | 2014/12/31 14:52:09 etcdserver: initial advertise peer URLs = http://localhost:2380,http://localhost:7001 44 | 2014/12/31 14:52:09 etcdserver: initial cluster = default=http://localhost:2380,default=http://localhost:7001 45 | 2014/12/31 14:52:10 etcdserver: start member ce2a822cea30bfca in cluster 7e27652122e8b2ae 46 | 2014/12/31 14:52:10 raft: ce2a822cea30bfca became follower at term 0 47 | 2014/12/31 14:52:10 raft: newRaft ce2a822cea30bfca [peers: [], term: 0, commit: 0, lastindex: 0, lastterm: 0] 48 | 2014/12/31 14:52:10 raft: ce2a822cea30bfca became follower at term 1 49 | 2014/12/31 14:52:10 etcdserver: added local member ce2a822cea30bfca [http://localhost:2380 http://localhost:7001] to cluster 7e27652122e8b2ae 50 | 2014/12/31 14:52:11 raft: ce2a822cea30bfca is starting a new election at term 1 51 | 2014/12/31 14:52:11 raft: ce2a822cea30bfca became candidate at term 2 52 | 2014/12/31 14:52:11 raft: ce2a822cea30bfca received vote from ce2a822cea30bfca at term 2 53 | 2014/12/31 14:52:11 raft: ce2a822cea30bfca became leader at term 2 54 | 2014/12/31 14:52:11 raft.node: ce2a822cea30bfca elected leader ce2a822cea30bfca at term 2 55 | 2014/12/31 14:52:11 etcdserver: published {Name:default ClientURLs:[http://localhost:2379 http://localhost:4001]} to cluster 7e27652122e8b2ae 56 | ``` 57 | 58 | 此时,可以使用 etcdctl 命令进行测试,设置和获取键值 `testkey: "hello world"`,检查 etcd 服务是否启动成功: 59 | ``` 60 | $ ./etcdctl set testkey "hello world" 61 | hello world 62 | $ ./etcdctl get testkey 63 | hello world 64 | ``` 65 | 说明 etcd 服务已经成功启动了。 66 | 67 | 当然,也可以通过 HTTP 访问本地 2379 或 4001 端口的方式来进行操作,例如查看 `testkey` 的值: 68 | ``` 69 | $ curl -L http://localhost:4001/v2/keys/testkey 70 | {"action":"get","node":{"key":"/testkey","value":"hello world","modifiedIndex":3,"createdIndex":3}} 71 | ``` 72 | 73 | ### Docker 镜像方式下载 74 | 75 | 镜像名称为 quay.io/coreos/etcd:v2.0.0_rc.1,可以通过下面的命令启动 etcd 服务监听到 4001 端口。 76 | ``` 77 | $ sudo docker run -p 4001:4001 -v /etc/ssl/certs/:/etc/ssl/certs/ quay.io/coreos/etcd:v2.0.0_rc.1 78 | ``` 79 | -------------------------------------------------------------------------------- /fig/intro.md: -------------------------------------------------------------------------------- 1 | ##快速搭建基于 Docker 的隔离开发环境 2 | 3 | 使用 `Dockerfile` 文件指定你的应用环境,让它能在任意地方复制使用: 4 | 5 | ``` 6 | FROM python:2.7 7 | ADD . /code 8 | WORKDIR /code 9 | RUN pip install -r requirements.txt 10 | ``` 11 | 12 | 在 `fig.yml` 文件中指定应用使用的不同服务,让它们能够在一个独立的环境中一起运行: 13 | 14 | ``` 15 | web: 16 | build: . 17 | command: python app.py 18 | links: 19 | - db 20 | ports: 21 | - "8000:8000" 22 | db: 23 | image: postgres 24 | ``` 25 | **注意不需要再额外安装 Postgres 了!* 26 | 27 | 接着执行命令 `fig up` ,然后 Fig 就会启动并运行你的应用了。 28 | 29 | ![Docker](../_images/fig-example-large.gif) 30 | 31 | Fig 可用的命令有: 32 | 33 | * 启动、停止,和重建服务 34 | * 查看服务的运行状态 35 | * 查看运行中的服务的输入日志 36 | * 对服务发送命令 37 | 38 | ##快速上手 39 | 我们试着让一个基本的 Python web 应用运行在 Fig 上。这个实验假设你已经知道一些 Python 知识,如果你不熟悉,但清楚概念上的东西也是没有问题的。 40 | 41 | 首先,[安装 Docker 和 Fig](install.md) 42 | 43 | 为你的项目创建一个目录 44 | 45 | ``` 46 | $ mkdir figtest 47 | $ cd figtest 48 | ``` 49 | 进入目录,创建 `app.py`,这是一个能够让 Redis 上的一个值自增的简单 web 应用,基于 Flask 框架。 50 | 51 | ``` 52 | from flask import Flask 53 | from redis import Redis 54 | import os 55 | app = Flask(__name__) 56 | redis = Redis(host='redis', port=6379) 57 | 58 | @app.route('/') 59 | def hello(): 60 | redis.incr('hits') 61 | return 'Hello World! I have been seen %s times.' % redis.get('hits') 62 | 63 | if __name__ == "__main__": 64 | app.run(host="0.0.0.0", debug=True) 65 | ``` 66 | 在 `requirements.txt` 文件中指定应用的 Python 依赖包。 67 | 68 | ``` 69 | flask 70 | redis 71 | ``` 72 | 下一步我们要创建一个包含应用所有依赖的 Docker 镜像,这里将阐述怎么通过 `Dockerfile` 文件来创建。 73 | 74 | ``` 75 | FROM python:2.7 76 | ADD . /code 77 | WORKDIR /code 78 | RUN pip install -r requirements.txt 79 | ``` 80 | 以上的内容首先告诉 Docker 在容器里面安装 Python ,代码的路径还有Python 依赖包。关于 Dockerfile 的更多信息可以查看 [镜像创建](../image/create.md#利用 Dockerfile 来创建镜像) 和 [Dockerfile 使用](../dockerfile/README.md) 81 | 82 | 接着我们通过 `fig.yml` 文件指定一系列的服务: 83 | 84 | ``` 85 | web: 86 | build: . 87 | command: python app.py 88 | ports: 89 | - "5000:5000" 90 | volumes: 91 | - .:/code 92 | links: 93 | - redis 94 | redis: 95 | image: redis 96 | ``` 97 | 这里指定了两个服务: 98 | 99 | * web 服务,通过当前目录的 `Dockerfile` 创建。并且说明了在容器里面执行`python app.py ` 命令 ,转发在容器里开放的 5000 端口到本地主机的 5000 端口,连接 Redis 服务,并且挂载当前目录到容器里面,这样我们就可以不用重建镜像也能直接使用代码。 100 | * redis 服务,我们使用公用镜像 [redis](https://registry.hub.docker.com/_/redis/)。 101 | * 102 | 现在如果执行 `fig up` 命令 ,它就会拉取 redis 镜像,启动所有的服务。 103 | 104 | ``` 105 | $ fig up 106 | Pulling image redis... 107 | Building web... 108 | Starting figtest_redis_1... 109 | Starting figtest_web_1... 110 | redis_1 | [8] 02 Jan 18:43:35.576 # Server started, Redis version 2.8.3 111 | web_1 | * Running on http://0.0.0.0:5000/ 112 | ``` 113 | 这个 web 应用已经开始在你的 docker 守护进程里面监听着 5000 端口了(如果你有使用 boot2docker ,执行 `boot2docker ip` ,就会看到它的地址)。 114 | 115 | 如果你想要在后台运行你的服务,可以在执行 `fig up` 命令的时候添加 `-d` 参数,然后使用 `fig ps` 查看有什么进程在运行。 116 | 117 | ``` 118 | $ fig up -d 119 | Starting figtest_redis_1... 120 | Starting figtest_web_1... 121 | $ fig ps 122 | Name Command State Ports 123 | ------------------------------------------------------------------- 124 | figtest_redis_1 /usr/local/bin/run Up 125 | figtest_web_1 /bin/sh -c python app.py Up 5000->5000/tcp 126 | ``` 127 | 128 | `fig run` 指令可以帮你向服务发送命令。例如:查看 web 服务可以获取到的环境变量: 129 | 130 | ``` 131 | $ fig run web env 132 | ``` 133 | 执行帮助命令 `fig --help` 查看其它可用的参数。 134 | 135 | 假设你使用了 `fig up -d` 启动 Fig,可以通过以下命令停止你的服务: 136 | 137 | ``` 138 | $ fig stop 139 | ``` 140 | 以上内容或多或少的讲述了如何使用Fig 。通过查看下面的引用章节可以了解到关于命令、配置和环境变量的更多细节。如果你有任何想法或建议,[可以在 GitHub 上提出](https://github.com/docker/fig)。 141 | 142 | -------------------------------------------------------------------------------- /kubernetes/quickstart.md: -------------------------------------------------------------------------------- 1 | # 快速上手 2 | 3 | 目前,Kubenetes 支持在多种环境下的安装,包括本地主机(Fedora)、云服务(Google GAE、AWS 等)。然而最快速体验 Kubernetes 的方式显然是本地通过 Docker 的方式来启动相关进程。 4 | 5 | 下图展示了在单节点使用 Docker 快速部署一套 Kubernetes 的拓扑。 6 | 7 | ![在 Docker 中启动 Kubernetes](../../_images/k8s-singlenode-docker.png) 8 | 9 | Kubernetes 依赖 Etcd 服务来维护所有主节点的状态。 10 | 11 | ## 启动 Etcd 服务。 12 | ```sh 13 | docker run --net=host -d gcr.io/google_containers/etcd:2.0.9 /usr/local/bin/etcd --addr=127.0.0.1:4001 --bind-addr=0.0.0.0:4001 --data-dir=/var/etcd/data 14 | ``` 15 | 16 | ## 启动主节点 17 | 启动 kubelet。 18 | ```sh 19 | docker run --net=host -d -v /var/run/docker.sock:/var/run/docker.sock gcr.io/google_containers/hyperkube:v0.17.0 /hyperkube kubelet --api_servers=http://localhost:8080 --v=2 --address=0.0.0.0 --enable_server --hostname_override=127.0.0.1 --config=/etc/kubernetes/manifests 20 | ``` 21 | 22 | ## 启动服务代理 23 | ```sh 24 | docker run -d --net=host --privileged gcr.io/google_containers/hyperkube:v0.17.0 /hyperkube proxy --master=http://127.0.0.1:8080 --v=2 25 | ``` 26 | 27 | ## 测试状态 28 | 在本地访问 8080 端口,应该获取到类似如下的结果: 29 | ```sh 30 | $ curl 127.0.0.1:8080 31 | { 32 | "paths": [ 33 | "/api", 34 | "/api/v1beta1", 35 | "/api/v1beta2", 36 | "/api/v1beta3", 37 | "/healthz", 38 | "/healthz/ping", 39 | "/logs/", 40 | "/metrics", 41 | "/static/", 42 | "/swagger-ui/", 43 | "/swaggerapi/", 44 | "/validate", 45 | "/version" 46 | ] 47 | } 48 | ``` 49 | 50 | ## 查看服务 51 | 所有服务启动后过一会,查看本地实际运行的 Docker 容器,应该有如下几个。 52 | ```sh 53 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 54 | ee054db2516c gcr.io/google_containers/hyperkube:v0.17.0 "/hyperkube schedule 2 days ago Up 1 days k8s_scheduler.509f29c9_k8s-master-127.0.0.1_default_9941e5170b4365bd4aa91f122ba0c061_e97037f5 55 | 3b0f28de07a2 gcr.io/google_containers/hyperkube:v0.17.0 "/hyperkube apiserve 2 days ago Up 1 days k8s_apiserver.245e44fa_k8s-master-127.0.0.1_default_9941e5170b4365bd4aa91f122ba0c061_6ab5c23d 56 | 2eaa44ecdd8e gcr.io/google_containers/hyperkube:v0.17.0 "/hyperkube controll 2 days ago Up 1 days k8s_controller-manager.33f83d43_k8s-master-127.0.0.1_default_9941e5170b4365bd4aa91f122ba0c061_1a60106f 57 | 30aa7163cbef gcr.io/google_containers/hyperkube:v0.17.0 "/hyperkube proxy -- 2 days ago Up 1 days jolly_davinci 58 | a2f282976d91 gcr.io/google_containers/pause:0.8.0 "/pause" 2 days ago Up 2 days k8s_POD.e4cc795_k8s-master-127.0.0.1_default_9941e5170b4365bd4aa91f122ba0c061_e8085b1f 59 | c060c52acc36 gcr.io/google_containers/hyperkube:v0.17.0 "/hyperkube kubelet 2 days ago Up 1 days serene_nobel 60 | cc3cd263c581 gcr.io/google_containers/etcd:2.0.9 "/usr/local/bin/etcd 2 days ago Up 1 days happy_turing 61 | ``` 62 | 63 | 这些服务大概分为三类:主节点服务、工作节点服务和其它服务。 64 | 65 | ### 主节点服务 66 | * apiserver 是整个系统的对外接口,提供 RESTful 方式供客户端和其它组件调用; 67 | * scheduler 负责对资源进行调度,分配某个 pod 到某个节点上; 68 | * controller-manager 负责管理控制器,包括 endpoint-controller(刷新服务和 pod 的关联信息)和 replication-controller(维护某个 pod 的复制为配置的数值)。 69 | 70 | ### 工作节点服务 71 | * kubelet 是工作节点执行操作的 agent,负责具体的容器生命周期管理,根据从数据库中获取的信息来管理容器,并上报 pod 运行状态等; 72 | * proxy 为 pod 上的服务提供访问的代理。 73 | 74 | ### 其它服务 75 | * etcd 是所有状态的存储数据库; 76 | * `gcr.io/google_containers/pause:0.8.0` 是 Kubernetes 启动后自动 pull 下来的测试镜像。 77 | -------------------------------------------------------------------------------- /appendix_command/README.md: -------------------------------------------------------------------------------- 1 | # Docker命令查询 2 | 3 | ##基本语法 4 | docker [OPTIONS] COMMAND [arg...] 5 | 一般来说,Docker 命令可以用来管理 daemon,或者通过 CLI 命令管理镜像和容器。可以通过 `man docker` 来查看这些命令。 6 | 7 | 8 | ##选项 9 | -D=true|false 10 | 使用 debug 模式。默认为 false。 11 | 12 | -H, --host=[unix:///var/run/docker.sock]: tcp://[host:port]来绑定或者 unix://[/path/to/socket] 来使用。 13 | 在 daemon 模式下绑定的 socket,通过一个或多个 tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd 来指定。 14 | 15 | --api-enable-cors=true|false 16 | 在远端 API 中启用 CORS 头。缺省为 false。 17 | 18 | -b="" 19 | 将容器挂载到一个已存在的网桥上。指定为 'none' 时则禁用容器的网络。 20 | 21 | --bip="" 22 | 让动态创建的 docker0 采用给定的 CIDR 地址; 与 -b 选项互斥。 23 | 24 | -d=true|false 25 | 使用 daemon 模式。缺省为 false。 26 | 27 | --dns="" 28 | 让 Docker 使用给定的 DNS 服务器。 29 | 30 | -g="" 31 | 指定 Docker 运行时的 root 路径。缺省为 /var/lib/docker。 32 | 33 | --icc=true|false 34 | 启用容器间通信。默认为 true。 35 | 36 | --ip="" 37 | 绑定端口时候的默认 IP 地址。缺省为 0.0.0.0。 38 | 39 | --iptables=true|false 40 | 禁止 Docker 添加 iptables 规则。缺省为 true。 41 | 42 | --mtu=VALUE 43 | 指定容器网络的 mtu。缺省为 1500。 44 | 45 | -p="" 46 | 指定 daemon 的 PID 文件路径。缺省为 /var/run/docker.pid。 47 | 48 | -s="" 49 | 强制 Docker 运行时使用给定的存储驱动。 50 | 51 | -v=true|false 52 | 输出版本信息并退出。缺省值为 false。 53 | 54 | --selinux-enabled=true|false 55 | 启用 SELinux 支持。缺省值为 false。SELinux 目前不支持 BTRFS 存储驱动。 56 | 57 | 58 | ##命令 59 | Docker 的命令可以采用 `docker-CMD` 或者 `docker CMD` 的方式执行。两者一致。 60 | 61 | docker-attach(1) 62 | 依附到一个正在运行的容器中。 63 | 64 | docker-build(1) 65 | 从一个 Dockerfile 创建一个镜像 66 | 67 | docker-commit(1) 68 | 从一个容器的修改中创建一个新的镜像 69 | 70 | docker-cp(1) 71 | 从容器中复制文件到宿主系统中 72 | 73 | docker-diff(1) 74 | 检查一个容器文件系统的修改 75 | 76 | docker-events(1) 77 | 从服务端获取实时的事件 78 | 79 | docker-export(1) 80 | 导出容器内容为一个 tar 包 81 | 82 | docker-history(1) 83 | 显示一个镜像的历史 84 | 85 | docker-images(1) 86 | 列出存在的镜像 87 | 88 | docker-import(1) 89 | 导入一个文件(典型为 tar 包)路径或目录来创建一个镜像 90 | 91 | docker-info(1) 92 | 显示一些相关的系统信息 93 | 94 | docker-inspect(1) 95 | 显示一个容器的底层具体信息。 96 | 97 | docker-kill(1) 98 | 关闭一个运行中的容器 (包括进程和所有资源) 99 | 100 | docker-load(1) 101 | 从一个 tar 包中加载一个镜像 102 | 103 | docker-login(1) 104 | 注册或登录到一个 Docker 的仓库服务器 105 | 106 | docker-logout(1) 107 | 从 Docker 的仓库服务器登出 108 | 109 | docker-logs(1) 110 | 获取容器的 log 信息 111 | 112 | docker-pause(1) 113 | 暂停一个容器中的所有进程 114 | 115 | docker-port(1) 116 | 查找一个 nat 到一个私有网口的公共口 117 | 118 | docker-ps(1) 119 | 列出容器 120 | 121 | docker-pull(1) 122 | 从一个Docker的仓库服务器下拉一个镜像或仓库 123 | 124 | docker-push(1) 125 | 将一个镜像或者仓库推送到一个 Docker 的注册服务器 126 | 127 | docker-restart(1) 128 | 重启一个运行中的容器 129 | 130 | docker-rm(1) 131 | 删除给定的若干个容器 132 | 133 | docker-rmi(1) 134 | 删除给定的若干个镜像 135 | 136 | docker-run(1) 137 | 创建一个新容器,并在其中运行给定命令 138 | 139 | docker-save(1) 140 | 保存一个镜像为 tar 包文件 141 | 142 | docker-search(1) 143 | 在 Docker index 中搜索一个镜像 144 | 145 | docker-start(1) 146 | 启动一个容器 147 | 148 | docker-stop(1) 149 | 终止一个运行中的容器 150 | 151 | docker-tag(1) 152 | 为一个镜像打标签 153 | 154 | docker-top(1) 155 | 查看一个容器中的正在运行的进程信息 156 | 157 | docker-unpause(1) 158 | 将一个容器内所有的进程从暂停状态中恢复 159 | 160 | docker-version(1) 161 | 输出 Docker 的版本信息 162 | 163 | docker-wait(1) 164 | 阻塞直到一个容器终止,然后输出它的退出符 165 | 166 | ##一张图总结 Docker 的命令 167 | 168 | ![命令周期](../_images/cmd_logic.png) 169 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [前言](README.md) 4 | * [Docker 简介](introduction/README.md) 5 | * [什么是 Docker](introduction/what.md) 6 | * [为什么要用 Docker](introduction/why.md) 7 | * [基本概念](basic_concept/README.md) 8 | * [镜像](basic_concept/image.md) 9 | * [容器](basic_concept/container.md) 10 | * [仓库](basic_concept/repository.md) 11 | * [安装](install/README.md) 12 | * [Ubuntu](install/ubuntu.md) 13 | * [CentOS](install/centos.md) 14 | * [镜像](image/README.md) 15 | * [获取镜像](image/pull.md) 16 | * [列出](image/list.md) 17 | * [创建](image/create.md) 18 | * [存出和载入](image/save_load.md) 19 | * [移除](image/rmi.md) 20 | * [实现原理](image/internal.md) 21 | * [容器](container/README.md) 22 | * [启动](container/run.md) 23 | * [守护态运行](container/daemon.md) 24 | * [终止](container/stop.md) 25 | * [进入容器](container/enter.md) 26 | * [导出和导入](container/import_export.md) 27 | * [删除](container/rm.md) 28 | * [仓库](repository/README.md) 29 | * [Docker Hub](repository/dockerhub.md) 30 | * [私有仓库](repository/local_repo.md) 31 | * [配置文件](repository/config.md) 32 | * [数据管理](data_management/README.md) 33 | * [数据卷](data_management/volume.md) 34 | * [数据卷容器](data_management/container.md) 35 | * [备份、恢复、迁移数据卷](data_management/management.md) 36 | * [使用网络](network/README.md) 37 | * [外部访问容器](network/port_mapping.md) 38 | * [容器互联](network/linking.md) 39 | * [高级网络配置](advanced_network/README.md) 40 | * [快速配置指南](advanced_network/quick_guide.md) 41 | * [配置 DNS](advanced_network/dns.md) 42 | * [容器访问控制](advanced_network/access_control.md) 43 | * [端口映射实现](advanced_network/port_mapping.md) 44 | * [配置 docker0 网桥](advanced_network/docker0.md) 45 | * [自定义网桥](advanced_network/bridge.md) 46 | * [工具和示例](advanced_network/example.md) 47 | * [编辑网络配置文件](advanced_network/config_file.md) 48 | * [实例:创建一个点到点连接](advanced_network/ptp.md) 49 | * [实战案例](cases/README.md) 50 | * [使用 Supervisor 来管理进程](cases/supervisor.md) 51 | * [创建 tomcat/weblogic 集群](cases/tomcat.md) 52 | * [多台物理主机之间的容器互联](cases/container_connect.md) 53 | * [标准化开发测试和生产环境](cases/environment.md) 54 | * [安全](security/README.md) 55 | * [内核名字空间](security/kernel_ns.md) 56 | * [控制组](security/control_group.md) 57 | * [服务端防护](security/daemon_sec.md) 58 | * [内核能力机制](security/kernel_capability.md) 59 | * [其它安全特性](security/other_feature.md) 60 | * [总结](security/summary.md) 61 | * [Dockerfile](dockerfile/README.md) 62 | * [基本结构](dockerfile/basic_structure.md) 63 | * [指令](dockerfile/instructions.md) 64 | * [创建镜像](dockerfile/build_image.md) 65 | * [底层实现](underly/README.md) 66 | * [基本架构](underly/arch.md) 67 | * [名字空间](underly/namespace.md) 68 | * [控制组](underly/cgroups.md) 69 | * [联合文件系统](underly/ufs.md) 70 | * [容器格式](underly/container_format.md) 71 | * [网络](underly/network.md) 72 | * [Docker Compose 项目](compose/README.md) 73 | * [简介](compose/intro.md) 74 | * [安装](compose/install.md) 75 | * [使用](compose/usage.md) 76 | * [命令说明](compose/commands.md) 77 | * [YAML 模板文件](compose/yaml_file.md) 78 | * [Docker Machine 项目](machine/README.md) 79 | * [简介](machine/intro.md) 80 | * [安装](machine/install.md) 81 | * [使用](machine/usage.md) 82 | * [Docker Swarm 项目](swarm/README.md) 83 | * [简介](swarm/intro.md) 84 | * [安装](swarm/install.md) 85 | * [使用](swarm/usage.md) 86 | * [调度器](swarm/scheduling.md) 87 | * [过滤器](swarm/filter.md) 88 | * [Etcd 项目](etcd/README.md) 89 | * [简介](etcd/intro.md) 90 | * [安装](etcd/install.md) 91 | * [使用 etcdctl](etcd/etcdctl.md) 92 | * [Fig 项目](fig/README.md) 93 | * [简介](fig/intro.md) 94 | * [安装](fig/install.md) 95 | * [命令参考](fig/cli_ref.md) 96 | * [fig.yml参考](fig/yml_ref.md) 97 | * [环境变量参考](fig/env_ref.md) 98 | * [实战 Django](fig/django.md) 99 | * [实战 Rails](fig/rails.md) 100 | * [实战 wordpress](fig/wordpress.md) 101 | * [CoreOS 项目](coreos/README.md) 102 | * [Kubernetes 项目](kubernetes/README.md) 103 | * [简介](kubernetes/intro.md) 104 | * [快速上手](kubernetes/quickstart.md) 105 | * [基本概念](kubernetes/concepts.md) 106 | * [kubectl 使用](kubernetes/kubectl.md) 107 | * [架构设计](kubernetes/design.md) 108 | * [附录一:命令查询](appendix_command/README.md) 109 | * [附录二:常见仓库介绍](appendix_repo/README.md) 110 | * [Ubuntu](appendix_repo/ubuntu.md) 111 | * [CentOS](appendix_repo/centos.md) 112 | * [MySQL](appendix_repo/mysql.md) 113 | * [MongoDB](appendix_repo/mongodb.md) 114 | * [Redis](appendix_repo/redis.md) 115 | * [Nginx](appendix_repo/nginx.md) 116 | * [WordPress](appendix_repo/wordpress.md) 117 | * [Node.js](appendix_repo/nodejs.md) 118 | * [附录三:有用的资源](appendix_resources/README.md) 119 | 120 | -------------------------------------------------------------------------------- /swarm/filter.md: -------------------------------------------------------------------------------- 1 | ## Swarm 过滤器 2 | swarm 的调度器(scheduler)在选择节点运行容器的时候支持几种过滤器 (filter):Constraint,Affinity,Port,Dependency,Health 3 | 4 | 可以在执行 `swarm manage` 命令的时候通过 `--filter` 选项来设置。 5 | 6 | ###Constraint Filter 7 | constraint 是一个跟具体节点相关联的键值对,可以看做是每个节点的标签,这个标签可以在启动docker daemon的时候指定,比如 8 | ```sh 9 | sudo docker -d --label label_name=label01 10 | ``` 11 | 12 | 也可以写在docker的配置文件里面(在ubuntu上面是 `/etc/default/docker`)。 13 | 14 | 在本次试验中,给083添加标签--label label_name=083,084添加标签--label label_name=084,124添加标签--label label_name=084, 15 | 16 | 以083为例,打开/etc/default/docker文件,修改DOCKER_OPTS: 17 | ```sh 18 | DOCKER_OPTS="-H 0.0.0.0:2375 -H unix:///var/run/docker.sock --label label_name=083" 19 | ``` 20 | 21 | 在使用docker run命令启动容器的时候使用 `-e constarint:key=value` 的形式,可以指定container运行的节点。 22 | 23 | 比如我们想在84上面启动一个 redis 容器。 24 | ```sh 25 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_1 -d -e constraint:label_name==084 redis 26 | fee1b7b9dde13d64690344c1f1a4c3f5556835be46b41b969e4090a083a6382d 27 | ``` 28 | 注意,是**两个**等号,不是一个等号,这一点会经常被忽略。 29 | 30 | 接下来再在084这台机器上启动一个redis 容器。 31 | ```sh 32 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_2 -d -e constraint:label_name==084 redis 4968d617d9cd122fc2e17b3bad2f2c3b5812c0f6f51898024a96c4839fa000e1 33 | ``` 34 | 然后再在083这台机器上启动另外一个 redis 容器。 35 | ```sh 36 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_3 -d -e constraint:label_name==083 redis 7786300b8d2232c2335ac6161c715de23f9179d30eb5c7e9c4f920a4f1d39570 37 | ``` 38 | 39 | 现在来看下执行情况: 40 | ```sh 41 | rio@085:~$ sudo docker -H 192.168.1.83:2376 ps 42 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 43 | 7786300b8d22 redis:latest "/entrypoint.sh redi 15 minutes ago Up 53 seconds 6379/tcp 083/redis_3 44 | 4968d617d9cd redis:latest "/entrypoint.sh redi 16 minutes ago Up 2 minutes 6379/tcp 084/redis_2 45 | fee1b7b9dde1 redis:latest "/entrypoint.sh redi 19 minutes ago Up 5 minutes 6379/tcp 084/redis_1 46 | ``` 47 | 48 | 可以看到,执行结果跟预期的一样。 49 | 50 | 但是如果指定一个不存在的标签的话来运行容器会报错。 51 | ```sh 52 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_0 -d -e constraint:label_name==0 redis 53 | FATA[0000] Error response from daemon: unable to find a node that satisfies label_name==0 54 | ``` 55 | 56 | ###Affinity Filter 57 | 通过使用 Affinity Filter,可以让一个容器紧挨着另一个容器启动,也就是说让两个容器在同一个节点上面启动。 58 | 59 | 现在其中一台机器上面启动一个 redis 容器。 60 | ```sh 61 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run -d --name redis redis 62 | ea13eddf667992c5d8296557d3c282dd8484bd262c81e2b5af061cdd6c82158d 63 | rio@085:~$ sudo docker -H 192.168.1.83:2376 ps 64 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 65 | ea13eddf6679 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 6379/tcp 083/redis 66 | ``` 67 | 68 | 然后再次启动两个 redis 容器。 69 | ```sh 70 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run -d --name redis_1 -e affinity:container==redis redis 71 | bac50c2e955211047a745008fd1086eaa16d7ae4f33c192f50412e8dcd0a14cd 72 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run -d --name redis_1 -e affinity:container==redis redis 73 | bac50c2e955211047a745008fd1086eaa16d7ae4f33c192f50412e8dcd0a14cd 74 | ``` 75 | 现在来查看下运行结果,可以看到三个容器都是在一台机器上运行 76 | ```sh 77 | rio@085:~$ sudo docker -H 192.168.1.83:2376 ps 78 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 79 | 449ed25ad239 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 6379/tcp 083/redis_2 80 | bac50c2e9552 redis:latest /entrypoint.sh redis 25 minutes ago Up 10 seconds 6379/tcp 083/redis_1 81 | ea13eddf6679 redis:latest /entrypoint.sh redis 28 minutes ago Up 3 minutes 6379/tcp 083/redis 82 | ``` 83 | 通过 `-e affinity:image=image_name` 命令可以指定只有已经下载了`image_name`镜像的机器才运行容器 84 | ```sh 85 | sudo docker –H 192.168.1.83:2376 run –name redis1 –d –e affinity:image==redis redis 86 | ``` 87 | redis1 这个容器只会在已经下载了 redis 镜像的节点上运行。 88 | 89 | ```sh 90 | sudo docker -H 192.168.1.83:2376 run -d --name redis -e affinity:image==~redis redis 91 | ``` 92 | 这条命令达到的效果是:在有 redis 镜像的节点上面启动一个名字叫做 redis 的容器,如果每个节点上面都没有 redis 容器,就按照默认的策略启动 redis 容器。 93 | 94 | ###Port Filter 95 | Port 也会被认为是一个唯一的资源 96 | ```sh 97 | sudo docker -H 192.168.1.83:2376 run -d -p 80:80 nginx 98 | ``` 99 | 100 | 执行完这条命令,之后任何使用 80 端口的容器都是启动失败。 101 | -------------------------------------------------------------------------------- /swarm/scheduling.md: -------------------------------------------------------------------------------- 1 | ## swarm 调度策略 2 | swarm支持多种调度策略来选择节点。每次在swarm启动container的时候,swarm会根据选择的调度策略来选择节点运行container。目前支持的有:spread,binpack和random。 3 | 4 | 在执行`swarm manage`命令启动 swarm 集群的时候可以通过 `--strategy` 参数来指定,默认的是spread。 5 | 6 | spread和binpack策略会根据每台节点的可用CPU,内存以及正在运行的containers的数量来给各个节点分级,而random策略,顾名思义,他不会做任何的计算,只是单纯的随机选择一个节点来启动container。这种策略一般只做调试用。 7 | 8 | 使用spread策略,swarm会选择一个正在运行的container的数量最少的那个节点来运行container。这种情况会导致启动的container会尽可能的分布在不同的机器上运行,这样的好处就是如果有节点坏掉的时候不会损失太多的container。 9 | 10 | binpack 则相反,这种情况下,swarm会尽可能的把所有的容器放在一台节点上面运行。这种策略会避免容器碎片化,因为他会把未使用的机器分配给更大的容器,带来的好处就是swarm会使用最少的节点运行最多的容器。 11 | 12 | ### spread 策略 13 | 先来演示下 spread 策略的情况。 14 | ```sh 15 | rio@083:~$ sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage --strategy=spread file:///tmp/cluster 16 | 7609ac2e463f435c271d17887b7d1db223a5d696bf3f47f86925c781c000cb60 17 | ats@sclu083:~$ sudo docker ps 18 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 19 | 7609ac2e463f swarm:latest "/swarm manage --str 6 seconds ago Up 5 seconds 0.0.0.0:2376->2375/tcp focused_babbage 20 | ``` 21 | 三台机器除了83运行了 Swarm之外,其他的都没有运行任何一个容器,现在在85这台节点上面在swarm集群上启动一个容器 22 | ```sh 23 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-1 -d -P redis 24 | 2553799f1372b432e9b3311b73e327915d996b6b095a30de3c91a47ff06ce981 25 | rio@085:~$ sudo docker -H 192.168.1.83:2376 ps 26 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 27 | 2553799f1372 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 192.168.1.84:32770->6379/tcp 084/node-1 28 | ``` 29 | 启动一个 redis 容器,查看结果 30 | ```sh 31 | 32 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-2 -d -P redis 33 | 7965a17fb943dc6404e2c14fb8585967e114addca068f233fcaf60c13bcf2190 34 | rio@085:~$ sudo docker -H 192.168.1.83:2376 ps 35 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 36 | 7965a17fb943 redis:latest /entrypoint.sh redis Less than a second ago Up 1 seconds 192.168.1.124:49154->6379/tcp 124/node-2 37 | 2553799f1372 redis:latest /entrypoint.sh redis 29 minutes ago Up 4 minutes 192.168.1.84:32770->6379/tcp 084/node-1 38 | ``` 39 | 再次启动一个 redis 容器,查看结果 40 | ```sh 41 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-3 -d -P redis 42 | 65e1ed758b53fbf441433a6cb47d288c51235257cf1bf92e04a63a8079e76bee 43 | rio@085:~$ sudo docker -H 192.168.1.83:2376 ps 44 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 45 | 7965a17fb943 redis:latest /entrypoint.sh redis Less than a second ago Up 4 minutes 192.168.1.227:49154->6379/tcp 124/node-2 46 | 65e1ed758b53 redis:latest /entrypoint.sh redis 25 minutes ago Up 17 seconds 192.168.1.83:32770->6379/tcp 083/node-3 47 | 2553799f1372 redis:latest /entrypoint.sh redis 33 minutes ago Up 8 minutes 192.168.1.84:32770->6379/tcp 084/node-1 48 | ``` 49 | 可以看到三个容器都是分布在不同的节点上面的。 50 | 51 | ### binpack 策略 52 | 现在来看看binpack策略下的情况。在083上面执行命令: 53 | ```sh 54 | rio@083:~$ sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage --strategy=binpack file:///tmp/cluster 55 | f1c9affd5a0567870a45a8eae57fec7c78f3825f3a53fd324157011aa0111ac5 56 | ``` 57 | 58 | 现在在集群中启动三个 redis 容器,查看分布情况: 59 | ```sh 60 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-1 -d -P redis 61 | 18ceefa5e86f06025cf7c15919fa64a417a9d865c27d97a0ab4c7315118e348c 62 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-2 -d -P redis 63 | 7e778bde1a99c5cbe4701e06935157a6572fb8093fe21517845f5296c1a91bb2 64 | rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-3 -d -P redis 65 | 2195086965a783f0c2b2f8af65083c770f8bd454d98b7a94d0f670e73eea05f8 66 | rio@085:~$ sudo docker -H 192.168.1.83:2376 ps 67 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 68 | 2195086965a7 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 192.168.1.83:32773->6379/tcp 083/node-3 69 | 7e778bde1a99 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 192.168.1.83:32772->6379/tcp 083/node-2 70 | 18ceefa5e86f redis:latest /entrypoint.sh redis 25 minutes ago Up 22 seconds 192.168.1.83:32771->6379/tcp 083/node-1 71 | ``` 72 | 73 | 可以看到,所有的容器都是分布在同一个节点上运行的。 -------------------------------------------------------------------------------- /compose/yaml_file.md: -------------------------------------------------------------------------------- 1 | ## YAML 模板文件 2 | 3 | 默认的模板文件是 `docker-compose.yml`,其中定义的每个服务都必须通过 `image` 指令指定镜像或 `build` 指令(需要 Dockerfile)来自动构建。 4 | 5 | 其它大部分指令都跟 `docker run` 中的类似。 6 | 7 | 如果使用 `build` 指令,在 `Dockerfile` 中设置的选项(例如:`CMD`, `EXPOSE`, `VOLUME`, `ENV` 等) 将会自动被获取,无需在 `docker-compose.yml` 中再次设置。 8 | 9 | ### `image` 10 | 11 | 指定为镜像名称或镜像 ID。如果镜像在本地不存在,`Compose` 将会尝试拉去这个镜像。 12 | 13 | 例如: 14 | ```sh 15 | image: ubuntu 16 | image: orchardup/postgresql 17 | image: a4bc65fd 18 | ``` 19 | 20 | ### `build` 21 | 22 | 指定 `Dockerfile` 所在文件夹的路径。 `Compose` 将会利用它自动构建这个镜像,然后使用这个镜像。 23 | 24 | ``` 25 | build: /path/to/build/dir 26 | ``` 27 | 28 | ### `command` 29 | 30 | 覆盖容器启动后默认执行的命令。 31 | 32 | ```sh 33 | command: bundle exec thin -p 3000 34 | ``` 35 | 36 | ### `links` 37 | 38 | 链接到其它服务中的容器。使用服务名称(同时作为别名)或服务名称:服务别名 `(SERVICE:ALIAS)` 格式都可以。 39 | 40 | ```sh 41 | links: 42 | - db 43 | - db:database 44 | - redis 45 | ``` 46 | 47 | 使用的别名将会自动在服务容器中的 `/etc/hosts` 里创建。例如: 48 | 49 | ```sh 50 | 172.17.2.186 db 51 | 172.17.2.186 database 52 | 172.17.2.187 redis 53 | ``` 54 | 55 | 相应的环境变量也将被创建。 56 | 57 | ### `external_links` 58 | 链接到 docker-compose.yml 外部的容器,甚至 并非 `Compose` 管理的容器。参数格式跟 `links` 类似。 59 | 60 | ``` 61 | external_links: 62 | - redis_1 63 | - project_db_1:mysql 64 | - project_db_1:postgresql 65 | ``` 66 | 67 | 68 | ### `ports` 69 | 70 | 暴露端口信息。 71 | 72 | 使用宿主:容器 `(HOST:CONTAINER)`格式或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。 73 | 74 | ``` 75 | ports: 76 | - "3000" 77 | - "8000:8000" 78 | - "49100:22" 79 | - "127.0.0.1:8001:8001" 80 | ``` 81 | 82 | *注:当使用 `HOST:CONTAINER` 格式来映射端口时,如果你使用的容器端口小于 60 你可能会得到错误得结果,因为 `YAML` 将会解析 `xx:yy` 这种数字格式为 60 进制。所以建议采用字符串格式。* 83 | 84 | 85 | ### `expose` 86 | 87 | 暴露端口,但不映射到宿主机,只被连接的服务访问。 88 | 89 | 仅可以指定内部端口为参数 90 | 91 | ```sh 92 | expose: 93 | - "3000" 94 | - "8000" 95 | ``` 96 | 97 | ### `volumes` 98 | 99 | 卷挂载路径设置。可以设置宿主机路径 (`HOST:CONTAINER`) 或加上访问模式 (`HOST:CONTAINER:ro`)。 100 | 101 | ```sh 102 | volumes: 103 | - /var/lib/mysql 104 | - cache/:/tmp/cache 105 | - ~/configs:/etc/configs/:ro 106 | ``` 107 | 108 | ### `volumes_from` 109 | 110 | 从另一个服务或容器挂载它的所有卷。 111 | 112 | ```sh 113 | volumes_from: 114 | - service_name 115 | - container_name 116 | ``` 117 | 118 | ### `environment` 119 | 120 | 设置环境变量。你可以使用数组或字典两种格式。 121 | 122 | 只给定名称的变量会自动获取它在 Compose 主机上的值,可以用来防止泄露不必要的数据。 123 | 124 | ``` 125 | environment: 126 | RACK_ENV: development 127 | SESSION_SECRET: 128 | 129 | environment: 130 | - RACK_ENV=development 131 | - SESSION_SECRET 132 | ``` 133 | 134 | ### `env_file` 135 | 从文件中获取环境变量,可以为单独的文件路径或列表。 136 | 137 | 如果通过 `docker-compose -f FILE` 指定了模板文件,则 `env_file` 中路径会基于模板文件路径。 138 | 139 | 如果有变量名称与 `environment` 指令冲突,则以后者为准。 140 | 141 | ```sh 142 | env_file: .env 143 | 144 | env_file: 145 | - ./common.env 146 | - ./apps/web.env 147 | - /opt/secrets.env 148 | ``` 149 | 150 | 环境变量文件中每一行必须符合格式,支持 `#` 开头的注释行。 151 | 152 | ```sh 153 | # common.env: Set Rails/Rack environment 154 | RACK_ENV=development 155 | ``` 156 | 157 | ### `extends` 158 | 基于已有的服务进行扩展。例如我们已经有了一个 webapp 服务,模板文件为 `common.yml`。 159 | ```sh 160 | # common.yml 161 | webapp: 162 | build: ./webapp 163 | environment: 164 | - DEBUG=false 165 | - SEND_EMAILS=false 166 | ``` 167 | 168 | 编写一个新的 `development.yml` 文件,使用 `common.yml` 中的 webapp 服务进行扩展。 169 | ```sh 170 | # development.yml 171 | web: 172 | extends: 173 | file: common.yml 174 | service: webapp 175 | ports: 176 | - "8000:8000" 177 | links: 178 | - db 179 | environment: 180 | - DEBUG=true 181 | db: 182 | image: postgres 183 | ``` 184 | 后者会自动继承 common.yml 中的 webapp 服务及相关环节变量。 185 | 186 | 187 | ### `net` 188 | 189 | 设置网络模式。使用和 `docker client` 的 `--net` 参数一样的值。 190 | 191 | ```sh 192 | net: "bridge" 193 | net: "none" 194 | net: "container:[name or id]" 195 | net: "host" 196 | ``` 197 | 198 | ### `pid` 199 | 跟主机系统共享进程命名空间。打开该选项的容器可以相互通过进程 ID 来访问和操作。 200 | 201 | ```sh 202 | pid: "host" 203 | ``` 204 | 205 | ### `dns` 206 | 207 | 配置 DNS 服务器。可以是一个值,也可以是一个列表。 208 | 209 | ```sh 210 | dns: 8.8.8.8 211 | dns: 212 | - 8.8.8.8 213 | - 9.9.9.9 214 | ``` 215 | 216 | ### `cap_add, cap_drop` 217 | 添加或放弃容器的 Linux 能力(Capabiliity)。 218 | ```sh 219 | cap_add: 220 | - ALL 221 | 222 | cap_drop: 223 | - NET_ADMIN 224 | - SYS_ADMIN 225 | ``` 226 | 227 | ### `dns_search` 228 | 229 | 配置 DNS 搜索域。可以是一个值,也可以是一个列表。 230 | 231 | ```sh 232 | dns_search: example.com 233 | dns_search: 234 | - domain1.example.com 235 | - domain2.example.com 236 | ``` 237 | 238 | ### `working_dir, entrypoint, user, hostname, domainname, mem_limit, privileged, restart, stdin_open, tty, cpu_shares` 239 | 240 | 这些都是和 `docker run` 支持的选项类似。 241 | 242 | ``` 243 | cpu_shares: 73 244 | 245 | working_dir: /code 246 | entrypoint: /code/entrypoint.sh 247 | user: postgresql 248 | 249 | hostname: foo 250 | domainname: foo.com 251 | 252 | mem_limit: 1000000000 253 | privileged: true 254 | 255 | restart: always 256 | 257 | stdin_open: true 258 | tty: true 259 | ``` 260 | -------------------------------------------------------------------------------- /kubernetes/concepts.md: -------------------------------------------------------------------------------- 1 | # 基本概念 2 | 3 | ![](../_images/kubernetes_design.jpg) 4 | 5 | * 节点(Node):一个节点是一个运行 Kubernetes 中的主机。 6 | * 容器组(Pod):一个 Pod 对应于由若干容器组成的一个容器组,同个组内的容器共享一个存储卷(volume)。 7 | * 容器组生命周期(pos-states):包含所有容器状态集合,包括容器组状态类型,容器组生命周期,事件,重启策略,以及replication controllers。 8 | * Replication Controllers(replication-controllers):主要负责指定数量的pod在同一时间一起运行。 9 | * 服务(services):一个Kubernetes服务是容器组逻辑的高级抽象,同时也对外提供访问容器组的策略。 10 | * 卷(volumes):一个卷就是一个目录,容器对其有访问权限。 11 | * 标签(labels):标签是用来连接一组对象的,比如容器组。标签可以被用来组织和选择子对象。 12 | * 接口权限(accessing_the_api):端口,ip地址和代理的防火墙规则。 13 | * web 界面(ux):用户可以通过 web 界面操作Kubernetes。 14 | * 命令行操作(cli):`kubecfg`命令。 15 | 16 | 17 | ## 节点 18 | 在 Kubernetes 中,节点是实际工作的点,以前叫做 Minion。节点可以是虚拟机或者物理机器,依赖于一个集群环境。每个节点都有一些必要的服务以运行容器组,并且它们都可以通过主节点来管理。必要服务包括 Docker,kubelet 和代理服务。 19 | 20 | ### 容器状态 21 | 22 | 容器状态用来描述节点的当前状态。现在,其中包含三个信息: 23 | 24 | #### 主机IP 25 | 26 | 主机IP需要云平台来查询,Kubernetes把它作为状态的一部分来保存。如果Kubernetes没有运行在云平台上,节点ID就是必需的。IP地址可以变化,并且可以包含多种类型的IP地址,如公共IP,私有IP,动态IP,ipv6等等。 27 | 28 | #### 节点周期 29 | 30 | 通常来说节点有 `Pending`,`Running`,`Terminated`三个周期,如果Kubernetes发现了一个节点并且其可用,那么Kubernetes就把它标记为 `Pending`。然后在某个时刻,Kubernetes将会标记其为 `Running`。节点的结束周期称为 `Terminated`。一个已经terminated的节点不会接受和调度任何请求,并且已经在其上运行的容器组也会删除。 31 | 32 | #### 节点状态 33 | 34 | 节点的状态主要是用来描述处于 `Running`的节点。当前可用的有 `NodeReachable` 和 `NodeReady` 。以后可能会增加其他状态。`NodeReachable` 表示集群可达。`NodeReady`表示kubelet返回 StatusOk并且HTTP状态检查健康。 35 | 36 | ### 节点管理 37 | 38 | 节点并非Kubernetes创建,而是由云平台创建,或者就是物理机器、虚拟机。在Kubernetes中,节点仅仅是一条记录,节点创建之后,Kubernetes会检查其是否可用。在Kubernetes中,节点用如下结构保存: 39 | 40 | ``` 41 | { 42 | "id": "10.1.2.3", 43 | "kind": "Minion", 44 | "apiVersion": "v1beta1", 45 | "resources": { 46 | "capacity": { 47 | "cpu": 1000, 48 | "memory": 1073741824 49 | }, 50 | }, 51 | "labels": { 52 | "name": "my-first-k8s-node", 53 | }, 54 | } 55 | ``` 56 | 57 | Kubernetes校验节点可用依赖于id。在当前的版本中,有两个接口可以用来管理节点:节点控制和Kube管理。 58 | 59 | ### 节点控制 60 | 61 | 在Kubernetes主节点中,节点控制器是用来管理节点的组件。主要包含: 62 | * 集群范围内节点同步 63 | * 单节点生命周期管理 64 | 65 | 节点控制有一个同步轮寻,主要监听所有云平台的虚拟实例,会根据节点状态创建和删除。可以通过 `--node_sync_period`标志来控制该轮寻。如果一个实例已经创建,节点控制将会为其创建一个结构。同样的,如果一个节点被删除,节点控制也会删除该结构。在Kubernetes启动时可用通过 `--machines`标记来显示指定节点。同样可以使用 `kubectl`来一条一条的添加节点,两者是相同的。通过设置 `--sync_nodes=false`标记来禁止集群之间的节点同步,你也可以使用api/kubectl 命令行来增删节点。 66 | 67 | ## 容器组 68 | 69 | 在Kubernetes中,使用的最小单位是容器组,容器组是创建,调度,管理的最小单位。 70 | 一个容器组使用相同的Dokcer容器并共享卷(挂载点)。一个容器组是一个特定运用的打包集合,包含一个或多个容器。 71 | 72 | 和运行的容器类似,一个容器组被认为只有很短的运行周期。容器组被调度到一组节点运行,知道容器的生命周期结束或者其被删除。如果节点死掉,运行在其上的容器组将会被删除而不是重新调度。(也许在将来的版本中会添加容器组的移动)。 73 | 74 | ### 容器组设计的初衷 75 | 76 | ### 资源共享和通信 77 | 78 | 容器组主要是为了数据共享和它们之间的通信。 79 | 80 | 在一个容器组中,容器都使用相同的网络地址和端口,可以通过本地网络来相互通信。每个容器组都有独立的ip,可用通过网络来和其他物理主机或者容器通信。 81 | 82 | 容器组有一组存储卷(挂载点),主要是为了让容器在重启之后可以不丢失数据。 83 | 84 | ### 容器组管理 85 | 86 | 容器组是一个运用管理和部署的高层次抽象,同时也是一组容器的接口。容器组是部署、水平放缩的最小单位。 87 | 88 | ### 容器组的使用 89 | 90 | 容器组可以通过组合来构建复杂的运用,其本来的意义包含: 91 | 92 | * 内容管理,文件和数据加载以及本地缓存管理等。 93 | * 日志和检查点备份,压缩,快照等。 94 | * 监听数据变化,跟踪日志,日志和监控代理,消息发布等。 95 | * 代理,网桥 96 | * 控制器,管理,配置以及更新 97 | 98 | ### 替代方案 99 | 100 | 为什么不在一个单一的容器里运行多个程序? 101 | 102 | * 1.透明化。为了使容器组中的容器保持一致的基础设施和服务,比如进程管理和资源监控。这样设计是为了用户的便利性。 103 | * 2.解偶软件之间的依赖。每个容器都可能重新构建和发布,Kubernetes必须支持热发布和热更新(将来)。 104 | * 3.方便使用。用户不必运行独立的程序管理,也不用担心每个运用程序的退出状态。 105 | * 4.高效。考虑到基础设施有更多的职责,容器必须要轻量化。 106 | 107 | ### 容器组的生命状态 108 | 109 | 包括若干状态值:pending、running、succeeded、failed。 110 | 111 | #### pending 112 | 113 | 容器组已经被节点接受,但有一个或多个容器还没有运行起来。这将包含某些节点正在下载镜像的时间,这种情形会依赖于网络情况。 114 | 115 | #### running 116 | 117 | 容器组已经被调度到节点,并且所有的容器都已经启动。至少有一个容器处于运行状态(或者处于重启状态)。 118 | 119 | #### succeeded 120 | 121 | 所有的容器都正常退出。 122 | 123 | #### failed 124 | 125 | 容器组中所有容器都意外中断了。 126 | 127 | ### 容器组生命周期 128 | 129 | 通常来说,如果容器组被创建了就不会自动销毁,除非被某种行为出发,而触发此种情况可能是人为,或者复制控制器所为。唯一例外的是容器组由 succeeded状态成功退出,或者在一定时间内重试多次依然失败。 130 | 131 | 如果某个节点死掉或者不能连接,那么节点控制器将会标记其上的容器组的状态为 `failed`。 132 | 133 | 举例如下。 134 | 135 | * 容器组状态 `running`,有 1 容器,容器正常退出 136 | * 记录完成事件 137 | * 如果重启策略为: 138 | * 始终:重启容器,容器组保持 `running` 139 | * 失败时:容器组变为 `succeeded` 140 | * 从不:容器组变为 `succeeded` 141 | * 容器组状态 `running`,有1容器,容器异常退出 142 | * 记录失败事件 143 | * 如果重启策略为: 144 | * 始终:重启容器,容器组保持 `running` 145 | * 失败时:重启容器,容器组保持 `running` 146 | * 从不:容器组变为 `failed` 147 | * 容器组状态 `running`,有2容器,有1容器异常退出 148 | * 记录失败事件 149 | * 如果重启策略为: 150 | * 始终:重启容器,容器组保持 `running` 151 | * 失败时:重启容器,容器组保持 `running` 152 | * 从不:容器组保持 `running` 153 | * 当有2容器退出 154 | * 记录失败事件 155 | * 如果重启策略为: 156 | * 始终:重启容器,容器组保持 `running` 157 | * 失败时:重启容器,容器组保持 `running` 158 | * 从不:容器组变为 `failed` 159 | * 容器组状态 `running`,容器内存不足 160 | * 标记容器错误中断 161 | * 记录内存不足事件 162 | * 如果重启策略为: 163 | * 始终:重启容器,容器组保持 `running` 164 | * 失败时:重启容器,容器组保持 `running` 165 | * 从不:记录错误事件,容器组变为 `failed` 166 | * 容器组状态 `running`,一块磁盘死掉 167 | * 杀死所有容器 168 | * 记录事件 169 | * 容器组变为 `failed` 170 | * 如果容器组运行在一个控制器下,容器组将会在其他地方重新创建 171 | * 容器组状态 `running`,对应的节点段溢出 172 | * 节点控制器等到超时 173 | * 节点控制器标记容器组 `failed` 174 | * 如果容器组运行在一个控制器下,容器组将会在其他地方重新创建 175 | 176 | ## Replication Controllers 177 | ## 服务 178 | ## 卷 179 | ## 标签 180 | ## 接口权限 181 | ## web界面 182 | ## 命令行操作 183 | -------------------------------------------------------------------------------- /image/create.md: -------------------------------------------------------------------------------- 1 | ##创建镜像 2 | 3 | 创建镜像有很多方法,用户可以从 Docker Hub 获取已有镜像并更新,也可以利用本地文件系统创建一个。 4 | 5 | ### 修改已有镜像 6 | 先使用下载的镜像启动容器。 7 | ``` 8 | $ sudo docker run -t -i training/sinatra /bin/bash 9 | root@0b2616b0e5a8:/# 10 | ``` 11 | 注意:记住容器的 ID,稍后还会用到。 12 | 13 | 在容器中添加 json 和 gem 两个应用。 14 | ``` 15 | root@0b2616b0e5a8:/# gem install json 16 | ``` 17 | 当结束后,我们使用 exit 来退出,现在我们的容器已经被我们改变了,使用 `docker commit` 命令来提交更新后的副本。 18 | ``` 19 | $ sudo docker commit -m "Added json gem" -a "Docker Newbee" 0b2616b0e5a8 ouruser/sinatra:v2 20 | 4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c 21 | ``` 22 | 其中,`-m` 来指定提交的说明信息,跟我们使用的版本控制工具一样;`-a` 可以指定更新的用户信息;之后是用来创建镜像的容器的 ID;最后指定目标镜像的仓库名和 tag 信息。创建成功后会返回这个镜像的 ID 信息。 23 | 24 | 25 | 使用 `docker images` 来查看新创建的镜像。 26 | ``` 27 | $ sudo docker images 28 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 29 | training/sinatra latest 5bc342fa0b91 10 hours ago 446.7 MB 30 | ouruser/sinatra v2 3c59e02ddd1a 10 hours ago 446.7 MB 31 | ouruser/sinatra latest 5db5f8471261 10 hours ago 446.7 MB 32 | ``` 33 | 之后,可以使用新的镜像来启动容器 34 | ``` 35 | $ sudo docker run -t -i ouruser/sinatra:v2 /bin/bash 36 | root@78e82f680994:/# 37 | ``` 38 | 39 | ###利用 Dockerfile 来创建镜像 40 | 使用 `docker commit` 来扩展一个镜像比较简单,但是不方便在一个团队中分享。我们可以使用 `docker build` 来创建一个新的镜像。为此,首先需要创建一个 Dockerfile,包含一些如何创建镜像的指令。 41 | 42 | 新建一个目录和一个 Dockerfile 43 | ``` 44 | $ mkdir sinatra 45 | $ cd sinatra 46 | $ touch Dockerfile 47 | ``` 48 | Dockerfile 中每一条指令都创建镜像的一层,例如: 49 | ``` 50 | # This is a comment 51 | FROM ubuntu:14.04 52 | MAINTAINER Docker Newbee 53 | RUN apt-get -qq update 54 | RUN apt-get -qqy install ruby ruby-dev 55 | RUN gem install sinatra 56 | ``` 57 | Dockerfile 基本的语法是 58 | * 使用`#`来注释 59 | * `FROM` 指令告诉 Docker 使用哪个镜像作为基础 60 | * 接着是维护者的信息 61 | * `RUN`开头的指令会在创建中运行,比如安装一个软件包,在这里使用 apt-get 来安装了一些软件 62 | 63 | 编写完成 Dockerfile 后可以使用 `docker build` 来生成镜像。 64 | 65 | ``` 66 | $ sudo docker build -t="ouruser/sinatra:v2" . 67 | Uploading context 2.56 kB 68 | Uploading context 69 | Step 0 : FROM ubuntu:14.04 70 | ---> 99ec81b80c55 71 | Step 1 : MAINTAINER Newbee 72 | ---> Running in 7c5664a8a0c1 73 | ---> 2fa8ca4e2a13 74 | Removing intermediate container 7c5664a8a0c1 75 | Step 2 : RUN apt-get -qq update 76 | ---> Running in b07cc3fb4256 77 | ---> 50d21070ec0c 78 | Removing intermediate container b07cc3fb4256 79 | Step 3 : RUN apt-get -qqy install ruby ruby-dev 80 | ---> Running in a5b038dd127e 81 | Selecting previously unselected package libasan0:amd64. 82 | (Reading database ... 11518 files and directories currently installed.) 83 | Preparing to unpack .../libasan0_4.8.2-19ubuntu1_amd64.deb ... 84 | Setting up ruby (1:1.9.3.4) ... 85 | Setting up ruby1.9.1 (1.9.3.484-2ubuntu1) ... 86 | Processing triggers for libc-bin (2.19-0ubuntu6) ... 87 | ---> 2acb20f17878 88 | Removing intermediate container a5b038dd127e 89 | Step 4 : RUN gem install sinatra 90 | ---> Running in 5e9d0065c1f7 91 | . . . 92 | Successfully installed rack-protection-1.5.3 93 | Successfully installed sinatra-1.4.5 94 | 4 gems installed 95 | ---> 324104cde6ad 96 | Removing intermediate container 5e9d0065c1f7 97 | Successfully built 324104cde6ad 98 | ``` 99 | 其中 `-t` 标记来添加 tag,指定新的镜像的用户信息。 100 | “.” 是 Dockerfile 所在的路径(当前目录),也可以替换为一个具体的 Dockerfile 的路径。 101 | 102 | 可以看到 build 进程在执行操作。它要做的第一件事情就是上传这个 Dockerfile 内容,因为所有的操作都要依据 Dockerfile 来进行。 103 | 然后,Dockfile 中的指令被一条一条的执行。每一步都创建了一个新的容器,在容器中执行指令并提交修改(就跟之前介绍过的 `docker commit` 一样)。当所有的指令都执行完毕之后,返回了最终的镜像 id。所有的中间步骤所产生的容器都被删除和清理了。 104 | 105 | *注意一个镜像不能超过 127 层 106 | 107 | 此外,还可以利用 `ADD` 命令复制本地文件到镜像;用 `EXPOSE` 命令来向外部开放端口;用 `CMD` 命令来描述容器启动后运行的程序等。例如 108 | ``` 109 | # put my local web site in myApp folder to /var/www 110 | ADD myApp /var/www 111 | # expose httpd port 112 | EXPOSE 80 113 | # the command to run 114 | CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"] 115 | ``` 116 | 117 | 现在可以利用新创建的镜像来启动一个容器。 118 | ``` 119 | $ sudo docker run -t -i ouruser/sinatra:v2 /bin/bash 120 | root@8196968dac35:/# 121 | ``` 122 | 还可以用 `docker tag` 命令来修改镜像的标签。 123 | ``` 124 | $ sudo docker tag 5db5f8471261 ouruser/sinatra:devel 125 | $ sudo docker images ouruser/sinatra 126 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 127 | ouruser/sinatra latest 5db5f8471261 11 hours ago 446.7 MB 128 | ouruser/sinatra devel 5db5f8471261 11 hours ago 446.7 MB 129 | ouruser/sinatra v2 5db5f8471261 11 hours ago 446.7 MB 130 | ``` 131 | 132 | *注:更多用法,请参考 [Dockerfile](../dockerfile/README.md) 章节。 133 | 134 | ### 从本地文件系统导入 135 | 要从本地文件系统导入一个镜像,可以使用 openvz(容器虚拟化的先锋技术)的模板来创建: 136 | openvz 的模板下载地址为 [templates](http://openvz.org/Download/templates/precreated) 。 137 | 138 | 比如,先下载了一个 ubuntu-14.04 的镜像,之后使用以下命令导入: 139 | ``` 140 | sudo cat ubuntu-14.04-x86_64-minimal.tar.gz |docker import - ubuntu:14.04 141 | ``` 142 | 然后查看新导入的镜像。 143 | ``` 144 | docker images 145 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 146 | ubuntu 14.04 05ac7c0b9383 17 seconds ago 215.5 MB 147 | ``` 148 | 149 | ###上传镜像 150 | 用户可以通过 `docker push` 命令,把自己创建的镜像上传到仓库中来共享。例如,用户在 Docker Hub 上完成注册后,可以推送自己的镜像到仓库中。 151 | ``` 152 | $ sudo docker push ouruser/sinatra 153 | The push refers to a repository [ouruser/sinatra] (len: 1) 154 | Sending image list 155 | Pushing repository ouruser/sinatra (3 tags) 156 | ``` 157 | -------------------------------------------------------------------------------- /swarm/usage.md: -------------------------------------------------------------------------------- 1 | ## 使用 2 | 在使用 swarm 管理集群前,需要把集群中所有的节点的 docker daemon 的监听方式更改为 `0.0.0.0:2375`。 3 | 4 | 可以有两种方式达到这个目的,第一种是在启动docker daemon的时候指定 5 | ```sh 6 | sudo docker -H 0.0.0.0:2375& 7 | ``` 8 | 9 | 第二种方式是直接修改 Docker 的配置文件(Ubuntu 上是 `/etc/default/docker`,其他版本的 Linux 上略有不同) 10 | 11 | 在文件的最后添加下面这句代码: 12 | ```sh 13 | DOCKER_OPTS="-H 0.0.0.0:2375 -H unix:///var/run/docker.sock" 14 | ``` 15 | 16 | 17 | 需要注意的是,一定要在所有希望被 Swarm 管理的节点上进行的。修改之后要重启 Docker 18 | ```sh 19 | sudo service docker restart 20 | ``` 21 | 22 | Docker 集群管理需要使用服务发现(Discovery service backend)功能,Swarm支持以下的几种方式:DockerHub 提供的服务发现功能,本地的文件,etcd,counsel,zookeeper 和 IP 列表,本文会详细讲解前两种方式,其他的用法都是大同小异的。 23 | 24 | 先说一下本次试验的环境,本次试验包括三台机器,IP地址分别为192.168.1.84,192.168.1.83和192.168.1.124.利用这三台机器组成一个docker集群,其中83这台机器同时充当swarm manager节点。 25 | 26 | ### 使用 DockerHub 提供的服务发现功能 27 | 28 | #### 创建集群 token 29 | 30 | 在上面三台机器中的任何一台机器上面执行 `swarm create` 命令来获取一个集群标志。这条命令执行完毕后,Swarm 会前往 DockerHub 上内置的发现服务中获取一个全球唯一的 token,用来标识要管理的集群。 31 | ```sh 32 | sudo docker run --rm swarm create 33 | ``` 34 | 35 | 我们在84这台机器上执行这条命令,输出如下: 36 | ```sh 37 | rio@084:~$ sudo docker run --rm swarm create 38 | b7625e5a7a2dc7f8c4faacf2b510078e 39 | ``` 40 | 41 | 可以看到我们返回的 token 是 `b7625e5a7a2dc7f8c4faacf2b510078e`,每次返回的结果都是不一样的。这个 token 一定要记住,后面的操作都会用到这个 token。 42 | 43 | #### 加入集群 44 | 45 | 在所有要加入集群的节点上面执行 `swarm join` 命令,表示要把这台机器加入这个集群当中。在本次试验中,就是要在 83、84 和 124 这三台机器上执行下面的这条命令: 46 | ```sh 47 | sudo docker run --rm swarm join addr=ip_address:2375 token://token_id 48 | ``` 49 | 其中的 ip_address 换成执行这条命令的机器的 IP,token_id 换成上一步执行 `swarm create` 返回的 token。 50 | 51 | 在83这台机器上面的执行结果如下: 52 | ```sh 53 | rio@083:~$ sudo docker run --rm swarm join --addr=192.168.1.83:2375 token://b7625e5a7a2dc7f8c4faacf2b510078e 54 | time="2015-05-19T11:48:03Z" level=info msg="Registering on the discovery service every 25 seconds..." addr="192.168.1.83:2375" discovery="token://b7625e5a7a2dc7 f8c4faacf2b510078e" 55 | ``` 56 | 这条命令不会自动返回,要我们自己执行 `Ctrl+C` 返回。 57 | 58 | #### 启动swarm manager 59 | 因为我们要使用 83 这台机器充当 swarm 管理节点,所以需要在83这台机器上面执行 `swarm manage` 命令: 60 | ```sh 61 | sudo docker run -d -p 2376:2375 swarm manage token://b7625e5a7a2dc7f8c4faacf2b510078e 62 | ``` 63 | 执行结果如下: 64 | ```sh 65 | rio@083:~$ sudo docker run -d -p 2376:2375 swarm manage token://b7625e5a7a2dc7f8c4faacf2b510078e 66 | 83de3e9149b7a0ef49916d1dbe073e44e8c31c2fcbe98d962a4f85380ef25f76 67 | ``` 68 | 这条命令如果执行成功会返回已经启动的 Swarm 的容器的 ID,此时整个集群已经启动起来了。 69 | 70 | 现在通过 `docker ps` 命令来看下有没有启动成功。 71 | ```sh 72 | rio@083:~$ sudo docker ps 73 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 74 | 83de3e9149b7 swarm:latest "/swarm manage token 4 minutes ago Up 4 minutes 0.0.0.0:2376->2375/tcp stupefied_stallman 75 | ``` 76 | 可以看到,Swarm 已经成功启动。 77 | 在执行 `Swarm manage` 这条命令的时候,有几点需要注意的: 78 | 79 | * 这条命令需要在充当 swarm 管理者的机器上执行 80 | * Swarm 要以 daemon 的形式执行 81 | * 映射的端口可以使任意的除了 2375 以外的并且是未被占用的端口,但一定不能是 2375 这个端口,因为 2375 已经被 Docker 本身给占用了。 82 | 83 | 集群启动成功以后,现在我们可以在任何一台节点上使用 `swarm list` 命令查看集群中的节点了,本实验在 124 这台机器上执行 `swarm list` 命令: 84 | ```sh 85 | rio@124:~$ sudo docker run --rm swarm list token://b7625e5a7a2dc7f8c4faacf2b510078e 86 | 192.168.1.84:2375 87 | 192.168.1.124:2375 88 | 192.168.1.83:2375 89 | ``` 90 | 输出结果列出的IP地址正是我们使用 `swarm join` 命令加入集群的机器的IP地址。 91 | 92 | 现在我们可以在任何一台安装了 Docker 的机器上面通过命令(命令中要指明swarm manager机器的IP地址)来在集群中运行container了。 93 | 本次试验,我们在 192.168.1.85 这台机器上使用 `docker info` 命令来查看集群中的节点的信息。 94 | 95 | 其中 info 也可以换成其他的 Docker 支持的命令。 96 | ```sh 97 | rio@085:~$ sudo docker -H 192.168.1.83:2376 info 98 | Containers: 8 99 | Strategy: spread 100 | Filters: affinity, health, constraint, port, dependency 101 | Nodes: 2 102 | sclu083: 192.168.1.83:2375 103 | └ Containers: 1 104 | └ Reserved CPUs: 0 / 2 105 | └ Reserved Memory: 0 B / 4.054 GiB 106 | sclu084: 192.168.1.84:2375 107 | └ Containers: 7 108 | └ Reserved CPUs: 0 / 2 109 | └ Reserved Memory: 0 B / 4.053 GiB 110 | ``` 111 | 结果输出显示这个集群中只有两个节点,IP地址分别是 192.168.1.83 和 192.168.1.84,结果不对呀,我们明明把三台机器加入了这个集群,还有 124 这一台机器呢? 112 | 经过排查,发现是忘了修改 124 这台机器上面改 docker daemon 的监听方式,只要按照上面的步骤修改写 docker daemon 的监听方式就可以了。 113 | 114 | 在使用这个方法的时候,使用swarm create可能会因为网络的原因会出现类似于下面的这个问题: 115 | ```sh 116 | rio@227:~$ sudo docker run --rm swarm create 117 | [sudo] password for rio: 118 | time="2015-05-19T12:59:26Z" level=fatal msg="Post https://discovery-stage.hub.docker.com/v1/clusters: dial tcp: i/o timeout" 119 | ``` 120 | 121 | ### 使用文件 122 | 123 | 第二种方法相对于第一种方法要简单得多,也不会出现类似于上面的问题。 124 | 125 | 第一步:在 swarm 管理节点上新建一个文件,把要加入集群的机器 IP 地址和端口号写入文件中,本次试验就是要在83这台机器上面操作: 126 | ```sh 127 | rio@083:~$ echo 192.168.1.83:2375 >> cluster 128 | rio@083:~$ echo 192.168.1.84:2375 >> cluster 129 | rio@083:~$ echo 192.168.1.124:2375 >> cluster 130 | rio@083:~$ cat cluster 131 | 192.168.1.83:2375 132 | 192.168.1.84:2375 133 | 192.168.1.124:2375 134 | ``` 135 | 136 | 第二步:在083这台机器上面执行 `swarm manage` 这条命令: 137 | ```sh 138 | rio@083:~$ sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage file:///tmp/cluster 139 | 364af1f25b776f99927b8ae26ca8db5a6fe8ab8cc1e4629a5a68b48951f598ad 140 | ``` 141 | 使用`docker ps`来查看有没有启动成功: 142 | ```sh 143 | rio@083:~$ sudo docker ps 144 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 145 | 364af1f25b77 swarm:latest "/swarm manage file: About a minute ago Up About a minute 0.0.0.0:2376->2375/tcp happy_euclid 146 | ``` 147 | 可以看到,此时整个集群已经启动成功。 148 | 149 | 在使用这条命令的时候需要注意的是注意:这里一定要使用-v命令,因为cluster文件是在本机上面,启动的容器默认是访问不到的,所以要通过-v命令共享。 150 | 151 | 接下来的就可以在任何一台安装了docker的机器上面通过命令使用集群,同样的,在85这台机器上执行docker info命令查看集群的节点信息: 152 | ```sh 153 | rio@s085:~$ sudo docker -H 192.168.1.83:2376 info 154 | Containers: 9 155 | Strategy: spread 156 | Filters: affinity, health, constraint, port, dependency 157 | Nodes: 3 158 | atsgxxx: 192.168.1.227:2375 159 | └ Containers: 0 160 | └ Reserved CPUs: 0 / 4 161 | └ Reserved Memory: 0 B / 2.052 GiB 162 | sclu083: 192.168.1.83:2375 163 | └ Containers: 2 164 | └ Reserved CPUs: 0 / 2 165 | └ Reserved Memory: 0 B / 4.054 GiB 166 | sclu084: 192.168.1.84:2375 167 | └ Containers: 7 168 | └ Reserved CPUs: 0 / 2 169 | └ Reserved Memory: 0 B / 4.053 GiB 170 | ``` 171 | -------------------------------------------------------------------------------- /compose/usage.md: -------------------------------------------------------------------------------- 1 | ## 使用 2 | 3 | ### 术语 4 | 首先介绍几个术语。 5 | 6 | * 服务(service):一个应用容器,实际上可以运行多个相同镜像的实例。 7 | * 项目(project):由一组关联的应用容器组成的一个完整业务单元。 8 | 9 | 可见,一个项目可以由多个服务(容器)关联而成,Compose 面向项目进行管理。 10 | 11 | ### 场景 12 | 下面,我们创建一个经典的 Web 项目:一个 [Haproxy](www.haproxy.org),挂载三个 Web 容器。 13 | 14 | 创建一个 `compose-haproxy-web` 目录,作为项目工作目录,并在其中分别创建两个子目录:`haproxy` 和 `web`。 15 | 16 | ### Web 子目录 17 | 18 | 这里用 Python 程序来提供一个简单的 HTTP 服务,打印出访问者的 IP 和 实际的本地 IP。 19 | 20 | #### index.py 21 | 22 | 编写一个 `index.py` 作为服务器文件,代码为 23 | ```sh 24 | #!/usr/bin/python 25 | #authors: yeasy.github.com 26 | #date: 2013-07-05 27 | 28 | import sys 29 | import BaseHTTPServer 30 | from SimpleHTTPServer import SimpleHTTPRequestHandler 31 | import socket 32 | import fcntl 33 | import struct 34 | import pickle 35 | from datetime import datetime 36 | from collections import OrderedDict 37 | 38 | class HandlerClass(SimpleHTTPRequestHandler): 39 | def get_ip_address(self,ifname): 40 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 41 | return socket.inet_ntoa(fcntl.ioctl( 42 | s.fileno(), 43 | 0x8915, # SIOCGIFADDR 44 | struct.pack('256s', ifname[:15]) 45 | )[20:24]) 46 | def log_message(self, format, *args): 47 | if len(args) < 3 or "200" not in args[1]: 48 | return 49 | try: 50 | request = pickle.load(open("pickle_data.txt","r")) 51 | except: 52 | request=OrderedDict() 53 | time_now = datetime.now() 54 | ts = time_now.strftime('%Y-%m-%d %H:%M:%S') 55 | server = self.get_ip_address('eth0') 56 | host=self.address_string() 57 | addr_pair = (host,server) 58 | if addr_pair not in request: 59 | request[addr_pair]=[1,ts] 60 | else: 61 | num = request[addr_pair][0]+1 62 | del request[addr_pair] 63 | request[addr_pair]=[num,ts] 64 | file=open("index.html", "w") 65 | file.write("

HA Webpage Visit Results

"); 66 | for pair in request: 67 | if pair[0] == host: 68 | guest = "LOCAL: "+pair[0] 69 | else: 70 | guest = pair[0] 71 | if (time_now-datetime.strptime(request[pair][1],'%Y-%m-%d %H:%M:%S')).seconds < 3: 72 | file.write("

#"+ str(request[pair][1]) +": "+str(request[pair][0])+ " requests " + "from <"+guest+"> to WebServer <"+pair[1]+">

") 73 | else: 74 | file.write("

#"+ str(request[pair][1]) +": "+str(request[pair][0])+ " requests " + "from <"+guest+"> to WebServer <"+pair[1]+">

") 75 | file.write(" "); 76 | file.close() 77 | pickle.dump(request,open("pickle_data.txt","w")) 78 | 79 | if __name__ == '__main__': 80 | try: 81 | ServerClass = BaseHTTPServer.HTTPServer 82 | Protocol = "HTTP/1.0" 83 | addr = len(sys.argv) < 2 and "0.0.0.0" or sys.argv[1] 84 | port = len(sys.argv) < 3 and 80 or int(sys.argv[2]) 85 | HandlerClass.protocol_version = Protocol 86 | httpd = ServerClass((addr, port), HandlerClass) 87 | sa = httpd.socket.getsockname() 88 | print "Serving HTTP on", sa[0], "port", sa[1], "..." 89 | httpd.serve_forever() 90 | except: 91 | exit() 92 | ``` 93 | 94 | #### index.html 95 | 生成一个临时的 `index.html` 文件,其内容会被 index.py 更新。 96 | ```sh 97 | $ touch index.html 98 | ``` 99 | 100 | #### Dockerfile 101 | 生成一个 Dockerfile,内容为 102 | ```sh 103 | FROM python:2.7 104 | WORKDIR /code 105 | ADD . /code 106 | EXPOSE 80 107 | CMD python index.py 108 | ``` 109 | 110 | ### haproxy 目录 111 | 在其中生成一个 `haproxy.cfg` 文件,内容为 112 | ```sh 113 | global 114 | log 127.0.0.1 local0 115 | log 127.0.0.1 local1 notice 116 | 117 | defaults 118 | log global 119 | mode http 120 | option httplog 121 | option dontlognull 122 | timeout connect 5000ms 123 | timeout client 50000ms 124 | timeout server 50000ms 125 | 126 | listen stats :70 127 | stats enable 128 | stats uri / 129 | 130 | frontend balancer 131 | bind 0.0.0.0:80 132 | mode http 133 | default_backend web_backends 134 | 135 | backend web_backends 136 | mode http 137 | option forwardfor 138 | balance roundrobin 139 | server weba weba:80 check 140 | server webb webb:80 check 141 | server webc webc:80 check 142 | option httpchk GET / 143 | http-check expect status 200 144 | ``` 145 | ### docker-compose.yml 146 | 编写 docker-compose.yml 文件,这个是 Compose 使用的主模板文件。内容十分简单,指定 3 个 web 容器,以及 1 个 haproxy 容器。 147 | 148 | ```sh 149 | weba: 150 | build: ./web 151 | expose: 152 | - 80 153 | 154 | webb: 155 | build: ./web 156 | expose: 157 | - 80 158 | 159 | webc: 160 | build: ./web 161 | expose: 162 | - 80 163 | 164 | haproxy: 165 | image: haproxy:latest 166 | volumes: 167 | - haproxy:/haproxy-override 168 | - haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro 169 | links: 170 | - weba 171 | - webb 172 | - webc 173 | ports: 174 | - "80:80" 175 | - "70:70" 176 | expose: 177 | - "80" 178 | - "70" 179 | ``` 180 | 181 | ### 运行 compose 项目 182 | 现在 compose-haproxy-web 目录长成下面的样子。 183 | ```sh 184 | compose-haproxy-web 185 | ├── docker-compose.yml 186 | ├── haproxy 187 | │ └── haproxy.cfg 188 | └── web 189 | ├── Dockerfile 190 | ├── index.html 191 | └── index.py 192 | ``` 193 | 在该目录下执行 `docker-compose up` 命令,会整合输出所有容器的输出。 194 | ``` 195 | $sudo docker-compose up 196 | Recreating composehaproxyweb_webb_1... 197 | Recreating composehaproxyweb_webc_1... 198 | Recreating composehaproxyweb_weba_1... 199 | Recreating composehaproxyweb_haproxy_1... 200 | Attaching to composehaproxyweb_webb_1, composehaproxyweb_webc_1, composehaproxyweb_weba_1, composehaproxyweb_haproxy_1 201 | ``` 202 | 203 | 此时访问本地的 80 端口,会经过 haproxy 自动转发到后端的某个 web 容器上,刷新页面,可以观察到访问的容器地址的变化。 204 | 205 | 访问本地 70 端口,可以查看到 haproxy 的统计信息。 206 | 207 | 当然,还可以使用 consul、etcd 等实现服务发现,这样就可以避免手动指定后端的 web 容器了,更为灵活。 208 | -------------------------------------------------------------------------------- /repository/local_repo.md: -------------------------------------------------------------------------------- 1 | ## 私有仓库 2 | 3 | 有时候使用 Docker Hub 这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。 4 | 5 | 本节介绍如何使用本地仓库。 6 | 7 | `docker-registry` 是官方提供的工具,可以用于构建私有的镜像仓库。 8 | ### 安装运行 docker-registry 9 | #### 容器运行 10 | 在安装了 Docker 后,可以通过获取官方 registry 镜像来运行。 11 | ``` 12 | $ sudo docker run -d -p 5000:5000 registry 13 | ``` 14 | 这将使用官方的 registry 镜像来启动本地的私有仓库。 15 | 用户可以通过指定参数来配置私有仓库位置,例如配置镜像存储到 Amazon S3 服务。 16 | ``` 17 | $ sudo docker run \ 18 | -e SETTINGS_FLAVOR=s3 \ 19 | -e AWS_BUCKET=acme-docker \ 20 | -e STORAGE_PATH=/registry \ 21 | -e AWS_KEY=AKIAHSHB43HS3J92MXZ \ 22 | -e AWS_SECRET=xdDowwlK7TJajV1Y7EoOZrmuPEJlHYcNP2k4j49T \ 23 | -e SEARCH_BACKEND=sqlalchemy \ 24 | -p 5000:5000 \ 25 | registry 26 | ```` 27 | 此外,还可以指定本地路径(如 `/home/user/registry-conf` )下的配置文件。 28 | ``` 29 | $ sudo docker run -d -p 5000:5000 -v /home/user/registry-conf:/registry-conf -e DOCKER_REGISTRY_CONFIG=/registry-conf/config.yml registry 30 | ``` 31 | 默认情况下,仓库会被创建在容器的 `/tmp/registry` 下。可以通过 `-v` 参数来将镜像文件存放在本地的指定路径。 32 | 例如下面的例子将上传的镜像放到 `/opt/data/registry` 目录。 33 | ``` 34 | $ sudo docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry 35 | ``` 36 | 37 | #### 本地安装 38 | 对于 Ubuntu 或 CentOS 等发行版,可以直接通过源安装。 39 | * Ubuntu 40 | ``` 41 | $ sudo apt-get install -y build-essential python-dev libevent-dev python-pip liblzma-dev 42 | $ sudo pip install docker-registry 43 | ``` 44 | * CentOS 45 | ``` 46 | $ sudo yum install -y python-devel libevent-devel python-pip gcc xz-devel 47 | $ sudo python-pip install docker-registry 48 | ``` 49 | 50 | 也可以从 [docker-registry](https://github.com/docker/docker-registry) 项目下载源码进行安装。 51 | ``` 52 | $ sudo apt-get install build-essential python-dev libevent-dev python-pip libssl-dev liblzma-dev libffi-dev 53 | $ git clone https://github.com/docker/docker-registry.git 54 | $ cd docker-registry 55 | $ sudo python setup.py install 56 | ``` 57 | 然后修改配置文件,主要修改 dev 模板段的 `storage_path` 到本地的存储仓库的路径。 58 | ``` 59 | $ cp config/config_sample.yml config/config.yml 60 | ``` 61 | 之后启动 Web 服务。 62 | ``` 63 | $ sudo gunicorn -c contrib/gunicorn.py docker_registry.wsgi:application 64 | ``` 65 | 或者 66 | ``` 67 | $ sudo gunicorn --access-logfile - --error-logfile - -k gevent -b 0.0.0.0:5000 -w 4 --max-requests 100 docker_registry.wsgi:application 68 | ``` 69 | 此时使用 curl 访问本地的 5000 端口,看到输出 docker-registry 的版本信息说明运行成功。 70 | 71 | *注:`config/config_sample.yml` 文件是示例配置文件。 72 | 73 | ###在私有仓库上传、下载、搜索镜像 74 | 创建好私有仓库之后,就可以使用 `docker tag` 来标记一个镜像,然后推送它到仓库,别的机器上就可以下载下来了。例如私有仓库地址为 `192.168.7.26:5000`。 75 | 76 | 先在本机查看已有的镜像。 77 | ``` 78 | $ sudo docker images 79 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 80 | ubuntu latest ba5877dc9bec 6 weeks ago 192.7 MB 81 | ubuntu 14.04 ba5877dc9bec 6 weeks ago 192.7 MB 82 | ``` 83 | 84 | 使用`docker tag` 将 `ba58` 这个镜像标记为 `192.168.7.26:5000/test`(格式为 `docker tag IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]`)。 85 | ``` 86 | $ sudo docker tag ba58 192.168.7.26:5000/test 87 | root ~ # docker images 88 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 89 | ubuntu 14.04 ba5877dc9bec 6 weeks ago 192.7 MB 90 | ubuntu latest ba5877dc9bec 6 weeks ago 192.7 MB 91 | 192.168.7.26:5000/test latest ba5877dc9bec 6 weeks ago 192.7 MB 92 | ``` 93 | 使用 `docker push` 上传标记的镜像。 94 | ``` 95 | $ sudo docker push 192.168.7.26:5000/test 96 | The push refers to a repository [192.168.7.26:5000/test] (len: 1) 97 | Sending image list 98 | Pushing repository 192.168.7.26:5000/test (1 tags) 99 | Image 511136ea3c5a already pushed, skipping 100 | Image 9bad880da3d2 already pushed, skipping 101 | Image 25f11f5fb0cb already pushed, skipping 102 | Image ebc34468f71d already pushed, skipping 103 | Image 2318d26665ef already pushed, skipping 104 | Image ba5877dc9bec already pushed, skipping 105 | Pushing tag for rev [ba5877dc9bec] on {http://192.168.7.26:5000/v1/repositories/test/tags/latest} 106 | ``` 107 | 用 curl 查看仓库中的镜像。 108 | ``` 109 | $ curl http://192.168.7.26:5000/v1/search 110 | {"num_results": 7, "query": "", "results": [{"description": "", "name": "library/miaxis_j2ee"}, {"description": "", "name": "library/tomcat"}, {"description": "", "name": "library/ubuntu"}, {"description": "", "name": "library/ubuntu_office"}, {"description": "", "name": "library/desktop_ubu"}, {"description": "", "name": "dockerfile/ubuntu"}, {"description": "", "name": "library/test"}]} 111 | ``` 112 | 这里可以看到 `{"description": "", "name": "library/test"}`,表明镜像已经被成功上传了。 113 | 114 | 现在可以到另外一台机器去下载这个镜像。 115 | ``` 116 | $ sudo docker pull 192.168.7.26:5000/test 117 | Pulling repository 192.168.7.26:5000/test 118 | ba5877dc9bec: Download complete 119 | 511136ea3c5a: Download complete 120 | 9bad880da3d2: Download complete 121 | 25f11f5fb0cb: Download complete 122 | ebc34468f71d: Download complete 123 | 2318d26665ef: Download complete 124 | $ sudo docker images 125 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 126 | 192.168.7.26:5000/test latest ba5877dc9bec 6 weeks ago 192.7 MB 127 | ``` 128 | 129 | 可以使用 [这个脚本](https://github.com/yeasy/docker_practice/raw/master/_local/push_images.sh) 批量上传本地的镜像到注册服务器中,默认是本地注册服务器 `127.0.0.1:5000`。例如: 130 | ``` 131 | $ wget https://github.com/yeasy/docker_practice/raw/master/_local/push_images.sh; sudo chmod a+x push_images.sh 132 | $ ./push_images.sh ubuntu:latest centos:centos7 133 | The registry server is 127.0.0.1 134 | Uploading ubuntu:latest... 135 | The push refers to a repository [127.0.0.1:5000/ubuntu] (len: 1) 136 | Sending image list 137 | Pushing repository 127.0.0.1:5000/ubuntu (1 tags) 138 | Image 511136ea3c5a already pushed, skipping 139 | Image bfb8b5a2ad34 already pushed, skipping 140 | Image c1f3bdbd8355 already pushed, skipping 141 | Image 897578f527ae already pushed, skipping 142 | Image 9387bcc9826e already pushed, skipping 143 | Image 809ed259f845 already pushed, skipping 144 | Image 96864a7d2df3 already pushed, skipping 145 | Pushing tag for rev [96864a7d2df3] on {http://127.0.0.1:5000/v1/repositories/ubuntu/tags/latest} 146 | Untagged: 127.0.0.1:5000/ubuntu:latest 147 | Done 148 | Uploading centos:centos7... 149 | The push refers to a repository [127.0.0.1:5000/centos] (len: 1) 150 | Sending image list 151 | Pushing repository 127.0.0.1:5000/centos (1 tags) 152 | Image 511136ea3c5a already pushed, skipping 153 | 34e94e67e63a: Image successfully pushed 154 | 70214e5d0a90: Image successfully pushed 155 | Pushing tag for rev [70214e5d0a90] on {http://127.0.0.1:5000/v1/repositories/centos/tags/centos7} 156 | Untagged: 127.0.0.1:5000/centos:centos7 157 | Done 158 | ``` 159 | -------------------------------------------------------------------------------- /etcd/etcdctl.md: -------------------------------------------------------------------------------- 1 | ## 使用 etcdctl 2 | 3 | etcdctl 是一个命令行客户端,它能提供一些简洁的命令,供用户直接跟 etcd 服务打交道,而无需基于 HTTP API 方式。这在某些情况下将很方便,例如用户对服务进行测试或者手动修改数据库内容。我们也推荐在刚接触 etcd 时通过 etcdctl 命令来熟悉相关的操作,这些操作跟 HTTP API 实际上是对应的。 4 | 5 | etcd 项目二进制发行包中已经包含了 etcdctl 工具,没有的话,可以从 [github.com/coreos/etcd/releases](https://github.com/coreos/etcd/releases) 下载。 6 | 7 | etcdctl 支持如下的命令,大体上分为数据库操作和非数据库操作两类,后面将分别进行解释。 8 | 9 | ``` 10 | $ etcdctl -h 11 | NAME: 12 | etcdctl - A simple command line client for etcd. 13 | 14 | USAGE: 15 | etcdctl [global options] command [command options] [arguments...] 16 | 17 | VERSION: 18 | 2.0.0-rc.1 19 | 20 | COMMANDS: 21 | backup backup an etcd directory 22 | mk make a new key with a given value 23 | mkdir make a new directory 24 | rm remove a key 25 | rmdir removes the key if it is an empty directory or a key-value pair 26 | get retrieve the value of a key 27 | ls retrieve a directory 28 | set set the value of a key 29 | setdir create a new or existing directory 30 | update update an existing key with a given value 31 | updatedir update an existing directory 32 | watch watch a key for changes 33 | exec-watch watch a key for changes and exec an executable 34 | member member add, remove and list subcommands 35 | help, h Shows a list of commands or help for one command 36 | 37 | GLOBAL OPTIONS: 38 | --debug output cURL commands which can be used to reproduce the request 39 | --no-sync don't synchronize cluster information before sending request 40 | --output, -o 'simple' output response in the given format (`simple` or `json`) 41 | --peers, -C a comma-delimited list of machine addresses in the cluster (default: "127.0.0.1:4001") 42 | --cert-file identify HTTPS client using this SSL certificate file 43 | --key-file identify HTTPS client using this SSL key file 44 | --ca-file verify certificates of HTTPS-enabled servers using this CA bundle 45 | --help, -h show help 46 | --version, -v print the version 47 | ``` 48 | 49 | ### 数据库操作 50 | 数据库操作围绕对键值和目录的 CRUD (符合 REST 风格的一套操作:Create)完整生命周期的管理。 51 | 52 | etcd 在键的组织上采用了层次化的空间结构(类似于文件系统中目录的概念),用户指定的键可以为单独的名字,如 `testkey`,此时实际上放在根目录 `/` 下面,也可以为指定目录结构,如 `cluster1/node2/testkey`,则将创建相应的目录结构。 53 | 54 | *注:CRUD 即 Create, Read, Update, Delete,是符合 REST 风格的一套 API 操作。* 55 | 56 | #### set 57 | 指定某个键的值。例如 58 | ``` 59 | $ etcdctl set /testdir/testkey "Hello world" 60 | Hello world 61 | ``` 62 | 支持的选项包括: 63 | ``` 64 | --ttl '0' 该键值的超时时间(单位为秒),不配置(默认为 0)则永不超时 65 | --swap-with-value value 若该键现在的值是 value,则进行设置操作 66 | --swap-with-index '0' 若该键现在的索引值是指定索引,则进行设置操作 67 | ``` 68 | 69 | #### get 70 | 获取指定键的值。例如 71 | ``` 72 | $ etcdctl set testkey hello 73 | hello 74 | $ etcdctl update testkey world 75 | world 76 | ``` 77 | 78 | 当键不存在时,则会报错。例如 79 | ``` 80 | $ etcdctl get testkey2 81 | Error: 100: Key not found (/testkey2) [1] 82 | ``` 83 | 84 | 支持的选项为 85 | ``` 86 | --sort 对结果进行排序 87 | --consistent 将请求发给主节点,保证获取内容的一致性 88 | ``` 89 | 90 | #### update 91 | 当键存在时,更新值内容。例如 92 | ``` 93 | $ etcdctl set testkey hello 94 | hello 95 | $ etcdctl update testkey world 96 | world 97 | ``` 98 | 99 | 当键不存在时,则会报错。例如 100 | ``` 101 | $ etcdctl update testkey2 world 102 | Error: 100: Key not found (/testkey2) [1] 103 | ``` 104 | 105 | 支持的选项为 106 | ``` 107 | --ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时 108 | ``` 109 | 110 | #### rm 111 | 删除某个键值。例如 112 | ``` 113 | $ etcdctl rm testkey 114 | 115 | ``` 116 | 117 | 当键不存在时,则会报错。例如 118 | ``` 119 | $ etcdctl rm testkey2 120 | Error: 100: Key not found (/testkey2) [8] 121 | ``` 122 | 123 | 支持的选项为 124 | ``` 125 | --dir 如果键是个空目录或者键值对则删除 126 | --recursive 删除目录和所有子键 127 | --with-value 检查现有的值是否匹配 128 | --with-index '0' 检查现有的 index 是否匹配 129 | 130 | ``` 131 | 132 | #### mk 133 | 如果给定的键不存在,则创建一个新的键值。例如 134 | ``` 135 | $ etcdctl mk /testdir/testkey "Hello world" 136 | Hello world 137 | ``` 138 | 当键存在的时候,执行该命令会报错,例如 139 | ``` 140 | $ etcdctl set testkey "Hello world" 141 | Hello world 142 | $ ./etcdctl mk testkey "Hello world" 143 | Error: 105: Key already exists (/testkey) [2] 144 | ``` 145 | 146 | 支持的选项为 147 | ``` 148 | --ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时 149 | ``` 150 | 151 | 152 | #### mkdir 153 | 如果给定的键目录不存在,则创建一个新的键目录。例如 154 | ``` 155 | $ etcdctl mkdir testdir 156 | ``` 157 | 当键目录存在的时候,执行该命令会报错,例如 158 | ``` 159 | $ etcdctl mkdir testdir 160 | $ etcdctl mkdir testdir 161 | Error: 105: Key already exists (/testdir) [7] 162 | ``` 163 | 支持的选项为 164 | ``` 165 | --ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时 166 | ``` 167 | 168 | #### setdir 169 | 170 | 创建一个键目录,无论存在与否。 171 | 172 | 支持的选项为 173 | ``` 174 | --ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时 175 | ``` 176 | 177 | #### updatedir 178 | 更新一个已经存在的目录。 179 | 支持的选项为 180 | ``` 181 | --ttl '0' 超时时间(单位为秒),不配置(默认为 0)则永不超时 182 | ``` 183 | 184 | #### rmdir 185 | 删除一个空目录,或者键值对。 186 | 187 | 若目录不空,会报错 188 | ``` 189 | $ etcdctl set /dir/testkey hi 190 | hi 191 | $ etcdctl rmdir /dir 192 | Error: 108: Directory not empty (/dir) [13] 193 | ``` 194 | 195 | #### ls 196 | 列出目录(默认为根目录)下的键或者子目录,默认不显示子目录中内容。 197 | 198 | 例如 199 | ``` 200 | $ ./etcdctl set testkey 'hi' 201 | hi 202 | $ ./etcdctl set dir/test 'hello' 203 | hello 204 | $ ./etcdctl ls 205 | /testkey 206 | /dir 207 | $ ./etcdctl ls dir 208 | /dir/test 209 | ``` 210 | 211 | 支持的选项包括 212 | ``` 213 | --sort 将输出结果排序 214 | --recursive 如果目录下有子目录,则递归输出其中的内容 215 | -p 对于输出为目录,在最后添加 `/` 进行区分 216 | ``` 217 | 218 | ### 非数据库操作 219 | 220 | #### backup 221 | 备份 etcd 的数据。 222 | 223 | 支持的选项包括 224 | ``` 225 | --data-dir etcd 的数据目录 226 | --backup-dir 备份到指定路径 227 | ``` 228 | #### watch 229 | 监测一个键值的变化,一旦键值发生更新,就会输出最新的值并退出。 230 | 231 | 例如,用户更新 testkey 键值为 Hello world。 232 | ``` 233 | $ etcdctl watch testkey 234 | Hello world 235 | ``` 236 | 237 | 支持的选项包括 238 | ``` 239 | --forever 一直监测,直到用户按 `CTRL+C` 退出 240 | --after-index '0' 在指定 index 之前一直监测 241 | --recursive 返回所有的键值和子键值 242 | ``` 243 | #### exec-watch 244 | 监测一个键值的变化,一旦键值发生更新,就执行给定命令。 245 | 246 | 例如,用户更新 testkey 键值。 247 | ``` 248 | $etcdctl exec-watch testkey -- sh -c 'ls' 249 | default.etcd 250 | Documentation 251 | etcd 252 | etcdctl 253 | etcd-migrate 254 | README-etcdctl.md 255 | README.md 256 | ``` 257 | 258 | 支持的选项包括 259 | ``` 260 | --after-index '0' 在指定 index 之前一直监测 261 | --recursive 返回所有的键值和子键值 262 | ``` 263 | 264 | #### member 265 | 通过 list、add、remove 命令列出、添加、删除 etcd 实例到 etcd 集群中。 266 | 267 | 例如本地启动一个 etcd 服务实例后,可以用如下命令进行查看。 268 | ``` 269 | $ etcdctl member list 270 | ce2a822cea30bfca: name=default peerURLs=http://localhost:2380,http://localhost:7001 clientURLs=http://localhost:2379,http://localhost:4001 271 | 272 | ``` 273 | ### 命令选项 274 | * `--debug` 输出 cURL 命令,显示执行命令的时候发起的请求 275 | * `--no-sync` 发出请求之前不同步集群信息 276 | * `--output, -o 'simple'` 输出内容的格式 (`simple` 为原始信息,`json` 为进行json格式解码,易读性好一些) 277 | * `--peers, -C` 指定集群中的同伴信息,用逗号隔开 (默认为: "127.0.0.1:4001") 278 | * `--cert-file` HTTPS 下客户端使用的 SSL 证书文件 279 | * `--key-file` HTTPS 下客户端使用的 SSL 密钥文件 280 | * `--ca-file` 服务端使用 HTTPS 时,使用 CA 文件进行验证 281 | * `--help, -h` 显示帮助命令信息 282 | * `--version, -v` 打印版本信息 283 | --------------------------------------------------------------------------------