本文將演示如何利用namespace建立一個完整的容器,並在裏面運行busybox。若是對namespace不是很熟悉,請先參考前面幾遍介紹不一樣類型namespace的文章。node
busybox是一個Linux下的可執行程序,採用靜態連接,不依賴於其餘任何動態庫。他裏面實現了一些Linux下經常使用的命令,如ls,hostname,date,ps,mount等等,詳細的介紹請參考它的官網。docker
本篇全部例子都在ubuntu-server-x86_64 16.04下執行經過shell
#建立一個單獨的目錄,後續全部的操做都在該目錄下進行,目錄名稱無特殊要求 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