Linux 容器在 v2.6.29版本以後就加入到內核之中了, 以前雖然也據說過, 但一直沒有太留心, 一直使用 KVM 來建立虛擬機.
直至最近 Docker 大出風頭, 纔開始關注. 想了解一下 Linux 容器到底是什麼? 與現有虛擬機技術(Xen, KVM等)有什麼區別?html
Linux 容器技術出現的很早, 其實也是一直虛擬化技術, 但彷佛一直沒有 Xen, KVM 這些來的出名.
同時, 在實現原理上, 和Xen, KVM之類的也是有很大區別的.
下面簡單說明下目前4類虛擬技術的區別: (下面說明中, VM:虛擬機, HOST:主機, 即安裝虛擬機的機器)python
傳統的虛擬化技術 (VirtualBox, VMware)
經過在Linux上安裝虛擬化軟件, 而後經過虛擬化軟件來安裝虛擬機系統, 大體結構以下:linux
VM1 VM2 VM3 ... ... |
VirtualBox or VMWare or ... |
Linux Kernel |
硬件 |
VM是由虛擬化軟件(VirtualBox, VMWare…)來管理的, Linux Kernel不能直接管理到各個VM.web
Xen (半虛擬化)
Xen是Linux上歷史比較長的虛擬化技術, 它的虛擬化結構大體以下:c#
Linux Kernel VM1 VM2 VM3 ... ... |
Xen |
硬件 |
Xen的虛擬化原理是在 Linux Kernel和硬件之間加入一層 Xen代碼, 有Xen來管理Linux Kernel和其它的VM.瀏覽器
KVM (最新的虛擬化技術)
相比其它的虛擬化技術, KVM是比較新的, 它須要CPU的支持. 它的虛擬化結構大體以下:bash
VM1 VM2 VM3 ... ... |
KVM (由內核管理) |
Linux Kernel |
硬件 |
這個結構和傳統的虛擬化技術很相似, 有一點不一樣的是, KVM和Linux Kernel是緊密結合的,
因此Linux Kernel可以更好的管理 VMs, VM的性能會比傳統的虛擬化技術更好.網絡
Linux 容器 (LXC - linux container)
LXC 是很是輕量級的, 它將 VM 的進程也假裝成 HOST 的進程. 大體的結構以下:多線程
p1(HOST), p2(VM), p3(VM), p4(HOST)...... |
Linux Kernel |
硬件 |
那麼, 對於某些系統進程, PID是固定的, 好比 init進程的PID=1, VM中的 init進程的PID是如何處理的呢?
原來, VM的 init進程的PID在 HOST的進程表中會顯示成其它PID(>1).app
從上面能夠看出, LXC這種虛擬化, VM的進程就像HOST的進程同樣運行, 管理, 因此建立和銷燬都是很是快速的.
注: 參考 http://veck.logdown.com/posts/200566-compare-of-kvm-and-lxc
Linux容器功能是基於 cgroups 和 Namespace 來實現的. 因此要了解 Linux 容器必須先了解 cgroup 和 Namespace.
cgroups 是將任意進程進行分組化管理的 Linux 內核功能.
經過cgroups能夠有效的隔離各種進程, 同時還能夠控制進程的資源佔用(CPU, 內存等等)狀況.
使用示例: (debian v7.6 x86_64)
mount -t tmpfs cgroup_root /sys/fs/cgroup mkdir /sys/fs/cgroup/test mount -t cgroup -ocpuset test /sys/fs/cgroup/test
此時, test目錄就是一個 cgroup, 這裏 -o 指定了 cpuset, cpuset是Linux中既定的一種cgroup, 後面有時間從新寫博客詳細介紹.
test 目錄有cgroup必須的各個文件
cd /sys/fs/cgroup/test ls -l total 0 -rw-r--r-- 1 root root 0 Aug 14 14:34 cgroup.clone_children --w--w--w- 1 root root 0 Aug 14 14:34 cgroup.event_control -rw-r--r-- 1 root root 0 Aug 14 14:34 cgroup.procs -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.cpu_exclusive -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.cpus -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.mem_exclusive -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.mem_hardwall -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.memory_migrate -r--r--r-- 1 root root 0 Aug 14 14:34 cpuset.memory_pressure -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.memory_pressure_enabled -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.memory_spread_page -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.memory_spread_slab -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.mems -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.sched_load_balance -rw-r--r-- 1 root root 0 Aug 14 14:34 cpuset.sched_relax_domain_level -rw-r--r-- 1 root root 0 Aug 14 14:34 notify_on_release -rw-r--r-- 1 root root 0 Aug 14 14:34 release_agent -rw-r--r-- 1 root root 0 Aug 14 14:34 tasks
其中部分文件介紹.
文件名 | R/W | 用途 |
---|---|---|
release_agent | RW | 刪除分組時執行的命令. 這個文件只存在於根分組 |
notify_on_release | RW | 設置是否執行 release\_agent. 爲1時執行 |
tasks | RW | 屬於分組的線程 TID 列表 |
cgroup.procs | R | 屬於分組的進程 PID 列表. 僅包括多線程進程的線程leader的TID, 這點與 tasks 不一樣 |
cgroup.event_control | RW | 監視狀態變化的分組刪除事件的配置文件 |
在cgroup中還能夠創建子cgroup, 創建的方法很簡單, 只要建立文件夾便可.
cd /sys/fs/cgroup/test mkdir test-child ls -l test-child # 建立了文件夾以後, 自動生成cgroup須要的文件 total 0 -rw-r--r-- 1 root root 0 Aug 14 15:10 cgroup.clone_children --w--w--w- 1 root root 0 Aug 14 15:10 cgroup.event_control -rw-r--r-- 1 root root 0 Aug 14 15:10 cgroup.procs -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.cpu_exclusive -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.cpus -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.mem_exclusive -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.mem_hardwall -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.memory_migrate -r--r--r-- 1 root root 0 Aug 14 15:10 cpuset.memory_pressure -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.memory_spread_page -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.memory_spread_slab -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.mems -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.sched_load_balance -rw-r--r-- 1 root root 0 Aug 14 15:10 cpuset.sched_relax_domain_level -rw-r--r-- 1 root root 0 Aug 14 15:10 notify_on_release -rw-r--r-- 1 root root 0 Aug 14 15:10 tasks
注意, 刪除子cgroup的時候, 要用 rmdir 來刪除文件夾, 用 rm -rf 的方法沒法刪除
cd /sys/fs/cgroup/test rmdir test-child
注: 參考內核文檔 Documentation/cgroups/cgroups.txt
使用Namespace, 可讓每一個進程組有獨立的PID, IPC和網絡空間.
Namespace的生效主要是經過 clone系統調用來實現的.
clone系統調用的第3個參數flags就是經過設置Namespace來劃分資源的.
參數種類以下:
名稱 | 說明 |
---|---|
CLONE_NEWIPC | 劃分IPC(進程間通訊)命名空間, 信號量(semaphore), 共享內存, 消息隊列等進程間通訊用的資源 |
CLONE_NEWNET | 劃分網絡命名空間. 分配網絡接口 |
CLONE_NEWNS | 劃分掛載的命名空間. 與chroot一樣分配新的根文件系統 |
CLONE_NEWPID | 劃分 PID 命名空間. 分配新的進程ID空間 |
CLONE_NEWUTS | 劃分 UTS(Universal Time sharing System)命名空間. 分配新的 UTS 空間 |
安裝 LXC
apt-get install lxc lxc-checkconfig # 安裝完成後, 用這個命令檢查系統是否可使用 lxc # 個人debian系統上有個 missing Cgroup namespace: CONFIG_CGROUP_NSmissing # 對於這個missing, 多是因爲系統中沒有掛載cgroup致使的, 掛載一個cgroup便可 mount -t cgroup cgroup /mnt/cgroup
建立容器
從現有模板建立容器, 比較慢, 須要下載
# 建立一個 debian 系統 lxc-create -n test -t debian
這樣建立的容器默認在 /var/lib/lxc/test 中, 爲了將容器建立在咱們指定的位置, 能夠寫個簡單的配置文件
lxc.conf, 裏面只須要一句
lxc.rootfs = /home/lxc/test
而後,
lxc-create -n test -t debian -f /path/to/lxc.conf
這樣, 就把容器建立在了 /home/lxc/test 中了, /var/lib/lxc/test 中只有一個 config文件(這個config文件能夠做爲 lxc-create 命令 -f 參數對應配置文件的參考)
啓動容器
啓動後就進行入了虛擬機的控制檯了. (果真像傳說同樣, 幾秒就啓動完成了 ^_^)
lxc-start -n test
中止容器
在主機中輸入中止的命令.
lxc-stop -n test
銷燬容器
銷燬以前, 能夠經過 lxc-ls 來查看有幾個容器
lxc-ls test lxc-destroy -n test lxc-ls
注: 參考URL - http://obdnmagazine.blogspot.com/2013/07/tested-lxc-080-rc1-debian-wheezyax3a6.html
嘗試在容器配置一次開發環境, 而後經過複製容器, 造成多個虛擬機.
# 主機中 root@debian-113:~# uliweb # 主機中沒有安裝uliweb 軟件包 -bash: uliweb: command not found root@debian-113:~# lxc-start -n test # 虛擬機登陸界面, 輸入用戶名和密碼 # 虛擬機中 root@test:~# apt-get install python root@test:~# apt-get install python-pip root@test:~# pip install Uliweb root@test:~# uliweb --version Uliweb version is 0.3.1
主機中設置網橋, 虛擬機用橋接方式上網, 確保每一個虛擬機有獨立的IP
# 主機中 root@debian-113:~# lxc-stop -n test root@debian-113:~# apt-cache search bridge-utils root@debian-113:~# brctl addbr br0 # 配置主機的網橋 root@debian-113:/var/lib/lxc/test# cat /etc/network/interfaces # This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). # The loopback network interface auto lo #auto eth0 iface lo inet loopback # 追加的網橋配置 auto br0 iface br0 inet static address 192.168.1.113 netmask 255.255.255.0 gateway 192.168.1.1 bridge_ports eth0 bridge_stp on bridge_fd 0 root@debian-113:/var/lib/lxc/test# /etc/init.d/networking restart
配置容器的網絡(也是在主機中修改容器的配置文件)
root@debian-113:/var/lib/lxc/test# cat /var/lib/lxc/test/config ... ... (不少默認生成的配置) # network <-- 這個 network 相關的是要追加的 lxc.network.type = veth lxc.network.flags = up lxc.network.link = br0 lxc.network.name = eth0
啓動Linux容器, 進入虛擬機
root@debian-113:/var/lib/lxc/test# lxc-start -n test # 登陸進入虛擬機, 確認虛擬機的IP root@test:~# cat /etc/network/interfaces <-- 默認是自動獲取IP auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp root@test:~# ifconfig <-- 個人機器自動分配的 192.168.1.167 # 建立一個簡單的uliweb工程 root@test:~# cd /home/ root@test:/home# mkdir CM-web root@test:/home# cd CM-web/ root@test:/home/CM-web# uliweb makeproject test root@test:/home/CM-web# cd test/ root@test:/home/CM-web/test# uliweb makeapp first_app root@test:/home/CM-web/test# uliweb runserver -h 0.0.0.0
啓動Web服務後, 就能夠在主機的瀏覽器中 經過 http://192.168.1.167:8000/ 來訪問虛擬機中的web服務了.
最後, 複製一個新的容器, 也就是再從新生成一個上面的 python uliweb 開發環境
# 在主機中 root@debian-113:~# cd /var/lib/lxc root@debian-113:/var/lib/lxc# cp -r test test2 # 修改 test2/config 以下 lxc.utsname = test2 <-- 修更名稱 xc.rootfs = /home/lxc/test2 <-- 修改 rootfs位置 ... ... <-- 其它部分不用修改, 和 test 同樣就行 root@debian-113:/var/lib/lxc# cd /home/lxc/ root@debian-113:/home/lxc# cp -r test test2 <-- 從新複製一份 rootfs root@debian-113:/home/lxc# lxc-start -n test2 <-- 啓動 test2 虛擬機, 其中環境和 test同樣, IP會不同, 自動獲取的 # 進入 test2 虛擬機中, 能夠直接啓動以前的 uliweb 測試工程, 也能夠從主機中訪問其web服務.