diff --git a/docs/how-to/containerd-kata.md b/docs/how-to/containerd-kata.md index ce61b122cc..71efa6754d 100644 --- a/docs/how-to/containerd-kata.md +++ b/docs/how-to/containerd-kata.md @@ -257,6 +257,48 @@ This launches a BusyBox container named `hello`, and it will be removed by `--rm The `--cni` flag enables CNI networking for the container. Without this flag, a container with just a loopback interface is created. +### Launch containers using `ctr` command line with rootfs bundle + +#### Get rootfs +Use the script to create rootfs +```bash +ctr i pull quay.io/prometheus/busybox:latest +ctr i export rootfs.tar quay.io/prometheus/busybox:latest + +rootfs_tar=rootfs.tar +bundle_dir="./bundle" +mkdir -p "${bundle_dir}" + +# extract busybox rootfs +rootfs_dir="${bundle_dir}/rootfs" +mkdir -p "${rootfs_dir}" +layers_dir="$(mktemp -d)" +tar -C "${layers_dir}" -pxf "${rootfs_tar}" +for ((i=0;i<$(cat ${layers_dir}/manifest.json | jq -r ".[].Layers | length");i++)); do + tar -C ${rootfs_dir} -xf ${layers_dir}/$(cat ${layers_dir}/manifest.json | jq -r ".[].Layers[${i}]") +done +``` +#### Get `config.json` +Use runc spec to generate `config.json` +```bash +cd ./bundle/rootfs +runc spec +mv config.json ../ +``` +Change the root `path` in `config.json` to the absolute path of rootfs + +```JSON +"root":{ + "path":"/root/test/bundle/rootfs", + "readonly": false +}, +``` + +#### Run container +```bash +sudo ctr run -d --runtime io.containerd.run.kata.v2 --config bundle/config.json hello +sudo ctr t exec --exec-id ${ID} -t hello sh +``` ### Launch Pods with `crictl` command line With the `crictl` command line of `cri-tools`, you can specify runtime class with `-r` or `--runtime` flag. diff --git a/src/runtime-rs/crates/resource/src/manager.rs b/src/runtime-rs/crates/resource/src/manager.rs index 78b40380ff..c7e6b2d32f 100644 --- a/src/runtime-rs/crates/resource/src/manager.rs +++ b/src/runtime-rs/crates/resource/src/manager.rs @@ -68,11 +68,14 @@ impl ResourceManager { pub async fn handler_rootfs( &self, cid: &str, + root: &oci::Root, bundle_path: &str, rootfs_mounts: &[Mount], ) -> Result> { let inner = self.inner.read().await; - inner.handler_rootfs(cid, bundle_path, rootfs_mounts).await + inner + .handler_rootfs(cid, root, bundle_path, rootfs_mounts) + .await } pub async fn handler_volumes( diff --git a/src/runtime-rs/crates/resource/src/manager_inner.rs b/src/runtime-rs/crates/resource/src/manager_inner.rs index 791d76a375..0f7dd9bb68 100644 --- a/src/runtime-rs/crates/resource/src/manager_inner.rs +++ b/src/runtime-rs/crates/resource/src/manager_inner.rs @@ -196,6 +196,7 @@ impl ResourceManagerInner { pub async fn handler_rootfs( &self, cid: &str, + root: &oci::Root, bundle_path: &str, rootfs_mounts: &[Mount], ) -> Result> { @@ -205,6 +206,7 @@ impl ResourceManagerInner { self.hypervisor.as_ref(), &self.sid, cid, + root, bundle_path, rootfs_mounts, ) diff --git a/src/runtime-rs/crates/resource/src/rootfs/mod.rs b/src/runtime-rs/crates/resource/src/rootfs/mod.rs index 7af49fed74..5f69dd4654 100644 --- a/src/runtime-rs/crates/resource/src/rootfs/mod.rs +++ b/src/runtime-rs/crates/resource/src/rootfs/mod.rs @@ -51,16 +51,37 @@ impl RootFsResource { } } + #[allow(clippy::too_many_arguments)] pub async fn handler_rootfs( &self, share_fs: &Option>, hypervisor: &dyn Hypervisor, sid: &str, cid: &str, + root: &oci::Root, bundle_path: &str, rootfs_mounts: &[Mount], ) -> Result> { match rootfs_mounts { + // if rootfs_mounts is empty + mounts_vec if mounts_vec.is_empty() => { + if let Some(share_fs) = share_fs { + let share_fs_mount = share_fs.get_share_fs_mount(); + // share fs rootfs + Ok(Arc::new( + share_fs_rootfs::ShareFsRootfs::new( + &share_fs_mount, + cid, + root.path.as_str(), + None, + ) + .await + .context("new share fs rootfs")?, + )) + } else { + return Err(anyhow!("share fs is unavailable")); + } + } mounts_vec if is_single_layer_rootfs(mounts_vec) => { // Safe as single_layer_rootfs must have one layer let layer = &mounts_vec[0]; @@ -86,7 +107,7 @@ impl RootFsResource { &share_fs_mount, cid, bundle_path, - layer, + Some(layer), ) .await .context("new share fs rootfs")?, diff --git a/src/runtime-rs/crates/resource/src/rootfs/share_fs_rootfs.rs b/src/runtime-rs/crates/resource/src/rootfs/share_fs_rootfs.rs index 87ee869a4c..e526422297 100644 --- a/src/runtime-rs/crates/resource/src/rootfs/share_fs_rootfs.rs +++ b/src/runtime-rs/crates/resource/src/rootfs/share_fs_rootfs.rs @@ -23,14 +23,18 @@ impl ShareFsRootfs { share_fs_mount: &Arc, cid: &str, bundle_path: &str, - rootfs: &Mount, + rootfs: Option<&Mount>, ) -> Result { - let bundle_rootfs = format!("{}/{}", bundle_path, ROOTFS); - rootfs.mount(&bundle_rootfs).context(format!( - "mount rootfs from {:?} to {}", - &rootfs, &bundle_rootfs - ))?; - + let bundle_rootfs = if let Some(rootfs) = rootfs { + let bundle_rootfs = format!("{}/{}", bundle_path, ROOTFS); + rootfs.mount(&bundle_rootfs).context(format!( + "mount rootfs from {:?} to {}", + &rootfs, &bundle_rootfs + ))?; + bundle_rootfs + } else { + bundle_path.to_string() + }; let mount_result = share_fs_mount .share_rootfs(ShareFsRootfsConfig { cid: cid.to_string(), diff --git a/src/runtime-rs/crates/runtimes/virt_container/src/container_manager/container.rs b/src/runtime-rs/crates/runtimes/virt_container/src/container_manager/container.rs index 764eba08ce..ce17613d38 100644 --- a/src/runtime-rs/crates/runtimes/virt_container/src/container_manager/container.rs +++ b/src/runtime-rs/crates/runtimes/virt_container/src/container_manager/container.rs @@ -17,6 +17,7 @@ use common::{ }, }; use kata_sys_util::k8s::update_ephemeral_storage_type; + use oci::{LinuxResources, Process as OCIProcess}; use resource::ResourceManager; use tokio::sync::RwLock; @@ -85,23 +86,30 @@ impl Container { let sandbox_pidns = is_pid_namespace_enabled(&spec); amend_spec(&mut spec, toml_config.runtime.disable_guest_seccomp).context("amend spec")?; + // get mutable root from oci spec + let mut root = match spec.root.as_mut() { + Some(root) => root, + None => return Err(anyhow!("spec miss root field")), + }; + // handler rootfs let rootfs = self .resource_manager - .handler_rootfs(&config.container_id, &config.bundle, &config.rootfs_mounts) + .handler_rootfs( + &config.container_id, + root, + &config.bundle, + &config.rootfs_mounts, + ) .await .context("handler rootfs")?; // update rootfs - match spec.root.as_mut() { - Some(root) => { - root.path = rootfs - .get_guest_rootfs_path() - .await - .context("get guest rootfs path")? - } - None => return Err(anyhow!("spec miss root field")), - }; + root.path = rootfs + .get_guest_rootfs_path() + .await + .context("get guest rootfs path")?; + let mut storages = vec![]; if let Some(storage) = rootfs.get_storage().await { storages.push(storage);