最佳虛擬容器LXC
和"真正的虛擬機環境"不同, "容器"(container)只能在Linux上虛擬Linux, 不能虛擬WIndows, 因為它不能虛擬硬件. 但是基於容器的虛擬機占用的資源很小--在一台中等的Linux服務器上, 創建幾百個虛擬機是輕而易舉的事情. 這種"容器"虛擬化技術, 又稱為OS-Level虛擬化,也就是"操作系統級虛擬化".
LXC(ontainer)是Linux內核支持的技術, 這個好處就會安全性. 管理LXC容器的方式又兩種:一種是使用Libvirt工具來管理,一種是使用lxc本身提供的工具管理. 兩者各有優劣: 前者使用方便, 但是缺乏Apparmor保護,不安全; 后者使用性不夠友好, 但是默認帶了Apparmor規則,可以保證安全性.
安裝LXC
使用apt命令就可以安裝lxc
# sudo apt install lxc
基本用法
LXC可以創建兩種不同的容器:
- 特權模式--以root身份運行各種lxc命令,創建特權容器;
- 普通模式--以普通用戶身份運行各種lxc命令,創建非特權容器
普通容器又很多限制(比如無法創建設備節點),不過也更安全(不會危害到主機),因為這種容器的root用戶,其實映射到主機上的一個普通用戶
特權模式基本用法
創建容器可以使用交互式和非交互式
交互式創建容器
# sudo lxc-create -t download --name ubuntu1
下面是輸出信息
Setting up the GPG keyring
Downloading the image index <-下載所有支持的Linux發行版列表
---
DIST RELEASE ARCH VARIANT BUILD
ubuntu xenial amd64 default 20171214_04:09
[...]
alpine 3.4 amd64 default 20171213_17:50
[...]
centos 6 amd64 default 20171214_02:16
[...]
debian buster amd64 default 20171214_04:09
[...]
---
Distribution: ubuntu <- 這里需要輸入操作系統(上面列表中的),我們選擇ubuntu
Release: xenial <- 選擇操作系統發行版本(上面列表中有的)
Architecture: amd64 <- 選擇架構,這里選擇64位
Downloading the image index
Downloading the rootfs
Downloading the metadata
The image cache is now ready
Unpacking the rootfs
---
You just created an Ubuntu container (release=xenial, arch=amd64, variant=default)
For security reason, container images ship without user accounts
and without a root password.
Use lxc-attach or chroot directly into the rootfs to set a root password
or create user accounts.
上面就是交互式創建容器的方式,創建出來的容器是沒有用戶的,需要使用lxc-attach或者chroot命令來設置,這個后面介紹.
非交互式創建
# sudo lxc-create -t download --name ubuntu2 -- \
--dist ubuntu -release xenial --arch amd64
非交互創建其實就是一次性將操作傳遞給模板而已,下面我們介紹一個各個參數:
- -t 模板: -t 選項后面跟的是模板,模式可以認為是一個原型,用來說明我們需要一個什么樣的容器(比如容器里面需不需要有vim, apache等軟件).模板實際上就是一個腳本文件(位於/usr/share/lxc/templates目錄),我們這里指定download模板(lxc-create會調用lxc-download腳本,該腳本位於剛說的模板目錄中)是說明我們目前沒有自己模板,需要下載官方的模板
- --name 容器名稱: 為創建的容器命名
- -- : --用來說明后面的參數是傳遞給download腳本的,告訴腳本需要下載什么樣的模板
- --dist 操作系統名稱:指定操作系統
- --release 操作系統: 指定操作系統,可以是各種Linux的變種
- --arch 架構: 指定架構,是x86還是arm,是32位還是64位
列出現有容器
簡單列出
# sudo lxc-ls
詳細列出
# sudo lxc-ls --fancy
查看容器信息
# sudo lxc-info --name ubuntu1
啟動和關閉容器
# sudo lxc-start --name ubuntu1
以服務的形式啟動容器
# sudo lxc-start --name ubuntu1 --daemon
# sudo lxc-stop --name ubuntu1
進入容器
進入容器的方式又三種:
- 用lxc-attach命令
- 用lxc-console命令
- 用SSH
進入容器
# sudo lxc-attach --name ubuntu1
讓容器執行某個命令(重啟ssh服務)
# sudo lxc-attach --name ubuntu1 -- restart ssh
提升特權,並指定名字空間,這個命令在測試主機上軟件時很有用
# sudo lxc-attach -name ubuntu1 -e -s 'NETWORK|UTSNAME'
登錄容器,需要輸入用戶名和密碼
# sodu lxc-consloe --name ubuntu1
使用SSH登錄
# ssh 用戶名@IP
容器的刪除
先停掉容器然后進行刪除
# sudo lxc-stop --name ubuntu1
# sudo lxc-destroy --name ubuntu1
非特權模式
通過非特權模式,普通用戶也可以創建和管理容器,而不需要root用戶權限.
用戶命名空間
這種非特權模式的實現使用了一種叫做"用戶命名空間(user namespace)"的特性.用戶命名空間是Linux下眾多命名空間(Linux namespace)之一.Linux下一個用戶本來有且只有一個uid和gid(可以通過id命令查看用戶的id).這個用戶命名空間特性可以允許一個普通用戶使用多個從屬uid和gid(用戶編號和組編號).擁有多個從屬uid和gid的意義在於做id映射,即將容器里面的用戶映射到外部的普通用戶上來.可以通過查看/ect/subuid和/etc/subgid來查看每個用戶的可以使用的從屬ID范圍.
從圖1可以看出用戶hdy的id為1000,其從屬id為圖二所示,每個用戶名后面就是該用戶可以使用的id范圍(起始id和可用id個數,中間用冒號隔開)
默認情況下,主機上的每個任務都是運行在初始用戶命名空間里面的.在初始用戶命名空間里,所有的id都是映射到整個id范圍的(也就是沒有做id映射).可以通過查看/proc/self/uid_map和/proc/self/uid_map查看映射信息.
在非特權容器中,lxc會使用uidmap軟件包提供的newuidmap和newgidmap程序來進行id映射.登入容器后,查看上面的兩個文件可以映射情況.
創建默認的配置文件
在允許普通普通用戶創建普通容器之前,需要做一些配置設置.
要讓普通用戶hdy能夠創建容器
# mkdir -p ~/.config/lxc
# touch .config/lxc/default.conf
執行完上面命令后,需要在default.conf文件中添加以下內容
# uid映射, 填寫用戶hdy的從屬id(/etc/subuid)
lxc.id_map = u 0 10000 65536
# gid映射, 填寫用戶hdy的從屬id(/etc/subgid)
lxc.id_map = g 0 10000 65536
# 定義網絡類型
lxc.network.type = veth
# 定義網絡接口,lxcbr0是lxc包虛擬出的網卡,可以通過ifconfig查看
lxc.network.link = lxcbr0
在/etc/lxc/lxc-usernet文件中添加以下內容:
# 用戶名 網絡類型 橋接到的網絡接口 允許普通用戶創建的網絡接口數量
hdy vneth lxcbr0 2
該文件是lxc用來管理非特權用戶網絡的.當普通用戶創建網絡接口時,lxc使用該文件的配置進行管理和控制.
創建非特權容器
前面配置完成后可以用普通用戶hdy創建容器了
創建容器
hdy@hdy-pc:~$ lxc-create -t download -name ubuntu2 -- -dist ubuntu -release xenial -arch amd64
開放權限,不然無法啟動容器
hdy@hdy-pc: chmod o+x -R ~/.local
啟動,進入,停止和刪除容器都不需要sudo
全局配置文件
- 對於特權容器,配置文件位於/etc/lxc
- 對於普通容器而言,配置文件位於~/.config/lxc下
- 以root身份創建的特權容器都位於/var/lbi/lxc下
- 普通用戶創建的容器在~/.local/share/lxc目錄下
克隆LXC容器
在大規模部署的情況下,我們一般不會逐個去手動的創建容器,而是搞好一個后直接克隆.
拷貝和快照
"克隆"要么是其他容器的一份拷貝,要么是其他容器的一份快照
拷貝:完整的復制原來的容器,所占的空間和原來的容器一樣大
快照:利用后台文件系統的快照功能,創建一個很小的新容器,在發生寫操作時才進行復制
要想使快照擁有這個寫時復制的特性,需要一個特殊存儲系統,支持快照的存儲方式有:aufs,btrfs,LVM,overlayfs,zfs等.每種存儲方式各有自己特點,這里不進一步說明
創建拷貝和快照
同過lxc-clone命令可以創建拷貝和快照,在創建之前需要停止容器
$ sudo lxc-stop --name ubuntu1
創建一個名為clone_ubuntu1的克隆
$ sudo lxc-copy -n ubuntu1 -N clone_ubuntu1
創建一個名為snapshot_ubuntu1的快照
$ sudo lxc-clone -s -n ubuntu1 -N snapshot_ubuntu1
lxc專門創建快照的快捷命令lxc-snapshot
該命令創建的快照位於/var/lib/lxc/容器名(如果是為普通容器創建快照,則位於~/.local/share/lxc/容器名)目錄下,快照名字為snap0,snap1...依次編號
創建快照,實際上是克隆
$ sudo lxc-snapshot -n ubuntu1
創建快照
$ sudo lxc-copy -s -n ubuntu1 -N snapshot_ubuntu1
$ sudo lxc-snapshot -n snapshot_ubuntu1
使用lxc-snapshot創建快照時需要創建aufs/overlayfs文件系統,所以先通過lxc-copy命令創建一個快照,同時會自動為該快照創建文件系統overlayfs.然后我們給新創建的快照snapshot_ubuntu1(容器)創建快照.也就是說現在有三個容器--ubuntu1,snapshot_ubuntu1,snap0.而容器snapshot_ubuntu1是ubunt1的快照,容器snap0是snapshot_ubuntu1的快照.snap0是lxc_snapshot創建的.snapshot_ubuntu1位於/var/lib/lxc目錄下,snap0位於/var/lib/lxc/snapshot_ubuntu1/snaps目錄下
假如我們在ubuntu1上做了一些誤操作,這時想通過快照將ubuntu1恢復過來,可以這樣實現.首先恢復一個容器的操作實際上是先將這個容器刪除掉,然后根據快照創建一個同名的容器.但是在打快照的時候會依賴於overlayfs文件系統的,而overlayfs會依賴於原始容器(ubuntu1)的rootfs.如果將ubuntu1刪除掉,那么rootfs將會被刪除,進而overlayfs會被破快掉,導致無法通過快照創建創建容器.這里只能采用迂回的方式,通過快照創建一個新的容器.
通過快照創建一個新的容器ubuntu2
$ sudo lxc-snapshot -r snap0 -n ubunt1 -N ubuntu2
LXC網絡
在默認的情況下,LXC會為每個容器創建一個專用的網絡命名空間,包括一個二層的網絡協議棧.LXC啟動的時候會創建一個叫做lxcbr0的橋接設備,使用默認設置創建的容器都會有一個vethxxx虛擬網卡(每個容器都有一個虛擬網卡與之綁定),這個網卡會被橋接lxcbr0上.
使用固定IP
默認情況下,容器的IP地址是動態分配的.如果要給容器設置固定IP地址,可以修改容器的配置文件.這里以修改普通容器的配置文件為例.
編輯文件
$ vim ~/.local/share/lxc/ubuntu1/config
添加固定ip
...
lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.ipv4 = 10.0.3.102
...
讓外界可以訪問容器
在默認情況下,容器只能被宿主主機訪問,外界是訪問不到容器的(默認NAT方式).如果想讓容器像普通服務器被外界訪問到,就需要使用橋接宿主主機eth0(或其他物理網卡)的設備
注意:只有特權容器才能被外界訪問,普通容器是無法被外界訪問的
創建橋接設備br0
在宿主主機上安裝橋接工具包
$ sudo apt install bridge-utils
在宿主服務器上,修改/etc/network/interfaces,創建br0橋設備
[...]
auto enp4s0f2 物理網卡
iface enp4s0f2 inet manual
auto br0
iface br0 inet dhcp
address 192.168.1.10 網橋IP地址
netmask 255.255.255.0 掩碼
gateway 192.168.1.1
dns-nameserver 114.114.114.114 8.8.8.8
bridge_ports enp4s0f2 #將物理網卡添加到虛擬網橋中
bridge_stp off
bridge_maxwait 0
bridge_fd 0
[...]
上面的配置主要是創建了一個網橋,而物理網卡enp4s0f2可以看做網橋的一個端口,然后關閉網卡,啟動網橋
$ sudo ifdown enp4s0f2 && sudo ifup br0
接下來停掉容器(這里以ubuntu1為列),修改其配置文件
$ sudo lxc-stop -n ubuntu1
$ vim /var/lib/lxc/ubuntu1/config
修改以下內容,容器橋接到br0上
lxc.network.link = br0
然后為容器配置固定IP
$ vim /var/lib/lxc/ubuntu1/rootfs/etc/network/interfaces
...
auto eth0
iface eth0 inet static
address 192.168.1.239
netmask 255.255.255.0
gateway 192.168.1.1
dns-nameserver 8.8.8.8 如果無法解析域名,則需要設置下