1.01.Alpine编译glibc
概要
本文档采用glibc2.28版本作为示例,模拟内网环境无法访问github等开源社区
为精简docker容器镜像,采用Alpine镜像,需要手动编译glibc源代码
制作编译好的glibc二进制文件
获取glibc二进制文件构建工具
# 内网环境可下载该工具包手动上传到服务器 git pull https://github.com/sgerrand/docker-glibc-builder.git
该构建工具中需要采用wget命令从第三方仓库下载glibc源代码,由于内网环境无法访问第三方仓库,我们需要对构建工具做一些修改
修改Dockerfile
本例采用修改过的openeuler-x86镜像,在原生的基础上安装了一些常用的命令例如vim
、tar
、telnet
等
FROM euleros-x86:202405V1 ENV DEBIAN_FRONTEND=noninteractive \ GLIBC_VERSION=2.28 \ PREFIX_DIR=/usr/glibc-compat COPY configparams /glibc-build/configparams COPY builder /builder # 内网环境 手动下载glibc源代码上传至根目录 COPY glibc-2.28.tar.gz /glibc-2.28.tar.gz # gcc bison make m4 都是编译所必须的命令 RUN yum -y install gcc bison make m4 ENTRYPOINT ["/builder"]
修改bulider脚本
#!/usr/bin/env bash set -eo pipefail; [[ "$TRACE" ]] && set -x main() { # 声明 version 和 prefix 如果不存在入参指定version和prefix就使用环境变量 GLIBC_VERSION 和 PREFIX_DIR declare version="${1:-$GLIBC_VERSION}" prefix="${2:-$PREFIX_DIR}" : "${version:?}" "${prefix:?}" { # 此处只删除了使用wget从第三方仓库下载glibc的步骤 tar zxf /glibc-$version.tar.gz mkdir -p /glibc-build && cd /glibc-build "/glibc-$version/configure" \ --prefix="$prefix" \ --libdir="$prefix/lib" \ --libexecdir="$prefix/lib" \ --enable-multi-arch \ --enable-stack-protector=strong make && make install tar --dereference --hard-dereference -zcf "/glibc-bin-$version.tar.gz" "$prefix" } >&2 [[ $STDOUT ]] && cat "/glibc-bin-$version.tar.gz" } main "$@"
构建编译glibc的镜像
# 首先进入Dockerfile文件同级目录 docker build -t "euler-glibc:2.28" .
运行 euler-glibc:2.28 镜像
# docker run --rm --env STDOUT=1 euler-glibc:2.28 {version} {prefix} > glibc-bin.tar.gz # 上述命令的 {version} 和{prefix}即 builder脚本的入参,如果在Dockerfile中写好了环境变量,这两个值可以不要 # 直接运行该镜像,编译时间可能比较长,要稍微等待一段时间 docker run --rm --env STDOUT=1 euler-glibc:2.28 > glibc-bin.tar.gz # 编译完成就会在当前文件夹内获得 名为 glibc-bin.tar.gz 的 libc二进制文件
制作alpine镜像apk包
获取apk包构建工具
# 内网环境同样手动下载 2.28 版本APKBUILD 有问题,建议直接使用2.35版本 git https://github.com/sgerrand/alpine-pkg-glibc.git
获取alpine镜像并配置apk源
构建apk包需要用的apk-sdk,apk是alpine的包管理工具,此处需要获取一个alpine镜像并配置apk仓库地址。
-
获取alpine镜像
可以直接从dockerhub拉取一个和alpine镜像,也可以下载rootfs自己构建,此处不赘述拉取过程 -
配置apk源
# 此处是我自己构建的alpine镜像所以tag是v1,具体名字根据实际的填写 FROM alpine:v1 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && apk update && apk add build-base alpine-sdk 编写完成Dockerfile之后构建该镜像并命名为
alpine:v2
修改APKBUILD文件
# Maintainer: Sasha Gerrand <alpine-pkgs@sgerrand.com> pkgname="glibc" pkgver="2.28" _pkgrel="0" pkgrel="0" pkgdesc="GNU C Library compatibility layer" arch="x86" url="https://github.com/sgerrand/alpine-pkg-glibc" license="LGPL" source="$pkgname-bin.tar.gz nsswitch.conf ld.so.conf" subpackages="$pkgname-bin $pkgname-dev $pkgname-i18n" triggers="$pkgname-bin.trigger=/lib:/usr/lib:/usr/glibc-compat/lib" package() { echo "----------------------------package start" echo "$pkgdir $srcdir $builddir" mkdir -p "$pkgdir/lib" "$pkgdir/usr/glibc-compat/lib/locale" "$pkgdir"/usr/glibc-compat/lib64 "$pkgdir"/etc cp -a "$srcdir"/usr "$pkgdir" cp "$srcdir"/ld.so.conf "$pkgdir"/usr/glibc-compat/etc/ld.so.conf rm "$pkgdir"/usr/glibc-compat/etc/rpc rm -rf "$pkgdir"/usr/glibc-compat/bin rm -rf "$pkgdir"/usr/glibc-compat/sbin rm -rf "$pkgdir"/usr/glibc-compat/lib/gconv rm -rf "$pkgdir"/usr/glibc-compat/lib/getconf rm -rf "$pkgdir"/usr/glibc-compat/lib/audit rm -rf "$pkgdir"/usr/glibc-compat/share rm -rf "$pkgdir"/usr/glibc-compat/var ln -s /usr/glibc-compat/lib/ld-linux-x86-64.so.2 ${pkgdir}/lib/ld-linux-x86-64.so.2 ln -s /usr/glibc-compat/lib/ld-linux-x86-64.so.2 ${pkgdir}/usr/glibc-compat/lib64/ld-linux-x86-64.so.2 ln -s /usr/glibc-compat/etc/ld.so.cache ${pkgdir}/etc/ld.so.cache echo "----------------------------package end" } bin() { echo "----------------------------bin start" depends="$pkgname libgcc" mkdir -p "$subpkgdir"/usr/glibc-compat cp -a "$srcdir"/usr/glibc-compat/bin "$subpkgdir"/usr/glibc-compat cp -a "$srcdir"/usr/glibc-compat/sbin "$subpkgdir"/usr/glibc-compat echo "----------------------------bin end" } i18n() { echo "----------------------------i18n start" depends="$pkgname-bin" arch="noarch" mkdir -p "$subpkgdir"/usr/glibc-compat cp -a "$srcdir"/usr/glibc-compat/share "$subpkgdir"/usr/glibc-compat echo "----------------------------i18n end" }
编写构建apk包的Dockerfile
FROM alpine:v2 LABEL maintainer="su.yingjun" email="i9xswanan@gmail.com" VOLUME ["/home/docker/alpine-pkg-glibc","/tmp"] # 创建构建用户 RUN adduser -D packager && addgroup packager abuild && echo 'packager ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/packager && chmod o+w /tmp #RUN adduser -D -s /bin/sh build && echo "build:build2024" | chpasswd && adduser build abuild && apk add alpine-sdk build-base abuild cmake git COPY APKBUILD /home/packager/APKBUILD COPY glibc-bin.tar.gz /home/packager/glibc-bin.tar.gz COPY glibc-bin.trigger /home/packager/glibc-bin.trigger COPY ld.so.conf /home/packager/ld.so.conf COPY nsswitch.conf /home/packager/nsswitch.conf USER packager WORKDIR /home/packager RUN abuild-keygen -n --append --install
dockerbuild -t alpine-apk-build:v1 .
运行构建apk包容器
# 此处挂载目录的原因是方便取出apk包和公钥文件,也可以使用docker cp取出 docker run --rm -it -v /home/docker/alpine-pkg-glibc:/tmp alpine-apk-build:v1 sh # 下方为登录容器后的命令 保证处于 /home/packager 目录下 abuild checksum abuild -r # 执行完成之后会在构建目录下出现 packages目录,该目录中存放打包好的apk文件,公钥文件存放在当前用户家目录下的.abuild 文件夹中,执行cp命令拷贝到挂载的目录中 cp ~/.abuild/*.rsa.pub ~/packages/glibc*.apk /tmp # 退出容器 exit
参考资料
- GNU下载地址
- https://github.com/sgerrand/alpine-pkg-glibc
- https://github.com/sgerrand/docker-glibc-builder
- Alpine apk源
- Alpine Wiki
- https://www.youtube.com/watch?v=ibeqoQpO33w&t=697s
附录
abuild -r 构建流程
abuild
是 Alpine Linux 的构建工具,用于构建 APK 包。执行 abuild -r
命令的全流程涉及多个步骤,包括准备构建环境、构建包、运行测试和创建最终的 APK 包。以下是 abuild -r
的详细流程:
1. 准备构建环境
更新并安装依赖
abuild
会根据APKBUILD
文件中的依赖定义安装构建所需的包。
初始化环境变量
- 设置必要的环境变量,如
srcdir
、builddir
、pkgdir
等。
2. 提取源代码
- 下载源代码:根据
APKBUILD
文件中的source
字段下载源代码和补丁文件。 - 校验文件完整性:通过校验和文件(如
sha512sums
)验证下载的文件是否完整。 - 解压源代码:将下载的源代码文件解压到
srcdir
。
3. 运行构建流程
prepare()
函数
- 这是一个可选的函数,用于在实际构建之前应用补丁或进行其他准备工作。
build()
函数
- 执行构建过程。这通常包括配置、编译和链接源代码。
- 具体步骤由
APKBUILD
文件中的build()
函数定义。例如,可能使用./configure
脚本、make
命令等。
4. 安装步骤
package()
函数
- 安装构建好的文件到
pkgdir
。 - 设置文件的权限和属性。
- 安装文档文件(如
README
、LICENSE
等)。
5. 创建 APK 包
abuild
会将pkgdir
中的内容打包成一个 APK 文件。- 生成的 APK 文件会放在
packages
目录下。
6. 签名 APK 包
- 如果你有签名密钥,
abuild
会对生成的 APK 包进行签名。签名密钥通常存储在~/.abuild/
目录中。
7. 运行测试(可选)
abuild
也可以运行测试(如果定义了check()
函数)。这通常在构建后执行,用于验证包的正确性。
8. 清理
- 清理临时文件和目录,确保构建环境干净。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异