概要
upstreamのcurlにおいてHTTP/3の実験的サポートが追加されました。
公式リポジトリのReadmeに詳細が載ってますが、とりあえずDocker上で動かせるのを確認したのでシェアします。
HTTP/3についてよくわからない方は詳解HTTP/3をご覧ください(ステマ)。
TL; DR
すぐ試したいという方は docker run --rm -it inductor/curl-quiche:latest
でコンテナを起動したあとに以下を実行すればよいです。(Ref: https://asnokaze.hatenablog.com/entry/2019/08/07/031904)
$ curl --http3 https://www.facebook.com/ -v -s -o /dev/null
Dockerfile
公式の手順を参考に書き起こしたDockerfileが以下です。Gitリポジトリはこちら
FROM ubuntu:18.04 as base-fetch
RUN apt-get update && apt-get install -y git
FROM ubuntu:18.04 as base-build
RUN apt-get update && apt-get install -y build-essential pkg-config
FROM base-fetch as fetch-quiche
WORKDIR /root
RUN git clone --recursive --depth 1 https://github.com/cloudflare/quiche
RUN mkdir quiche/deps/boringssl/build
FROM base-build as prepare-quiche
RUN apt-get update && apt-get install -y cmake golang-go
COPY --from=fetch-quiche /root/quiche /root/quiche
WORKDIR /root/quiche/deps/boringssl/build
RUN cmake -DCMAKE_POSITION_INDEPENDENT_CODE=on ..
RUN make -j`nproc`
WORKDIR /root/quiche/deps/boringssl
RUN mkdir .openssl/lib -p
RUN cp build/crypto/libcrypto.a build/ssl/libssl.a .openssl/lib
RUN ln -s $PWD/include .openssl
FROM base-build as build-quiche
WORKDIR /root
RUN apt-get update && apt-get install -y wget ca-certificates && \
wget https://sh.rustup.rs -O install.sh \
&& chmod +x install.sh \
&& ./install.sh -y \
&& rm -rf install.sh && \
apt-get purge -y --auto-remove wget ca-certificates
COPY --from=prepare-quiche /root/quiche /root/quiche
WORKDIR /root/quiche/
RUN QUICHE_BSSL_PATH=$PWD/deps/boringssl \
$HOME/.cargo/bin/cargo \
build \
--release \
--features \
pkg-config-meta
FROM base-fetch as fetch-curl
WORKDIR /root
RUN git clone --depth 1 https://github.com/curl/curl
FROM base-build as build-curl
RUN apt-get update && apt-get install -y autoconf libtool
COPY --from=fetch-curl /root/curl /root/curl
WORKDIR /root/curl
RUN ./buildconf
COPY --from=build-quiche /root/quiche /root/quiche
RUN ./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" \
--with-ssl=$PWD/../quiche/deps/boringssl/.openssl \
--with-quiche=$PWD/../quiche/target/release
RUN make -j`nproc`
RUN make install
FROM ubuntu:18.04 as executor
COPY --from=build-curl /etc/ld.so.conf.d/libc.conf /etc/ld.so.conf.d/libcurl.conf
COPY --from=build-curl /usr/local/lib/libcurl.so.4 /usr/local/lib/libcurl.so.4
COPY --from=build-curl /etc/ld.so.conf.d/libc.conf /etc/ld.so.conf.d/libquiche.conf
COPY --from=build-curl /root/quiche/target/release/libquiche.so /usr/local/lib/libquiche.so
COPY --from=build-curl /usr/local/bin/curl /usr/local/bin/curl
RUN ldconfig
CMD ["bash"]
Dockerfileの設計戦略について
今回書いたDockerfileではマルチステージビルドと呼ばれる機能を使っています。
これは、Dockerfileにおける FROM
句を複数回呼び出すことで複数のビルド(1ビルドの単位をステージと呼びます)を展開できる機能です。こうすると、ある特定のステージから別のステージに対してファイルをコピーできるようになり、ソースコードのコンパイル用ステージとコンパイル済みバイナリの実行用ステージなどを分けることで、イメージサイズを小さくすることができるようになるという効果があります。
具体的にはこんな感じです。
FROM golang:alpine as builder
WORKDIR /app
COPY . /app
RUN go build -o /hoge
FROM alpine as executor
COPY --from=builder /hoge /hoge
CMD ["/hoge"]
こうすることで、golangのビルドに必要だったライブラリ群がすべて不要となり、実行用のイメージ+生成したバイナリのDockerイメージが出来上がります。
このDockerfileを書くにあたって、当初ベースイメージにはDebianを使ったのですが、何も考えずに作ったら2GBのイメージが出来上がりました。Debian Slimに変えて色々頑張った結果、98MBにまで小さくなりました。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
inductor/curl-quiche debian b8288aeca6a3 24 minutes ago 98.1MB
inductor/curl-quiche ubuntu 60f6ebe7ce0c 10 minutes ago 92.2MB
また、最近(最近でもないか?)UbuntuのオフィシャルイメージがめちゃくちゃコンパクトになったこともあったのでUbuntuで試してみたところ、92MBになりました。びっくり!
BuildKitを用いたDockerイメージビルドの並列実効性
BuildKitはDockerのバージョン18.06より搭載された次世代Dockerイメージビルドツールで、後方互換性を保ちながらも既存のビルダーに比べキャッシュやビルド実行並列性などが向上しているのが特徴です。
Dockerfileを見ていただくとわかるかと思いますが、fetchやbuildでベースイメージを分けたり、複数のステージで別々のファイルを別々にビルドしたりと、かなり細かくステージを分けています。
これは、BuildKitでは並列に実行可能な命令は並列に行うという特徴を持っているためで、他のステージに依存しない命令を複数ステージに分割すると実行並列性が増してビルド時間の短縮につながるために行っている対応です。
例えばあるプログラムをコンパイルするために必要な対応が
・ビルドに必要な別のライブラリを取得
・ライブラリのビルドに必要なパッケージを入れて
・ライブラリをコンパイル
・プログラムのソースコードを取得
・プログラムのビルドに必要なパッケージを入れて
・プログラムをコンパイル
だった場合、並列に実行できないのはプログラムのコンパイルだけです(ライブラリ自体のコンパイルに依存するため)
そのため、以下のように書くと同時に処理が走るというわけです。
FROM hoge as base-lib
RUN 共通パッケージのインストール
FROM hoge as fetch-lib
RUN lib取得
FROM hoge as build-lib
COPY --from=fetch-lib /path/to/lib # フェッチの処理に引っ張られる
RUN libコンパイル
FROM hoge as base-program
RUN 共通パッケージのインストール
FROM hoge as fetch-program
RUN program取得
FROM hoge as build-program
COPY --from=fetch-program /path/to/program # フェッチの処理に引っ張られる
COPY --from=build-lib /bin/lib # libのビルドに引っ張られる
RUN programコンパイル
FROM hoge as executor
COPY --from=build-program /bin/program
CMD ["/bin/program"]
Alpineは?
聞かないでください。
quicheのコンパイルで死亡して諦めました。
誰か上手くいったらおしえて