From 802c18a5d2211fe9674117baf4eaef0f1a0d2717 Mon Sep 17 00:00:00 2001 From: Hugo Amalric Date: Fri, 15 Apr 2022 20:59:54 +0200 Subject: [PATCH] feat: seat cgroups proc number Signed-off-by: Hugo Amalric --- Cargo.lock | 63 +++++++++++++++++++++++++++++++++++++++- container/Cargo.toml | 1 + container/src/cgroups.rs | 29 ++++++++++++++++++ container/src/cpu.rs | 59 +++++++++++++++++++++++++++++++++++++ container/src/lib.rs | 11 ++++++- src/cli/run.rs | 5 +++- 6 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 container/src/cgroups.rs create mode 100644 container/src/cpu.rs diff --git a/Cargo.lock b/Cargo.lock index 0a56ba0..feaadc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "atty" version = "0.2.14" @@ -37,6 +46,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cgroups-rs" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdae996d9638ba03253ffa1c93345a585974a97abbdeab9176c77922f3efc1e8" +dependencies = [ + "libc", + "log", + "nix 0.23.1", + "regex", +] + [[package]] name = "clap" version = "3.0.5" @@ -71,6 +92,7 @@ dependencies = [ name = "container" version = "0.1.0" dependencies = [ + "cgroups-rs", "lazy_static", "oci-spec", "proc-mounts", @@ -234,6 +256,15 @@ version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +[[package]] +name = "log" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +dependencies = [ + "cfg-if", +] + [[package]] name = "memchr" version = "2.4.1" @@ -262,6 +293,19 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + [[package]] name = "oci-spec" version = "0.5.4" @@ -381,6 +425,23 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "regex" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -501,7 +562,7 @@ version = "0.7.0" source = "git+https://github.com/virt-do/unshare?branch=main#7b0a2e8d906bcdb2efa62d3ce9580dc359b731fd" dependencies = [ "libc", - "nix", + "nix 0.20.2", ] [[package]] diff --git a/container/Cargo.toml b/container/Cargo.toml index 2b3b6d7..2c58815 100644 --- a/container/Cargo.toml +++ b/container/Cargo.toml @@ -10,6 +10,7 @@ oci-spec = "0.5.3" unshare = { git = "https://github.com/virt-do/unshare", branch = "main" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +cgroups-rs = "0.2.9" [dev-dependencies] proc-mounts = "0.3.0" diff --git a/container/src/cgroups.rs b/container/src/cgroups.rs new file mode 100644 index 0000000..4e52d88 --- /dev/null +++ b/container/src/cgroups.rs @@ -0,0 +1,29 @@ +use cgroups_rs::Cgroup; +use cgroups_rs::Resources; + +#[derive(Default, Clone)] +pub struct Cgroups { + cgroup: Cgroup, + resources: Resources, +} + +impl Cgroups { + pub fn new() -> Self { + let h = cgroups_rs::hierarchies::auto(); + let cgroup: Cgroup = Cgroup::new(h, "kaps"); + let resources = cgroups_rs::Resources::default(); + + Cgroups { + cgroup, + resources, + } + } + + pub fn set_cpus(&mut self, cpus: u64) { + self.resources + .cpu + .attrs + .insert("cgroup.procs".to_string(), cpus.to_string()); + self.cgroup.apply(&self.resources).unwrap(); + } +} diff --git a/container/src/cpu.rs b/container/src/cpu.rs new file mode 100644 index 0000000..0ebab53 --- /dev/null +++ b/container/src/cpu.rs @@ -0,0 +1,59 @@ +use oci_spec::runtime::LinuxCpu; +use anyhow::{Result}; + +const CGROUP_CPU_SHARES: &str = "cpu.shares"; +const CGROUP_CPU_QUOTA: &str = "cpu.cfs_quota_us"; +const CGROUP_CPU_PERIOD: &str = "cpu.cfs_period_us"; +const CGROUP_CPU_BURST: &str = "cpu.cfs_burst_us"; +const CGROUP_CPU_RT_RUNTIME: &str = "cpu.rt_runtime_us"; +const CGROUP_CPU_RT_PERIOD: &str = "cpu.rt_period_us"; +const CGROUP_CPU_STAT: &str = "cpu.stat"; +const CGROUP_CPU_PROCS: &str = "cgroup.procs"; + +pub struct Cpu {} + +impl Cpu { + fn apply(cgroups: &Cgroups, cpu: &LinuxCpu) -> Result<()> { + if let Some(cpu_shares) = cpu.shares() { + if cpu_shares != 0 { + cgroups.resources.cpu.attrs.insert(CGROUP_CPU_SHARES.to_string(), cpu_shares.to_string()); + } + } + + if let Some(cpu_period) = cpu.period() { + if cpu_period != 0 { + cgroups.resources.cpu.attrs.insert(CGROUP_CPU_PERIOD.to_string(), cpu_period.to_string()); + } + } + + if let Some(cpu_quota) = cpu.quota() { + if cpu_quota != 0 { + cgroups.resources.cpu.attrs.insert(CGROUP_CPU_QUOTA.to_string(), cpu_quota.to_string()); + } + } + + if let Some(cpu_burst) = cpu.burst() { + cgroups.resources.cpu.attrs.insert(CGROUP_CPU_BURST.to_string(), cpu_burst.to_string()); + } + + if let Some(rt_runtime) = cpu.realtime_runtime() { + if rt_runtime != 0 { + cgroups.resources.cpu.attrs.insert(CGROUP_CPU_RT_RUNTIME.to_string(), rt_runtime.to_string()); + } + } + + if let Some(rt_period) = cpu.realtime_period() { + if rt_period != 0 { + cgroups.resources.cpu.attrs.insert(CGROUP_CPU_RT_PERIOD.to_string(), rt_period.to_string()); + } + } + + if let Some(cpus) = cpu.cpus() { + if cpus != 0 { + cgroups.resources.cpu.attrs.insert(CGROUP_CPU_PROCS.to_string(), cpus.to_string()); + } + } + + Ok(()) + } +} diff --git a/container/src/lib.rs b/container/src/lib.rs index ea399c5..171c9e9 100644 --- a/container/src/lib.rs +++ b/container/src/lib.rs @@ -2,11 +2,13 @@ use std::path::PathBuf; use oci_spec::runtime::Spec; +use cgroups::Cgroups; use command::Command; use environment::Environment; use mounts::Mounts; use namespaces::Namespaces; +mod cgroups; mod command; mod environment; mod mounts; @@ -45,11 +47,13 @@ pub struct Container { environment: Environment, /// The command entrypoint command: Command, + /// Nomber of cpus + cpus: u64 } impl Container { /// Build a new container with the bundle provided in parameters. - pub fn new(bundle_path: &str) -> Result { + pub fn new(bundle_path: &str, cpus: u64) -> Result { let bundle = PathBuf::from(bundle_path); // Load the specification from the file @@ -78,6 +82,7 @@ impl Container { command: Command::from(spec.process()), namespaces, rootfs, + cpus, ..Default::default() }) } @@ -98,6 +103,10 @@ impl Container { return self.mounts.cleanup(self.rootfs.clone()); } }; + + let mut cgroups = Cgroups::new(); + cgroups.set_cpus(self.cpus); + child.wait().map_err(Error::ContainerWaitCommand)?.code() }; diff --git a/src/cli/run.rs b/src/cli/run.rs index 80204c3..f04acca 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -17,12 +17,15 @@ pub struct RunCommand { /// The bundle used by the container. #[clap(short, long)] bundle: String, + /// The number of cpus used by the container. + #[clap(short, long)] + cpus: u64, } impl Handler for RunCommand { fn handler(&self) -> Result<()> { // Create a container by passing the bundle provided in arguments to it's constructor. - let container = Container::new(&self.bundle)?; + let container = Container::new(&self.bundle, self.cpus)?; // Run the container // At the moment, we don't have a detached mode for the container,