超譯
https://gianarb.it/blog/linuxkit-operating-system-build-for-containers
超譯目的:
linuxkit 是什麼?從這篇來了解 linuxkit 是什麼。
內容:
Linuxkit 是 Docker 在 DockerCon 2017 呈現的的新專案。在 GitHub 的專案描述為:
一個安全,可攜、玲瓏的操作系統,為了容器而打造。
我已非常興奮,在 Justin Cormack 與其他貢獻者在其為私人庫的時候,我已經在觀察這專案。我也被邀請以 ci-wg 團隊的角色進入 CNCF,從第一天開始我就喜愛這專案。
你可想像,linuxkit 是個建立者,建立基於容器的 Linux 操作系統的所有東西。
這專案可以留在持續整合系統(CI system),讓我們可測試不同的核心版本與散佈。你可用小核心帶著你所需的所有服務,你可以利用 Docker 或 QEMU 建立不同的可執行服務在雲端上,例如谷歌雲平台。
持續交付,新模式
我對谷歌雲平台沒很大信心,我想用 AWS 為服務供應者來做些數學。假設我已經有最一般的持續整合系統,一個大盒子持續執行已設定好的工作,支援你所有的專案。或是你已經有可用的容器,擁有獨立分開的環境。
假設你的 jenkins 已經準備好在 m3.xlarge:
m3.xlarge
每月吃到吐會花掉 $194.72。
來做夢一下,你有一個非常小的伺服器,它只是個前端程式,讓你的 CI 與所有工作執行在不同的實體上,如同 t2.small
這麼小。
t2.small
使用一個小時要付 $0.72。
我算一個小時是因為付錢的最小單位為小時,我希望你的 CI job 可以跑低於一小時。簡單算一下要付多少錢,就像你以前付錢一樣。
194.72 / 0.72 ~ 270 大約是每月 270 個 build。
如果你一個月跑少於 270 個 build 的話,你可以省下一些錢。但你可以有其他的益處:
- 更多的 job,更多的實體。非常容易擴展。對 Jenkins master/slave 等更容易些。
- 有多少時間是假日,你的 Jenkins 仍然開啟但沒事可做?這些日子你仍然要為那前端付錢。
你的持續交付的不同設計,會有這些不同的益處。
LinuxKit CI 實作
這裡有個目錄叫 ./test 它包含一些 linuxkit 的使用例。我會解釋實務上 linuxkit 如何被測試。因為它自己用自己,超酷的!
首先你需要下載並編譯 linuxkit:
git clone github.com:linuxkit/linuxkit $GOPATH/src/github.com/linuxkit/linuxkit
make
./bin/moby
你可以把它搬到你的 $PATH
(使用 make install)。
$ moby
Please specify a command.
USAGE: moby [options] COMMAND
Commands:
build Build a Moby image from a YAML file
run Run a Moby image on a local hypervisor or remote cloud
version Print version information
help Print this message
Run 'moby COMMAND --help' for more information on the command
Options:
-q Quiet execution
-v Verbose execution
在這時間點,CLI
還是很簡單,最重要的指令是建立與執行。linuxkit 是建基於 YAML 檔,它可以描述你的核心,需要什麼應用與服務。我們從 linuxkit/test/test.yml 開始。
kernel:
image: "mobylinux/kernel:4.9.x"
cmdline: "console=ttyS0"
init:
- mobylinux/init:8375addb923b8b88b2209740309c92aa5f2a4f9d
- mobylinux/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
- mobylinux/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b
- mobylinux/ca-certificates:eabc5a6e59f05aa91529d80e9a595b85b046f935
onboot:
- name: dhcpcd
image: "mobylinux/dhcpcd:0d4012269cb142972fed8542fbdc3ff5a7b695cd"
binds:
- /var:/var
- /tmp:/etc
capabilities:
- CAP_NET_ADMIN
- CAP_NET_BIND_SERVICE
- CAP_NET_RAW
net: host
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
- name: check
image: "mobylinux/check:c9e41ab96b3ea6a3ced97634751e20d12a5bf52f"
pid: host
capabilities:
- CAP_SYS_BOOT
readonly: true
outputs:
- format: kernel+initrd
- format: iso-bios
- format: iso-efi
- format: gcp-img
linuxkit 會建立所有的東西在一個容器裡面,這表示你不需要一堆相依,它非常容易使用。它產生不同的 output
,在這例子有 kernel+initrd
、iso-bios
、iso-efi
、gcp-img
,它相依於你想要執行的核心的平台。
我多解釋一下這 YAML 如何工作的。你可以看到有不同的主要區段:kernel
、init
、onboot
、service
與其他。
幾乎每個都有個關鍵字 image
,就如我之前所說,因為每個東西都用在容器上,在這例子都存在 hub.docker.com/u/mobylinux/ 裡。
基礎的核心是 mobylinux/kernel:4.9.x
,README.md說:
kernel
指定 Docker image 的核心,包含核心與檔案系統的 tarball,eg 包含 modules。這例子的核心是從kernel/
所建立。init
是 Docker image 基礎的init
行程,這是由基礎系統所取出來的,包含init
、containerd
、runc
與一些其他工具。其由pkg/init/
所建立。onboot
是系統容器,按順序執行,他們應該做完事就馬上結束。services
是系統服務,它們會在系統開啟之後一直執行。files
是額外加入 image 的檔案。outputs
是描述哪些要建立的東西,像是 ISO 之類的。
到此,我們可以試,如果你在 MacOS 上,你不需要安裝任何東西,只要一個被 linuxkit 支援的 hyperkit 就可以了。
./test
包含不同的測試,但現在我們先專注在 ./test/check
的目錄。這包含一組檢定,確認這核心怎麼被 LinuxKit 建立。舉例來說,它們是 smoke test,在每次新的 pull request 被建在庫時被執行。
就如我之前說,每個東西都在容器內執行,如果你看 check 目錄,那裡有個 makefilie,它會建立一個 mobylinux/check image,在 test.yml
裡面是這樣:
onboot:
- name: check
image: "mobylinux/check:c9e41ab96b3ea6a3ced97634751e20d12a5bf52f"
pid: host
capabilities:
- CAP_SYS_BOOT
readonly: true
你可以用這 check 目錄的 Makefile 來建立一個新版的 check,只要使用這指令 make
。
當你有正確版本的測試,我們可以用 moby 來建立 image:
cd $GOPATH/src/github.com/linuxkit/linuxkit
moby build test/test.yml
它的部份輸出:
Create outputs:
test-bzImage test-initrd.img test-cmdline
test.iso
test-efi.iso
test.img.tar.gz
這目錄裡面,你會看到有許多根目錄下所有的檔案,這些檔案可用 qemu 執行,可用谷歌雲平台執行,可用 hyperkit 執行…等。
moby run test
在 MacOS 用 LinuxKit 這指令是使用 hyperkit 去啟動一個 VM,我無法把所有的輸出都貼出來,但你可以看 hypervisor 的記錄:
virtio-net-vpnkit: initialising, opts="path=/Users/gianlucaarbezzano/Library/Containers/com.docker.docker/Data/s50"
virtio-net-vpnkit: magic=VMN3T version=1 commit=0123456789012345678901234567890123456789
Connection established with MAC=02:50:00:00:00:04 and MTU 1500
early console in extract_kernel
input_data: 0x0000000001f2c3b4
input_len: 0x000000000067b1e5
output: 0x0000000001000000
output_len: 0x0000000001595280
kernel_total_size: 0x000000000118a000
booted via startup_32()
Physical KASLR using RDRAND RDTSC...
Virtual KASLR using RDRAND RDTSC...
Decompressing Linux... Parsing ELF... Performing relocations... done.
Booting the kernel.
[ 0.000000] Linux version 4.9.21-moby (root@84baa8e89c00) (gcc version 6.2.1 20160822 (Alpine 6.2.1) ) #1 SMP Sun Apr 9 22:21:32 UTC 2017
[ 0.000000] Command line: earlyprintk=serial console=ttyS0
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
[ 0.000000] x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: 256
[ 0.000000] x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
[ 0.000000] x86/fpu: Using 'eager' FPU context switches.
[ 0.000000] e820: BIOS-provided physical RAM map:
[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000003fffffff] usable
當 VM 準備好,LinuxKit 會啟動所有的 init
、onboot
,這些記錄非常好懂,像 test.yml
啟動 containerd
與 runc
:
init:
- mobylinux/init:8375addb923b8b88b2209740309c92aa5f2a4f9d
- mobylinux/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
- mobylinux/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b
- mobylinux/ca-certificates:eabc5a6e59f05aa91529d80e9a595b85b046f935
onboot:
- name: dhcpcd
image: "mobylinux/dhcpcd:0d4012269cb142972fed8542fbdc3ff5a7b695cd"
binds:
- /var:/var
- /tmp:/etc
capabilities:
- CAP_NET_ADMIN
- CAP_NET_BIND_SERVICE
- CAP_NET_RAW
net: host
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
- name: check
image: "mobylinux/check:c9e41ab96b3ea6a3ced97634751e20d12a5bf52f"
pid: host
capabilities:
- CAP_SYS_BOOT
readonly: true
Welcome to LinuxKit
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
/ # INFO[0000] starting containerd boot... module=containerd
INFO[0000] starting debug API... debug="/run/containerd/debug.sock" module=containerd
INFO[0000] loading monitor plugin "cgroups"... module=containerd
INFO[0000] loading runtime plugin "linux"... module=containerd
INFO[0000] loading snapshot plugin "snapshot-overlay"... module=containerd
INFO[0000] loading grpc service plugin "healthcheck-grpc"... module=containerd
INFO[0000] loading grpc service plugin "images-grpc"... module=containerd
INFO[0000] loading grpc service plugin "metrics-grpc"... module=containerd
最後一步是 check
,它執行真正的測試套裝:
kernel config test succeeded!
info: reading kernel config from /proc/config.gz ...
Generally Necessary:
- cgroup hierarchy: properly mounted [/sys/fs/cgroup]
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: enabled
- CONFIG_CGROUP_SCHED: enabled
........
.......
Moby test suite PASSED
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
[ 3.578681] ACPI: Preparing to enter system sleep state S5
[ 3.579063] reboot: Power down
最後的記錄是 check-kernel-config.sh
的產出。
如果你使用 linux
,你可以用相同的指令,但預設你是使用 qemu,它是一個開源機器模擬器。
sudo apt-get install qemu
我的 Asus Zenbook 是裝 Ubuntu,我在它上面測試,當我執行 moby run
,它會用 qemu 來執行其指令:
/usr/bin/qemu-system-x86_64 -device virtio-rng-pci -smp 1 -m 1024 -enable-kvm
-machine q35,accel=kvm:tcg -kernel test-bzImage -initrd test-initrd.img -append
console=ttyS0 -nographic
預設是在 x86_64
上測試,但 qemu 支援其他的架構與裝置。與例來說,你可以模擬一個 arm 與樹莓派。在這時點,LinuxKit 還沒準備好支援其他架構。但這是此專案的主要範圍。這只是時間問題,應該很快!
偵測一個 build 是否成功可能不如你所想的簡單。這 VM 內的狀態不是你從筆電內取得的那一個。在這時候要了解你的 PR 內的程式碼好或不好,我們是這樣解析輸出的:
define check_test_log
@cat $1 |grep -q 'Moby test suite PASSED'
endef
現在解釋 linuxkit 自我測試是如何工作的,正是解釋它本身如何工作的最好方法。這正好是拼圖的一片,如果你看過 every pr 它有個 GitHub 狀態,裡面指到一個網站,它有一些特殊 build 的記錄。那些不在 linuxkit 的管理之內,因為它只是一個 builder 用來建立環境的。其餘是被 datakit 所管。我會在另一個貼文談到。
結論
runc、docker、containerd、rkt,還有 Prometheus、InfluxDB、Telegraf 很多專案支援不同的架構,它們需要用不同的設定與能力在不同的核心上執行。它們需要在你的筆電上跑,在你的 IBM 伺服器跑,在樹莓派上跑。
這專案還在早期階段,但我了解為何 Docker 需要類似的東西,如我所言,其他專案需要這種東西以獲得一些益處。讓它開源,是非常好的,而且我很榮幸成為此驚艷專案的其中一員。我做了一些最終測試並嘗試了解它如何設計與工作。這是我測試的結果。我希望這篇文章能對給予正確觀念上幫上一些忙。
我計畫是建立一組設定來測試 InfluxDB 且用 qemu
讓它在不同架構與裝置測試。敬請期待新的貼文。
一些連結:
- INTRODUCING MOBY PROJECT: A NEW OPEN-SOURCE PROJECT TO ADVANCE THE SOFTWARE CONTAINERIZATION MOVEMENT
- github.com/linuxkit
- github.com/moby
審閱者: Justin Cormack