在第一章中,我们已经简单的了解了
Docker是什么,以及如何安装Docker并且成功的运行了Docker Hello Word镜像。这篇我们详细介绍容器运行那些事情。(第一篇跳转)
Docker容器的生命周期
在了解Docker容器如何启动之前,我们先了解下Docker容器的生命周期,以便帮助我们更好的管理容器。
0x01 创建阶段
创建阶段是容器运行的第一个阶段,可以使用命令docker create命令创建一个容器,在创建的时候,Docker会在底层镜像上新建一个可写层作为容器层,这个过程就叫做容器的创建。在这个阶段,Docker会做以下几件事情。
- 拉取镜像:
Docker会判断要创建的容器的镜像在本地是否存在。如果存在,则会省略该步骤,如果不存在,则会从远程镜像仓库中拉取相关的镜像。 - 复制容器镜像:
Docker会从指定的镜像复制出一个只读层,也被称为镜像层。 - 创建容器层:
Docker会在镜像层的基础之上创建一个可写层,也被称为容器层。在这层中,Docker会创建容器所存储的文件系统,配置信息等。 - 创建配置:
Docker会根据启动参数,为容器分配网络,存储和其他配置。 - 返回容器
ID,该ID用于启动容器。
0x02 启动阶段
启动阶段是Docker容器的一个重要阶段,通过命令docker start启动容器,这个阶段会将上一步创建的容器启动起来。在启动阶段,Docker会做如下的事情:
Docker的守护线程会在容器内部创建一个容器的守护线程,(创建的方式是通过Linux系统的命名空间和控制组技术实现的,后续文章会介绍)。Docker的守护线程还会根据之间的状态来恢复容器,包括网络配置,环境变量,挂载点等。- 容器的守护线程会执行启动阶段要在容器内部运行的命令,来将容器内部的应用程序启动。
Docker守护线程会将容器状态修改为已经启动。
在容器启动的过程中,Docker的守护线程和容器的守护线程之间是相辅相成,互相合作的。Docker的守护线程会在宿主机层面为容器要运行提供相应的帮助,如网络环境的创建,存储卷的操作,而容器的守护线程只是负责在容器内部执行网络和容器卷的操作,它不能直接创建或者删除网络和存储卷,也可以认为网络和挂载等操作是由Docker守护进程控制的,容器守护进程执行的。
0x03 停止阶段
可以使用docker stop命令来停止。在停止过程中,会做如下的事情:
Docker守护线程接收到docker stop命令之后,如果是普通的关闭,会向容器的守护线程发送SIGTERM信号,如果是强制停止,会向容器的守护线程发送SIGKILL信号。- 容器的守护线程接受到
Docker的守护线程发送来的SIGTERM信号之后,会向容器内运行的应用程序发送SIGTERM信号,当10s之后,应用程序还没有停止,Docker的守护线程会重新发送SIGKILL信号来强制停止。 - 如果容器的守护线程接受到的是
SIGKILL信号,他就会直接给应用程序发送SIGKILL来强制停止应用程序。 - 容器的守护线程还会接触容器的网络配置,将容器从网络中移除。
- 容器的守护线程还会卸载容器的挂载点,释放对应资源。
Docker的守护线程最后会将容器的状态设置为已停止,更新Docker守护线程的的状态信息。- 最后
Docker会生成容器快照,以便在后续可以恢复容器状态。
0x04 删除阶段
相较于上面三个阶段,容器的删除操作内容就少的多了,如果容器在运行状态被删除,就会先执行停止阶段的全部操作。并且在最后删除容器,以及容器的文件系统。
Docker容器的维护命令
下面将根据上述Docker的不同生命周期为基础,介绍Docker相关的维护命令。
0x01 创建容器
创建容器使用的是Docker Create命令,语法如下:
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
常用的选项如下:
-i,--interactive:启用容器的交互式模式。
该参数表示在容器创建的时候,将标准输入流(stdin)保持打开状态,以便命令可以通过终端(或者管道)向容器内部传递数据。该参数通常配合-t参数使用。
需要注意的是,如果容器没有运行任何交互式进程,则-i参数会没有什么作用。
-t,--tty为容器分配一个虚拟终端。
-t参数表示在创建容器的时候,分配一个伪终端(pseudo-TTY)并绑定到标准输入流(stdin)上,以便在容器中进行交互式操作。
-v,--volume将本地文件系统的路径挂在到容器中。
-v参数可以将主机上的一个目录(或者文件)挂在到容器内部,使得容器可以访问该目录(或者文件)。该参数可以指定一个本地主机路径和容器内的路径,并且使用冒号(:)分割开来。例如:
docker run -v /root/path:/container/path image_name
需要注意的是,如果挂载的主机路径不存在,则Docker会自动创建。如果容器内部,挂在的路径不存在,Docker也会自动创建。并且如果在容器内部修改了文件,这些修改也会反映到主机上,反之亦然。
同时,使用-v参数还可以挂在一个Docker数据卷到容器内部的路径上,以便多个容器可以共享一个数据卷。例如:
docker run -v mydata:/container/path image_name
有关于“容器卷”的相关内容,会在后续的文章中详细介绍。
如果想要在容器中挂在多个路径或者容器卷,可以使用多个-v参数。
--name为容器指定名称
在默认请款下,Docker会为每个容器起一个随机的名字,但是这样很不好管理。为此,我们可以使用--name参数指定一个名字,便于在命令中引入该容器。
docker run --name my-container image_name
需要注意的是,Docker中的容器名称必须是唯一的,如果试图为容器指定一个正在使用中的名字,会被Docker拒绝并报错。
-e为容器指定环境变量
该参数用于设置容器内的环境变量。环境变量可以在容器内部的应用程序中使用。如果想要设置多个环境变量,可以使用多个-e参数,如果在参数中存在空格或者其他特殊字符,需要使用引号把变量引起来。
docker run -e "DB_HOST=my host" image_name
这时,我们在容器内部就可以查看到环境变量的值了。
--network指定容器的网络模式
该参数用于指定容器的网络模式,也可以将容器连接到自定义的网络中,关于网络的详细配置我们会在后面的文章详细说明。
0x02 启动容器
启动容器使用的是docker start命令,该命令既可以启动使用docker create命令刚刚创建好的容器,也可以启动被暂停的容器。
具体命令如下:
docker start [OPTIONAL] CONTAINER [CONTAINER ...]
在Docker启动时常用的参数
-a,--attach:将容器的标准输出和标准错误输出链接到当前终端
-a参数可以将容器的标准输出和标准错误输出链接到当前终端。使用-a参数可以在容器启动之后立即查看容器的输出信息,方便调试和排查问题。
需要注意的是,使用-a参数,只会将容器链接到当前终端,并不会在后台运行。容器会随着当前终端的关闭而停止。
-i,--interactive:允许容器进行交互式操作
该参数和创建容器时候使用的-i参数意义是一样的,这里不在赘述。
-p,--publish:将容器内的端口映射到宿主机的端口
该参数用于指定容器的端口映射。通过端口映射,可以将容器的内部的服务绑定到宿主机的端口上,从而实现对容器内服务的访问。
docker start -p 80:8080 my_container
上述命令中,-p 80:8080参数将容器的8080端口映射进宿主机的80端口上。这样,就可以通过访问宿主机80端口的方式访问容器内部的服务。
需要注意的是,如果容器的端口在创建容器的时候已经被指定了,那么docker start命令中不需要再指定。如果在docker create中指定的参数和docker start中指定的参数不一致,那么就会以docker start中的参数为准。
-d,--detach:启动容器,并且放在后台运行
该参数会在后台启动一个容器。具体来说-d参数表示"后台运行 (detached mode)",启动容器之后会立即返回命令提示符,不会讲容器的标准输出和标准错误输出链接到当前终端(除非使用了-it)。
-e,--env:设置容器的环境变量
该参数和docker create中的参数意义相同。
-m,--memory:设置容器的内存
该参数用于设置容器的内存限制,即限制容器可以使用的内存最大量。语法如下:
docker start -m <momory-limit> <container>
其中<memory-limit>表示内存限制,可以使用如下的格式:
<number>:表示限制使用<number>字节的内存限制,例如1000000表示限制为1MB。<number> <unit>:表示限制使用指定单位的内存,其中<unit>可以是以下的单位之一:b(字节),k(千字节),m(兆字节),g(千兆字节),t(太字节)。
例如,如果要为名为my_container的容器设置内存限制为1G。可以使用如下命令:
docker start -m 1g my_container
0x03 创建并启动
Docker中的docker start命令可以同时实现创建并启动容器。这个命令相当于执行了docker create和docker start两个命令。通过docker run命令可以快速的创建并启动一个容器,同时也可以在启动容器时候指定各种参数和选项。而docker run中的很多参数和docker create,docker start的参数相同。
docker run [OPTIONS] IMAGE [COMMAND] [ARG ...]
其中OPTIONS为可选项,IMAGE为要运行的镜像名称或者ID,COMMAND为容器启动之后要执行的命令 ARG...为命令执行的参数。
常用的选项如下:
-d:容器在后台运行
详见docker start部分。
-it:以交互终端的方式运行容器
这是一个组合参数,组合了-t参数和-i参数,这两个参数的组合可以实现以当前终端交互的方式和docker容器进行通信。
--name:给容器命名。
详见docker create部分。
-p:将容器内部的端口映射到主机的端口上
详见docker start部分。
-v:将主机目录或者文件挂载到容器中
详见docker create部分。
-e:设置环境变量
详见docker create部分。
--restart:在容器退出的时候自动重启重启
该参数用于指定容器在意外停止时是否重启的动作。该参数支持如下的选项:
no:默认,容器退出之后不自动重启。on-failure[:max-retries]:容器非正常退出(推出状态码不为0)时重启重启,如果重启次数超过max-retries则不再重启。always:无论容器以什么方式退出,总是自动重启容器。unless-stopped:容器非正常退出时重启容器,除非手动停止容器。
如下,创建一个名为my-container的容器,并且在退出的时候自动重启容器:
docker run --name my-container --restart=always my-image
--network:指定容器所在的网络
详见docker create部分。
-u:指定容器中的用户
该参数用于设置容器内执行进程的用户或者用户组,其具体格式为<user>[:<group>],用户和用户组之间使用冒号分隔。
例如,-u 1000表示容器内的进程将以用户ID为1000的身份运行,而用户组将默认与该用户ID相关联的默认用户组。如果需要指定用户组,可以使用user:group的格式,例如-u 1000:1000表示容器内的进程以用户ID为1000,用户组为1000的身份运行。
需要注意的是,如果指定的用户或者用户组不存在,这容器将无法启动。另外,在某些情况下,如果容器的程序需要使用root权限,需要在启动的时候使用-u 0参数,以避免权限问题。
使用-u参数可以在一定程度上保证容器的安全性,因为如果容器内部的程序以root用户身份运行,这在容器攻破的时候可能会导致系统安全性问题。
--entrypoint:默认覆盖容器的enterpoint
该参数用于指定容器启动之后默认执行的命令,覆盖镜像中设置的ENTRYPOINT。他可以在不更改Docker镜像的情况下修改容器的启动命令。
使用--entrypoint,可以指定一个代替的可执行文件或命令作为容器的默认入口点,以便在运行容器时启动不同的应用程序或者脚本。
例如,假如有一个使用Python作为入口点的Docker镜像,并且想要在容器中执行一些base命令而不是Python命令。可以使用该参数覆盖默认入口点:
docker run --entrypoint /bin/bash python-image
这样在容器启动时执行/bin/base,而不是默认的Python命令。
-rm:容器退出后自动删除容器
该命令是在容器运行结束之后自动删除容器,这样可以减少不必要的容器垃圾占用空间,方便管理。
需要注意的是,--rm参数只对正常退出的容器有效。如果容器是由于未处理的异常(例如docker stop命令强制停止容器)而退出的,则不会自动删除容器,需要手动删除。
0x04 容器停止
容器停止使用的是docker stop命令,基本语法如下:
docker stop [OPTIONS] CONTAINER [CONTAINER...]
其中OPTIONS为可选参数,CONTAINER为要停止的容器名称或者ID。
该命令常用的参数如下:
-t,--time:指定容器停止前的等待时间
该参数用于设置等待容器停止的时间,单位为秒。当容器收到停止信号后,Docker会等待一段时间让容器自行停止运行,如果在等待的时间内容器仍未停止,则Docker会强制停止容器。
-t参数的完整格式为--time,可以直接指定等待时间,例如:
docker stop -t 30 container_name
上面的命令会等待容器停止30秒,如果超时仍未停止,这强制停止容器。如果不指定-t参数,这默认等待10秒。
需要注意的是,-t参数只在Docker 1.13及以上版本可用。在早期的版本中,Docker使用的是-t/--timeout参数来设置容器停止的等待时间。
-f,--force:强制停止
使用-f参数可以强制停止运行中的容器,相当于发送了SIGKILL信号。如果没有使用该参数,Docker会向容器发送SIGTERM信号,给容器一定的时间优雅的停止。如果超过了指定的时间,在发送SIGKILL强制终止容器。
需要注意的是,使用docker stop -f可能会导致正在运行中的任务或者进程被强制终止,并可能导致数据丢失或者损坏。因此,并不推荐使用该参数。
0x05 重启容器
容器重启指的是重新启动正在运行中的容器,命令的基本语法如下:
docker restart [OPTIONS] CONTAINER [CONTAINER ...]
其中OPTIONS表示可选参数,CONTAINER表示目前要重启的容器的名称或者ID
该命令的常用参数和停止容器的参数相同,都是-t和-f参数,一个表示延迟等待的时间,另一个表示强制立即重启,这里不再赘述。
0x06 暂停容器
暂停容器使用的是docker pause 命令,该命令会暂停一个运行中的容器,容器内的所有进程将会被暂停,直到使用docker unpause命令恢复,该容器的命令格式如下:
docker pause CONTAINER
当执行Docker pause命令之后,Docker会发送SIGSTOP信号到容器的守护进程,从而暂停该容器的所有进程。在这个过程中,容器的状态仍然是running,但是所有的进程都处于暂停状态,无法被分配到CPU时间,也无法响应外部的请求。当使用docker unpause命令时,Docker发送SIGCONT信号到容器的守护进程,从而恢复容器中的所有进程,使其继续运行。
0x07 容器解除暂停
解除容器暂停的命令是docker unpause,具体格式如下:
docker unpause CONTAINER
在使用docker unpause命令时候,容器的状态必须是暂停状态,如果是非暂停状态,使用该命令不会有任何效果。
0x08 容器配置更新
更新容器的配置可以使用docker update命令,该命令可以修改包括CPU,内存,挂载点,网络设置,容器标签等。更新的后的配置将立即应用到正在运行的容器中,而无需重启容器。
该命令的格式如下:
docker update [OPTIONS ] CONTAINER
其中,OPTIONS是指更新容器的参数,CONTAINER指的是需要更新的容器名称或者容器ID。
常用的参数:
--cpus:设置容器的CPU资源上限
例如:
docker update --cpus 1.5 myContainer
上面的命令代表将容器myContainer的CPU限制设置为1.5个,这个是可以是一个浮点数,代表CPU核心的比例,比如设置0.5代表只能使用0.5个核心。
需要注意的是,如果在创建容器时使用了--cpus参数,那么使用update命令更新容器时,会覆盖容器创建时的参数。如果容器在创建的时候没有设置,那么使用--cpus命令的设置将生效。
在更新的时候,如果超过了宿主机的CPU核心数量,那么容器可用的CPU数量将设置为系统的CPU数量限制。
并且该参数只会限制容器内应用进程的CPU的使用限制,对于容器自身的那部分CPU并不会限制,虽然这部分的大小可以忽略不计。
--memory:修改容器的内存限制
和--cpus类似,设置容器的内存资源上限。命令格式如下:
docker update --memory <limit> CONTAINER
其中,limit可以是如下格式之一:
- 指定内存大小:例如
2G,512MB,表示限制容器使用的内存为2G或者512MB。 - 使用
0表示取消限制。
需要注意的是,--memory限制的是容器使用的内存大小,而不是宿主机上的大小。如果设置的内存大小小于实际使用的内存大小,容器会被强制停止。另外--cpus参数一样,--memory也只对容器内部运行的进程和子进程生效,不会限制容器自身(容器进程本身)的内存使用。
0x09 查看容器列表
查看容器列表可以使用docer ps命令,包括容器的ID,名称,说使用的镜像,状态,创建时间等。该命令有一些常用的参数如下:
-a:显示所有的容器,包括已经停止的容器。
-q:只显示容器的ID
-f:展示容器的过滤条件
该命令展示的数据如下:
CONTAINER_ID:容器IDIMAGE:容器使用的镜像COMMAND:容器的入口点(执行的命令)CREATED:创建时间STATUS:状态PORTS:容器的端口映射NAME:容器的名称
0x0a 获取容器的详细信息
可以使用docker inspect命令来获取容器的详细信息,以JSON格式输出。该命令还可以用于获取其他Docker对象的详细信息(例如镜像,网络等)。该命令内容的详细解析将会在后续文章中具体讲解。
0x0b 在容器内部执行新线程
可以使用docker exec命令在容器内部执行命令。该命令语法格式如下:
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
其中OPTIONS代表执行的选项,CONTAINER表示要执行命令的容器名称或者ID,COMMAND和ARGS指定要在容器内执行的命令和参数。常用的OPTIONS如下:
-d,--detach=false:后台运行
指定命令在后台执行,不阻塞当前终端
-i,--interactive=false:标准输入打开
参见docker start的-i参数
-t,--tty=false:分配一个虚拟终端
参见docker start的-t参数。
0x0c 删除容器
如果想要删除容器,可以使用docker rm命令,该命令格式如下:
docker rm [OPTIONS] CONTAINER [CONTAINER ...]
其中OPTIONS是一些可选参数,CONTAINER是要删除的容器名称或者容器ID。
参见的参数有:
-f: 强制删除。
强制删除可以在容器运行状态就删除。如果没有使用该参数,这必须停止容器才能删除,如果使用该参数,则不必使用该参数。
-v:删除容器的卷
在删除容器的时候,默认不会删除容器卷,如果使用了-v参数,可以删除该容器使用的卷。