【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(Dockerfile使用手册)

时间:2024-01-26 13:45:48

Dockerfile

Docker 是一套构建在 Linux 内核之上的高级工具,旨在帮助开发人员和运维人员更轻松地交付应用程序和依赖关系,实现跨系统和跨主机的部署。使用安全且轻量级的容器环境来实现这一目标。容器可以手动创建,也可以通过编写 Dockerfile 自动创建。开发人员和运维人员可以将应用程序及其依赖打包到容器中,实现应用程序的可移植性和环境一致性。

Dockerfile 是一系列命令和参数的脚本,应用于基础镜像,最终创建新镜像。它简化了整个流程,极大简化了部署工作。从 FROM 命令开始,Dockerfile 包含各种方法、命令和参数,最终生成可用于容器创建的新镜像。

Dockerfile的语法

  • Dockerfile 指令不区分大小写,但强烈建议使用大写来表示指令名称。
  • 每行只能包含一条指令,不要把多个指令写在同一行上,否则这些指令将不会被执行。可以在指令之前使用"#"来添加注释或取消不需要的指令。
  • Dockerfile 指令可分为构建指令和设置指令两大类。构建指令用于构建镜像,设置指令用于配置和设置镜像内部的环境。

Dockerfile 语法示例

Dockerfile语法由两部分构成,注释和命令+参数

Dockerfile由一行行命令语句组成,并且支持用“#”开头作为注释,一般的,Dockerfile分为四部分:基础镜像信息,维护者信息,镜像操作指令和容器启动时执行的指令。

注释的行块
command argument argument ..
一个简单的例子:Print "Hello docker!"
RUN echo "Hello docker!"

Dockerfile命令介绍

Dockerfile有十几条命令可用于构建镜像,接下来我们把Dockerfile里面常用的指令介绍一下。

【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(Dockerfile使用手册)_Dockerfile


FROM(指定一个基础镜像)

通常情况下,一个有效的 Dockerfile 的第一条指令应该是 FROM,用于指定基础镜像,image 指定的是任何合理存在的 Docker 镜像, 这句是放在最最开头的地方,也是Dockerfile的核心!

第一条指令必须为FROM指令,并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)。

格式

FROM <image name> 或者指定镜像版本 FROM <image name>:<tag>

如果没有指定tag ,latest 将会被指定为要使用的基础镜像版本,后续的指令将基于这个基础镜像构建你的应用程序或服务,请将 your_base_image:latest 替换为您实际使用的基础镜像的标识符和版本号。这样你就能够基于指定的基础镜像构建你的应用程序或服务。

它会在本地先找找有没有这个镜像,如果没有,它会去docker官方的仓库去找优先相关的或最接近的镜像下载到本地。


MAINTAINER(指定维护者的信息)

MAINTAINER构建指令,告诉别人这个镜像是谁创建的。

格式

MAINTAINER <yourname> 作者名称将被录入到镜像里。


RUN

RUN命令是Dockerfile执行命令的核心部分。它接受命令作为参数并用于创建镜像。将在当前image中执行任意合法命令并提交执行结果,命令执行提交后,就会自动执行Dockerfile中的下一个指令。

格式

每条指令将在当前镜像基础上执行,并提交为新的镜像。(可以用“\”换行)。

RUN <command> 或 RUN ["", "", ""]
RUN <linuxcommand>  <anything linux shell>

RUN指令缓存不会在下个命令执行时自动失效。比如 RUN apt-get dist-upgrade -y 的缓存就可能被用于下一个指令. --no-cache 标志可以被用于强制取消缓存使用。

不像CMD命令,RUN命令用于创建镜像(在之前commit的层之上形成新的层)。


ENV(构建指令,用于设置image的环境变量)

ENV命令用于docker容器设置环境变量。这些变量以”key=value”的形式存在,并可以在容器内被脚本或者程序调用。这个机制给在容器中运行应用带来了极大的便利。

格式

指定环境变量,会被RUN指令使用,并在容器运行时保存。

ENV <key><value>
案例

比如你的镜像要执行的程序需要使用到java的包,那么你可以使用这个方法,

ENV JAVA_HOME /server/lib/java-sdk

ENV设置的环境变量,可以使用 docker inspect命令来查看。同时还可以使用docker run --env =来修改环境变量。


USER(设置指令,设置container的用户)

USER 用来切换运行属主身份的。Docker 默认是使用 root,但若不需要,建议切换使用者身分,毕竟 root 权限太大了,使用上有安全的风险。

格式

指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。

USER <system username>
USER 751

WORKDIR

WORKDIR 用来切换工作目录的,用于设置CMD指明的命令的运行目录。为后续的 RUN 、 CMD 、 ENTRYPOINT 指令配置工作目录。(可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径, 则会基于之前命令指定的路径)

Docker 默认的工作目录是/,只有 RUN 能执行 cd 命令切换目录,而且还只作用在当下下的 RUN,也就是说每一个 RUN 都是独立进行的。如果想让其他指令在指定的目录下执行,就得靠 WORKDIR。WORKDIR 动作的目录改变是持久的,不用每个指令前都使用一次 WORKDIR。

格式
WORKDIR /path/to/workdir
WORKDIR ~/

Docker 默认的工作目录是/,只有 RUN 能执行 cd 命令切换目录,而且还只作用在当下下的 RUN,也就是说每一个 RUN 都是独立进行的。如果想让其他指令在指定的目录下执行,就得靠 WORKDIR。WORKDIR 动作的目录改变是持久的,不用每个指令前都使用一次 WORKDIR。


COPY

复制本地主机的 (当使用本地目录为源目录时,推荐使用 COPY)

格式
COPY <src>  <dest>

COPY 将文件从路径 。

<src> 必须是想对于源文件夹的一个文件或目录,也可以是一个远程的url,<dest> 是目标容器中的绝对路径。 所有的新文件和文件夹都会创建UID 和 GID 。事实上如果 <src> 是一个远程文件URL,那么目标文件的权限将会是600。


ADD(构建指令,将宿主机的文件复制到镜像里)

ADD命令有两个参数,源和目标。它的基本作用是从源系统的文件系统上复制文件到目标容器的文件系统。如果源是一个URL,那该URL的内容将被下载并复制到容器中。

格式

复制指定的到容器的中,可以是Dockerfile所在的目录的一个相对路径;可以是URL,也可以是tar.gz(自动解压)

ADD  <src>  <dest>
# Usage: ADD [source directory or URL] [destination directory]
ADD /my_app_folder /my_app_folder
  • <src> 必须是想对于源文件夹的一个文件或目录,也可以是一个远程的url。
  • <dest> 是目标容器中的绝对路径。

所有的新文件和文件夹都会创建UID 和 GID。事实上如果 <src> 是一个远程文件URL,那么目标文件的权限将会是600。


VOLUME

VOLUME命令用于让你的容器访问宿主机上的目录,创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

格式
VOLUME ["/my_files"]

EXPOSE(设置指令,设置container要映射到宿主机的端口)

EXPOSE 指令指定在docker允许时指定的端口进行转发,该参数是对外开放container的端口,使外部通过宿主机的IP以及容器所映射的端口来访问容器。但是必须保证所映射的端口没有被使用或占用。开放端口必须结合使用才能达到目的。

格式
EXPOSE <port>  [ <port> ...]
EXPOSE 8080

告诉Docker服务端暴露端口,在容器启动时需要通过 -p 做端口映射。Dockerfile里面我们设置80端口

EXPOSE 80

在运行的时候,我们要进行映射。

docker run -it -p 80:80 centos7/lynk	 //开放80端口映射到容器80端口

或指定其他端口进行映射

docker run -it -p 8080:80 centos7/lynk  //开放8080端口映射到容器80端口

CMD(设置指令,用户设置container启动时候执行的操作)

和RUN命令相似,CMD可以用于执行特定的命令。和RUN不同的是,这些命令不是在镜像构建的过程中执行的,而是在用镜像构建容器后被调用。

指定启动容器时执行的命令,每个Dockerfile只能有一条CMD指令,如果指定了多条指令,则最后一条执行。(会被启动时指定的命令覆盖)

格式

CMD ["","",""]

Dockerfile.中只能有一个CMD指令。 如果你指定了多个,那么最后个CMD指令是生效的。 CMD指令的主要作用是提供默认的执行容器。这些默认值可以包括可执行文件,也可以省略可执行文件。 当你使用shell或exec格式时, CMD 会自动执行这个命令。

Usage 1: CMD application "argument", "argument", ..
CMD "echo" "Hello docker!"

ONBUILD(设置指令,在子镜像中执行)

ONBUILD 指定的命令在构建的时候并不执行,而是在他的子镜像中执行。其实就是让指令延迟執行,延迟到下一个使用 FROM 的 Dockerfile 在建立 image 时执行,只限延迟一次。

格式
ONBUILD <下一个要运行的Dockerfile关键字>

ONBUILD 的使用情景是在建立镜像时取得最新的源码 (搭配 RUN) 与限定系统框架。配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令


ARG

ARG 是自 Docker 1.9 版本引入的指令。它用于定义在构建镜像过程中使用的变量,在镜像构建完成后,这些变量就会失效。换句话说,ARG 定义的变量只在构建镜像时有效,不会在运行镜像时存在。

在 Dockerfile 中,可以使用 ARG 指令来定义一个或多个变量,然后在后续的指令中引用这些变量。这使得您可以在构建过程中传递参数或配置选项,方便地定制化镜像构建过程。

格式
ARG variable_name[=default_value]

在构建镜像时,可以通过在 docker build 命令中使用 --build-arg 选项来传递具体的值给 ARG 变量。

其中,variable_name 是变量的名称,可以使用该变量在后续的指令中引用。default_value 是可选的默认值,表示如果在构建过程中没有传递具体的值,将使用默认值。

docker build --build-arg app_version=2.0 -t my_image .
# 定义一个名为 "app_version" 的变量,设置默认值为 "1.0"
ARG app_version=1.0
# 在后续的指令中使用该变量
RUN echo "Application version: $app_version"

这将使用传递的值覆盖默认值,使得在构建过程中可以动态地定制化变量。


LABEL

LABEL 指令用于给Docker镜像添加元数据标签,用于描述镜像相关的信息。这些标签可以包括作者、版本、描述、维护者、构建日期等。

LABEL 指令通常位于Dockerfile的顶部或镜像构建过程的初始化阶段,用于提供关于镜像的信息,帮助用户更好地了解和管理镜像。这些标签可以在镜像仓库中查看,也可以通过docker inspect命令查看。

以下是一个 LABEL 指令的示例:

# 设置镜像的元数据标签
LABEL maintainer="John Doe <john.doe@example.com>"
LABEL version="1.0"
LABEL description="This is a sample Docker image"

通过使用 LABEL 指令,您可以为镜像指定元数据,提供关键的信息,使镜像更易于管理和使用。这对于团队协作、镜像版本控制和文档化都非常有用。


ENTRYPOINT

配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。(每个 Dockerfile 中只能有一个 ENTRYPOINT ,当指定多个时,只有最后一个起效)

格式
ENTRYPOINT ["","",""]

是指定 Docker image 运行成 instance (也就是 Docker container) 时,要执行的命令或者文件。

Dockerfile文件案例

个比较简单的 Dockerfile,以下是对每个指令的分析:

FROM docker.io/centos
MAINTAINER The CentOS Test Images - test
RUN mkdir -p /usr/app
RUN ls
RUN pwd
COPY /jdk /usr/app/jdk/
ADD tomcat/ /usr/app/tomcat/
ADD hadoop/ /usr/app/hadoop/
ENV JAVA_HOME /usr/app/jdk
ENV PATH $JAVA_HOME/bin:$PATH
#ADD /soft/jdk /
#ADD /soft/tomcat /
#ADD /soft/hadoop /
# Volumes for systemd
# VOLUME ["/run", "/tmp"]
# Environment for systemd
# ENV container=docker
# For systemd usage this changes to /usr/sbin/init
# Keeping it as /bin/bash for compatibility with previous
#CMD ["/bin/bash"]
  1. FROM docker.io/centos
  • 基础镜像选择为 docker.io/centos,即从Docker Hub上的CentOS镜像开始构建。
  1. MAINTAINER The CentOS Test Images - test
  • 设置镜像的维护者信息为 "The CentOS Test Images - test"。请注意,MAINTAINER 指令已经被标记为废弃,推荐使用 LABEL 指令代替。
  1. RUN mkdir -p /usr/app
  • 在镜像中创建一个目录 /usr/app
  1. RUN ls
  • 在构建过程中执行 ls 命令,用于列出当前目录的内容。这可能是为了在构建过程中验证镜像的构建环境。
  1. RUN pwd
  • 在构建过程中执行 pwd 命令,用于打印当前工作目录的路径。同样,这可能是为了在构建过程中验证镜像的构建环境。
  1. COPY /jdk /usr/app/jdk/
  • 将主机上项目根目录下的 jdk 文件夹复制到镜像中的 /usr/app/jdk/ 目录。
  1. ADD tomcat/ /usr/app/tomcat/
  • 将主机上项目根目录下的 tomcat 文件夹复制到镜像中的 /usr/app/tomcat/ 目录。与 COPY 指令类似,但 ADD 还支持从URL中复制文件。
  1. ADD hadoop/ /usr/app/hadoop/
  • 将主机上项目根目录下的 hadoop 文件夹复制到镜像中的 /usr/app/hadoop/ 目录。
  1. ENV JAVA_HOME /usr/app/jdk
  • 设置环境变量 JAVA_HOME/usr/app/jdk,指定了Java的安装路径。
  1. ENV PATH $JAVA_HOME/bin:$PATH
  • $JAVA_HOME/bin 加入到 $PATH 环境变量中,使得可以直接使用 java 命令。
  1. 注释这个Dockerfile的作用是构建一个基于CentOS的镜像,并在镜像中安装了JDK、Tomcat和Hadoop。

总结介绍

Dockerfile是一种类似于Linux下shell脚本的文本文件,用于定义Docker镜像。通过编写Dockerfile并执行一条命令,您可以简单地构建和配置镜像。使用Dockerfile,您可以自定义服务器结构和配置,轻松构建完整的环境。Dockerfile的设计目标是使镜像配置变得简单和便捷,提供可重复和可移植的镜像构建过程。

它具有可靠性和简单性,使应用程序和服务的分发变得更加简单。使用Dockerfile可以轻松管理和配置镜像,让您专注于其他重要任务。请注意,Dockerfile只能被Docker解释器识别和使用,不能被非Docker环境所使用。