如何使用Docker图像、容器和Dockerfile

2020-10-26 21:49:55

当你刚开始的时候,Docker可能会让你感到困惑。即使您看了几个教程,它的术语仍然可能不清楚。本文的目标读者是那些安装过Docker并有过一些经验的人,但可能需要澄清一下。我们将制作Docker的所有三个核心部分,并提供一些有用的其他命令。它将涵盖很多内容,一定要点击链接。

我们将逐步介绍这张图的每一个部分,但将前面的三个主要阶段看作路线图会很有帮助。简而言之,Dockerfile用于构建镜像。图像用于创建容器。然后,您必须启动并连接到容器上。Run命令允许您一次组合所有创建、启动和附加命令。

为了让我们的项目有所作为,我们将创建一个server.js文件,该文件发送一个简单的文本响应。这是本教程中唯一的节点代码。您不需要知道Node。

Const http=Required(";http";);const app=(req,res)=>;{console.log(";ping!";);res.end(";Hello here.";,";utf-8";);}http.createServer(App).listen(3000);console.log(";server started";);

Dockerfile只是一个文本文件,其中包含Docker将解释以生成图像的指令。它大部分时间相对较短,主要由相互构建的单独线路组成。它应该称为Dockerfile(区分大小写),并且没有文件扩展名。下面是一个简单的示例:

这不是关于如何编写Dockerfile的教程,但是让我们花一点时间来讨论一下。我们的Dockerfile所做的是从DockerHub(或您的机器)拉下名为node:12-slm的节点映像,以便我们可以在其上构建自定义映像。DockerHub是一个在线图片库;有点像NPM或Pip。然后,我们将server.js复制到环境中,以便最终的容器可以访问它。Dockerfile中的最后一件事通常是容器创建后要运行的CMD(命令)。在我们的示例中,它将启动我们的server.js。

注意:CMD数组的每一段都要用双引号括起来,这一点很重要,否则它将无法正常工作。

从Dockerfile构建映像的方法是在命令行上运行build。以下命令假定我们与server.js和Dockerfile位于同一目录中:

那个。告诉Docker从当前目录中的Dockerfile构建。作为额外奖励,我们为我们的图像添加了my-node-img标记。这将帮助我们指定正在使用的图像,而不必使用ID。这里有一个关于图像标签的指南。您应该知道,您可以使用图像和容器ID代替标记和名称,但是单词更容易记住。建造可能需要一分钟,但一旦完成,我们就会有自己的形象!通过运行以下命令查看它:

如果Dockerfile是用于创建镜像的一组指令,那么将镜像看作是用于创建容器的模板会很有帮助。映像负责设置容器内将存在的应用程序和环境。需要了解的重要一点是,图像是只读的。您不需要对图像进行编辑,而是对Dockerfile进行编辑,然后构建新的图像。

使Docker如此强大的功能之一是图像可以分层。在每个Dockerfile中,您将从一个基础映像开始。而那些基础图像可能是从其他图像构建而来的,它一直都是图像。这种分层效果有助于实现用于CI/CD目的的缓存等功能。但不管怎样,除了创建容器之外,图像也没什么好处,所以我们就这么做吧!

最后,我们要说到好东西了。从技术上讲,您需要做的就是创建容器:

但是,对于我们的服务器示例来说,这是无用的。我们需要添加一些标志:

--name允许我们指定自己的名称。如果我们不这样做,Docker会自动为容器生成一个名称,但它们又长又可怕。Init表示我们使用的是Docker内置的Tini包。它处理ctrl-C,使我们不会被困在容器中。接下来是-p,它将主机的端口3000连接到Docker容器的端口3000。没有它,我们将无法连接到我们的服务器。最后一个参数是将创建容器的实际图像标记。

容器是实际运行我们的应用程序的东西。可以将容器想象成一个孤立的Linux盒子。它本质上是一个重量更轻的虚拟机。拥有集装箱的意义在于标准化。应用程序只需关心它在其中运行的容器。不会再说了,“但它能在我的机器上工作!”如果应用程序在容器中运行,则无论容器本身驻留在何处,它都将以相同的方式工作。这使得本地开发和生产部署都变得非常非常容易。

Create所做的只是创建容器,而不是启动它。您仍然可以看到它与坞站PS和一些额外的过滤器一起存在:

但是,如果您转到localhost:3000,则什么也不会发生。我们的集装箱仍然不活动,它只是…。存在;其状态仅为“已创建”。通过运行以下命令启动它:

现在,当您转到localhost:3000时,它会响应!因为我们的容器正式“运行”了,所以我们也可以使用常规的docker ps来查看它,默认情况下,它只显示正在运行的容器。

我们如何查看容器的输出和日志?从技术上讲,您可以运行一个命令,但在键入它之前请稍候:

请注意:如果您运行ATTACH,您的终端将在显示容器日志时停滞。更糟糕的是,如果您连接然后按ctrl-C组合键退出,它实际上会在退出时停止容器。或者更糟的是,它将忽略ctrl-C并捕获您的终端。如果这种情况发生在您身上,您将不得不打开一个新的终端并停止容器(稍后将详细介绍)。这就是在您的应用程序中应该处理SIGTERM或使用TINI包的原因,就像我们在示例中所做的那样。查看输出的更好方法是Docker logs命令:

这将显示从您的容器打印的日志。按Ctrl-C组合键可以在不中断容器的情况下离开这里。如果您只想静态打印日志,那么可以省略-f标志。

如果您想要进入容器来浏览文件系统,则需要运行以下命令:

EXEC在运行的容器上执行任何命令。如果它是交互式的,比如打开bash shell,则必须包括-it标志。另外,请注意某些容器可能没有安装bash,因此如果不起作用,您可能需要尝试使用sh或ash。

正如您在信息图中所记得的那样,Run是一种快捷方式,可以一次完成创建、启动和附加操作:

但是,正如我们所说的,连接会占用终端,这可能不是您想要的。运行带有-d标志的命令(分离模式),以便容器进入后台:

除了新的--rm标志之外,所有选项仍在执行与create相同的操作。这只是在我们停止容器时将容器从机器中删除。这将允许您运行相同的命令,而不会出现名称空间问题;它主要用于练习。

当然,您会想要停下来移走旧的/卡住的容器,幸运的是这很简单:

子shell使用-q(安静)标志仅返回容器ID,然后将其提供给停止命令。

Run实际上不需要映像位于主机上。如果Docker在本地找不到指定的镜像,会尝试在DockerHub上找到。这在与Run的另一个特性配合使用时非常有用:它可以在新创建的容器上执行命令。例如,您可以启动一个节点映像,然后在bash中启动它,而不是默认的Node repl:

要运行的命令紧跟在图像标记之后。请记住,如果命令是交互式的,则只需要-it标志。例如,如果您只想查看Linux版本,则不需要任何标志:

我们有一个集装箱,是的,但是第二个集装箱呢?这是Docker的另一个强大特性:您可以轻松地将容器联网在一起。但是,一旦您有2个或更多的容器需要管理,我不建议您尝试从命令行控制它们。不,您需要开始使用的是容器编排系统,通常是用于本地开发的Docker和用于实际生产的Kubernetes。我推荐看这个视频来学习作曲的基础知识,这个系列可以让你更深入地了解Kubernetes。

#构建您的镜像docker build-t my-node-img。#show Specific image docker image ls my-node-img#要查看机器docker映像ls上的所有图像,请使用微包、名称和端口docker创建容器--init--name my-app-p 3000:3000 my-node-img#show new create容器docker ps-a--filter";name=my-app";#启动您的集装箱码头启动my-app#连接到容器(不推荐)docker连接my-app#查看容器日志(推荐)码头日志-f my-app#访问容器';S system docker exec-it my-app bash#使用运行快捷方式docker run--name my-app-p 3000:3000-d--init--rm my-node-img#停止正在运行的容器docker stop my-app#删除非正在运行的容器docker rm my-app#查看所有正在运行的容器docker ps#停止所有正在运行的容器docker stop$(docker ps-q)#检查容器docker运行节点的Linux版本:12-slm cat/etc/Issue