Docker-学习四Dockerfile-创建镜像-详细版
Docker 学习(四)——Dockerfile 创建镜像 (详细版)
一、Dockerfile 简介
1、什么是Dockerfile
Dockerfile是一 个 文本格式的配置文件 ,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成 image 即可, 省去了敲命令的麻烦。
Dockerfile结构大致分为四个部分: 基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令 。Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以“#“号开头的注释。
Dockerfile 中指令的一般格式为
INSTRUCTION arguments,
包括
“
配置指令" (配置镜像信息)和 “操作指令" (具体执行操作)
2、Docker 镜像结构的分层
Docker 镜像采用 联合文件系统(UnionFS) ,通过分层叠加实现高效存储和构建。 每层都是只读文件系统,最终容器运行时在最上层添加可写层 。
ockerfile中的每一个run命令,都会生成一层镜像,新镜像是从base镜像上一层层叠加起来生成的, 镜像的分层结构最大的好处就是共享资源 。多个容器共享一个基础镜像,当某个容器修改了基础镜像的内容,例如/etc下的文件,其他容器的/etc不会改变,因为只有当使用镜像运行一个容器实例时,才会在rootfs只读层上挂载一层可读可写层,下面的都是可读层,原来的镜像不会被修改。
3、Dockerfile构造镜像原则:
(1) 单一职责 :每个层级只做每个层级的事
(2) 提供注释信息 :最好提供注释信息,以便他人理解
(3) 保持容器最小化
(4) 合理选择基础镜像 :基础镜像的选择很重要,尽量选择成熟易用的基础镜像版本
(5) 最小化镜像层数 :镜像层数不宜过多,尽量精简,否则容易出错,也可能会影响加载速度
4、Dockerfile 指令与层生成关系:
指令类型 | 是否生成新层 | 典型指令 | 优化建议 |
基础层 | 是 | FROM | 选择体积小的基础镜像(如 busybox、alpine) |
文件操作 | 是 | COPY / ADD/RUN | 合并文件操作到 RUN 指令 |
配置指令 | 否(元数据层) | ENV / LABEL / EXPOSE | 集中声明式配置 |
构建阶段 | 独立层组 | FROM … AS builder | 使用多阶段减少最终层数 |
入口指令 | 是 | CMD / ENTRYOINT | 保持单一入口点 |
二、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
Dockerfile 文件说明:
- 每一行以Dockerfile的指令开头,指令不区分大小写,但是惯例使用大写
- 使用 # 开始作为注释
- 每一行只支持一条指令,每条指令可以携带多个参数
- 指令按文件的顺序从上+
- 至下进行执行
- 每个指令的执行会生成一个新的镜像层,为了减少分层和镜像大小,尽可能将多条指令合并成一条指令
- 制作镜像一般可能需要反复多次,每次执行dockfile都按顺序执行,从头开始,已经执行过的指令已经缓存,不需要再执行,后续有一行指令没执行过,再往后的指令将会重新执行,所以为加速镜像制作,将最常变化的内容放下dockerfile的文件的后面
三、制作镜像
1、如何制作Docker 镜像?
制作docker镜像主要有两种方式: 基于容器提交(docker commit) 和 基于Dockerfile构建(docker build)。
下面将具体介绍如何自行创建一个带有 SSH 服务的镜像。
2.方法一:docker commit 手动提交容器为镜像
适用场景:
- 快速测试:临时修改容器并保存为镜像,用于调试或验证配置。
- 简单实验:无需编写复杂脚本,适合新手入门。
优点: 操作简单,适合快速测试,无需学习Dockerfile
缺点: 臃肿,维护困难
具体步骤:
(1)拉取镜像
[root@localhost ~]# docker pull ubuntu:18.04
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
(2)配置软件源
[root@localhost ~]# docker run --name c1 -it --rm ubuntu:18.04 bash
root@b5c47f7812be:/# mv /etc/apt/sources.list{,.bak}
root@b5c47f7812be:/# echo deb http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse > /etc/apt/sources.list.d/163.list
echo deb http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse >> /etc/apt/sources.list.d/163.list
echo deb http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse >> /etc/apt/sources.list.d/163.list
echo deb http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse >> /etc/apt/sources.list.d/163.list
echo deb http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse >> /etc/apt/sources.list.d/163.list
echo deb-src http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse >> /etc/apt/sources.list.d/163.list
echo deb-src http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse >> /etc/apt/sources.list.d/163.list
echo deb-src http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse >> /etc/apt/sources.list.d/163.list
echo deb-src http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse >> /etc/apt/sources.list.d/163.list
echo deb-src http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse >> /etc/apt/sources.list.d/163.list
(3) 安装配置ssh服务
root@b5c47f7812be:/# apt update
root@b5c47f7812be:/# apt install openssh-server -y
root@b5c47f7812be:/# mkdir -p /var/run/sshd
rot@b5c47f7812be:/# /usr/sbin/sshd -D &
取消pam登录限制:
root@b5c47f7812be:/# sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/' /etc/pam.d/sshd
(4)配置免密钥登录
[root@localhost ~]# ssh-keygen -f ~/.ssh/id_rsa -P '' -q #宿主机上面生成一对密钥对
[root@localhost ~]# cd ~/.ssh
[root@localhost .ssh]# cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0tumSdw229Qtqmr07OOv6B1M3YH34Dso2ZJaQpWtBVrOFCt2mVESzjtf8roQkb0ESUWGAxqmCIMchtmL04LfCSYMlx6CkrReBCaBBjHg8EURTnIgHNC+qkXIhmVIxLiOFfhKZ4+NUWuZHpdVZE4zlKkEceCUaTplvFSAcBMdeQxb3dQeGnYAJyT+7HXBALuXEzumDts/6zkhfr5ejTbo3cSBy1zIIA6hgSaq38wPYMmwpxW8dqsXWtJhiNa1IXF1csbZdVKIko383DBh+KsdrjUW4HOkicrJoT6jZSn2MxggSfAIWkRp4d4G5497TaTz9h9I/EWZT3NRbIvP1z4Yh1JWaNjCwXfmTzZT7sdo0IcimNGtB0K2JBbqSJ8k9uoDi9q3SurfDzE2NvmfBYBgD26ZyycKJeoUS6RmbtkHUiFxSFoiX9fIjSz6oN0pR7htl/N/hsXi3UZzaV/63imgOEZ80pMz5EGCViDQxV/2H/kPL14hpdWKxi9xq6H1Z6+U= root@localhost.localdomain
root@b5c47f7812be:/# mkdir ~/.ssh
root@b5c47f7812be:/# echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0tumSdw229Qtqmr07OOv6B1M3YH34Dso2ZJaQpWtBVrOFCt2mVESzjtf8roQkb0ESUWGAxqmCIMchtmL04LfCSYMlx6CkrReBCaBBjHg8EURTnIgHNC+qkXIhmVIxLiOFfhKZ4+NUWuZHpdVZE4zlKkEceCUaTplvFSAcBMdeQxb3dQeGnYAJyT+7HXBALuXEzumDts/6zkhfr5ejTbo3cSBy1zIIA6hgSaq38wPYMmwpxW8dqsXWtJhiNa1IXF1csbZdVKIko383DBh+KsdrjUW4HOkicrJoT6jZSn2MxggSfAIWkRp4d4G5497TaTz9h9I/EWZT3NRbIvP1z4Yh1JWaNjCwXfmTzZT7sdo0IcimNGtB0K2JBbqSJ8k9uoDi9q3SurfDzE2NvmfBYBgD26ZyycKJeoUS6RmbtkHUiFxSFoiX9fIjSz6oN0pR7htl/N/hsXi3UZzaV/63imgOEZ80pMz5EGCViDQxV/2H/kPL14hpdWKxi9xq6H1Z6+U= root@localhost.localdomain > ~/.ssh/authorized_keys
服务启动脚本:
root@b5c47f7812be:/# echo '#!/bin/bash' > /run.sh
root@b5c47f7812be:/# echo /usr/sbin/sshd -D >> /run.sh
root@b5c47f7812be:/# chmod +x /run.sh
root@b5c47f7812be:/#
(5)提交镜像
[root@localhost .ssh]# docker commit c1 ssh:ubuntu_v1
sha256:96ed9e0701e36c933449c56f956cff2cabe87ad153321dc55d8baf9cbcb7fd0d
[root@localhost .ssh]# docker push ssh:ubuntu_v1
The push refers to repository [docker.io/library/ssh]
Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
[root@localhost .ssh]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ssh ubuntu_v1 96ed9e0701e3 58 seconds ago 250MB
ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
(6)验证镜像
[root@localhost .ssh]# docker run -d -p 10022:22 ssh:ubuntu_v1 /run.sh
80a16ea16612f90a869ebf60120f685892a1707277697f7cde167ded4f7f0f4b
[root@localhost .ssh]# ssh 192.168.8.161 -p 10022
The authenticity of host '[192.168.8.161]:10022 ([192.168.8.161]:10022)' can't be established.
ECDSA key fingerprint is SHA256:mMyHF3hJnJ5ogyvA7fyJsvWfVFKlCcGsK92IQSEoJYE.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[192.168.8.161]:10022' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 4.18.0-553.el8_10.x86_64 x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
To restore this content, you can run the 'unminimize' command.
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
root@80a16ea16612:~#
3.Dockerfile 标准化构建镜像
适用场景:
- 标准化、可重复的镜像构建流程。
- 需要版本控制、分层优化和自动化部署。
优点: 镜像轻级,可版本控制,易于维护,支持自动化构建
缺点: 需要学习Dockerfile语法,编写较难且耗时
具体步骤:
(1)创建目录
[root@localhost ~]# mkdir ubuntu
[root@localhost ~]# cd ubuntu
(2)编辑Dockerfile文件
[root@localhost ubuntu]# vim Dockerfile
FROM ubuntu:18.04
LABEL Mail=admin@qq.com
RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak
COPY 163.list /etc/apt/sources.list.d/163.list
RUN apt update && apt install -y openssh-server && mkdir -p /var/run/sshd
RUN sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/' /etc/pam.d/sshd
COPY run.sh /run.sh
RUN chmod +x /run.sh && mkdir /root/.ssh
COPY authorized_keys /root/.ssh/authorized_keys
EXPOSE 22/tcp
CMD ["/run.sh"]
(3)把需要的文件复制到创建的目录下
[root@localhost ubuntu]# vim 163.list
deb http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse
[root@localhost ubuntu]# vim run.sh
#!/bin/bash
/usr/sbin/sshd -D
[root@localhost ubuntu]# vim authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0tumSdw229Qtqmr07OOv6B1M3YH34Dso2ZJaQpWtBVrOFCt2mVESzjtf8roQkb0ESUWGAxqmCIMchtmL04LfCSYMlx6CkrReBCaBBjHg8EURTnIgHNC+qkXIhmVIxLiOFfhKZ4+NUWuZHpdVZE4zlKkEceCUaTplvFSAcBMdeQxb3dQeGnYAJyT+7HXBALuXEzumDts/6zkhfr5ejTbo3cSBy1zIIA6hgSaq38wPYMmwpxW8dqsXWtJhiNa1IXF1csbZdVKIko383DBh+KsdrjUW4HOkicrJoT6jZSn2MxggSfAIWkRp4d4G5497TaTz9h9I/EWZT3NRbIvP1z4Yh1JWaNjCwXfmTzZT7sdo0IcimNGtB0K2JBbqSJ8k9uoDi9q3SurfDzE2NvmfBYBgD26ZyycKJeoUS6RmbtkHUiFxSFoiX9fIjSz6oN0pR7htl/N/hsXi3UZzaV/63imgOEZ80pMz5EGCViDQxV/2H/kPL14hpdWKxi9xq6H1Z6+U= root@localhost.localdomain
(4)构建镜像
(5)验证镜像
四、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;"]