01.Alpine编译glibc

概要

本文档采用glibc2.28版本作为示例,模拟内网环境无法访问github等开源社区

为精简docker容器镜像,采用Alpine镜像,需要手动编译glibc源代码

制作编译好的glibc二进制文件

获取glibc二进制文件构建工具

bash 复制代码
# 内网环境可下载该工具包手动上传到服务器
git pull https://github.com/sgerrand/docker-glibc-builder.git

该构建工具中需要采用wget命令从第三方仓库下载glibc源代码,由于内网环境无法访问第三方仓库,我们需要对构建工具做一些修改

修改Dockerfile

本例采用修改过的openeuler-x86镜像,在原生的基础上安装了一些常用的命令例如vimtartelnet

dockerfile 复制代码
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脚本

bash 复制代码
#!/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的镜像

bash 复制代码
# 首先进入Dockerfile文件同级目录
docker build -t "euler-glibc:2.28" .

运行 euler-glibc:2.28 镜像

bash 复制代码
# 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包构建工具

bash 复制代码
# 内网环境同样手动下载 2.28 版本APKBUILD 有问题,建议直接使用2.35版本
git https://github.com/sgerrand/alpine-pkg-glibc.git

获取alpine镜像并配置apk源

构建apk包需要用的apk-sdk,apk是alpine的包管理工具,此处需要获取一个alpine镜像并配置apk仓库地址。

  1. 获取alpine镜像

    可以直接从dockerhub拉取一个和alpine镜像,也可以下载rootfs自己构建,此处不赘述拉取过程

  2. 配置apk源

    dockerfile 复制代码
    # 此处是我自己构建的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文件

bash 复制代码
# 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

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包容器

bash 复制代码
# 此处挂载目录的原因是方便取出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

参考资料

  1. GNU下载地址
  2. https://github.com/sgerrand/alpine-pkg-glibc
  3. https://github.com/sgerrand/docker-glibc-builder
  4. Alpine apk源
  5. Alpine Wiki
  6. https://www.youtube.com/watch?v=ibeqoQpO33w&t=697s

附录

abuild -r 构建流程

abuild 是 Alpine Linux 的构建工具,用于构建 APK 包。执行 abuild -r 命令的全流程涉及多个步骤,包括准备构建环境、构建包、运行测试和创建最终的 APK 包。以下是 abuild -r 的详细流程:

1. 准备构建环境

更新并安装依赖

  • abuild 会根据 APKBUILD 文件中的依赖定义安装构建所需的包。

初始化环境变量

  • 设置必要的环境变量,如 srcdirbuilddirpkgdir 等。

2. 提取源代码

  • 下载源代码:根据 APKBUILD 文件中的 source 字段下载源代码和补丁文件。
  • 校验文件完整性:通过校验和文件(如 sha512sums)验证下载的文件是否完整。
  • 解压源代码:将下载的源代码文件解压到 srcdir

3. 运行构建流程

prepare() 函数

  • 这是一个可选的函数,用于在实际构建之前应用补丁或进行其他准备工作。

build() 函数

  • 执行构建过程。这通常包括配置、编译和链接源代码。
  • 具体步骤由 APKBUILD 文件中的 build() 函数定义。例如,可能使用 ./configure 脚本、make 命令等。

4. 安装步骤

package() 函数

  • 安装构建好的文件到 pkgdir
  • 设置文件的权限和属性。
  • 安装文档文件(如 READMELICENSE 等)。

5. 创建 APK 包

  • abuild 会将 pkgdir 中的内容打包成一个 APK 文件。
  • 生成的 APK 文件会放在 packages 目录下。

6. 签名 APK 包

  • 如果你有签名密钥,abuild 会对生成的 APK 包进行签名。签名密钥通常存储在 ~/.abuild/ 目录中。

7. 运行测试(可选)

  • abuild 也可以运行测试(如果定义了 check() 函数)。这通常在构建后执行,用于验证包的正确性。

8. 清理

  • 清理临时文件和目录,确保构建环境干净。
相关推荐
TsengOnce1 小时前
Docker 安装 禅道-21.2版本-外部数据库模式
运维·docker·容器
无为扫地僧2 小时前
三、ubuntu18.04安装docker
ubuntu·docker
谷莠子9053 小时前
hadoop实验之创业有感
hadoop·docker·团队开发
G丶AEOM3 小时前
Docker快速入门
docker
大熊程序猿4 小时前
airflow docker 安装
运维·docker·容器
带电的小王5 小时前
Docker在Ubuntu上安装
ubuntu·docker
fanruitian5 小时前
docker 为单个容器设置代理
运维·docker·容器
梁萌5 小时前
Docker快速安装Tomcat
docker·容器·tomcat·镜像
Doker 多克7 小时前
IntelliJ IDEA Docker集成
spring cloud·docker·intellij-idea
筏镜14 小时前
调整docker bridge地址冲突,通过bip调整 bridge地址
java·docker·eureka