「Docker系列教程第二篇」:容器我啊,跑起来了

872 阅读19分钟

在第一章中,我们已经简单的了解了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 createdocker start两个命令。通过docker run命令可以快速的创建并启动一个容器,同时也可以在启动容器时候指定各种参数和选项。而docker run中的很多参数和docker createdocker 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

上面的命令代表将容器myContainerCPU限制设置为1.5个,这个是可以是一个浮点数,代表CPU核心的比例,比如设置0.5代表只能使用0.5个核心。

需要注意的是,如果在创建容器时使用了--cpus参数,那么使用update命令更新容器时,会覆盖容器创建时的参数。如果容器在创建的时候没有设置,那么使用--cpus命令的设置将生效。

在更新的时候,如果超过了宿主机的CPU核心数量,那么容器可用的CPU数量将设置为系统的CPU数量限制。

并且该参数只会限制容器内应用进程的CPU的使用限制,对于容器自身的那部分CPU并不会限制,虽然这部分的大小可以忽略不计。

--memory:修改容器的内存限制

--cpus类似,设置容器的内存资源上限。命令格式如下:

docker update --memory <limit> CONTAINER

其中,limit可以是如下格式之一:

  • 指定内存大小:例如2G512MB,表示限制容器使用的内存为2G或者512MB
  • 使用0表示取消限制。

需要注意的是,--memory限制的是容器使用的内存大小,而不是宿主机上的大小。如果设置的内存大小小于实际使用的内存大小,容器会被强制停止。另外--cpus参数一样,--memory也只对容器内部运行的进程和子进程生效,不会限制容器自身(容器进程本身)的内存使用。

0x09 查看容器列表

查看容器列表可以使用docer ps命令,包括容器的ID,名称,说使用的镜像,状态,创建时间等。该命令有一些常用的参数如下:

-a:显示所有的容器,包括已经停止的容器。

-q:只显示容器的ID

-f:展示容器的过滤条件

该命令展示的数据如下:

docker ps.png

  • CONTAINER_ID:容器ID
  • IMAGE:容器使用的镜像
  • COMMAND:容器的入口点(执行的命令)
  • CREATED:创建时间
  • STATUS:状态
  • PORTS:容器的端口映射
  • NAME:容器的名称

0x0a 获取容器的详细信息

可以使用docker inspect命令来获取容器的详细信息,以JSON格式输出。该命令还可以用于获取其他Docker对象的详细信息(例如镜像,网络等)。该命令内容的详细解析将会在后续文章中具体讲解。

0x0b 在容器内部执行新线程

可以使用docker exec命令在容器内部执行命令。该命令语法格式如下:

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

其中OPTIONS代表执行的选项,CONTAINER表示要执行命令的容器名称或者IDCOMMANDARGS指定要在容器内执行的命令和参数。常用的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参数,可以删除该容器使用的卷。