分享

Linux 容器的使用

 码农书馆 2017-12-22

Linux 容器在 v2.6.29版本之后就加入到内核之中了, 之前虽然也听说过, 但一直没有太留心, 一直使用 KVM 来创建虚拟机.
直至最近 Docker 大出风头, 才开始关注. 想了解一下 Linux 容器究竟是什么? 与现有虚拟机技术(Xen, KVM等)有什么区别?

Linux 容器技术出现的很早, 其实也是一直虚拟化技术, 但似乎一直没有 Xen, KVM 这些来的出名.
同时, 在实现原理上, 和Xen, KVM之类的也是有很大区别的.
下面简单说明下目前4类虚拟技术的区别: (下面说明中, VM:虚拟机, HOST:主机, 即安装虚拟机的机器)

  1. 传统的虚拟化技术 (VirtualBox, VMware)
    通过在Linux上安装虚拟化软件, 然后通过虚拟化软件来安装虚拟机系统, 大致结构如下:

     VM1  VM2 VM3 ... ...                                   
                 VirtualBox or VMWare or ...                
                    Linux Kernel                            
                     硬件                                   

    VM是由虚拟化软件(VirtualBox, VMWare…)来管理的, Linux Kernel不能直接管理到各个VM.

  2. Xen (半虚拟化)
    Xen是Linux上历史比较长的虚拟化技术, 它的虚拟化结构大致如下:

     Linux Kernel  VM1  VM2 VM3 ... ...                     
                     Xen                                    
                     硬件                                   

    Xen的虚拟化原理是在 Linux Kernel和硬件之间加入一层 Xen代码, 有Xen来管理Linux Kernel和其它的VM.

  3. KVM (最新的虚拟化技术)
    相比其它的虚拟化技术, KVM是比较新的, 它需要CPU的支持. 它的虚拟化结构大致如下:

     VM1  VM2 VM3 ... ...                                   
                     KVM (由内核管理)                       
                    Linux Kernel                            
                     硬件                                   

    这个结构和传统的虚拟化技术很类似, 有一点不同的是, KVM和Linux Kernel是紧密结合的,
    所以Linux Kernel能够更好的管理 VMs, VM的性能会比传统的虚拟化技术更好.

  4. 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).

    从上面可以看出, LXC这种虚拟化, VM的进程就像HOST的进程一样运行, 管理, 所以创建和销毁都是非常快速的.

: 参考 http://veck./posts/200566-compare-of-kvm-and-lxc

Linux 容器相关的2个重要概念

Linux容器功能是基于 cgroups 和 Namespace 来实现的. 所以要了解 Linux 容器必须先了解 cgroup 和 Namespace.

cgroups

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_agentRW删除分组时执行的命令. 这个文件只存在于根分组
notify_on_releaseRW设置是否执行 release\_agent. 为1时执行
tasksRW属于分组的线程 TID 列表
cgroup.procsR属于分组的进程 PID 列表. 仅包括多线程进程的线程leader的TID, 这点与 tasks 不同
cgroup.event_controlRW监视状态变化的分组删除事件的配置文件

在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 (命名空间)

使用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 空间

Linux 容器的使用方法 (以下命令基于 debian v7.5)

  1. 安装 LXC

    apt-get install lxc
    lxc-checkconfig   # 安装完成后, 用这个命令检查系统是否可以使用 lxc
    # 我的debian系统上有个 missing
    Cgroup namespace: CONFIG_CGROUP_NSmissing
    # 对于这个missing, 可能是由于系统中没有挂载cgroup导致的, 挂载一个cgroup即可
    mount -t cgroup cgroup /mnt/cgroup
  2. 创建容器
    从现有模板创建容器, 比较慢, 需要下载

    # 创建一个 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 参数对应配置文件的参考)

  3. 启动容器
    启动后就进行入了虚拟机的控制台了. (果然像传说一样, 几秒就启动完成了 ^_^)

    lxc-start -n test
  4. 停止容器
    在主机中输入停止的命令.

    lxc-stop -n test
  5. 销毁容器
    销毁之前, 可以通过 lxc-ls 来查看有几个容器

    lxc-ls
      test
    lxc-destroy -n test
    lxc-ls

: 参考URL - http://obdnmagazine./2013/07/tested-lxc-080-rc1-debian-wheezyax3a6.html

容器示例 - 配置python uliweb 开发环境

尝试在容器配置一次开发环境, 然后通过复制容器, 形成多个虚拟机.

# 主机中
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服务.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多