很多人剛接觸docker的時候就會感覺非常神奇,感覺這個技術非常新穎,其實並不然,docker使用到的技術都是之前已經存在過的,只不過舊酒換了新瓶罷了。簡單來說docker本質其實是一個
特殊的程式
,這個程式特殊在它被Namespace
和Cgroup
技術做了裝飾,Namespace
將該程式與Linux系統進行隔離開來,讓該程式處於一個虛擬的沙盒中,而Cgroup
則對該程式做了一系列的資源限制,兩者配合模擬出來一個沙盒的環境。
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。
4.1 隔離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
成功了。
4.2 其他的隔離
我們想對此程式進行那種隔離,只需要在
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)
}
}
文章會首發於我微信公眾號上,掃碼關注,及時獲取最新內容
本作品採用《CC 協議》,轉載必須註明作者和本文連結