【runc 源码分析】namespace 源码分析
来源:互联网 发布:stl源码是什么 编辑:程序博客网 时间:2024/06/05 17:40
1 Config
libcontainer/configs/config.go 中结构体 Config 中使用 namespace,Config 为在容器环境中执行进行定义了配置选项
// Config defines configuration options for executing a process inside a contained environment.type Config struct { // Namespaces specifies the container's namespaces that it should setup when cloning the init process // If a namespace is not provided that namespace is shared from the container's parent process Namespaces Namespaces `json:"namespaces"`}
2 namespace
libcontainer/configs/namespace_linux.go 中结构体 Namespace 定义了 namespace,Config 为在容器环境中执行进行定义了配置选项,只有两项内容,类型与路径
// Namespace defines configuration for each namespace. It specifies an// alternate path that is able to be joined via setns.type Namespace struct { Type NamespaceType `json:"type"` Path string `json:"path"`}
// Namespace defines configuration for each namespace. It specifies an// alternate path that is able to be joined via setns.type Namespace struct { Type NamespaceType `json:"type"` Path string `json:"path"`}
2.1 namespace 类型
libcontainer/configs/namespace_linux.go 中定义类型如下所示,包括 net,pid,mnt,ipc,user,uts
const ( NEWNET NamespaceType = "NEWNET" NEWPID NamespaceType = "NEWPID" NEWNS NamespaceType = "NEWNS" NEWUTS NamespaceType = "NEWUTS" NEWIPC NamespaceType = "NEWIPC" NEWUSER NamespaceType = "NEWUSER")
2.2 namespace 方法
libcontainer/configs/namespace_linux.go 中函数 IsNamespaceSupported 返回是否 namespace 可以使用,使用了全局变量 supportedNamespaces,key 为类型,value 为 true / false。NsName 转换 namespace 类型为相应的文件名,判断 /proc/self/ns/${type-to-file} 存在与否
// IsNamespaceSupported returns whether a namespace is available or// notfunc IsNamespaceSupported(ns NamespaceType) bool { nsLock.Lock() defer nsLock.Unlock() supported, ok := supportedNamespaces[ns] if ok { return supported } nsFile := NsName(ns) // if the namespace type is unknown, just return false if nsFile == "" { return false } _, err := os.Stat(fmt.Sprintf("/proc/self/ns/%s", nsFile)) // a namespace is supported if it exists and we have permissions to read it supported = err == nil supportedNamespaces[ns] = supported return supported}
libcontainer/configs/namespace_linux.go 中函数 GetPath 路径为 /proc/${pid}/ns/${type-to-file}
func (n *Namespace) GetPath(pid int) string { return fmt.Sprintf("/proc/%d/ns/%s", pid, NsName(n.Type))}
2.3 namespaces 方法
libcontainer/configs/namespace_linux.go 中 Namespaces 定义的函数如下都比较简单
type Namespaces []Namespace
func (n *Namespaces) Remove(t NamespaceType) bool {}func (n *Namespaces) Add(t NamespaceType, path string) {}func (n *Namespaces) index(t NamespaceType) int {}func (n *Namespaces) Contains(t NamespaceType) bool {}func (n *Namespaces) PathOf(t NamespaceType) string {}
2.4 namespaces 系统调用参数
libcontainer/configs/namespace_syscall.go 中 namespaceInfo 定义了 namespce 系统调用参数
var namespaceInfo = map[NamespaceType]int{ NEWNET: unix.CLONE_NEWNET, NEWNS: unix.CLONE_NEWNS, NEWUSER: unix.CLONE_NEWUSER, NEWIPC: unix.CLONE_NEWIPC, NEWUTS: unix.CLONE_NEWUTS, NEWPID: unix.CLONE_NEWPID,}
Namespace
系统调用参数
隔离内容
UTS
CLONE_NEWUTS
主机名与域名
IPC
CLONE_NEWIPC
信号量、消息队列和共享内存
PID
CLONE_NEWPID
进程编号
Network
CLONE_NEWNET
网络设备、网络栈、端口等等
Mount
CLONE_NEWNS
挂载点(文件系统)
User
CLONE_NEWUSER
用户和用户组
CloneFlags 函数遍历数组中所有 namespace 类型,返回 clone flags
// CloneFlags parses the container's Namespaces options to set the correct// flags on clone, unshare. This function returns flags only for new namespaces.func (n *Namespaces) CloneFlags() uintptr { var flag int for _, v := range *n { if v.Path != "" { continue } flag |= namespaceInfo[v.Type] } return uintptr(flag)}
3 namespace 调用函数
libcontainer/container_linux.go 中函数 newInitProcess 调用 CloneFlags 获得,传给 bootstrapData 函数使用
func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe, rootDir *os.File) (*initProcess, error) { nsMaps := make(map[configs.NamespaceType]string) for _, ns := range c.config.Namespaces { if ns.Path != "" { nsMaps[ns.Type] = ns.Path } } _, sharePidns := nsMaps[configs.NEWPID] data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps) if err != nil { return nil, err } return &initProcess{ cmd: cmd, childPipe: childPipe, parentPipe: parentPipe, manager: c.cgroupManager, config: c.newInitConfig(p), container: c, process: p, bootstrapData: data, sharePidns: sharePidns, rootDir: rootDir, }, nil}
func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe, rootDir *os.File) (*initProcess, error) { nsMaps := make(map[configs.NamespaceType]string) for _, ns := range c.config.Namespaces { if ns.Path != "" { nsMaps[ns.Type] = ns.Path } } _, sharePidns := nsMaps[configs.NEWPID] data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps) if err != nil { return nil, err } return &initProcess{ cmd: cmd, childPipe: childPipe, parentPipe: parentPipe, manager: c.cgroupManager, config: c.newInitConfig(p), container: c, process: p, bootstrapData: data, sharePidns: sharePidns, rootDir: rootDir, }, nil}
libcontainer/container_linux.go 中函数 bootstrapData 使用 netlink 请求与内核进行通信,添加的数据类型有 CloneFlagsAttr,NsPathAttr,UidmapAttr,GidmapAttr,OomScoreAdjAttr,RootlessAttr 等,将数据进行序列化
func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string) (io.Reader, error) { // create the netlink message r := nl.NewNetlinkRequest(int(InitMsg), 0) // write cloneFlags r.AddData(&Int32msg{ Type: CloneFlagsAttr, Value: uint32(cloneFlags), }) // write custom namespace paths if len(nsMaps) > 0 { nsPaths, err := c.orderNamespacePaths(nsMaps) if err != nil { return nil, err } r.AddData(&Bytemsg{ Type: NsPathsAttr, Value: []byte(strings.Join(nsPaths, ",")), }) } // write namespace paths only when we are not joining an existing user ns _, joinExistingUser := nsMaps[configs.NEWUSER] if !joinExistingUser { // write uid mappings if len(c.config.UidMappings) > 0 { b, err := encodeIDMapping(c.config.UidMappings) if err != nil { return nil, err } r.AddData(&Bytemsg{ Type: UidmapAttr, Value: b, }) } // write gid mappings if len(c.config.GidMappings) > 0 { b, err := encodeIDMapping(c.config.GidMappings) if err != nil { return nil, err } r.AddData(&Bytemsg{ Type: GidmapAttr, Value: b, }) // The following only applies if we are root. if !c.config.Rootless { // check if we have CAP_SETGID to setgroup properly pid, err := capability.NewPid(os.Getpid()) if err != nil { return nil, err } if !pid.Get(capability.EFFECTIVE, capability.CAP_SETGID) { r.AddData(&Boolmsg{ Type: SetgroupAttr, Value: true, }) } } } } // write oom_score_adj r.AddData(&Bytemsg{ Type: OomScoreAdjAttr, Value: []byte(fmt.Sprintf("%d", c.config.OomScoreAdj)), }) // write rootless r.AddData(&Boolmsg{ Type: RootlessAttr, Value: c.config.Rootless, }) return bytes.NewReader(r.Serialize()), nil}
func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string) (io.Reader, error) { // create the netlink message r := nl.NewNetlinkRequest(int(InitMsg), 0) // write cloneFlags r.AddData(&Int32msg{ Type: CloneFlagsAttr, Value: uint32(cloneFlags), }) // write custom namespace paths if len(nsMaps) > 0 { nsPaths, err := c.orderNamespacePaths(nsMaps) if err != nil { return nil, err } r.AddData(&Bytemsg{ Type: NsPathsAttr, Value: []byte(strings.Join(nsPaths, ",")), }) } // write namespace paths only when we are not joining an existing user ns _, joinExistingUser := nsMaps[configs.NEWUSER] if !joinExistingUser { // write uid mappings if len(c.config.UidMappings) > 0 { b, err := encodeIDMapping(c.config.UidMappings) if err != nil { return nil, err } r.AddData(&Bytemsg{ Type: UidmapAttr, Value: b, }) } // write gid mappings if len(c.config.GidMappings) > 0 { b, err := encodeIDMapping(c.config.GidMappings) if err != nil { return nil, err } r.AddData(&Bytemsg{ Type: GidmapAttr, Value: b, }) // The following only applies if we are root. if !c.config.Rootless { // check if we have CAP_SETGID to setgroup properly pid, err := capability.NewPid(os.Getpid()) if err != nil { return nil, err } if !pid.Get(capability.EFFECTIVE, capability.CAP_SETGID) { r.AddData(&Boolmsg{ Type: SetgroupAttr, Value: true, }) } } } } // write oom_score_adj r.AddData(&Bytemsg{ Type: OomScoreAdjAttr, Value: []byte(fmt.Sprintf("%d", c.config.OomScoreAdj)), }) // write rootless r.AddData(&Boolmsg{ Type: RootlessAttr, Value: c.config.Rootless, }) return bytes.NewReader(r.Serialize()), nil}
/var/run/runc/container-bbbb/state.json 中纪录运行容器的状态信息,各个 namespace 对应的路径
"namespace_paths": {
"NEWIPC": "/proc/3193/ns/ipc",
"NEWNET": "/proc/3193/ns/net",
"NEWNS": "/proc/3193/ns/mnt",
"NEWPID": "/proc/3193/ns/pid",
"NEWUSER": "/proc/3193/ns/user",
"NEWUTS": "/proc/3193/ns/uts"
}
"NEWIPC": "/proc/3193/ns/ipc",
"NEWNET": "/proc/3193/ns/net",
"NEWNS": "/proc/3193/ns/mnt",
"NEWPID": "/proc/3193/ns/pid",
"NEWUSER": "/proc/3193/ns/user",
"NEWUTS": "/proc/3193/ns/uts"
}
阅读全文
0 0
- 【runc 源码分析】namespace 源码分析
- runC源码分析——namespace
- 【runc 源码分析】cgroup 源码分析
- 【runc 源码分析】runc create / start 流程分析
- runC源码分析——cgroup
- docker RunC Create 源码简单分析
- runc源码分析——create和start
- runC源码分析——Create/Run Container
- runC源码分析——主体调用链
- runc源码分析——create和start
- Linux kernel Namespace源码分析
- Ext源码分析:解析Ext的命名空间,Ext.namespace
- Ext源码分析:解析Ext的命名空间,Ext.namespace
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- JS学习-面向对象编程
- 微信小程序:隐藏和显示功能
- HDU-1078FatMouse and Cheese 记忆化搜索
- WIFI吞吐率的提升方法
- “烫”字和“屯”字的原因
- 【runc 源码分析】namespace 源码分析
- Spring核心技术--事务管理
- Go语言的程序结构
- 10.emoji
- Oracle 大量数据常见优化查询
- java数据结构与算法-有序数组二分查找
- 配置MySQL以及本地和远程访问数据库
- 使用Jpeglib
- C#目录树控件