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
实践技巧:
- Docker会缓存COPY层,若源文件未变化,后续构建会复用缓存。
- 建议将变化频繁的文件(如源代码)放在Dockerfile末尾,减少缓存失效。
- 只复制必要的文件,避免冗余内容进入镜像。
- 将依赖文件(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 → /appRUN pwd → / |
| 推荐用法 | 首选(简洁、清晰) | 仅在需要临时切换目录时使用 |
实践技巧
- 使用绝对路径:避免相对路径带来的歧义。
- 统一工作目录:整个 Dockerfile 中使用一致的工作目录(如 /app),提高可读性。
- 避免多层级 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,因为每个容器都是独立的应用空间
- 使用 USER 前,需确保用户已在容器内创建(如 RUN useradd)
- 指定 USER 前,需确保用户对工作目录和执行命令所需的文件有足够权限
- 可通过 docker run -u 临时覆盖 Dockerfile 中的 USER 设置
- 不同基础镜像的用户配置不同(如 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"]

浙公网安备 33010602011771号