Dockerfile 文件详解

Docker · 2024-11-26

介绍

  • Dockerfile 是一个用来构建镜像的文本文件,文本内容包含一条条构建镜像所需的指令和说明。
  • #Dockerfile 中的注释
  • Dockerfile 基本结构:基础镜像、镜像元信息、镜像操作指令、容器启动时执行命令。
  • Docker 自上而下顺序执行 Dockerfile 的指令,文件命名 Dockerfile

Dockerfile 指令

FROM

  • 指定基础镜像,必须是第一条指令。

用法:

FROM image
FROM image:<tag>
# tag 是可选项,默认值 latest

RUN

  • 运行指定的命令

用法:

RUN <command>
RUN ["executable", "param1", "param2"]
# 第一种后面直接跟shell 命令
# Linux 默认:/bin/sh -c
# windows 默认:cmd /S /C
# 第二种类似于函数调用
# executable 相当于 可执行文件,param* 是两个参数
# 举例:
RUN /bin/bash -c source $HOME/.bashrc; echo $HOME
RUN ["/bin/bash", "-c", "echo hello"]
# 注意:多行命令不要写多个RUN,原因是Dockerfile 中每一个指令都会建立一层
有可能造成镜像的臃肿、多层,不仅增加构建部署的时间,还容易出错。

CMD

  • 容器启动运行命令

用法:

CMD ["executable", "param1", "param2"]
CMD ["param1", "param2"]
CMD command param1 param2
# 举例:
CMD ["sh", "-c", "echo $HOME"]
CMD ["echo", "$HOME"]
# 注意:参数一定要使用双引号。
# 原因:参数传递后,docker 解析的是一个 JSON array
  • RUN 是构建容器运行的命令以及提交运行结果
  • CMD 是容器启动时执行的命令,在构建时并不运行。

LABEL

  • 镜像指定标签

用法:

LABEL <key>=<value> <key>=<value>
# 注:一个Dockerfile 可以有多个LABEL, 但是不建议写多个,如果太长需要换行可以使用\
# 例:
LABEL key1=value1 \
key2=value2 \
key3=value3

MAINTAINER

  • 指定作者

用法:

MAINTAINER <name>

EXPOSE

  • 为暴露容器运行时的监听端口给外部,但是 EXPOSE 并不会使容器访问主机的端口,如果想使容器与主机端口有映射关系,必须在容器启动的时候加上 -P 参数

用法:

EXPOSE 22

ENV

  • 设置环境变量

用法:

ENV <key> <value>
ENV <key>=<value>
# 语法区别:第一种是一次设置一个,第二种可以一次设置多个

ENV VAR1=value1 VAR2="value2" VAR3="hello world" \
    VAR4=hello\ world 

ENV VAR5="He said: \"It's good!\""

ADD

  • 复制命令,将文件复制到镜像中。
  • 相当于 scp。只是 scp 需要将用户名和密码的权限验证,而 ADD 不用。

用法:

ADD <src> <dest>
ADD ["src", "dest"]
# <dest> 路径可以是容器内的绝对路径,也可以是工作目录的相对路径
# <src> 可以是本地文件,也可以是一个 url
# 例:
ADD test path_dir/
ADD http://www.baidu.com/ /
# 尽量不要把<src> 写成一个文件夹,如果<src> 是一个文件夹,复制整个目录的内容,包括文件系统元文件。

COPY

  • 复制命令

用法:

COPY <src> <dest>
COPY ["<src>", "<dest>"]
# 与 ADD 区别,COPY 的 <src> 只能是本地文件,其他用法一致

ENTRYPOINT

  • 功能是启动时的默认命令

用法:

ENTRYPOINT ["executable", "param1", "param2"] 
ENTRYPOINT command param1 param2

# 如果从上到下看到这里的话,那么你应该对这两种语法很熟悉啦。
# 第二种就是写shell
# 第一种就是可执行文件加参数
# 与CMD比较说明(这俩命令太像了,而且还可以配合使用):
# 1. 相同点:
-   只能写一条,如果写了多条,那么只有最后一条生效
-   容器启动时才运行,运行时机相同
# 2. 不同点:
-   ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖
-   如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数
# 如下:
FROM ubuntu
ENTRYPOINT ["top", "-b"]  
CMD ["-c"]

# 如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD是一个完整的指令,那么它们两个会互相覆盖,谁在最后谁生效
# 如下:
FROM ubuntu
ENTRYPOINT ["top", "-b"]  
CMD ls -al
# 那么将执行ls -al ,top -b不会执行。

VOLUME

  • 可实现挂载功能,可以将内地文件夹或者其他容器中得文件夹挂在到这个容器中

用法:

VOLUME ["/data"]
# 说明:
# ["/data"]可以是一个JsonArray ,也可以是多个值。所以如下几种写法都是正确的
VOLUME ["/var/log/"]
VOLUME /var/log
VOLUME /var/log /var/db
# 一般的使用场景为需要持久化存储数据时
# 容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。
# 所以当数据需要持久化时用这个命令。

USER

  • 设置启动容器的用户,可以是用户名或UID,所以,只有下面的两种写法是正确的

用法:

USER daemo
USER UID
# 注意:如果设置了容器以daemon用户去运行,那么RUN, CMD 和 ENTRYPOINT 都会以这个用户去运行

WORKDIR

用法:

WORKDIR /path/to/workdir
# 设置工作目录,对RUN,CMD,ENTRYPOINT,COPY,ADD生效。如果不存在则会创建,也可以设置多次。
# 如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
# pwd执行的结果是/a/b/c
# WORKDIR也可以解析环境变量
# 如:
ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
# pwd的执行结果是/path/$DIRNAME

ARG

用法:

ARG <name>[=<default value>]
# 设置变量命令,ARG命令定义了一个变量,在docker build创建镜像的时候,使用 --build-arg <varname>=<value>来指定参数
# 如果用户在build镜像时指定了一个参数没有定义在Dockerfile种,那么将有一个Warning
# 提示如下:
[Warning] One or more build-args [foo] were not consumed.**
# 我们可以定义一个或多个参数,如下:
FROM busybox
ARG user1
ARG buildno
# 也可以给参数一个默认值:
FROM busybox
ARG user1=someuser
ARG buildno=1
# 如果我们给了ARG定义的参数默认值,那么当build镜像时没有指定参数值,将会使用这个默认值

ONBUILD

用法:

ONBUILD [INSTRUCTION]
# 这个命令只对当前镜像的子镜像生效。
# 比如当前镜像为A,在Dockerfile种添加:
ONBUILD RUN ls -al
# 这个 ls -al 命令不会在A镜像构建或启动的时候执行
# 此时有一个镜像B是基于A镜像构建的,那么这个ls -al 命令会在B镜像构建的时候被执行。

STOPSIGNAL

用法:

STOPSIGNAL signal
STOPSIGNAL命令是的作用是当容器推出时给系统发送什么样的指令

HEALTHCHECK

  • 容器健康状况检查命令

用法:

HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK NONE
# 第一个的功能是在容器内部运行一个命令来检查容器的健康状况
# 第二个的功能是在基础镜像中取消健康检查命令
# [OPTIONS]的选项支持以下三中选项:
--interval=DURATION 两次检查默认的时间间隔为30秒
--timeout=DURATION 健康检查命令运行超时时长,默认30秒
--retries=N 当连续失败指定次数后,则容器被认为是不健康的,状态为unhealthy,默认次数是3
# 注意:
# HEALTHCHECK命令只能出现一次,如果出现了多次,只有最后一个生效。
# CMD后边的命令的返回值决定了本次健康检查是否成功,具体的返回值如下:
    0: success - 表示容器是健康的
    1: unhealthy - 表示容器已经不能工作了
    2: reserved - 保留值
# 例子:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
# 健康检查命令是:
curl -f http://localhost/ || exit 1
# 两次检查的间隔时间是5秒
# 命令超时时间为3秒

构建镜像

docker build -t 镜像名:标签名 Dockerfile路径(可以是绝对路径,也可以是相对路径)

示例

# 构建Python 环境镜像,运行python 脚本
FROM python:3.9

# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 设置工作目录
WORKDIR /app

# 复制当前目录的内容到容器中的 /app 目录
COPY . /app

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

# 运行 Python 脚本
CMD ["python", "app.py"]
Theme Jasmine by Kent Liao