在 docker 中编译 rust 程序
2019-08-01 16:08 rust
为了保证一致的编译环境, 可以考虑把代码放在 docker 中编译.
做法也很简单, 下面以之前用到的 musl-demo
示例程序为例来说明一下.
Cargo.toml 文件内容:
[package]
name = "musl-demo"
version = "0.1.0"
authors = ["Xu Shaohua <shaohua@biofan.org>"]
edition = "2018"
[dependencies]
openssl = "0.10.24"
rust_sodium = "0.10.2"
[profile.release]
lto = true
main.rs 文件内容:
extern crate openssl;
extern crate rust_sodium;
use openssl::ssl::{SslConnector, SslMethod};
fn test_openssl() {
let mut ctx = SslConnector::builder(SslMethod::tls()).unwrap();
// set_ciphersuites was added in OpenSSL 1.1.1, so we can only call it when linking against that version
#[cfg(openssl111)]
ctx.set_ciphersuites("TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256").unwrap();
}
fn test_sodium() {
println!("version of sodium: {}.{}",
rust_sodium::version::version_major(),
rust_sodium::version::version_minor()
);
}
fn main() {
test_openssl();
test_sodium();
}
使用本地的包依赖
默认情况下, cargo 会从 crates.io 下载依赖包, 这对于持续构建的环境来说并不合适. 还好, 在新版本中 cargo 加入了 vendor 命令, 可以将依赖包缓存到本地.
$ cargo vendor
会在项目根目录生成 vendor/ 目录. 然后根据提示, 在 .cargo/config
文件中加入:
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
现在来看, cargo vendor
还有一些问题, 比如生成的 vendor 目录比较大, 这个很简单的
项目, 里包含了超过 100M 的文件, 里面竟然还有一些测试用的数据文件, 其实都是可以
删除的.
编写 Dockerfile
上面的 Cargo.toml 里面, 引入了两个本地 C 库的依赖, openssl 和 libsodium. 这个在 编译时要安装了相应的 C 库的, 我们都可以在 Dockerfile 中事先安装完.
Docker hub 中提供了 x86/x86_64/arm64 这三个版本的 rust 稳定版镜像. 我们用的是 1.36-buster.
以下定义了用于构建 musl-demo 项目的 docker 镜像:
FROM rust:1.36-buster
LABEL Build environment for musl-demo project
RUN echo 'deb http://ftp.cn.debian.org/debian/ stable main' > /etc/apt/sources.list
RUN apt update
RUN apt install libssl-dev libsodium-dev build-essential binutils upx -y
CMD ["/bin/bash"]
然后生成编译时的 docker 镜像:
$ sudo docker build -t musl-demo-build .
开始编译
使用刚刚生成的 docker 镜像编译项目:
$ sudo docker run --rm --user ${uid -u}:${uid -g} \
-v ${PWD}/..:/usr/src/musl-demo \
-w /usr/src/musl-demo \
musl-build cargo build --release
可以压缩一下生成的可执行文件:
$ sudo docker run --rm --user ${uid -u}:${uid -g} \
-v ${PWD}/..:/usr/src/musl-demo \
-w /usr/src/musl-demo \
musl-build strip target/release/musl-demo
$ sudo docker run --rm --user ${uid -u}:${uid -g} \
-v ${PWD}/..:/usr/src/musl-demo \
-w /usr/src/musl-demo \
musl-build upx target/release/musl-demo
在服务器上运行 musl-demo
先将生成的 musl-demo 可执行文件同步到远程服务器, 再在服务器上生成一个运行时的 docker 镜像.
FROM musl-build
LABEL Runtime environment for musl-demo project
COPY musl-demo /opt/
CMD ["/opt/musl-demo"]