2017-08-08 31 views
0

以下のコードでは、syscall.CLONE_NEWNSでプロセスを開始すると、プロセスが終了すると名前空間内のすべてのマウントオプションがクリアされると考えました。golangマウント名前空間:マウントされたボリュームは、プロセスが終了してもクリアされません。

でもそうですか?

package main 
import (
     "fmt" 
     "os" 
     "os/exec" 
     "syscall" 
) 

var command string = "/usr/bin/bash" 

func container_command() { 

     fmt.Printf("starting container command %s\n", command) 
     cmd := exec.Command(command) 
     cmd.SysProcAttr = &syscall.SysProcAttr{Cloneflags: syscall.CLONE_NEWPID | 
       syscall.CLONE_NEWNS, 
     } 
     cmd.Stdin = os.Stdin 
     cmd.Stdout = os.Stdout 
     cmd.Stderr = os.Stderr 

     if err := cmd.Run(); err != nil { 
       fmt.Println("error", err) 
       os.Exit(1) 
     } 
} 

func main() { 
     fmt.Printf("starting current process %d\n", os.Getpid()) 
     container_command() 
     fmt.Printf("command ended\n") 

} 

これを実行してディレクトリをマウントすると、このディレクトリはプログラムの終了後でも終了します。

[[email protected] go]# go run namespace-1.go 
starting current process 7558 
starting container command /usr/bin/bash 
[[email protected] go]# mount --bind /home /mnt 
[[email protected] go]# ls /mnt 
vagrant 
[[email protected] go]# exit 
exit 
command ended 
[[email protected] go]# ls /mnt 
vagrant 
[[email protected] go]# 

これが望ましい動作であれば、どのようにprocをコンテナ実装にマウントしますか?なぜなら私が名前空間内にprocをマウントすると、私は

[[email protected] go]# mount -t proc /proc 
[[email protected] go]# exit 
exit 
command ended 
[[email protected] go]# mount 
mount: failed to read mtab: No such file or directory 
[[email protected] go]# 

procを取り戻すために再マウントする必要があるからです。

更新: 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 container_stack[STACK_SIZE]; 

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

int container_main(void* arg) 
{ 
     printf("Container [%5d] - inside the container!\n", getpid()); 
      sethostname("container",10); 
      system("mount -t proc proc /proc"); 
      execv(container_args[0], container_args); 
      printf("Something's wrong!\n"); 
      return 1; 
} 

int main() 
{ 
    printf("start a container!\n"); 
    int container_pid = clone(container_main, container_stack+STACK_SIZE, 
      CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL); 
    waitpid(container_pid, NULL, 0); 
    printf("container ended!\n"); 
    return 0; 
} 

コマンドの出力:

[[email protected] ~]# gcc a.c 
[[email protected] ~]# ./a.out 
start a container! 
Container [ 1] - inside the container! 
[[email protected] ~]# ps -ef 
UID  PID PPID C STIME TTY   TIME CMD 
root   1  0 0 08:57 pts/0 00:00:00 /bin/bash 
root  17  1 0 08:57 pts/0 00:00:00 ps -ef 
[[email protected] ~]# exit 
exit 
container stopped! 
[[email protected] ~]# ps -ef 
Error, do this: mount -t proc proc /proc 
[[email protected] ~]# cat a.c 

答えて

1

これは名前空間の間のイベントの伝播をマウントすることにより起こります。マウントポイントの伝播タイプはMS_SHAREDです。

MS_SHARED:このマウントポイントは、「ピアグループ」のメンバである他のマウントポイントとマウントイベントとアンマウントイベントを共有します。マウントポイントがこのマウントポイントで追加または削除されると、この変更はピアグループに伝播され、マウントまたはアンマウントもそれぞれのピアマウントポイントの下で行われます。伝播も逆方向に行われるため、ピアマウントのマウントイベントとアンマウントイベントもこのマウントポイントに伝播します。

ソース - https://lwn.net/Articles/689856/

/proc/self/mountinfoshared:Nタグは、マウントはピアグループに伝播するイベントを共有していることを示しています

ほとんどのLinuxディストリビューションでは
$ sudo go run namespace-1.go 
[[email protected]]# mount --bind /home/andrii/test /mnt 
# The propagation type is MS_SHARED 
[[email protected]]# grep '/mnt' /proc/self/mountinfo 
264 175 254:0 /home/andrii/test /mnt rw,noatime shared:1 - ext4 
/dev/mapper/cryptroot rw,data=ordered 
[[email protected]]# exit 
$ ls /mnt 
test_file 

デフォルトの伝播のタイプがあるMS_SHAREDですsystemdによって設定される。 man 7 mount_namespacesNOTESを参照してください:

新しい マウントポイントのデフォルトの伝播タイプはMS_SHAREDは、通常より 便利ですが、多くの場合MS_PRIVATEであるという事実にもかかわらず。このため、systemd(1)はシステム起動時にすべてのマウント ポイントをMS_SHAREDとして自動的に再マウントします。したがって、現代のほとんどのシステムでは、 のデフォルトの伝播タイプは実際にはMS_SHAREDです。

あなたは完全に分離された名前空間が必要な場合は、すべてのプライベートマウントポイントをこの方法で行うことができます:

$ sudo go run namespace-1.go 
[[email protected]]# mount --make-rprivate/
[[email protected]]# mount --bind /home/andrii/test /mnt 
# The propagation type is MS_PRIVATE now 
[[email protected]]# grep '/mnt' /proc/self/mountinfo 
264 175 254:0 /home/andrii/test /mnt rw,noatime - ext4 
/dev/mapper/cryptroot rw,data=ordered 
[[email protected]]# exit 
$ ls /mnt 
+1

感謝を。記録のために、golangで 'mount --make-private /'を達成するために、マウントフラグは 'syscall.MS_PRIVATE | syscall.MS_REC'です –

関連する問題