使用Alpine作为基础镜像的最佳实践
使用Alpine作为基础镜像的最佳实践
在基于Tekton或Jenkins的DevOps环境中,如何高效管理工具镜像一直是一个挑战。本文将探讨如何通过选择Alpine作为基础镜像,并解决其带来的稳定性与兼容性问题,来优化工具镜像的维护与使用。
背景
在基于Tekton或Jenkins的构建引擎中,通常需要内置一些工具类镜像,这些镜像包含必要的二进制工具,如Git、Ansible、Helm、yq、jq等。随着时间的推移,这些工具镜像往往会变得庞大且难以维护,主要问题在于每次修改镜像版本时,都需要对所有使用该镜像的任务进行回归测试。
为了解决这个问题,可以考虑为不同任务配置专门的镜像,将这些CLI工具拆分到对应任务的小镜像中,这样可以缩小回归测试的范围,同时也能更快地修复漏洞。
要求
在为任务创建专用镜像时,需要满足以下需求:
- 镜像体积尽可能小
- 镜像包含的漏洞尽可能少
- 支持多架构(amd64与arm64)
- 稳定性,确保每次构建出来的制品都是一样的
- 兼容性,兼容之前的任务功能
基础镜像选择
目前可选的基础镜像主要有以下几种:
基础镜像 | 大小 | 包管理工具 | 架构支持 | 漏洞情况 |
---|---|---|---|---|
Ubuntu | 71M | apt | amd64/arm64 | 存在漏洞 |
Alpine | 7.8M | apk | amd64/arm64 | 存在漏洞 |
Distroless | 2.6M | 无 | amd64/arm64 | 无 |
从体积和包管理工具的便利性来看,Alpine成为最佳选择。虽然Distroless体积更小,但缺乏包管理工具,而Ubuntu体积过大。Alpine的包管理工具apk在安装某些工具时比Ubuntu的apt更方便,例如Ansible可以直接通过apk add
安装。
稳定性问题
为了保证镜像构建的稳定性,在通过apk add
安装二进制工具时,需要指定工具的版本,防止每次构建都安装最新版本导致兼容性问题。但是直接指定版本号会带来定时炸弹风险,因为Alpine社区会删除旧版本工具,导致安装命令失败。
为了解决这个问题,可以采用以下几种方法:
使用Stable版本的库
将旧版本仓库地址写入/etc/apk/repositories
文件中,然后通过package filter获取旧版本工具的确切版本号。例如:
RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.2/main' >> /etc/apk/repositories
指定版本号范围
通过指定版本号范围来避免大版本改动带来的兼容性问题。例如:
RUN apk add --no-cache "ansible<=9.6"
本地安装
将需要的包下载到Nexus仓库中,然后在构建镜像时下载并安装。例如:
apk add --allow-untrusted /path/to/file.apk
兼容性问题
Alpine中的二进制工具依赖于BusyBox提供的能力,这些工具是阉割版本,可能会缺少一些执行参数和相关能力。例如,Alpine中的tar
命令支持的参数远少于Ubuntu中的tar
命令。为了解决这个问题,需要重新安装完整的工具版本。
参考资料
- Alpine Packager Filter
- 如何在Alpine中安装特定版本的包
- Alpine、Busybox、Distroless:谁才是容器基础镜像的真正王者?