V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dataman
V2EX  ›  程序员

在 Mac OS 的 Xhyve 引擎之上启动 LinuxKit 的玩法

  •  
  •   dataman · 2017-05-04 11:40:36 +08:00 · 2845 次点击
    这是一个创建于 2764 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在 Dockercon2017 上发布了一个能够在容器内创建最小 Linux OS 镜像的架构—— LinuxKit。

    听起来是不是很酷?数人云在外网上看到一篇关于 Mac OS with Xhyve 上启动 LinuxKit 的文章,学习工具最好的方法就是让它物尽其用,原文作者在与会后回奥斯汀的飞机上就已经着手研究它,接下来小数就把这篇文章跟大家简单地进行分享。


    首先,需要准备好以下环境:

    1. 一台 2010 年以后的 Mac ( CPU 支持 EPT )
    2. OS X 10.10.3 或更高版本
    3. Git 客户端
    4. Docker running (示例是 17.04.0-ce-mac7 (16352))
    5. GNU make
    6. GNU tar
    7. Homebrew

    准备完毕后,按照以下步骤实施。

    安装 Xhyve

    第一步,需要安装 Xhyve。Xhyve 是一个在 OSx ’ s Hypervisor 运行的虚拟机操作系统,其架构允许在用户空间内运行虚拟机。这是 Docker 为 MAC 用户准备的。有很多方法可以做到这一点,但最简单的莫过于用 Homebrew。在机器上安装——

    $ brew update
    
    $ brew install --HEAD xhyve
    

    安装完成后,检验是否按照如下代码运行:

    $ xhyve -h
    

    如果看到包含各种可用 flags 的输出,那么可以准备进入下一步。

    构建 Moby

    第二步是构建 Moby 工具。此工具会提供读取。稍后会详细说明 Yaml 的功能点,执行多样化的 Docker 命令来建立 Linux OS,如果喜欢,现在就可以运行 Image。

    这比 Moby ’ s Hyperkit 项目要方便。建立 Kernel 和 Initrdimages 会比 a qcow image 耗时更少,所以,如果需要快速的重复 Xhyve,这是一个不错的实现方式。

    首先,CD 到任意一个喜欢的工作目录,并 Clone LinuxKit repo:

    $ git clone https://github.com/linuxkit/linuxkit.git
    

    接下来安装 Moby binary:

    $ cd linuxkit
    $ make
    $ sudo make install
    

    完成后,需要准备建立使用 LinuxKit 的首个 Linux image。

    定制和构建 Linux 映像

    完成这些先决条件后,先建立首个镜像。LinuxKit 项目包括一些例子,其中某些例子也在 Dockercon 做了现场 Demo。在 Onboot 建立一个能够启动 Redis instance 的简单镜像,这样比从复杂的角度入手更快!

    首先,启动一个能够描述 Linux image 的 Yaml file,接着拉取实例,将会拿到基础的 Docker image,并且给 Redis 增加一个入口。

    $ vi linux-redis.yaml
    kernel:
    image: "linuxkit/kernel:4.9.x"
    cmdline: "console=ttyS0 console=tty0 page_poison=1"
    init:
    - linuxkit/init:63eed9ca7a09d2ce4c0c5e7238ac005fa44f564b
    - linuxkit/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
    - linuxkit/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b
    - linuxkit/ca-certificates:eabc5a6e59f05aa91529d80e9a595b85b046f935
    onboot:
    - name: sysctl
    image: "linuxkit/sysctl:1f5ec5d5e6f7a7a1b3d2ff9dd9e36fd6fb14756a"
    net: host
    pid: host
    ipc: host
    capabilities:
    - CAP_SYS_ADMIN
    readonly: true
    - name: sysfs
    image: linuxkit/sysfs:6c1d06f28ddd9681799d3950cddf044b930b221c
    - name: binfmt
    image: "linuxkit/binfmt:8881283ac627be1542811bd25c85e7782aebc692"
    binds:
    - /proc/sys/fs/binfmt_misc:/binfmt_misc
    readonly: true
    - name: format
    image: "linuxkit/format:53748000acf515549d398e6ae68545c26c0f3a2e"
    binds:
    - /dev:/dev
    capabilities:
    - CAP_SYS_ADMIN
    - CAP_MKNOD
    - name: mount
    image: "linuxkit/mount:d2669e7c8ddda99fa0618a414d44261eba6e299a"
    binds:
    - /dev:/dev
    - /var:/var:rshared,rbind
    capabilities:
    - CAP_SYS_ADMIN
    rootfsPropagation: shared
    command: ["/mount.sh", "/var/lib/docker"]
    services:
    - name: rngd
    image: "linuxkit/rngd:3dad6dd43270fa632ac031e99d1947f20b22eec9"
    capabilities:
    - CAP_SYS_ADMIN
    oomScoreAdj: -800
    readonly: true
    - name: dhcpcd
    image: "linuxkit/dhcpcd:57a8ef29d3a910645b2b24c124f9ce9ef53ce703"
    binds:
    - /var:/var
    - /tmp/etc:/etc
    capabilities:
    - CAP_NET_ADMIN
    - CAP_NET_BIND_SERVICE
    - CAP_NET_RAW
    net: host
    oomScoreAdj: -800
    - name: ntpd
    image: "linuxkit/openntpd:a570316d7fc49ca1daa29bd945499f4963d227af"
    capabilities:
    - CAP_SYS_TIME
    - CAP_SYS_NICE
    - CAP_SYS_CHROOT
    - CAP_SETUID
    - CAP_SETGID
    net: host
    - name: redis
    image: "redis:3.0.7-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
    outputs:
    - format: kernel+initrd
    

    现在快速地查看下这个文件。在没有展开更详尽的介绍之前(那些在 LinuxKit git repo 中可以看到的),我们将聚焦在以下要点上——

    开始的部分是“基础”镜像,定义了 Kernel 和 Kernel 命令行参数;

    紧接着,是一些 Init 所需的 OCI 兼容的 LinuxKit 镜像;在此之后,是 Onboot 部分,里面描述的是另外一些需要再其他服务启动之前由 RunC 顺序启动的基础镜像;

    再之后就是服务( Services )了,同样是 OCI 兼容的镜像,由 Containerd 启动并保持运行状态。

    最后,指定构建过程中 Moby 将要创建的输出文件信息。下面,构建镜像。

    $ moby build linux-redis
    

    下列是可以看到的输出信息——

    Extract kernel image: linuxkit/kernel:4.9.x
    Add init containers:
    Process init image: linuxkit/init:63eed9ca7a09d2ce4c0c5e7238ac005fa44f564b
    Process init image: linuxkit/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
    Process init image: linuxkit/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b
    Process init image: linuxkit/ca-certificates:eabc5a6e59f05aa91529d80e9a595b85b046f935
    Add onboot containers:
    Create OCI config for linuxkit/sysctl:1f5ec5d5e6f7a7a1b3d2ff9dd9e36fd6fb14756a
    Create OCI config for linuxkit/sysfs:6c1d06f28ddd9681799d3950cddf044b930b221c
    Create OCI config for linuxkit/binfmt:8881283ac627be1542811bd25c85e7782aebc692
    Create OCI config for linuxkit/format:53748000acf515549d398e6ae68545c26c0f3a2e
    Create OCI config for linuxkit/mount:d2669e7c8ddda99fa0618a414d44261eba6e299a
    Add service containers:
    Create OCI config for linuxkit/rngd:3dad6dd43270fa632ac031e99d1947f20b22eec9
    Create OCI config for linuxkit/dhcpcd:57a8ef29d3a910645b2b24c124f9ce9ef53ce703
    Create OCI config for linuxkit/openntpd:a570316d7fc49ca1daa29bd945499f4963d227af
    Create OCI config for redis:3.0.7-alpine
    Add files:
    etc/docker/daemon.json
    Create outputs:
    linux-redis-bzImage linux-redis-initrd.img linux-redis-cmdline
    

    以下是创建的文件:

    The raw kernel image (linux-redis-bzImage)
    The init  ramdisk (linux-redis-initrd.img)
    The commandline options youll need to provide to xhyve in a file
    

    运行和输出

    现在已经建立镜像,准备运行。

    首先,必须要创建一个告诉 Xhyve 如何实例镜像作为虚拟机的脚本。在这之前,着重强调,可以通过 Moby 工具输出一个 Qcow image。

    接着使用 Moby run 如同 VM 一样运行 Image。推荐使用 Xhyve,因为现在没有其他的 Non-linuxkt 操作系统能够在 Hypervisor 架构上运行。

    下面需要做一件事来运行镜像:一个为了建立虚拟机而定义的 Xhyve 参数的本。在这个脚本中主要的项目是从 Moby 构建流程中获取的。

    下面是一个启动 Redis server 的例子:

    $ vi linux-redis.sh
    #!/bin/sh
    
    KERNEL="linux-redis-bzImage"
    INITRD="linux-redis-initrd.img"
    CMDLINE="console=ttyS0 console=tty0 page_poison=1"
    
    MEM="-m 1G"
    PCI_DEV="-s 0:0,hostbridge -s 31,lpc"
    LPC_DEV="-l com1,stdio"
    ACPI="-A"
    #SMP="-c 2"
    
    # sudo if you want networking enabled
    NET="-s 2:0,virtio-net"
    
    xhyve $ACPI $MEM $SMP $PCI_DEV $LPC_DEV $NET -f kexec,$KERNEL,$INITRD,"$CMDLINE"
    

    一旦文件已经创建,使之可执行并且运行它。目前的环节中有些需要注意的事项:

    1、如果有任何 VPN 连接到无线网络上,请关掉它。因为当 VPN 运行时会有一些已知的流量路径问题。

    2、如果准备网络连接虚拟机,需要执行一些超级用户的脚本。

    当没问题后运行它:

    $ chown 755 linux-redis.sh
    $ sudo ./linux-redis.sh
    

    当虚拟机运行的时候将有一组 Output 会 Fly,最后,在新虚拟机上得到一个命令行:

    Welcome to LinuxKit
    
                           ##         .
                      ## ## ##        ==
                   ## ## ## ## ##    ===
               /"""""""""""""""""\___/ ===
          ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
               \______ o           __/
                 \    \         __/
                  \____\_______/
    
    / # [ 2.125127] IPVS: Creating netns size=2104 id=1
    [ 2.125466] IPVS: ftp: loaded support on port[0] = 21
    [ 2.156114] IPVS: Creating netns size=2104 id=2
    [ 2.156496] IPVS: ftp: loaded support on port[0] = 21
    [ 2.177714] tsc: Refined TSC clocksource calibration: 2193.340 MHz
    [ 2.178170] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x1f9d9f9c94d, max_idle_ns: 440795310624 ns
    [ 2.399509] IPVS: Creating netns size=2104 id=3
    [ 2.400027] IPVS: ftp: loaded support on port[0] = 21
    [ 2.670029] IPVS: Creating netns size=2104 id=4
    [ 2.670555] IPVS: ftp: loaded support on port[0] = 21
    [ 2.773492] random: dhcpcd: uninitialized urandom read (112 bytes read)
    [ 2.791653] random: redis-server: uninitialized urandom read (19 bytes read)
    [ 2.792066] random: redis-server: uninitialized urandom read (1024 bytes read)
    [ 2.911251] IPVS: Creating netns size=2104 id=5
    [ 2.911770] IPVS: ftp: loaded support on port[0] = 21
    [ 2.935150] random: rngd: uninitialized urandom read (16 bytes read)
    [ 2.955187] random: crng init done
    [ 3.187797] clocksource: Switched to clocksource tsc
    
    / #
    

    当 Redis server 正在运行时,看看发生了什么:

    / # netstat -an
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address Foreign Address State
    tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN
    tcp 0 0 :::6379 :::* LISTEN
    udp 0 0 192.168.64.17:44773 52.6.160.3:123 ESTABLISHED
    udp 0 0 192.168.64.17:44091 208.75.89.4:123 ESTABLISHED
    udp 0 0 0.0.0.0:68 0.0.0.0:*
    udp 0 0 192.168.64.17:33429 192.96.202.120:123 ESTABLISHED
    udp 0 0 192.168.64.17:39584 69.89.207.99:123 ESTABLISHED
    raw 0 0 ::%192:58 ::%32631:* 58
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags Type State I-Node Path
    unix 2 [ ACC ] STREAM LISTENING 14907 /var/run/dhcpcd.sock
    unix 2 [ ACC ] STREAM LISTENING 14909 /var/run/dhcpcd.unpriv.sock
    unix 2 [ ACC ] STREAM LISTENING 14248 /run/containerd/debug.sock
    unix 2 [ ACC ] STREAM LISTENING 14258 /run/containerd/containerd.sock
    unix 2 [ ACC ] STREAM LISTENING 15051 /var/run/ntpd.sock
    unix 3 [ ] STREAM CONNECTED 15055
    unix 3 [ ] STREAM CONNECTED 15050
    unix 2 [ ] DGRAM 15025
    unix 3 [ ] STREAM CONNECTED 15054
    unix 3 [ ] STREAM CONNECTED 15049
    / #
    

    看起来机器的 Redis 默认端口是 6379。现在,看它是否在网络上可以被看到和获取。首先,找到虚拟机的 IP 地址:

    / # ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 brd 127.255.255.255 scope host lo
    valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
    valid_lft forever preferred_lft forever
    2: bond0: <BROADCAST,MULTICAST400> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether ca:41:0c:a4:ea:c2 brd ff:ff:ff:ff:ff:ff
    3: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 1a:23:2d:47:af:d5 brd ff:ff:ff:ff:ff:ff
    4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether f2:94:56:b6:96:93 brd ff:ff:ff:ff:ff:ff
    inet 192.168.64.17/24 brd 192.168.64.255 scope global eth0
    valid_lft forever preferred_lft forever
    inet6 fe80::f094:56ff:feb6:9693/64 scope link
    valid_lft forever preferred_lft forever
    5: teql0: mtu 1500 qdisc noop state DOWN qlen 100
    link/void
    6: tunl0@NONE: mtu 1480 qdisc noop state DOWN qlen 1
    link/ipip 0.0.0.0 brd 0.0.0.0
    7: gre0@NONE: mtu 1476 qdisc noop state DOWN qlen 1
    link/gre 0.0.0.0 brd 0.0.0.0
    8: gretap0@NONE: <BROADCAST,MULTICAST> mtu 1462 qdisc noop state DOWN qlen 1000
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    9: ip_vti0@NONE: mtu 1332 qdisc noop state DOWN qlen 1
    link/ipip 0.0.0.0 brd 0.0.0.0
    10: ip6_vti0@NONE: mtu 1500 qdisc noop state DOWN qlen 1
    link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
    11: sit0@NONE: mtu 1480 qdisc noop state DOWN qlen 1
    link/sit 0.0.0.0 brd 0.0.0.0
    12: ip6tnl0@NONE: mtu 1452 qdisc noop state DOWN qlen 1
    link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
    13: ip6gre0@NONE: mtu 1448 qdisc noop state DOWN qlen 1
    link/[823] 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
    

    ip 地址是 192.168.64.17,从 Max OS X 主机,使用 Netcat 测试连接状态和服务器状态:

    $ nc 192.168.64.17 6379
    ping
    +PONG
    

    一旦完成 Poking around,键入 halt 关闭虚拟机

    / # halt
    

    结束语

    现在我们就有了一个运行在 OS X 虚拟机中的可用的 LinuxKit image。 然而这也仅仅只是一个开始,可以用这个模板来创建其他镜像,定制你想要的东西。同时,不是一定需要使用 Redis,尝试替换成你自己服务的 Docker images,启动虚拟机。

    在之后的文章中,我还会尝试使用其他的 Moby projece tools,比如 Infrakit 和 Hyperkit,通过使用他们来展示 Linuxkt OS Images 更多的能力。

    原文链接: http://www.nebulaworks.com/blog/2017/04/23/getting-started-linuxkit-mac-os-x-xhyve/

    欢迎关注数人云微信公众号,如有后续文章我们会第一时间进行跟进!

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3006 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 14:47 · PVG 22:47 · LAX 06:47 · JFK 09:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.