Docker Dockerfile

参考资料:https://docs.docker.com/engine/reference/builder/

镜像制作

# 基于Dockerfile,直接构建镜像
docker build -t app:v1 .  # 通过Dockerfile文件,批量构建镜像

# 基于容器运行状态环境,直接创建镜像
docker commit 8b21b81f4fb7 busybox:v1  # 通过修改现有容器,将之手动构建为镜像

# 基于镜像包文件,直接导入导出镜像
docker export nginx -o nginx_container.tar  # 将容器环境导出为包文件,nginx容器名
docker import nginx_container.tar nginx:v1  # 从tar文件生成镜像

文件构建

Usage:  docker build [OPTIONS] PATH
-t, --tag    镜像标签(format: "[registry/]repository[:tag]")
-f, --file   Dockerfile 的名称(默认值:"PATH/Dockerfile")
--no-cache   构建镜像时不使用缓存
--pull       总是尝试拉取所有引用的镜像
--build-arg  设置构建时变量
--progress   设置进度输出类型(可选值:"auto"、"none"、"plain"、"quiet"、"rawjson"、"tty")。使用 plain 可展示容器输出(默认值 "auto")
--rm         构建成功自动移除中间容器

清理构建缓存

# 清理构建缓存
docker builder prune

# 强制清理所有缓存:
# 此命令会删除所有构建缓存,包括当前镜像依赖的层,后续构建将需要重新下载和编译所有内容。
docker builder prune -a --force

# 保留部分缓存空间:确保至少保留 5GB 的缓存空间,只删除超出部分。
docker builder prune --keep-storage=5GB

组合使用清理Docker空间

# 清理构建缓存
docker builder prune -f

# 清理未使用的镜像、容器、网络和卷
docker system prune -a --volumes

示例

# 假设 Dockerfile 在当前目录
docker build -t my-image:v1 .

# 指定 Dockerfile 位置和标签
docker build -t my-image:v1 -f /path/to/Dockerfile .

# 指定 Dockerfile 位置和标签、以及选项参数
docker build --build-arg APP_VERSION=1.2 -t my-image:v1 .

Dockerfile指令

FROM LABEL

FROM rockylinux:9
LABEL version="1.0" \
      author="yangqing@gitc.cc" \
      description="This is a sample Docker image"

# ✅ 推荐(OCI 标准,生产、开源镜像首选)
LABEL org.opencontainers.image.authors="张三 <zhangsan@example.com>"

# ✅ 简单兼容写法
LABEL maintainer="张三 <zhangsan@example.com>"

RUN

# shell风格
# 默认在/bin/sh -c的Shell环境中执行命令。支持Shell的特性,比如管道
RUN <command>

# exec风格
# 直接调用可执行文件。不支持Shell的特性(如管道和变量替换),更适用于跨平台的场景。
RUN ["executable", "param1", "param2"]

示例: 使用exec风格执行shell命令

RUN apt-get update
RUN ["apt-get", "update"]

EXPOSE

声明容器在运行时会监听的网络端口

# 声明单个端口
EXPOSE 80

# 声明多个端口
EXPOSE 80 443

# 声明端口和协议
EXPOSE 80/tcp
EXPOSE 53/udp

CMD

# shell风格
CMD command param1 param2

# exec风格
CMD ["executable","param1","param2"]
CMD ["/bin/bash", "-c","executable","param1","param2"]

# 作为ENTRYPOINT的参数,当CMD的内容会作为参数传递给 ENTRYPOINT。
CMD ["param1","param2"]

ENTRYPOINT

# shell风格
ENTRYPOINT command param1 param2

# exec风格
ENTRYPOINT ["executable", "param1", "param2"]

示例:

# 使用 exec 格式避免 shell 拦截信号(如 SIGTERM),确保容器能优雅停止。
ENTRYPOINT ["nginx", "-g", "daemon off;"]  # 正确(直接运行 nginx 进程)
ENTRYPOINT nginx -g 'daemon off;'          # 错误(shell 会拦截终止信号)

ENV

在 Dockerfile 中, ENV 指令用于设置环境变量。这些变量会被写入容器中,可在后续的 RUN 指令中使
用,也会被带入运行时环境,供应用程序读取。

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2> ...

示例

# 设置单个变量
ENV APP_PORT 8080
ENV DB_HOST localhost

# 设置多个变量(推荐)
ENV APP_PORT=8080 DB_HOST=localhost DB_USER=admin DB_PASS=secret

应用场景

#1 为 Dockerfile 后续的 RUN、CMD、ENTRYPOINT 等指令减轻压力
ENV NODE_VERSION 16.14.2
RUN curl -sL https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linuxx64.tar.gz | tar -xz -C /usr/local/
#2 容器内的应用程序可以通过环境变量获取配置:
ENV APP_ENV=production
CMD ["node", "app.js"] # app.js 可以读取 process.env.APP_ENV
#3 使用 docker build --build-arg 可以在构建时动态设置环境变量
ARG DB_HOST
ENV DB_HOST=$DB_HOST # 将构建参数的值赋给环境变量

COPY

COPY 是 Dockerfile 中用于从构建上下文(build context)复制文件或目录到容器中的核心指令。它支
持基本复制功能,并能处理文件权限和所有权,是构建镜像时的常用命令。

COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"] # 支持空格的路径(JSON格式)

解析:

  • 源路径:构建上下文中的文件或目录路径(可以是相对路径或绝对路径)。
  • 目标路径:容器内的绝对路径,若不存在会自动创建。

示例

# 复制单个文件
COPY app.js /app/

# 复制目录
COPY src/ /app/src/

# 通配符支持
COPY *.txt /app/config/

# 使用 --chown 选项修改文件的用户和组(仅适用于 Linux 容器)
COPY --chown=www-data:www-data html/ /var/www/html/

# 若目标路径以 / 结尾:视为目录,源文件会被复制到该目录下。
COPY file.txt /app/ # 结果:/app/file.txt

# 若目标路径不以 / 结尾:视为文件名,源文件会被重命名为该目标路径。
COPY file.txt /app/new.txt # 结果:/app/new.txt

实践技巧:

  1. Docker会缓存COPY层,若源文件未变化,后续构建会复用缓存。
  2. 建议将变化频繁的文件(如源代码)放在Dockerfile末尾,减少缓存失效。
  3. 只复制必要的文件,避免冗余内容进入镜像。
  4. 将依赖文件(package.json、requirements.txt)与源代码分开复制,利用缓存加速构建。

ADD

ADD 是 Dockerfile 中用于从源路径复制文件或目录到容器内目标路径的指令,功能比 COPY 更强大,但也更复杂。

ADD [--chown=<user>:<group>] <源路径>... <目标路径>
ADD [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"] # 支持空格的路径(JSON格式)

解析:

  • 源路径:可以是本地文件/目录、远程URL,或归档文件(如 tar、zip)。
  • 目标路径:容器内的绝对路径,若不存在会自动创建。

示例

# 与 COPY 类似,可复制构建上下文中的文件或目录
ADD app.js /app/ # 复制单个文件
ADD src/ /app/src/ # 递归复制目录内容

# 可直接从 URL 下载文件到容器
ADD https://example.com/file.txt /app/data/ # 下载远程文件

# 若源路径是本地的 tar、gzip、bzip2 等压缩文件,会自动解压到目标路径
ADD archive.tar.gz /app/ # 自动解压到 /app/ 目录

# 使用 --chown 选项修改文件的用户和组(仅适用于 Linux 容器)
ADD --chown=www-data:www-data html/ /var/www/html/ # 设置文件所有者

建议根据具体场景选择:

  • 简单复制:使用 COPY。
  • 解压本地归档:使用 ADD。
  • 远程资源:使用 RUN 命令手动处理

WORKDIR

WORKDIR是Dockerfile中的重要指令,用于设置后续RUN、CMD、ENTRYPOINT、COPY和ADD指令的工作目录。类似于 shell中的cd命令,但作用于镜像构建过程和容器运行时。

WORKDIR <路径>

解析:

  • 路径:容器内的绝对路径,若不存在会自动创建。

示例

# 设置工作目录,后续命令会在 WORKDIR 指定的目录下执行:
WORKDIR /app
RUN echo "Hello from $(pwd)" # 输出:Hello from /app
COPY . . # 将构建上下文复制到 /app/

# 可多次使用 WORKDIR 改变目录:
WORKDIR /tmp
RUN touch test.txt
WORKDIR /app
COPY --from=0 /tmp/test.txt . # 从 /tmp/ 复制文件到 /app/

# 若路径为相对路径,则相对于上一个 WORKDIR:
WORKDIR /app
WORKDIR src # 实际路径为 /app/src

# WORKDIR设置的目录会成为容器启动后执行命令的默认工作目录:
WORKDIR /app
CMD ["node", "server.js"] # 等价于在 /app/ 目录下执行 node server.js

WORKDIR和RUN cd对比

特性 WORKDIR RUN cd
生效范围 对后续所有指令有效 仅对当前 RUN 指令有效
目录持久性 永久改变工作目录 只在当前命令中临时改变目录
示例 WORKDIR /app RUN pwd → /app RUN cd /app && pwd → /app
RUN pwd → /
推荐用法 首选(简洁、清晰) 仅在需要临时切换目录时使用

实践技巧

  1. 使用绝对路径:避免相对路径带来的歧义。
  2. 统一工作目录:整个 Dockerfile 中使用一致的工作目录(如 /app),提高可读性。
  3. 避免多层级 WORKDIR:过多切换目录会降低 Dockerfile 的可读性。

USER

USER 是 Dockerfile 中用于指定后续命令(如 RUN 、 CMD 、 ENTRYPOINT )执行用户和组的指令。通过设置非 root 用户,可以增强容器的安全性,避免以特权用户运行应用程序

USER <用户名>[:<用户组>]

解析:

  • 用户名:容器内已存在的用户名称(如 nginx、node)。
  • 用户组(可选):指定用户所属的组(如 www-data:www-data)。

示例

# USER 之后的命令将以指定用户的身份执行:
RUN useradd -m appuser # 创建用户
USER appuser # 切换到 appuser
RUN touch /app/file # 以 appuser 身份创建文件

# 由 USER 指定的用户创建的文件将属于该用户
USER appuser
RUN echo "Hello" > /app/hello.txt # hello.txt 属于 appuser

# USER 不会改变工作目录,但需确保用户对工作目录有访问权限:
WORKDIR /app
USER appuser
CMD ["node", "server.js"] # 在 /app 目录下以 appuser 身份运行

最佳实践:有安全要求在使用,没事别乱用USER,因为每个容器都是独立的应用空间

  1. 使用 USER 前,需确保用户已在容器内创建(如 RUN useradd)
  2. 指定 USER 前,需确保用户对工作目录和执行命令所需的文件有足够权限
  3. 可通过 docker run -u 临时覆盖 Dockerfile 中的 USER 设置
  4. 不同基础镜像的用户配置不同(如 Alpine 使用 adduser 而非 useradd)。

强烈注意:如果编译的软件环境使用普通用户,有可能无法在后期docker的host网络模式上运行,因为Linux 系统中,1-1023 端口属于特权端口,只有 root 用户(或具备 CAP 有 CAP_NET_BIND_SERVICE 权限的进程)才能绑定这些端口。

ARG

ARG是Dockerfile中用于定义构建时参数的指令,允许你在构建镜像时通过 docker build --build-arg 动态传递变量值。这些参数仅在镜像构建过程中有效,不会成为容器运行时的环境变量。

ARG <参数名>[=<默认值>]

解析:

  • 参数名:自定义的参数名称(如 NGINX_VERSION、BUILD_DATE)。
  • 默认值(可选):若未通过 --build-arg 传递值,则使用默认值。
  • 传递参数命令:docker build --build-arg <参数名>=<值>

配置示例1: 构建时动态传参

# 定制Dockerfile指令
ARG APP_ENV=development
RUN echo "Building for $APP_ENV"

# 构建时覆盖默认值:
docker build --build-arg APP_ENV=production -t myapp .

配置示例2: ARG 定义的值可用于设置 ENV 环境变量或者LABEL 标签

ARG NODE_VERSION=16
ENV NODE_VERSION=$NODE_VERSION # 将 ARG 值赋给 ENV
RUN npm install --node=$NODE_VERSION

---
ARG BUILD_DATE=$(date +%Y-%m-%d)
LABEL build.date=$BUILD_DATE

注意事项:

  • ARG 仅在构建时有效,容器运行时无法访问。
  • 若需在运行时使用参数,应通过 ENV 或 docker run -e 传递。
  • ARG 最好放到用到该值的位置前一行,便于使用缓存

示例文件Dockerfile

准备环境

# 获取软件包
mkdir /app && cd /app && \
wget https://nginx.org/download/nginx-1.30.0.tar.gz \
wget https://nginx.org/download/nginx-1.28.0.tar.gz
# 定制网站首页
echo "Nginx VERSION Web Page from Rocky" > index.html

Dockerfile

# 使用Rocky Linux 9作为基础镜像
FROM rockylinux:9
LABEL maintainer="xiaoming"

# 设置环境变量
ENV NGINX_PREFIX=/app \
    BUILD_DIR=/tmp/build \
    NGINX_USER=nginx \
    NGINX_GROUP=nginx

# 创建 Nginx 用户和组
RUN groupadd -r $NGINX_GROUP && \
    useradd -r -g $NGINX_GROUP -d $NGINX_PREFIX $NGINX_USER

# 设置工作目录(用于构建过程)
WORKDIR $BUILD_DIR

# 安装编译依赖
RUN dnf makecache && dnf install -y \
    gcc make gcc-c++ glibc glibc-devel \
    pcre pcre-devel openssl openssl-devel \
    systemd-devel zlib-devel libxml2 libxml2-devel \
    libxslt libxslt-devel php-gd gd-devel wget && \
    dnf clean all && rm -rf /var/cache/dnf

# 定义可在构建时传递的参数(默认值为 1.30.0)
ARG NGINX_VERSION=1.30.0

# 使用 ADD 指令添加并自动解压源码包
ADD nginx-${NGINX_VERSION}.tar.gz .

# 设置工作目录到解压后的源码目录
WORKDIR nginx-${NGINX_VERSION}

# 编译安装 Nginx
RUN ./configure --prefix=$NGINX_PREFIX \
    --user=$NGINX_USER --group=$NGINX_GROUP && \
    make && make install && \
    setcap 'cap_net_bind_service=+ep' $NGINX_PREFIX/sbin/nginx && \
    dnf remove -y gcc make gcc-c++ glibc-devel \
    pcre-devel openssl-devel zlib-devel libxml2-devel libxslt-devel gd-devel && \
    dnf clean all && rm -rf /tmp/* /var/cache/dnf

# 设置工作目录为 Nginx 安装目录
WORKDIR $NGINX_PREFIX

# 添加自定义配置和首页
COPY index.html html/
RUN sed -i "s/VERSION/$NGINX_VERSION/" html/index.html && \
    chown -R $NGINX_USER:$NGINX_GROUP $NGINX_PREFIX

# 切换用户
USER $NGINX_USER

# 暴露端口
EXPOSE 80

# 启动 Nginx
ENTRYPOINT ["/app/sbin/nginx", "-g", "daemon off;"]

构建镜像

docker build -t rocky_nginx:v1.30.0 .

传参方式构建

docker build --build-arg NGINX_VERSION=1.28.0 -t rocky_nginx:v1.28.0 .

运行访问

# 运行
docker run --name n30 -d rocky_nginx:v1.30.0
docker run --name n28 -d rocky_nginx:v1.28.0

# 访问
curl $(docker inspect -f {{.NetworkSettings.Networks.bridge.IPAddress}} n30)
Nginx 1.30.0 Web Page from Rocky

curl $(docker inspect -f {{.NetworkSettings.Networks.bridge.IPAddress}} n28)
Nginx 1.28.0 Web Page from Rocky

故障排查

# 普通用户不能绑定 1–1023 端口
# 1.传统方案,给单个程序特权,无视端口限制
setcap 'cap_net_bind_service=+ep' /app/sbin/nginx
getcap /app/sbin/nginx

# 2.内核放开端口限制 net.ipv4.ip_unprivileged_port_start = 0 默认值1024
sysctl net.ipv4.ip_unprivileged_port_start
cat /proc/sys/net/ipv4/ip_unprivileged_port_start

其他指令

VOLUME

VOLUME 是 Dockerfile 的一个指令,用于定义容器中的持久化存储路径。它允许数据在容器重启或删除后仍然保留,并且可以在多个容器间共享。

# 单个路径
VOLUME /path/to/volume

# 多个路径(使用数组形式)
VOLUME ["/path1", "/path2"]

ONBUILD

ONBUILD 是一个特殊指令,用于定义当镜像被用作其他镜像的基础时执行的触发器。它允许父镜像(如开发环境)为子镜像(如应用部署)预定义一些操作,增强镜像的复用性。

ONBUILD <其他 Dockerfile 指令>

onbuild作用

  • 延迟执行指令:在父镜像中定义 ONBUILD 指令,这些指令不会在构建父镜像时执行,而是在使用该父镜像构建子镜像时自动触发。
  • 简化继承:减少子镜像 Dockerfile 的重复代码,尤其适合框架、工具链等基础镜像。
  • 模块化设计:将通用逻辑封装在父镜像中,子镜像只需关注业务差异。

示例

基础镜像的Dockerfile文件,构建后的镜像名字规划为 my-node-base
FROM node:18

# 设置工作目录
WORKDIR /app

# 定义 ONBUILD 触发器
ONBUILD COPY package*.json ./
ONBUILD RUN npm install
ONBUILD COPY . .

# 默认命令(子镜像可覆盖)
CMD ["node", "index.js"]
# 中阶镜像的Dockerfile文件
FROM my-node-base # 继承基础镜像

# 无需重复 COPY 和 npm install
ENV NODE_ENV=production

# 可选:覆盖默认命令
CMD ["npm", "start"]

实践技巧

适用于通用流程:如依赖安装、代码复制、环境准备等。
避免硬编码:使用环境变量代替固定值,增强灵活性。
错误处理:在 ONBUILD 指令中添加错误检查,避免子镜像构建失败。

---
循环触发风险:ONBUILD 指令不能再包含 ONBUILD,否则会导致循环触发。
明确标记:建议在父镜像标签中包含 onbuild 字样(如 my-base:onbuild),避免意外触发。

严重注意:多阶段构建的时候,肯定会遇到用户权限的问题,所以,一定要好好的规划,比如下面的nginx编译环境涉及到sudo的环境定制

# 创建 Nginx 用户和组
RUN groupadd -r $NGINX_GROUP && \
    useradd -r -g $NGINX_GROUP $NGINX_USER && \
    yum install -y sudo && \
    echo "$NGINX_USER ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$NGINX_USER && \
    chmod 0440 /etc/sudoers.d/$NGINX_USER

案例实战

前期准备

mkdir -p /app/{conf,scripts}
cd /app
wget https://nginx.org/download/nginx-1.30.0.tar.gz

# 创建nginx.conf,extra.conf和start-nginx.sh配置文件
root@localhost:/app# cat conf/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    include conf.d/*.conf;
}
root@localhost:/app# cat conf/extra.conf
# 自定义日志格式
log_format custom_format  '$remote_addr - $remote_user [$time_local] '
                          '"$request" $status $body_bytes_sent '
                          '"$http_referer" "$http_user_agent" '
                          '"$http_x_forwarded_for"';

# 启用自定义日志格式
access_log /app/logs/access_custom.log custom_format;

# 额外的虚拟主机配置
server {
    listen 8080;
    server_name localhost;

    location /test {
        return 200 "Hello from extra.conf!\n";
    }
}
root@localhost:/app# cat scripts/start-nginx.sh
#!/bin/sh
# 修正日志目录及文件权限(关键步骤)
sudo chown -R $NGINX_USER:$NGINX_GROUP $NGINX_PREFIX/logs

# 启动 Nginx
exec $NGINX_PREFIX/sbin/nginx -g "daemon off;"
root@localhost:/app# chmod +x scripts/start-nginx.sh

定制Dockerfile 构建基准镜像名为nginx-base

root@localhost:/app# cat Dockerfile
# 使用Rocky Linux 9作为基础镜像
FROM rockylinux:9
LABEL maintainer="xiaoming"

# 设置环境变量
ENV NGINX_PREFIX=/app \
    BUILD_DIR=/tmp/build \
    NGINX_USER=nginx \
    NGINX_GROUP=nginx

# 创建 Nginx 用户和组
RUN groupadd -r $NGINX_GROUP && \
    useradd -r -g $NGINX_GROUP -d $NGINX_PREFIX $NGINX_USER && \
    dnf makecache && dnf install -y sudo && \
    echo "$NGINX_USER ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$NGINX_USER && \
    chmod 0440 /etc/sudoers.d/$NGINX_USER

# 设置工作目录(用于构建过程)
WORKDIR $BUILD_DIR

# 安装编译依赖
RUN dnf makecache && dnf install -y \
    gcc make gcc-c++ glibc glibc-devel \
    pcre pcre-devel openssl openssl-devel \
    systemd-devel zlib-devel libxml2 libxml2-devel \
    libxslt libxslt-devel php-gd gd-devel wget && \
    dnf clean all && rm -rf /var/cache/dnf

# 定义可在构建时传递的参数(默认值为 1.30.0)
ARG NGINX_VERSION=1.30.0

# 使用 ADD 指令添加并自动解压源码包
ADD nginx-${NGINX_VERSION}.tar.gz .

# 设置工作目录到解压后的源码目录
WORKDIR nginx-${NGINX_VERSION}

# 编译安装 Nginx
RUN ./configure --prefix=$NGINX_PREFIX \
    --user=$NGINX_USER --group=$NGINX_GROUP && \
    make && make install && \
    setcap 'cap_net_bind_service=+ep' $NGINX_PREFIX/sbin/nginx && \
    dnf remove -y gcc make gcc-c++ glibc-devel \
    pcre-devel openssl-devel zlib-devel libxml2-devel libxslt-devel gd-devel && \
    dnf clean all && rm -rf /tmp/* /var/cache/dnf

# 设置工作目录为 Nginx 安装目录
WORKDIR $NGINX_PREFIX

# 添加自定义配置和首页
COPY index.html html/
COPY conf/nginx.conf conf/
COPY scripts/start-nginx.sh sbin/
RUN sed -i "s/VERSION/$NGINX_VERSION/" html/index.html && \
    chown -R $NGINX_USER:$NGINX_GROUP $NGINX_PREFIX

# 切换用户
USER $NGINX_USER

# 暴露端口
EXPOSE 80

# 新增:VOLUME
VOLUME ["$NGINX_PREFIX/conf/conf.d"]

# 新增:ONBUILD
ONBUILD ADD conf/extra.conf $NGINX_PREFIX/conf/conf.d/extra.conf
ONBUILD RUN sudo chown -R $NGINX_USER:$NGINX_GROUP $NGINX_PREFIX && \
            sudo $NGINX_PREFIX/sbin/nginx -t

# 新增:HEALTHCHECK,定义容器的健康检查机制
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
    CMD curl -f http://localhost/ || exit 1

# 新增:STOPSIGNAL,允许你自定义容器优雅关闭的行为
STOPSIGNAL SIGQUIT

# 最后切换到非 root 用户(在ONBUILD之后)
USER $NGINX_USER

# 启动 Nginx
ENTRYPOINT ["sbin/start-nginx.sh"]

定制衍生镜像为Dockerfile.derived

root@localhost:/app# cat Dockerfile.derived 
FROM nginx-base

# 注意:
#     只需要一行 FROM 指令即可
#     不需要额外的指令,ONBUILD 会自动执行基础镜像Dockerfile里面的指令

构建镜像

# 构建基础镜像
docker build -t nginx-base .

# 定制衍生镜像
docker build -f Dockerfile.derived -t nginx-derived .

启动验证

# 基于衍生镜像启动容器
docker run -d -p 80:80 -p 8080:8080 --name nginx-test nginx-derived

# 检查容器的日志目录是否被挂载为卷
docker inspect nginx-test | grep Mounts -A 20

# 检查容器的健康状态
root@localhost:/app# docker ps
CONTAINER ID   IMAGE           COMMAND                 CREATED          STATUS                    PORTS                                                                              NAMES
64c56538eadd   nginx-derived   "sbin/start-nginx.sh"   24 minutes ago   Up 24 minutes (healthy)   0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp   nginx-test
# 结果显示:
#     healthy 是 检测成功的状态

# 测试访问
root@localhost:/app# curl localhost
Nginx 1.30.0 Web Page from Rocky
root@localhost:/app# curl localhost:8080
Nginx 1.30.0 Web Page from Rocky
root@localhost:/app# curl localhost:8080/test
Hello from extra.conf!

.dockerignore

在 Docker 构建过程中, .dockerignore 文件用于排除不需要添加到镜像中的文件和目录,从而减少镜像大小、提高构建速度,并避免敏感信息被包含在镜像中。

语法规则

# :注释的行。
* :排除匹配任意字符
**:排除匹配任意目录
? :排除匹配单个字符
/ :排除路径
! :白名单,包含文件
示例:
cat .dockerignore
*
!Dockerfile
!conf/nginx.conf
!conf/extra.conf
# 1. 排除 Docker 相关的临时文件
.dockerignore
Dockerfile
Dockerfile.derived
# 2. 排除源码包和编译临时文件(如果 softs 目录只在构建基础镜像时用,且已通过 ADD 加入,可排除)
softs/
tmp/
build/
# 3. 排除日志和缓存文件
*.log
*.tmp
.cache/
logs/
# 4. 排除敏感文件(如密钥、配置密码等,根据实际情况添加)
*.key
*.pem
.env
passwords.txt
# 5. 排除版本控制文件(可选,不影响构建但可减小上下文)
.git/
.gitignore
.idea/
.vscode/
# 6. 排除其他不需要的文件类型,添加 **/ 前缀表示 “匹配所有目录(包括当前目录和子目录)”
**/*.md
**/*.txt
**/*.log

多阶段构建

Docker 的多阶段构建(Multi-stage Build) 是一种通过在单个 Dockerfile 中定义多个构建阶段,来优化镜像体积、简化构建流程的技术。它的核心思想是:将构建过程拆分为 “构建阶段” 和 “运行阶段”,只将运行所需的最小文件复制到最终镜像中。

关键语法

阶段命名:
    通过 FROM <镜像> AS <阶段名> 为阶段命名(如 AS builder),方便后续阶段引用。

复制产物:
    通过 COPY --from=<阶段名> <源路径> <目标路径> 从指定阶段复制文件到当前阶段(仅复制需要的文件)。
    注意:源路径,必须使用绝对路径,不允许使用环境变量来实现。

选择最终阶段:
    构建时,默认以最后一个阶段作为最终镜像;也可通过 --target <阶段名> 指定构建某个中间阶段(用于调试)。

使用场景

编译型语言(Java、Go、C++ 等):
    需要先编译再运行的场景,可分离 “编译环境” 和 “运行环境”。

前端项目(Vue、React 等):
    用 Node 镜像构建静态资源,再复制到 Nginx 镜像中运行。

任何需要 “构建产物” 与 “构建环境” 分离的场景。

示例一

# 第一阶段:构建阶段(编译代码)
FROM maven:3.8-openjdk-17 AS builder # 命名为 builder
WORKDIR /app
COPY pom.xml src/ ./ # 复制源代码和依赖配置
RUN mvn package -DskipTests # 编译并打包为 JAR 文件

# 第二阶段:运行阶段(仅保留运行所需文件)
FROM openjdk:17-jre-alpine # 使用轻量的 JRE 镜像
WORKDIR /app
# 从 builder 阶段复制打包好的 JAR 文件
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8000
ENTRYPOINT ["java", "-jar", "app.jar"]

示例二

# 第一阶段:编译阶段 - 使用JDK镜像编译Java代码
FROM jdk-alpine:17 AS builder
# 设置编译工作目录
WORKDIR /build
# 复制Java源代码到容器中
COPY jar/HelloWorld.java .
# 编译Java文件生成class文件
RUN javac HelloWorld.java
# 创建MANIFEST.MF文件指定主类
RUN echo "Main-Class: HelloWorld" > MANIFEST.MF
# 打包所有class文件为JAR包
RUN jar cfm hello-world.jar MANIFEST.MF *.class

# 第二阶段:运行阶段 - 构建最终应用镜像
FROM jdk-alpine:17
# 设置应用工作目录
WORKDIR /app
# 从编译阶段复制打包好的JAR文件
COPY --from=builder /build/hello-world.jar .
# 暴露应用端口
EXPOSE 8000
# 启动命令
ENTRYPOINT ["java", "-jar", "hello-world.jar"]
posted @ 2026-11-10 20:32  墨清竹  阅读(8)  评论(0)    收藏  举报