Linux容器LXC學習之Namespace

Linux Containers即就是Linux容器,是一個加強版的Chroot。容器可以提供輕量級的虛擬化,一遍隔離進程和資源,而且不需要提供指令解釋機制以及全虛擬化的其他複雜性。; 

LXC主要依賴Linux內核的3種隔離機制(isolation infrastructure):

  • Chroot 將應用隔離島一個虛擬的私有root下
  • Cgroups 實現資源控制,給每個用戶實例可以按需提供其計算資源
  • Namespaces 提供了隔離性,每個用戶實例之間相互隔離,互不影響

Linux的3.12內核支持6 種Namespace:

  • UTS:隔離進程的hostname
  • IPC:進程間通信
  • PID:隔離進程間的PID namespace,clone新建的進程PID namespace中PID從 1 開始
  • NS:mount掛載點
  • NET:網絡訪問,包括接口
  • USER:將本地的虛擬user-id映射到真實的user-id

想要測試LXC的namespace隔離功能,可以使用clone函數,該函數的flag指定了要隔離的類型:

#include <sched.h>
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ... );
 
fn:子進程要執行的函數
child_stack:子進程的棧空間
flag:創建子進程的標誌
arg:傳給子進程的參數

namespace中對應前五種可以使用clone函數的flag激活,如下: 


下邊對每一種namespace進行實例驗證。

UTS namespace

#define _GNU_SOURCE //功能測試宏,可以在程序中定義(必須程序開頭),也可以在編譯時指定 gcc -D_GNU_SOURCE 程序名
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
 
#define STACK_SIZE (1024 * 1024)
 
static char child_stack[STACK_SIZE]; //定義成void *child_stack時,子進程不執行
char * const child_args[] = {
"/bin/bash",
NULL
};
 
int child_main(void* arg) {
printf("Child inside Namespace\n");
sethostname("In Namespace",12); //子進程中設置hostname,區分父子進程UTS命令空間
execv(child_args[0], child_args);
printf("execv error\n");
return -1;
}
 
int main()
{
printf("Parent outside Namespace \n");
int child_pid = clone(child_main, child_stack + STACK_SIZE, CLONE_NEWUTS | SIGCHLD, NULL); //函數名代表函數的首地址,此處也可以寫成&child_main
//子進程棧空間,不加STACK_SIZE時,無法執行子進程的/bin/bash
if(child_pid == -1)
perror("clone");
waitpid(child_pid, NULL, 0);
printf("child exit...\n");
 
exit(EXIT_SUCCESS);
}
[ty@tiany docker]$ sudo ./a.out
Parent outside Namespace
Child inside Namespace
[root@In Namespace docker]# hostname
In Namespace
[root@In Namespace docker]# exit
exit
child exit...
[ty@tiany docker]$ hostname
tiany.com
[ty@tiany docker]$

IPC

ipc namespace測試和上一個程序基本一致,只需要在clone函數中開啓CLONE_NEWIPC標誌即可,在子進程中創建消息隊列,其他進程中看不見,反之亦然。

測試如下所示:

inside IPC namespace :


outside IPC namespace: 



PID Namspace

在clone函數中添加CLONE_NEWPID標誌,即就是開啓了PID namespace; 
在子進程執行的程序中,添加 
printf("I am [%5d] child \n",getpid());打印子進程PID,測試如下:

[ty@tiany docker]$ sudo ./a.out
I am [13021] parent ?
I am [ 1] child
[root@In Namespace docker]#

會輸出子進程PID爲1,就是因爲隔離了父子進程的PID namespace,在父進程時可以使用top 或 “ps exf”命令顯示自己和子進程(未映射的)的PID,會發現在子進程時使用ps命令和父進程時的內容一模一樣,是因爲這些工具否是從真實的”/proc”文件系統中獲取信息,而/proc是尚未隔離的。

NS namespace和NET namespace的測試代碼地址:

https://github.com/ty92/Linux-LXC

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章