从构建应用、安装依赖项和服务,到自动化部署等等——一切始于Dockerfile。让我们回顾一下Dockerfile的语法,从基础到复杂,以及构建Docker镜像时的一些最佳实践。
本指南将编写一个Dockerfile,指导Docker为我们将交付的应用程序选择一个最小化的Linux(基础镜像),并附带我们选择的工具集和特定配置,有效地构建我们自己的Linux发行版,该发行版恰好适合运行我们的应用程序。
使用Docker,您可以“构建、交付和运行任何应用程序,无论在何处”。也就是说,您可以将您的应用程序与所有二进制文件和运行时库、后端工具、操作系统调整甚至应用程序运行所需的特定服务打包在一起——并使其能够立即交付和自动部署。
Docker实现的软件容器技术使这一切成为可能。尽管我在这里不会详细介绍其背后的细节,但您可以在《理解Docker、容器和更安全的软件交付》中阅读更多关于Docker、软件容器是什么以及它们如何工作的信息。
在开始之前,您需要安装Docker,无论是在本地机器上还是在远程服务器上。
幸运的是,最新版本的Docker(截至撰写本文时为1.12版)使安装过程非常流畅,并且您可以获得针对Windows、MacOS和Linux的简单易懂的指南。
为了在Docker中构建镜像,您首先需要在一个名为Dockerfile的纯文本文件中设置此构建的指令和上下文(稍后将详细介绍)。此文件具有类似于Apache配置文件的语法——每行一条指令及其相应的参数,所有指令都按顺序依次处理。注释以#字符和空格开头。最后,一旦您有了Dockerfile,命令docker build将构建镜像,我们稍后将更详细地介绍。
在我们开始编写Dockerfile之前,我们将设置工作区。我们将在主目录中创建一个名为my_image的目录,将其用作我们的工作目录,并将Dockerfile放在其中:
mkdir ~/my_build cd ~/my_build touch Dockerfile
现在我们准备开始构建镜像了。
在创建镜像时,大多数情况下,您将使用一个起点——即另一个镜像。这可以是Docker Hub中提供的官方Ubuntu、MySQL、WordPress或任何其他镜像。您也可以使用之前自己创建的镜像。
注意:您可以使用Docker的保留的最小镜像(称为scratch)创建自己的基础镜像,其中包含您自己的核心工具和目录结构。我不会在此处介绍此过程,但您可以参考Docker网站上关于创建基础镜像的指南。
例如,如果您想从最小化的Debian发行版开始,您将向Dockerfile添加以下内容:
# 设置基础镜像 FROM debian
FROM必须是您编写Dockerfile时使用的第一条指令。请注意,您还可以通过在镜像名称的末尾附加:和version_name来使用基础镜像的特定版本。例如:
# 设置基础镜像 FROM debian:sid
在上面的代码中,我们使用的是“sid” Debian(不稳定发行版)。当您使用任何这些工具的官方基础镜像时,这在您需要特定版本的Ruby或Python解释器、MySQL版本等时也很重要。目前,在本指南中,我们将坚持使用默认的(稳定的)debian镜像。
您可以选择指定维护者是谁,用您的姓名或负责构建的人员或团队替换Lucero del Alba:
# 作者 MAINTAINER Lucero del Alba
这不是必需的,但我们也可以使用LABEL指令添加一些元数据,这些信息稍后在使用docker inspect命令检查镜像时将可用:
# 额外的元数据 LABEL version="1.0" LABEL description="First image with Dockerfile."
有关此功能的更多信息,请参阅Docker对象标签。
此时,我们将选择一些要包含在镜像中的工具和库,以便我们的容器拥有执行预期操作所需的一切。在本教程结束时,我们将执行一项非常接近实际构建Linux发行版的工作。
某些容器(例如运行PostgreSQL数据库的容器)旨在在后台运行。但是,我们经常需要一个控制台来对容器执行某些操作,因此我们可能需要一些额外的工具,因为基础镜像只会捆绑最少的GNU工具。
在尝试在镜像上安装附加包时,您几乎肯定会遇到缓存问题。这是因为基础镜像带有缓存的元数据,并且您从中提取数据的实时存储库经常发生变化。
在基于Debian的发行版中,您可以在安装新包之前添加以下命令来处理此问题:
mkdir ~/my_build cd ~/my_build touch Dockerfile
代码编辑器、语言环境、git或tmux等工具——现在是安装以后所需的一切的时候了,以便它们捆绑在镜像中。
我们将每行安装一个:
# 设置基础镜像 FROM debian
我们可以在一行中安装所有这些,但是如果我们稍后要添加或删除包,则需要重新运行整个过程。因此,这里的最佳实践是每行安装一个包,以便您可以从Docker的缓存中获益。
此外,保持简洁。您不希望“以防万一”安装工具,因为这可能会增加构建时间和镜像大小。
我们还将在此镜像中交付我们的应用程序。您是否需要特定版本的PHP、Ruby或Python以及某些模块?现在是交付应用程序所需的所有程序和运行时的时候了。
您可以随意指定,因为此容器旨在仅运行您的应用程序:
# 设置基础镜像 FROM debian:sid
在此示例中,我们将安装Python 3以及Psycopg 2(用于连接到PostgreSQL数据库)、Python Mustache模块和YAML模块。(在创建您自己的Dockerfile时,您自然会安装所需的特定依赖项。)
您的发行版也可能没有您需要的特定模块或程序的包。但是您不需要在运行的容器中手动安装它!相反,您可以使用RUN指令(每行一个)批量下载、编译和设置应用程序所需的任何库。
您甚至可以在单独的文件上编写脚本,将此文件添加到构建并运行它,我们将在“交付您自己的应用程序”部分看到。
为了使您的镜像整洁且尽可能小,最好在安装序列结束时进行清理:
# 作者 MAINTAINER Lucero del Alba
同样,请注意我们使用的是apt-get,因为我们选择了Debian,但是请对基础镜像的发行版使用相应的命令。
构建此环境的全部目的是为了使您可以顺利交付应用程序并准备运行。为了将文件、目录甚至远程URL的内容添加到镜像中,我们将使用ADD指令。
但是,在添加文件之前,我们需要将它们放在适当的上下文中。为了简化操作,我们将所有内容都放在前面提到的my_build目录中,与Dockerfile本身一起。
假设使用我们想要放入镜像中的应用程序和所有内容,我们在~/my_build中具有以下文件(其中app.py和lib.py位于子目录app/中):
mkdir ~/my_build cd ~/my_build touch Dockerfile
我们将.bashrc和.profile脚本添加到容器中的/root目录中,以便它们在我们在容器上启动shell时执行,并将app/的内容复制到容器中的/app/目录中。
我们添加以下指令:
# 设置基础镜像 FROM debian
最后,我们将设置一些在系统和应用程序级别都需要的一些环境变量。
你们中的许多人使用默认的Debian字符集就可以了,但是由于我们的目标是国际受众,让我们看看如何拥有UTF-8终端。我们之前安装了locales包,所以现在我们要做的就是生成字符集并设置适当的Linux环境:
# 设置基础镜像 FROM debian:sid
您可能还需要为应用程序设置一些环境变量,用于交换密码和路径。Dockerfile提供ENV指令来精确地执行此操作:
# 作者 MAINTAINER Lucero del Alba
请注意,您还可以在启动容器时从命令行传递环境变量,这对于共享一些敏感信息(例如密码)可能很方便。
当然,您必须根据您的需要调整Dockerfile,但希望您能了解其可能性。
这是完整的文件:
# 额外的元数据 LABEL version="1.0" LABEL description="First image with Dockerfile."
从my_build目录内部,我们将使用docker build命令,传递-t标志来使用名称“标记”新镜像,在本例中为my_image。.表示Dockerfile位于当前目录中,以及所谓的“上下文”——即该位置中可能存在的其余文件:
# 更新源列表 RUN apt-get clean RUN apt-get update
这将生成一个长输出,其中每个“步骤”都是我们Dockerfile中的一个指令。这是一个截断的输出:
# 每行安装一个基本应用程序,以获得更好的缓存 RUN apt-get install -qy git RUN apt-get install -qy locales RUN apt-get install -qy nano RUN apt-get install -qy tmux RUN apt-get install -qy wget
我们可以使用docker images命令列出我们的镜像:
# 安装应用程序运行时和模块 RUN apt-get install -qy python3 RUN apt-get install -qy python3-psycopg2 RUN apt-get install -qy python3-pystache RUN apt-get install -qy python3-yaml
这将输出我们新创建的my_image以及我们下载的其他基础镜像:
# 清理 RUN apt-get -qy autoremove
……就是这样,我们的镜像已准备好交付和运行!
最后,为了启动我们新创建的镜像的交互式终端,我们将使用docker run命令:
<code>.bashrc .profile app/app.py app/lib.py Dockerfile</code>
我没有介绍Dockerfile的所有可能性。特别是,我没有回顾如何EXPOSE端口以便您可以运行服务甚至在它们之间链接容器;如何HEALTHCHECK容器以验证它们仍在工作;甚至如何指定VOLUME以从主机存储和恢复数据……以及其他有用功能。
我们将在以后的文章中介绍这些内容。目前,您可能想查看以下资源。
来自Docker网站:
来自SitePoint:
Dockerfile是一个文本文档,其中包含用户可以在命令行上调用的所有命令,以组装镜像。使用Dockerfile简化了在Docker中构建镜像的过程。它允许您自动化该过程,使其更有效率且更不容易出错。Dockerfile还提供了关于如何构建镜像的清晰、版本控制的文档,这使得其他开发人员更容易理解您的工作并使用或修改它。
Dockerfile提供了多种优化构建过程的方法。最有效的方法之一是使用多阶段构建。这允许您在Dockerfile中使用多个FROM语句。每个FROM指令都可以使用不同的基础,并且每个指令都开始构建的新阶段。您可以选择性地将工件从一个阶段复制到另一个阶段,留下您不希望在最终镜像中出现的所有内容。
编写Dockerfile有几个最佳实践。首先,您应该避免安装不必要的包,以保持镜像大小较小。其次,使用多阶段构建来优化构建过程。第三,每个Dockerfile都应表示单个应用程序。如果您有多个应用程序,则应使用多个Dockerfile。最后,您应该使用.dockerignore文件来排除不应包含在镜像中的文件和目录。
可以通过构建镜像并使用shell命令运行它来调试Dockerfile。如果构建失败,Docker将返回错误消息,可以帮助您识别问题。您还可以使用RUN命令来执行将帮助您调试Dockerfile的命令。
是的,您可以在Dockerfile中使用环境变量。ENV指令将环境变量设置为该值。此值将在构建阶段的所有后续指令的环境中,并且也可以在许多指令中内联替换。
您可以使用COPY指令将新文件从主机复制到Docker镜像。文件从主机上的源复制到Docker镜像中的目标。
您可以使用EXPOSE指令通知Docker容器在运行时侦听指定的网络端口。但是,这实际上并没有发布端口。要发布端口,您需要在docker run命令上使用-p标志。
您可以使用WORKDIR指令为Dockerfile中后续的任何RUN、CMD、ENTRYPOINT、COPY和ADD指令设置工作目录。
您可以使用RUN指令在Docker镜像中运行命令。这将在当前镜像之上新的层上执行任何命令,并提交结果。
您可以使用CMD指令为正在执行的容器提供默认值。这些可以包括可执行文件,或者可以省略可执行文件,在这种情况下,您必须指定ENTRYPOINT指令。
This revised output maintains the original image formatting and avoids significant changes to the article's meaning while rephrasing sentences and paragraphs for originality. Remember to replace /uploads/20250218/...
with the actual image URLs.
以上是如何使用Dockerfile构建图像的详细内容。更多信息请关注PHP中文网其他相关文章!