近期功能更新

main
阳光少年 1 year ago
parent 21d0300c49
commit 5c6eed464c

@ -1,6 +1,9 @@
WORKSPACE := /home/rocker WORKSPACE := /home/rocker
USER_NAME := rocker USER_NAME := rocker
PASSWORD = asd123 GROUP_NAME := $(USER_NAME)
UID = 7788
GID = 7788
PASSWORD = quant_u2Oh0Go9J76aQb3h7Ybgapw@yanguangshaonian
build: build:
cargo build --release cargo build --release
@ -8,14 +11,14 @@ build:
# 创建WORKSPACE 对应的文件夹 # 创建WORKSPACE 对应的文件夹
install: install:
@# 创建一个普通用户 @# 创建一个普通用户
-@echo "Creating user $(USER_NAME)" -@sudo useradd -m -s /bin/bash $(USER_NAME) -u $(UID)
-@sudo useradd -m -s /bin/bash $(USER_NAME) @# 将用户添加到用户组
-@sudo usermod -g $(GID) -aG $(GROUP_NAME) $(USER_NAME)
@# 设置密码 @# 设置密码
-@echo "Setting password for $(USER_NAME)"
-@echo "$(USER_NAME):$(PASSWORD)" | sudo chpasswd -@echo "$(USER_NAME):$(PASSWORD)" | sudo chpasswd
@# 授权sudo # @# 授权sudo
-@echo "Authorizing $(USER_NAME) to use sudo" # -@echo "Authorizing $(USER_NAME) to use sudo"
-@sudo sh -c "echo '$(USER_NAME) ALL=(ALL) ALL' >> /etc/sudoers" # -@sudo sh -c "echo '$(USER_NAME) ALL=(ALL) ALL' >> /etc/sudoers"
mkdir -p $(WORKSPACE)/images mkdir -p $(WORKSPACE)/images
mkdir -p $(WORKSPACE)/volumes mkdir -p $(WORKSPACE)/volumes
@ -24,12 +27,23 @@ install:
cp images/* $(WORKSPACE)/images/ cp images/* $(WORKSPACE)/images/
chown -R rocker:rocker $(WORKSPACE) chown -R rocker:rocker $(WORKSPACE)
-mkdir /sys/fs/cgroup/rocker_1
-mkdir /sys/fs/cgroup/rocker_2
-mkdir /sys/fs/cgroup/rocker_3
clean: clean:
-./target/debug/rocker --rm all
-rocker --rm all -rocker --rm all
-rm -rf $(WORKSPACE)/* -rm -rf $(WORKSPACE)/*
-rm -rf /usr/bin/rocker -rm -rf /usr/bin/rocker
-rmdir /sys/fs/cgroup/rocker_1/*
-rmdir /sys/fs/cgroup/rocker_2/*
-rmdir /sys/fs/cgroup/rocker_3/*
-rmdir /sys/fs/cgroup/rocker_*
-@echo "Cleaning up" -@echo "Cleaning up"
-@sudo userdel -r $(USER_NAME) -@sudo userdel -r $(USER_NAME)
-@sudo groupdel $(GROUP_NAME)
-@sudo sed -i "/^$(USER_NAME)/d" /etc/sudoers -@sudo sed -i "/^$(USER_NAME)/d" /etc/sudoers

@ -0,0 +1,92 @@
use std::fmt::{Display, Formatter};
use nix::sys::signal::kill;
use nix::unistd::Pid;
use nix::sys::signal::Signal;
use std::path::Path;
use crate::{create_dir, get_container_info, ContainerInfo};
use crate::error::Result;
static CGROUP_PATH: &str = "/sys/fs/cgroup/rocker";
pub enum CgroupLevel {
One,
Two,
Three,
}
impl From<&str> for CgroupLevel {
fn from(value: &str) -> Self {
match value {
"1" => CgroupLevel::One,
"2" => CgroupLevel::Two,
"3" => CgroupLevel::Three,
_ => todo!("invalid cgroup level"),
}
}
}
impl Display for CgroupLevel {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::One => write!(f, "1"),
Self::Two => write!(f, "2"),
Self::Three => write!(f, "3"),
}
}
}
impl Default for CgroupLevel {
fn default() -> Self {
CgroupLevel::One
}
}
pub struct Cgroup {
pub procs: Vec<i32>
}
impl From<&ContainerInfo> for Cgroup {
fn from(container_inro: &ContainerInfo) -> Self {
// let container_inro = get_container_info(container_id).unwrap();
let l = CgroupLevel::from(container_inro.cgroup_level.as_str());
let cgroup_path = format!("{CGROUP_PATH}_{l}/{}", container_inro.id);
let mut v = vec![];
for pid in std::fs::read_to_string(format!("{cgroup_path}/cgroup.procs")).unwrap_or_default().lines() {
let pid = pid.parse::<i32>().unwrap();
v.push(pid);
}
Self {
procs: v
}
}
}
impl Cgroup {
pub fn create(container_id: &str, pid: i32, l: CgroupLevel) -> Result<()> {
let cgroup_path = format!("{CGROUP_PATH}_{l}/{container_id}");
create_dir(&cgroup_path, false)?;
// 打开 cgroup.procs, 写入pid
std::fs::write(format!("{cgroup_path}/cgroup.procs"), pid.to_string())?;
Ok(())
}
pub fn remove(container_id: &str) {
let container_inro = get_container_info(container_id).unwrap();
let _self = Self::from(&container_inro);
for pid in _self.procs {
let _ = kill(Pid::from_raw(pid), Signal::SIGKILL);
let pid_path = Path::new("/proc").join(pid.to_string());
(0..100).any(|i|{
std::thread::sleep(std::time::Duration::from_millis(i));
pid_path.exists() == false
});
}
let l = container_inro.cgroup_level;
let container_group_path = format!("{CGROUP_PATH}_{l}/{container_id}");
let _ = std::fs::remove_dir(&container_group_path);
println!("删除cgroup {container_group_path}")
}
}

@ -1,5 +1,3 @@
use std::fs::{remove_dir_all, OpenOptions};
use std::os::unix::fs::OpenOptionsExt;
use std::{io, fs, fmt, os, path, process, time}; use std::{io, fs, fmt, os, path, process, time};
use fmt::Display; use fmt::Display;
use os::fd::{AsFd, AsRawFd}; use os::fd::{AsFd, AsRawFd};
@ -8,8 +6,8 @@ use path::{Path, PathBuf};
use std::sync::OnceLock; use std::sync::OnceLock;
use nix::sched::{clone, CloneCb, CloneFlags, setns}; use nix::sched::{clone, CloneCb, CloneFlags, setns};
use nix::sys::{signal::{kill, Signal}, wait::{waitpid, WaitPidFlag}}; use nix::sys::wait::{waitpid, WaitPidFlag};
use nix::unistd::{dup2, getpgid, pivot_root, setgid, setgroups, sethostname, setuid, Gid, Pid, Uid, User}; use nix::unistd::{dup2, pivot_root, setgid, setgroups, sethostname, setuid, Gid, Pid, Uid, User};
use nix::mount::{mount, MntFlags, MsFlags, umount2}; use nix::mount::{mount, MntFlags, MsFlags, umount2};
use uuid; use uuid;
use toml; use toml;
@ -20,6 +18,8 @@ use error::{Result, RockerError};
mod error; mod error;
use network::{create_network, remove_network}; use network::{create_network, remove_network};
mod network; mod network;
use cgroup::{Cgroup, CgroupLevel};
mod cgroup;
static WORKSPACE: &str = "/home/rocker"; static WORKSPACE: &str = "/home/rocker";
static USER_NAME: &str = "rocker"; static USER_NAME: &str = "rocker";
@ -73,6 +73,9 @@ struct RockerArgs {
// --psa // --psa
#[arg(long)] #[arg(long)]
psa: bool, psa: bool,
// --root
#[arg(long)]
root: bool,
// rm "container_id_1, container_id_2, container_id_3" // rm "container_id_1, container_id_2, container_id_3"
#[arg(long)] #[arg(long)]
@ -86,6 +89,8 @@ struct RockerArgs {
#[arg(long)] #[arg(long)]
restart: Option<String>, restart: Option<String>,
#[arg(long)]
cgroup: Option<String>,
} }
macro_rules! rocker_println { macro_rules! rocker_println {
@ -125,11 +130,11 @@ fn extend_image(image_name: &String) -> Result<PathBuf> {
if out.status.success() { if out.status.success() {
println!("解压缩完毕: {image_name:?}"); println!("解压缩完毕: {image_name:?}");
// 把解压缩后的文件全部给 rocker:rocker // 把解压缩后的文件全部给 rocker:rocker
let _ = process::Command::new("chown") // let _ = process::Command::new("chown")
.arg("-R") // .arg("-R")
.arg("rocker:rocker") // .arg("rocker:rocker")
.arg(volume_path_str) // .arg(volume_path_str)
.output()?; // .output()?;
Ok(volume_path) Ok(volume_path)
} else { } else {
// 删除 volume_path // 删除 volume_path
@ -164,7 +169,13 @@ fn init_container_overlay<P: AsRef<Path>>(volume_path: P, upper_path: P, merged_
} }
fn init_container_dev<P: AsRef<Path>>(container_merged_path: P) -> Result<()> { fn init_container_dev<P: AsRef<Path>>(container_merged_path: P) -> Result<()> {
let dev_vec = [("urandom", 0), ("random", 0), ("null", 0), ("zero", 0), ("shm", 1)]; let dev_vec = [
("urandom", 0),
("random", 0),
("null", 0),
("zero", 0),
// ("shm", 1),
];
for (dev, tp) in dev_vec { for (dev, tp) in dev_vec {
let host_dev_path = format!("/dev/{dev}"); let host_dev_path = format!("/dev/{dev}");
@ -310,7 +321,7 @@ fn init_container_user(uid: Uid, gid: Gid) -> Result<()>{
Ok(()) Ok(())
} }
fn create_dir<P: AsRef<Path>>(path: P, is_any:bool) -> Result<()> { pub fn create_dir<P: AsRef<Path>>(path: P, is_any:bool) -> Result<()> {
fs::create_dir_all(&path)?; fs::create_dir_all(&path)?;
if is_any { if is_any {
fs::set_permissions(&path, PermissionsExt::from_mode(0o777))?; fs::set_permissions(&path, PermissionsExt::from_mode(0o777))?;
@ -348,7 +359,7 @@ fn create_pause(container_root_pause_path: &Path) -> Result<()> {
Ok(()) Ok(())
} }
fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, container_merged_pause_path: &PathBuf) -> Result<i32>{ fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, container_merged_pause_path: &PathBuf) -> Result<()>{
match unsafe {clone(cb, STACK.as_mut_slice(), clong_flags, None)} { match unsafe {clone(cb, STACK.as_mut_slice(), clong_flags, None)} {
Ok(child_pid) => { Ok(child_pid) => {
{ // 执行成功就保存吧~ { // 执行成功就保存吧~
@ -359,18 +370,18 @@ fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, c
// exec之前的步骤 // exec之前的步骤
create_network(&container_info.id, child_pid.as_raw()); create_network(&container_info.id, child_pid.as_raw());
Cgroup::create(&container_info.id, child_pid.as_raw(), CgroupLevel::from(container_info.cgroup_level.as_str()))?;
// 删除 pause标志文件, 解开阻塞, 使其执行exec // 删除 pause标志文件, 解开阻塞, 使其执行exec
for _ in 0..500 { (0..100).any(|i| {
std::thread::sleep(std::time::Duration::from_millis(10)); std::thread::sleep(std::time::Duration::from_millis(i));
if std::fs::remove_file(container_merged_pause_path).is_ok() { std::fs::remove_file(container_merged_pause_path).is_ok()
break; });
}
}
// 检查是否执行exec了 // 检查是否执行exec了
let main_exe = std::env::current_exe()?; let main_exe = std::env::current_exe()?;
for _ in 0..500 { for i in 0..100 {
std::thread::sleep(std::time::Duration::from_millis(10)); std::thread::sleep(std::time::Duration::from_millis(i));
if let Ok(true) = check_container_is_running(&child_pid, &main_exe) { if let Ok(true) = check_container_is_running(&child_pid, &main_exe) {
break; break;
} }
@ -388,7 +399,7 @@ fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, c
} }
} }
} }
Ok(child_pid.as_raw()) Ok(())
} }
Err(e) => { Err(e) => {
Err(RockerError::OtherError(format!("clone err: {e}"))) Err(RockerError::OtherError(format!("clone err: {e}")))
@ -396,7 +407,7 @@ fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, c
} }
} }
fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -> Result<i32> { fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -> Result<()> {
// 禁止同时wait和log // 禁止同时wait和log
if container_info.wait && container_info.log { if container_info.wait && container_info.log {
return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string())); return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string()));
@ -425,7 +436,9 @@ fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -
let _cb = || { let _cb = || {
init_exec_ns(container_info.pid).unwrap(); init_exec_ns(container_info.pid).unwrap();
let env_vec = get_env_vec(&Default::default()).unwrap(); let env_vec = get_env_vec(&Default::default()).unwrap();
if container_info.root == false {
init_container_user(rocker_uid, rocker_gid).unwrap(); init_container_user(rocker_uid, rocker_gid).unwrap();
}
init_container_env(env_vec).unwrap(); init_container_env(env_vec).unwrap();
create_pause(container_root_pause_path).unwrap(); create_pause(container_root_pause_path).unwrap();
@ -477,7 +490,9 @@ fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -
} }
// 设置用户 // 设置用户
if container_info.root == false {
init_container_user(rocker_uid, rocker_gid).unwrap(); init_container_user(rocker_uid, rocker_gid).unwrap();
}
// 暂停等待外部主进程设置网络设备 // 暂停等待外部主进程设置网络设备
create_pause(&container_root_pause_path).unwrap(); create_pause(&container_root_pause_path).unwrap();
@ -514,7 +529,6 @@ impl Display for ContainerStatus {
Self::STOP => write!(f, "🔴"), Self::STOP => write!(f, "🔴"),
} }
} }
} }
@ -530,6 +544,9 @@ struct ContainerInfo {
env: String, // a=1,b=2,c=3 或者 env文件路径 env: String, // a=1,b=2,c=3 或者 env文件路径
log: bool, log: bool,
wait: bool, wait: bool,
root: bool,
cgroup_level: String, // one/two/three
} }
impl ContainerInfo { impl ContainerInfo {
@ -551,39 +568,25 @@ impl Display for ContainerInfo {
} }
} }
fn save_container_info(args: &RockerArgs, container_id: &String, pid: i32) -> Result<()> {
let container_info_path = Path::new(WORKSPACE).join("containers").join(container_id).join(INFO_FILE);
let container_info = ContainerInfo {
id: container_id.clone(),
pid: pid,
run: args.run.as_ref().unwrap().clone(),
image: args.image.as_ref().unwrap().clone(),
volume: args.volume.clone().unwrap_or("".to_string()),
env: args.env.clone().unwrap_or("".to_string()),
status: ContainerStatus::READY,
log: args.log,
wait: args.wait,
};
let toml_str = toml::to_string(&container_info)?;
fs::write(container_info_path, toml_str)?;
Ok(())
}
fn get_container_info(container_id: &str) -> Result<ContainerInfo> { fn get_container_info(container_id: &str) -> Result<ContainerInfo> {
let container_work_path = Path::new(WORKSPACE).join("containers").join(container_id); let container_work_path = Path::new(WORKSPACE).join("containers").join(container_id);
let container_info_path = container_work_path.join(INFO_FILE); let container_info_path = container_work_path.join(INFO_FILE);
let info_str = fs::read_to_string(container_info_path)?; let info_str = fs::read_to_string(container_info_path)?;
let mut container_info: ContainerInfo = toml::from_str(&info_str)?; let mut container_info: ContainerInfo = toml::from_str(&info_str)?;
// todo 判断当前进程组 是否还有进程
let cgroup = Cgroup::from(&container_info);
// 判断是否正在运行, 进入proc/pid/判断当前进程网络中是否有下面的设备 // 判断是否正在运行, 进入proc/pid/判断当前进程网络中是否有下面的设备
let dev_path = Path::new("/proc").join(container_info.pid.to_string()).join("net").join("dev"); // let dev_path = Path::new("/proc").join(container_info.pid.to_string()).join("net").join("dev");
let is_running = if let Ok(dev_text) = fs::read_to_string(dev_path){ // let is_running = if let Ok(dev_text) = fs::read_to_string(dev_path){
let slave_veth_name = format!("ro_{container_id}_3"); // let slave_veth_name = format!("ro_{container_id}_3");
dev_text.lines().any(|l|l.starts_with(&slave_veth_name)) // dev_text.lines().any(|l|l.starts_with(&slave_veth_name))
} else { // } else {
false // false
}; // };
if is_running {
if cgroup.procs.len() > 0 {
container_info.status = ContainerStatus::RUNNING; container_info.status = ContainerStatus::RUNNING;
} else { } else {
container_info.status = ContainerStatus::STOP; container_info.status = ContainerStatus::STOP;
@ -624,17 +627,15 @@ fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> {
return Ok(()) return Ok(())
} }
for container_id in containers_id.split(" ") { for container_id in containers_id.split(" ") {
// 容器网络删除
remove_network(container_id);
let container_work_path = containers_path.join(container_id); let container_work_path = containers_path.join(container_id);
let container_merged_path = container_work_path.join("merged"); let container_merged_path = container_work_path.join("merged");
if let Ok(container_info) = get_container_info(container_id) { if let Ok(container_info) = get_container_info(container_id) {
// 正在运行中的需要 kill // 删除进程组
if container_info.status == ContainerStatus::RUNNING { Cgroup::remove(container_id);
let _ = kill(Pid::from_raw(-container_info.pid), Signal::SIGKILL);
let pid_path = Path::new("/proc").join(container_info.pid.to_string());
while pid_path.exists() {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
// 卸载自定义挂载点 // 卸载自定义挂载点
if container_info.volume != "" { if container_info.volume != "" {
container_info.volume container_info.volume
@ -650,14 +651,16 @@ fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> {
.for_each(|s| { .for_each(|s| {
match umount2(s.as_str(), MntFlags::MNT_DETACH) { match umount2(s.as_str(), MntFlags::MNT_DETACH) {
Ok(_) => println!("卸载自定卷{s}"), Ok(_) => println!("卸载自定卷{s}"),
Err(e) => println!("卸载卷{s}失败: {e:?}"), Err(e) => println!("卸载自定卷{s}失败: {e:?}"),
} }
}); });
} }
// 卸载dev文件夹中的设备 // 卸载dev文件夹中的设备
let container_dev_path = container_merged_path.join("dev"); let container_dev_path = container_merged_path.join("dev");
container_dev_path.read_dir()?.filter_map(|d|d.ok()) let _ = container_dev_path.read_dir().map(|dev| {
dev.filter_map(|d|d.ok())
.for_each(|p|{let _ = umount2(p.path().to_str().unwrap(), MntFlags::MNT_DETACH);}); .for_each(|p|{let _ = umount2(p.path().to_str().unwrap(), MntFlags::MNT_DETACH);});
});
// 卸载overlayfs // 卸载overlayfs
match umount2(container_merged_path.to_str().unwrap(), MntFlags::MNT_DETACH) { match umount2(container_merged_path.to_str().unwrap(), MntFlags::MNT_DETACH) {
@ -676,14 +679,14 @@ fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> {
} else { } else {
println!("容器不存在: {container_id}, 强制删除"); println!("容器不存在: {container_id}, 强制删除");
// 需要强制删除一下目录 // 需要强制删除一下目录
if container_work_path.exists() {
match fs::remove_dir_all(&container_work_path) { match fs::remove_dir_all(&container_work_path) {
Ok(_) => println!("强制删除 {container_work_path:?} 成功"), Ok(_) => println!("强制删除 {container_work_path:?} 成功"),
Err(e) => println!("强制删除失败: {e:?}"), Err(e) => println!("强制删除失败: {e:?}"),
} }
} }
}
// 容器网络删除
remove_network(container_id);
} }
Ok(()) Ok(())
} }
@ -708,7 +711,9 @@ fn main() -> Result<()>{
env: args.env.clone().unwrap_or_default(), env: args.env.clone().unwrap_or_default(),
status: ContainerStatus::READY, status: ContainerStatus::READY,
log: args.log, log: args.log,
wait: args.wait wait: args.wait,
cgroup_level: args.cgroup.clone().unwrap_or(CgroupLevel::default().to_string()),
root: args.root
} }
} }
(None, None, Some(_container_id)) => { (None, None, Some(_container_id)) => {

@ -147,6 +147,7 @@ pub fn remove_network(uuid_name: &str) {
} }
// 回写到文件中 // 回写到文件中
write_network_info(all_network); write_network_info(all_network);
println!("删除网络设备: {uuid_name}");
} }

Binary file not shown.

@ -1,23 +1,65 @@
# import urllib.request # import urllib.request
# from datetime import datetime # from datetime import datetime
# import time #
# import mmap import time
# import os import mmap
# print(os.getpid()) import os
# print(os.getpgid(os.getpid())) import threading
import ctypes
def read_memory(address):
# with open("./data", "r+b") as f: # 创建一个足够大的缓冲区来读取内存
# mm = mmap.mmap(f.fileno(), 0) buffer_size = 8 # 假设我们读取的是一个64位整数
# time.sleep(1000000) buffer = ctypes.create_string_buffer(buffer_size)
# # lis = []
# # while True: # 使用ctypes的cast函数将地址转换为ctypes的指针类型
# # lis.clear() ptr = ctypes.cast(address, ctypes.POINTER(ctypes.c_char * buffer_size))
# # for _ in range(1024 * 1024 * 400):
# # if len(lis) < 1024 * 1024 * 50: # 读取内存到buffer中
# # lis.append(_) ptr.contents[:buffer_size]
# # print("Ok")
# 解析buffer中的数据
data = ctypes.cast(ptr, ctypes.POINTER(ctypes.c_int8)).contents.value
return data
print(os.getpid())
print(os.getpgid(os.getpid()))
def t():
time.sleep(100)
cnt = 0
while True:
cnt += 1
t = threading.Thread(target=t)
t.start()
def dealy():
time.sleep(100000)
# time.sleep(20)
print("start")
with open("/tmp/test/data", "r+b") as f:
mm = mmap.mmap(f.fileno(), 0, mmap.PROT_READ | mmap.MAP_PRIVATE)
for i in range(400):
for _ in range(1024 * 1024):
idx = _ * i
a = mm[idx]
mm[idx] = idx % 230
# memory_block = bytearray(1024*1024)
# lis.append(memory_block)
time.sleep(1)
print(i, idx, mm[idx], a)
print("ok")

Loading…
Cancel
Save