独自の仮想化コンテナ#4 PIDネーミングスペースの作成
📖 概要
今日、仮想化コンテナを実装するための最も基本的なPID 네임스페이스
テクノロジーを使用します.
前回の投稿で述べたJNIコードの作成は、すべての練習が完了した後に続行されます.また、#2 기초 이론
ではこれらの概念が1編で議論されているため、詳細に説明されていない内容に重点を置いて議論する.
📦 PIDネーミングスペースとは?
PIDネーミングスペースの詳細については、こちらを参考にしてください!を参照してください.
PIDネーミングスペースは、特定のプロセスを他のプロセスから分離し、自分がinitプロセスだと思っているようにします.
🔧 体験する
🖥 実験環境:Ubuntu 20.04 LTS、AMD 64アーキテクチャ
1.unshareコマンドの使用
unshare -fp /bin/bash
上記のコマンドを使用すると、新しいbashウィンドウが開きます.
PIDネーミングスペースの詳細については、こちらを参考にしてください!を参照してください.
PIDネーミングスペースは、特定のプロセスを他のプロセスから分離し、自分がinitプロセスだと思っているようにします.
🔧 体験する
🖥 実験環境:Ubuntu 20.04 LTS、AMD 64アーキテクチャ
1.unshareコマンドの使用
unshare -fp /bin/bash
上記のコマンドを使用すると、新しいbashウィンドウが開きます.
unshare -fp /bin/bash
unshare
:新しいネーミングスペースを作成し、ドライバのコマンド-fp
f
オプション:フォークリフト特定プログラムはunshareプロセスのサブプロセスで駆動されます.p
オプション:PIDネーミングスペースの作成/bin/bash
:bash shellを分離するプログラムを指定2.差異の比較
これで、別のネーミングスペースで分離bash shellが実行されます.
現在の状況では、プログラムは自分をinitプロセスと認識します.pstreeコマンドでチェックできますか?
pstree
うん.しかし不思議なことにbash shellではない他のプログラムも一緒に現れます.何か問題がありますか.
プロセス分離に失敗したと思うかもしれませんが、実際には正常です.
3.PIDネーミングスペースの問題
まず,
왜 이러한 현상이 일어나는가?
PIDネーミング空間の役割を理解するには,pstreeの動作原理も理解しなければならない.まず,PIDネーミングスペースは,
특정 프로세스가 스스로를 init 프로세스라고 인식하도록
(他のプロセスにアクセスできない)を分離する機能にすぎない.その後、プロセスクエリ命令(pstreeまたはpsコマンドなど)は、
/proc
というディレクトリで識別され、出力される.何か気づいたか?
はい、bash shellのPIDネーミングスペースだけを隔離しました.
したがって、bash shellから発行されたpstreeコマンドは、ネーミングスペース以外の/procディレクトリをスキャンし、bash shell標準のpstreeではなく外部標準を出力します.
もっと簡単に言えば...
/proc
ディレクトリ/proc
ディレクトリであるため、外部条件下のpstree4.mount-procオプション
実際、Linux開発者もこれらの問題を知っているので、これらの問題を解決するためのオプションを別途作成しました.
mount-proc
という名前のオプションで、このオプションの基礎(?)私たちはまだmountオプション(ネーミングスペースをマウント)を勉強していないので、簡単に紹介します.問題のフォルダを別のインストールネーミングスペースに分離するオプション
そう思えばいい
もしそうであれば、このオプションを使用してbash shellを再度開きます.
unshare -fp --mount-proc /bin/bash
pstreeコマンドを再入力しましょうか?pstree
次の結果が表示される可能性があります.bash───pstree
独立したbash shell条件からpstreeを取得することに成功しました.C言語で/proc
を記述しましょう.プログラムの作成と実行
コードの作成
以前、LinuxのコマンドShell環境では、격리를 자동화하는 프로그램
コマンドで名前空間を管理できました.では、C言語ではどうなるのでしょうか.
C言語はタイトルファイルunshare
を提供している.コードファイルを作成するには、次の手順に従います.
注意:次のコードは、Githubの|45915|、|Repositoryのコードを参照して作成されます.#define _GNU_SOURCE
#include <stdio.h> // 표준 입출력
#include <sched.h> // unshare() 메소드 및 flags
#include <unistd.h> // execl() 메소드
#include <sys/wait.h> // wait() 메소드
#include <sys/mount.h> // mount() 메소드
// unshare 함수를 위한 인자
// PID 네임스페이스(p 옵션), FS 네임스페이스(mount를 위한 옵션)
const int flags = CLONE_NEWPID | CLONE_NEWNS;
// bash를 실행하는 함수
void spawnShell() {
execl("/bin/bash", "bash", (char*)NULL);
}
// '/proc' 디렉터리를 재마운트하는 함수
int remountProc() {
if(mount("none", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)) return -1;
return 0;
}
int main() {
// 네임스페이스 구성
if(unshare(flags) == -1) {
printf("Unshare failed!\n");
return -1;
}
printf("unshared process successfully\n");
// 자식 프로세스 생성(분기점)
int forkResponse = fork();
// 현 프로세스의 종류에 따라 기능 분리
switch(forkResponse) {
case 0: // 자식 프로세스일 때
printf("현재 자식 프로세스입니다 / PID : %d\n", getpid());
if(remountProc() == -1) {
printf("Mounting /proc failed!");
return -1;
}
printf("Mount successed!\n");
printf("Spawning /bin/bash :\n");
spawnShell(); // '/bin/bash' 실행
break;
case -1: // 부모 프로세스에서 오류 발생 시
printf("fork() 실행 중 오류 발생\n");
break;
default: // 부모 프로세스일 때(자식 PID 반환)
printf("부모(PID %d)로부터 자식 프로세스(PID %d) 생성\n", getpid(), forkResponse);
wait(NULL); // 중요: 자식 프로세스(/bin/bash)가 종료될 때까지 대기함.
printf("Child process has exited.\n\n");
}
return 0;
}
コアコード
sched.hの旗
// unshare 함수를 위한 인자
// PID 네임스페이스(p 옵션), FS 네임스페이스(mount를 위한 옵션)
const int flags = CLONE_NEWPID | CLONE_NEWNS;
...
int main() {
// 네임스페이스 구성
if(unshare(flags) == -1) {
...
ご覧のように、util-linux/util-linux
メソッドを呼び出すと、パラメータ値はweary/unsharepp
を超えます.unshareを実行すると、このパラメータはどのネーミングスペースを作成するかを決定します.
ただし、unshare
の初期化値を表示すると、複数の定数のビット演算が表示されます.どうしてですか.
JAVAのようにオブジェクト向け言語を使用する人は、通常、unshare
をメソッドに渡すときにクラスを作成して渡します.形式は次のとおりです.class Config {
boolean CLONE_NEWPID;
boolean CLONE_NEWNS;
}
しかし、C言語ではクラスはサポートされておらず、代替材料としてflags
が存在するが、実施の特性上、メモリの浪費が深刻である.したがって,C言語では主にビット演算によるflagが用いられる.
通常、整数は4バイト、整数は32ビットです.したがって、合計32個の「真/偽」フィールドを表示できます.
サンプルコードでは、オプションflags
およびBool만으로 이루어진 여러 설정값
flag.どちらのオプションもBit OR演算で、最終的なflag値は次のようになります. 00100000000000000000000000000000 (CLONE_NEWPID)
+ 00000000000000100000000000000000 (CLONE_NEWNS)
―――――――――――――――――――――――――――――――――――――
= 00100000000000100000000000000000
構造体呼び出し
// 자식 프로세스 생성(분기점)
int forkResponse = fork();
// 현 프로세스의 종류에 따라 기능 분리
switch(forkResponse) {
...
CLONE_NEWPID
メソッドは、プロセス自体のメモリをコピーすることによってサブプロセスを作成します.その後、親プロセスはCLONE_NEWNS
を返し、子プロセスはfork
を返します.
画像として表示:
実行例
次のコマンドを使用してコードをコンパイルして実行します.sudo su & gcc -o myContainer 코드파일명.c && ./myContainer
この操作を行うと、次の画面が表示されます.unshared process successfully
부모(PID <부모 PID>)로부터 자식 프로세스(PID <자식 PID>) 생성
현재 자식 프로세스입니다 / PID : 1
Mount successed!
Spawning /bin/bash :
root@<호스트명>:/<디렉터리명>#
今からpstreeコマンドを使いましょうか?bash───pstree
以前にコマンドで実装されたfork()
bashと同様に、bashが생성된 자식 프로세스의 PID
と認識されていることがわかります.
👏 の最後の部分
申し訳ございませんが、この文章には約3週間かかりました.実際、書くこと自体にはあまり時間がかかりませんでした.学校のビデオ編集の仕事と私の怠惰なので、完成が遅いです.これからはあまり時間がかかりません.
次の投稿では、0
について説明します.
ありがとうございます.
Reference
この問題について(独自の仮想化コンテナ#4 PIDネーミングスペースの作成), 我々は、より多くの情報をここで見つけました
https://velog.io/@vinto1819/나만의-가상화-컨테이너-만들기-4-PID-네임스페이스
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
#define _GNU_SOURCE
#include <stdio.h> // 표준 입출력
#include <sched.h> // unshare() 메소드 및 flags
#include <unistd.h> // execl() 메소드
#include <sys/wait.h> // wait() 메소드
#include <sys/mount.h> // mount() 메소드
// unshare 함수를 위한 인자
// PID 네임스페이스(p 옵션), FS 네임스페이스(mount를 위한 옵션)
const int flags = CLONE_NEWPID | CLONE_NEWNS;
// bash를 실행하는 함수
void spawnShell() {
execl("/bin/bash", "bash", (char*)NULL);
}
// '/proc' 디렉터리를 재마운트하는 함수
int remountProc() {
if(mount("none", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)) return -1;
return 0;
}
int main() {
// 네임스페이스 구성
if(unshare(flags) == -1) {
printf("Unshare failed!\n");
return -1;
}
printf("unshared process successfully\n");
// 자식 프로세스 생성(분기점)
int forkResponse = fork();
// 현 프로세스의 종류에 따라 기능 분리
switch(forkResponse) {
case 0: // 자식 프로세스일 때
printf("현재 자식 프로세스입니다 / PID : %d\n", getpid());
if(remountProc() == -1) {
printf("Mounting /proc failed!");
return -1;
}
printf("Mount successed!\n");
printf("Spawning /bin/bash :\n");
spawnShell(); // '/bin/bash' 실행
break;
case -1: // 부모 프로세스에서 오류 발생 시
printf("fork() 실행 중 오류 발생\n");
break;
default: // 부모 프로세스일 때(자식 PID 반환)
printf("부모(PID %d)로부터 자식 프로세스(PID %d) 생성\n", getpid(), forkResponse);
wait(NULL); // 중요: 자식 프로세스(/bin/bash)가 종료될 때까지 대기함.
printf("Child process has exited.\n\n");
}
return 0;
}
// unshare 함수를 위한 인자
// PID 네임스페이스(p 옵션), FS 네임스페이스(mount를 위한 옵션)
const int flags = CLONE_NEWPID | CLONE_NEWNS;
...
int main() {
// 네임스페이스 구성
if(unshare(flags) == -1) {
...
class Config {
boolean CLONE_NEWPID;
boolean CLONE_NEWNS;
}
00100000000000000000000000000000 (CLONE_NEWPID)
+ 00000000000000100000000000000000 (CLONE_NEWNS)
―――――――――――――――――――――――――――――――――――――
= 00100000000000100000000000000000
// 자식 프로세스 생성(분기점)
int forkResponse = fork();
// 현 프로세스의 종류에 따라 기능 분리
switch(forkResponse) {
...
sudo su & gcc -o myContainer 코드파일명.c && ./myContainer
unshared process successfully
부모(PID <부모 PID>)로부터 자식 프로세스(PID <자식 PID>) 생성
현재 자식 프로세스입니다 / PID : 1
Mount successed!
Spawning /bin/bash :
root@<호스트명>:/<디렉터리명>#
bash───pstree
申し訳ございませんが、この文章には約3週間かかりました.実際、書くこと自体にはあまり時間がかかりませんでした.学校のビデオ編集の仕事と私の怠惰なので、完成が遅いです.これからはあまり時間がかかりません.
次の投稿では、
0
について説明します.ありがとうございます.
Reference
この問題について(独自の仮想化コンテナ#4 PIDネーミングスペースの作成), 我々は、より多くの情報をここで見つけました https://velog.io/@vinto1819/나만의-가상화-컨테이너-만들기-4-PID-네임스페이스テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol