了解 Docker 容器的各种状态对于任何认真的 Docker 用户都至关重要。
我将解释容器生命周期,然后显示生命周期每个阶段的 Docker 命令。
但在学习所有这些东西之前,让我们再次回顾一下容器的概念。
同样,什么是 Docker 容器?
容器的大多数传统定义如下:
容器是操作系统虚拟化的一种形式。虽然传统的基于虚拟机管理程序的虚拟化需要单独的内核用于单独的虚拟机,但容器共享相同的主机内核,因此,它更轻量级,启动速度更快
定义因来源而异,但要点是相同的。
我发现它很无聊,而且不必要地复杂。我想在这里使用一些不同的东西来定义容器。
容器是一堆被欺骗的进程。
为什么这么说呢?因为容器只是进程的集合,有时只是单个进程。这些进程正在被欺骗其主机的不同资源,如网络,进程树,文件系统,主机名等。
你可以运行任何进程,甚至是像bash
这样的shell,并从中隐藏你实际的进程树,给它一组不同的网络,隐藏实际的根文件系统,给它一个不同的主机名,基本上,你最终会做的是创建一个容器化的进程版本。
这是通过命名空间、单独的根文件系统和 cgroup 实现的。
Docker只是围绕运行和管理容器的较低级别工具的包装器,或者更具体地说是容器生命周期。
除此之外,Docker还做了许多其他事情,比如使容器的网络变得容易,处理存储,拉动和推送容器映像等。
Docker在这里让我们的生活更轻松。
现在,让我们看一下 Docker 容器生命周期
容器生命周期基本上是一系列阶段,从容器的创建到销毁。
下图将非常清楚地说明这一点。
容器生命周期
让我解释一下容器生命周期的每个阶段。
- 创建:许多人认为,当您运行容器时,只需一步即可完成。但事实并非如此。有一个过程,它首先创建容器,然后再创建其他任何内容。稍后将对此进行详细介绍。
- 已启动/正在运行:创建容器后,可以启动该容器,之后状态将更改为 。这是容器实际执行某些操作时。
Running
- 暂停:传统上,为了暂停一个进程(容器基本上是这样),我们使用SIGSTOP信号,并取消暂停SIGCONT信号。但是,由于该过程可以观察到此信号,因此使用cgroup冻结器而不是信号。这样,通过冻结 cgroup 来暂停进程。
- 已退出/已停止:与 相反,但与 不同。停止容器意味着将信号发送到主容器进程,即容器命名空间中的 PID 1。然后,它会等待 10 秒钟,让进程正常退出。如果没有,就会发出一个信号,我们都知道这意味着什么,不是吗?
Running
Paused
SIGTERM
SIGKILL
- 销毁/删除:容器不再存在,它曾经分配的所有资源现在都消失了。
我希望这已经使容器生命周期的概念现在更加清晰。在下一节中,我将介绍所有特定的 docker 命令,这些命令将帮助您管理容器的所有这些状态。
用于管理容器生命周期的 Docker 命令
控制容器生命周期的所有命令(如果更具体,则为子命令)都属于子命令 。container
在终端中,如果执行,您将获得与可在容器上执行的多个操作关联的子命令列表。docker container --help
但我们并不关心这里的所有这些问题。让我们只关注其中的一个特定子集。
容器创建
容器创建由以下命令处理:
docker container create
docker create
第一个是长形式,而第二个是,你猜对了,是短形式。
我建议你使用长格式,因为它更冗长,我认为这是一个很好的做法。
什么是容器创建?
容器创建是在指定映像的 R/O 层之上创建 R/W 层,并准备运行所需的程序。创建容器不会启动实际过程,您可以在创建阶段指定所有配置参数,如功能、CPU 限制、内存限制、容器映像等,然后随时启动容器,而无需重新指定这些参数。
阅读可配置选项的列表。docker container create --help
例
首先创建一个如下所示的容器(我在这里使用了一个图像来运行命令alpine
sleep infinity
)
docker container create \
--name alpine alpine:latest sleep infinity
创建容器后,您应该在终端屏幕中获取它的ID。现在,您可以筛选容器列表以查找未运行但刚刚创建的容器。
docker container ls --filter=status=created
在这里,我正在过滤列表,以便仅获取创建的容器。查看该列,这是指定容器状态的内容。您应该看到如下内容:-STATUS
➟ docker container ls --filter=status=created
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3f8d56fb3f78 alpine:3.13.4 "sleep infinity" 17 seconds ago Created alpine
您还可以检查容器并查看它所处的状态。
➟ docker container inspect -f '{{json .State.Status}}' alpine
"created"
使用不会给你带来任何不同。docker create
容器启动
要启动容器,请使用以下两个命令之一:-
docker container start
docker start
这里也是一样,一个长版本和一个短版本。我建议你使用这个命令。...container start
什么是容器启动?
创建容器后,可以启动它。启动容器意味着实际运行容器化应用程序。
虽然创建容器仅准备所有配置(容器的运行方式、运行时环境、运行时约束、容器名称等),但它不会分配任何资源。
启动容器会分配必要的资源并运行应用程序。
例
请考虑我们创建的上一个容器。只需使用容器名称或 ID 启动命令,如下所示:
docker container start alpine
容器启动后,其状态将从 更改为 。在容器列表中,您可以像以前一样再次按状态进行筛选:-Created
Running
docker container ls --filter=status=running
在列上,而不是显示容器自启动以来已运行多长时间。STATUS
Running
➟ docker container ls --filter=status=running
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3f8d56fb3f78 alpine:3.13.4 "sleep infinity" 8 minutes ago Up 18 seconds alpine
您还可以检查容器以查看其状态。我将使用 Go 模板将输出格式化为我唯一需要的内容,即状态。
docker container inspect \
-f '{{json .State.Status}}' alpine
你应该看到这样的东西 -
➟ docker container inspect -f '{{json .State.Status}}' alpine
"running"
听起来不是多余的,但会做同样的事情。docker start
特殊 docker run命令
这是一个特殊的命令,它将容器的创建和启动联系在一起,这是我们所有人最常使用的命令。
docker container run
docker run
这些命令本质上是(i)创建容器,然后立即(ii)启动相同的容器。
这很有用,因为创建并保留容器以在以后开始并不是我们经常做的事情。当您在命令行上使用 Docker CLI 时,您将在这里运行一个容器。这正是命令的作用。...container run
例
此命令的示例非常简单。若要运行容器,请使用 , 而不是 使用 。docker container create
docker container run
您必须将要传递给的所有选项传递给此命令。这是因为 Docker 在那一刻需要所有这些信息,因为没有更多的第二步。docker container create
docker container run
➟ docker container run --name echo-me alpine:3.13.4 echo "Subscribe to Linux Handbook"
Subscribe to Linux Handbook
docker pause
暂停容器意味着它的声音。我们不会停止任何进程,只是暂停它。因此,如果容器内的进程从 1 计数到 100,并且在计数为 50 时暂停,然后在以后取消暂停,则计数将从 50恢复。
需要了解的一件事是,虽然"暂停"
是实际状态,但"未暂停"
不是。取消暂停某个已暂停的容器时,实质上是将状态从"已暂停"
更改为"正在运行"。
用于暂停容器的命令如下:-
docker container pause
docker pause
同样,您可以使用取消暂停的对应项取消暂停容器:-
docker container unpause
docker unpause
容器如何暂停?
使用SIGSTOP信号暂停进程,要取消暂停,则使用 SIGCONT 信号。由于这些信号可以通过过程来观察,而不是信号,因此使用cgroup冷冻器。这样,通过冻结 cgroup 来暂停进程。冻结 cgroup 会冻结其所有任务及其所有子 cgroup。
例:
为了这个演示,我创建了一个特殊的容器。通过执行以下命令拉取映像:-
docker image pull debdutdeb/pause-demo:v1
您可以在此处检查Dockerfile和代码。
拉出后,在一个终端上,使用此映像启动容器
docker container run --name pause-demo debdutdeb/pause-demo:v1
它现在应该显示从 0 开始计数并进行。应如下所示
➟ docker container run --name pause-demo debdutdeb/pause-demo:v1
Count at 30
在另一个终端上,暂停此容器。
docker container pause pause-demo
暂停容器的那一刻,您应该会看到倒计时停止,但终端还没有回到您身边。这是因为容器尚未停止(我将在本文后面讨论这一点)。取消暂停此容器后,倒计时应恢复,而不是重新启动。
docker container unpause pause-demo
要取回终端,请在单独的终端上运行
docker container stop pause-demo
这是一个简短的视频,将在行动中展示这一点:-
在停止容器之前,您可以像以前那样检查暂停容器的状态:
➟ docker container inspect -f '{{json .State.Status}}' pause-demo
"paused"
docker stop
您可以使用以下两个命令之一停止 Docker 容器:-
docker container stop
docker stop
停止容器意味着停止与其关联的所有进程。
这与暂停容器不同。如果停止容器,则可以重新启动它,但进程不会从它们以前所处的状态恢复。进程可以将其状态信息保存在"文件"中,并从该文件还原其状态,但这是另一种情况。
例如,在停止上一个容器后,如果尝试使用命令重新启动它,它将从头开始计数,这与恢复计数的对应项不同。pause-demo
...container start
pause
该过程如何运作?
当您要求 Docker 停止容器时,它会向容器的 PID 1 发送信号。之后,它会等待10秒,这是它的正常时间段,该过程被赋予此时间以正常退出,换句话说,清理并完成它正在工作的任何内容。10秒结束后,Docker会发送最后一个信号,我不必告诉你接下来会发生什么。SIGTERM
SIGKILL
Docker 将信号发送到容器的 PID 1,因为其他每个进程都是 PID 1 的子进程,如果此进程被终止/终止,则 chil 进程将自动不复存在。
通过下面的示例,这一点变得更加清晰。
例:
您需要再次拉取图像。
docker image pull debdutdeb/stop-demo:v1
有关 Dockerfile 和源代码,请查看此要点。
在一个终端中,从此映像启动容器。
docker container run --name stop-demo debdutdeb/stop-demo:v1
执行后,您应该会看到一个屏幕,告诉您其PID并且正在等待。
➟ docker container run --name stop-demo debdutdeb/stop-demo:v1
My PID in this container is 1
Waiting...
打开另一个终端,并对此容器执行 stop 命令。
docker container stop stop-demo
运行后,您应该在运行容器的终端上看到,告诉您IT正在经历什么,即接收信号。SIGTERM
之后,它开始计数秒数,10秒后你会看到它只是停止计数。这并不是因为我以这种方式硬编码了它,实际上我硬编码了它以无限地继续下去。
但是在10秒后,Docker发送了一个我们无法捕获或忽略的信号,该过程必然会被杀死。SIGKILL
您可以使用带有 的选项更改 Docker 在发送信号之前的等待时间。SIGKILL
-t
docker container stop
完成所有操作后,您应该看到类似这样的东西
➟ docker container run --name stop-demo debdutdeb/stop-demo:v1
My PID in this container is 1
Waiting...
SIGTERM ignored,
Starting count..
10 seconds
这是一个小视频,演示了这一点:-
您现在可以像这样检查此容器的状态:-...container inspect
➟ docker container inspect -f '{{json .State.Status}}' stop-demo
"exited"
容器删除
使用以下两个命令之一删除容器:-
docker container rm
docker rm
容器删除与容器创建相反。删除容器时,它已消失,无法将该特定容器带回来。您可以使用相同的配置从同一映像启动一个新映像,使其相同,但它不会与以前的映像完全相同。
例:
例如,只需删除以前的容器即可。stop-demo
docker container rm stop-demo
到目前为止,您创建然后停止的所有容器都可以通过一个命令删除:-
docker container prune
这将删除所有状态为 的容器。Exited
输出示例:
✗ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
ffbdd621c01d0eb3f42d348eeb75c731ddd9bd85674bb90dece32bd70357e541
21b9ed6a6198cd6ee7e162aebd936ae3e93b3b0f738161924a825a27794f2b20
f5f5149866a6ced675ad3bfff0b7386f75ee3fdbddca86be8b8ba341dba4b27f
Total reclaimed space: 0B
因此,您学习了容器生命周期概念。您还学习了 Docker 命令来管理容器生命周期的每个阶段。