Docker 学习(四)——Dockerfile 创建镜像

发布于:2025-03-08 ⋅ 阅读:(30) ⋅ 点赞:(0)

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;"]