作者 | 飞向星的客机


🌟 前言

镜像是构建容器的蓝图,Docker 以镜像为模板,构建出容器。

容器在镜像的基础上被构建,也在镜像的基础上运行,容器依赖于镜像。

本文将对 容器的运行 及相关内容进行详细讲解。

容器运行

在 Docker 官方网站可以查询与 Docker 相关的资料以及帮助手册,但是内容都是英文的,可能会对一些小白造成困扰。(而且,访问 Docker 官方网站特别缓慢 )。

使用 docker run 命令可以运行容器,该命令底层其实是 docker create 与 docker start 两条命令的结合体,运行容器需要先基于镜像创建一个容器,然后启动容器,完成一个容器的运行,如图所示👇

例如,基于镜像启动一个新容器,并打印当月的日历,示例代码如下:

从以上示例中可以看到日历已经被打印出来,但无法看到容器是否运行。

ps 命令在 Linux 系统中被用来查看进程,在 Docker 中被用来查看容器,因为运行中的容器也是一个进程,示例代码如下:

从以上示例中可以看到,一个 Docker 容器以 CentOS 镜像为基础运行,并传了一个 cal(打印当前月份日历)命令,容器正常启动并执行了 cal 命令。

除此之外,还可以通过指定参数,启动一个bash交互终端,代码如下:

上述代码创建了一个交互式的容器,并分配了一个伪终端,使用户可以通过命令行与容器进行交互。终端对宿主机进行直接操作,宿主机通过一个虚拟终端将对 Docker 的指令传输给容器,这个虚拟终端就是伪终端,对容器进行直接操作。

执行 docker run 命令启动容器时,Docker 会进行如下操作。

(1)检测本地是否存在指定的镜像,不存在则从默认的 Docker Hub 公有仓库下载。

(2)使用镜像创建(docker create)并启动(docker run)容器。

(3)分配一个文件系统,并在只读层外面挂载一个可读可写层。

(4)从宿主机配置的网桥接口中桥接一个虚拟接口到容器中去。

(5)从地址池分配一个 IP 地址给容器。

(6)执行用户指定的命令。

(7)执行之后容器被终止(docker stop)。

另外,在 docker run 命令中可以添加相应参数,实现不同的功能。

下面运行一个容器,并使用终端对其进行操作,示例代码如下:

以上命令执行成功的前提是本地含有 CentOS 镜像。其中,-i 表示捕获标准输入输出,-t 表示分配一个终端或控制台。

下面运行一个容器,并为其设置环境变量,示例代码如下:

其中,-e 参数是在创建容器时为容器配置环境变量。

此时已经成功创建了一个容器,接着查看它的环境变量,示例代码如下:

从以上示例中可以看到,key=1000 的环境变量已经设置成功。

🍇 自动重启的容器

下面运行一个正常的容器,示例代码如下:

在新创建的容器中,使用 exit 命令即可退出容器,但容器也将停止运行。

查看容器状态,示例代码如下:

可以看到,容器此时的状态为 “Exited”,说明容器处于终止状态。

下面运行一个添加参数的容器,示例代码如下:

不出意外的话,此时容器应该是终止状态。

接着,验证容器的状态,示例代码如下:

从示例中可以看到,容器此时不是终止状态,而是运行状态。这是由于添加了 –restart 参数的容器被终止后自动重启。

🍇 自定义名称的容器

下面运行一个自定义名称的容器,示例代码如下:

从示例中可以看到,创建容器时添加了 -name 参数来定义容器名称。创建之后容器的名字就是指定的 “test”。

🍇 开启端口的容器

下面创建一个开启 80 端口的容器,示例代码如下:

参数冒号之前是宿主机端口号,冒号之后是容器的端口号,表示宿主机的 80 端口映射到容器的 80 端口上。

从示例中可以看到,容器正在运行,并且可以看到开启了 80 端口。

为了验证,使用 curl 工具访问容器端口,示例代码如下:

访问容器 80 端口的返回值为 200,说明容器端口能够被用户正常访问。

接下来,将容器停止,并再次访问容器端口,示例代码如下:

再次访问容器端口时,连接被拒绝,说明先前的服务由是 Docker 容器来提供的,只是通过宿主机的端口向外网开放。

🍇 与宿主机共享目录的容器

首先在宿主机上创建需要共享的目录与文件,示例代码如下:

已经在 /root/test/ 目录下别创建了 a.txt 与 b.txt 两个文件,接着创建一个可以共享这两个文件的容器,示例代码如下:

-v 参数用来指定文件路径,–privileged 参数用来给用户添加操作权限。

从示例中可以看到,目录与文件共享成功。

进入容器

容器在宿主机中共有三种状态,分别为运行(Up)状态、暂停(Paused)状态与终止(Exited)状态。

下面通过示例来观察容器的三种状态。

2.1 容器的三种状态

🍑 运行状态

运行一个名为 test-nginx 的 Nginx 容器,并将容器 80 端口映射到宿主机 80 端口,示例代码如下:

这时,容器已经创建完成,通过 ps 命令查看容器是否为运行状态,示例代码如下:

从以上示例中可以看出,此时容器状态为运行状态。

🍑 暂停状态

下面通过命令使容器进入暂停状态,示例代码如下:

docker pause 是暂停容器的命令,上述示例中,暂停了名为 test-nginx 的容器。

接着通过命令查看容器是否成功暂停,示例代码如下:

从以上示例中可以看到,容器仍是运行状态,但同时也是暂停状态。

接着通过 curl 工具对该容器进行访问测试,示例代码如下:

通过访问测试发现,此时无法访问到容器网页,但是服务器没有拒绝连接,说明暂停容器的本质是暂停容器中的服务。

下面使用 docker unpause 命令使暂停状态的容器终止暂停状态,示例代码如下:

此时,命令执行完毕,接着查看容器状态,示例代码如下:

从以上代码中可以看到,暂停状态已经被终止,容器只处于运行状态。

接着用 curl 工具对容器进行访问测试,示例代码如下:

从以上示例中可以看到,此时网站已经可以正常访问,说明容器中的服务正常运行。

🍑 终止状态

当不再需要某一个业务继续运行时,就要通过命令使该业务的容器终止,示例代码如下:

以上示例使用 docker stop 命令终止了容器 test-nginx,接着验证容器状态,示例代码如下:

从以上示例中可以看出,此时容器为终止状态,接着对容器进行访问测试,示例代码如下:

从测试结果中可以看出,客户端请求被拒绝,服务已关闭。与暂停状态的容器不同是,终止状态的容器会给客户端发送拒绝的回应。

下面使用 docker start 命令将终止状态的容器唤醒,示例代码如下:

示例中使用 docker start 命令对处于终止状态的容器进行了唤醒,接着查看容器此刻状态,示例代码如下:

从以上示例中可以看出,此时容器状态为运行状态。接着对该容器进行访问测试,示例代码如下:

通过访问测试结果可以看出,此时容器中的服务已经可以正常访问。

2.2 docker attach 与 docker exec

在企业中,运维工程师与开发工程师都可能会有进入容器内部的需求。

但是不建议使用SSH(Secure Shell)登录容器,因为这违背了一个容器里只有一个进程的原则,同时增加了被攻击的风险。

建议使用以下两种 Docker 原生方式进入容器。

🍑 docker attach

通过 docker attach 命令可以进入到一个已经在运行容器的虚拟输入设备,然后执行其他命令。

下面演示 docker attach 命令的使用方式。

创建任意一个容器,这里以 CentOS 为例,示例代码如下:

此时 CentOS 容器已经创建成功,接着使用 docker attach 命令与容器 ID 号进入容器中,示例代码如下:

在以上示例中,不仅进入了容器,还对容器执行了 ls 命令,说明此时已经可以在命令行直接对容器进行操作。

在退出容器时需要注意的是,直接从容器中使用 exit 命令或者 Ctrl+d 组合键退出容器,会导致容器终止。如果想要退出当前容器,并且不终止容器,可以使用 Ctrl+P+Q 组合键退出终端。下面进行示例演示,示例代码如下:

从以上示例中可以看到,容器已经被终止。接着将容器启动并进入容器,再使用 Ctrl+P+Q 组合键退出,示例代码如下:

上述示例启动了容器并使用 Ctrl+P+Q 组合键退出了容器,接着查看当前容器状态,示例代码如下:

上述示例中可以看到,容器处于运行状态,并没有被终止。

docker attach 还有有共享屏幕的功能,两个终端同时使用 docker attach 进入同一个容器时可以看到同步操作。如图所示:

🍑 docker exec

下面对 exec 的参数进行介绍,如表所示。

docker exec 可以在宿主机上向运行的容器传输命令,示例代码如下:

以上示例通过 docker exec 命令向容器发送 ls 命令,并将结果回显至终端。

下面创建一个新容器,并为容器启动一个虚拟终端,使用命令行对容器进行操作,示例代码如下:

上述示例通过虚拟终端对容器进行一系列的操作。接着使用 exit 命令退出容器,并查看容器状态,示例代码如下:

以上示例使用 exit 命令退出了容器,但容器仍在运行状态。

这说明 docker exec 与 docker attach 不同,在使用 exec 进入的容器中执行 exit 命令不会终止容器,只会退出当前 bash 终端。

所以在工作中,建议大家使用 docker exec 命令进入容器,这样不容易出现操作失误。