01.Alpine编译glibc

alpine,glibc · 浏览次数 : 0

小编点评

**Dockerfile** ```dockerfile FROM alpine:v2 LABEL maintainer="su.yingjun" email="i9xswanan@gmail.com" # 创建构建用户 adduser -D packager & addgroup packager abuild & echo 'packager ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/packager chmod o+w /tmp # 创建build用户 adduser build -D -s /bin/sh build & echo "build:build2024" | chpasswd adduser build abuild & apk add alpine-sdk build-base abuild cmake gitCOPY APKBUILD /home/packager/APKBUILDCOPY glibc-bin.tar.gz /home/packager/glibc-bin.tar.gzCOPY glibc-bin.trigger /home/packager/glibc-bin.triggerCOPY ld.so.conf /home/packager/ld.so.confCOPY nsswitch.conf /home/packager/nsswitch.conf USER packagerWORKDIR /home/packager # 运行构建apk包容器 RUN abuild-keygen -n --append --installdockerbuild -t alpine-apk-build:v1 . RUN docker build --rm -it -v /home/docker/alpine-pkg-glibc:/tmp alpine-apk-build:v1 sh #挂载目录的原因 VOLUME [\"/home/docker/alpine-pkg-glibc\",\"/tmp\"]# 创建挂载目录,方便取出apk包和公钥文件 # 登录容器 RUN container_id=$(docker ps -q | grep -o id).split(':')[1] docker exec -it --user alpine $container_id bash # 执行构建流程 RUN abuild -r ``` **构建流程** 1. 准备构建环境更新并安装依赖abuild。 2. 提取源代码下载源代码和补丁文件。 3. 运行构建流程prepare() 函数,应用补丁或进行其他准备工作。 4. 安装构建好的文件到 pkgdir。 5. 创建 APK 包。 6. 签名 APK 包。 7. 运行测试(可选)。 8. 清理清理临时文件和目录,确保构建环境干净。

正文

概要

本文档采用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相似的内容:

01.Alpine编译glibc

概要 本文档采用glibc2.28版本作为示例,模拟内网环境无法访问github等开源社区 为精简docker容器镜像,采用Alpine镜像,需要手动编译glibc源代码 制作编译好的glibc二进制文件 获取glibc二进制文件构建工具 # 内网环境可下载该工具包手动上传到服务器 git pull

Python性能测试框架:Locust实战教程

01认识Locust Locust是一个比较容易上手的分布式用户负载测试工具。它旨在对网站(或其他系统)进行负载测试,并确定系统可以处理多少个并发用户,Locust 在英文中是 蝗虫 的意思:作者的想法是在测试期间,放一大群 蝗虫 攻击您的网站。当然事先是可以用 Locust 定义每个蝗虫(或测试用

大厂内部的压测方案设计分享!

01为什么要做压测 1、什么是压力测试? 不断向被测对象施加压力,测试系统在压力情况下的表现。 2、压力测试的目的是什么? 测试得出系统的极限性能指标,从而给出合理的承诺值或者容量告警; 找出系统的性能瓶颈,对性能做出优化; 测试系统在高负载情况下的稳定性; 验证系统在过载情况下的限流和降级预案;

背包DP

01 背包 \(01\) 的意图很明显,就是每个物品有 \(01\),即 选 和 不选 两种方式。 暴力 考虑设定一个状态 \(dp[i][j]\) 表示在前 \(i\) 个当中,花费为 \(j\) 所能获得的最大值。 转移可以: \(dp_{i,j}=\max(dp_{i-1,j},dp_{i-1

01_斐波那契数列

509. 斐波那契数 斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1 给你n ,请计算 F(n)

云原生最佳实践系列 6:MSE 云原生网关使用 JWT 进行认证鉴权

01 方案概述 MSE 网关可以为后端服务提供转发路由能力,在此基础上,一些敏感的后端服务需要特定认证授权的用户才能够访问。MSE 云原生网关致力于提供给云上用户体系化的安全解决方案,其中 JWT 认证能力是在 Json Web Token 这种结构化令牌的基础上实现了一套基于用户体系对用户的 AP

01.前后端分离中台框架后端 Admin.Core 学习-介绍与配置说明

## 中台框架后端项目 Admin.Core 的介绍与配置说明 > 中台admin是前后端分离权限管理系统,Admin.Core为后端项目,基于.NET 7.0开发。 > 支持多租户、数据权限、动态 Api、任务调度、OSS 文件上传、滑块拼图验证、多数据库,分布式缓存、分布式事务等 - 接口文档一

01背包问题

题目 题目描述 有 N N N 件物品和一个容量是 V V V 的背包。每件物品只能使用一次。 第 i i i 件物品的体积是 v i v_i vi​,价值是 w i w_i wi​。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 第一行两个整

01背包问题的js解决方式

如果你有兴趣看这个相信你已经对背包问题有所了解,所以关于背包问题的描述,我就不写了。只记录一下自己对这个问题的一些看法和思考,于我而言,这个东西现在困扰我的是如何确定最优解。实质上关于背包问题网上的东西我大体都有看过,对于这个问题,常见的就是使背包重量动态增长,然后遍历每个要装入的这些包裹,当包裹的

[转帖]TIKV扩容之刨坑填坑​

01 背景 某tidb集群收到告警,TIKV 节点磁盘使用率85%以上,联系业务无法快速删除数据,于是想到扩容TIKV 节点,原先TIKV 节点机器都是6TB的硬盘,目前只有3TB的机器可扩,也担心region 均衡后会不会打满3TB的盘,PD 调度策略来看应该是会根据不同存储机器的资源配置和使用情