環境
コンテナで開発・ビルドできるようにする。
しばらく離れていた&環境が変わったので自分用備忘録
wsl2+Docker Desktopに関してはこことこことここを参考にした。
hyper-vからの乗り換えの場合、
wsl2を使えるようにしてからhyper-vを無効化したらエラーが出たので、
-
- (Docker Desktopアンインストール)
-
- hyper-v 無効化
-
- wsl2有効化
- (Docker Desktop再インストール)
とすると確実かもしれない。
本編
1. コンテナイメージの取得・確認
PowerShellにて
PS:> docker pull rust:latest
(結果略)
PS:> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rust latest c69fb046b993 3 days ago 1.28GB
2. composeファイルの作成
vscodeで開発用コンテナを立ち上げるために、docker-composeファイルを作成します。
vscodeの機能で作成することもできますが、追加で少しやりたいことがあるため自作します。
version: '3.7'
services:
rust-dev:
image: rust:latest
container_name: rust_dev
working_dir: /app
volumes:
- ./:/app
- rust_dev_target:/app/target
tty: true
environment:
USER: xxxxx # cargo で必要になる
CARGO_BUILD_TARGET_DIR: /app/target
volumes:
rust_dev_target:
external: true
基本的な部分の解説はdocker-composeのリファレンスとか、その他の解説記事に任せるとして、
やりたかったことに関わる2点だけ
-
- environmentのCARGO_BUILD_TARGET_DIR
-
- この環境変数で指定したディレクトリに、targetが吐き出される
-
- volumes
-
- node_modulesを隔離するための方法から着想を得たやり方。
-
- CARGO_BUILD_TARGET_DIRでtargetフォルダをプロジェクトの外に出し、[^1]
-
- そこにrust_dev_targetという外部ボリュームをマウントしなおしている。
- これによってコンテナを削除してもtargetの中身を維持することができる。
composeファイルと同じ階層に.envファイルを置いておくと、環境変数として自動で読み込んでくれる。[^2]
これを使って一部置き換えておくことで、例えばマウント先のフォルダ変えたいなーってなったときに少しだけ便利。
composeファイル内での環境変数の参照は${~~}で出来る
.env
mnt=/app
docker-compose.local.yml
version: ‘3.7’
services:
rust-dev:
image: rust:latest
container_name: rust_dev
working_dir: ${mnt}
volumes:
– ./:${mnt}
– rust_dev_target:${mnt}/target
tty: true
environment:
USER: xxxxx
CARGO_BUILD_TARGET_DIR: ${mnt}/target
volumes:
rust_dev_target:
external: true
3. vscodeでコンテナを立ち上げる
4. プロジェクトの作成
開発はThe Rust Programming Languageを参考にすれば問題ないと思う。
著者とコミュニティに感謝。
Cargoでプロジェクトを作成すればHello worldが出来る。
root@02080d70998d:/app# cargo --version
cargo 1.47.0 (f3c7e066a 2020-08-28)
root@02080d70998d:/app# cargo new hello --bin
Created binary (application) `hello` package
root@02080d70998d:/app# cd hello
root@02080d70998d:/app/hello# cargo run
(略)
Hello, world!
5. オートフォーマット
右下のベルマークのところに
Some Rust components not installed. Install?
と出るのでYesでインストール。
終わると保存したときに整形されるようになる。
コンテナを削除(orリビルド)した場合はもう一度やる必要がある。
6. マルチステージビルド
リリースビルドと同時にコンテナ化したいので専用のDockerfileとcomposeファイルを作る。
ついでにパッケージインストールはキャッシュさせて高速化したいのでそのあたりも対応。 [^3]
FROM rust:latest AS builder
WORKDIR /app
ENV USER=root
# RUN rustup target add x86_64-unknown-linux-musl
RUN cargo new my_prj
WORKDIR /app/my_prj
COPY ./hello/Cargo.toml ./hello/Cargo.lock ./
RUN cargo build --release
COPY ./hello/src ./src
RUN cargo build --release
FROM debian:stretch-slim AS prod
ENV TZ=Asia/Tokyo
COPY --from=builder /app/my_prj/target/release/ /usr/local/bin
WORKDIR /app
CMD ["hello"]
空プロジェクトを一度ビルドしてからsrcを入れ替えて再ビルドしている。
alpine向けにビルドしようとしてうまくいかなかったので調査中。
続いてcompose
version: '3.7'
services:
builder:
build:
context: .
dockerfile: DockerFile
target: builder
image: rust-test:builder
rust_test:
build:
context: .
dockerfile: DockerFile
target: prod
image: rust-test:latest
builderサービスをtarget: builder[^4]として定義してあげることで、マルチステージビルドにおけるビルドステージにあたるコンテナにタグをつけておくことができる。
こうすることでdanglingイメージ(:のこと)にならないので、ビルド途中の状態がキャッシュ出来る。
7. 実行用compose作成
rust-test:latestに必要な環境変数とか与えて実行できるようにする。
目新しいことがないので割愛
おわりに
開発用のDBも同時に立ち上がるようにしたり、他にもやったことがあるけど今回はここまで
追記
hot-reload効かない問題への対処
[^1]: targetフォルダは、通常プロジェクトフォルダの内部にできるが、composeファイルにプロジェクトファイルの名称を入れたくなかったため外出ししている
[^2]: 別フォルダに置く場合はenv_filesに指定する。
[^3]: Dockerfile的にはキャッシュしていると思うが、Rustのビルドの仕組みに明るくないので保証はできない。
[^4]: AS で付けた名前
[^5]: \cや\d以下の任意のフォルダ