agent: sandbox shared pid namespace support

Add support shareProcessNamespace.
BTW, this commit only support shared pid namespace by
sharing the infrastructure pause container's pid namespace
with other containers, instead of creating a new pid
namespace different from pause container.

Fixes: #342

Signed-off-by: fupan.lfp <fupan.lfp@antfin.com>
This commit is contained in:
fupan.lfp 2020-07-13 15:45:52 +08:00
parent afcf269c9b
commit c6e4d092d6
3 changed files with 68 additions and 14 deletions

View File

@ -65,6 +65,11 @@ impl Namespace {
self
}
pub fn as_pid(mut self) -> Self {
self.ns_type = NamespaceType::PID;
self
}
pub fn set_root_dir(mut self, dir: &str) -> Self {
self.persistent_ns_dir = dir.to_string();
self

View File

@ -79,6 +79,7 @@ impl agentService {
let cid = req.container_id.clone();
let mut oci_spec = req.OCI.clone();
let use_sandbox_pidns = req.get_sandbox_pidns();
let sandbox;
let mut s;
@ -121,7 +122,7 @@ impl agentService {
s.container_mounts.insert(cid.clone(), m);
}
update_container_namespaces(&s, &mut oci)?;
update_container_namespaces(&s, &mut oci, use_sandbox_pidns)?;
// Add the root partition to the device cgroup to prevent access
update_device_cgroup(&mut oci)?;
@ -162,6 +163,7 @@ impl agentService {
ctr.start(p)?;
s.update_shared_pidns(&ctr)?;
s.add_container(ctr);
info!(sl!(), "created container!");
@ -1478,7 +1480,11 @@ pub fn start<S: Into<String>>(s: Arc<Mutex<Sandbox>>, host: S, port: u16) -> ttr
// path set by the spec, since we will always ignore it. Indeed, it makes no
// sense to rely on the namespace path provided by the host since namespaces
// are different inside the guest.
fn update_container_namespaces(sandbox: &Sandbox, spec: &mut Spec) -> Result<()> {
fn update_container_namespaces(
sandbox: &Sandbox,
spec: &mut Spec,
sandbox_pidns: bool,
) -> Result<()> {
let linux = match spec.linux.as_mut() {
None => {
return Err(
@ -1488,14 +1494,8 @@ fn update_container_namespaces(sandbox: &Sandbox, spec: &mut Spec) -> Result<()>
Some(l) => l,
};
let mut pidNs = false;
let namespaces = linux.namespaces.as_mut_slice();
for namespace in namespaces.iter_mut() {
if namespace.r#type == NSTYPEPID {
pidNs = true;
continue;
}
if namespace.r#type == NSTYPEIPC {
namespace.path = sandbox.shared_ipcns.path.clone();
continue;
@ -1505,13 +1505,19 @@ fn update_container_namespaces(sandbox: &Sandbox, spec: &mut Spec) -> Result<()>
continue;
}
}
// update pid namespace
let mut pid_ns = LinuxNamespace::default();
pid_ns.r#type = NSTYPEPID.to_string();
if !pidNs && !sandbox.sandbox_pid_ns {
let mut pid_ns = LinuxNamespace::default();
pid_ns.r#type = NSTYPEPID.to_string();
linux.namespaces.push(pid_ns);
// Use shared pid ns if useSandboxPidns has been set in either
// the create_sandbox request or create_container request.
// Else set this to empty string so that a new pid namespace is
// created for the container.
if sandbox_pidns && sandbox.sandbox_pidns.is_some() {
pid_ns.path = String::from(sandbox.sandbox_pidns.as_ref().unwrap().path.as_str());
}
linux.namespaces.push(pid_ns);
Ok(())
}

View File

@ -7,9 +7,11 @@
use crate::linux_abi::*;
use crate::mount::{get_mount_fs_type, remove_mounts, TYPEROOTFS};
use crate::namespace::Namespace;
use crate::namespace::NSTYPEPID;
use crate::network::Network;
use libc::pid_t;
use netlink::{RtnlHandle, NETLINK_ROUTE};
use oci::LinuxNamespace;
use protocols::agent::OnlineCPUMemRequest;
use regex::Regex;
use rustjail::cgroups;
@ -34,10 +36,10 @@ pub struct Sandbox {
pub pci_device_map: HashMap<String, String>,
pub shared_utsns: Namespace,
pub shared_ipcns: Namespace,
pub sandbox_pidns: Option<Namespace>,
pub storages: HashMap<String, u32>,
pub running: bool,
pub no_pivot_root: bool,
pub sandbox_pid_ns: bool,
pub sender: Option<Sender<i32>>,
pub rtnl: Option<RtnlHandle>,
}
@ -58,10 +60,10 @@ impl Sandbox {
pci_device_map: HashMap::new(),
shared_utsns: Namespace::new(&logger),
shared_ipcns: Namespace::new(&logger),
sandbox_pidns: None,
storages: HashMap::new(),
running: false,
no_pivot_root: fs_type.eq(TYPEROOTFS),
sandbox_pid_ns: false,
sender: None,
rtnl: Some(RtnlHandle::new(NETLINK_ROUTE, 0).unwrap()),
})
@ -191,6 +193,30 @@ impl Sandbox {
self.containers.insert(c.id.clone(), c);
}
pub fn update_shared_pidns(&mut self, c: &LinuxContainer) -> Result<()> {
// Populate the shared pid path only if this is an infra container and
// sandbox_pidns has not been passed in the create_sandbox request.
// This means a separate pause process has not been created. We treat the
// first container created as the infra container in that case
// and use its pid namespace in case pid namespace needs to be shared.
if self.sandbox_pidns.is_none() && self.containers.len() == 0 {
let init_pid = c.init_process_pid;
if init_pid == -1 {
return Err(ErrorKind::ErrorCode(String::from(
"Failed to setup pid namespace: init container pid is -1",
))
.into());
}
let mut pid_ns = Namespace::new(&self.logger).as_pid();
pid_ns.path = format!("/proc/{}/ns/pid", init_pid);
self.sandbox_pidns = Some(pid_ns);
}
Ok(())
}
pub fn get_container(&mut self, id: &str) -> Option<&mut LinuxContainer> {
self.containers.get_mut(id)
}
@ -553,4 +579,21 @@ mod tests {
s.add_container(linux_container);
assert!(s.get_container("some_id").is_some());
}
#[test]
fn update_shared_pidns() {
skip_if_not_root!();
let logger = slog::Logger::root(slog::Discard, o!());
let mut s = Sandbox::new(&logger).unwrap();
let test_pid = 9999;
let mut linux_container = create_linuxcontainer();
linux_container.init_process_pid = test_pid;
s.update_shared_pidns(&linux_container).unwrap();
assert!(s.sandbox_pidns.is_some());
let ns_path = format!("/proc/{}/ns/pid", test_pid);
assert_eq!(s.sandbox_pidns.unwrap().path, ns_path);
}
}