From d4e9369d3da908af3f72454bb9f0d742995e1ecd Mon Sep 17 00:00:00 2001 From: "alex.lyn" Date: Sun, 1 Jun 2025 21:38:15 +0800 Subject: [PATCH 1/5] runtime-rs: Implement guest-pull rootfs via virtual volumes This commit introduces comprehensive support for rootfs mount mgmt through Kata Virtual Volumes, specifically enabling the guest-pull mechanism. It enhances the runtime's ability to: (1) Extract image references from container annotations (CRI/CRI-O). (2) Process `KataVirtualVolume` objects, configuring them for guest-pull operations. (3) Set up the agent's storage for guest-pulled images. This functionality streamlines the process of pulling container images directly within the guest for rootfs, aligning with guest-side image management strategies. Fixes #10690 Signed-off-by: alex.lyn --- .../crates/resource/src/rootfs/mod.rs | 1 + .../resource/src/rootfs/virtual_volume.rs | 297 ++++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 src/runtime-rs/crates/resource/src/rootfs/virtual_volume.rs diff --git a/src/runtime-rs/crates/resource/src/rootfs/mod.rs b/src/runtime-rs/crates/resource/src/rootfs/mod.rs index a9dbf5a827..c33854870b 100644 --- a/src/runtime-rs/crates/resource/src/rootfs/mod.rs +++ b/src/runtime-rs/crates/resource/src/rootfs/mod.rs @@ -11,6 +11,7 @@ use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use kata_types::mount::Mount; mod block_rootfs; +pub mod virtual_volume; use hypervisor::{device::device_manager::DeviceManager, Hypervisor}; use std::{sync::Arc, vec::Vec}; diff --git a/src/runtime-rs/crates/resource/src/rootfs/virtual_volume.rs b/src/runtime-rs/crates/resource/src/rootfs/virtual_volume.rs new file mode 100644 index 0000000000..32cf69a76a --- /dev/null +++ b/src/runtime-rs/crates/resource/src/rootfs/virtual_volume.rs @@ -0,0 +1,297 @@ +// Copyright (c) 2024-2025 Ant Group +// +// SPDX-License-Identifier: Apache-2.0 +// + +use std::path::Path; +use std::str::FromStr; +use std::{collections::HashMap, path::PathBuf}; + +use anyhow::{anyhow, Context, Result}; +use async_trait::async_trait; +use oci_spec::runtime as oci; +use serde_json; +use tokio::sync::RwLock; + +use hypervisor::device::device_manager::DeviceManager; +use kata_types::{ + annotations, + container::ContainerType, + mount::{KataVirtualVolume, KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL}, +}; + +/// Image guest-pull related consts +const KUBERNETES_CRI_IMAGE_NAME: &str = "io.kubernetes.cri.image-name"; +const KUBERNETES_CRIO_IMAGE_NAME: &str = "io.kubernetes.cri-o.ImageName"; +const KATA_VIRTUAL_VOLUME_PREFIX: &str = "io.katacontainers.volume="; +const KATA_VIRTUAL_VOLUME_TYPE_OVERLAY_FS: &str = "overlayfs"; +const KATA_GUEST_ROOT_SHARED_FS: &str = "/run/kata-containers/"; + +const CRI_CONTAINER_TYPE_KEY_LIST: &[&str] = &[ + // cri containerd + annotations::cri_containerd::CONTAINER_TYPE_LABEL_KEY, + // cri-o + annotations::crio::CONTAINER_TYPE_LABEL_KEY, +]; + +/// Retrieves the image reference from OCI spec annotations. +/// +/// It checks known Kubernetes CRI and CRI-O annotation keys for the container type. +/// If the container is a PodSandbox, it returns "pause". +/// Otherwise, it attempts to find the image name using the appropriate Kubernetes +/// annotation key. +pub fn get_image_reference(spec_annotations: &HashMap) -> Result<&str> { + info!( + sl!(), + "get image reference from spec annotation: {:?}", spec_annotations + ); + for &key in CRI_CONTAINER_TYPE_KEY_LIST { + if let Some(type_value) = spec_annotations.get(key) { + if let Ok(container_type) = ContainerType::from_str(type_value) { + return match container_type { + ContainerType::PodSandbox => Ok("pause"), + _ => { + let image_name_key = if key == annotations::crio::CONTAINER_TYPE_LABEL_KEY { + KUBERNETES_CRIO_IMAGE_NAME + } else { + KUBERNETES_CRI_IMAGE_NAME + }; + + spec_annotations + .get(image_name_key) + .map(AsRef::as_ref) + .ok_or_else(|| anyhow!("get image reference failed")) + } + }; + } + } + } + + Err(anyhow!("no target image reference found")) +} + +/// Handles storage configuration for KataVirtualVolume based on its type. +/// Specifically processes `KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL` type. +/// Processes a virtual volume specifically for image guest-pull scenarios. +/// It enriches the volume info with image reference and metadata, then serializes it into agent.Storage. +fn handle_virtual_volume_storage( + cid: &str, + annotations: &HashMap, + virt_volume: &KataVirtualVolume, +) -> Result { + if virt_volume.volume_type.as_str() == KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL { + // get container image reference + let image_ref = get_image_reference(annotations).context("get image reference failed.")?; + + let mut virtual_volume_info = virt_volume.clone(); + // Merge metadata + for (k, v) in annotations.iter() { + if let Some(ref mut image_pull) = virtual_volume_info.image_pull { + image_pull.metadata.insert(k.to_owned(), v.to_owned()); + } + } + // Serialize ImagePull as JSON + let image_pull_info = serde_json::to_string(&virtual_volume_info.image_pull) + .map_err(|e| anyhow!(e.to_string()))?; + + // build the agent Storage Object + Ok(agent::Storage { + source: image_ref.to_string(), + driver: KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL.to_string(), + driver_options: vec![format!( + "{}={}", + KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL, image_pull_info + )], + fs_type: KATA_VIRTUAL_VOLUME_TYPE_OVERLAY_FS.to_string(), + mount_point: Path::new(KATA_GUEST_ROOT_SHARED_FS) + .join(cid) + .join("rootfs") + .display() + .to_string(), + ..Default::default() + }) + } else { + Err(anyhow!( + "Error in handle virtual volume storage with unsupported type: {:?}", + virt_volume.volume_type + )) + } +} + +#[derive(Clone, Debug, Default)] +pub(crate) struct VirtualVolume { + guest_path: PathBuf, + storages: Vec, +} + +impl VirtualVolume { + #[allow(dead_code)] + pub(crate) async fn new( + cid: &str, + annotations: &HashMap, + options: Vec, + ) -> Result { + let mut volumes = Vec::new(); + + // It's ensured that the virtual volume info is indeed existing in the options, as pre-check with `is_kata_virtual_volume()` is done. + for o in options.iter() { + // Iterate over reference to avoid consuming options + if let Some(stripped_str) = o.strip_prefix(KATA_VIRTUAL_VOLUME_PREFIX) { + // Ensure `from_base64` provides a descriptive error on failure + let virt_volume = KataVirtualVolume::from_base64(stripped_str).context(format!( + "Failed to decode KataVirtualVolume from base64: {}", + stripped_str + ))?; + + let vol = handle_virtual_volume_storage(cid, annotations, &virt_volume) + .context("Failed to handle virtual volume storage object")?; + volumes.push(vol); + + // As there's only one virtual volume supported, when the first one is hit, just break the iteration. + break; + } + } + + let guest_path = Path::new(KATA_GUEST_ROOT_SHARED_FS) + .join(cid) + .join("rootfs") + .to_path_buf(); + + Ok(VirtualVolume { + guest_path, + storages: volumes, + }) + } +} + +#[async_trait] +impl super::Rootfs for VirtualVolume { + async fn get_guest_rootfs_path(&self) -> Result { + Ok(self.guest_path.display().to_string().clone()) + } + + async fn get_rootfs_mount(&self) -> Result> { + Ok(vec![]) + } + + async fn get_storage(&self) -> Option { + Some(self.storages[0].clone()) + } + + async fn get_device_id(&self) -> Result> { + Ok(None) + } + + async fn cleanup(&self, _device_manager: &RwLock) -> Result<()> { + Ok(()) + } +} + +pub fn is_kata_virtual_volume(m: &kata_types::mount::Mount) -> bool { + let options = m.options.clone(); + options + .iter() + .any(|o| o.starts_with(&KATA_VIRTUAL_VOLUME_PREFIX.to_owned())) +} + +#[cfg(test)] +mod tests { + use crate::rootfs::virtual_volume::{ + KATA_GUEST_ROOT_SHARED_FS, KATA_VIRTUAL_VOLUME_PREFIX, KATA_VIRTUAL_VOLUME_TYPE_OVERLAY_FS, + }; + + use super::get_image_reference; + use super::VirtualVolume; + use kata_types::mount::{KataVirtualVolume, KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL}; + use std::{collections::HashMap, path::Path}; + + #[test] + fn test_get_image_ref() { + // Test Standard cri-containerd image name + let mut annotations_x = HashMap::new(); + annotations_x.insert( + "io.kubernetes.cri.container-type".to_string(), + "container".to_string(), + ); + annotations_x.insert( + "io.kubernetes.cri.image-name".to_string(), + "example-image-x".to_string(), + ); + let image_ref_result_crio = get_image_reference(&annotations_x); + assert!(image_ref_result_crio.is_ok()); + assert_eq!(image_ref_result_crio.unwrap(), "example-image-x"); + + // Test cri-o image name + let mut annotations_crio = HashMap::new(); + annotations_crio.insert( + "io.kubernetes.cri-o.ContainerType".to_string(), + "container".to_string(), + ); + annotations_crio.insert( + "io.kubernetes.cri-o.ImageName".to_string(), + "example-image-y".to_string(), + ); + let image_ref_result_crio = get_image_reference(&annotations_crio); + assert!(image_ref_result_crio.is_ok()); + assert_eq!(image_ref_result_crio.unwrap(), "example-image-y"); + + // Test PodSandbox type + let mut annotations_pod_sandbox = HashMap::new(); + annotations_pod_sandbox.insert( + "io.kubernetes.cri.container-type".to_string(), + "sandbox".to_string(), + ); + let image_ref_result_pod_sandbox = get_image_reference(&annotations_pod_sandbox); + assert!(image_ref_result_pod_sandbox.is_ok()); + assert_eq!(image_ref_result_pod_sandbox.unwrap(), "pause"); + } + + #[tokio::test] + async fn test_virtual_volume_new_success() { + let virt_vol = KataVirtualVolume { + volume_type: KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL.to_string(), + source: KATA_VIRTUAL_VOLUME_TYPE_OVERLAY_FS.to_owned(), + ..Default::default() + }; + let encoded_vol = virt_vol.to_base64().unwrap(); + let options = vec![format!("{}{}", KATA_VIRTUAL_VOLUME_PREFIX, encoded_vol)]; + + let mut annotations = HashMap::new(); + annotations.insert( + "io.kubernetes.cri.container-type".to_string(), + "container".to_string(), + ); + annotations.insert( + "io.kubernetes.cri.image-name".to_string(), + "example-image-x".to_string(), + ); + + let cid = "4adf90201"; + let result = VirtualVolume::new(cid, &annotations, options).await; + assert!(result.is_ok()); + let virt_vol_obj = result.unwrap(); + + // 1. Verify guest_path + let expected_guest_path = Path::new(KATA_GUEST_ROOT_SHARED_FS) + .join(cid) + .join("rootfs"); + assert_eq!(virt_vol_obj.guest_path, expected_guest_path); + + // 2. Verify storages vector length + assert_eq!(virt_vol_obj.storages.len(), 1); + + // 3. Verify the content of the AgentStorage object + let storage = &virt_vol_obj.storages[0]; + + assert_eq!(storage.source, "example-image-x".to_string()); + assert_eq!(storage.driver, KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL); + assert_eq!(storage.fs_type, KATA_VIRTUAL_VOLUME_TYPE_OVERLAY_FS); + + let expected_mount_point = Path::new(KATA_GUEST_ROOT_SHARED_FS) + .join(cid) + .join("rootfs") + .display() + .to_string(); + assert_eq!(storage.mount_point, expected_mount_point); + } +} From 2600fc6f438235c33836516d2f4b8d534fed84c6 Mon Sep 17 00:00:00 2001 From: "alex.lyn" Date: Sun, 1 Jun 2025 21:58:39 +0800 Subject: [PATCH 2/5] runtime-rs: Add Spec annotation to help pass image information We need get the relevent image ref from OCI runtime Spec, especially the annotation of it. Fixes #10690 Signed-off-by: alex.lyn --- src/runtime-rs/crates/resource/src/manager.rs | 4 +++- src/runtime-rs/crates/resource/src/manager_inner.rs | 4 +++- src/runtime-rs/crates/resource/src/rootfs/mod.rs | 3 ++- .../virt_container/src/container_manager/container.rs | 3 +++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/runtime-rs/crates/resource/src/manager.rs b/src/runtime-rs/crates/resource/src/manager.rs index f2b35996fb..05e0b04605 100644 --- a/src/runtime-rs/crates/resource/src/manager.rs +++ b/src/runtime-rs/crates/resource/src/manager.rs @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 // +use std::collections::HashMap; use std::sync::Arc; use agent::{Agent, Storage}; @@ -100,10 +101,11 @@ impl ResourceManager { root: &oci::Root, bundle_path: &str, rootfs_mounts: &[Mount], + annotations: &HashMap, ) -> Result> { let inner = self.inner.read().await; inner - .handler_rootfs(cid, root, bundle_path, rootfs_mounts) + .handler_rootfs(cid, root, bundle_path, rootfs_mounts, annotations) .await } diff --git a/src/runtime-rs/crates/resource/src/manager_inner.rs b/src/runtime-rs/crates/resource/src/manager_inner.rs index ba5eae5cf5..f8d40cff72 100644 --- a/src/runtime-rs/crates/resource/src/manager_inner.rs +++ b/src/runtime-rs/crates/resource/src/manager_inner.rs @@ -4,7 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::{sync::Arc, thread}; +use std::{collections::HashMap, sync::Arc, thread}; use agent::{types::Device, Agent, OnlineCPUMemRequest, Storage}; use anyhow::{anyhow, Context, Ok, Result}; @@ -320,6 +320,7 @@ impl ResourceManagerInner { root: &oci::Root, bundle_path: &str, rootfs_mounts: &[Mount], + annotations: &HashMap, ) -> Result> { self.rootfs_resource .handler_rootfs( @@ -331,6 +332,7 @@ impl ResourceManagerInner { root, bundle_path, rootfs_mounts, + annotations, ) .await } diff --git a/src/runtime-rs/crates/resource/src/rootfs/mod.rs b/src/runtime-rs/crates/resource/src/rootfs/mod.rs index c33854870b..61317daaa4 100644 --- a/src/runtime-rs/crates/resource/src/rootfs/mod.rs +++ b/src/runtime-rs/crates/resource/src/rootfs/mod.rs @@ -14,7 +14,7 @@ mod block_rootfs; pub mod virtual_volume; use hypervisor::{device::device_manager::DeviceManager, Hypervisor}; -use std::{sync::Arc, vec::Vec}; +use std::{collections::HashMap, sync::Arc, vec::Vec}; use tokio::sync::RwLock; use self::{block_rootfs::is_block_rootfs, nydus_rootfs::NYDUS_ROOTFS_TYPE}; @@ -67,6 +67,7 @@ impl RootFsResource { root: &oci::Root, bundle_path: &str, rootfs_mounts: &[Mount], + _annotations: &HashMap, ) -> Result> { match rootfs_mounts { // if rootfs_mounts is empty 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 75c6427c0a..93cd6effd0 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 @@ -110,6 +110,8 @@ impl Container { // is 'true'. None => true, }; + let annotations = spec.annotations().clone().unwrap_or_default(); + amend_spec( &mut spec, toml_config.runtime.disable_guest_seccomp, @@ -131,6 +133,7 @@ impl Container { root, &config.bundle, &config.rootfs_mounts, + &annotations, ) .await .context("handler rootfs")?; From c9ffbaf30dd936845626cdd52f885d2193da5270 Mon Sep 17 00:00:00 2001 From: "alex.lyn" Date: Sun, 1 Jun 2025 22:01:42 +0800 Subject: [PATCH 3/5] runtime-rs: Support handling Kata Virtual Volume in handle_rootfs In CoCo scenarios, there's no image pulling on host side, and it will disable such operations, that's to say, there's no files sharing between host and guest, especially for container rootfs. We introduce Kata Virtual Volume to help handle such cases: (1) Introduce is_kata_virtual_volume to ensure the volume is kata virtual volume. (2) Introduce VirtualVolume Handling logic in handle_rootfs when the mount is kata virtual volume. Fixes #10690 Signed-off-by: alex.lyn --- .../crates/resource/src/rootfs/mod.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/runtime-rs/crates/resource/src/rootfs/mod.rs b/src/runtime-rs/crates/resource/src/rootfs/mod.rs index 61317daaa4..e0d34e22ba 100644 --- a/src/runtime-rs/crates/resource/src/rootfs/mod.rs +++ b/src/runtime-rs/crates/resource/src/rootfs/mod.rs @@ -12,7 +12,9 @@ use async_trait::async_trait; use kata_types::mount::Mount; mod block_rootfs; pub mod virtual_volume; + use hypervisor::{device::device_manager::DeviceManager, Hypervisor}; +use virtual_volume::{is_kata_virtual_volume, VirtualVolume}; use std::{collections::HashMap, sync::Arc, vec::Vec}; use tokio::sync::RwLock; @@ -67,7 +69,7 @@ impl RootFsResource { root: &oci::Root, bundle_path: &str, rootfs_mounts: &[Mount], - _annotations: &HashMap, + annotations: &HashMap, ) -> Result> { match rootfs_mounts { // if rootfs_mounts is empty @@ -92,6 +94,17 @@ impl RootFsResource { // Safe as single_layer_rootfs must have one layer let layer = &mounts_vec[0]; let mut inner = self.inner.write().await; + + if is_guest_pull_volume(share_fs, layer) { + let mount_options = layer.options.clone(); + let virtual_volume: Arc = Arc::new( + VirtualVolume::new(cid, annotations, mount_options.to_vec()) + .await + .context("kata virtual volume failed.")?, + ); + return Ok(virtual_volume); + } + let rootfs = if let Some(dev_id) = is_block_rootfs(&layer.source) { // handle block rootfs info!(sl!(), "block device: {}", dev_id); @@ -160,3 +173,10 @@ impl RootFsResource { fn is_single_layer_rootfs(rootfs_mounts: &[Mount]) -> bool { rootfs_mounts.len() == 1 } + +pub fn is_guest_pull_volume( + share_fs: &Option>, + m: &kata_types::mount::Mount, +) -> bool { + share_fs.is_none() && is_kata_virtual_volume(m) +} From 21570751400c731f217a661fcba325bc1c94f079 Mon Sep 17 00:00:00 2001 From: "alex.lyn" Date: Sun, 1 Jun 2025 22:28:56 +0800 Subject: [PATCH 4/5] kata-types: Introduce a helper method to adjust rootfs mounts This commit introduces the `adjust_rootfs_mounts` function to manage root filesystem mounts for guest-pull scenarios. When the force guest-pull mechanism is active, this function ensures that the rootfs is exclusively configured via a dedicated `KataVirtualVolume`. It disregards any provided input mounts, instead generating a single, default `KataVirtualVolume`. This volume is then base64-encoded and set as the sole mount option for a new, singular `Mount` entry, which is returned as the only item in the `Vec`. This change guarantees consistent and exclusive rootfs configuration when utilizing guest-pull for container images. Signed-off-by: alex.lyn --- src/libs/kata-types/src/mount.rs | 55 ++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/libs/kata-types/src/mount.rs b/src/libs/kata-types/src/mount.rs index 848bde6355..629a1ee3b5 100644 --- a/src/libs/kata-types/src/mount.rs +++ b/src/libs/kata-types/src/mount.rs @@ -512,6 +512,29 @@ pub fn split_bind_mounts(bindmount: &str) -> (&str, &str) { (real_path, mode) } +/// This function, adjust_rootfs_mounts, manages the root filesystem mounts based on guest-pull mechanism. +/// - the function disregards any provided rootfs_mounts. +/// Instead, it forcefully creates a single, default KataVirtualVolume specifically for guest-pull operations. +/// This volume's representation is then base64-encoded and added as the only option to a new, singular Mount entry, +/// which becomes the sole item in the returned Vec. +/// This ensures that when guest pull is active, the root filesystem is exclusively configured via this virtual volume. +pub fn adjust_rootfs_mounts() -> Result> { + // We enforce a single, default KataVirtualVolume as the exclusive rootfs mount. + let volume = KataVirtualVolume::new(KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL.to_string()); + + // Convert the virtual volume to a base64 string for the mount option. + let b64_vol = volume + .to_base64() + .context("failed to base64 encode KataVirtualVolume")?; + + // Create a new Vec with a single Mount entry. + // This Mount's options will contain the base64-encoded virtual volume. + Ok(vec![Mount { + options: vec![format!("{}={}", "io.katacontainers.volume", b64_vol)], + ..Default::default() // Use default values for other Mount fields + }]) +} + #[cfg(test)] mod tests { use super::*; @@ -681,4 +704,36 @@ mod tests { ); assert_eq!(volume.fs_type.as_str(), "rafsv6") } + + #[test] + fn test_adjust_rootfs_mounts_basic_success() { + let result = adjust_rootfs_mounts(); + assert!(result.is_ok()); + let mounts = result.unwrap(); + + // 1. Mount length is 1 + assert_eq!(mounts.len(), 1); + let returned_mount = &mounts[0]; + + // 2. Verify Mount's fields and ensure source, destination, typ with default value + let expected_default_mount = Mount::default(); + assert_eq!(returned_mount.source, expected_default_mount.source); + assert_eq!( + returned_mount.destination, + expected_default_mount.destination + ); + assert_eq!(returned_mount.fs_type, expected_default_mount.fs_type); + + // 3. Mount's options + assert_eq!(returned_mount.options.len(), 1); + let option_str = &returned_mount.options[0]; + assert!(option_str.starts_with("io.katacontainers.volume=")); + + let expected_volume_obj = + KataVirtualVolume::new(KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL.to_string()); + let expected_b64_vol = expected_volume_obj.to_base64().unwrap(); + let (_prefix, encoded_vol) = option_str.split_once("io.katacontainers.volume=").unwrap(); + + assert_eq!(encoded_vol, expected_b64_vol); + } } From cebb259e5142bc74f48e0ad7e4fb11340e622711 Mon Sep 17 00:00:00 2001 From: "alex.lyn" Date: Sun, 1 Jun 2025 22:45:15 +0800 Subject: [PATCH 5/5] runtime-rs: Introduce force guest pulling image Container image integrity protection is a critical practice involving a multi-layered defense mechanism. While container images inherently offer basic integrity verification through Content-Addressable Storage (CAS) (ensuring pulled content matches stored hashes), a combination of other measures is crucial for production environments. These layers include: Encrypted Transport (HTTPS/TLS) to prevent tampering during transfer; Image Signing to confirm the image originates from a trusted source; Vulnerability Scanning to ensure the image content is "healthy"; and Trusted Registries with stringent access controls. In certain scenarios, such as when container image confidentiality requirements are not stringent, and integrity is already ensured via the aforementioned mechanisms (especially CAS and HTTPS/TLS), adopting "force guest pull" can be a viable option. This implies that even when pulling images from a container registry, their integrity remains guaranteed through content hashes and other built-in mechanisms, without relying on additional host-side verification or specialized transfer methods. Since this feature is already available in runtime-go and offers synergistic benefits with guest pull, we have chosen to support force guest pull. Fixes #10690 Signed-off-by: alex.lyn --- src/libs/kata-types/src/mount.rs | 2 ++ .../crates/resource/src/manager_inner.rs | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/libs/kata-types/src/mount.rs b/src/libs/kata-types/src/mount.rs index 629a1ee3b5..eac2afbffb 100644 --- a/src/libs/kata-types/src/mount.rs +++ b/src/libs/kata-types/src/mount.rs @@ -63,6 +63,8 @@ pub const KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS: &str = "image_nydus_fs"; pub const KATA_VIRTUAL_VOLUME_LAYER_NYDUS_FS: &str = "layer_nydus_fs"; /// Download and extra container image inside guest vm. pub const KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL: &str = "image_guest_pull"; +/// In CoCo scenario, we support force_guest_pull to enforce container image guest pull without remote snapshotter. +pub const KATA_IMAGE_FORCE_GUEST_PULL: &str = "force_guest_pull"; /// Manager to manage registered storage device handlers. pub type StorageHandlerManager = HandlerManager; diff --git a/src/runtime-rs/crates/resource/src/manager_inner.rs b/src/runtime-rs/crates/resource/src/manager_inner.rs index f8d40cff72..2f419c4100 100644 --- a/src/runtime-rs/crates/resource/src/manager_inner.rs +++ b/src/runtime-rs/crates/resource/src/manager_inner.rs @@ -17,8 +17,11 @@ use hypervisor::{ }, BlockConfig, Hypervisor, VfioConfig, }; -use kata_types::config::{hypervisor::TopologyConfigInfo, TomlConfig}; use kata_types::mount::Mount; +use kata_types::{ + config::{hypervisor::TopologyConfigInfo, TomlConfig}, + mount::{adjust_rootfs_mounts, KATA_IMAGE_FORCE_GUEST_PULL}, +}; use oci::{Linux, LinuxCpu, LinuxResources}; use oci_spec::runtime::{self as oci, LinuxDeviceType}; use persist::sandbox_persist::Persist; @@ -322,6 +325,16 @@ impl ResourceManagerInner { rootfs_mounts: &[Mount], annotations: &HashMap, ) -> Result> { + let adjust_rootfs_mounts = if !self + .config() + .runtime + .is_experiment_enabled(KATA_IMAGE_FORCE_GUEST_PULL) + { + rootfs_mounts.to_vec() + } else { + adjust_rootfs_mounts()? + }; + self.rootfs_resource .handler_rootfs( &self.share_fs, @@ -331,7 +344,7 @@ impl ResourceManagerInner { cid, root, bundle_path, - rootfs_mounts, + &adjust_rootfs_mounts, annotations, ) .await