Docker 教程(二):Dockerfile

简介: Dockerfile包含一组关于如何构建Docker镜像的说明,通过docker build命令执行Dockerfile文件,可以构建一个Docker镜像,本文介绍了如何编写Dockerfile文件以及构建一个Docker镜像。

image.png

你好,我是看山。


本文源自并发编程网的翻译邀请,翻译的是 Jakob Jenkov 的 《Docker 教程》 中的第二篇。


Dockerfile包含一组关于如何构建Docker镜像的说明,通过docker build命令执行Dockerfile文件,可以构建一个Docker镜像,本文介绍了如何编写Dockerfile文件以及构建一个Docker镜像。


Dockerfile的好处

Dockerfile文件以书面形式说明了如何构建一个Docker镜像,Docker镜像通常包含如下内容:


首先需要一个基本的Docker镜像,在这个基础Docker镜像上构建自己的Docker镜像。

一组需要安装在Docker镜像中的工具和应用。

一组需要复制到Docker镜像中的文件(比如配置文件)。

可能需要在防火墙中打开的网络(TPC/UDP)端口或其他。

等等。。。

首先,在Dockerfile文件中以书面形式说明这些,就意味着,我们不用特意记住应用程序如何安装,包括操作系统什么要求、需要安装的应用程序、需要赋值的文件、需要打开的网络端口等,这些内容都被记录在Dockerfile中。


另外,通过Dockerfile文件构建Docker镜像,我们不需要手动执行这些繁琐重复且容易出错的工作。Docker会自动做这些事情,简单、快速、且不容易出错。


第三,我们很容易和其他人分享Dockerfile文件,并且他们可以自己构建Docker镜像。


第四,Dockerfile很容易存储在Git这样的版本控制器中,这样就可以跟踪Dockerfile(服务器、应用配置)的变更记录。版本控制器也可以很容易的让人们协同合作,比如在Dockerfile上,以及分享Dockerfile。


Dockerfile的结构

Dockerfile包含一组指令,每个指令有一个命令和参数组成,类似于命令行可执行文件。下面是一个Dockerfile简单示例:


# 基础镜像
FROM ubuntu:latest
# 这里可以有更多安装软件和复制文件到镜像中的说明。
COPY    /myapp/target/myapp.jar    /myapp/myapp.jar
# 在Docker容器中执行的命令。
CMD echo Starting Docker Container

Docker基础镜像

Docker镜像是由层组成,每一层都会为最终的Docker镜像添加一些内容。每一个层实际上都是一个单独的Docker镜像,所以说,Docker镜像是由一个或多个层镜像组成,我们可以在其上添加自己的层。


当通过Dockerfile文件指定自己的Docker镜像时,通常是从一个Docker基础镜像开始。这是另一个Docker镜像,可以在其上构建自己的Docker镜像。这个Docker基础镜像本身可能也包含多个层,并且是基于另一个基础镜像构建的。


我们可以使用From命令在Dockerfile文件中指定Docker镜像作为基础镜像,如下节所述。


MAINTAINER

MAINTAINER命令用于说明谁在维护这个Dockerfile文件。比如:


MAINTAINER   Joe Blocks <joe@blocks.com>

MAINTAINER命令并不常用,因为这类信息在Git存储或其他地方有了。


FROM

FROM命令用于指定Docker基础镜像,如果是从原始Linux镜像开始,可以使用如下命令:


# 基础镜像
FROM ubuntu:latest

CMD

CMD命令用于指定启动Docker容器是需要执行的命令,该容器是基于此Dockerfile构建的Docker镜像,下面是一些Dockerfile的CMD示例:


CMD echo Docker container started.

本例是打印“Docker container started”这行文本。


下一个CMD示例是启动一个java应用:


CMD java -cp /myapp/myapp.jar com.jenkov.myapp.MainClass arg1 arg2 arg3

COPY

COPY命令将一个或多个文件从主机(从Dockerfile文件构建Docker镜像的机器)复制到Docker镜像中,可以复制的内容包括文件或目录,下面是一个示例:


COPY    /myapp/target/myapp.jar    /myapp/myapp.jar

这个例子是把主机的/myapp/target/myapp.jar文件复制到Docker进行中的/myapp/myapp.jar文件。第一个参数是主机路径(从哪里来),第二个参数是Docker镜像的路径(到哪里去)。


我们还可以复制一个目录到Docker镜像中,比如:


COPY    /myapp/config/prod    /myapp/config

这个例子是把主机的/myapp/config/prod目录复制到Docker镜像中的/myapp/config目录。


我们还可以复制多个文件到Docker镜像中的一个目录中,比如:


COPY    /myapp/config/prod/conf1.cfg   /myapp/config/prod/conf2.cfg   /myapp/config/

这个例子是将主机的/myapp/config/prod/conf1.cfg文件和/myapp/conig/prod/conf2.cfg文件复制到Docker镜像中的/myapp/config/目录中。注意,目标目录必须以/(斜杠)结束才能工作。


ADD

ADD命令与COPY命令工作方式相同,只有一些细微的差别:


ADD命令可以复制并提取TAR文件到Docker镜像中。

ADD命令可以通过HTTP下载文件,并复制到Docker镜像中。

下是一些示例:


ADD    myapp.tar    /myapp/

这个例子是将指定的TAR文件解压缩并提取到Docker镜像的/myapp/目录中。


下面是另一个例子:


ADD    http://jenkov.com/myapp.jar    /myapp/

ENV

ENV命令是在Docker镜像中设置环境变量,此环境变量可用于CMD命令在Docker镜像内部启动应用程序。举个例子:


ENV    MY_VAR   123

本例将环境变量MY_VAR设置为值123。


RUN

RUN可以在Docker镜像中执行命令行指令,执行时机是Docker镜像构建过程中,所以RUN命令只会执行一次。RUN命令可用于在Docker镜像中安装应用程序、提取文件或其他命令行功能,这些操作只需要执行一次,以供Docker镜像后续使用。


RUN apt-get install some-needed-app

ARG

ARG命令允许定义一个参数,这个参数可以在通过Dockerfile文件构建Docker镜像时,通过命令参数传递给Docker。比如:

ARG tcpPort

当执行docker build命令执行Dockerfile构建Docker镜像时,可以指定tcpPort参数,比如:

docker build --build-arg tcpPort=8080 .

注意,--build-arg后面的tcpPort=8080,是将tcpPort参数的值设置为8080。


我们可以通过多个ARG命令定义多个参数,举个例子:


ARG tcpPort
ARG useTls

当构建Docker镜像时,必须为所有构建参数提供值。【译者注,1.13版本之前,不提供值会直接报错,1.13版本之后,不提供值不会报错,但是会弹出警告】。举个例子:


docker build --build-arg tcpPort=8080 --build-arg useTls=true .

我们可以为ARG设置默认值,当构建Docker镜像时,如果没有指定参数值,将使用默认值。举个例子:

ARG tcpPort=8080
ARG useTls=true

如果tcpPort和useTls在生成Docker镜像时,都没有设置参数,将使用默认值8080和true。


ARG声明的参数通常在Dockerfile的其他地方引用,比如:


ARG tcpPort=8080
ARG useTls=true
CMD start-my-server.sh -port ${tcpPort} -tls ${useTls}

注意:两个引用${tcpPort}和${useTls},引用名是tcpPort和useTls这两个ARG声明的参数。


docker build --build-arg tcpPort=8080

WORKDIR

WORKDIR命令指明了Docker镜像中的工作目录,工作目录将对WORKDIR指令之后的所有命令生效,举个例子:


WORKDIR    /java/jdk/bin

EXPOSE

EXPOSE命令将对外开放Docker容器中的网络端口,比如,如果Docker容器运行一个web服务器,那么,该web服务器可能需要打开端口80,以便客户端链接到它。举个例子:


EXPOSE   8080

我们还可以指明打开端口的通信协议,比如:UDP和TCP。下面是设置允许通信协议的示例:


EXPOSE   8080/tcp 9999/udp

如果没有指定协议,将默认认定为TCP协议。


VOLUME

VOLUME命令会在Docker镜像中创建一个目录,这个目录可以挂载到Docker主机上。换句话说,可以在Docker镜像中创建目录,比如/data,这个目录可以在稍后挂载到Docker主机的/container-data/container1目录上。挂载成功后,容器会启动。下面是一个使用VOLUME命令在Dockerfile中定义装载目录的示例:


VOLUME   /data

ENTRYPOINT

ENTRYPOINT命令为从该Docker镜像启动Docker容器提供入口点,入口点是Docker容器启动时执行的应用程序或命令。这样,ENTRYPOINT和CMD工作方式类似,不同之处在于,使用ENTRYPOINT时,当ENTRYPOINT执行的应用程序完成时,Docker容器将关闭。因此,ENTRYPOINT使Docker镜像本身成为一个可执行命令,可以启动,完成后关闭。以下是ENTRYPOINT示例:


ENTRYPOINT java -cp /apps/myapp/myapp.jar com.jenkov.myapp.Main

这个示例将在容器启动时执行Java应用程序的主类com.jenkov.myapp.Main,当应用程序关闭时,Docker容器也会关闭。


HEALTHCHECK

HEALTHCHECK命令可以定期执行健康检查,以监视Docker容器中运行的应用程序的运行状况。如果命令返回0,Docker将认为应用程序和容器正常,如果命令返回1,Docker会认为应用程序和容器不正常。示例如下:


HEALTHCHECK java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck

这个示例中使用了java应用程序的com.jenkov.myapp.HealthCheck作为健康检查的命令,我们可以使用任何有意义的健康检查命令。


健康检查间隔时间

默认情况下,Docker每30秒执行一次HEALTHCHECK命令。如果想修改时间间隔,我们可以自定义时间,通过--interval参数,可以指定健康检查的检查间隔时间。下面是一个将HEALTHCHECK间隔设置为60秒的示例:


HEALTHCHECK --interval=60s java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck

健康检查开始时间

默认情况下,Docker会立即检查Docker容器的监控状况。但是,有些应用程序可能需要一段时间启动,因此,只有经过某段时间后再进行健康检查才有意义。我们可以使用--start-period参数设置健康检查开始时间。下面是一个将健康检查设置为5分钟的示例,在Docker开始健康检查之前,为容器和应用程序提供300秒(5分钟)的启动时间:


HEALTHCHECK --start-period=300s java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck

健康检查超时时间

健康检查很有可能超时,如果HEALTCHECK命令需要超过给定时间限制才完成,Docker将认为健康检查超时。可以使用--timeout参数设置超时时间,如下是设置超时时间为5秒的示例:


HEALTHCHECK --timeout=5s java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck

注意,如果健康检查超时,Docker也会认为容器不健康。


健康检查重复次数

如果HEALTHCHECK命令执行失败,有可能是结果返回1,或者执行超时,Docker会在认定容器不健康前,重试3次HEALTHCHECK命令,用于检查Docker容器是否返回健康状态。可以通过--retries设置重试次数。下面是将重试次数设置为5的示例:


HEALTHCHECK --retries=5 java -cp /apps/myapp/healthcheck.jar com.jenkov.myapp.HealthCheck https://localhost/healthcheck

推荐阅读

Docker 教程(一):Docker 是什么

Docker 教程(二):Dockerfile

Docker 教程(三):Docker 命令


目录
相关文章
|
1月前
|
关系型数据库 MySQL Java
Docker Compose详细教程(从入门到放弃)
Docker Compose详细教程(从入门到放弃)
181 0
|
1月前
|
Oracle 关系型数据库 数据库
|
3月前
|
关系型数据库 MySQL 数据库
百度搜索:蓝易云【【Docker】Docker部署Mysql并设置数据持久化教程】
通过以上步骤,您已经成功地在Docker中部署了MySQL,并设置了数据持久化,确保数据在容器重新启动或迁移时得以保留。
50 0
|
3月前
|
Cloud Native NoSQL Redis
云原生 Docker Dockerfile 构建应用
【1月更文挑战第9天】云原生 Docker Dockerfile 构建应用
|
3月前
|
Cloud Native Docker 容器
云原生 Docker Dockerfile 构建配置
【1月更文挑战第9天】云原生 Docker Dockerfile 构建配置
|
3月前
|
分布式计算 Java Linux
【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(Dockerfile使用手册)
Docker 是一套构建在 Linux 内核之上的高级工具,旨在帮助开发人员和运维人员更轻松地交付应用程序和依赖关系,实现跨系统和跨主机的部署。使用安全且轻量级的容器环境来实现这一目标。容器可以手动创建,也可以通过编写 Dockerfile 自动创建。开发人员和运维人员可以将应用程序及其依赖打包到容器中,实现应用程序的可移植性和环境一致性。
119 5
【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(Dockerfile使用手册)
|
3月前
|
大数据 数据管理 Docker
【Datahub系列教程】Datahub入门必学——DatahubCLI之Docker命令详解
【Datahub系列教程】Datahub入门必学——DatahubCLI之Docker命令详解
238 0
|
3月前
|
Java 持续交付 Docker
Docker 项目如何使用 Dockerfile 构建镜像?
Docker 简介:讲述 Docker 的起源、它是如何革新现代软件开发的,以及它为开发者和运维团队带来的好处。重点强调 Docker 的轻量级特性和它在提高应用部署、扩展和隔离方面的优势。
|
6天前
|
Ubuntu Docker 索引
ubuntu 20.04 安装docker教程和安装中遇到的问题解决方案(超详细 附加图文教程)
ubuntu 20.04 安装docker教程和安装中遇到的问题解决方案(超详细 附加图文教程)
28 0
|
29天前
|
jenkins Java 持续交付
Docker搭建持续集成平台Jenkins最简教程
Jenkins 是一个广泛使用的开源持续集成工具,它能够自动化构建、测试和部署软件项目。在本文中,我们将使用 Docker 搭建一个基于 Jenkins 的持续集成平台。
114 2