容器是Docker的另一个核心概念。简单来说,容器是镜像的一个运行实例。所不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层。如果认为虚拟机是模拟运行的一整套操作系统(包括内核、应用运行态环境和其他系统环境)和跑在上面的应用,那么Docker容器就是独立运行的一个(或一组)应用,以及它们必需的运行环境。
本章将具体介绍围绕容器的重要操作,包括创建一个容器、启动容器、终止一个容器、进入容器内执行操作、删除容器和通过导入导出容器来实现容器迁移等。
4.1 创建容器
从现在开始,忘掉“臃肿”的虚拟机吧。对容器进行操作就跟直接操作应用一样简单、快速。Docker容器实在太轻量级了,用户可以随时创建或删除容器。
1.新建容器
可以使用docker create命令新建一个容器,例如:
使用docker create命令新建的容器处于停止状态,可以使用docker start命令来启动它。
Create命令和后续的run命令支持的选项都十分复杂,主要包括如下几大类:与容器运行模式相关、与容器和环境配置相关、与容器资源限制和安全保护相关,参见表4-1、表4-2、表4-3。
3.新建并启动容器
除了创建容器后通过start命令来启动,也可以直接新建并启动容器。所需要的命令主要为docker run,等价于先执行docker create命令,再执行docker start命令。
例如,下面的命令输出一个“Hello World”,之后容器自动终止:
这跟在本地直接执行/bin/echo'hello world'几乎感觉不出任何区别。
当利用docker run来创建并启动容器时,Docker在后台运行的标准操作包括:
·检查本地是否存在指定的镜像,不存在就从公有仓库下载;
·利用镜像创建一个容器,并启动该容器;
·分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层;
·从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中;
·从网桥的地址池配置一个IP地址给容器;
·执行用户指定的应用程序;
·执行完毕后容器被自动终止。
下面的命令启动一个bash终端,允许用户进行交互:
在容器内用ps命令查看进程,可以看到,只运行了bash应用,并没有运行其他无关的进程。
用户可以按Ctrl+d或输入exit命令来退出容器:
对于所创建的bash容器,当使用exit命令退出之后,容器就自动处于退出(Exited)状态了。
这是因为对Docker容器来说,当运行的应用退出后,容器也就没有继续运行的必要了。
某些时候,执行docker run会出错,因为命令无法正常执行容器会直接退出,此时可以查看退出的错误代码。
默认情况下,常见错误代码包括:
·125:Docker daemon执行出错,例如指定了不支持的Docker命令参数;
·126:所指定命令无法执行,例如权限出错;
·127:容器内命令无法找到。
命令执行后出错,会默认返回错误码。
4.守护态运行
更多的时候,需要让Docker容器在后台以守护态(Daemonized)形式运行。此时,可以通过添加-d参数来实现。
例如下面的命令会在后台运行容器:
容器启动后会返回一个唯一的id,也可以通过docker ps命令来查看容器信息:
4.2 终止容器
可以使用docker stop来终止一个运行中的容器。该命令的格式为docker stop[-t|--time[=10]][CONTAINER...]。
首先向容器发送SIGTERM信号,等待一段超时时间(默认为10秒)后,再发送SIGKILL信号来终止容器:
4.3 进入容器
在使用-d参数时,容器启动后会进入后台,用户无法看到容器中的信息,也无法进行操作。
这个时候如果需要进入容器进行操作,有多种方法,包括使用官方的attach或exec命令,以及第三方的nsenter工具等。
下面分别介绍一下。
1.attach命令
attach是Docker自带的命令,命令格式为:
docker attach [--detach-keys[=[]]] [--no-stdin] [--sig-proxy[=true]] CONTAINER
支持三个主要选项:
·--detach-keys[=[]]:指定退出attach模式的快捷键序列,默认是CTRL-p CTRL-q;
·--no-stdin=true|false:是否关闭标准输入,默认是保持打开;
·--sig-proxy=true|false:是否代理收到的系统信号给应用进程,默认为true。
下面示例如何使用该命令:
$ docker run -itd ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550
执行任意命令。该命令的基本格式为:
docker exec [-d|--detach] [--detach-keys[=[]]] [-i|--interactive] [--privileged]
[-t|--tty] [-u|--user[=USER]] CONTAINER COMMAND [ARG...]。
比较重要的参数有:
·-i,--interactive=true|false:打开标准输入接受用户输入命令,默认为false;
·--privileged=true|false:是否给执行命令以高权限,默认为false;
·-t,--tty=true|false:分配伪终端,默认为false;
·-u,--user="":执行命令的用户名或ID。
例如进入到刚创建的容器中,并启动一个bash:
4.4 删除容器
可以使用docker rm命令来删除处于终止或退出状态的容器,命令格式为docker rm[-f|--force][-l|--link][-v|--volumes]CONTAINER[CONTAINER...]。
主要支持的选项包括:
·-f,--force=false:是否强行终止并删除一个运行中的容器;
·-l,--link=false:删除容器的连接,但保留容器;
·-v,--volumes=false:删除容器挂载的数据卷。
例如,查看处于终止状态的容器,并删除:
4.5 导入和导出容器
某些时候,需要将容器从一个系统迁移到另外一个系统,此时可以使用Docker的导入和导出功能。这也是Docker自身提供的一个重要特性。
1.导出容器
导出容器是指导出一个已经创建的容器到一个文件,不管此时这个容器是否处于运行状态,可以使用docker export命令,该 命令的格式为docker export[-o|--output[=""]]CONTAINER。其中,可以通过-o选项来指定导出的tar文件名,也可以直接通过重定向来实现。
首先查看所有的容器,如下所示:
2.导入容器
导出的文件又可以使用docker import命令导入变成镜像,该命令格式为:
docker import [-c|--change[=[]]] [-m|--message[=MESSAGE]] file|URL|-[REPOSITORY[:TAG]]
用户可以通过-c,--change=[]选项在导入的同时执行对容器进行修改的Dockerfile指令(可参考第8章内容)。
下面将导出的test_for_run.tar文件导入到系统中:
之前镜像章节中笔者曾介绍过使用docker load命令来导入一个镜像文件,与docker import命令十分类似。
实际上,既可以使用docker load命令来导入镜像存储文件到本地镜像库,也可以使用docker import命令来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也更大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。
4.6 本章小结
容器是直接提供应用服务的组件,也是Docker实现快速启停和高效服务性能的基础。
通过本章内容的介绍和示例,相信读者很快能掌握对容器整个生命周期进行管理的各项操作命令。
在生产环境中,因为容器自身的轻量级特性,笔者推荐使用容器时在一组容器前引入HA(High Availability,高可靠性)机制。例如使用HAProxy工具来代理容器访问,这样在容器出现故障时,可以快速切换到功能正常的容器。此外,建议通过指定合适的容器重启策略,来自动重启退出的容器。
来源:Docker技术入门与实战 (第2版) 作者:杨保华 戴王剑 曹亚仑