docker 详解
很多人刚接触 docker
的时候就会感觉非常神奇,感觉这个技术非常新颖,其实并不然,docker
使用到的技术都是之前已经存在过的,只不过旧酒换了新瓶罢了。简单来说 docker
本质其实是一个特殊的进程,这个进程特殊在它被 Namespace
和Cgroup
技术做了装饰,Namespace
将该进程与Linux
系统进行隔离开来,让该进程处于一个虚拟的沙盒中,而 Cgroup
则对该进程做了一系列的资源限制,两者配合模拟出来一个沙盒的环境。
Namespac
Linux 对线程提供了六种隔离机制,分别为:uts
pid
user
mount
network ipc
,它们的作用如下:
- uts: 用来隔离主机名
- pid:用来隔离进程 PID 号的
- user: 用来隔离用户的
- mount:用来隔离各个进程看到的挂载点视图
- network: 用来隔离网络
- ipc:用来隔离 System V IPC 和 POSIX message queues
环境配置
因为我们是在 Windows
里面写代码,然后将代码编译好,放到 Linux
中执行,所以这里我们要更改下我们 goland
的环境,因为在不同的环境中,go
导入的文件也是不同,如果我们的环境使用的 Windows
,那么使用 os/exec
包时,导入的将是 exec_windows.go
,而如果我们的环境是 Linux
,那么将会导入 exec_linux.go
文件,因为只有 Linux
才会给创建进程时提供这个隔离参数,所以我们需要把环境改成 Linux
。
Go 实现进程隔离
隔离 uts
package main
import (
"log"
"os"
"os/exec"
"syscall"
)
func main() {
cmd := exec.Command("sh")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS,
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
}
我们编译一下,放到 Linux
中测试一下,windows
中编译需要先把 GOOS
改成 Linux
,然后再执行 go build
,编译脚本如下
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build main.go
将 main
放到 Linux
环境中运行,这里我用的是 Centos
4.2 测试能否隔离主机名
给 main 文件添加可执行权限
chmod +x main
查看当前主机名
执行 main 文件
./main
修改主机名
hostname -b 新主机名
再次查看主机名,我们看到已经将主机名修改为 test 了
退出 shell,再次查看主机名
这时我们发现,外部的主机名,并没有被改变,说明该进程成功的将自己的 hostname
与外部的 hostname
进行隔离了。这也证明我们使用 uts namespace
成功了。
其他的隔离
我们想对此进程进行那种隔离,只需要在 Cloneflags
中添加参数即可
package main
import (
"log"
"os"
"os/exec"
"syscall"
)
func main() {
cmd := exec.Command("sh")
cmd.SysProcAttr = &syscall.SysProcAttr{
// 隔离 uts,ipc,pid,mount,user,network
Cloneflags: syscall.CLONE_NEWUTS |
syscall.CLONE_NEWIPC |
syscall.CLONE_NEWPID |
syscall.CLONE_NEWNS |
syscall.CLONE_NEWUSER |
syscall.CLONE_NEWNET,
// 设置容器的UID和GID
UidMappings: []syscall.SysProcIDMap{
{
// 容器的UID
ContainerID: 1,
// 宿主机的UID
HostID: 0,
Size: 1,
},
},
GidMappings: []syscall.SysProcIDMap{
{
// 容器的GID
ContainerID: 1,
// 宿主机的GID
HostID: 0,
Size: 1,
},
},
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
}
转自:微信号 跟派大星学编程