• runc的detach, console, tty等相关问题


    runc 端解析:

    1、 runc/utils_linux.go

    func (r *runner) run(config *specs.Process) (int , error)

    在该函数中第一次对容器的IO进行了处理,首先调用tty, err := setupIO(process, rootuid, rootgid, r.console, config.Terminal, r.detach, || r.create),创建并返回了一个结构tty,tty的具体类型如下所示:

    type tty struct {
    
      console  libcontainer.Console
    
      state    *term.State
      closers  []io.Closer
      postStart []io.Closer
    
      wg    sync.WaitGroup 
    }
    

    之后又有handler := newSignalHandler(tty, r.enableSubreaper)以及tty.ClosePostStart(), status, err := handler.forward(process)对tty进行处理(主要是针对winsize)。同时,我们可以发现在handler.forward函数之前有对r.detach进行判断,若r.detach为true则直接返回了。

    2、runc/utils_linux.go

    // setupIO sets the proper IO on the process depending on the configuration

    // detach and createTTy will not work unless a console path is passed  --->即detach 和createTty不能同时为true,除非console不为空

    func setupIO(process *libcontainer.Process, rootuid, rootgid int, console string, createTTY, detach bool) (*tty, error)

    (1)当createTTy为true时,调用 return createTty(process, rootuid, rootgid, console) ---> 要求tty,则优先创建tty

    (2)当detach为true时,调用dupStdio(process, rootuid, rootgid), 最后再返回一个空的tty, return &tty{}

    (3)当createTTy和detach都为false时,则return createStdioPipes(process, rootuid, rootgid)

    ------------------------------------------------------------  tty方式 ----------------------------------------------------

    3、runc/tty.go

    func createTty(p *libcontainer.Process, rootuid, rootgid int, consolePath string) (*tty, error)

    (1)当用户指定了consolePath的时候,则直接调用p.consoleFromPath(consolePath),再返回一个空的tty, return &tty{}

    (2)当用户未指定consolePath时,则调用console, err := p.NewConsole(rootuid, rootgid)创建一个新的console,并且将标准输入输出与console相连。接着调用state, err := term.SetRawTerminal(os.Stdin.Fd())函数将标准输入设置为raw mode。最后返回:

    return &tty {
    
      console:  console,
      state:   state,
      closers:  []io.Closer{
        console,
      },
    
    }
    

      

    4、runc/libcontainer/process.go

    // ConsoleFromPath sets the process's console with the path provided

    func (p *Process) ConsoleFromPath(path string) error

    仅仅只是将path赋值给p.consolePath

    5、runc/libcontainer/console_linux.go

    // NewConsole returns an initialized console that can be used within a container by copying bytes

    // from the master side to the slave that is attached as the tty for the container's init process

    func NewConsole(uid, gid int) (Console, error)

    首先调用master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR | syscall.O_NOCTTY|syscall.O_CLOEXEC, 0),打开主设备,接着调用console, err := ptsname(master)获取从设备的设备名,之后再对主从设备进行一系列的操作。最后,return &linuxConsole{ slavePath: console, master: master}

    ------------------------------------------------------------------------ detach 模式---------------------------------------------------------------

    6、runc/utils_linux.go

    func dupStdio(process *libcontainer.Process, rootuid, rootgid int) error

    该函数的操作很简单,就是直接将标准IO,os.Stdin, os.Stdout, os.Stderr和process的Stdin, Stdout, Stderr相连,然后改变这几个文件描述符的uid和gid即可。

    --------------------------------------------------------------------------- 不分配terminal,不detach ------------------------------------------

    7、runc/tty.go

    // setup standard pipes so that the TTY of the calling runc process is not inherited by the container

    func createStdioPipes(p *libcontainer.Process, rootuid, rootuid int) (*tty, error)

    首先调用i, err := p.InitializeIO(rootuid, rootgid),其中函数InitializeIO函数做的工作其实就是创建了三个管道,并将一端连接process的STDIO,再将另一端返回给i。接着对tty 结构进行填充,主要将STDIO赋值给tty.Closers和tty.postStart。最后将i和os.StdIO相连。

    容器内解析:

    1、runc/libcontainer/standard_init_linux.go

    func (l *linuxStandardInit) Init() error

    该函数先判断从runc端传来的配置中l.config.Console是否为空,如果不为空,则调用console = newConsoleFromPath(l.config.Console),获取一个linuxConsole的实例,其中只将slavePath字段设置为l.config.Console。之后,再调用console.dupStdio(),在dupStdio中打开SlaveConsole文件,并且将fds 复制到当前进程的stdio。如果console不为空,则调用system.Setctty()。在Setctty()中,只是简单地调用了函数,syscall.RawSyscall(syscall.SYS_IOCTL, 0, uintptr(syscall.TIOCSCTTY), 0)

    2、runc/libcontainer/console_linux.go

    // newConsoleFromPath is an internal function returning an initialized console for use inside a container's MNT namespace

    func newConsoleFromPath(slavePath) *linuxConsole

    只是简单地返回 return &linuxConsole{ slavePath: slavePath}

    3、 runc/libcontainer/console_linux.go

    // dupStdio opens the slavePath for the console and dups the fds to the current processes stdio, fd 0, 1, 2

    func (c *linuxConsole) dupStdio() error

    (1)、首先打开console: slave, err := c.open(syscall.O_RDWR),再调用fd := int(slave.Fd())转换为文件描述符

    (2)、最后,调用syscall.Dup3()将STDIO绑定到console上

    4、runc/libcontainer/system/linux.go

    func Setctty() error

    该函数只是简单地调用了syscall.RawSyscall(syscall.SYS_IOCTL, 0, uintptr(syscall.TIOCSCTTY), 0)

  • 相关阅读:
    修改注册表改变程序默认安装路径
    任务管理器在右下角的图标不显示
    WORD中插入的公式与文字对不齐——公式比文字高——文字比公式低
    tablespace
    使用Working Set让eclipse环境看着更清爽
    Grub4DOS 0.4.4 下载
    Windows和Linux操作系统下Eclipse开发C/C++程序的代码提示
    不同的编译器:GCC G++ C C++的区别
    oracle基础
    JS相关
  • 原文地址:https://www.cnblogs.com/YaoDD/p/5974066.html
Copyright © 2020-2023  润新知