環境
version | 備考 | |
---|---|---|
windows10 Pro | 1903 | (OSビルド) 18362.1082 |
Docker Desktop | 2.4.0.0(48506) | wsl2で動作 |
vscode | 1.49.3 | |
コンテナで開発・ビルドできるようにする。 | ||
しばらく離れていた&環境が変わったので自分用備忘録 | ||
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の中身を維持することができる。
小技とか
mnt=/app
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でコンテナを立ち上げる
-
適当なフォルダを作って上記のcomposeファイルを置き、codeで開く
-
vscodeに拡張機能Remote - Containersを追加する。
-
左下に追加される緑のボタンを押し、
Remote-Containers: Add Development Container Configuration Files...
を選択する -
From 'docker-compose.local.yml'
を選択する。
すると、.devcontainerというフォルダにdevcontainer.json、docker-compose.yml が作成されるのでそれぞれ編集する{docker-compose.yml}
version: '3.7'
services:
rust-dev:
# volumes: # この行コメントアウトした
# Update this to wherever you want VS Code to mount the folder of your project
# - .:/workspace:cached # この行もコメントアウト
# Overrides default command so things don't shut down after the process ends.
command: /bin/sh -c "while sleep 1000; do :; done"
```
こちらはvolumesをコメントアウトするだけ。
見やすさのために省略しているが、コメントに説明が書いてあるので、読んで適宜変更。
```{json:devcontainer.json}
{
"name": "rust😀",
"dockerComposeFile": [
"..\\docker-compose.local.yml",
"docker-compose.yml"
],
"service": "rust-dev",
"workspaceFolder": "/app",
"settings": {
"terminal.integrated.shell.linux": null,
"editor.formatOnSave": true,
"rust.target_dir": "/app/target"
},
"extensions": [
"rust-lang.rust",
"vadimcn.vscode-lldb"
]
}
```
<details><summary>分かる範囲で詳細</summary><div>
+ name
これだけコメントがない。vscodeでの表示上の名前、だけだと思う。
+ dockerComposeFile
composeファイルを読み込む順に書く。composeファイルをさらに分割している場合はここに書けばよい。
**基本的には変更する必要はない。**
+ service
composeファイルのservicesに定義した名前。複数定義している場合はメインとなるものを。
**基本的には変更する必要はない**
+ workspaceFolder
composeファイルで定義した、*working_dir*と同じ値を設定する。
コメントアウトすると`/`を開くのでdocker-compose.local.ymlで定義した値が上書きされるっぽい
じゃあ*working_dir*要らなかったじゃん。ソダネー
+ settings
vscodeのsetting.jsonに書いている内容をそのまま書ける。
コンテナ内部にだけ適用されるので、下記extensionsで追加する拡張機能に対する設定はここに書いておけば間違いない。
+ extensions
コンテナに導入したい拡張機能のIDを書く。IDは拡張機能の名前の横に表示されている。
例)図の灰色ががっている部分がID
とりあえずRust拡張機能とCodeLLDB。他にいいものがあれば知りたい。
+ forwardPorts
コンテナのポート開放する際にはアンコメントする。composeファイルにportsで書いても同じ。
</div></details>
**注意点**
settingsのrust.target_dir
これを書かないと、追加したcrateをrlsが見つけられずエラーが出る
-
volume作成
PS:> docker volume create rust_dev_target PS:> docker volume ls DRIVER VOLUME NAME local rust_dev_target
composeファイルで
external:true
しているので先に作っておかないとエラーになる -
左下の緑のボタンを押し、
Remote-Containers: Reopen in Container
を選択する。準備編終わり。
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ファイルを作る。
ついでにパッケージインストールはキャッシュさせて高速化したいのでそのあたりも対応。 2
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: builder3として定義してあげることで、マルチステージビルドにおけるビルドステージにあたるコンテナにタグをつけておくことができる。
こうすることでdanglingイメージ(<none>:<none>
のこと)にならないので、ビルド途中の状態がキャッシュ出来る。
7. 実行用compose作成
rust-test:latestに必要な環境変数とか与えて実行できるようにする。
目新しいことがないので割愛
おわりに
開発用のDBも同時に立ち上がるようにしたり、他にもやったことがあるけど今回はここまで
追記
hot-reload効かない問題への対処
プロジェクトをwindowsのファイルシステム上4に構築すると、
windows-linuxのファイルシステム間の問題でソースコードの変更検知がうまく走らない。
そのため、wslで管理しているディレクトリにコードを置く必要がある。
具体的には、
\\wsl$\Ubuntu-20.04\home\ユーザー名\workspace\プロジェクト名
など。