CI/CDでRustビルド高速化
事前準備
- プロジェクト作成
cargo init
- Dockerファイル作成
- Dockerビルドコマンドを実行
docker build -f dockerfile .
- (ビルドしたイメージはAWS ECRなどに入れて、ECSで動けるようにする)
docker push xxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:yyyy
方法1 - Dockerの書き方の改善
- 一般的なDocker設定ファイルは以下となります
dockerfile_1
FROM rust:latest
WORKDIR /usr/src/myapp
COPY . .
RUN cargo build --release
RUN cargo install --path .
CMD ["/usr/local/cargo/bin/myapp"]
- Docker ビルド実行して、結果を見ます
docker build -f dockerfile_1 .
- Docker ビルドをもう一回実行して、結果を見ます
docker build -f dockerfile_1 .
- 結論: 2回目の実行はコードは何も変わらないですので、Dockerビルドは全部キャッシュ使えます。
- Docker ビルドをもう一回実行して、結果を見ます
docker build -f dockerfile_1 .
-「Step 3/6」からキャッシュされて、ライブラリーなどダウンロードして、インストールする処理が実行されます。
- コードだけ修正したのに、ライブラリーが再インストールされますので、ビルド時間が発生しました。
- 原因はコード変更されたので、
Step 3/6 : COPY . .
キャッシュしないので、これ以降はキャッシュできなくなります。 - ライブラリーインストールなので、あまり変わらないので、先にインストールして、キャッシュ効くように修正しないといけません。
- 具体的には以下のコードです
dockerfile_2
FROM rust:latest
WORKDIR /usr/src/myapp
COPY Cargo.toml Cargo.toml
RUN mkdir src/
RUN echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs
RUN cargo build --release
RUN rm -f target/release/deps/myapp*
COPY . .
RUN cargo build --release
RUN cargo install --path .
CMD ["/usr/local/cargo/bin/myapp"]
- ビルドして、結果を見ます
docker build -f dockerfile_2 .
- コードを修正して、再ビルドして、結果をみます。
docker build -f dockerfile_2 .
- 「Step 6/11 : RUN cargo build --release」にはキャッシュされました。
方法2 - Imageサイズ改善
- image名を指定して、Dockerビルドして、イメージサイズを確認しましょう
docker build -t apptest -f dockerfile_2 .
- Hello wordの表示だけなのに、イメージサイズは1.4GBがでた
- イメージサイズは大きくになると、イメージPUSHなどは時間がかかります。
- Rust言語でビルドしたファイルだけがあれば動けますが、ビルドの時にダウンロードしたライブラリーなどはイメージに入っていますので、サイズは大きいでした。
- ビルドしたファイルを別のImageに入れると、Imageのサイズは小さくになります。
- 以下に修正して、再ビルドします。
dockerfile_2
# ------------------------------------------------------------------------------
# Cargo Build Stage
# ------------------------------------------------------------------------------
FROM rust:latest as cargo-build
WORKDIR /usr/src/myapp
COPY Cargo.toml Cargo.toml
RUN mkdir src/
RUN echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs
RUN cargo build --release
RUN rm -f target/release/deps/myapp*
COPY . .
RUN cargo build --release
RUN cargo install --path .
# ------------------------------------------------------------------------------
# Final Stage
# ------------------------------------------------------------------------------
FROM alpine:latest
COPY --from=cargo-build /usr/src/myapp/target/release/myapp /usr/local/bin/myapp
CMD ["myapp"]
docker build -t apptest -f dockerfile_2 .
docker image ls
- ビルドしたファイルは別のイメージに入れました。 不要なファイルはイメージにないので、イメージのサイズはすごく小さくになりました。
方法3 - クラウドキャッシュを使います。
- 上の方法はキャッシュ使いますが、キャッシュデータはロカールに置きます。
- CIでビルドする場合、毎回にビルドRunnerが変わりますので、前回のビルドはキャッシュできません
- ビルドするイメージをPUSHして、次回のビルドは前のイメージからキャッシュします。
docker build -t xxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:yyyy -f dockerfile_2 .
docker push xxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:yyyy
- 次回にビルドの時にキャッシュを指定します。
docker build \
-t xxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:yyyy \
--cache-from xxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:yyyy \
-f dockerfile_2 .
- 注意: 方法2ではイメージサイズは小さくにしたが、このイメージはビルドイメージではないので、
--cache-from
指定しても効かないです。
方法4 - Rustビルドキャッシュ
- sccacheを使います
- https://github.com/mozilla/sccache
- ビルドしたファイルはS3にキャッシュします。
- ビルドするときに、S3からキャッシュをとって、必要なファイルだけビルドします。