RustでDockerを操作する練習
Tokioを使うのでチュートリアルとAsynchronous Programming in Rustは読んでおいた方が良いと思う。
Rustの非同期I/Oはランタイムが勝手に何かやることが少ないので理解はしやすいかもしれない。他の言語の非同期処理は詳しくないので使いやすいかはよくわからない。
Rustのasync
/await
に関してはとりあえず以下のような適当な理解しかしていない。
-
async
-
async
は関数やブロックに指定でき、await
など非同期処理はその中でのみ実行可能。 - 非同期処理はできることがない時に処理を中断して別のタスクに処理を譲る必要があり、その時に状態を退避しなければならない。
async
はその退避すべき状態の場所をコンパイラに教えている。
-
-
await
- 上記の通りランタイムは自動的には何もしてくれないので、明示的に非同期処理が完了しているか確認するためのもの。
-
await
の他にjoin!
とかselect!
のマクロで確認することも可能。
bollardのドキュメントやサンプルプログラムやテストを見ながら以下のようなプログラムを書いた。Dockerのversionコマンド相当を呼んで結果を表示するだけ。
#[tokio::main]
pub async fn main() {
let docker = Docker::connect_with_unix_defaults().unwrap();
let version = docker.version().await.unwrap();
println!("{:?}", version);
}
#[tokio::main]
はmain関数で非同期I/Oを使うおまじない。mainでなければ要らない。bollardのサンプルにあるようにtokio::runtime::Runtime
を使っても良い。
API呼び出し(上記コードでは.version()
)が非同期I/Oになっているので.await
でI/O完了まで待ち合わせている。
話が前後するが、UbuntuでDockerを使う場合にやることメモ。Ubuntuのレポジトリにはないので、Docker本家のレポジトリを登録してCommunity Editionをインストールする。
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
sudo apt install docker-ce
sudo usermod -aG docker ${USER}
Dockerfileからイメージをビルドする方法。
bollardのbuild_image
メソッドを使う。渡すのはDockerfileではなくDockerfileを含めた必要なファイル一式のtaball。圧縮しなくても良い。
Rustでtarballを作る方法はbollardのテストを参考にすると良い。
Config
やBuildImageOptions
のようにフィールドが多い構造体を生成する時にデフォルト値を与えてくれる。
let config = Config {
image: Some(image.to_owned()),
..Default::default()
};
このように一部のフィールドを指定しつつ残りはデフォルトを使うことができる。
Rust Design Patternsでイディオムとして紹介されているし、Rust API Guidelinesでも実装することが推奨されている。
Bind mountする方法。
docker run -v /tmp:/mnt
相当は以下で実現できる。
let config = Config {
image: Some(imagename),
host_config: Some(HostConfig {
binds: Some(vec![String::from("/tmp:/mnt")]),
..Default::default()
}),
..Default::default()
};
Bind mountはホストに依存する機能なので、Config
ではなくHostConfig
で指定する。
ネットワーク関連のサンプルを探すと network_test.rs というテストを見つけた。
ただこれはネットワーク(bridge)を作るもので、やりたい事とは違うか。やりたいのはコンテナを既存のbridgeに繋ぐ方法。
裏技的だが、netnsでコンテナに無理矢理vethを生やすというやり方もありかも。(Rustはもはや関係ないが)
コンテナ(内のbash)のnetnsにvethを生やす。
docker run -it ubuntu bash
pid=$(pidof bash)
sudo ip netns attach hoge $pid
sudo ip link add name veth0 type veth peer name veth1
sudo ip link set veth1 netns hoge