天天看點

Linux命名空間學習教程(一) UTS

本文講的是Linux命名空間學習教程(一) UTS,【編者的話】Docker核心解決的問題是利用LXC來實作類似VM的功能,進而利用更加節省的硬體資源提供給使用者更多的計算資源。而 LXC所實作的隔離性主要是來自核心的命名空間, 其中pid、net、ipc、mnt、uts 等命名空間将容器的程序、網絡、消息、檔案系統和hostname 隔離開。本文是Linux命名空間系列教程的第一篇,通過一個簡單的例子介紹了Linux容器以及UTS命名空間。DockerOne在撸代碼的基礎上進行了校對和整理。

我在OVH工作的時候,曾經為一款“即将釋出”的産品添加安全機制,而這項工作需要用到Linux的命名空間(Linux namespace)。在學習過程中我發現,Linux的命名空間很強大,但是這方面的文檔卻非常少。

大多數人都應該聽說過LXC——LinuX Containers,它是一個加強版的Chroot。簡單的說,LXC就是将不同的應用隔離開來,這有點類似于chroot,chroot是将應用隔離到一個虛拟的私有root下,而LXC在這之上更進了一步。LXC内部依賴Linux核心的3種隔離機制(isolation infrastructure):

Chroot

Cgroups

Namespaces

我本可以将這個系列命名為《如何建構你自己的LXC》,進而赢得更高的Google排名,但這樣做可能會顯得我太狂妄。事實上,LXC所做的事情遠不止隔離,它還包含模闆管理、當機以及其它更多的功能。這個系列将會為你解開LXC的神秘面紗。

在這個系列中,我們将使用最簡單的C程式啟動/bin/bash ,并逐漸為它加入各種隔離機制。

好了,現在我們開始吧。

有意思的是,Linux的容器工具并沒有提供一個類似黑盒般神秘的容器解決方案,而是提供單獨隔離構件(isolation building block),統稱為Namespaces。每一個新版本都會有新的構件釋出出來。這樣你就可以跟據你的特定應用的情況,選擇所需要的構件。

Linux的3.12核心支援6種Namespace:

UTS: hostname(本文介紹)

IPC: 程序間通信 (之後的文章會講到)

PID: "chroot"程序樹(之後的文章會講到)

NS: 挂載點,首次登陸Linux(之後的文章會講到)

NET: 網絡通路,包括接口(之後的文章會講到)

USER: 将本地的虛拟user-id映射到真實的user-id(之後的文章會講到)

如下是一個程式的完整骨架,用于從子程序啟動/bin/bash程式(為了保持例子簡單,是以去掉了錯誤檢查):

main-0-template.c

define _GNU_SOURCE

include <sys/types.h>

include <sys/wait.h>

include <stdio.h>

include <sched.h>

include <signal.h>

include <unistd.h>

define STACK_SIZE (1024 * 1024)

static char child_stack[STACK_SIZE];

char* const child_args[] = {

"/bin/bash",

NULL

};

int child_main(void* arg) {

printf(" - World !\n");

execv(child_args[0], child_args);

printf("Ooops\n");

return 1;

}

int main() {

printf(" - Hello ?\n");

int child_pid = clone(child_main, child_stack + STACK_SIZE, SIGCHLD, NULL);

waitpid(child_pid, NULL, 0);

return 0;

請注意,這裡我們使用的是clone而不是fork系統調用。這正是魔法(即将)發生的地方。

jean-tiare@jeantiare-Ubuntu:~/blog$ gcc -Wall main.c -o ns && ./ns

- Hello ?

- World !

jean-tiare@jeantiare-Ubuntu:~/blog$ # inside the container

jean-tiare@jeantiare-Ubuntu:~/blog$ exit

jean-tiare@jeantiare-Ubuntu:~/blog$ # outside the container

OK,帥呆了。不過,假如沒有注釋,你很難注意到我們在子程序的/bin/bash中。事實上,當我在寫這篇文章的時候,好幾次不小心退出父程序的shell。

現在做一些修改,如直接修改主機名(the hostname with 0% env vars tricks),是不是會很牛逼?就單單用Namespace?很簡單,我們隻要:

在clone系統調用中使用CLONE_NEWUTS的标志

在子程序中調用sethostname

main-1-uts.c

// (needs root privileges (or appropriate capabilities))

//[...]

sethostname("In Namespace", 12);

int child_pid = clone(child_main, child_stack+STACK_SIZE,

    CLONE_NEWUTS | SIGCHLD, NULL);

運作一下:

jean-tiare@jeantiare-Ubuntu:~/blog$ gcc -Wall main.c -o ns && sudo ./ns

root@In Namespace:~/blog$ # inside the container

root@In Namespace:~/blog$ exit

事情就是這個樣子(至少這篇文章中是這樣)!namespace真是太TM容易上手了:clone,設定特定的CLONE_NEW*标志,設定新的env,搞定!

你希望更加深入?有興趣可以閱讀一下excellent LWN article series on namespaces。

原文連結:Introduction to Linux namespaces – Part 1: UTS(翻譯:孫科 審校:李穎傑)

原文釋出時間為: 2014-12-24 

本文作者:孫科 

本文來自雲栖社群合作夥伴DockerOne,了解相關資訊可以關注DockerOne。

原文标題:Linux命名空間學習教程(一) UTS