[原创] 移植LXC容器到高通MDM9607设备上的测试过程
1 沙盒介绍
沙盒是用来隔离运行中程序的一种安全机制,通常是为了缓解系统的故障或者软件缺陷的传递。比如可以用来执行未测试或者不信任的程序/代码,这样就可以把对操作系统的危害隔离开来。从提供一个高度控制环境角度来说,可以把沙盒看作是一种虚拟化的特殊例子。沙盒的实现方式有很多实现,如:
- 类似jail,主要实现网络访问控制, 文件系统命名空间限制。
- 虚拟机来仿真一个完整的主机,在虚拟机上常规的操作系统可以从真实的硬件上启动和运行。
- seccomp是linux内核自带的一个沙盒。如果启用 seccomp 将只允许调用 write(), read(), exit(), sigreturn() 系统调用。
- 还有很多其他实现具体可以参考
维基百科上的介绍
2 沙盒选型
本次基于虚拟化来实现沙盒机制,可供选择的项目有下面这些:
具体可以参考维基百科上的介绍
下面简要介绍一些项目:
2.1 chroot
可以改变当前运行进程和他的子进程显示的目录。运行在这个环境的程序只能访问它自己的目录,不能访问外面的目录。但是他的功能很简单,如上图所示,除了对文件系统的部分隔离之外,其他的特性都是不能用的(红色)。
2.2 docker
是Docker公司开发的的一个软件容器,可以运行在多种操作系统上,linux/MAC/windows等。它是操作系统层级的虚拟化,在操作系统层提供了抽象和自动化的一个虚拟化。Docker功能很丰富如上图所示,很多特性可用(绿色)。Docker很强大被集成到很多商业的基础工具中比如:
Amazon Web Services, Ansible,CFEngine,Chef,Google Cloud Platform, IBM Bluemix,HPE Helion Stackato, Jelastic,Jenkins,Kubernetes,Microsoft Azure,OpenStack Nova,OpenSVC,Oracle Container Cloud Service,Puppet,Salt,Vagrant,and VMware vSphere Integrated Containers.
2.3 LXC
LXC是Linux containers的简称,是一种基于容器的操作系统层级的虚拟化技术。LXC功能很丰富如上图所示,很多特性可用(绿色)。LXC是利用Linux内核安全特性而设计的一个用户层接口,他是一个完全开源的项目。通过提供强大的API接口和一些简单的工具,它使linux用户很容易创建和管理系统/应用级的容器。lxc有这些特点:
- 虚拟化开销小(LXC的诸多特性基本由内核提供,而内核实现这些特性只有极少的花费)。
- 快速部署。利用LXC来隔离特定应用,只需要安装LXC,即可使用LXC相关命令来创建并启动容器来为应用提供虚拟执行环境。传统的虚拟化技术则需要先创建虚拟机,然后安装系统,再部署应用。
具体介绍可以参考官网
2.4 方案确定
根据chroot,docker,lxc技术特点,功能,开发难度,最终选择lxc容器作为沙盒进行移植开发(Chroot太简单,docker又比较复杂。LXC开发难度适中,系统开销低等,功能基本能满足安全需求)。
3 lxc开发介绍
开发调试环境
1)硬件使用搭载高通MDM9607 MCU的设备
2)交叉编译工具:oecore-x86_64-armv7a-vfp-neon-toolchain-nodistro.0.sh
Lxc包含内核层和用户层(用户层包括工具和库)。在用户层工具可以直接通过命令行来实现容器,也可以使用对应的库自己编码对容器相关操作进行使用(提供了函数调用接口)。
3.1 内核配置
LXC需要内核一些模块的支持,需要把相关的内核选型选上,具体可以参考
官网man手册
- 内核版本要求:Linux kernel >= 2.6.32
$bitbake -c menuconfig linux-quic
image.png
Control Group support
全部选上
image.png
Checkpoint/restore support
选上
image.png
Namespaces support
全部选上
image.png
Support multiple instances of devpts
选上
image.png
MAC-VLAN support
Virtual ethernet pair device
选上
image.png
802.1d Ethernet Bridging
选上
- 我在我的编译环境下只能通过下面的方式才能编译成功,其他方法试过都不行。完成相关操作之后把.config保存起来,比如我这边是
$cp apps_proc/poky/build/tmp-glibc/work/mdm9607-oe-linux-gnueabi/linux-quic/git-r5/build/.config ~/.
$bitbake linux-quic -c cleanall
$cp ~/.config kernel/msm-3.18/arch/arm/configs/L170YX_defconfig
$./buildL170YXSHIP app
3.2 lxc源码库编译
重新开一个终端,不然和之前bitbake的编译环境会有冲突。
Lxc项目最新的源码可以到https://github.com/lxc/lxc下载
1)下载源码:
$git clone https://github.com/lxc/lxc.git
2)配置交叉编译的环境,我的是:
$source ~/local/environment-setup-armv7a-vfp-neon-oe-linux-gnueabi
3)配置编译
我的编译目录是/home/zgk/lxc/lxc
$cd /home/zgk/lxc/lxc
$make maintainer-clean
$./autogen.sh
$./configure --prefix=/home/zgk/lxc/test --host=arm-oe-linux-gnueabi --target=arm-oe-linux-gnueabi --build=x86_64-linux
$make
$sudo make install
备注:
- configure的命令行变量--prefix指定最终编译结果的输出,需要指定一下方便打包下载到设备;--host指定编译后的源码运行的环境;--target目标类型;--build编译的环境。
- Git直接clone现在下载下来的是stable-2.1的分支版本,我有checkout到stable-1.1分支版本进行编译并下载到设备上进行测试无法测试成功,从出错结果查看可能是我们交叉编译环境配置参数有些问题不适合该版本,有尝试调整了一些编译参数,无果最终放弃测试。
4)编译结果打包
$tar cf test.tar test
3.3 设备上环境配置
把编译好的内核镜像mdm9607-boot.img烧录到设备上之后。可以对设备使用容器环境进行配置。
1)安装路径配置
我在主机编译环境中是把相关的编译结果放在/home/zgk/lxc/test位置。如果你使用lxc工具默认配置的话最好,也把test.tar放到该目录下。
#mkdir -p /home/zgk/lxc
#adb push test.tar /home/zkg/lxc
#tar xf test.tar
结果会自动解压到test目录
- 备注:如果根目录被挂载成只读的,需要重新挂载为可读写的,才能在上面操作
#mount -o rw,remount /
2)配置环境变量
增加动态库搜索路径和可执行程序的搜索路径
#export LD_LIBRARY_PATH=/home/zgk/lxc/test/lib:$LD_LIBRARY_PATH
#export PATH=/home/zgk/lxc/test/bin:$PATH
3)为容器配置网络
我这边是根据现有设备环境直接进行配置,仅提供一个参考
#ifconfig lo up
#ifconfig rndis0 0.0.0.0
#ifconfig bridge0 172.16.90.184
#brctl setfd bridge0 0
#route add default gw 172.16.90.1 bridge0
4)cgroup节点挂载
#mkdir -p /cgroup
#mount -t cgroup cgroup /cgroup
5)检查容器的环境
看是否已经配置好了
#lxc-checkconfig
输出无红色的说明容器运行基本环境已经配置好了,下面是我这边配置完检查的结果:
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: enabled
newuidmap is not installed
newgidmap is not installed
Network namespace: enabled
Multiple /dev/pts instances: enabled
--- Control groups ---
Cgroups: enabled
Cgroup v1 mount points:
/cgroup
Cgroup v2 mount points:
Cgroup v1 systemd controller: /home/zgk/lxc/test/bin/lxc-checkconfig: line 158: printf \033[1;31m: not found
Cgroup v1 freezer controller: /home/zgk/lxc/test/bin/lxc-checkconfig: line 165: printf \033[1;31m: not found
Cgroup v1 clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
--- Misc ---
Veth pair device: enabled, not loaded
Macvlan: enabled, not loaded
Vlan: missing
Bridges: enabled, not loaded
Advanced netfilter: enabled, not loaded
CONFIG_NF_NAT_IPV4: enabled, not loaded
CONFIG_NF_NAT_IPV6: missing
CONFIG_IP_NF_TARGET_MASQUERADE: enabled, not loaded
CONFIG_IP6_NF_TARGET_MASQUERADE: missing
CONFIG_NETFILTER_XT_TARGET_CHECKSUM: missingCONFIG_NETFILTER_XT_MATCH_COMMENT: missing
FUSE (for use with lxcfs): missing
--- Checkpoint/Restore ---
checkpoint restore: enabled
CONFIG_FHANDLE: missing
CONFIG_EVENTFD: enabled
CONFIG_EPOLL: enabled
CONFIG_UNIX_DIAG: missing
CONFIG_INET_DIAG: enabled
CONFIG_PACKET_DIAG: missing
3.4 容器使用简介
安装完之后设备的/home/zgk/lxc/test/bin目录有下面工具可以使用:
lxc-attach
lxc-copy
lxc-ls
lxc-unshare
lxc-autostart
lxc-create
lxc-monitor
lxc-update-config
lxc-cgroup
lxc-destroy
lxc-snapshot
lxc-usernsexec
lxc-checkconfig
lxc-device
lxc-start
lxc-wait
lxc-checkpoint
lxc-execute
lxc-stop
lxc-config
lxc-freeze
lxc-top
lxc-console
lxc-info
lxc-unfreeze
工具的使用可以参考https://linuxcontainers.org/lxc/manpages/
1)创建容器
#lxc-create -n foo -f ./lxc.conf -t none
-n指定容器的名字
-f指定容器的配置文件,不指定的话就会使用默认的配置
-t指定使用什么模板,我这里不使用模板
我这里的配置文件lxc.conf内容如下:
lxc.uts.name = virtfoo
lxc.net.0.type = veth
lxc.net.0.flags = up
lxc.net.0.link = bridge0
lxc.net.0.ipv4.address = 172.16.90.20/24
lxc.net.0.name = rndis0
lxc.rootfs.path = /
lxc.rootfs.path指定容器根文件系统的目录,不指定的话和操作系统是共享根目录的,我这里只是测试就把它设成和操作系统是同一的,如果实际要安全考虑需要指定容器自己的根文件系统的目录。容器里面的程序只能访问该指定目录下的文件,之外的无法访问。
2)启动容器
#lxc-start -n foo
3)在容器中运行自己的程序
我这边自己写了个测试程序hello。
#lxc-attach -n foo ./hello
4)查询容器的状态
#lxc-info -n foo
5)停止容器
#lxc-stop -n foo
6)销毁容器
#lxc-destroy -n foo
7)通过API接口进行调用
- lxccontainer.h里面定义了提供给C语言调用的API接口。在我的环境下是在目录/home/zgk/lxc/test/include/lxc/
- 具体的实现在目录/home/zgk/lxc/test/lib/下,有静态库和动态库看开发需要进行选择liblxc.so/liblxc.la
- 样例代码可以参考官网https://linuxcontainers.org/lxc/documentation
参考文献
[1] https://en.wikipedia.org/wiki/Operating-system-level_virtualization#IMPLEMENTATIONS
[2] https://en.wikipedia.org/wiki/Seccomp
[3] https://en.wikipedia.org/wiki/Chroot
[4] https://www.ibm.com/developerworks/linux/library/l-lxc-containers/
[5] http://www.linuxcertif.com/man/7/lxc/
[6] http://www.cnblogs.com/lisperl/tag/%E8%99%9A%E6%8B%9F%E5%8C%96%E6%8A%80%E6%9C%AF/
[7] https://www.ibm.com/developerworks/cn/linux/l-lxc-containers/
[8] https://www.ibm.com/developerworks/cn/linux/theme/virtualization/
[9] https://github.com/lxc/lxc