优化 Docker 镜像大小常见方法
平时我们构建的 Docker 镜像通常比较大,占用大量的磁盘空间,随着容器的大规模部署,同样也会浪费宝贵的带宽资源。本文将介绍几种常用的方法来优化 Docker 镜像大小,这里我们使用 Docker Hub 官方上的 Redis 镜像进行说明。
手动管理
我们能够直接想到的方法就是直接修改官方的 Redis 镜像 Dockerfile 文件,手动删除容器运行后不需要的组件,然后重新构建一个新镜像。这种方法理论上是可行的,但是容易出错,而且效果也不是特别明显。主要是不能和官方的镜像实时同步。
多阶段构建
Docker 在17.05 版本起提供了多阶段构建的功能来解决这个问题,这种方法是通过丢弃中间层来实现的,并通过中间层来提供有关如何创建最终镜像及其内容信息来完成的,只需要保留容器化应用所需的组件即可。在更上层的实现如下所示:
以一些镜像作为构建的基础
和平常一样运行命令来构造你的应用
将所需的制品复制到另外一个单独的镜像
Distroless
在严重依赖容器化技术,尤其是 Docker 之后,谷歌早就意识到了使用臃肿镜像的弊端。所以他们提供了自己的方法来解决这个问题,即 distroless 镜像。与典型的Linux 基础镜像(绑定了很多软件)不同,在 distroless 上对你的应用进行 docker化,最终的镜像只包含应用及其运行时的依赖项,大多数 Linux 发行版中包含的标准软件,如包管理器,甚至 shell 都被会被排除在外。
同样的,要使用 Google 的 distroless 镜像,需要使用上面我们提到的多阶段构建,如下所示:
FROM redis:latest AS build
ARG TIME_ZONE
RUN mkdir -p /opt/etc && \
cp -a --parents /lib/x86_64-linux-gnu/libm.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc.so.* /opt && \
cp -a --parents /usr/local/bin/redis-server /opt && \
cp -a --parents /usr/local/bin/redis-sentinel /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-UTC} /opt/etc/localtime
FROM gcr.io/distroless/base
COPY --from=build /opt /
VOLUME /data
WORKDIR /data
ENTRYPOINT ["redis-server"]
使用redis:latest为基础镜像,然后保留需要的一些二进制文件(redis-server二进制文件以及所有的相关依赖),然后使用 distroless 镜像作为构建的最终镜像的基础,将opt目录内容复制到该镜像目录中来。
然后我们只需要重新构建镜像即可:
$ docker build -t redis:distroless .
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
redis distroless 7d50bd873bea 15 seconds ago 28.2MB
redis latest 1319b1eaa0b7 3 days ago 104MB
我们可以看到镜像由以前的 104MB 变成了 28.2MB,大大降低了镜像的大小。
注意:在 Linux 下面我们可以使用 ldd 工具来查找指定的二进制文件所需要的依赖,比如
$ ldd $(which redis-server)。
使用 distroless 镜像来降低 Docker 镜像的大小是一个非常有效的方法,但是这样做也有一个明显的缺点就是最终的镜像中没有 shell 程序了,使得调试 Docker 容器就非常非常困难,当然这样也降低了应用被攻击的危险,使其更加安全,如果我们将应用部署到 Kubernetes 集群的话,我们可以利用 kubectl-debug 这样的工具来辅助调试应用。
Alpine Linux
另外一种比较常见的方式是选择在 Alpine Linux 基础上构建应用镜像,Alpine Linux 是一个特别适合创建最小化 Docker 镜像的发行版。Apline Linux 使用较小的 musl C 库代替 glibc,并将其静态链接,这意味着针对 musl 编译的程序将变成可重定位的 (relocatable)的二进制文件,从而无需包含共享对象,从而可以显著降低镜像的大小。
redis:alpine 镜像大概为 30MB 左右,这样做的缺点是,通常 musl 的性能不如 glibc。当然也有另外一个好处,那就是和上面的 distroless 相比,Alpine 是成熟的 Linux 发行版,提供基本的 shell 访问,使得调试 Docker 容器应用更为方便。在 Docker Hub 上面也可以找到几乎所有流行软件的 Alpine 版本,比如 Redis、Nginx、MySQL 等等。
GNU Guix
最后,我们可以使用 GNU Guix,一个多功能的软件包管理工具,其中就有一项可以创建 Docker 镜像的功能。Guix 区分了包的运行时依赖与构建依赖,所以 Guix 构建的 Docker 镜像将只包含明确指定的程序,加上他们的运行时依赖,就像 distroless 的方法一样。但和 distroless 不同的时候,distroless 需要你自己去查程序的运行时依赖关系(当然也要写 Dockerfile),而 Guix 只需要运行一条命令即可:$ guix pack -f docker redis 。
通过上面的命令创建的 Redis 镜像大小约为 70MB,和原本的镜像相比有明显的减少,虽然比 distroless 和 Alpine 方法创建的镜像稍大,但使用 Guinx 确实提供了一些其他的优点。比如,如果你想让你的最终镜像也包含一个 shell,以便像 Alpine 那样去调试,那么只需要在 Guxi 打包的时候指定上就可以了:$ guix pack -f docker redis bash ,如果你想包含其他软件,也可以继续在后面添加即可。
Guix 的功能特性意味着包的构建可以100%复用,所以我们可以在 CI/CD 流水线管道中加入 Guix 支持,这样构建过程就非常顺畅了。
有的人可能会觉得 Guix 听起来很酷,但是并不想为了构建更小的 Docker 镜像而去下载安装另外一个工具,更何况 Guix 只在 Linux 下面工作,很多开发者还是 MacOS 用户,去配置 Guix 也挺麻烦。其实这点并不用担心,Guix 本身也有 Docker 镜像在 Docker Hub 上,所以使用起来也并不会太复杂,只需要简单的使用 $ docker run guix 命令即可。
除了 Guix 之外,值得一提的还有一个名为 Nix 的软件包管理工具,对 Guix 所述的每一点都同样有效并且适用于 Nix。
原文链接
https://docs.docker.com/develop/develop-images/multistage-build/
https://github.com/GoogleContainerTools/distroless
https://alpinelinux.org/
http://guix.gnu.org/
https://appfleet.com/blog/methods-optimize-docker-image-size/
- End -
关注「开源Linux」加星标,提升IT技能
好文章,分享、点赞、在看三连哦️↓↓↓
优化 Docker 镜像大小常见方法的更多相关文章
- 深刻理解Docker镜像大小
都说容器大法好,可是假设没有Docker镜像,Docker该是多无趣啊. 是否还记得第一个接触Docker的时候,你从Docker Hub下拉的那个镜像呢?在那个处女镜像的基础上.你执行了容器生涯的处 ...
- 简单谈谈Docker镜像的使用方法_docker
在上篇文章(在Docker中搭建Nginx服务器)中,我们已经介绍了如何快速地搭建一个实用的Nginx服务器.这次我们将围绕Docker镜像(Docker Image),介绍其使用方法.包括三部分: ...
- Docker容器技术-优化Docker镜像
一.优化Docker镜像 1.降低部署时间 一个大的Docker应用是如何影响在新Docker宿主机上的部署时间. (1)编写Dockerfile创建一个大Docker镜像 [root@bogon ~ ...
- docker镜像的创建方法docker file方式
什么是docker file文件? 简单来说,docker file文件就是一个命令文本集合,容来记录创建docker镜像的步骤 快速入门: 1.新建一个docker file文件dockerfile ...
- docker镜像的创建方法docker commit方式
Docker 提供了两种构建镜像的方法: docker commit 命令(交互式修改创建) Dockerfile 构建文件 (文本命令定义) Docker commit方法: 1.运行一个现有容器 ...
- JAVA SpringBoot 项目打包(JAR),在打包成 docker 镜像的基本方法
1,打包 SpringBoot 项目,使用 IDEA 如下图 2,将 JAR 包上传到安装了 Docker 的 linux 服务器上,并且在相容目录下创建一个名为 Dockerfile 的文件 3,在 ...
- Dockerfile减少构建镜像大小的方法
这几天基于Dockerfile构建应用需要的特殊的镜像,比如Nginx需要add很多module的,就需要在镜像内编译和做build. 通过Dockerfile构建镜像时,很容易把镜像构建得很大. 从 ...
- .NET 5.0 Docker 镜像 错误修复方法
在给eshopondapr 打镜像的时候碰到了3个错误 1.restore: Received an unexpected EOF or 0 bytes from the transport stre ...
- Docker镜像优化
前言 上篇博文说到使用Visual Studio Tools for Docker帮助我们生成Dockerfile,现在我们讨论下生成的Dockerfile的优劣. 一.以往Dockerfile构建模 ...
随机推荐
- Springmvc入门基础(六) ---拦截器应用demo
1.拦截器定义 Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理. 2.拦截器demo demo需求: 拦截用户请求,判断用 ...
- 在虚拟机里面安装mysql
https://dev.mysql.com/downloads/repo/yum/ 首先到网站里面下载 mysql80-community-release-el7-3.noarch.rpm 通过xft ...
- 学习Walle(一)
一.概述 Walle 一个web部署系统工具,配置简单.功能完善.界面流畅.开箱即用!支持git.svn版本管理,支持各种web代码发布,PHP,Python,JAVA等代码的发布.回滚,可以通过we ...
- PID控制算法的C语言实现
参考: PID控制器开发笔 浅谈位置式PID 专家PID控制在快速系统中的仿真及应用(这篇了论文介绍的积分分离PID.专家PID(脚本实现和simulink实现)很详细) PID控制算法的C语言实现一 ...
- HTML5与HTML4区别简介
移动互联网的快速发展,尤其是4G时代已经来临,加上微软在Windows 10中搭载了新的浏览器Edge取代了IE的地位,所以现在很多网站都开始抛弃IE朝着HTML5发展,PC端在不同浏览器之间的兼容性 ...
- 判断页面环境是否在小程序的webview中
最近公司需要做小程序项目,但是又希望能够快速开发,就想着把web端的响应式页面放到webview里快速开发.但在判断页面环境的时候出现一些问题. 环境问题 用小程序提供的wx.miniProgram. ...
- 【promise| async/await】代码的控制力
什么样的代码好控制? 结构 + 节奏 --- 什么鬼? 如何控制节奏? 具体例子看看怎么控制节奏?
- vue2.0开发聊天程序(八) 初步完成
项目地址 服务器源码地址:https://github.com/ermu592275254/chat-socket 网页源码地址:https://github.com/ermu592275254/ch ...
- 实验 3 Spark 和 Hadoop 的安装
1. 安装 Hadoop 和 Spark 进入 Linux 系统,参照本教程官网"实验指南"栏目的"Hadoop 的安装和使用",完成 ...
- 【uniapp 开发】uni-app 技术点的链接记录
优雅的H5下拉刷新.零依赖,高性能,多主题,易拓展 https://ask.dcloud.net.cn/article/12772 图像(头像)选择,截取,压缩,上传的分享 https://ask.d ...