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 命令


目录
相关文章
|
2月前
|
机器人 网络安全 数据安全/隐私保护
autMan奥特曼机器人-对接Docker版本NTQQ详细教程
本文介绍了如何在服务器上搭建NTQQ机器人,通过官方NTQQ对接各框架,实现QQ登录的稳定运行。文章提到了需要准备一台服务器和相应的软件,并详细描述了通过SSH链接服务器、创建文件夹和配置文件、编辑配置文件地址端口、运行容器等步骤。同时,文章还介绍了VNC连接的使用和配置,以及使用watchtower进行NTQQ的更新。文章总结起来就是在服务器上搭建NTQQ机器人,实现QQ登录的稳定性和自动登录功能,同时提供了更新和维护的方法。
95 3
autMan奥特曼机器人-对接Docker版本NTQQ详细教程
|
21天前
|
缓存 Linux Docker
【最新版正确姿势】Docker安装教程(简单几步即可完成)
之前的老版本Docker安装教程已经发生了变化,本文分享了Docker最新版安装教程,其他操作系统版本也可以参考官 方的其他安装版本文档。
668 2
【最新版正确姿势】Docker安装教程(简单几步即可完成)
|
1月前
|
Java 应用服务中间件 Linux
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
本文主要讲解了Docker的安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库以及Docker容器虚拟化与传统虚拟机比较。
373 11
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
|
12天前
|
数据库 Docker 容器
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。Dockerfile定义了构建镜像所需的所有指令,包括基础镜像选择、软件安装、文件复制等,极大提高了开发和部署的灵活性与一致性。掌握Dockerfile的编写,对于提升软件开发效率和环境管理具有重要意义。
28 9
|
18天前
|
关系型数据库 MySQL Java
【Docker最新版教程】一文带你快速入门Docker常见用法,实现容器编排和自动化部署上线项目
Docker快速入门到项目部署,MySQL部署+Nginx部署+docker自定义镜像+docker网络+DockerCompose项目实战一文搞定!
|
1月前
|
应用服务中间件 PHP nginx
Docker-compose 编排lnmp(dockerfile) 完成Wordpress
通过使用Docker Compose,我们可以轻松编排LNMP环境并部署WordPress。本文详细介绍了各组件的Dockerfile和配置文件编写,并通过docker-compose.yml文件实现了整个环境的自动化部署。这种方法不仅简化了部署过程,还提高了环境的可移植性和一致性。希望本文能帮助你更好地理解和使用Docker Compose来管理和部署复杂的应用程序。
70 3
|
2月前
|
Linux Docker 容器
Centos安装docker(linux安装docker)——超详细小白可操作手把手教程,包好用!!!
本篇博客重在讲解Centos安装docker,经博主多次在不同服务器上测试,极其的稳定,尤其是阿里的服务器,一路复制命令畅通无阻。
1458 4
Centos安装docker(linux安装docker)——超详细小白可操作手把手教程,包好用!!!
|
2月前
|
关系型数据库 MySQL Linux
基于阿里云服务器Linux系统安装Docker完整图文教程(附部署开源项目)
基于阿里云服务器Linux系统安装Docker完整图文教程(附部署开源项目)
334 3
|
2月前
|
Docker 容器
docker中使用Dockerfile自动创建数据卷
【10月更文挑战第12天】
26 5
|
2月前
|
数据可视化 数据挖掘 Docker
Docker Desktop 安装 ClickHouse 超级简单教程
Docker Desktop 安装 ClickHouse 超级简单教程
59 1