Docker 解析:使用 Dockerfile 自动构建镜像

简介


Docker 容器是使用 基础 镜像创建的。一个镜像可以是基本的,只包含操作系统的基本要素,也可以包含一个准备好启动的复杂的预构建应用程序堆栈。

在使用 Docker 构建镜像时,每个操作(例如执行的命令,比如 apt-get install)都会形成一个新的层叠在之前的层之上。然后可以使用这些基础镜像来创建新的容器。

在这篇 DigitalOcean 文章中,我们将尽可能自动化这个过程,并演示通过 Dockerfiles 来实现 Docker 和容器的最佳实践和方法:逐步、自动地从基础镜像构建容器。

术语表


1. Docker 简介


2. Dockerfiles


3. Dockerfile 语法


  1. 什么是语法?
  2. Dockerfile 语法示例

4. Dockerfile 命令


  1. ADD
  2. CMD
  3. ENTRYPOINT
  4. ENV
  5. EXPOSE
  6. FROM
  7. MAINTAINER
  8. RUN
  9. USER
  10. VOLUME
  11. WORKDIR

5. 如何使用 Dockerfiles


6. Dockerfile 示例:创建安装 MongoDB 的镜像


  1. 创建空的 Dockerfile
  2. 定义我们的文件及其目的
  3. 设置要使用的基础镜像
  4. 定义维护者(作者)
  5. 更新应用程序仓库列表
  6. 设置下载 MongoDB 的参数和命令
  7. 设置 MongoDB 的默认端口
  8. 保存 Dockerfile
  9. 构建我们的第一个镜像
  10. 运行 MongoDB 实例

Docker 简介


Docker 项目提供了一些在一些 Linux 内核特性之上构建的高级工具。其目标是帮助开发人员和系统管理员将应用程序及其所有依赖项一起移植,并在各种系统和机器上 无忧地 运行。

Docker 通过为应用程序创建安全的基于 LXC(即 Linux 容器)的环境来实现这一目标,这些环境被称为 "Docker 容器"。这些容器是使用 Docker 镜像 创建的,这些镜像可以通过手动执行命令或通过 Dockerfiles 自动构建。

注意: 要了解更多关于 Docker 及其部分(例如 Docker 守护程序、CLI、镜像等)的信息,请查看我们的项目介绍文章:如何在 Ubuntu 16.04 上安装和使用 Docker。

Dockerfiles


每个 Dockerfile 都是一个脚本,由各种命令(指令)和参数依次列出,用于自动在基础镜像上执行操作以创建(或形成)一个新镜像。它们用于组织事物,并通过简化整个部署过程大大帮助部署。

Dockerfiles 以定义一个图像 FROM 开始,该图像是 构建过程 的起点。随后是各种其他方法、命令和参数(或条件),以返回一个新的图像,该图像将用于创建 Docker 容器。

它们可以通过以各种方式提供 Dockerfile 的内容来使用,以便由 docker 守护程序 构建图像(如 如何使用 部分中所述)。

Dockerfile 语法


在我们开始讨论 Dockerfiles 之前,让我们快速了解其语法及其实际含义。

什么是语法?


在编程中,语法简单地意味着一种结构,用于按顺序排列命令、参数和执行应用程序所需的所有其他内容,以执行一个过程(即一个函数/一系列指令)。

这些结构基于明确定义的规则,并且程序员必须遵循这些规则,以与使用或期望它们的任何计算机应用程序(例如解释器、守护程序等)进行交互。如果脚本(即包含要执行的一系列任务的文件)没有正确结构化(即语法错误),计算机程序将无法解析它。解析大致可以理解为对输入进行检查,最终目标是理解其含义。

Dockerfiles 使用简单、清晰的语法,使它们非常容易创建和使用。它们被设计为自解释的,特别是因为它们允许像良好编写的应用程序源代码一样进行注释。

Dockerfile 语法示例


Dockerfile 语法由两种主要的行块组成:注释和命令 + 参数。

# 用于注释的行块
命令 参数 参数 ..

一个简单的示例:

# 打印 "Hello docker!"
RUN echo "Hello docker!"

Dockerfile 命令(指令)


目前有大约十几种不同的命令集,Dockerfiles 可以包含这些命令集以使 Docker 构建一个镜像。在本节中,我们将在单独讨论所有这些命令之前逐一介绍它们。

注意: 如前一节(Dockerfile 语法)所述,所有这些命令都应按照您希望它们由 docker 守护程序执行的顺序(即执行)依次列出(即编写)在单个纯文本文件(即 Dockerfile)中。然而,其中一些命令(例如 MAINTAINER)可以放置在您认为合适的任何位置(但始终在 FROM 命令之后),因为它们不构成任何执行,而是 定义的值(即一些附加信息)。

ADD


ADD 命令有两个参数:源和目的地。它基本上将主机上源目录中的文件复制到容器自己的文件系统中的设置目的地。然而,如果源是一个 URL(例如 http://github.com/user/file/),那么将下载该 URL 的内容并放置在目的地。

示例:

# 用法: ADD [源目录或 URL] [目的地目录]
ADD /my_app_folder /my_app_folder

CMD


CMD 命令与 RUN 类似,用于执行特定命令。然而,与 RUN 不同的是,CMD 不是在构建时执行,而是在使用正在构建的镜像实例化容器时执行。因此,它应被视为在基于该镜像创建容器时执行的初始默认命令。

澄清一下: CMD 的一个示例是在容器创建时运行一个已经使用 RUN(例如 RUN apt-get install ...)在镜像中安装的应用程序。使用 CMD 设置的默认应用程序执行命令将成为默认命令,并替换在创建时传递的任何命令。

示例:

# 用法 1: CMD 应用程序 "参数", "参数", ..
CMD "echo" "Hello docker!"

ENTRYPOINT


ENTRYPOINT 参数设置每次使用正在构建的镜像创建容器时使用的具体默认应用程序。例如,如果您在镜像中安装了特定应用程序,并且您将使用该镜像仅运行该应用程序,您可以使用 ENTRYPOINT 来指定,这样每次从该镜像创建容器时,您的应用程序将成为目标。

如果将 ENTRYPOINT 与 CMD 结合使用,可以从 CMD 中删除 "应用程序",只留下将传递给 ENTRYPOINT 的 "参数"。

示例:

# 用法: ENTRYPOINT 应用程序 "参数", "参数", ..
# 注意: 参数是可选的。它们可以由 CMD 提供,
#      或在创建容器时提供。
ENTRYPOINT echo

# 使用 CMD 的示例:
# 通过 CMD 设置的参数可以在 *run* 期间被覆盖
CMD "Hello docker!"
ENTRYPOINT echo

ENV


ENV 命令用于设置环境变量(一个或多个)。这些变量由"键值"对组成,可以被脚本和应用程序在容器内访问。Docker 的这一功能为运行程序提供了巨大的灵活性。

示例:

# 用法: ENV 键 值
ENV SERVER_WORKS 4

EXPOSE


EXPOSE 命令用于将指定端口与容器内运行的进程与外部世界(即主机)进行网络关联。

示例:

# 用法: EXPOSE [端口]
EXPOSE 8080

要了解 Docker 网络,请查看 Docker 容器网络文档。

FROM


FROM 指令可能是 Dockerfile 中最关键的指令。它定义了用于启动构建过程的基础镜像。它可以是任何镜像,包括您之前创建的镜像。如果在主机上找不到 FROM 镜像,Docker 将尝试在 Docker Hub 或其他容器存储库中找到它(并下载)。它需要是 Dockerfile 中声明的第一个命令。

示例:

# 用法: FROM [镜像名称]
FROM ubuntu

MAINTAINER


可以在文件中的任何位置设置的命令之一(尽管最好是在顶部声明)是 MAINTAINER。这个非执行命令声明了作者,因此设置了镜像的作者字段。然而,它应该在 FROM 之后声明。

示例:

# 用法: MAINTAINER [姓名]
MAINTAINER 作者的姓名

RUN


RUN 命令是 Dockerfile 的中心执行指令。它以命令作为参数并运行它以形成镜像。与 CMD 不同,它实际上用于构建镜像(在前一个镜像的顶部形成另一层,该层被提交)。

示例:

# 用法: RUN [命令]
RUN aptitude install -y riak

USER


USER 指令用于设置基于正在构建的镜像运行容器的 UID(或用户名)。

示例:

# 用法: USER [UID]
USER 751

VOLUME


VOLUME 命令用于启用容器访问主机机器上的目录(即挂载它)。

示例:

# 用法: VOLUME ["/dir_1", "/dir_2" ..]
VOLUME ["/my_files"]

WORKDIR


WORKDIR 指令用于设置 CMD 中定义的命令要执行的位置。

示例:

# 用法: WORKDIR /路径
WORKDIR ~/

如何使用 Dockerfiles


使用 Dockerfiles 就像让 Docker 守护程序运行一个一样简单。执行脚本后的输出将是新 Docker 镜像的 ID。

用法:

# 在当前位置使用 Dockerfile 构建一个镜像
# 例如:docker build -t [name] .
docker build -t my_mongodb .    

Dockerfile 示例:创建一个安装 MongoDB 的镜像


在 Dockerfiles 的最后一节中,我们将创建一个 Dockerfile 文档,并逐步填充它,最终得到一个可以用来创建运行 MongoDB 容器的 Dockerfile。

注意: 在开始编辑 Dockerfile 后,所有下面各节的内容和参数都将依次写入(追加)到其中,遵循我们的示例和Docker 语法部分的解释。您可以在本教程的最后部分看到最终结果。

创建空的 Dockerfile


使用 nano 文本编辑器,让我们开始编辑我们的 Dockerfile。

nano Dockerfile

定义我们的文件及其目的


虽然可选,但始终是一个好习惯,让自己和其他人在必要时能够弄清楚这个文件是什么,以及它的目的是什么。因此,我们将用花哨的注释(#)开始我们的 Dockerfile 来描述它。

############################################################
# Dockerfile to build MongoDB container images
# Based on Ubuntu
############################################################

设置要使用的基础镜像


# 将基础镜像设置为 Ubuntu
FROM ubuntu

定义维护者(作者)


# 文件作者 / 维护者
MAINTAINER Example McAuthor

设置下载 MongoDB 的参数和命令


################## 开始安装 ######################
# 按照 MongoDB 文档的说明安装 MongoDB
# 参考:http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/

# 添加软件包验证密钥
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10

# 将 MongoDB 添加到存储库源列表
RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/mongodb.list

# 更新存储库源列表
RUN apt-get update

# 安装 MongoDB 软件包(.deb)
RUN apt-get install -y mongodb-10gen

# 创建默认数据目录
RUN mkdir -p /data/db

##################### 安装结束 #####################

设置 MongoDB 的默认端口


# 公开默认端口
EXPOSE 27017

# 执行入口点(MongoDB)的默认端口
CMD ["--port 27017"]

# 设置默认容器命令
ENTRYPOINT usr/bin/mongod

保存 Dockerfile


在将所有内容追加到文件后,是时候保存并退出了。按下 CTRL+X,然后按 Y 确认并保存 Dockerfile。

最终文件应如下所示:

############################################################
# Dockerfile to build MongoDB container images
# Based on Ubuntu
############################################################

# 将基础镜像设置为 Ubuntu
FROM ubuntu

# 文件作者 / 维护者
MAINTAINER Example McAuthor

################## 开始安装 ######################
# 按照 MongoDB 文档的说明安装 MongoDB
# 参考:http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/

# 添加软件包验证密钥
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10

# 将 MongoDB 添加到存储库源列表
RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/mongodb.list

# 更新存储库源列表
RUN apt-get update

# 安装 MongoDB 软件包(.deb)
RUN apt-get install -y mongodb-10gen

# 创建默认数据目录
RUN mkdir -p /data/db

##################### 安装结束 #####################

# 公开默认端口
EXPOSE 27017

# 执行入口点(MongoDB)的默认端口
CMD ["--port 27017"]

# 设置默认容器命令
ENTRYPOINT usr/bin/mongod

构建我们的第一个镜像


根据之前的解释,我们已经准备好用 docker 创建我们的第一个 MongoDB 镜像了!

docker build -t my_mongodb .

注意: 这里的 -t [name] 标志用于给镜像打标签。要了解在构建过程中还可以做什么,请运行 docker build --help

运行 MongoDB 实例


使用我们构建的镜像,现在我们可以进行最后一步:创建一个运行 MongoDB 实例的容器,可以使用我们选择的名称(如果需要,可以使用 -name [name])。

bash 复制代码
docker run -name my_first_mdb_instance -i -t my_mongodb

注意: 如果没有设置名称,我们将需要处理复杂的包含字母数字的 ID,可以通过使用 docker ps -l 命令列出所有容器来获取。

注意: 要从容器中分离出来,请使用转义序列 CTRL+P,然后是 CTRL+Q

祝您使用愉快!

相关推荐
小燚~几秒前
ubuntu开机进入initramfs状态
linux·运维·ubuntu
年薪丰厚7 分钟前
如何在K8S集群中查看和操作Pod内的文件?
docker·云原生·容器·kubernetes·k8s·container
小林熬夜学编程7 分钟前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
zhangj11258 分钟前
K8S Ingress 服务配置步骤说明
云原生·容器·kubernetes
岁月变迁呀9 分钟前
kubeadm搭建k8s集群
云原生·容器·kubernetes
墨水\\10 分钟前
二进制部署k8s
云原生·容器·kubernetes
Source、11 分钟前
k8s-metrics-server
云原生·容器·kubernetes
上海运维Q先生12 分钟前
面试题整理15----K8s常见的网络插件有哪些
运维·网络·kubernetes
颜淡慕潇15 分钟前
【K8S问题系列 |19 】如何解决 Pod 无法挂载 PVC问题
后端·云原生·容器·kubernetes
hhhhhhh_hhhhhh_21 分钟前
ubuntu18.04连接不上网络问题
linux·运维·ubuntu