【Docker—基础】容器

容器是基于镜像创建的可运行实例,并且单独存在,一个镜像可以创建出多个容器。运行容器化环境时,实际上是在容器内部创建该文件系统的读写副本。这将添加一个容器层,该层允许修改镜像的整个副本。如图所示。

容器 VS 虚拟机

在虚拟机模型中,首先要开启物理机并启动 Hypervisor 引导程序(跳过了 BIOS 和 Bootloader 代码等)。一旦 Hypervisor 启动,就会占有机器上的全部物理资源,如 CPU、RAM、存储和 NIC。Hypervisor 接下来就会将这些物理资源划分为虚拟资源,并且看起来与真实物理资源完全一致。然后 Hypervisor 会将这些资源打包进一个叫作虚拟机(VM)的软件结构当中。这样用户就可以使用这些虚拟机,并在其中安装操作系统和应用。

而容器模型则略有不同。服务器启动之后,所选择的操作系统会启动。与虚拟机模型相同,OS 也占用了全部硬件资源。在 OS 层之上,需要安装容器引擎(如 Docker)。容器引擎可以获取系统资源,比如进程树、文件系统以及网络栈,接着将资源分割为安全的互相隔离的资源结构,称之为容器。每个容器看起来就像一个真实的操作系统,在其内部可以运行应用。

从更高层面上来讲,Hypervisor是硬件虚拟化(Hardware Virtualization)——Hypervisor将硬件物理资源划分为虚拟资源;另外,容器是操作系统虚拟化(OS Virtualization)——容器将系统资源划分为虚拟资源。

容器的生命周期

容器操作

启动容器

命令的基础格式为 docker [container] run : 。如:

$ docker run -it --name=busybox busybox

当使用docker run 创建并启动容器时,Docker 后台执行的流程为:

  • Docker 会检查本地是否存在 busybox 镜像,如果镜像不存在则从 Docker Hub 拉取 busybox 镜像;
  • 使用 busybox 镜像创建并启动一个容器;
  • 分配文件系统,并且在镜像只读层外创建一个读写层;
  • 从 Docker IP 池中分配一个 IP 给容器;
  • 执行用户的启动命令运行镜像。

上述命令中, -t 参数的作用是分配一个伪终端,-i 参数则可以终端的 STDIN 打开,同时使用 -it 参数可以让我们进入交互模式。

若尝试在容器内执行一些基础命令,可能会发现某些指令无法正常工作。这是因为大部分容器镜像都是经过高度优化的。这意味着某些命令或者包可能没有安装。

需要注意的是,对于容器来说, 杀死容器中的主进程,则容器也会被杀死。

进入容器

处于运行状态的容器可以通过 docker attach、docker exec、nsenter 等多种方式进入容器。

  • docker attach: 将本机标准输入(键盘输入)输到容器中,也可以将容器的输出显示在本机的屏幕上,如果你想查看容器运行过程中产生的标准输入输出,用 docker attach。
  • docker exec: 如果你要进入已运行的容器,并且执行命令,用 docker exec。此时会单独启动一个进程,每个窗口都是独立且互不干扰的,也是使用最多的一种方式。

停止和删除容器

容器启动后,如果我们想停止运行中的容器,可以使用 docker stop 命令。命令格式为 docker [container] stop [-t|–time[=10]]。该命令首先会向运行中的容器发送 SIGTERM 信号,如果容器内 1 号进程接受并能够处理 SIGTERM,则等待 1 号进程处理完毕后退出,如果等待一段时间后,容器仍然没有退出,则会发送 SIGKILL 强制终止容器。

如果你想查看停止状态的容器信息,你可以使用 docker ps -a 命令。处于终止状态的容器也可以通过 docker start 命令来重新启动。此外,docker restart 命令会将一个运行中的容器终止,并且重新启动它。

删除容器命令的使用方式如下:docker [container] rm [OPTIONS] CONTAINER [CONTAINER…]。

如果要删除正在运行中的容器,必须添加 -f (或 –force) 参数, Docker 会发送 SIGKILL 信号强制终止正在运行的容器。

利用重启策略进行容器的自我修复

通常建议在运行容器时配置好重启策略。这是容器的一种自我修复能力,可以在指定事件或者错误后重启来完成自我修复。重启策略应用于每个容器,可以作为 –restart 参数被强制传入 docker run命令中,或者在 Compose 文件中声明(在使用 Docker Compose以及Docker Stacks 的情况下)。 目前容器支持的重启策略包括 always、unless-stopped 和 on-failed。

always 策略是一种简单的方式。除非容器被明确停止,比如通过 docker stop 命令,否则该策略会一直尝试重启处于停止状态的容器。该策略有一个很有意思的特性,当 daemon 重启的时候,停止的容器也会被重启。

unless-stopped 和 always 的最大区别,就是那些指定了 –restart unless-stopped 并处于 Stopped(Exited) 状态的容器,不会在 Docker daemon 重启的时候被重启。

on-failure 策略会在退出容器并且返回值不是 0 的时候,重启容器。当容器处于 Stopped 状态,在 Docker daemon 重启的时候,容器也会被重启。

导入导出容器

我们可以使用 docker export CONTAINER 命令导出一个容器到文件,不管此时该容器是否处于运行中的状态。

通过 docker export 命令导出的文件,可以使用 docker import 命令导入,执行完 docker import 后会变为本地镜像,最后再使用 docker run 命令启动该镜像,这样我们就实现了容器的迁移。

导入容器的命令格式为 docker import [OPTIONS] file|URL [REPOSITORY[:TAG]]。