sandbox
資料夾結構sandbox
├── cli.rs (*)
├── error.rs (part 1)
├── instance.rs
├── instance_utils.rs
├── manager.rs
├── mod.rs (part 1)
├── oci.rs
├── shim.rs
└── stdio.rs
sandbox/cli.rs
本章節要來看的是 cli
,此處為當我們執行 containerd-shim-...
時,會呼叫的實際函式。
需要注意的是,不管是哪一種版本的執行檔,包含:containerd-shim-[runtime]-v1
、containerd-shim-[runtime]d-v1
、containerd-[runtime]d
,實際上都會進入同樣的進入點,再根據執行程式的名稱決定建立與觸發對應的執行模式。有了這個關係,在追蹤程式碼的時候可以更加有結構性的深入。
use std::path::PathBuf;
use std::sync::mpsc::channel;
use std::sync::Arc;
use containerd_shim::{parse, run, Config};
use ttrpc::Server;
use crate::sandbox::manager::Shim;
use crate::sandbox::{Instance, Local, ManagerService, ShimCli};
use crate::services::sandbox_ttrpc::{create_manager, Manager};
// 使用 `git_version` 函式庫中的 `git_describe` 來取得版本資訊
pub mod r#impl {
pub use git_version::git_describe;
}
// 從本 crates 中取得版本與修訂版本的資訊
pub use crate::{revision, version};
// 定義版本與修訂版本的 macro
#[macro_export]
macro_rules! version {
() => {
env!("CARGO_PKG_VERSION")
};
}
// 定義修訂版本的 macro
#[macro_export]
macro_rules! revision {
() => {
Some($crate::sandbox::cli::r#impl::git_describe!(
"--match=:",
"--always",
"--abbrev=15",
"--dirty=.m"
))
};
}
// 主函式,用於啟動 shim
pub fn shim_main<I>(name: &str, version: &str, revision: Option<&str>, config: Option<Config>)
where
I: 'static + Instance + Sync + Send,
I::Engine: Default,
{
// 解析命令行參數
let os_args: Vec<_> = std::env::args_os().collect();
// argv0 代表呼叫 shim 的命令行的第一個參數,為 shim 的名稱,下面會藉由這個名稱來判斷 shim 的執行模式
// flags 代表除了 argv0 以外的命令行參數,為對應執行模式的參數
let flags = parse(&os_args[1..]).unwrap();
let argv0 = PathBuf::from(&os_args[0]);
let argv0 = argv0.file_stem().unwrap_or_default().to_string_lossy();
// 處理 --version 參數
if flags.version {
println!("{argv0}:");
println!(" Runtime: {name}");
println!(" Version: {version}");
println!(" Revision: {}", revision.unwrap_or("<none>"));
println!();
std::process::exit(0);
}
// name 指的是該 runtime 的名稱,例如:wasmtime
// 為了能統一化,因此將其轉換為小寫
let lower_name = name.to_lowercase();
// 根據名稱產生對應的 shim 名稱
let shim_cli = format!("containerd-shim-{lower_name}-v1");
let shim_client = format!("containerd-shim-{lower_name}d-v1");
let shim_daemon = format!("containerd-{lower_name}d");
let shim_id = format!("io.containerd.{lower_name}.v1");
// 根據 argv0 與 shim 名稱判斷並選擇對應的執行模式
match argv0.to_lowercase() {
s if s == shim_cli => {
run::<ShimCli<I>>(&shim_id, config);
}
s if s == shim_client => {
run::<Shim>(&shim_client, config);
}
s if s == shim_daemon => {
// 如果是 shim_daemon,則啟動 ttrpc 服務
log::info!("starting up!");
let s: ManagerService<Local<I>> = Default::default();
let s = Arc::new(Box::new(s) as Box<dyn Manager + Send + Sync>);
let service = create_manager(s);
let mut server = Server::new()
.bind("unix:///run/io.containerd.wasmwasi.v1/manager.sock")
.expect("failed to bind to socket")
.register_service(service);
server.start().expect("failed to start daemon");
log::info!("server started!");
let (_tx, rx) = channel::<()>();
rx.recv().unwrap();
}
_ => {
// 如果不是 shim_cli、shim_client、shim_daemon,則印出錯誤訊息並結束程式
eprintln!("error: unrecognized binary name, expected one of {shim_cli}, {shim_client}, or {shim_daemon}.");
std::process::exit(1);
}
}
}