经过一段时间对lxc容器部署的实践和理解,阶段性总结如下:
对于arm,按LXC提供工具的正常的流程:
checkconfig:配置内核,使lxc-checconfig的所有项变绿色。(其实lxc-checkconfig只是一个对内核.config压缩包进行检查的脚本)
create:使用template,从模板的发行版(如alpine,ubuntu)的官网镜像源下载对应的rooft,放到/var或者/usr/local/var目录;
start:将rootfs mount到/usr/local/lib目录,建立必要的网络服务(因此在此之前先建立虚拟网桥服务);
对于csky:
checkconfig:因为rootfs里没有包含congfig.gz文件,可以手动打包然后运行lxc-checkconfig检查;
create:因为生态问题,目前发行版的镜像源还不支持arch=csky,因此需要手动将rootfs和config放置到指定目录,然后通过lxc-ls确认;
start:基本和arm一致,会碰到因为工具链和rootfs支持不完善导致的问题,具体见下面的详细笔记;
========== 详细笔记 =========
1.
LXC
容器
部署(
imx6
)
LXC
:
Linux Container容器,是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源。Linux
容器功能是基于
cgroups
和
Namespace
来实现的
.
所以要了解
Linux
容器必须先了解
cgroup
和
Namespace
。
1.1
虚拟机环境
1.1.1
安装
LXC
服务
1
、
a
pt-get install lxc。
2
、
lxc-checkconfig
,检查当前
Linux
内核支持
LXC
的情况。要是一切都已被启用,内核对
LXC
的支持已准备就绪。
1.1.2
使用
LXC
1、lxc-create -n lxc-ubuntu -t ubuntu:
-n
指定容器名
。
-t
指定模板名,这里必须为
ubuntu。
其中配置模板在
/usr/share/
默认
创建与本地主机同一版本号和同一架构的最小
Ubuntu
安装系统
。
容器存储在
/var/lib/lxc/<container-name>
,根文件系统则位于
/var/lib/lxc/<container-name>/rootfs
。LXC
创建过程中下载的所有程序包则缓存在
/var/cache/lxc
里面
。
2、 lxc-ls --fancy:查看容器列表,
3、lxc-start -n lxc-ubuntu
:启动
lxc
容器。后面加
-F
可以把启动过程放在前台,会打印更多的调试信息。
4、brctl show lxcbr0
:确认
容器的接口(
vethSS7RB5
)自动连接到
LXC
的内部网桥(
lxcbr0
)
。
5、lxc-console -n lxc-ubuntu
:登入容器的控制台,提示需要输入用户名和密码,默认都是
ubuntu
,退出控制台使用
exit
。
6、lxc-stop -n lxc-ubuntu
:停止容器,注意需要在另一个终端输入。
1.1.3
遇到过的问题:
1、
在虚拟机上重新
start
容器时:不知道是之前使用了
destroy
,还是强制关闭虚拟机了,
lxc-start
的时候提示“
lxc_ovs_attach_bridge: 1817 Failed to attach "lxcbr0" to openvswitch bridge "vethDSDW29"
”,通过
ifconfig
发现
lxcbr0
网卡没有了,通过
apt-get
卸载,重新安装才解决。
dpkg --list
;
apt-get --purge remove
包名(
--purge
是可选项,写上这个属性是将软件及其配置文件一并删除)
1.2
Imx6
目标板环境
1.2.1
编译
lxc
下载
lxc2.0.0
版本
。
1、设置环境变量:
. /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa9hf-neon-poky-linux-gnueabi
。
利用
nxp
自带的环境变量配置脚本,设置当前环境变量:
CC
、
LD
、
LIB
。
2、
配置检查:
./configure --build=x86_64-linux --host= --target=arm-poky-linux --bindir=/home/cql/imx6/lxc-2.0.0/bin
。检查通过后会执行
. /configure
相关概念
--build=
编译该软件所使用的平台
--host=
该软件将运行的平台
--target=
该软件所处理的目标平台
3、
编译
make
。
4、
安装:
make install
。
5、
将生成的工具集打包通过
ssh
放到目标板:
scp -r lxc_bin
root@192.168.199.102:/usr/
s
bin
/lxc_bin
。
6、执行lxc-checkconfig看内核还缺哪些服务,如下如所示,需要将内核的对应配置打开,重新编译内核。
1.2.2
配置内核
根据lxc-checkconfig的运行结果,查看当前内核还差哪些服务,根据服务重新配置内核。
1、
执行
make menuconfig
。如果虚拟机缺少
ncurses
,需要先安装
apt-get install libncurses5-dev。
2、
如果在
menuconfig
中搜索不到选项的关键字,需要查看
lxc-checkconfig脚本代码,确认错误打印的实际条件。
1.2.3
编译内核
1
、
make menuconfig
如果提示
make menuconfig fatal error
:
ncurses.h
;是因为缺少图形化动态库
ncurses
;通过
apt-get install libncurses5-dev
解决。又提示:
recipe for target 'script/kconfig/dochecklx
;重启虚拟机解决。
2
、
make distclean
3
、
make imx_v7_defconfig
4
、
make zImage
提示:
make /bin/sh: 1: lzop: not found,
虚拟机缺少
lzop
压缩工具,使用
apt-get install lzop
后解决
。
5
、
make dtbs
6
、
make modules
1.2.4
构建容器
1、
将模板拷贝到目标板:
scp -r templates/ root@192.168.199.228:/usr/local/share/lxc/
。并设置可执行权限。
2、
将配置文件从
lxc-2.0.0/config/templates
拷贝到目标板:
scp -r config/templates/* root@192.168.199.228:/usr/local/share/lxc/config/
。
3、
将
lxc
工具集拷贝到目标板:
scp ../bin/* root@192.168.199.129:/sbin/
4、
将动态库拷贝到目标板:
scp src/lxc/liblxc.so
root@192.168.199.129:/usr/local/lib
;并创建软连接:
ln -s /usr/local/lib/liblxc.so /usr/lib/liblxc.so.1
。后面工具集使用的需要用到软连接。
5、
修改
/usr/local/share/lxc/template/lxc-xxx
编辑模板:将
fetch
函数
wget
超时增加到
100
。
6、
创建容器:
lxc_create -n lxc0 -t alpine
。
7、启动容器:lxc-start -n lxc0 -o /dev/stdout -l debug -F。
8、
查看
lxc
版本:
lxc-device --version
。
1.2.5
重要目录说明:
1、
容器的模板路劲:
/usr/local/share/lxc/templates
。不同的
lxc
版本路径有变化,这个对应的是
lxc2.0.0,
比如笔者虚拟机上
lxc2.0.11
的目录是
/usr/local/share/lxc/templates
。通过阅读模板脚本可以看到其他目录的差异。
2、
容器的文件系统路径:
/usr/local/var/lib/lxc$(lxcname)/rootfs
,虚拟机是:
/var/lib/lxc/$(lxcname)/rootfs/
。
3、
容器的配置文件路径:
/usr/local/var/lib/lxc$(lxcname)/config
,虚拟机是:
/var/lib/lxc/$(lxcname)/config
。
1.2.6
遇到过的问题:
1
、配置
lxc
编译脚本的时候:
./configure
一直有问题,
报
“
cannot find crt1.o
”等各种错误,
从
config.log
上看是链接出错,反复调整
CC
、
--build
、
--host
、
--target
还是没有效果
,最后还是使用
nxp
的环境变量脚本更方便一些。
2、
编译内核前配置的时候:
make menuconfig
,提示“
fatal error
:
ncurses.h
”;是因为缺少图形化动态库
ncurses
;通过
apt-get install libncurses5-dev
解决。又提示:
recipe for target 'script/kconfig/dochecklx
;重启虚拟机解决。
3、
创建容器的时候,
lxc-create -n lxc0 -t alpine -l debug
提示:
lxc-create: utils.c: get_template_path: 1427 Permission denied - bad template: alpine
。查看模板的路径和内容均确认是正确的。因为
template
文件是脚本,需要可执行权限,
chmod 777 /usr/local/share/lxc/templates/*
,提高权限,解决。
4、
创建
lxc
容器的时候:
lxc-create -n lxc0 -t alpine
,提示“
wget: server returned error: HTTP/1.1 400 Bad Request
”,直接使用
wget
工具测试“
wget
http://www.bai.com”,发现是可以下载网页的,但是使用
wget
https://alpinelinux.org/keys/alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
,是不行的,提示相同的错误。应该是
wget
软件问题,去
https://www.busybox.net/
查看busybox
的版本发布说明,
wget
在笔者使用的
busybox_1.27.2
这个版本之后确实有修复
wget
的问题。
5、
继续创建容器:提示
“
sha256sum: WARNING: 1 computed checksum did NOT match
”。直接使用
sha256sum
相应的
.pub
文件,确实有问题,查看文件内容,和虚拟机相应文件对比,明显不对,应该是之前
wget
下载错误导致,删除
.pub
,解决。
6、
继续创建容器:提示下载
apk_tool
超时,
再次创建的时候直接解压
apk_tool
失败,想起
alpine
的模板脚本的
fetch
函数里配置的是
wget -T 10
,超时时间可能不够,修改超时时间到
100
,解决。
7、
创建容器的时候,提示错误:
“
lxc-create: utils.c: get_template_path: 1340 Permission denied - bad template: alpine
”。阅读代码发现是
access
错误,应是没有权限,给
templates
和
config
都加上操作权限,解决。
8、
启动容器的时候:提示
“
lxc-start 20200714015606.656 ERROR lxc_start - start.c:lxc_spawn:1093 - failed initializing cgroup support
”,放开调试打印:
lxc-start -n lxc0 -o /dev/stdout -l debug -F
,
“
lxc-start 20200714041349.939 ERROR lxc_cgfs - cgfs.c:do_setup_cgroup_limits:1993 - No such file or directory - Error setting devices.deny to a for lxc0
”。官网查到应该是
2.0.0
的版本对不支持
systemd
的内核有
bug
,这个在后面的版本中有修复。通过在
/etc/fstab
文件中加入挂载信息解决:
cgroup /sys/fs/cgroup cgroup defaults 0 0
重启后系统会自动挂载文件系统。
9、Linux
内核配置文件
打包在/proc/config.gz
1.
LXC
容器部署(csky)
1.1
编译
lxc
1、
设置环境变量:
. /opt/csky-toolchain/environment-setup-csky
。利用通用的环境变量配置脚本,设置当前环境变量:
CC
、
LD
、
LIB
。
2、
配置检查:
/configure --build=x86_64-linux --host=csky-abiv2-linux --target=csky-abiv2-linux --bindir=/home/cql/fuxi_h/lxc-2.x.x/bin
。
--build=
编译该软件所使用的平台
--host=
该软件将运行的平台
--target=
该软件所处理的目标平台
3、
编译
make
。
4、
安装:
make install
。
5、执行lxc-checkconfig看内核还缺哪些服务,如下如所示,需要将内核的对应配置打开,重新编译内核。
1.2
内核配置
1、
将默认配置覆盖到
../obj/.config
,在内核目录执行:
make ARCH=csky CROSS_COMPILE=/opt/csky-toolchain/bin/csky-linux-gnuabiv2- O=../obj/ fx6evb_defconfig
。
2、根据上面lxc-checkconfig
的检测结果配置内核:
Make ARCH=csky O=../obj/ menuconfig
。(注:配置
CONFIG_NF_NAT_IPV4
需要先打开
NF_CONNTRACK
,其他的根据宏名称搜索即可)
3、
编译内核并把内核和
roofs
一起打包到
image
:
make ARCH=csky CROSS_COMPILE=/opt/csky-toolchain/bin/csky-abiv2-linux- CONFIG_INITRAMFS_SOURCE=/home/cql/fuxi_h/rootfs/work/fx6/tmp_fs O=../obj -j8
1.3
创建容器
因为通过模板来创建
lxc
的时候,需要从发行版官网下载和
arch
相对应的镜像,
cksy
的生态不健全,各个发行版还不支持
csky
,所以不能使用
lxc_create -n lxc0 -t alpine
来创建容器。
手动将
rootfs
和
config
文件拷贝到
/usr/local/var/lib/lxc/lxcXXX/
或者
/var/lib/lxc/lxcXXX
目录下(自己编译的库
liblxc.so.1.0.0
使用的前者路径,虚拟机和默认的
liblxc.so.l.6.0
使用的是后者,具体什么原因还确定),这个时候就可以通过
lxc-ls
看看有没有
lxcXXX
。
环境构建:
1
、
mount -t cgroup none /root/cgroupfs(
目录可以随意,这样在
/proc/1/cgroup
文件才有内容
)
。
2
、执行
lxc-net
,创建虚拟网桥,通过
ifconfig
确认网桥
lxcbr0
是否
OK
。
1.4
启动容器
1
、输入命令
lxc-start -n lxc0 -l debug -o /tmp/lxclog12
1.5
进入容器
1、lxc-attach -n lxc0
。
1.6
退出容器
键入
exit
即可退出容器
1.7
配置网络
1.7.1
主机网络配置:
1、
配置
dns
:更改
/etc/resolv.conf
:
search lan nameserver 192.168.199.1
2、重启网络服务:/etc/init.d/S40network restart。
3、
确认能
ping
通外网:
ping www.baidu.com
。
1.7.2
容器网络配置:
1、
修改启动脚本
/et/init.d/rcS
:
/sbin/ifconfig eth0 10.0.3.100 netmask 255.255.255.0
/sbin/route add default gw 10.0.3.1 eth0
2
、重启容器:验证可以
ping
通外网。
1.8
遇到过的问题
1
、
## Booting kernel from Legacy Image at 00080000 ...
Image Name: fx6-kernel-iamge
Image Type: CSKY Linux Kernel Image (uncompressed)
Data Size: 10435776 Bytes = 10 MiB
Load Address: 00080000
Entry Point: 00080000
Verifying Checksum ... Bad Data CRC
ERROR: can't get kernel image!
==
》内核大小超过了扇区大小,检查
uboot
的配置和
dd
命令的大小。
Uboot
查看分区大小:
pr
;修改内核分区大小命令:
env set flash_kernel_size 0x900000。
==
》使用浙大的
rootfs
的
rcS
替换南网自制的,实现启动。
2
、
lxc-start: lxc0: cgroups/cgroup.c: cgroup_init: 54 Failed to initialize cgroup driver
==
》
cg_hybrid_init
函数中需要访问
read_file("/proc/1/cgroup");
内核的这个文件是空的,导致
lxc start
异常退出。
a.
在
meuconfig:General setup-->Control Group support
下选择你们想要的
cgroup
项
b.
重新编译,启动,在
shell
界面把
cgroup
挂载到一个目录
(path/dir)
下,即运行命令
mount -t cgroup none path/dir
c.
就能
/proc/1/cgroup
文件中看到内容了
3
、
lxc-start: lxc0: storage/dir.c: dir_mount: 198 No such file or directory - Failed to mount "/var/lib/lxc/lxc-busybox/rootfs" on "/usr/local/lib/lxc/rootfs"
==
》在
/var
路劲中配置
rootfs
路径,
lxc
启动会将这个目录
mount
到
/usr
目录。
4
、
lxc-start lxc0 19700101001039.724 ERROR conf - conf.c:lxc_allocate_ttys:1001 - No such file or directory - Failed to create tty 0
lxc-start lxc0 19700101001039.728 ERROR conf - conf.c:lxc_create_ttys:1102 - Failed to allocate ttys
==
》参考
lxc
源码自带的重新
openpty.c
文件实现
openpty
函数
4
、
conf - conf.c:setup_caps:2567 - unknown capability sys_module
lxc-start lxc0 19700101005037.568 ERROR conf - conf.c:lxc_setup:3806 - Failed to drop capabilities
==
》在
lxc_setup
函数中屏蔽掉
setup_caps
。
根本原因分析:
configure
脚本通过检查工具链是否包含
libcap
相关的库和头文件来决定是否在
config.h
中打开宏
HAVE_LIBCAP
,如果这个宏没有打开,将会导致了
setup_caps
的匹配失败。
待优化解决方案:构建工具链的时候需要开启
libcap
选项,因为默认使用动态库,
rootfs
也需要
libcap.so.