CI/CDでRustビルド高速化

# CI/CDでRustビルド高速化
## 事前準備
- プロジェクト作成

```
cargo init
```

- Dockerファイル作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/015b5db6-d634-9768-619a-d3effff84d90.png)

- 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 .
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/87cbd881-ae47-3b4a-29f6-8b2dcae8e4cf.png)


---

- Docker ビルドをもう一回実行して、結果を見ます

```
docker build -f dockerfile_1 .
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/3900f022-f6c7-9284-71a5-6dd33aebd07c.png)

---

- 結論: 2回目の実行はコードは何も変わらないですので、Dockerビルドは全部キャッシュ使えます。


---

- コードをちょっと修正します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/3f283d10-6855-d14c-c9fb-913407469e1a.png)


---

- Docker ビルドをもう一回実行して、結果を見ます

```
docker build -f dockerfile_1 .
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/7f33d2bb-cec8-ab58-3c87-a7334d383fbc.png)


---

-「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 .
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/37b8eae0-00a5-847b-8d94-6f7370db2516.png)


---

- コードを修正して、再ビルドして、結果をみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/20db7eae-1a64-2052-38bb-2562319f658a.png)

```
docker build -f dockerfile_2 .
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/26a4048b-90ce-0878-eead-a3ea4790603d.png)


---

- 「Step 6/11 : RUN cargo build --release」にはキャッシュされました。


---

## 方法2 - Imageサイズ改善

---

- image名を指定して、Dockerビルドして、イメージサイズを確認しましょう

```
 docker build -t apptest -f dockerfile_2 .

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/0885ffc2-263b-bb24-503a-6f0c14eb1e48.png)


---

- 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
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/8d24a55a-9a9a-d702-623e-a762478ba677.png)


---


- ビルドしたファイルは別のイメージに入れました。　不要なファイルはイメージにないので、イメージのサイズはすごく小さくになりました。


---

# 方法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 . 
```


---

- 注意： 方法２ではイメージサイズは小さくにしたが、このイメージはビルドイメージではないので、`--cache-from` 指定しても効かないです。

---

# 方法4 - Rustビルドキャッシュ

---

- sccacheを使います
- https://github.com/mozilla/sccache
- ビルドしたファイルはS3にキャッシュします。
- ビルドするときに、S3からキャッシュをとって、必要なファイルだけビルドします。