mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-17 14:58:16 +00:00
runtime-rs: add the ephemeral memory based volume support
For k8s, there's two type of volumes based on ephemral memory, one is emptydir volume based on ephemeral memory, and the other one is used for shm device such as /dev/shm. Thus add a new volume type ephemeral volume to support those two type volumes and remove the legacy shm volume. Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
This commit is contained in:
114
src/runtime-rs/crates/resource/src/volume/ephemeral_volume.rs
Normal file
114
src/runtime-rs/crates/resource/src/volume/ephemeral_volume.rs
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||
// Copyright (c) 2019-2022 Ant Group
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::Volume;
|
||||
use crate::share_fs::DEFAULT_KATA_GUEST_SANDBOX_DIR;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use async_trait::async_trait;
|
||||
use hypervisor::device::device_manager::DeviceManager;
|
||||
use kata_sys_util::mount::{get_mount_path, get_mount_type};
|
||||
use kata_types::mount::KATA_EPHEMERAL_VOLUME_TYPE;
|
||||
use nix::sys::stat::stat;
|
||||
use oci_spec::runtime as oci;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct EphemeralVolume {
|
||||
mount: oci::Mount,
|
||||
storage: Option<agent::Storage>,
|
||||
}
|
||||
|
||||
impl EphemeralVolume {
|
||||
pub(crate) fn new(m: &oci::Mount) -> Result<Self> {
|
||||
if m.source().is_none() {
|
||||
return Err(anyhow!(format!(
|
||||
"got a wrong volume without source: {:?}",
|
||||
m
|
||||
)));
|
||||
}
|
||||
|
||||
// refer to the golang `handleEphemeralStorage` code at
|
||||
// https://github.com/kata-containers/kata-containers/blob/9516286f6dd5cfd6b138810e5d7c9e01cf6fc043/src/runtime/virtcontainers/kata_agent.go#L1354
|
||||
|
||||
let source = &get_mount_path(m.source());
|
||||
let file_stat =
|
||||
stat(Path::new(source)).with_context(|| format!("mount source {}", source))?;
|
||||
|
||||
// if volume's gid isn't root group(default group), this means there's
|
||||
// an specific fsGroup is set on this local volume, then it should pass
|
||||
// to guest.
|
||||
let dir_options = if file_stat.st_gid != 0 {
|
||||
vec![format!("fsgid={}", file_stat.st_gid)]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let file_name = Path::new(source)
|
||||
.file_name()
|
||||
.context(format!("get file name from {:?}", &m.source()))?;
|
||||
let source = Path::new(DEFAULT_KATA_GUEST_SANDBOX_DIR)
|
||||
.join(KATA_EPHEMERAL_VOLUME_TYPE)
|
||||
.join(file_name)
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.map_err(|e| anyhow!("failed to get ephemeral path {:?}", e))?;
|
||||
|
||||
// Create a storage struct so that kata agent is able to create
|
||||
// tmpfs backed volume inside the VM
|
||||
let ephemeral_storage = agent::Storage {
|
||||
driver: String::from(KATA_EPHEMERAL_VOLUME_TYPE),
|
||||
driver_options: Vec::new(),
|
||||
source: String::from("tmpfs"),
|
||||
fs_type: String::from("tmpfs"),
|
||||
fs_group: None,
|
||||
options: dir_options,
|
||||
mount_point: source.clone(),
|
||||
};
|
||||
|
||||
let mut mount = oci::Mount::default();
|
||||
mount.set_destination(m.destination().clone());
|
||||
mount.set_typ(Some("bind".to_string()));
|
||||
mount.set_source(Some(PathBuf::from(&source)));
|
||||
mount.set_options(Some(vec!["rbind".to_string()]));
|
||||
|
||||
Ok(Self {
|
||||
mount,
|
||||
storage: Some(ephemeral_storage),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Volume for EphemeralVolume {
|
||||
fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> {
|
||||
Ok(vec![self.mount.clone()])
|
||||
}
|
||||
|
||||
fn get_storage(&self) -> Result<Vec<agent::Storage>> {
|
||||
let s = if let Some(s) = self.storage.as_ref() {
|
||||
vec![s.clone()]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
async fn cleanup(&self, _device_manager: &RwLock<DeviceManager>) -> Result<()> {
|
||||
// TODO: Clean up EphemeralVolume
|
||||
warn!(sl!(), "Cleaning up EphemeralVolume is still unimplemented.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_device_id(&self) -> Result<Option<String>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_ephemeral_volume(m: &oci::Mount) -> bool {
|
||||
get_mount_type(m).as_str() == KATA_EPHEMERAL_VOLUME_TYPE
|
||||
}
|
@@ -6,9 +6,9 @@
|
||||
|
||||
mod block_volume;
|
||||
mod default_volume;
|
||||
mod ephemeral_volume;
|
||||
pub mod hugepage;
|
||||
mod share_fs_volume;
|
||||
mod shm_volume;
|
||||
pub mod utils;
|
||||
|
||||
pub mod direct_volume;
|
||||
@@ -67,10 +67,9 @@ impl VolumeResource {
|
||||
// handle mounts
|
||||
for m in oci_mounts {
|
||||
let read_only = get_mount_options(m.options()).iter().any(|opt| opt == "ro");
|
||||
let volume: Arc<dyn Volume> = if shm_volume::is_shm_volume(m) {
|
||||
let shm_size = shm_volume::DEFAULT_SHM_SIZE;
|
||||
let volume: Arc<dyn Volume> = if ephemeral_volume::is_ephemeral_volume(m) {
|
||||
Arc::new(
|
||||
shm_volume::ShmVolume::new(m, shm_size)
|
||||
ephemeral_volume::EphemeralVolume::new(m)
|
||||
.with_context(|| format!("new shm volume {:?}", m))?,
|
||||
)
|
||||
} else if is_block_volume(m) {
|
||||
|
@@ -1,119 +0,0 @@
|
||||
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||
// Copyright (c) 2019-2022 Ant Group
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::Volume;
|
||||
use crate::share_fs::DEFAULT_KATA_GUEST_SANDBOX_DIR;
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use hypervisor::device::device_manager::DeviceManager;
|
||||
use kata_sys_util::mount::{get_mount_path, get_mount_type};
|
||||
use oci_spec::runtime as oci;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub const SHM_DIR: &str = "shm";
|
||||
// DEFAULT_SHM_SIZE is the default shm size to be used in case host
|
||||
// IPC is used.
|
||||
pub const DEFAULT_SHM_SIZE: u64 = 65536 * 1024;
|
||||
|
||||
// KATA_EPHEMERAL_DEV_TYPE creates a tmpfs backed volume for sharing files between containers.
|
||||
pub const KATA_EPHEMERAL_DEV_TYPE: &str = "ephemeral";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ShmVolume {
|
||||
mount: oci::Mount,
|
||||
storage: Option<agent::Storage>,
|
||||
}
|
||||
|
||||
impl ShmVolume {
|
||||
pub(crate) fn new(m: &oci::Mount, shm_size: u64) -> Result<Self> {
|
||||
let (storage, mount) = if shm_size > 0 {
|
||||
// storage
|
||||
let mount_path = Path::new(DEFAULT_KATA_GUEST_SANDBOX_DIR).join(SHM_DIR);
|
||||
let mount_path = mount_path.to_str().unwrap();
|
||||
let option = format!("size={}", shm_size);
|
||||
|
||||
let options = vec![
|
||||
String::from("noexec"),
|
||||
String::from("nosuid"),
|
||||
String::from("nodev"),
|
||||
String::from("mode=1777"),
|
||||
option,
|
||||
];
|
||||
|
||||
let storage = agent::Storage {
|
||||
driver: String::from(KATA_EPHEMERAL_DEV_TYPE),
|
||||
driver_options: Vec::new(),
|
||||
source: String::from("shm"),
|
||||
fs_type: String::from("tmpfs"),
|
||||
fs_group: None,
|
||||
options,
|
||||
mount_point: mount_path.to_string(),
|
||||
};
|
||||
|
||||
let mut oci_mount = oci::Mount::default();
|
||||
oci_mount.set_destination(m.destination().clone());
|
||||
oci_mount.set_typ(Some("bind".to_string()));
|
||||
oci_mount.set_source(Some(PathBuf::from(&mount_path)));
|
||||
oci_mount.set_options(Some(vec!["rbind".to_string()]));
|
||||
|
||||
(Some(storage), oci_mount)
|
||||
} else {
|
||||
let mut oci_mount = oci::Mount::default();
|
||||
oci_mount.set_destination(m.destination().clone());
|
||||
oci_mount.set_typ(Some("tmpfs".to_string()));
|
||||
oci_mount.set_source(Some(PathBuf::from("shm")));
|
||||
oci_mount.set_options(Some(
|
||||
[
|
||||
"noexec",
|
||||
"nosuid",
|
||||
"nodev",
|
||||
"mode=1777",
|
||||
&format!("size={}", DEFAULT_SHM_SIZE),
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect(),
|
||||
));
|
||||
|
||||
(None, oci_mount)
|
||||
};
|
||||
|
||||
Ok(Self { storage, mount })
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Volume for ShmVolume {
|
||||
fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> {
|
||||
Ok(vec![self.mount.clone()])
|
||||
}
|
||||
|
||||
fn get_storage(&self) -> Result<Vec<agent::Storage>> {
|
||||
let s = if let Some(s) = self.storage.as_ref() {
|
||||
vec![s.clone()]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
async fn cleanup(&self, _device_manager: &RwLock<DeviceManager>) -> Result<()> {
|
||||
// TODO: Clean up ShmVolume
|
||||
warn!(sl!(), "Cleaning up ShmVolume is still unimplemented.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_device_id(&self) -> Result<Option<String>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_shm_volume(m: &oci::Mount) -> bool {
|
||||
get_mount_path(&Some(m.destination().clone())).as_str() == "/dev/shm"
|
||||
&& get_mount_type(m).as_str() != KATA_EPHEMERAL_DEV_TYPE
|
||||
}
|
Reference in New Issue
Block a user