DarkNode

Life, the Universe and Everything

在 Alpine Linux 下静态链接并打包程序

本文发表于:
最后修改于:
分类:system
合计信息量:8.59kb

相关说明

很长一段时间内,我考虑过在 VPS 上使用 Docker 来快速初始化,但相对于我目前的使用方式来看,Docker 从安装到使用都过于复杂了。

某一天我从 Docker 想到 Golang,从 Golang 想到静态编译,又联想起 fpm 打包工具,一个新的方案产生了。

文中命令以 De­bian 8.0 为基础。

安装 Alpine Linux

将 Alpine Linux 安装到/var/rootfs 下,再 ch­root 进去,就能获得一个干净而隔离的编译环境,Alpine Linux 下默认使用 musl-libc,一个可以很方便地静态链接到程序里的 libc 库。

#!/usr/bin/env bash
# -*- cod­ing: utf-8 -*-

ex­port SOURCE='http://dl-cdn.alpinelinux.org/alpine/lat­est-sta­ble/main'
ex­port CH­ROOT='/var/rootfs'
ex­port VER_APK="2.6.8-r2"

mkdir -p $CH­ROOT
curl $SOURCE/x86_64/apk-tools-sta­tic-$VER_APK.apk | tar xz -C / sbin/apk.sta­tic
apk.sta­tic -X $SOURCE -U --al­low-un­trusted --root $CH­ROOT --initdb add alpine-base

echo 'name­server 8.8.8.8' > $CH­ROOT/etc/re­solv.conf
echo $SOURCE > $CH­ROOT/etc/apk/repos­i­to­ries

mount -t proc none $CH­ROOT/proc
mount -o bind /sys $CH­ROOT/sys
mount -o bind /dev $CH­ROOT/dev

ch­root $CH­ROOT /bin/sh -l

编译并静态链接 Ng­inx

我使用如下的脚本编译并静态链接 Ng­inx:

#!/usr/bin/env bash
# -*- cod­ing: utf-8 -*-

ex­port VER_NG­INX="1.11.13"
ex­port VER_LIBERSSL="2.5.2"
ex­port VER_ZLIB="1.2.11"
ex­port VER_PCRE="8.40"
ex­port PKG_BUILD="curl build-base linux-head­ers perl"

apk --up­date add $PKG_BUILD
curl -sSL http://ng­inx.org/down­load/ng­inx-$VER_NG­INX.tar.gz | tar xz -C /tmp
curl -sSL http://ftp.openbsd.org/pub/OpenBSD/Li­breSSL/li­bressl-$VER_LIBERSSL.tar.gz | tar xz -C /tmp
curl -sSL http://ftp.csx.cam.ac.uk/pub/soft­ware/pro­gram­ming/pcre/pcre-$VER_PCRE.tar.gz | tar xz -C /tmp
curl -sSL http://zlib.net/zlib-$VER_ZLIB.tar.gz | tar xz -C /tmp

cd /tmp/ng­inx-$VER_NG­INX/
    ./con­fig­ure \
        --pre­fix=/etc/ng­inx \
        --sbin-path=/usr/sbin/ng­inx \
        --conf-path=/etc/ng­inx/ng­inx.conf \
        --er­ror-log-path=/var/log/ng­inx/er­ror.log \
        --http-log-path=/var/log/ng­inx/ac­cess.log \
        --pid-path=/var/run/ng­inx.pid \
        --lock-path=/var/run/ng­inx.lock \
        --http-client-body-temp-path=/var/cache/ng­inx/client_temp \
        --http-proxy-temp-path=/var/cache/ng­inx/proxy_temp \
        --user=no­body \
        --group=nogroup \
        --with-file-aio \
        --with-threads \
        --with-http_ssl_mod­ule \
        --with-http_v2_mod­ule \
        --with-http_se­cure_link_mod­ule \
        --with­out-http_fastcgi_mod­ule \
        --with­out-http_uwsgi_mod­ule \
        --with­out-http_scgi_mod­ule \
        --with­out-http_mem­cached_mod­ule \
        --with-openssl=../li­bressl-$VER_LIBERSSL \
        --with-zlib=../zlib-$VER_ZLIB \
        --with-pcre=../pcre-$VER_PCRE \
        --with-pcre-jit \
        --with-cc=x86_64-alpine-linux-musl-gcc \
        --with-cc-opt="-Os" \
        --with-ld-opt="-sta­tic -s"
    make in­stall

生成的程序将在/var/rootfs/usr/sbin/ng­inx 处。

打包 Ng­inx

首先参考 官方文档 安装 fpm,接着准备如下的目录结构:

ng­inx
├── etc
│   └── ng­inx
│       ├── ca.pem
│       ├── cert.pem
│       ├── dh­param.pem
│       ├── key.pem
│       ├── mime.conf
│       ├── ng­inx.conf
│       └── site.conf
├── script
│   └── ng­inx
├── usr
│   └── sbin
│       └── ng­inx
└── var
    ├── cache
    │   └── ng­inx
    └── log
        └── ng­inx

其中 ng­inx/script/ng­inx 是 sys­temd 配置文件:

$ cat script/ng­inx 
[Unit]
De­scrip­tion=Ng­inx Server Ser­vice
Af­ter=net­work.tar­get

[Ser­vice]
Type=fork­ing
PID­File=/var/run/ng­inx.pid
Ex­ec­Start­Pre=/bin/mkdir -p /var/www/
Ex­ec­Start­Pre=/bin/chown Daniel:Daniel /var/www/
Ex­ec­Start­Pre=/usr/sbin/ng­inx -t
Ex­ec­Start=/usr/sbin/ng­inx
Ex­e­cRe­load=/usr/sbin/ng­inx -s re­load
Ex­ec­Stop=/sbin/start-stop-dae­mon --quiet --stop --retry QUIT/5 --pid­file /run/ng­inx.pid
Time­out­StopSec=5
KillMode=mixed

[In­stall]
Want­edBy=multi-user.tar­get

其中 ng­inx/etc/ng­inx 目录下是 Ng­inx 配置文件,如此即可将 Ng­inx 的配置文件一并打包,打包命令如下:

fpm -s dir -C ng­inx -t deb -n ng­inx -v 1.11.13-0 -a amd64 -f \
    --ex­clude 'script' \
    --deb-sys­temd    ng­inx/script/ng­inx

随后即可生成 ng­inx_1.11.13-0_amd64.deb,在目标机器上直接执行 dpkg -i ng­inx_1.11.13-0_amd64.deb 一键部署完成 Ng­inx。

编译并静态链接 Shad­ow­socks

#!/usr/bin/env bash
# -*- cod­ing: utf-8 -*-

ex­port VER_SSLIBEV="3.0.5"
ex­port VER_SIPOBFS="0.0.3"
ex­port VER_MBEDTLS="2.4.2"
ex­port VER_SODIUM="1.0.12"
ex­port VER_UDNS="0.4"
ex­port VER_PCRE="8.40"
ex­port VER_EV="4.24"
ex­port PKG_BUILD="curl build-base linux-head­ers au­to­conf au­tomake libtool"
ex­port CFLAGS="-Os"
ex­port LD­FLAGS="-sta­tic -s"

apk --up­date up­grade
apk --up­date add $PKG_BUILD
curl -sSL https://github.com/shad­ow­socks/shad­ow­socks-libev/archive/v$VER_SSLIBEV.tar.gz | tar xz -C /tmp
curl -sSL https://github.com/shad­ow­socks/sim­ple-obfs/archive/v$VER_SIPOBFS.tar.gz | tar xz -C /tmp
curl -sSL https://github.com/AR­Mmbed/mbedtls/archive/mbedtls-$VER_MBEDTLS.tar.gz | tar xz -C /tmp
curl -sSL https://github.com/jedisct1/lib­sodium/re­leases/down­load/$VER_SODIUM/lib­sodium-$VER_SODIUM.tar.gz | tar xz -C /tmp
curl -sSL http://www.cor­pit.ru/mjt/udns/udns-$VER_UDNS.tar.gz | tar xz -C /tmp
curl -sSL http://ftp.csx.cam.ac.uk/pub/soft­ware/pro­gram­ming/pcre/pcre-$VER_PCRE.tar.gz | tar xz -C /tmp
curl -sSL http://dist.schmorp.de/libev/At­tic/libev-$VER_EV.tar.gz | tar xz -C /tmp

curl -sSL https://github.com/shad­ow­socks/lib­bloom/archive/mas­ter.tar.gz | tar xz -C /tmp
curl -sSL https://github.com/shad­ow­socks/lib­cork/archive/shad­ow­socks.tar.gz | tar xz -C /tmp
curl -sSL https://github.com/shad­ow­socks/ipset/archive/shad­ow­socks.tar.gz | tar xz -C /tmp

cd /tmp/lib­sodium-$VER_SODIUM/
    ./con­fig­ure \
        --pre­fix=/usr \
        --en­able-shared=false
    make in­stall

cd /tmp/mbedtls-mbedtls-$VER_MBEDTLS/
    make DEST­DIR=/usr in­stall

cd /tmp/udns-$VER_UDNS/
    ./con­fig­ure --with-ipv6
    make
    in­stall -D -m0644 udns.h /usr/in­clude/udns.h
    in­stall -D -m0755 libudns.a /usr/lib/libudns.a

cd /tmp/pcre-$VER_PCRE/
    ./con­fig­ure \
        --pre­fix=/usr \
        --en­able-jit \
        --en­able-utf8 \
        --en­able-uni­code-prop­er­ties \
        --en­able-shared=false \
        --dis­able-cpp \
        --with-match-limit-re­cur­sion=8192
    make in­stall

cd /tmp/libev-$VER_EV/
    ./con­fig­ure \
        --pre­fix=/usr \
        --en­able-shared=false
    make in­stall

cd /tmp/shad­ow­socks-libev-$VER_SSLIBEV/
    cp /tmp/lib­bloom-mas­ter/* lib­bloom/
    cp /tmp/lib­cork-shad­ow­socks/* lib­cork/
    cp /tmp/ipset-shad­ow­socks/* li­bipset/
    ./au­to­gen.sh
    ./con­fig­ure --dis­able-doc­u­men­ta­tion
    make in­stall

cd /tmp/sim­ple-obfs-$VER_SIPOBFS/
    cp /tmp/lib­cork-shad­ow­socks/* lib­cork/
    ./au­to­gen.sh
    ./con­fig­ure --dis­able-doc­u­men­ta­tion
    make in­stall

生成的程序将在/var/rootfs/usr/lo­cal/bin/ss-server 和/var/rootfs/usr/lo­cal/bin/obfs-server 处。

打包 Shad­ow­socks

准备如下的目录结构:

shad­ow­socks
├── etc
│   └── shad­ow­socks.json
├── script
│   ├── obfs
│   └── shad­ow­socks
└── usr
    └── bin
        ├── obfs-server
        └── ss-server

其中 script/obfs 和 script/shad­ow­socks 是 sys­temd 配置文件:

$ cat shad­ow­socks/script/obfs 
[Unit]
De­scrip­tion=Shad­ow­socks-Libev Obfs Ser­vice
Af­ter=net­work.tar­get

[Ser­vice]
Type=sim­ple
Lim­it­NOFILE=32768
Ex­ec­Start=/usr/bin/obfs-server -s 0.0.0.0 -p xxx --obfs http -r 127.0.0.1:xxx --failover 127.0.0.1:xxx
Restart=on-fail­ure

[In­stall]
Want­edBy=multi-user.tar­get

$ cat shad­ow­socks/script/shad­ow­socks 
[Unit]
De­scrip­tion=Shad­ow­socks-Libev Server Ser­vice
Af­ter=net­work.tar­get

[Ser­vice]
Type=sim­ple
Lim­it­NOFILE=32768
Ex­ec­Start=/usr/bin/ss-server -c /etc/shad­ow­socks.json
Restart=on-fail­ure

[In­stall]
Want­edBy=multi-user.tar­get

其中 shad­ow­socks/etc/shad­ow­socks.json 目录下是 Shad­ow­socks 配置文件,如此即可将 Shad­ow­socks 的配置文件一并打包,打包命令如下:

fpm -s dir -C shad­ow­socks -t deb -n shad­ow­socks -v 3.0.5-0 -a amd64 -f \
    --ex­clude 'script' \
    --deb-sys­temd    shad­ow­socks/script/shad­ow­socks \
    --deb-sys­temd    shad­ow­socks/script/obfs

随后即可生成 shad­ow­socks_3.0.5-0_amd64.deb,在目标机器上直接执行 dpkg -i shad­ow­socks_3.0.5-0_amd64.deb 一键部署完成 Shad­ow­socks。