Docker 镜像构建与优化

一、Dockerfile 构建镜像

1.1.拉取所需镜像

首先 docker pull 拉取一个 centos7 的镜像。

docker pull centos:7

下载 nginx 源码包。

官网:nginx: download

wget https://nginx.org/download/nginx-1.26.3.tar.gz

1.2.解决 CentOS 7 安装源问题

因为原本的 centos 7 安装源有问题不能下载软件,所以需要更换容器的安装源。以下是根据宿主机本机搭建共享安装源供容器使用,可也自行更换阿里或者其他平台的开源镜像源。

1.2.1.添加新光盘

搭建本地 Apache 服务,共享本地 RHEL 7 安装源供容器 CentOS 7 使用。

添加新 CD/DVD 设置 RHEL 7.9 的镜像文件。

1.2.2.配置 Apache 服务

安装 httpd ,配置服务。

yum install httpd -y
vim /etc/httpd/conf/httpd.conf

修改 httpd 主配置文件监听端口为 8888,为了与容器的端口不冲突。

构建访问页面,共享 RHEL 7.9 信息。

mkdir /var/www/html/rhel7.9
mount /dev/sr1 /var/www/html/rhel7.9/
systemctl enable --now httpd

1.2.3.测试

浏览器可访问到共享的光盘信息。

1.3.运行 CentOS 容器,修改 yum 源

查看 centos 容器网络(此时 IP :172.17.0.2)。

docker inspect centos

容器看到主机的网络为与容器同一网段的 IP 地址,所以,接下来在容器里配置 yum 源,需要设置容器连接的本机 IP(172.17.0.1),而不是本机真实 IP(192.168.67.140)。

运行 CentOS 容器,配置 yum 源。

docker run -it --name centos centos:7
​
# 进入容器,执行以下命令
cd /etc/yum.repos.d/
rm -rf *.repo
​
cat >> centos7.repo << EOF
[centos7]
name=centos7.9
baseurl=http://172.17.0.1:8888/rhel7.9/
gpgcheck=0
EOF
​
# 退出容器,但不关闭容器,使用命令 ctrl+p+q
# 提交 centos 现有状态
docker commit -m "add repo" centos centos:repo

SIZE 没大的变化。

因为原本的 centos 镜像安装源不能安装软件,所以需要搭建能安装软件的 centos 镜像,为了下面编写构建文件做准备。

1.4.编写构建文件

1.4.1.构建参数

FROM指定 base 镜像 eg:FROM busybox:version
COPY复制文件 eg:COPY file/file 或者 COPY ["file","/"]
MAINTAINER指定作者信息,比如邮箱 eg:MAINATINER user@example.com 在最新版的 docker 中用 LABEL KEY=“VALUE” 代替
ADD功能和 copy 相似,指定压缩文件或 url eg:ADD test.tar /mnt 或者 eg:ADD http://ip/test.tar /mnt
ENV指定环境变量 eg:ENV FILENAME test
EXPOSE暴露容器端口 eg:EXPOSE 80
VOLUME申明数据卷,通常指数据挂载点 eg:VOLUME["/var/www/html"]
WORKDIR切换路径 eg:WORKDIR /mnt
RUN在容器中运行的指令 eg:touch file
CMD在容器启动时自动运行的动作可以被覆盖 eg:CMD echo $FILENAME 会调用 shell 解析 eg:CMD["/bin/sh","-c","echo $FILENAME"]不调用 shell 解析
ENTRYPOINT和 CMD 功能和用法类似,但动作不可被覆盖

镜像层机制解析

  • Docker 镜像层的工作原理:

    • Docker 镜像是由多个只读层(Layer)叠加而成的。每个 RUN、COPY、ADD 指令都会生成一个新层。镜像层具有共享特性,相同的文件内容在多个镜像中只存储一次。但过多的镜像层会增加镜像体积和构建时间,因此合并层是优化的关键。

缓存机制说明

  • Docker 构建缓存的机制和注意事项:

    • Docker 在构建时会缓存每一层的结果。若某层指令未改变,后续构建会复用缓存。但修改上层指令会导致下层缓存失效。例如,将 ADD 指令放在 RUN 之前可以减少缓存失效的概率。

1.4.2.创建 Dockerfile

在家目录下建立文件。

mkdir /root/docker
cd /root/docker/
cp /root/nginx-1.26.3.tar.gz /root/docker/     # 注意:构建所需的所有文件多要与 Dockerfile 在同一个文件夹里
​
# 编写构建文件
cat >> Dockerfile << EOF
FROM centos:repo                             # 指定基础镜像,不过'repo'不是有效的CentOS镜像标签,应替换为如'centos:7'等有效标签
LABEL Mail=haha@qq.com                       # 为镜像添加元数据标签,标注维护者邮箱为haha@qq.com
ADD nginx-1.26.3.tar.gz /mnt                 # 将当前目录下的nginx-1.26.3.tar.gz文件添加到镜像的/mnt目录,ADD可自动解压压缩包
EXPOSE 80                                    # 声明容器运行时监听的端口为80,仅作声明,不进行实际端口映射
WORKDIR /mnt/nginx-1.26.3                    # 设置后续命令执行的工作目录为/mnt/nginx-1.26.3
RUN yum install gcc make pcre-devel openssl-devel -y  # 使用yum包管理器安装编译Nginx所需的依赖包
RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module                      # 执行Nginx配置脚本,指定安装目录和开启相关模块
RUN make                                     # 执行make命令,编译Nginx源代码
RUN make install                             # 执行make install命令,将编译好的Nginx安装到指定目录
VOLUME ["/usr/local/nginx/html"]             # 创建数据卷,用于持久化存储数据和容器间共享
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]  # 定义容器启动时执行的命令,以非守护进程模式启动Nginx
EOF

1.4.3.通过 Dockerfile 构建镜像

docker build -t centos:v1 /root/docker/

以下是通过 CentOS7 构建出来的 nginx 镜像。

问题:

  1. 镜像层冗余问题:多个 RUN 指令会生成多个镜像层,这会让镜像体积增大,还可能产生不必要的缓存。

  2. 包安装缓存问题:yum install 后没有清理缓存,这会让镜像体积增大。


二、镜像优化方案

2.1.镜像优化策略

  • 镜像层合并:把多个 RUN 指令合并成一个,以此减少镜像层数量,进而减小镜像体积。

  • 包安装缓存清理:在 yum install 之后添加 yum clean all 和 rm -rf /var/cache/yum 来清理缓存。

2.2.镜像优化示例

2.2.1.缩减镜像层

cd /root/docker/
​
# 修改构建文件
cat >> Dockerfile << EOF
FROM centos:repo
LABEL Mail=haha@qq.com
ADD nginx-1.26.3.tar.gz /mnt
EXPOSE 80
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
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
EOF
​
docker build -t centos:v2 /root/docker/

查看建立的镜像,v2 比 v1 小了一些。

解决的问题:

  • 镜像层冗余问题

    • 原问题

    • 原 Dockerfile 中使用了多个 RUN 指令,每个 RUN 指令都会在镜像构建过程中创建一个新的镜像层,这会导致镜像层数增多,最终使得镜像体积变大,同时也可能造成不必要的缓存问题。

    • 解决方式

    • 修改后的 Dockerfile 将多个 RUN 指令合并为一个,即 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。这样只创建一个镜像层,减少了镜像层数,有效减小了镜像体积。

  • 包安装缓存问题

    • 原问题

    • 原 Dockerfile 里 yum install 后没有清理缓存,这些缓存会被包含在镜像中,从而增加镜像体积。

    • 解决方式

    • 修改后的 Dockerfile 在 yum install 之后添加了 yum clean all 命令,它会清理 yum 的缓存文件,进一步减小了镜像体积。

  • 临时文件残留问题

    • 原问题

    • 原 Dockerfile 构建完成后,/mnt/nginx - 1.26.3 目录下的文件仍然存在于镜像中,这会增加镜像的冗余数据。

    • 解决方式

    • 修改后的 Dockerfile 在安装完成 Nginx 后添加了 rm -rf /mnt/nginx - 1.26.3 命令,将解压的 Nginx 源码目录删除,避免了临时文件占用镜像空间。

  • 构建效率问题

    • 原问题

    • 多个 RUN 指令可能会导致每次构建时都需要重新执行多个步骤,影响构建效率。

    • 解决方式

    • 合并 RUN 指令后,Docker 可以一次性执行多个操作,减少了中间层的创建和处理,在一定程度上提高了构建效率。

2.2.2.多阶构建

cd /root/docker/
​
# 修改构建文件
cat >> Dockerfile << EOF
FROM centos:repo AS build
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
​
FROM centos:repo
LABEL Mail=haha@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;"]
EOF
​
docker build -t centos:v3 /root/docker/

查看建立的镜像,v3 比 v2 小了一些。

解决的问题:

  • 镜像体积显著减小

    • 原问题

    • 在单阶段构建时,构建过程中用到的所有工具(如编译工具、依赖库等)以及临时文件都会被打包进最终镜像,导致镜像体积庞大。例如,在安装和编译 Nginx 时,需要安装 gcc、make、pcre - devel、openssl - devel 等编译工具和依赖库,但在运行 Nginx 时,这些编译工具和依赖库并非必需,却依然存在于最终镜像中,增加了镜像的冗余数据。

    • 解决方式

    • 多阶段构建将构建过程分为多个阶段。在第一个阶段(build 阶段),使用包含编译工具的基础镜像进行编译和安装操作,完成后可以丢弃该阶段中使用的所有编译工具和临时文件。第二个阶段从一个新的基础镜像开始,仅将第一个阶段构建好的可执行文件和必要的配置文件复制到新的镜像中。在这个例子中,仅将 /usr/local/nginx 目录从 build 阶段复制到最终镜像,避免了编译工具和临时文件进入最终镜像,从而显著减小了镜像体积。

  • 提高镜像安全性

    • 原问题

    • 单阶段构建的镜像中包含了构建过程中使用的所有工具和依赖,这些工具和依赖可能存在安全漏洞。例如,编译工具可能存在已知的安全隐患,将其留在最终镜像中会给容器的运行带来安全风险。

    • 解决方式

    • 多阶段构建的最终镜像只包含运行应用所需的最小化依赖。在第二个阶段,使用一个干净、轻量级的基础镜像,不包含构建阶段的编译工具和其他不必要的软件包,减少了潜在的安全漏洞,提高了镜像的安全性。

  • 构建过程的独立性和可维护性增强

    • 原问题

    • 单阶段构建的 Dockerfile 中,构建步骤和运行步骤混杂在一起,当需要修改构建过程或者运行配置时,可能会相互影响,导致维护困难。而且,单阶段构建的逻辑不够清晰,难以理解每个步骤的目的。

    • 解决方式

    • 多阶段构建将构建过程和运行过程分离,每个阶段都有明确的职责。build 阶段专注于编译和安装应用,而第二个阶段专注于运行应用。这种分离使得 Dockerfile 的逻辑更加清晰,易于理解和维护。如果需要修改构建过程,只需要修改 build 阶段;如果需要调整运行配置,只需要修改第二个阶段,相互之间的影响较小。

  • 构建效率提升

    • 原问题

    • 单阶段构建每次构建都需要重新执行所有步骤,即使某些步骤的结果在之前的构建中已经存在。例如,每次构建都需要重新安装编译工具和依赖库,浪费了时间和资源。

    • 解决方式

    • 多阶段构建可以利用 Docker 的缓存机制。如果 build 阶段的代码和配置没有发生变化,Docker 可以复用之前构建的结果,只需要重新构建有变化的部分。在第二个阶段,由于只复制必要的文件,复制操作的时间也会减少,从而提高了整体的构建效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39528.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHP回调后门分析

什么是PHP回调后门&#xff1f; PHP回调后门是指攻击者利用PHP的回调函数等技术&#xff0c;绕过WAF&#xff08;Web应用防火墙&#xff09;&#xff0c;在受攻击的PHP应用程序中插入恶意代码。这种后门可以被用来执行任意PHP代码&#xff0c;例如访问数据库、执行系统命令、窃…

vue数据重置

前言 大家在开发后台管理系统的过程中&#xff0c;一定会遇到一个表格的条件查询重置功能吧&#xff0c;如果说查询条件少&#xff0c;重置起来还算是比较简单&#xff0c;如果元素特别多呢&#xff0c;那玩意写起来可遭老罪喽&#xff0c;那今天就给大家整一个如何快速重置数…

【js逆向入门】图灵爬虫练习平台 第九题

地址&#xff1a;aHR0cHM6Ly9zdHUudHVsaW5ncHl0b24uY24vcHJvYmxlbS1kZXRhaWwvOS8 f12进入了debugger&#xff0c;右击选择一律不在此处暂停&#xff0c; 点击继续执行 查看请求信息 查看载荷&#xff0c;2个加密参数&#xff0c;m和tt 查看启动器&#xff0c;打上断点 进来 往…

OpenCV第2课 OpenCV的组成结构与图片/视频的加载及展示

1.OpenCV 的组成结构 2.OpenCV 的具体模块 3. 图像的读取 4. 视频的读取 1.OpenCV 的组成结构 OpenCV 是由很多模块组成的,这些模块可以分成很多层: 最底层是基于硬件加速层(HAL)的各种硬件优化。再上一层是opencv_contrib 模块所包含的OpenCV 由其他开发人员所贡献的代…

scNET:整合scRNA-seq和PPI用于学习基因和细胞的embedding

scRNA-seq 技术的最新进展为深入了解各种组织的异质性提供了前所未有的视角。然而&#xff0c;仅靠基因表达数据往往无法捕捉和识别细胞通路和复合物的变化&#xff0c;因为这些变化在蛋白质水平上更容易被察觉。此外&#xff0c;由于scRNA-seq数据存在高噪声水平和零膨胀等固有…

吴恩达机器学习笔记复盘(十一)逻辑回归的代价和损失函数

简介 逻辑回归是一种二分类算法&#xff0c;损失函数和代价函数和线性回归模型不同。目标是根据特征预测标签Y&#xff08;0或1&#xff09;。模型通过参数W和B拟合数据&#xff0c;但如何选择最优参数成为关键。本质上说线性回归的损失函数是对数值本身的误差平均值描述&…

ctfshow WEB web3

提示是一道php伪协议文件包含的题目&#xff0c;通过get传递的参数是 url 使用 Burp 抓包&#xff0c;发送给 Repeater 构造php伪协议&#xff0c;通过url传递 ?urlphp://input <?php system("pwd");?> 查看当前目录 <?php system("ls");?…

Windows部署deepseek R1训练数据后通过AnythingLLM当服务器创建问答页面

如果要了解Windows部署Ollama 、deepseek R1请看我上一篇内容。 这是接上一篇的。 AnythingLLM是一个开源的全栈AI客户端&#xff0c;支持本地部署和API集成。它可以将任何文档或内容转化为上下文&#xff0c;供各种语言模型&#xff08;LLM&#xff09;在对话中使用。以下是…

word中指定页面开始添加页码

第一步&#xff1a; 插入页码 第二步&#xff1a; 把光标放到指定起始页码处 第三步&#xff1a; 取消链接到前一节 此时关掉页脚先添加分节符 添加完分节符后恢复点击 第四步&#xff1a; 设置页码格式&#xff0c;从1开始 第五步&#xff1a; 删掉不要的页码&#xff0c…

多语言语料库万卷·丝路2.0开源,数据模态全面升级,搭建文化交流互鉴AI桥梁

3月22日&#xff0c;上海人工智能实验室&#xff08;上海AI实验室&#xff09;联合新华社新闻信息中心、上海外国语大学、外研在线等&#xff0c;发布全新升级的“万卷丝路2.0”多语言语料库&#xff0c;通过构建多语言开源数据底座&#xff0c;以人工智能赋能“一带一路”高质…

Windows桌面采集技术

在进入具体的方式讨论前&#xff0c;我们先看看 Windows 桌面图形界面的简化架构&#xff0c;如下图&#xff1a; 在 Windows Vista 之前&#xff0c;Windows 界面的复合画面经由 Graphics Device Interface&#xff08;以下简称 GDI&#xff09;技术直接渲染到桌面上。 在 Wi…

C# BULK INSERT导入大数据文件数据到SqlServer

BULK INSERT 的核心原理 BULK INSERT 是一种通过数据库原生接口高效批量导入数据的技术&#xff0c;其核心原理是绕过逐条插入的 SQL 解析和执行开销&#xff0c;直接将数据以二进制流或批量记录的形式传输到数据库。 在.NET中&#xff0c;主要通过 ​SqlBulkCopy 类​&#x…

Power BI嵌入应用:常见问题与调试技巧

将Power B 嵌入应用时的常见问题与调试技巧 Power BI Embedded 是一项 Microsoft Azure 服务&#xff0c;允许开发人员将交互式 Power BI 报表和仪表板嵌入到外部自定义应用程序或网站中。将Power BI嵌入应用程序能有效提升用户体验&#xff0c;但实施过程中可能面临一些典型问…

Android Studio编译问题

文章目录 GradleJDK版本不兼容 Gradle JDK版本不兼容 Incompatible because this component declares an API of a component compatible with Java 11 and the consumer needed a runtime of a component compatible with Java 8 查看module内gradle文件是否设置jdk版本&…

Four.meme是什么,一篇文章读懂

一、什么是Four.meme&#xff1f; Four.meme 是一个运行在 BNB 链的去中心化平台旨在为 meme 代币供公平启动服务。它允许用户以极低的成本创建和推出 meme 代币&#xff0c;无需预售或团队分配&#xff0c;它消除了传统的预售、种子轮和团队分配&#xff0c;确保所有参与者有…

解决PHP内存溢出问题的讨论和分析

PHP作为一种广泛使用的服务器端脚本语言&#xff0c;在处理大量数据或复杂任务时&#xff0c;常常会遇到内存溢出的问题。内存溢出不仅会导致程序崩溃&#xff0c;还可能影响服务器的稳定性。本文将探讨解决PHP内存溢出问题的最佳实践&#xff0c;并通过代码示例进行详细说明。…

git,openpnp - 根据安装程序打包名称找到对应的源码版本

文章目录 git,openpnp - 根据安装程序打包名称找到对应的源码版本概述笔记备注 - 提交时间不可以作为查找提交记录的依据END git,openpnp - 根据安装程序打包名称找到对应的源码版本 概述 想在openpnp官方最新稳定版上改一改&#xff0c;首先就得知道官方打包的安装程序对应的…

基于Spring Boot的停车场管理系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

基于Spring Boot + Vue的银行管理系统设计与实现

基于Spring Boot Vue的银行管理系统设计与实现 一、引言 随着金融数字化进程加速&#xff0c;传统银行业务向线上化转型成为必然趋势。本文设计并实现了一套基于Spring Boot Vue的银行管理系统&#xff0c;通过模块化架构满足用户、银行职员、管理员三类角色的核心业务需求…

Unity | Tag、Layer常量类生成工具

在项目开发中我们可以对诸如Layer、Tag等编辑器数据进行常量生成&#xff0c;来代替在代码中通过输入字符串生成常量的形式以提高开发效率。 Layer的生成可以通过LayerMask.LayerToName获取层名称&#xff08;也可以从TagManager.asset中获得 &#xff09;&#xff0c;Tag的生成…