Created
August 29, 2021 08:38
-
-
Save sighingnow/4988a0100bc5030d301926f79254133a to your computer and use it in GitHub Desktop.
Rust version of "Containers From Scratch" by Liz Rice, https://www.youtube.com/watch?v=8fi7uSYlOdc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::env; | |
use nix::sched; | |
use nix::sched::CloneFlags; | |
use nix::sys::signal::Signal; | |
use nix::sys::wait::waitpid; | |
use nix::unistd; | |
use cgroups_rs as cgroup; | |
use cgroups_rs::{Cgroup}; | |
use cgroups_rs::cgroup_builder::{CgroupBuilder}; | |
fn run(args: &[String]) { | |
println!("Running run {:?} as {}", args, unistd::getpid()); | |
let clone_flags = CloneFlags::CLONE_NEWUTS | CloneFlags::CLONE_NEWPID | CloneFlags::CLONE_NEWNS; | |
const STACK_SIZE: usize = 1024 * 1024; | |
let stack: &mut [u8; STACK_SIZE] = &mut [0; STACK_SIZE]; | |
let proc = sched::clone( | |
Box::new(|| { | |
child(args); | |
return 0; | |
}), | |
stack, | |
clone_flags, | |
Some(Signal::SIGCHLD as i32), | |
) | |
.expect("Failed to create container process"); | |
waitpid(proc, None).unwrap(); | |
println!("Finishes run ..."); | |
} | |
fn attach_to_cgroup() { | |
let hierarchy = cgroup::hierarchies::auto(); | |
let cg: Cgroup = CgroupBuilder::new("example") | |
.pid() | |
.maximum_number_of_processes(cgroup::MaxValue::Value(100)) | |
.done() | |
.build(hierarchy); | |
// add current task to this cgroup | |
cg.add_task(cgroup::CgroupPid::from(unistd::getpid().as_raw() as u64)).unwrap(); | |
} | |
fn child(args: &[String]) { | |
println!("Running child {:?} as {}", args, unistd::getpid()); | |
let unshare_flags = CloneFlags::CLONE_NEWNS; | |
sched::unshare(unshare_flags).unwrap(); | |
unistd::sethostname("container").unwrap(); | |
attach_to_cgroup(); | |
let exitcode = std::process::Command::new(args[0].as_str()) | |
.args(args.get(1..).unwrap_or_default()) | |
.spawn() | |
.expect("Failed to execute container command") | |
.wait() | |
.unwrap(); | |
match exitcode.code() { | |
Some(code) => { | |
if code != 0 { | |
panic!("Exit with code {}", code); | |
} | |
} | |
None => () | |
} | |
println!("Finishes child ..."); | |
} | |
fn main() { | |
let args: Vec<String> = env::args().collect(); | |
if args.len() < 2 { | |
panic!("Require command to run") | |
} | |
match args[1].as_str() { | |
"run" => run(args.get(2..).unwrap_or_default()), | |
"child" => child(args.get(2..).unwrap_or_default()), | |
cmd => { | |
panic!("Unsupported command: {}", cmd) | |
} | |
} | |
} |
The original Go version can be found at https://github.com/lizrice/containers-from-scratch
See also the rootless variant: https://gist.github.com/sighingnow/460987887ef2c1bb809e47b25b8981ff
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Depends on