目的
x86_64-unknown-linux-musl
でビルドしたバイナリを使って、DockerコンテナのAlpineからHTTPS通信をしたい!
HTTPS通信と書いていますが、想定しているユースケースはhyper
を使った通信処理です。
gothamなど多くのWebFrameworkがhyper
を使用しているため、WebServerを作る場合のTipsでもあります。
Ubuntuでビルドして、Ubuntuで起動するなら簡単ですが、musl
を使ってBuildし
Alpineで起動するとハマりどころが多いのでメモっておきます。
前提
軽量なDockerイメージにするため、Compile OSとRuntime OSを分けます。
環境
- Compile OS: ubuntu16.04
- Runtime OS: alpine3.7
- Rust: v1.23
- Target:
rust-opensslx86_64-unknown-linux-musl
- SSL Lib: OpenSSL(openssl-rust)
-
サンプルソース
-
make
で実行
-
設定
Compile時の設定
OpenSSLを静的リンクするために以下の設定を行います。
- OpenSSLを
musl-libc
を使ってコンパイルし、Staticなlibraryを用意 - 静的リンクするためのビルド設定を環境変数に設定
OPENSSL_STATIC=1
- 必要に応じて
OPENSSL_
プリフィックスで始まる環境変数の設定
具体的にはこちらのDockerfileが参考となります。
Runtime時の設定
Linuxディストリビューションによって証明書のパスが違うため、証明書のパスを設定する必要があります。
Alpineで実行する際には以下の設定をします。
$ apk add --no-cache ca-certificates && update-ca-certificates
$ export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
$ export SSL_CERT_DIR=/etc/ssl/certs
他の方法として、Alpine以外のLinuxディストリビューションでも動作させたい場合、openssl-probeを使うことで証明書のパスをRuntime時に解決できます
[dependencies]
openssl-probe = "0.1"
init_ssl_cert_env_vars()
を実行する。
extern crate openssl_probe;
fn main() {
openssl_probe::init_ssl_cert_env_vars();
//... your code
}
Docker
上記で紹介したイメージを利用しMultiStageでbuildすると、軽量なDockerイメージを作成できます。
FROM ekidd/rust-musl-builder:stable AS rust-builder
ADD . .
RUN cargo build --release --target x86_64-unknown-linux-musl
FROM alpine:3.7
COPY --from=rust-builder /home/rust/src/target/x86_64-unknown-linux-musl/release/{bin} /usr/local/bin
RUN apk add --no-cache ca-certificates && update-ca-certificates
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
ENV SSL_CERT_DIR=/etc/ssl/certs
CMD ["{bin}"]
サンプルソースでは13Mと軽量なDockerイメージを作ることができました。
備考
証明書が発見できない場合は以下の様なエラーが発生します。
The OpenSSL library reported an error: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed:s3_clnt.c:1269