美文网首页
使用Dockerfile创建镜像

使用Dockerfile创建镜像

作者: mini鱼 | 来源:发表于2023-12-24 13:42 被阅读0次

    1、 Dockerfile基本结构

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

    # This Dockerfile uses the ubuntu image
    # VERSION 2 - EDITION 1
    # Author: docker_user
    # Command format: Instruction [arguments / command] ..
    # Base image to use, this must be set as the first line
    FROM ubuntu
    # Maintainer: docker_user <docker_user at email.com> (@docker_user)
    MAINTAINER docker_user docker_user@email.com
    # Commands to update the image
    RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/
    sources.list
    RUN apt-get update && apt-get install -y nginx
    RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
    # Commands when creating a new container
    CMD /usr/sbin/nginx
    

    其中,一开始必须指明所基于的镜像名称,接下来一般是说明维护者信息。后面则是镜像操作指令,例如RUN指令,RUN指令将对镜像执行跟随的命令。每运行一条RUN指令,镜像就添加新的一层,并提交。最后是CMD指令,用来指定运行容器时的操作命令。

    Dockerfile 官方参考

    2、 指令说明

    Dockerfile 指令 说明
    FROM 指定基础镜像,用于后续的指令构建。
    MAINTAINER 指定Dockerfile的作者/维护者。(已弃用,推荐使用LABEL指令)
    LABEL 添加镜像的元数据,使用键值对的形式。
    RUN 在构建过程中在镜像中执行命令。
    CMD 指定容器创建时的默认命令。(可以被覆盖)
    ENTRYPOINT 设置容器创建时的主要命令。(不可被覆盖)
    EXPOSE 声明容器运行时监听的特定网络端口。
    ENV 在容器内部设置环境变量。
    ADD 将文件、目录或远程URL复制到镜像中,tar文件会自动解压。
    COPY 将文件或目录复制到镜像中。
    VOLUME 为容器创建挂载点或声明卷。
    WORKDIR 设置后续指令的工作目录。
    USER 指定后续指令的用户上下文。
    ARG 定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。
    ONBUILD 当该镜像被用作另一个构建过程的基础时,添加触发器。
    STOPSIGNAL 设置发送给容器以退出的系统调用信号。
    HEALTHCHECK 定义周期性检查容器健康状态的命令。
    SHELL 覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。
    • FROM
      指定所创建镜像的基础镜像,如果本地不存在,则默认会去Docker Hub下载指定镜像。
      任何Dockerfile中的第一条非注释指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像,可以使用多个FROM指令(每个镜像一次)。
      空镜像: scratch

    • MAINTAINER
      指定维护者信息,格式为MAINTAINER <name>,已弃用,推荐使用LABEL指令

    LABEL org.opencontainers.image.authors="SvenDowideit@home.org.au"

    • RUN
      运行指定的命令。
      格式为RUN <command>或RUN ["executable","param1","param2"]。注意,后一个指令会被解析为Json数组,因此必须用双引号。
      前者默认将在shell终端中运行命令,即/ bin/sh -c;后者则使用exec执行,不会启动shell环境。
      指定使用其他终端类型可以通过第二种方式实现,例如RUN ["/bin/ bash","-c","echo hello"]。
      每条RUN指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用\来换行。例如:
    RUN apt-get update \
    && apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev \
    && rm -rf /var/cache/apt
    
    • CMD
      CMD指令用来指定启动容器时默认执行的命令。它支持三种格式:
      · CMD ["executable","param1","param2"]使用 exec执行,是推荐使用的方式;
      · CMD command param1 param2在/bin/sh中执行,提供给需要交互的应用;
      · CMD ["param1","param2"]提供给 ENTRYPOINT的默认参数。
      每个Dockerfile只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行。
      如果用户启动容器时手动指定了运行的命令(作为run的参数),则会覆盖掉CMD指定的命令。
    • LABEL
      LABEL指令用来指定生成镜像的元数据标签信息。
    LABEL version="1.0"
    LABEL description="This text illustrates \ that label-values can span multiple lines."
    
    • EXPOSE
      声明镜像内服务所监听的端口。

    EXPOSE 22 80 8443

    注意,该指令只是起到声明作用,并不会自动完成端口映射。
    在启动容器时需要使用-P,Docker主机会自动分配一个宿主机的临时端口转发到指定的端口;使用-p,则可以具体指定哪个宿主机的本地端口会映射过来。

    • ENV
      指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在
    ENV PG_MAJOR 9.3
    ENV PG_VERSION 9.3.4
    RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/
    postgress && …
    ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
    

    指令指定的环境变量在运行时可以被覆盖掉,如docker run --env <key>=<value> built_image。

    • ADD
      该命令将复制指定的<src>路径下的内容到容器中的<dest>路径下。
      格式为ADD<src><dest>。
      其中<src>可以是Dockerfile所在目录的一个相对路径(文件或目录),也可以是一个URL,还可以是一个tar文件(如果为tar文件,会自动解压到<dest>路径下)。<dest>可以是镜像内的绝对路径,或者相对于工作目录(WORKDIR)的相对路径。

    ADD *.c /code/

    • COPY
      格式为COPY<src><dest>。
      复制本地主机的<src>(为Dockerfile所在目录的相对路径、文件或目录)下的内容到镜像中的<dest>下。目标路径不存在时,会自动创建。
      路径同样支持正则格式。
      当使用本地目录为源目录时,推荐使用COPY。

    • 指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。
      支持两种格式:

    ENTRYPOINT ["executable", "param1", "param2"](exec调用执行);
    ENTRYPOINT command param1 param2(shell中执行)。
    

    此时,CMD指令指定值将作为根命令的参数。
    每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个有效。
    在运行时,可以被--entrypoint参数覆盖掉,如docker run --entrypoint。

    • VOLUME
      创建一个数据卷挂载点,格式为VOLUME["/data"]。
      可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保存的数据等。

    • USER
      指定运行容器时的用户名或UID,后续的RUN等指令也会使用指定的用户身份。
      格式为USER daemon。
      当服务不需要管理员权限时,可以通过该命令指定运行用户,并且可以在之前创建所需要的用户。例如:

    RUN groupadd -r postgres && useradd -r -g postgres postgres

    • WORKDIR
      为后续的RUN、CMD和ENTRYPOINT指令配置工作目录。
      格式为WORKDIR/path/to/workdir。
      可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:
    WORKDIR /a
    WORKDIR b
    WORKDIR c
    RUN pwd
    

    则最终路径为/ a/b/c。

    • ARG
      指定一些镜像内使用的参数(例如版本号信息等),这些参数在执行docker build命令时才以--build-arg <varname>=<value>格式传入。
      格式为ARG<name>[=<default value>]。
      则可以用docker build --build-arg <name>=<value>.来指定参数值。
      它与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

    构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。

    • ONBUILD
      配置当所创建的镜像作为其他镜像的基础镜像时,所执行的创建操作指令。
      格式为ONBUILD[INSTRUCTION]。
      例如,Dockerfile使用如下的内容创建了镜像 image-A:
    [...]
    ONBUILD ADD . /app/src
    ONBUILD RUN /usr/local/bin/python-build --dir /app/src
    [...]
    

    如果基于image-A创建新的镜像时,新的Dockerfile中使用FROM image-A指定基础镜像,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令:

    FROM image-A
    #Automatically run the following
    ADD . /app/src
    RUN /usr/local/bin/python-build --dir /app/src
    

    使用ONBUILD指令的镜像,推荐在标签中注明,例如ruby:1.9-onbuild。

    • STOPSIGNAL
      指定所创建镜像启动的容器接收退出的信号值。例如:

    STOPSIGNAL signal

    • HEALTHCHECK
      配置所启动容器如何进行健康检查(如何判断健康与否),自Docker1.12开始支持。
      格式有两种:

    HEALTHCHECK [OPTIONS] CMD command:根据所执行命令返回值是否为0来判断;

    ·HEALTHCHECK[OPTIONS]CMD command:根据所执行命令返回值是否为0来判断;
    ·HEALTHCHECK NONE:禁止基础镜像中的健康检查。
    OPTION支持:
    ·--interval=DURATION(默认为:30s):过多久检查一次;
    ·--timeout=DURATION(默认为:30s):每次检查等待结果的超时;
    ·--retries=N(默认为:3):如果失败了,重试几次才最终确定失败。

    • SHELL
      指定其他命令使用shell时的默认shell类型。
      默认值为["/bin/sh","-c"]。

    3、创建镜像

    编写完成Dockerfile之后,可以通过docker build命令来创建镜像。

    $ docker build -t test-image:1.1 /tmp/docker_builder/

    4、使用.dockerignore文件

    可以通过.dockerignore文件(每一行添加一条匹配模式)来让 Docker忽略匹配模式路径下的目录和文件。例如:

    # comment
    */temp*
    */*/temp*
    tmp?
    ~*
    

    5、最佳实践

    所谓最佳实践,实际上是从需求出发,来定制适合自己、高效方便的镜像。
    首先,要尽量吃透每个指令的含义和执行效果,自己多编写一些简单的例子进行测试,弄清楚了再撰写正式的Dockerfile。此外,Docker Hub官方仓库中提供了大量的优秀镜像和对应的Dockefile,可以通过阅读它们来学习如何撰写高效的Dockerfile。
    笔者在应用过程中也总结了一些实践经验。建议读者在生成镜像过程中,尝试从如下角度进行思考,完善所生成的镜像。

    • 精简镜像用途:尽量让每个镜像的用途都比较集中、单一,避免构造大而复杂、多功能的镜像;
    • 选用合适的基础镜像:过大的基础镜像会造成生成臃肿的镜像,一般推荐较为小巧的debian镜像;
    • 提供足够清晰的命令注释和维护者信息:Dockerfile也是一种代码,需要考虑方便后续扩展和他人使用;
    • 正确使用版本号:使用明确的版本号信息,如1.0,2.0,而非latest,将避免内容不一致可能引发的惨案;
    • 减少镜像层数:如果希望所生成镜像的层数尽量少,则要尽量合并指令,例如多个RUN指令可以合并为一条;
    • 及时删除临时文件和缓存文件:特别是在执行apt-get指令后,/var/cache/apt下面会缓存一些安装包;
    • ·提高生成㏿度:如合理使用缓存,减少内容目录下的文件,或使用.dockerignore文件指定等;
    • 调整合理的指令顺序:在开启缓存的情况下,内容不变的指令尽量放在前面,这样可以尽量复用;
    • 减少外部源的干扰:如果确实要从外部引入数据,需要指定持久的地址,并带有版本信息,让他人可以重复而不出错。

    相关文章

      网友评论

          本文标题:使用Dockerfile创建镜像

          本文链接:https://www.haomeiwen.com/subject/laxhndtx.html