如何为初学者编写 Dockerfile

如何为初学者编写 Dockerfile

在深入了解Dockerfile是什么之前,让我们先做一个小实验。还记得上一节我们拉取的Python镜像吗?我们先使用 docker run -it 命令进入容器。回想一下 -it 参数的作用——它为容器分配一个伪TTY,允许用户与容器进行交互。进入容器后,让我们列出当前目录中的所有文件:

[root@novita ~]# docker run -it python:3.7 /bin/bash
root@692f87774bf7:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@692f87774bf7:/# 

接下来,我们创建一个名为 hello.py 的文件,然后再次列出所有文件:

root@692f87774bf7:/# touch hello.py
root@692f87774bf7:/# ls
bin  boot  dev  etc  hello.py  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

可以看到 hello.py 已经创建成功。现在,我们退出容器,并使用相同的 docker run -it python:3.7 /bin/bash 命令重新进入容器的交互模式,然后再次列出所有文件:

root@692f87774bf7:/# exit
exit
[root@novita ~]# docker run -it python:3.7 /bin/bash
root@65c767655e8a:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@65c767655e8a:/#

你现在可能已经注意到问题了。奇怪的是,我们之前创建的文件消失了。这是因为在容器内部执行的操作并不会修改镜像。容器只是在镜像之上添加了一个可写层,就像临摹书法模板用的描红纸——无论你在描红纸上写什么,都不会影响下面那一层。这个特性有点像虚拟机快照。

但问题来了:如果容器内的操作不会修改镜像,那我们如何才能实现快速部署,而不必在每次代码部署前都重复某些操作呢?那样效率太低了。假设你是一家社交平台的技术负责人,突然出现了一个爆款活动,需要快速扩容到数百台云服务器来应对海量用户流量。你的团队选择了 Docker 来部署应用。如果你用上述方法部署,用户可能会失望。等到服务恢复时,他们可能已经流失了。

这时候就要用到 Dockerfile。根据 Docker 的官方介绍:Docker 可以通过读取 Dockerfile 中的指令来自动构建镜像。Dockerfile 是一个文本文档,其中包含了用户可以在命令行上调用的所有用于组装镜像的命令。使用 docker build,用户可以创建一个自动构建,它会依次执行多条命令行指令。

简单来说,Dockerfile 是一个文本文档,其中包含了从命令行构建镜像需要的所有命令。它就像一个说明书,指导如何将一组积木拼装成想要的镜像。

我们从一个实际场景来探索如何构建 Dockerfile,以 Python 镜像为例。在我的本地机器(容器外部)上有一个名为 Optimal_Hotel_Matching.py 的 Python 脚本。它是一个网页抓取程序。让我们尝试在容器内运行它:不出所料,报错了,因为 Python 镜像中没有安装第三方模块 requests HTTP 库。这是一个典型的设置依赖环境的场景。让我们尝试用 Dockerfile 来解决这个问题。

在编写第一个 Dockerfile 之前,我们先熟悉一些常见的 Dockerfile 指令:

  • FROM:指定构建的基础镜像。
  • MAINTAINER:描述镜像创建者的姓名和邮箱。
  • RUN:Dockerfile 中最关键的指令之一。它在容器中执行命令并提交结果。
  • CMD:指定容器启动时要执行的命令。
  • COPY:将主机上的文件复制到容器的文件系统中。
  • WORKDIR:为 Dockerfile 中后续的 RUNCMDENTRYPOINT 指令设置工作目录。

现在,让我们编写第一个 Dockerfile 来满足我们的需求:安装 requests 库并运行脚本。以下是一个可能的方案:

FROM python:3.7                             # 指定基础镜像为 python:3.7
MAINTAINER ultra "tech@novita.ai"     # 镜像创建者的姓名和邮箱
RUN pip install requests                  # 安装 requests 库
WORKDIR /dockerfileTest                   # 设置工作目录
COPY . .                                  # 将当前目录内容复制到容器中
CMD ["python", "Optimal_Hotel_Matching.py"]  # 运行脚本的命令

将上述内容保存到项目目录中名为 Dockerfile 的文件中。现在,使用 docker build 命令构建镜像,并添加标签以便识别:

[root@novita dockerfileTest]# docker build --tag python:requests .
Sending build context to Docker daemon  5.12 kB
...

构建完成后,使用 docker images 命令验证:

[root@novita dockerfileTest]# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
python                  requests            04f20acdc288        2 hours ago         926 MB
...

可以看到,本地已经生成了一个标记为 requests 的新 Python 镜像。尝试运行这个镜像,看看 No module named 'requests' 错误是否仍然存在,以及程序是否按预期运行。

[root@novita dockerfileTest]# docker run python:requests
Computing distance between 116.368816,39.866464  and  116.438946,39.921624
Computing distance between 116.370910,39.869603  and  116.438946,39.921624
...

成功了!容器运行了代码并退出了。这样就结束了吗?在这篇文章中,我分享了 Dockerfile 的一个简单应用。在实际的企业生产环境中,Dockerfile 通常要复杂得多。

Novita AI 是一个一站式云平台,助力实现您的 AI 抱负。通过无缝集成的 API、无服务器计算和 GPU 加速,我们提供经济高效的工具,助您快速构建和扩展 AI 驱动业务。无需操心基础设施,免费开始使用 —— Novita AI 让您的 AI 梦想变为现实。

推荐阅读:

  1. 开发 ESRGAN 4 倍放大工具的终极指南
  2. 掌握 Stable Diffusion LoRA:成功策略