Docker 进阶篇01 — Dockerfile

概述

本章,您将学习 Docker 当中一个重要的文本文件 —— Dockerfile

Q:什么是 Dockerfile?有什么用?

Dockerfile:用来构建 Docker 镜像的文本文件,该文件的内容类比 GNU/Linux 当中的 Shell 脚本,其由一条又一条构建镜像所需的指令和参数构成。Dockerfile 文件的内容需要遵循特定的格式和指令集,请参阅 这里

前面使用过 docker commit 这种方式,它可以在原始镜像生成的容器实例的基础之上生成增强版镜像,这种方式对于一些简单操作是没问题的,但是面对复杂的操作就会很麻烦(因为每次都要 commit 提交)。为了提高使用者的使用效率,Docker 当中引入了 Dockerfile ,您可以在文本文件中写入您需要的功能清单(相当于实现多次 commit 提交),最后构建成适合生产环境的增强版镜像。

file

构建镜像并生成容器实例的三个步骤:

  • 编写 Dockerfile 文件
  • 使用 docker build 命令构建镜像
  • 使用 docker run 命令生成容器实例

Dockerfile 基础知识

在正式编写 Dockerfile 之前,您需要了解这些:

  • Dockerfile 当中的指令(Instruction)关键字 必须大写 且每个指令至少书写一个参数(Arguments)
  • 构建镜像时,docker 会按照从上到下的顺序读取 Dockerfile 文件内容且按照顺序依次执行
  • # 开头表示注释行
  • 每条指令都会创建一个只读的镜像层并且进行 commit 提交。多个镜像层最终堆叠成一个完整镜像

Dockerfile 中常见的指令关键字

  • FROM - 该关键字出现在 Dockerifle 的首行,代表构建的镜像是基于哪个原始镜像(基础镜像)。
  • ENV - 构建镜像过程中设置的环境变量。环境变量以键值对的方式出现,例如 ENV MY_NAME="John Doe" 或者 ENV MY_NAME "John Doe"。通常而言,该关键字出现在 FROM 关键字之后。
  • WORKDIR - 容器创建完成后,通过 docker execdocker run进入到容器内部时默认的工作目录。
  • MAINTAINER - 设置生成镜像的 "Author" 字段,该关键字已经被弃用,请使用 LABEL 关键字作为替代
  • RUN - 容器实例构建成镜像时需要执行的命令,RUN 有两种格式:
    • shell 格式 - RUN [OPTIONS] <command> ...
    • exec 格式 - RUN [OPTIONS] [ "<command>", ... ]
  • EXPOSE - 容器实例对外暴露的端口,如果未指定端口协议,则默认为 TCP
  • STOPSIGNA - 容器实例退出时发出的信号,可以具体的信号名称,也可以数字。默认为 15(SIGTERM)
  • USER - 指定运行容器时的用户名或 UID。在该指令之后的 RUN 指令也会使用该用户进行执行。不书写该指令,则默认用户为 root
  • VOLUME - 数据持久化时需要设置容器实例内的映射目录(也称数据卷、挂载点),请注意!不是设置宿主机的映射目录。
  • ADD - 将宿主机目录下的文件复制到容器实例中且自动解压 .tar 归档文件。语法如下(src 必须与 Dockerfile 位于同一个目录下):
    • ADD [OPTIONS] <src> ... <dest>
    • ADD [OPTIONS] ["<src>", ... "<dest>"]
  • COPY - 将宿主机的目录或目录下的文件拷贝到容器实例中,类似于 ADD 指令
  • CMD - 容器实例启动之后要运行的命令。请注意不要将它和 RUN 指令混淆。在一个 Dockerfile 文件中您可以指定多个 CMD 指令,但是仅最后一个生效。在格式上,该指令同样也支持 shell 格式与 exec 格式。该指令会被 docker run 后面的命令覆盖掉
  • ENTRYPOINT - 类似于 CMD 指令,指容器实例启动之后要运行的命令,但是该指令不会被 docker run 后面的命令覆盖掉。
    • 若和 CMD 一起使用,则 ENTRYPOINT 指令所处的位置需要在 CMD 指令之前,此时的 CMD 指令的含义不再是运行命令,而是将 CMD 里面的内容变成了传递给 ENTRYPOINT 的参数。

在 Github 网站,我们可以找到 Tomcat 镜像的 Dockerfile 文件(去掉了注释行):

FROM eclipse-temurin:21-jre-jammy

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME

ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR

ENV TOMCAT_MAJOR 10
ENV TOMCAT_VERSION 10.1.55
ENV TOMCAT_SHA512 f36af12391a277e5c3a802a8e1a2a1e4354cd461b547d2e1a33ac0ab88d707d3fb2591e034a17b7d3a6b965a4c977a97dbf29bb81a3867e85aeec3d8d189e22e

COPY --from=tomcat:10.1.55-jdk21-temurin-jammy $CATALINA_HOME $CATALINA_HOME
RUN set -eux; \
    apt-get update; \
    xargs -rt apt-get install -y --no-install-recommends < "$TOMCAT_NATIVE_LIBDIR/.dependencies.txt"; \
    rm -rf /var/lib/apt/lists/*

RUN set -eux; \
    nativeLines="$(catalina.sh configtest 2>&1)"; \
    nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')"; \
    nativeLines="$(echo "$nativeLines" | sort -u)"; \
    if ! echo "$nativeLines" | grep -E 'INFO: Loaded( APR based)? Apache Tomcat Native library' >&2; then \
        echo >&2 "$nativeLines"; \
        exit 1; \
    fi

EXPOSE 8080

ENTRYPOINT []

CMD ["catalina.sh", "run"]

Dockerfile 编写案例

需求:

  • 基于 Rocky Linux 8.9 镜像
  • 需要有 vim 命令
  • 准备 Nginx 的一些依赖包,源代码编译最新版的 Nginx

基本操作步骤:

  • 第一步:拉取基础镜像—— docker pull rockylinux:8.9.20231119

  • 第二步:在宿主机中准备 .tar.gz 的 nginx 归档压缩包并存放在 /tmp/nginx/ 目录中

  • 第三步:在 /tmp/nginx/ 目录中新增名称为 Dockerfile 的文件,其内容为:

    FROM rockylinux:8.9.20231119
    
    ENV WORK_PATH /usr/local/nginx
    RUN mkdir -p "$WORK_PATH"
    
    WORKDIR $WORK_PATH
    
    # 安装 dnf
    RUN yum -y install dnf
    
    # 安装 vim
    RUN dnf -y install vim
    
    # 一些必要的依赖包
    RUN dnf -y update \
    && dnf -y install tar gzip bzip2 zip mtr gcc gcc-c++ openssl openssl-devel make pcre pcre-devel
    
    # 新建目录
    RUN mkdir -p /usr/local/src
    
    # 添加必要的用户
    RUN groupadd -r nginx \
    && useradd -r -g  nginx -s /sbin/nologin nginx
    
    # 复制宿主机的 .tar.gz 到容器实例中
    COPY nginx-1.31.1.tar.gz /tmp/
    
    # 解压
    RUN tar -vxf /tmp/nginx-1.31.1.tar.gz -C /usr/local/src/
    
    # 开始编译 nginx
    RUN cd /usr/local/src/nginx-1.31.1/ && ./configure --prefix=/usr/local/nginx/ \
    --user=nginx \
    --group=nginx \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_gzip_static_module \
    && make && make install
    
    ENTRYPOINT ["/usr/local/nginx/sbin/nginx"]
    CMD ["-g", "daemon off;"]
    
    EXPOSE 80/TCP 443/TCP
    
    # 这里使用默认信号 15 (SIGTERM)
    STOPSIGNAL SIGTERM
  • 第四步:使用 docker build 命令构建自定义的增强版镜像,在您的终端执行:

    Shell > cd /tmp/nginx/ && docker build -t mynginx:latest .
    [+] Building 40.8s (16/16) FINISHED                                                                      docker:default
    => [internal] load build definition from Dockerfile                                                               0.0s
    => => transferring dockerfile: 1.05kB                                                                             0.0s
    => [internal] load metadata for docker.io/library/rockylinux:8.9.20231119                                         0.0s
    => [internal] load .dockerignore                                                                                  0.0s
    => => transferring context: 2B                                                                                    0.0s
    => [ 1/11] FROM docker.io/library/rockylinux:8.9.20231119                                                         0.0s
    => [internal] load build context                                                                                  0.0s
    => => transferring context: 42B                                                                                   0.0s
    => CACHED [ 2/11] RUN mkdir -p "/usr/local/nginx"                                                                 0.0s
    => CACHED [ 3/11] WORKDIR /usr/local/nginx                                                                        0.0s
    => CACHED [ 4/11] RUN yum -y install dnf                                                                          0.0s
    => CACHED [ 5/11] RUN dnf -y install vim                                                                          0.0s
    => CACHED [ 6/11] RUN dnf -y update && dnf -y install tar gzip bzip2 zip mtr gcc gcc-c++ openssl openssl-devel m  0.0s
    => CACHED [ 7/11] RUN mkdir -p /usr/local/src                                                                     0.0s
    => [ 8/11] RUN groupadd -r nginx && useradd -r -g  nginx -s /sbin/nologin nginx                                   0.6s
    => [ 9/11] COPY nginx-1.31.1.tar.gz /tmp/                                                                         0.1s
    => [10/11] RUN tar -vxf /tmp/nginx-1.31.1.tar.gz -C /usr/local/src/                                               0.6s
    => [11/11] RUN cd /usr/local/src/nginx-1.31.1/ && ./configure --prefix=/usr/local/nginx/ --user=nginx --group=n  39.3s
    => exporting to image                                                                                             0.2s
    => => exporting layers                                                                                            0.2s
    => => writing image sha256:57ba773840045be8f168980d808b455c81a2bbb91a86b3c4aedb9708f10b1fad                       0.0s
    => => naming to docker.io/library/mynginx:latest                                                                  0.0s

    docker build 命令的选项说明:

    • -t - 设置构建需要的步骤或阶段。如您所见,我们共需要 11 个步骤来完成镜像的构建。
    • . - 这里的点并不表示 Dockerfile 文件的路径位置,而是表示 构建镜像所需的上下文(由于构建镜像需要在服务端的 Docker 引擎上,因此需要将本地的文件上传给 Docker 引擎,即所谓的上下文),这也解释了为什么使用 COPY ./nginx-1.31.1.tar.gz /tmp/ 这种方式是无法工作的。上面的输出信息中有这样的一行 —— "transferring context"
  • 第五步:验证镜像。

    Shell > docker images
    REPOSITORY   TAG            IMAGE ID       CREATED          SIZE
    mynginx      latest         57ba77384004   10 minutes ago   823MB
    rockylinux   8.9.20231119   c79048e50f5f   2 years ago      198MB
    
    Shell > docker run -d -p 80:80 -p 443:443 --name="new" mynginx:latest
    
    Shell > docker ps
    CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                                                                      NAMES
    c168d4d6db06   mynginx:latest   "/usr/local/nginx/sb…"   3 seconds ago   Up 2 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   new

    获取网页内容:

    Shell > curl http://192.168.100.20:80
Avatar photo

关于 陸風睿

GNU/Linux 从业者、开源爱好者、技术钻研者,撰写文档既是兴趣也是工作内容之一。Q - "281957576";WeChat - "jiulongxiaotianci",Github - https://github.com/jimcat8
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇