Docker 使用 C/S 架构。Docker 客户端与 docker 守护进程进行通信,docker 容器的构建、运行、发布均是由 docker daemon 完成的。Docker 的客户端与服务端既可在同一系统中运行,也可以用客户端连接到远端的服务端。它们之间是借助 UNIX 套接字或网络接口,使用 REST API 进行通信。

image-center

常用全局命令

命令 说明
查看命令列表 docker
查看版本 docker --version
查看版本 docker version
查看详细安装信息 docker info

docker 守护进程

dockerd 会侦听 docker API 的请求,它还负责管理 docker 对象,如镜像、容器、网络、映射卷等。dockerd 还可以与其它守护进程进行通信,以管理 docker 的服务。

docker 客户端

docker 是客户端,用户主要通过它与 docker 服务端进行交互。在使用 docker container run 这样的命令时,客户端会将这些命令发送给 dockerd,由它来执行。docker 命令需要使用 docker API。docker 客户端可以与多个守护进程进行通信。

docker 仓库

docker registry

Docker 仓库用来保存 docker 镜像。Docker Hub 是公共的仓库,所有人都可以使用,docker 默认的配置会自动从 Docker Hub 查找镜像。如果需要,也可以运行私有仓库。如果使用 Docker Datacenter,其中就包含 Docer Trusted Registry。

在使用 docker pulldocker run 命令时,所需的镜像会从当前配置的仓库拉取;在使用 docker push 时,也会把镜像推送到当前配置的仓库中。

在 Docker store 中,可以购买、销售自己的 docker 镜像,当然也可以免费提供。例如,你可以从软件商手里购买一个镜像,其中包含一个应用或服务,然后使用该镜像将应用部署到你的测试、预发布、生产环境中。通过推送新版本并重新部署,来实现应用的升级。

docker 对象

镜像

image

镜像是个只读的模板,其中包含用来创建 docker 容器的指令。一个镜像经常是基于另一个镜像的,在原来的基础上进行了一些个性化的定制。例如,可以基于 ubuntu 镜像创建一个新的镜像,但在其中可以安装 Apache 和应用程序,以及必要的配置文件。

容器是由运行一个镜像得到的,镜像 是一个可执行的文件包,其中包含了应用程序运行所需的一切:代码、运行时、库、环境变量、配置文件。

容器 是镜像的一个运行时实例,执行镜像以后,在内存中得到的就是容器。可以用 docker ps 查看当前运行状态的容器。

Docker 把应用程序及其依赖,打包在镜像文件里面。只有通过这个文件,才能生成 Docker 容器。镜像文件可以看作是容器的模板。Docker 根据镜像文件生成容器的实例。同一个镜像文件,可以生成多个同时运行的容器实例。

镜像是二进制文件。实际开发中,一个镜像文件往往通过继承另一个镜像文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的镜像基础上,往里面加入 Apache 服务器,形成你的镜像。

# 查看本机所有镜像文件
$ docker image ls

# 删除镜像文件
$ docker image rm imagefile

镜像文件是通用的,一台机器的镜像文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的镜像文件,而不是自己制作。即使要定制,也应该基于别人的镜像文件进行加工,而不是从零开始制作。

为了方便共享,镜像文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库 Docker Hub 是最重要、最常用的镜像仓库。此外,出售自己制作的镜像文件也是可以的。

镜像的管理

Dockerfile

Dockerfile 文件是一个文本文件,用来配置镜像。Docker 会根据该文件的配置来生成二进制的镜像文件。Dockerfile 中的每条命令都会在镜像中创建 一层。如果修改了 Dockerfile,并重新构建镜像,只有 发生了修改的层 才会被重建。正因如此,镜像才会轻量化,小而且快。

首先,在项目的根目录下,新建一个文本文件 .dockerignore,该文件的目的是告诉 docer 打包时要排除指定的文件。

.git
node_modules
npm-debug.log

然后,在 项目的根目录 中,新建一个文本文件 Dockerfile

# 使用官方库中的 Python 镜像
FROM python:2.7-slim

# 将工作目录设定为 /app
WORKDIR /app

# 将当前目录中的内容复制到容器中的 /app 目录
COPY . /app

# 安装 requirements.txt 文件中指定的所有软件包,包括所有的依赖也会打包进镜像
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# 打开容器的 80 端口
EXPOSE 80

# 定义环境变量
ENV NAME World

# 容器启动时,第一个被运行的程序是 app.py
CMD ["python", "app.py"]

RUNCMD 的区别:

RUN 是在构建镜像文件期间执行的,执行结果都会打包进镜像文件,一个 Dockerfile 中可以有多条 RUN

CMD 是在容器启动以后执行的,一个 Dockerfile 中只能有一条 CMD

另外,如果在 Dockerfile 中指定了 CMD,而启动容器时又在 docker container run 后面显式指定了要运行的程序,如 /bin/bash,则该参数会 覆盖 Dockerfile 中的 CMD 定义。

构建镜像

配置完 Dockerfile 就可以用来构建镜像了。

$ docker image build -t whathefuck .
# 或
$ docker image build -t whathefuck:0.0.1 .

其中 -t 用于指定镜像文件的名字和标签,t 代表 tag,格式为 name:tag,冒号后指定标签,通常用做版本号。如果不指定,默认的标签是 latest。

如果运行成功,用 docker image ls 就可以看到新生成的镜像文件 whathefuck 了。

删除镜像
$ docker image rm whathefuck
发布镜像

容器运行成功以后,可以把镜像文件发布到 docker 仓库。首先要在 hub.docker.com 上注册一个账户,然后用以下命令 登陆 docker hub:

$ docker login

为本地镜像文件标注用户名和版本:

$ docker image tag [imageName] [username]/[repository]:[tag]
# 范例
$ docker image tag whathefuck:0.0.1 neo/whathefuck:0.0.1

或者重新构建一次镜像文件:

$ docker image build -t [username]/[repository]:[tag] .

然后,发布镜像文件:

$ docker image push [username]/[repository]:[tag]

如果在别人的机器上临时登陆 docker hub,安全起见,记得要及时退出:

$ docker logout

命令小结

命令 说明
查看镜像列表,隐藏中间步骤镜像 docker image ls
查看所有镜像列表 docker image ls -a
删除镜像文件 docker image rm IMAGE
删除所有镜像文件 docker image rm $(docker IMAGE ls -aq)
构建镜像 docker build -t IMAGE .
从特定文件构建镜像 docker build -f NOTdockerfile -t IMAGE.
登陆 docker hub docker login
注销 docker hub docker logout
为本地镜像打标签 docker tag IMAGE user/repo:tag
上传打过标签的镜像 docker push user/repo:tag

容器

container

镜像文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件: 镜像文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。

使用 Docker API 或命令行,容器可以被创建、运行、终止、删除、移动。可以把某个容器连接到一个或多个网络中,可以为其添加存储(映射驱动),还可以基于该容器当前的状态创建一个新的镜像。

默认情况下,一个容器相对来说与其它容器及宿主机是隔离开的。

容器是由其镜像以及创建、启动时的配置参数定义的,容器被删除以后,其状态发生的任何变化,如果没有保存在持久存储设备上,就会丢失。

# 列出本机正在运行的容器
$ docker container ls

# 列出本机所有容器,包括终止运行的容器
$ docker container ls --all

上面命令的输出结果之中,包括容器的 ID。很多地方都需要提供这个 ID,比如上一节终止容器运行的docker container kill命令。

终止运行的容器文件,依然会占据硬盘空间,可以使用 docker container rm [containerID] 命令删除。运行该命令之后,再使用 docker container ls --all 命令,就会发现被删除的容器文件已经消失了。

容器的管理

生成容器

docker container run 命令会用镜像文件来生成容器。

$ docker container run -p 8000:3000 -it whathefuck /bin/bash
# 或者
$ docker container run -p 8000:3000 -it whathefuck:0.0.1 /bin/bash

指令解释:

-p:端口映射。 把本机的 8000 端口映射为容器的 3000 端口。docker 中运行的进程,其接触到的文件系统和网络接口都是虚拟的,与本机的文件系统和网络接口是隔离的,因此需要定义容器与物理机的端口映射(map)。

-it:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。

whathefuck:0.0.1name:tag ,镜像文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)。

/bin/bash:容器启动以后,内部要第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell。

删除容器

如果容器是在前台运行的,可以使用 ^C 来结束进程,然后 exit 退出容器。

此外,还可以用 docker container kill [containerID] 来终止容器。

容器停止运行以后,不会自动消失,可以用 docker container rm [containerID] 删除容器文件。

另外,在启动容器的时候,如果用 docker container run --rm,当容器终止运行后便会自动删除容器文件。

如:

$ docker container run --rm -p 8000:3000 -it whathefuck /bin/bash

命令小结

命令 说明
仅查看运行状态的容器列表 docker container ls
查看所有容器列表,包括终止运行的 docker container ls -a
可看所有容器列表,只显示数字 ID docker container ls -aq
查看帮助 docker container --help
查看容器的端口映射 docker container port CONTAINER
查看容器的 IP 地址 docker container inspect --format '' CONTAINER
查看容器的日志 docker container logs CONTAINER
启动容器 docker container run username/repo:tag
启动容器,端口映射 docker container run -p 4000:80 IMAGE
启动容器,后台运行 docker container run -d -p 4000:80 IMAGE
重新运行已经终止的容器 docker container start -ai IMAGE
在运行中的容器上执行额外的进程 docker container exec -it mysql bash
优雅终止容器 docker container stop <hash>
强制终止容器 docker container kill <hash>
删除容器文件 docker container rm <hash>
删除所有容器 docker container rm $(docker container ls -aq)

服务

service

通过服务可以扩展容器,令其穿越多个 docker daemon,所有这些 daemon 一起组成了一个容器集群(swarm),其中可以有多个管理者和工人。

容器集群的每个成员都是一个 docker daemon,这些 daemon 之间都使用 Docerk API 进行通信。可以用服务来定义所需的状态,如服务副本的数量,这些数量在任何时候必须始终保持不变。

默认情况下,服务是由所有的工人节点进行负载均衡的。对于访问来说,docker 服务看上去就是一个应用。docker 引擎是在 Docker v1.12 版本开始支持容器集群模式的。