Alpine 是一个与 OpenWrt 类似的以 Musl + Busybox 为基础的精简 Linux 发行版,其包构建与管理结合了 Debian/Ubuntu apt、RHEL/CentOS yum 与 FreeBSD ports 等多个系统的特点。
由于我不做嵌入式开发,因此 Alpine 主要用于容器应用,以及构建全静态 C/C++ 程序。
apk 是 Alpine 的包管理工具,集成了类似 dpkg/apt, rpm/yum 的功能,对比下 apk -h
与 apt -h
的输出,开发者还是挺有意思的:
$ apk -h
...
This apk has coffee making abilities.
$ apt -h
...
This APT has Super Cow Powers.
修改软件源
# vi /etc/apk/repositories
http://mirrors.ustc.edu.cn/alpine/v3.10/main
http://mirrors.ustc.edu.cn/alpine/v3.10/community
显然,apk 源的类型就是一个文件夹,类似于 Ubuntu 源的 main restricted universe multiverse 等各种类型。
可以为源命名,如:
# vi /etc/apk/repositories
http://mirrors.ustc.edu.cn/alpine/v3.10/main
http://mirrors.ustc.edu.cn/alpine/v3.10/community
@ceph /ceph/apk
这样在安装软件包时可以安装指定源里面的包,如:
$ sudo apk add ceph-common@ceph
更新软件包索引
# apk update
fetch http://mirrors.ustc.edu.cn/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://mirrors.ustc.edu.cn/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
v3.10.2-36-g2fa274fe2c [http://mirrors.ustc.edu.cn/alpine/v3.10/main]
v3.10.2-37-g3ee31e5e22 [http://mirrors.ustc.edu.cn/alpine/v3.10/community]
OK: 10334 distinct packages available
列出所有可更新的版本
# apk list -u
更新已安装软件包
# apk upgrade
判断软件包版本号
检测版本号是否合法,有输出则表示非法:
$ apk version -c 12.2.12-r2.43-g204a43f004
12.2.12-r2.43-g204a43f004
$ echo $?
1
$ apk version -c 12.2.12-r2
$ echo $?
0
比较版本号:
$ apk version -t 12.2.12-r1 12.2.12-r2
<
Alpine 的软件包版本号规则与 Gentoo 下的软件包版本号规则保持一致(相比 deb、rpm 非常之不灵活,在构建 apk 包时需要特别注意):
{digit}{.digit}...{letter}{_suf{#}}...{-r#}
具体算法可以参考如下代码:
https://github.com/alpinelinux/apk-tools/blob/v2.10.4/src/version.c
安装软件包
安装最新的软件包:
# apk add ceph-common
安装指定版本的软件包:
# apk add 'ceph-common=14.2.1-r0'
# apk add 'ceph-common<14.2.1-r0'
注意 Alpine 的源与 yum 源类似,只保留软件包最新的版本,如需要安装老版本则需要增加老版本的源。
列出所有已安装包
# apk list -I
列出软件包内容
列出已安装软件包内容:
# apk info -L ceph-common
列出本地软件包内容:
$ apk manifest ./ceph-common-12.2.12-r2.43-g204a43f004.apk
(null): .pre-install
sha1:7876192f4a86d7e8e6ba00f8ba7665d16000e027 etc/ceph/rbdmap
sha1:728ed29877636f9a1f7e523dc00f8dc3de086d32 etc/udev/rules.d/50-rbd.rules
sha1:d6a80d93b67b857373ea6630de4059531faef18f sbin/mount.ceph
sha1:e674ede90c25e57523e280c95fab5f23e2d20bf1 usr/bin/ceph
sha1:976e8bfeed14c759d046ee7c8cd372bbad3d7638 usr/bin/ceph-authtool
sha1:f2664e9d538c47e5b60f3269ecfac977a056013b usr/bin/ceph-conf
sha1:9471e4cd2faed6d0b44781e06571752437fd1a3f usr/bin/ceph-dencoder
...
通过文件查询所属软件包
# apk info -W /usr/lib/librados.so.2
与 rpm -qf
类似。
删除已安装软件包
# apk del ceph-common
查询软件包信息
# apk info ceph-common
比较遗憾的是没有查询本地 apk 包信息的命令。
搜索软件包
# apk search ceph-common
下载软件包
# apk fetch ceph-common
安装本地软件包
# apk add ./ceph-common-14.2.1-r0.apk
验证本地软件包签名
# apk verify ./ceph-common-14.2.1-r0.apk
注意:用于签名的私钥对应的公钥必须拷贝至 /etc/apk/keys 目录,否则会有如下的错误:
$ apk verify alpine/ceph/x86_64/librados-12.2.12-r2.43-g5cb60f2c3c.apk
alpine/ceph/x86_64/librados-12.2.12-r2.43-g5cb60f2c3c.apk: 0 - UNTRUSTED
生成 apk 签名密钥对
$ sudo apk add alpine-sdk
$ abuild-keygen -a -i
>>> Generating public/private rsa key pair for abuild
Enter file in which to save the key [/home/runsisi/.abuild/luo.runbing@example.com-5d735ebc.rsa]: /home/runsisi/.abuild/runsisi@hust.edu.cn.rsa
Generating RSA private key, 2048 bit long modulus (2 primes)
................................+++++
....+++++
e is 65537 (0x010001)
writing RSA key
>>> Installing /home/runsisi/.abuild/runsisi@hust.edu.cn.rsa.pub to /etc/apk/keys...
>>>
>>> Please remember to make a safe backup of your private key:
>>> /home/runsisi/.abuild/runsisi@hust.edu.cn.rsa
>>>
$ ls /etc/apk/keys/
alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub
alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub runsisi@hust.edu.cn.rsa.pub
$ ls ~/.abuild/
abuild.conf runsisi@hust.edu.cn.rsa runsisi@hust.edu.cn.rsa.pub
$ cat ~/.abuild/abuild.conf
PACKAGER_PRIVKEY="/home/runsisi/.abuild/runsisi@hust.edu.cn.rsa"
-i
选项把公钥拷贝至 /etc/apk/keys 目录。
为本地 apk 文件创建本地源
# apk index -o x86_64/APKINDEX.tar.gz x86_64/*.apk
使用本地源
# tree /home/runsisi/ceph/alpine/ceph
/home/runsisi/ceph/alpine/ceph
└── x86_64
├── APKINDEX.tar.gz
├── ceph-12.2.12-r2.43-g204a43f004.apk
├── ceph-base-12.2.12-r2.43-g204a43f004.apk
├── ceph-bash-completion-12.2.12-r2.43-g204a43f004.apk
├── ceph-common-12.2.12-r2.43-g204a43f004.apk
...
# vi /etc/apk/repositories
http://dl-cdn.alpinelinux.org/alpine/v3.10/main
http://dl-cdn.alpinelinux.org/alpine/v3.10/community
/home/runsisi/ceph/alpine/ceph
注意源的目录结构必须是 /path/to/repo/$arch/{APKINDEX.tar.gz, *.apk}
,且 repositories 文件中的 URL 仅指定到 $arch
的父目录这一级,这是和 yum baseurl 的最大区别。
同时需要特别注意的是,当前 apk 还不能处理 no_proxy
环境变量,请见 PR27。
# apk update
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
WARNING: Ignoring /home/runsisi/ceph/alpine/ceph/x86_64/APKINDEX.tar.gz: UNTRUSTED signature
v3.10.2-36-g2fa274fe2c [http://dl-cdn.alpinelinux.org/alpine/v3.10/main]
v3.10.2-38-g39a872f50f [http://dl-cdn.alpinelinux.org/alpine/v3.10/community]
OK: 10334 distinct packages available
显然,索引文件需要进行签名,如有需要,所有 apk 相关的命令都可以通过指定 --allow-untrusted
选项进行规避:
# apk update --allow-untrusted
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
v3.10.2-36-g2fa274fe2c [http://dl-cdn.alpinelinux.org/alpine/v3.10/main]
v3.10.2-38-g39a872f50f [http://dl-cdn.alpinelinux.org/alpine/v3.10/community]
OK: 10356 distinct packages available
# apk policy librados --allow-untrusted
librados policy:
14.2.1-r0:
http://dl-cdn.alpinelinux.org/alpine/v3.10/community
12.2.12-r2.43-g204a43f004:
/home/runsisi/ceph/alpine/ceph
为源索引文件签名
# abuild-sign -k ~/.abuild/runsisi@hust.edu.cn.rsa x86_64/APKINDEX.tar.gz
签名之后 apk 命令就不再需要指定 --allow-untrusted
选项进行规避了。
注意:
- 用于签名的私钥对应的公钥必须拷贝至 /etc/apk/keys 目录,否则 apk update 仍然会报错 UNTRUSTED signature(公钥文件名不要修改);
-k
指定的签名私钥必须用绝对地址,abuild-sign 不支持相对地址;- 用于给 apk 包签名的私钥与给索引文件签名的私钥可以不同,但需要保证第一条;
- 索引文件不支持多次重复签名,否则 apk update 时会报错 BAD signature。
解决找不到 dynamic loader 的问题
# ./go
/bin/sh: ./go: not found
# ldd go
/lib64/ld-linux-x86-64.so.2 (0x7f7d53a64000)
libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7f7d53a64000)
libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f7d53a64000)
# ls /lib64/ld-linux-x86-64.so.2
ls: /lib64/ld-linux-x86-64.so.2: No such file or directory
# apk add libc6-compat
# apk manifest libc6-compat
sha1:b261ba9eb77e829f4b27f114716b844939d292a1 lib/libm.so.6
sha1:b261ba9eb77e829f4b27f114716b844939d292a1 lib/libc.so.6
sha1:b261ba9eb77e829f4b27f114716b844939d292a1 lib/libcrypt.so.1
sha1:b261ba9eb77e829f4b27f114716b844939d292a1 lib/librt.so.1
sha1:b261ba9eb77e829f4b27f114716b844939d292a1 lib/libutil.so.1
sha1:b261ba9eb77e829f4b27f114716b844939d292a1 lib/libpthread.so.0
sha1:b261ba9eb77e829f4b27f114716b844939d292a1 lib64/ld-linux-x86-64.so.2
# ls -l /lib64/ld-linux-x86-64.so.2
lrwxrwxrwx 1 root root 26 Sep 26 05:33 /lib64/ld-linux-x86-64.so.2 -> /lib/libc.musl-x86_64.so.1
参考资料
Alpine Linux package management
https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management
Package policies
https://wiki.alpinelinux.org/wiki/Package_policies
File Naming Rules
https://devmanual.gentoo.org/ebuild-writing/file-format/index.html#file-naming-rules
Creating a Package Repository for Alpine Linux
https://engineering.fundingcircle.com/blog/2015/04/28/create-alpine-linux-repository/
Static linking for C++ with Docker and Alpine Linux
https://www.reddit.com/r/cpp/comments/a3raez/static_linking_for_c_with_docker_and_alpine_linux/
Lightweight containers for building C++
https://github.com/foonathan/docker
Static binaries for a C++ application
https://www.arangodb.com/2018/04/static-binaries-c-plus-plus-application/
最后修改于 2019-09-07