1
0
mirror of https://github.com/containers/youki synced 2024-09-20 02:41:47 +02:00

Merge branch 'utam0k:main' into main

This commit is contained in:
nalpine 2021-05-27 11:37:20 -04:00
commit f37079b56f
3 changed files with 82 additions and 0 deletions

View File

@ -3,6 +3,7 @@ name = "youki"
version = "0.0.1"
authors = ["utam0k <k0ma@utam0k.jp>"]
edition = "2018"
description = "A container runtime written in Rust"
[dependencies]
clap = "3.0.0-beta.2"

53
docs/doc-draft.md Normal file
View File

@ -0,0 +1,53 @@
_This is a draft for a high level documentation of Youki. After finished this is intended to provide how control flow and high level functioning of Youki happens for development purposes._
## Some reference links
These are references to various documentations and specifications, which can be useful to understand commands and constraints.
- [OCI runtime specification] : The specification for a container runtime. Any OCI complaisant runtime must follow this.
- [runc man pages] : has information on various commandline options supported by runc, can be used to understand commands and their options.
- [cgroups man page](https://man7.org/linux/man-pages/man7/cgroups.7.html) : contains information about cgroups, their creation, deletion etc.
---
## Control flow diagram
This is diagram as given in #14, which is not actually how this works, but helpful to understand overall flow. Someone needs to check and correct.
```mermaid
sequenceDiagram
participant U as User
participant D as Docker
participant YP as Youki(Parent Process)
participant YC as Youki(Child Process)
participant YI as Youki(Init Process)
U ->> D : $ docker run --rm -it --runtime youki $image
D ->> YP : youki create $container_id
YP ->> YC : fork(2)
YC ->> YC : create new namespace
YC ->> YI : fork(2)
YI ->> YI : Mount the device
YI -->> YP : ready message (Unix domain socket)
YP ->> D : exit $code
D ->> YP : $ youki start $container_id
YP -->> YI : start message (Unix domain socket)
YI ->> YI : run the commands in dockerfile
D ->> D : monitor pid written in pid file
D ->> U : exit $code
```
---
## Control flow
### main invocation
On invoking Youki, main function parses args passed to it, which contains directory path to store container state (check runc . 8 . md in [runc man pages]), optional log path and log format string and a subcommand such as create, delete etc.
From there it matches subcommand arg with possible subcommand and takes appropriate actions, such as creating a new container, deleting a container erc.
[oci runtime specification]: https://github.com/opencontainers/runtime-spec/blob/master/runtime.md
[runc man pages]: (https://github.com/opencontainers/runc/blob/master/man/runc.8.md)

View File

@ -1,3 +1,7 @@
//! # Youki
//! Container Runtime written in Rust, inspired by [railcar](https://github.com/oracle/railcar)
//! This crate provides a container runtime which can be used by a high-level container runtime to run containers.
use std::fs;
use std::path::PathBuf;
@ -12,15 +16,20 @@ use youki::spec;
use youki::start;
use youki::{cgroups::Manager, command::linux::LinuxCommand};
/// High-level commandline option definition
/// This takes global options as well as individual commands as specified in [OCI runtime-spec](https://github.com/opencontainers/runtime-spec/blob/master/runtime.md)
/// Also check [runc commandline documentation](https://github.com/opencontainers/runc/blob/master/man/runc.8.md) for more explanation
#[derive(Clap, Debug)]
#[clap(version = "1.0", author = "utam0k <k0ma@utam0k.jp>")]
struct Opts {
/// root directory to store container state
#[clap(short, long, default_value = "/run/youki")]
root: PathBuf,
#[clap(short, long)]
log: Option<PathBuf>,
#[clap(long)]
log_format: Option<String>,
/// command to actually manage container
#[clap(subcommand)]
subcmd: SubCommand,
}
@ -40,6 +49,9 @@ pub struct Delete {
pub struct StateArgs {
pub container_id: String,
}
/// Subcommands accepted by Youki, confirming with [OCI runtime-spec](https://github.com/opencontainers/runtime-spec/blob/master/runtime.md)
/// Also for a short information, check [runc commandline documentation](https://github.com/opencontainers/runc/blob/master/man/runc.8.md)
#[derive(Clap, Debug)]
enum SubCommand {
#[clap(version = "0.0.1", author = "utam0k <k0ma@utam0k.jp>")]
@ -66,6 +78,8 @@ impl SubCommand {
}
}
/// This is the entry point in the container runtime. The binary is run by a high-level container runtime,
/// with various flags passed. This parses the flags, creates and manages appropriate resources.
fn main() -> Result<()> {
let opts = Opts::parse();
@ -88,11 +102,17 @@ fn main() -> Result<()> {
SubCommand::Create(create) => create.exec(root_path, LinuxCommand),
SubCommand::Start(start) => start.exec(root_path),
SubCommand::Kill(kill) => {
// resolves relative paths, symbolic links etc. and get complete path
let root_path = fs::canonicalize(root_path)?;
// state of container is stored in a directory named as container id inside
// root directory given in commandline options
let container_root = root_path.join(&kill.container_id);
if !container_root.exists() {
bail!("{} doesn't exists.", kill.container_id)
}
// load container state from json file, and check status of the container
// it might be possible that kill is invoked on a already stopped container etc.
let container = Container::load(container_root)?.refresh_status()?;
if container.can_kill() {
let sig = signal::from_str(kill.signal.as_str())?;
@ -109,15 +129,23 @@ fn main() -> Result<()> {
}
}
SubCommand::Delete(delete) => {
// state of container is stored in a directory named as container id inside
// root directory given in commandline options
let container_root = root_path.join(&delete.container_id);
if !container_root.exists() {
bail!("{} doesn't exists.", delete.container_id)
}
// load container state from json file, and check status of the container
// it might be possible that delete is invoked on a running container.
let container = Container::load(container_root)?.refresh_status()?;
if container.can_delete() {
if container.root.exists() {
// remove the directory storing container state
fs::remove_dir_all(&container.root)?;
let spec = spec::Spec::load("config.json")?;
// remove the cgroup created for the container
// check https://man7.org/linux/man-pages/man7/cgroups.7.html
// creating and removing cgroups section for more information on cgroups
let cmanager = Manager::new(spec.linux.unwrap().cgroups_path)?;
cmanager.remove()?;
}