Docker 在DockerCon 2017大会上发布了一个自己的操作系统,宣称LinuxKit,安全,精简,强移植性。经过研究后发现LinuxKit就是kernel+busybox实现的一个微缩linux系统,其中直接安装了containerd和runc服务。其他服务全部都使用容器启动。一句话概括,LinuxKit就是希望在操作系统层面除了containerd之外其他服务都跑在容器中,这是一个几乎全部服务都在容器中的操作系统。
LinuxKit的使用
先介绍下LinuxKit是如何使用的。
项目地址:https://github.com/linuxkit/linuxkit
LinuxKit工程提供了工具来构建我们自己的操作系统。
moby 通过yml文件的描述,构建自定义的操作系统。
linuxkit 用来帮忙在不同平台启动镜像的工具。
首先安装moby和linuxkit工具和下载linuxkit代码
go get -u github.com/linuxkit/linuxkit/src/cmd/moby go get -u github.com/linuxkit/linuxkit/src/cmd/linuxkit git clone https://github.com/linuxkit/linuxkit
然后开始编译定制化的linux操作系统,我们使用LinuxKit提供的linuxkit.yml来进行编译
cd linuxkit moby build linuxkit.yml
编译完成后,我们可以看到新出现的文件,这就是通过linuxkit.yml编译出来的内核和ramdisk
linuxkit-bzImage 编译出的kernel linuxkit-cmdline 启动时候的grub需要带的参数。 linuxkit-efi.iso EFI启动镜像 linuxkit-initrd.img 一个ramdisk linuxkit.iso BIOS启动镜像
接下来可以通过linuxkit工具来启动这个系统。
linuxkit run linuxkit
linuxkit 会根据系统自动选择合适的hypervisor来启动镜像。 由于我在linux上,所以启动的时候使用了kvm来启动虚拟机。
Welcome to LinuxKit ##. ## ## ## == ## ## ## ## ## === / "" "" "" "" "" "" "" "" "" \ ___ / = = = ~~~ { ~~~~~~~~~~~~~~~~~ / === --~~~ \ ______ o __ / \ \ __ / \ ____ \ _______ /
启动时候可以看到我们可爱的小鲸鱼。这时候我们订制的专门跑容器的系统就完成了。
这里看一下系统启动了那些程序
/ # pstree / # pstree init-+-containerd-+-containerd-shim---nginx---nginx |-containers---ctr |-sh---pstree `-sh
使用默认的linuxkit.yml 其实就是启动了一个nginx服务。而且这个系统中的init程序直接启动了containerd。以后所有的服务都是通过容器启动的。
linuxkit分析
通过刚才的使用介绍可以看到,其实lilnuxkit是给用户提供了一种通过yml来订制自己的微缩操作系统的方式。那么我们还是先从这个linuxkit.yml文件来看。
#指定了需用的内核版本,以及启动参数 kernel: image: "linuxkit/kernel:4.9.x" cmdline: "console=ttyS0 console=tty0 page_poison=1" #指定init程序 init: - linuxkit/init:42fe8cb1508b3afed39eb89821906e3cc7a70551 - linuxkit/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9 - linuxkit/containerd:60e2486a74c665ba4df57e561729aec20758daed - linuxkit/ca-certificates:eabc5a6e59f05aa91529d80e9a595b85b046f935 #指定了启动时候的会运行的系统容器,执行一次就会停止的。 onboot: - name: sysctl image: "linuxkit/sysctl:2cf2f9d5b4d314ba1bfc22b2fe931924af666d8c" net: host pid: host ipc: host capabilities: - CAP_SYS_ADMIN readonly: true - name: binfmt image: "linuxkit/binfmt:8881283ac627be1542811bd25c85e7782aebc692" binds: - /proc/sys/fs/binfmt_misc:/binfmt_misc readonly: true - name: dhcpcd image: "linuxkit/dhcpcd:48e249ebef6a521eed886b3bce032db69fbb4afa" binds: - /var:/var - /tmp/etc:/etc capabilities: - CAP_NET_ADMIN - CAP_NET_BIND_SERVICE - CAP_NET_RAW net: host command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"] #在镜像生命周期中都要启动的系统服务 services: - name: rngd image: "linuxkit/rngd:c42fd499690b2cb6e4e6cb99e41dfafca1cf5b14" capabilities: - CAP_SYS_ADMIN oomScoreAdj: -800 readonly: true - name: nginx image: "nginx:alpine" capabilities: - CAP_NET_BIND_SERVICE - CAP_CHOWN - CAP_SETUID - CAP_SETGID - CAP_DAC_OVERRIDE net: host #镜像中包含的文件及内容 files: - path: etc/docker/daemon.json contents: '{"debug": true}' trust: image: - linuxkit/kernel #输出的文件,kernel,initrd,bios-iso和efi-iso outputs: - format: kernel+initrd - format: iso-bios - format: iso-efi
文件比较简单,通过阅读文件可以看到,通过指定不同的容器镜像,最终可以帮助我们生成想要的 镜像。
生成了镜像,我们自然要研究一下这个linuxkit操作系统和现在发行版linux有哪些区别。
在使用linuxkit启动时,可以看到qemu相关的参数。
/usr/bin/docker-current run -i --rm -v /home/git/linuxkit:/tmp -w /tmp --device /dev/kvm linuxkit/qemu:17f052263d63c8a2b641ad91c589edcbb8a18c82 qemu-system-x86_64 -device virtio-rng-pci -smp 1 -m 1024 -enable-kvm -machine q35,accel=kvm:tcg -kernel linuxkit-bzImage -initrd linuxkit-initrd.img -append console=ttyS0 console=tty0 page_poison=1 -nographic
观察后可以发现,在启动虚拟机时候,并没有挂载硬盘,而是使用了指定kernel和ramdisk的方式来进行的。
这样看来linuxkit其实就是一个使用kernel和ramdisk直接启动的操作系统。 而ramdisk就包含了服务的容器镜像,在init程序启动之后,就通过containerd来拉起服务。linuxkit的init程序是用shell编写,因此我们这里也打开来看看。
#!/bin/sh setup_console() { tty=${1%,*} speed=${1#*,} inittab="$2" securetty="$3" line= term="linux" [ "$speed" = "$1" ] && speed=115200 case "$tty" in ttyS*|ttyAMA*|ttyUSB*|ttyMFD*) line="-L" term="vt100" ;; tty?) line="" speed="38400" term="" ;; esac # skip consoles already in inittab grep -q "^$tty:" "$inittab" && return echo "$tty::once:cat /etc/issue" >> "$inittab" echo "$tty::respawn:/sbin/getty -n -l /bin/sh $line $speed $tty $term" >> "$inittab" if ! grep -q -w "$tty" "$securetty"; then echo "$tty" >> "$securetty" fi } #在/mnt 下挂载了tmpfs /bin/mount -t tmpfs tmpfs /mnt #将根目录下的所有内容都copy到了/mnt下 /bin/cp -a / /mnt 2>/dev/null /bin/mount -t proc -o noexec,nosuid,nodev proc /proc for opt in $(cat /proc/cmdline); do case "$opt" in console=*) setup_console ${opt#console=} /mnt/etc/inittab /mnt/etc/securetty;; esac done #进行操作系统根目录的切换 /mnt 这里的/sbin/init 其实是软连接到busybox exec /bin/busybox switch_root /mnt /sbin/init
文件内容依然简单可以看到,init程序给/mnt挂载了tmpfs系统,这是一个内存文件系统。然后将ramdisk中的所有内容都copy到了/mnt下,然后切换根目录到 /mnt。然后交给busybox继续启动。 busybox接着就开始启动containerd,并通过runc启动系统应用容器等。
linuxkit使用场景
从官方的描述来看,Linuxkit为每种容器提供了一个基于容器的方法,生成轻量级Linux子系统。当为特定硬件或者拥有特定功能定制系统时非常有用。每个LinuxKit子系统都有其自己的Linux核心,而每个系统守护进程或者系统服务都是一个容器。这些Linux子系统一旦被打包成ISO镜像,就可以用来启动物理机或者虚拟环境。Docker以提供的服务方式维护这些子系统。
这里其实可以看到Linuxkit解决了docker一直以来的问题容器和host共享内核,以至于有些应用不能够很好的在docker上使用的问题。 linuxkit具有的特点: - Linuxkit作为一个操作系统,本身可以在物理机或者虚拟机上启动。 - linuxkit是只读文件系统,并且相当轻量级只有60M左右,可以被应用在无盘启动系统中。 - linuxkit的理念同docker理念一脉相承。不同的镜像对应不同的应用,灵活,轻量,无状态。
可以预见到,可以直接在裸机上通过pxe来启动对应的linuxkit镜像,或者使用虚拟机快速启动linuxkit镜像,用户已经无需再预先搭建docker平台来启动容器。可以说linuxkit给容器化带来了更广阔的前景。