Linux Namespace系列(09):利用Namespace建立一個簡單可用的容器

本文將演示如何利用namespace建立一個完整的容器,並在裏面運行busybox。若是對namespace不是很熟悉,請先參考前面幾遍介紹不一樣類型namespace的文章。node

busybox是一個Linux下的可執行程序,採用靜態連接,不依賴於其餘任何動態庫。他裏面實現了一些Linux下經常使用的命令,如ls,hostname,date,ps,mount等等,詳細的介紹請參考它的官網docker

本篇全部例子都在ubuntu-server-x86_64 16.04下執行經過shell

準備container的根目錄

#建立一個單獨的目錄,後續全部的操做都在該目錄下進行,目錄名稱無特殊要求
dev@ubuntu:~$ mkdir chroot && cd chroot
#下載編譯好的busybox可執行文件
dev@ubuntu:~/chroot$ wget https://busybox.net/downloads/binaries/1.21.1/busybox-x86_64
#建立new_root/bin目錄,new_root將會是新容器的根目錄,bin目錄用來放busybox
#因爲/bin默認就在PATH中,因此裏面放的程序均可以直接在shell裏面執行,不須要帶完整的路徑
dev@ubuntu:~/chroot$ mkdir -p new_root/bin
dev@ubuntu:~/chroot$ chmod +x ./busybox-x86_64

#將busybox-x86_64移到bin目錄下,並重命名爲busybox
dev@ubuntu:~/chroot$ mv busybox-x86_64 new_root/bin/busybox
#運行ls試試,確保busybox能正常工做
dev@ubuntu:~/chroot$ ./new_root/bin/busybox ls
new_root

#安裝busybox到bin目錄,不安裝的話每次執行ls命令都須要使用上面那種格式: busybox ls
#安裝以後就會建立一個ls到busybox的硬連接,這樣執行ls的時候就不用再輸入前面的busybox了
dev@ubuntu:~/chroot$ ./new_root/bin/busybox --install ./new_root/bin/

#運行下bin下面的ls,確保安裝成功
dev@ubuntu:~/chroot$ ls -l ./new_root/bin/ls
-rwxrwxr-x 348 dev dev 973200 7月   9  2013 ./new_root/bin/ls
dev@ubuntu:~/chroot$ ./new_root/bin/ls
new_root

#使用chroot命令,切換根目錄
dev@ubuntu:~/chroot$ sudo chroot ./new_root/ sh

#切換成功,因爲new_root下面只有busybox,沒有任何配置文件,
#因此shell的提示符裏只包含當前目錄
#嘗試運行幾個命令,一切正常
/ # ls
bin
/ # which ls
/bin/ls
/ # hostname
ubuntu
/ # id
uid=0 gid=0 groups=0
/ # exit
dev@ubuntu:~/chroot$

建立容器並作相關配置

#新建/data目錄用來在主機和容器之間共享數據
dev@ubuntu:~/chroot$ sudo mkdir /data
dev@ubuntu:~/chroot$ sudo chown dev:dev /data
dev@ubuntu:~/chroot$ touch /data/001

#建立新的容器,指定全部namespace相關的參數,
#這裏--propagation private是爲了讓容器裏的mount point都變成private的,
#這是由於pivot_root命令須要原來根目錄的掛載點爲private,
#只有咱們須要在host和container之間共享掛載信息的時候,才須要使用shared或者slave類型
dev@ubuntu:~/chroot$ unshare --user --mount --ipc --pid --net --uts -r --fork --propagation private bash
#設置容器的主機名
root@ubuntu:~/chroot# hostname container01
root@ubuntu:~/chroot# exec bash

#建立old_root用於pivot_root命令,建立data目錄用於綁定/data目錄
root@container01:~/chroot# mkdir -p ./new_root/old_root/ ./new_root/data/

#因爲pivot_root命令要求老的根目錄和新的根目錄不能在同一個掛載點下,
#因此這裏利用bind mount,在原地建立一個新的掛載點
root@container01:~/chroot# mount --bind ./new_root/ ./new_root/

#將/data目錄綁定到new_root/data,這樣pivot_root後,就能訪問/data下的東西了
root@container01:~/chroot# mount --bind /data ./new_root/data

#進入new_root目錄,而後切換根目錄
root@container01:~/chroot# cd new_root/
root@container01:~/chroot/new_root# pivot_root ./ ./old_root/

#但shell提示符裏顯示的當前目錄仍是原來的目錄,沒有切換到‘/’下,
#這是由於當前運行的shell仍是host裏面的bash
root@container01:~/chroot/new_root# ls
bin  data  old_root

#從新加載new_root下面的shell,這樣contianer和host就沒有關係了,
#從shell提示符中能夠看出,當前目錄已經變成了‘/’
root@container01:~/chroot/new_root# exec sh
/ # 
#因爲沒有/etc目錄,也就沒有相關的profile,因而shell的提示符裏面只包含當前路徑。

#設置PS1環境變量,讓shell提示符好看點,這裏直接寫了root在提示符裏面,
#是由於咱們新的container裏面沒有帳號相關的配置文件,
#雖然系統知道當前帳號的ID是0,但不知道帳號的用戶名是什麼。
/ # export PS1='root@$(hostname):$(pwd)# '
root@container01:/# 

#沒有/etc目錄,沒有user相關的配置文件,因此不知道ID爲0的用戶名是什麼
root@container01:/# whoami
whoami: unknown uid 0

#mount命令依賴於/proc目錄,因此這裏mount操做失敗
root@container01:/# mount
mount: no /proc/mounts

#從新mount /proc
root@container01:/# mkdir /proc
root@container01:/# mount -t proc none /proc

#這時能夠看到全部的mount信息了,從host複製過來的mount信息都掛載在/old_root目錄下
root@container01:/# mount
/dev/mapper/ubuntu--vg-root on /old_root type ext4 (rw,relatime,errors=remount-ro,data=ordered)
udev on /old_root/dev type devtmpfs (rw,nosuid,relatime,size=1005080k,nr_inodes=251270,mode=755)
devpts on /old_root/dev/pts type devpts (rw,nosuid,noexec,relatime,mode=600,ptmxmode=000)
tmpfs on /old_root/dev/shm type tmpfs (rw,nosuid,nodev)
......
/dev/mapper/ubuntu--vg-root on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/mapper/ubuntu--vg-root on /data type ext4 (rw,relatime,errors=remount-ro,data=ordered)
none on /proc type proc (rw,nodev,relatime)

#umount掉/old_root下的全部mount point
root@container01:/# umount -l /old_root
#這時候就只剩下根目錄,/proc,/data三個掛載點了
root@container01:/# mount
/dev/mapper/ubuntu--vg-root on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/mapper/ubuntu--vg-root on /data type ext4 (rw,relatime,errors=remount-ro,data=ordered)
none on /proc type proc (rw,nodev,relatime)

#試試cd命令,提示失敗, $HOME仍是指向老的/home/dev,
#除了$HOME以外,還有其餘一些環境變量也有一樣的問題。
#這主要是因爲咱們新的container中缺乏配置文件,致使不少環境變量沒有更新。
root@container01:/# cd
sh: cd: can not cd to /home/dev

#試試ps,顯示的是container裏面啓動的進程
root@container01:/# ps
PID   USER     TIME   COMMAND
    1 0          0:00 sh
   55 0          0:00 ps

#touch文件001成功
root@container01:/# touch /data/001
#新建立一個002文件
root@container01:/# touch /data/002
root@container01:/# ls /data
001  002

#退出contianer01,在/data目錄能看到咱們上面在container01種建立的002文件
root@container01:/# exit
dev@ubuntu:~/chroot$ ls /data
001  002

結束語

本文利用busybox和pivot_root演示瞭如何建立一個簡單的容器,而且實現了在host和container之間共享文件夾。這個容器的功能很是簡單,不少目錄都沒有構建,致使只能運行busybox裏面的部分命令,有些命令運行時會有異常。要想構造一個完整易用的容器,還須要不少工做要作,這裏只演示了冰山一角,在後續的「docker系列」中,將深刻分析docker是如何一步一步幫助咱們構建安全易用的contianer的,敬請期待。ubuntu

參考

相關文章
相關標籤/搜索