本文共 21287 字,大约阅读时间需要 70 分钟。
本文基于 ubuntu 16.04 操作。
很多人可能不知道 LXD,但可能听说过老牌容器 LXC(远早于 docker)。
[LXC][] 由 [Canonical Ltd][] 和 [Ubuntu][] 开发维护,其灵感可能来自 [OpenVZ][] 等轻量级虚拟机(容器)。
原有的 LXC 工具比较难用(需要用户了解一些底层知识),同时开发团队想要修改(优化)一些默认配置和特性(如安全增强,默认创建非特权容器)。为了保持兼容性,不宜在旧的已有 LXC 工具(如lxc-create
, lxc-start
等)上动刀,于是新设计封装了一套上层运维操作工具,即 [LXD][]。LXC 使用 C 开发,LXD 使用 golang 开发。早期版本的 docker 其实也是基于 LXC 封装,LXD 可能也借鉴了 docker 的一些思想。LXD 拆分为 daemon(命令为 lxd
)和客户端(命令为 lxc
)两部分。 LXD 的定位很清晰:系统容器,直接对标虚拟机 ,甚至可以直接运行虚拟机镜像(但是不启动内核)。
系统容器运行整套操作系统(再说一次,除了内核),应用容器(如 docker)运行应用,两者不冲突。可以在 LXD 容器里安装和使用 docker,跟在物理机和虚拟机上没什么两样。LXD 还支持与 OpenStack 集成(nova-lxd 项目,可替代 OpenStack 上的虚拟机?)。[LXD][] 远没有 docker 流行,网上资料不多。
但 通过 和命令行帮助,已经足够轻松了解和使用 LXD,读来感觉非常可爱。ubuntu 下可直接从软件仓库安装 LXD:
sudo aptitude install lxd lxd-client -y
lxd-client
是客户端软件包,安装后得到 lxc
命令。当前版本 lxd 默认会拉起 lxdbr0 网桥,可修改 lxd.service 不要依赖 lxd-bridge.service,避免拉起这个默认网桥:
sudo systemctl stop lxd-bridge.servicesudo rsync -ai /{lib,etc}/systemd/system/lxd.servicesudo sed -r -e '/^(After|Requires)=/ s#lxd-bridge.service\s*##g' /etc/systemd/system/lxd.service -isudo systemctl daemon-reload
另外 /etc/default/lxd-bridge
文件包含 lxd 网桥相关配置,可配置 lxd 软件包修改此配置文件。
echo 'lxd lxd/setup-bridge boolean false' | sudo debconf-set-selectionsecho 'lxd lxd/use-existing-bridge boolean true' | sudo debconf-set-selectionsecho 'lxd lxd/bridge-name string br0' | sudo debconf-set-selectionssudo dpkg-reconfigure -f noninteractive lxd
为了使用新版 LXD 功能和特性,可从源码编译安装新版本 LXD。
安装开发依赖。建议手动下载安装 golang 最新版本,其他依赖可直接从软件仓库安装:
sudo aptitude install acl dnsmasq-base git liblxc1 lxc-dev libacl1-dev make pkg-config rsync squashfs-tools tar xz-utils -y
从源码编译最新 release 版本:
mkdir lxd.gopathcd lxd.gopath/cat > .envrc <<< $'export GOPATH="${PWD}"\nGOROOT="$(readlink -f /opt/go1.10)"\nPATH="${GOROOT}/bin:${GOPATH}/bin:$PATH"'direnv allow .git clone git@github.com:lxc/lxd.git src/github.com/lxc/lxd( cd src/github.com/lxc/lxd/ && git tag --sort=version:refname | tail )( cd src/github.com/lxc/lxd/ && git reset --hard lxd-3.0.0 )make -C src/github.com/lxc/lxd/
安装到 local 目录:
$ sudo install bin/lxd bin/lxc -t /usr/local/bin/ -v'bin/lxd' -> '/usr/local/bin/lxd''bin/lxc' -> '/usr/local/bin/lxc'
转移软件包 lxd 可执行文件,使用本地新版本替代:
sudo systemctl stop lxdsudo dpkg-divert --rename --add /usr/bin/lxcsudo dpkg-divert --rename --add /usr/bin/lxdsudo ln -sfT /usr/{local/,}bin/lxcsudo ln -sfT /usr/{local/,}bin/lxd
其他办法:修改 lxd.service 使用新版本 lxd 可执行文件。
sudo systemctl stop lxd
sudo sed -r -e 's#(/usr/)(bin/lxd)b#1local/2#g' /etc/systemd/system/lxd.service -isudo systemctl daemon-reload如果 `lxc` 命令被 hash 到系统路径,则需要解除 hash 以使用 local 下的新版 lxc 命令。
hash -d lxc
LXD daemon, 有时也称作服务器(server)。
LXD 相关操作通常通过客户端 lxc 命令执行,但 lxd 命令也包含一些特殊操作。一个用户可能会用到的操作是lxd init
,初始化 lxd daemon。 $ lxd init --helpDescription: Configure the LXD daemonUsage: lxd init [flags]Examples: init --preseed init --auto [--network-address=IP] [--network-port=8443] [--storage-backend=dir] [--storage-create-device=DEVICE] [--storage-create-loop=SIZE] [--storage-pool=POOL] [--trust-password=PASSWORD]Flags: --auto Automatic (non-interactive) mode --network-address Address to bind LXD to (default: none) --network-port Port to bind LXD to (default: 8443) (default -1) --preseed Pre-seed mode, expects YAML config from stdin --storage-backend Storage backend to use (btrfs, dir, lvm or zfs, default: dir) --storage-create-device Setup device based storage using DEVICE --storage-create-loop Setup loop based storage with SIZE in GB (default -1) --storage-pool Storage pool to use or create --trust-password Password required to add new clientsGlobal Flags:# ... ...
lxd init 也是与 daemon 通信完成操作,相当于一个特殊的 lxc 命令。其主要有两个操作,配置网络和存储。
lxd 与 git 类似,采用分布式的架构,任意两个节点都可以相互通信。配置网络地址将其暴露到网络上,其他节点可使用密码连接。
lxd init --auto --network-address=0.0.0.0 --trust-password=1234
也可以直接使用 lxc 命令修改和查看网络地址(及其他 server 配置):
$ lxc config set core.https_address 0.0.0.0:8443$ lxc config show config: core.https_address: 0.0.0.0:8443 core.trust_password: true
提供一个简便的命令,创建一个名为 default 的("默认")存储,并配置(名为 default 的)默认 profile 使用此存储创建容器。
创建一个名为 lxd 的 lvm vg,使用此 vg 创建 "默认" 存储。lxd init --auto --storage-backend=lvm --storage-pool=lxd
当然也可以直接使用 lxc 命令查看和执行相关操作:
$ lxc storage list+---------+-------------+--------+--------+---------+| NAME | DESCRIPTION | DRIVER | SOURCE | USED BY |+---------+-------------+--------+--------+---------+| default | | lvm | lxd | 1 |+---------+-------------+--------+--------+---------+$ lxc profile show defaultconfig: {}description: Default LXD profiledevices: root: path: / pool: default type: diskname: defaultused_by: []
参考: 。
与 docker 不同,LXD 不区分容器和数据卷。
换句话说,容器根文件系统(容器卷)和数据卷在 LXD 使用完全相同的存储方案,统称为存储卷(storage volume),唯一区别是容器卷会使用镜像进行初始化。这有个好处,如设计一套存储计算分离的存储方案,则天然同时适用于容器卷和数据卷。LXD 内置支持多种存储后端,如 dir, btrfs, lvm, zfs, ceph 等,推荐使用 zfs 和 btrfs。为了方便我们可以使用熟悉的 lvm (thinpool)。前面已经介绍过创建和查看存储,在此不再敖述。
LXD 采用类似 git 分布式架构管理和分发镜像(和容器?),
任意两个节点都可以互相通信,并且许多操作天然支持访问和操作 remote 节点。$ lxc remote list+-----------------+------------------------------------------+---------------+-----------+--------+--------+| NAME | URL | PROTOCOL | AUTH TYPE | PUBLIC | STATIC |+-----------------+------------------------------------------+---------------+-----------+--------+--------+| images | https://images.linuxcontainers.org | simplestreams | | YES | NO |+-----------------+------------------------------------------+---------------+-----------+--------+--------+| local (default) | unix:// | lxd | tls | NO | YES |+-----------------+------------------------------------------+---------------+-----------+--------+--------+| ubuntu | https://cloud-images.ubuntu.com/releases | simplestreams | | YES | YES |+-----------------+------------------------------------------+---------------+-----------+--------+--------+| ubuntu-daily | https://cloud-images.ubuntu.com/daily | simplestreams | | YES | YES |+-----------------+------------------------------------------+---------------+-----------+--------+--------+
添加远程节点:
lxc remote add han2017 https://han2017:8443/ --accept-certificate --password=1234
可以直接使用远程镜像创建容器,LXD 会自动拷贝镜像到本地 cache(私有镜像),并自动管理(自动更新,过期清理)。
也可以显式手动从远程节点拷贝镜像到本地:
lxc image copy ubuntu:16.04 local: --alias ubuntu/16.04 --publiclxc image copy han2017:ubuntu/16.04 local: --copy-aliases --public
$ lxc image list+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+| ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCH | SIZE | UPLOAD DATE |+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+| ubuntu/16.04 | be7cec7c9489 | yes | ubuntu 16.04 LTS amd64 (release) (20180405) | x86_64 | 156.27MB | Apr 7, 2018 at 8:17am (UTC) |+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+$ sudo tree -L 3 -a /var/lib/lxd/images//var/lib/lxd/images/├── be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a└── be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a.rootfs
/var/lib/lxd/images/
目录下。参考: 。
LXD 容器配置可划分为两部分:
lxc config
或 lxc profile
管理。lxc config device
或 lxc profile device
管理。如磁盘设备,网络设备等。注意,容器内磁盘设备通常是使用文件系统,而不是块设备。为了方便管理容器配置,LXD 支持使用 profile 预设管理容器配置模板。
lxc config
管理已创建容器实例配置,lxc profile
管理容器 profile 配置。创建容器时可指定多个 profile,多个 profile 与容器自身配置叠加覆盖得到最终有效配置。 使用 lxc init
命令创建容器:
$ lxc init --helpDescription: Create containers from imagesUsage: lxc init [:] [ :][ ] [flags]Examples: lxc init ubuntu:16.04 u1Flags: -c, --config Config key/value to apply to the new container -e, --ephemeral Ephemeral container -n, --network Network name -p, --profile Profile to apply to the new container -s, --storage Storage pool name --target Node name -t, --type Instance type$ lxc network list+--------+----------+---------+-------------+---------+| NAME | TYPE | MANAGED | DESCRIPTION | USED BY |+--------+----------+---------+-------------+---------+| br0 | bridge | NO | | 0 |+--------+----------+---------+-------------+---------+| enp5s0 | physical | NO | | 0 |+--------+----------+---------+-------------+---------+
-p
指定 profile, 可重复多次以指定多个 profile 叠加覆盖。不指定时默认使用 default
。-c
指定容器 key/value 配置。-s
使用指定存储池创建容器卷。容器卷未指定大小时默认与镜像大小相同。-n
创建网卡设备连接到指定网络。可指定外部(手动管理的)网桥(或网卡等网络设备?)名。可简化起见,可设置创建特权容器。
一个原因是,LXD 非特权容器默认开启了用户 idmap,虽然 LXD 对 idmap 做了很好的支持,但 idmap 解决的问题比带来的问题更多,如与宿主机共享文件系统问题等。修改默认 profile:
lxc profile set default security.privileged true
创建容器:
$ lxc list+------+-------+------+------+------+-----------+| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |+------+-------+------+------+------+-----------+$ lxc storage volume list default+------+------+-------------+---------+| TYPE | NAME | DESCRIPTION | USED BY |+------+------+-------------+---------+$ sudo lvs lxd$ lxc init ubuntu/16.04 test -s default -n br0Creating test$ lxc list+------+---------+------+------+------------+-----------+| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |+------+---------+------+------+------------+-----------+| test | STOPPED | | | PERSISTENT | 0 |+------+---------+------+------+------------+-----------+$ lxc config show testarchitecture: x86_64# ... ...devices: br0: nictype: bridged parent: br0 type: nic root: path: / pool: default type: diskephemeral: falseprofiles:- defaultstateful: falsedescription: ""$ lxc storage volume list default+-----------+------------------------------------------------------------------+-------------+---------+| TYPE | NAME | DESCRIPTION | USED BY |+-----------+------------------------------------------------------------------+-------------+---------+| container | test | | 1 |+-----------+------------------------------------------------------------------+-------------+---------+| image | be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a | | 1 |+-----------+------------------------------------------------------------------+-------------+---------+$ sudo lvs lxd LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert LXDThinpool lxd twi-aotz-- 98.00g 0.91 0.09 containers_test lxd Vwi-a-tz-- 10.00g LXDThinpool images_be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a 8.90 images_be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a lxd Vwi-a-tz-- 10.00g LXDThinpool 8.90
创建容器时即完成创建容器卷(作为容器设备)(网卡等容器设备则是启动容器时才创建)。
启动容器:
$ brctl showbridge name bridge id STP enabled interfacesbr0 8000.0227625084a8 yes enp5s0 tap0$ lxc start test$ brctl showbridge name bridge id STP enabled interfacesbr0 8000.0227625084a8 yes enp5s0 tap0 vethKFYJSY$ ip link show dev vethKFYJSY6: vethKFYJSY@if5:mtu 1500 qdisc noqueue master br0 state UP mode DEFAULT group default qlen 1000 link/ether fe:69:14:43:db:75 brd ff:ff:ff:ff:ff:ff link-netnsid 0$ lxc exec -t test /bin/bashroot@test:~# ip -4 addr1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever5: eth0@if6: mtu 1500 qdisc noqueue state UP group default qlen 1000 link-netnsid 0 inet 192.168.100.77/24 brd 192.168.100.255 scope global eth0 valid_lft forever preferred_lft forever
另外发现 lxc exec
的进程报 "not a tty":
root@test:~# ttynot a ttyroot@test:~# ll /proc/$$/fd/0lrwx------ 1 root root 64 Apr 7 09:24 /proc/445/fd/0 -> /dev/pts/2root@test:~# findmnt /dev/TARGET SOURCE FSTYPE OPTIONS/dev none tmpfs rw,relatime,size=492k,mode=755root@test:~# findmnt /dev/pts/TARGET SOURCE FSTYPE OPTIONS/dev/pts devpts devpts rw,relatime,gid=5,mode=620,ptmxmode=666root@test:~# ls /dev/pts/ptmx
lxc exec
进程使用的应该是从宿主机上继承的伪终端(上例即 /dev/pts/2
)。宿主机上可看到相关进程信息如下:
$ pschain -C bash -fww fUID PID PPID C STIME TTY STAT TIME CMD# ... ...root 24225 1 0 4月06 ? Ssl 11:43 /usr/bin/lxd --group lxd --logfile=/var/log/lxd/lxd.logroot 30251 24225 0 17:23 ? Sl 0:00 \_ /usr/local/bin/lxd forkexec test /var/lib/lxd/containers /var/log/lxd/test/lxc.conf -- env TERM=xterm PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin HOME=/root USER=root LANG=C.UTF-8 -- cmd /bin/bashroot 30259 30251 0 17:23 pts/2 Ss+ 0:00 \_ /bin/bash$ sudo ls -l /proc/30259/fd/0 --colorlrwx------ 1 root root 64 4月 7 17:30 /proc/30259/fd/0 -> /dev/pts/2
如果要执行的命令强依赖正确设置 tty,一个简单的解决办法是 在容器内重新分配伪终端,如使用 script
命令包装要执行的命令。
$ lxc exec -t test /bin/bashroot@test:~# ttynot a ttyroot@test:~# script -c /bin/bash /dev/nullScript started, file is /dev/nullroot@test:~# tty/dev/pts/0
可以在 lxc exec 时直接执行 script 命令:
$ lxc exec -t test -- script -c /bin/bash /dev/nullScript started, file is /dev/nullroot@test:~# tty/dev/pts/0
容器添加磁盘(文件系统)设备,设置 source 为宿主机文件系统路径,即使用路径绑定,即可轻松访问宿主机文件系统。
LXD 支持动态添加路径绑定,操作立即生效,非常方便。新建 profile 方便管理相关配置:
lxc profile create share-hostlxc profile set share-host security.privileged truelxc profile device add share-host /etc/apt/ disk {source,path}=/etc/apt/
$ lxc profile show share-host config: security.privileged: "true"description: ""devices: /etc/apt/: path: /etc/apt/ source: /etc/apt/ type: diskname: share-hostused_by: []
security.privileged=true
。容器添加 profile:
$ lxc exec -t test findmnt /etc/apt/$ lxc profile add test share-hostProfile share-host added to test$ lxc config show test# ... ...profiles:- default- share-hoststateful: falsedescription: ""$ lxc exec -t test findmnt /etc/apt/TARGET SOURCE FSTYPE OPTIONS/etc/apt /dev/mapper/vg-ubu1604[/etc/apt] ext4 rw,relatime,errors=remount-ro,data=ordered
$ lxc profile device add share-host /var/cache/apt/ disk {source,path}=/var/cache/apt/Device /var/cache/apt/ added to share-host$ lxc exec -t test findmnt /var/cache/apt/TARGET SOURCE FSTYPE OPTIONS/var/cache/apt /dev/mapper/vg-ubu1604var[/cache/apt] ext4 rw,relatime,data=ordered
LXD 不支持分层镜像,镜像制作工具也没有 docker 完善。如何制作 LXD 镜像呢?
参考: 。
将容器发布为镜像:
$ lxc image list+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+| ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCH | SIZE | UPLOAD DATE |+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+| ubuntu/16.04 | be7cec7c9489 | yes | ubuntu 16.04 LTS amd64 (release) (20180405) | x86_64 | 156.27MB | Apr 7, 2018 at 8:17am (UTC) |+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+$ sudo tree -L 3 -a /var/lib/lxd/images//var/lib/lxd/images/├── be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a└── be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a.rootfs$ lxc publish test --alias test --publicContainer published with fingerprint: cd1d4f8ce11dc9b6ff2b0a2c45e3cf1bc1370bbb45724b245880b757636537d3$ lxc image list+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+| ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCH | SIZE | UPLOAD DATE |+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+| test | cd1d4f8ce11d | yes | | x86_64 | 243.98MB | Apr 7, 2018 at 4:40pm (UTC) |+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+| ubuntu/16.04 | be7cec7c9489 | yes | ubuntu 16.04 LTS amd64 (release) (20180405) | x86_64 | 156.27MB | Apr 7, 2018 at 8:17am (UTC) |+--------------+--------------+--------+---------------------------------------------+--------+----------+-----------------------------+$ sudo tree -L 3 -a /var/lib/lxd/images//var/lib/lxd/images/├── be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a├── be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a.rootfs└── cd1d4f8ce11dc9b6ff2b0a2c45e3cf1bc1370bbb45724b245880b757636537d30 directories, 3 files$ lxc storage volume list default+-----------+------------------------------------------------------------------+-------------+---------+| TYPE | NAME | DESCRIPTION | USED BY |+-----------+------------------------------------------------------------------+-------------+---------+| container | test | | 1 |+-----------+------------------------------------------------------------------+-------------+---------+| image | be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a | | 1 |+-----------+------------------------------------------------------------------+-------------+---------+
使用新镜像创建容器:
$ lxc init test test2 -p share-host -p default -s default -n br0Creating test2$ lxc list+-------+---------+------+------+------------+-----------+| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |+-------+---------+------+------+------------+-----------+| test | STOPPED | | | PERSISTENT | 0 |+-------+---------+------+------+------------+-----------+| test2 | STOPPED | | | PERSISTENT | 0 |+-------+---------+------+------+------------+-----------+$ lxc storage volume list default+-----------+------------------------------------------------------------------+-------------+---------+| TYPE | NAME | DESCRIPTION | USED BY |+-----------+------------------------------------------------------------------+-------------+---------+| container | test | | 1 |+-----------+------------------------------------------------------------------+-------------+---------+| container | test2 | | 1 |+-----------+------------------------------------------------------------------+-------------+---------+| image | be7cec7c948958adfbb9bc7dbd292762d2388cc883466815fc2b6bc06bf06f5a | | 1 |+-----------+------------------------------------------------------------------+-------------+---------+| image | cd1d4f8ce11dc9b6ff2b0a2c45e3cf1bc1370bbb45724b245880b757636537d3 | | 1 |+-----------+------------------------------------------------------------------+-------------+---------+
友好排版请 。
转载地址:http://xqjyo.baihongyu.com/