概要

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

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

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

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

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

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

修改Dockerfile

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

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仓库地址。

  1. 获取alpine镜像

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

  2. 配置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

参考资料

  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. 清理

  • 清理临时文件和目录,确保构建环境干净。

01.Alpine编译glibc的更多相关文章

  1. alpine编译安装tengine,并使用supervisor启动

    Alpine是一个小型的linux系统,官方docker镜像只有不到5MB,非常适合作为容器镜像. Alpine Linux is a security-oriented, lightweight L ...

  2. uboot-2012.04.01移植编译前准备

    一:准备移植1.从下面的官网下载uboot-2012.04.012.建立sourceinsight工程 a.解压并在E:\colin weidongshan\transplant_u-boot-201 ...

  3. uboot 2013.01 s3c6400编译失败

    通常我们对s3c6410平台开发u-boot是在s3c6400的基础上修改而成的,但是从uboot 2013.01这个版本之后的版本都把smdk6400对应的配置给删除了. 这是因为该版本smdk64 ...

  4. [笔记]Modelsim系列01:编译Altera库的方法

    意义:一劳永逸,不用每次对那些包含Quartus II生成文件的工程进行功能仿真时,都需要重新编译一堆东西.节约时间成本. 版本:ModelSim SE 6.5d 打开Modelsim软件,默认会打开 ...

  5. 深入理解Java虚拟机 #01# 自己编译JDK

    x 首先用书上的脚本尝试,失败. 之后根据源文件的 README 编译,抛出: root@linux:/opt/openjdk# sh ./get_source.sh ERROR: Need init ...

  6. 在openwrt 17.01上编译最新nginx 1.14.2的笔记

    openwrt 17.01源码对应的nginx版本是1.10.2,有些新功能没有,所以需要升级到nginx 1.14.2最新的稳定版 https://github.com/macports/macpo ...

  7. 如何使用新的glibc来编译自己的程序

    http://www.sysnote.org/2015/08/25/use-new-glibc/ 通常情况下我们都是直接使用glibc提供的一些库函数,但是某些特殊的情况,比如要修改glibc的一些代 ...

  8. 009全志R16平台tinav3.0下编译不过的问题

    009全志R16平台tinav3.0下编译不过的问题 2018/11/13 11:39 版本:V1.0 开发板:SC3817R SDK:tina v3.0 1.01原始编译全志r16平台tinav3. ...

  9. 编译软件基础知识(1/2) via LinuxSir

    内容来自LinuxSir: 如果不出意外的话,会出现say.so => not found. 这时的./test是不能运行的.但至少说明程序运行时是需要这个库的.那为什么找不到这个库呢?那就让我 ...

  10. X86上搭建交叉工具链,来给龙芯笔记本编译本地工具链(未完待续)

    故事的背景是,我买了一台龙芯2F的笔记本来装B. 为什么说是装B呢?因为不但操作系统是Linux,而且CPU还是龙芯的. 一般人有这么酷的装备吗?简直是装B大圣啊. 这里一定要申明一点,本人不是IT技 ...

随机推荐

  1. Linux命令之查找CPU资源利用情况(lscpu和top详解)

    1.lscpu命令:获取CPU架构完整详细信息,例如架构信息,CPU模式,CPU频率,CPU核心数.线程数.缓存大小. 在终端输入"lscpu": 参数详解: [Architect ...

  2. 谢老师2024春 - Day1:组合数学

    Day1:组合数学 A - P5520 [yLOI2019] 青原樱 隔板法: 已选择的位置:\(m\) 棵樱花树. 未选择的位置:\(n-m\) 个空位置 板的数量(一棵樱花树就是一个板):\(m\ ...

  3. 云钉一体:EventBridge 联合钉钉连接器打通云钉生态

    ​简介:今天,EventBridge 联合钉钉连接器,打通了钉钉生态和阿里云生态,钉钉的生态伙伴可以通过通道的能力驱动阿里云上海量的计算力. 作者:尘央 背景 "以事件集成阿里云,从 Eve ...

  4. Serverless Kubernetes 落地实践

    ​简介:如何通过原生 Kubernetes 提供 Serverless 能力?如何借力丰富的云原生社区生态?本文将给大家介绍一下我们在 Serverless Kubernetes 上的落地实践. 作者 ...

  5. Dataphin核心功能(四):安全——基于数据权限分类分级和敏感数据保护,保障企业数据安全

    简介:<数据安全法>的发布,对企业的数据安全使用和管理提出了更高的要求.Dataphin提供基于数据分级分类和数据脱敏的敏感数据识别和保护能力,助力企业建立合规的数据安全体系,保障企业数据 ...

  6. 日志审计携手DDoS防护助力云上安全

    ​简介: 本文主要介绍日志审计结合DDoS防护保障云上业务安全的新实践. 日志审计携手DDoS防护助力云上安全 1 背景介绍 设想一下,此时你正在高速公路上开车去上班,路上还有其他汽车,总体而言,大家 ...

  7. 用python编写向通信产品发送AT指令的程序实例

    一.安装pyserial包pip install pyserial 二.实例代码 # -*- coding: utf-8 -*- import time import hashlib from ser ...

  8. UOS 开启 VisualStudio 远程调试 .NET 应用之旅

    本文记录的是在 Windows 系统里面,使用 VisualStudio 2022 远程调试运行在 UOS 里面 dotnet 应用的配置方法 本文写于 2024.03.19 如果你阅读本文的时间距离 ...

  9. Mysql带条件取多条随机记录

    有个文章段落表part,有两种类型的段落,即part_type取1或2,要从表中随机取多条任意类型的段落,比如3条. 方法一 ORDER BY后接RAND() select * from part w ...

  10. 有意思!一个关于 Spring 历史的在线小游戏

    发现 Spring One 的官网上有个好玩的彩蛋,分享给大家! 进到Spring One的官网,可以看到右下角有个类似马里奥游戏中的金币图标. 点击该金币之后,会打开一个新的页面,进入下面这样一个名 ...