第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁 慕課教程 Docker 入門教程 Docker 入門教程 容器核心技術(shù)--Namespace

容器核心技術(shù)–Namespace

上文提到,容器技術(shù)的核心有兩個:Namespace 和 Cgroup。本節(jié)先來介紹 Namespace 是什么。

簡單來說,Namespace 可以為容器提供系統(tǒng)資源隔離能力。

當(dāng)然,這樣講過于籠統(tǒng),我們來舉個例子:假如一個容器中的進程需要使用 root 權(quán)限,出于安全考慮,我們不可能把宿主機的 root 權(quán)限給他。但是通過 Namespace 機制,我們可以隔離宿主機與容器的真實用戶資源,謊稱一個普通用戶就是 root,過這個程序。從這個角度看,Namespace 就是內(nèi)核對進程說謊的機制,目前(Linux最新的穩(wěn)定版本為5.6),內(nèi)核可以說的謊話有 8 種:

Namespace 系統(tǒng)調(diào)用
Mount CLONE_NEWNS
UTS CLONE_NEWUTS
IPC CLONE_NEWIPC
PID CLONE_NEWPID
Network CLONE_NEWNET
User CLONE_NEWUSER
Cgroup CLONE_NEWCGROUP
Time CLONE_NEWTIME

1. Namespace 詳解

1.1 Mount Namespace

Mount Namespace 用來隔離文件系統(tǒng)的掛載點,不同的 Mount namespace 擁有各自獨立的掛載點信息。在 Docker 這樣的容器引擎中,Mount namespace 的作用就是保證容器中看到的文件系統(tǒng)的視圖。

1.2 UTS Namespace

UTS Namespace 用來隔離系統(tǒng)的主機名、hostname 和 NIS 域名。

1.3 IPC Namespace

IPC 就是在不同進程間傳遞和交換信息。IPC Namespace 使得容器內(nèi)的所有進程,進行的數(shù)據(jù)傳輸、共享數(shù)據(jù)、通知、資源共享等范圍控制在所屬容器內(nèi)部,對宿主機和其他容器沒有干擾。

1.4 PID Namespace

PID namespaces用來隔離進程的 ID 空間,使得不同容器里的進程 ID 可以重復(fù),相互不影響。

1.5 Network Namespace

Network namespace 用來隔離網(wǎng)絡(luò),每個 namespace 可以有自己獨立的網(wǎng)絡(luò)棧,路由表,防火墻規(guī)則等

1.6 user namespace

user namespace 是例子中講到的,控制用戶 UID 和 GID 在容器內(nèi)部和宿主機上的一個映射,主要用來管理權(quán)限。

1.7 Time namespace

這個 Namespace 允許操作系統(tǒng)為進程設(shè)定不同的系統(tǒng)時間

1.8 Cgroup Namespace

這個 Namespace 用來限制 CGroup 根目錄下不同層級目錄的權(quán)限,使得 CGROUP 根目錄下的子目錄的進程無法影響到父目錄。

2. 實踐出真知

2.1 感受 Namespace

講了那么多理論,Namespace 能不能讓我們直接觀察到呢?

讓我們進入 Linux 環(huán)境,執(zhí)行如下操作:

# 進入/proc/目錄
cd /proc/
# 查看當(dāng)前目錄下有哪些文件或目錄
ls
# 隨便進入一個以數(shù)字(進程號)命名的目錄,比如1
cd 1
# 查看ns(Namespace)目錄下的內(nèi)容
ls -al ns

圖片描述

當(dāng)前目錄下紅色的鏈接,就是這個進程對應(yīng)的 Namespace。

有興趣的讀者可以看看其他不同進程的 Namespace,比對下是否有差異。如果你找到某個進程的Namespace 與其他的不一致,就說明這個進程指定了 Namespace 隔離。

2.2 使用 Namespace 自制簡易容器

將以下代碼保存到/root/test/container.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/capability.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

#define STACK_SIZE (1024 * 1024)

static char container_stack[STACK_SIZE];
char* const container_args[] = {
        "/bin/bash",
        NULL
};

int pipefd[2];

void set_map(char* file, int inside_id, int outside_id, int len) {
        FILE* mapfd = fopen(file, "w");
        if (NULL == mapfd) {
                perror("open file error");
                return;
        }
        fprintf(mapfd, "%d %d %d", inside_id, outside_id, len);
        fclose(mapfd);
}

void set_uid_map(pid_t pid, int inside_id, int outside_id, int len) {
        char file[256];
        sprintf(file, "/proc/%d/uid_map", pid);
        set_map(file, inside_id, outside_id, len);
}

void set_gid_map(pid_t pid, int inside_id, int outside_id, int len) {
        char file[256];
        sprintf(file, "/proc/%d/gid_map", pid);
        set_map(file, inside_id, outside_id, len);
}

int container_main()
{
        char ch;
        close(pipefd[1]);
        read(pipefd[0], &ch, 1);
        sethostname("container",10);

        /* Mount Namespace */
        mount("proc", "/proc", "proc", 0, NULL);
        mount("none", "/tmp", "tmpfs", 0, "");

        execv(container_args[0], container_args);
        return 1;
}

int main()
{
        const int gid=getgid(), uid=getuid();

        pipe(pipefd);

        int container_pid = clone(container_main, container_stack+STACK_SIZE,
            CLONE_NEWCGROUP|CLONE_NEWIPC|CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWUSER | SIGCHLD, NULL);
        set_uid_map(container_pid, 0, uid, 1);
        set_gid_map(container_pid, 0, gid, 1);
        close(pipefd[1]);
        waitpid(container_pid, NULL, 0);
        return 0;
}

我們不用讀懂這個代碼,只需要留意下 main 主函數(shù)中這部分

int container_pid = clone(container_main, container_stack+STACK_SIZE,
                    CLONE_NEWCGROUP|CLONE_NEWIPC|CLONE_NEWNET|CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWUSER | SIGCHLD, NULL);

這段代碼 調(diào)用 clone 實現(xiàn)線程的系統(tǒng)調(diào)用,用來創(chuàng)建一個新的進程,并可以通過設(shè)計上述參數(shù)達(dá)到隔離。

執(zhí)行下面的操作

# 安裝可能需要的依賴
sudo dnf install -y libcap-devel
# 編譯這個文件
cc container.c -o container
# 運行
./container

執(zhí)行我們編譯好的container程序后,發(fā)現(xiàn)我們處于一個新的環(huán)境的終端中,你可以在這里驗證你的猜測,比如查看當(dāng)前環(huán)境的進程 ps,當(dāng)前登錄的用戶 whoami,網(wǎng)絡(luò)狀況 ip a等等,使用exit 可以退出回到原來的環(huán)境。
我們確實通過系統(tǒng)調(diào)用,創(chuàng)建了一個與宿主機資源隔離的容器環(huán)境。

3. 小結(jié)

本節(jié)我們介紹了 Namespace 機制,和它的 8 種隔離類型,并實現(xiàn)了一具有命名空間隔離功能的“容器”,在這個過程中,希望大家對容器和 Namespace 機制有了更深入的理解。