Dockerfile是一个文本格式的配置文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成 image 即可, 省去了敲命令的麻烦。
Dockerfile结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以“#“号开头的注释。
Dockerfile 中指令的一般格式为 INSTRUCTION arguments, 包括 “配置指令" (配置镜像信息)和 “操作指令" (具体执行操作)
1、Docker 镜像结构的分层
Docker 镜像采用联合文件系统(UnionFS),通过分层叠加实现高效存储和构建。每层都是只读文件系统,最终容器运行时在最上层添加可写层。
ockerfile中的每一个run命令,都会生成一层镜像,新镜像是从base镜像上一层层叠加起来生成的,镜像的分层结构最大的好处就是共享资源。多个容器共享一个基础镜像,当某个容器修改了基础镜像的内容,例如/etc下的文件,其他容器的/etc不会改变,因为只有当使用镜像运行一个容器实例时,才会在rootfs只读层上挂载一层可读可写层,下面的都是可读层,原来的镜像不会被修改。
Dockerfile 指令与层生成关系:
指令类型 | 是否生成新层 | 典型指令 | 优化建议 |
基础层 | 是 | FROM | 选择体积小的基础镜像(如 busybox、alpine) |
文件操作 | 是 | COPY / ADD/RUN | 合并文件操作到 RUN 指令 |
配置指令 | 否(元数据层) | ENV / LABEL / EXPOSE | 集中声明式配置 |
构建阶段 | 独立层组 | FROM ... AS builder | 使用多阶段减少最终层数 |
入口指令 | 是 | CMD / ENTRYOINT | 保持单一入口点 |
2、Dockerfile 操作常用指令
FROM 镜像 :指定新镜像的基础镜像,第一条指令必须为FROM 指令,每创建一个镜像就需要一条 FROM 指令。
RUN 命令 : 在所基于的镜像上执行命令,并提交到新的的镜像中,会叠加一层,叠加的命令都会在其中。
COPY 源文件/目录 目标文件/目录: (只复制本地主机上的文件/目录复制到目标地点,源文件/目录要与Dockerfile 在相同的目录中
ADD 源文件/目录 目标文件/目录 :增强版COPY,支持URL自动下载和压缩包自动解压(tar/gzip等)。COPY与 ADD 指令功能类似,当使用本地目录为源目录时,推荐使用 COPY。
ENV 环境变量 变量值 :设置环境变量(运行时持久生效)
WORKDIR 路径 /home :为后续的 RUN、CMD、ENTRYPOINT 指定工作目录
VOLUME [“目录”] :在容器中创建一个挂载点
ENTRYPOINT ["要运行的程序", "参数 1", "参数 2"] :设定容器启动时第一个运行的命令及其参数。
CMD ["要运行的程序", "参数1", "参数2"] :每个 Dockerfile 只能有 CMD 命令 如果指定了多条命令,只有最后一条会被执行 如果用户启动容器时候手动指定了运行的命令(作为 run口命令的参数),则会覆盖掉 CMD 指定的命令。注意优先级:RUN>ENTRYPOINT>CMD
EXPOSE 端口号:指定新镜像加载到 Docker 时要开启的端口
LABEL <key>=<value> :添加元数据(镜像作者、版本等)
Dockerfile 文件说明:
- 每一行以Dockerfile的指令开头,指令不区分大小写,但是惯例使用大写
- 使用 # 开始作为注释
- 每一行只支持一条指令,每条指令可以携带多个参数
- 指令按文件的顺序从上+
- 至下进行执行
- 每个指令的执行会生成一个新的镜像层,为了减少分层和镜像大小,尽可能将多条指令合并成一条指令
- 制作镜像一般可能需要反复多次,每次执行dockfile都按顺序执行,从头开始,已经执行过的指令已经缓存,不需要再执行,后续有一行指令没执行过,再往后的指令将会重新执行,所以为加速镜像制作,将最常变化的内容放下dockerfile的文件的后面
3、Dockerfile 实战 ——制作nginx镜像
[root@localhost ~]# mkdir docker/
[root@localhost ~]# cd docker/
[root@localhost ~]# wget http://nginx.org/download/nginx-1.26.3.tar.gz
[root@localhost docker]# vim Dockerfile
FROM centos:7
LABEL Mail=admin@qq.com
ADD nginx-1.26.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.3
RUN yum install gcc make pcre-devel openssl-devel -y && \
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module && \
make && make install && \
rm -rf /mnt/nginx-1.26.3 && \
yum clean all
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off"]
生成nginx镜像:
根据错误日志,主要因 CentOS 7 官方软件源失效导致 yum
操作失败。我们可以编辑 Dockerfile,在执行 yum install
命令前,替换 CentOS 7 的默认软件源为可用镜像源(如阿里云源)
FROM centos:7
LABEL Mail=admin@qq.com
ADD nginx-1.26.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.3
#替换 CentOS 7 的默认软件源为阿里云源
RUN rm -rf /etc/yum.repos.d/CentOS-* \
&& curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
&& yum clean all && yum makecache
RUN yum install gcc make pcre-devel openssl-devel -y && \
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module && \
make && make install && \
rm -rf /mnt/nginx-1.26.3 && \
yum clean all
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off"]
可以发现生成的镜像体积较大
如何通过Dockerfile自动化构建并优化镜像,同时确保镜像安全性和最小化体积?
(1)选择最小化基础镜像、合并指令减少镜像层数
(2)多阶段构建(核心优化手段)
(3)安全加固措施:非 Root 用户运行、定期更新基础镜像、漏洞扫描集成
(4)高级优化技巧:依赖精准控制、压缩构建上下文、 二进制文件瘦身
以下我通过多阶段构建来实例制作nginx:v2
[root@localhost docker]# cat Dockerfile
FROM centos:7 AS build
ADD nginx-1.26.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.3
RUN rm -rf /etc/yum.repos.d/CentOS-* \
&& curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
&& yum clean all && yum makecache
RUN yum install gcc make pcre-devel openssl-devel -y && \
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module && \
make && make install && \
rm -rf /mnt/nginx-1.26.3 && \
yum clean all
FROM centos:7
LABEL Mail=admin@qq.com
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]