1. 程式人生 > 實用技巧 >一種混合包管理和容器管理方案,及在tinycorelinux上安裝containerd和openfaas

一種混合包管理和容器管理方案,及在tinycorelinux上安裝containerd和openfaas

本文關鍵字:在tinycorelinux上裝docker,virtual appliance vs virtual appstack,no cgroup mount found in mountinfo: unknown,jailing process inside rootfs caused: pivot_root invalid argument: unknown

在《利用openfaas faasd在你的雲主機上部署function serverless面板》 和《panel.sh:一個nginx+docker的雲函和線上IDE面板,發明你自己的paas(1),(2)》文中,我們談到openfaas是一種基於containerd(docker官方經過對舊docker進行模組化重構後得到的二進位制級的可複用結構,作為容器的執行時實現存在,containerd+runc+cni是預設的代替原docker的選型,

https://github.com/containerd/containerd/releases也是把cni,containerd,runc這樣打包一起的)的雲函式面板,《tinycorelinux上編譯安裝lxc,lxd》《tinycorelinux上裝ovz》這些文章也都是在linux上容器選型的例子。

容器化為什麼這麼重要,因為容器是現在最流行的virtual cloud appliance(cloud appliance化是app部署級別的融合,代表著“為雲APP造一種包結構”,你可以將其簡單理解為雲軟體包,cloud appliance要與app開發用的內部cloud appstack融合化區別開)代表,作為統一部署方案,它主要關注解決叢集和雲上那些“軟體發行資源配額的隔離”問題,軟體的資源配額從來都是一個複雜的關聯問題,可巧這些問題在本地和原生的包管理軟體中(包主要關注解決依賴問題)也存在,linux上提供了統一的整套核心級支援方案(比如liblxc,libcgroups,基於它們+brtfs可以完全用shell發明一套簡單的docker執行時,當然這跟我們需要的,最終完備的容器和容器管理系統containerd,openfaas是沒法比的),另一方面,“資源隔離”稍微更進一步,就很容易與“軟體怎麼樣啟動”這些問題相關聯,變成systemd這類軟體要解決的問題(systemd-nspawn可以建立最輕量級的容器),進而變成k8s這類軟體要解決的問題。所以,這三大問題融合和關聯發生在方方面面,,很容易成為某種“混合包管理和容器管理”融合體系要解決的中心問題,進而需要這樣一種軟體,core os的https://github.com/rkt/rkt就是這一類軟體的代表併為此構建出一個基於容器作為包管理的OS(雖然2020年中期它們準備dreprecate了)。

這就是說,容器化的實現可以簡單也可以複雜,不同OS也有整合不同複雜容器管理的方案,除了core os的rkt這種,tc的tce pkg本身就是一種沙盒環境,不過它與上述提到的lxc,ovz,containerd這些真正意義的容器化沒有關係。前述與openfaas相關的這些文章都是在流行的linux發行版中實踐裝openfaas的例子,接下來的本文將介紹嘗試在tinycorelinux11中裝真正的容器,即containerd和openfaas的安裝實踐過程。

這裡的主要問題是,tc本身是一種raw linux發行版,追求小和簡單,一般地,跟alpine一樣tc往往作為容器guest os如boot2docker,鮮少在tc上裝containerd作為容器伺服器環境,因此,在tc中裝容器可能會因為沒有現成參考方案而顯得繁瑣。比如,tc也沒有使用systemd這類複雜的init啟動管理系統而是簡單的sysv init(雖然systemd提出了一個巨大的init pid 1,但是它只關注“啟動”,這點上,它還是符合kiss的)。一般linux發行都是依賴systemd處理容器設定的一些至關重要的基礎問題,比如稍後我們會談到systemd自動管理cgroups,,而這些在tc中都沒有,需要手動還不見得能解決,

不管了,下面開始嘗試實踐,我們的測試環境是tc11。

1,製造一個containerd.tcz和faasd.tcz

準備一個集成了openssh,sudo passwd tc,做好了bootcode tce=sda1,echo過 /opt/tcemirror,/etc/passwd,/etc/shadow > /mnt/sda1/opt/.filetool.lst,tar 進restore=sda1 mydata.gz的基本ezremasterd tc11 iso,即《一個fully retryable的rootbuild packer指令碼,從0打造matecloudos(2)》中第一小節那樣的iso。我們開啟二個引導了這個iso的虛擬機器,都用parted格好sda1,這二虛擬機器準備一個生成containerd.tcz和faasd.tcz用(生成後在其目錄下python -m SimpleHTTPServer 80供以後下載,事先ifconfig看好ip),另一個測試生成的tcz(/opt/tcemirror設成第一臺地址+11.x/x86_64/tcz正確的結構),在第一臺虛擬機器的/mnt/sda1根目錄中,安排這些檔案:

準備資料夾結構和binaries:
docker採用前述文章的版本組合而成(做二資料夾一個containerd-root,其中cni放在/opt/cin/bin,runc放在/usr/local/sbin,containerd放在/usr/local/bin,一個faasd-root,其中放/usr/local/bin/faasd,faas-cli,最後,前文提到的幾個offline docker image也集進來放在faasd-root/tmp/*.tar)。這些exe設好chmod +x,由於這些exe都是go的,都是靜態連結的,在tc11上可直接執行(lib64一定要ln -s 一下到lib,否則ctr不能起作用)。

準備幾個配置檔案:
一些containerd和faasd啟動時的動態檔案,不用建立。否則會導致只讀檔案系統無法寫入錯誤
/etc/cni/net.d/10-openfaas.conflist
/var/lib/faasd/secrets/*
/var/lib/faasd/resolv.conf
/var/lib/faasd-provider/resolv.conf
這些檔案必須要
/var/lib/faasd/docker-compose.yaml
/var/lib/faasd/prometheus.yml

準備overlay module:
在第一臺中tce-load -iw bc compiletc perl5重新編譯kernel,在config中把config_overy_fs開啟為m,得到overlay module,因為它在tc11中被關閉了。下載tc11中所需的kernel編譯檔案http://mirrors.163.com/tinycorelinux/11.x/x86_64/release/src/kernel/到/mnt/sda1
解壓並cp config-5.4.3-tinycore64 linux-5.4.3/.config
sudo make oldconfig,提示幾個互動項直接回車
sudo make install
sudo make modules_install
把得到的overlay module file(在/lib/modules/fs中)放到準備打包的containerd.tcz資料夾結構中。

準備2個服務檔案並分別chmod +x:
containerd-root/usr/local/init.d/start-containerd:
/sbin/modprobe overlay
/usr/local/bin/containerd
containerd-root/usr/local/init.d/start-faasd:
for i in 1 2 3; do [[ ! -z "$(ctr image list|grep basic-auth-plugin)" ]] && break;ctr --address=/run/containerd/containerd.sock image import /tmp/faasd-containers/basic-auth-plugin-0.18.18.tar;echo "checking basic-auth ($i),if failed at 3,it may require a reboot"; sleep 3;done         
for i in 1 2 3; do [[ ! -z "$(ctr image list|grep nats)" ]] && break;ctr --address=/run/containerd/containerd.sock image import /tmp/faasd-containers/nats-streaming-0.11.2.tar;echo "checking nats ($i),if failed at 3,it may require a reboot"; sleep 3;done                                
for i in 1 2 3; do [[ ! -z "$(ctr image list|grep prometheus)" ]] && break;ctr --address=/run/containerd/containerd.sock image import /tmp/faasd-containers/prometheus-v2.14.0.tar;echo "checking prometheus ($i),if failed at 3,it may require a reboot"; sleep 3;done                       
for i in 1 2 3; do [[ ! -z "$(ctr image list|grep gateway)" ]] && break;ctr --address=/run/containerd/containerd.sock image import /tmp/faasd-containers/gateway-0.18.18.tar;echo "checking gateway ($i),failed at 3,it may require a reboot"; sleep 3;done                                   
for i in 1 2 3; do [[ ! -z "$(ctr image list|grep queue-worker)" ]] && break;ctr --address=/run/containerd/containerd.sock image import /tmp/faasd-containers/queue-worker-0.11.2.tar;echo "checking queueworker ($i),if failed at 3,it may require a reboot"; sleep 3;done
cd /var/lib/faasd
/usr/local/bin/faasd provider
/usr/local/bin/faasd up

準備mkall.sh放到/mnt/sda1根下chmod +x起來:
mkall.sh的內容(注意到統一作為tc:staff存放到tcz中):
rm -rf containerd.tcz containerd.tcz.md5.txt faasd.tcz faasd.tcz.md5.txt faasd.tcz
mksquashfs containerd-root containerd.tcz -noappend -no-fragments -force-uid tc
md5sum containerd.tcz > containerd.tcz.md5.txt
mksquashfs faasd-root faasd.tcz -noappend -no-fragments -force-uid tc -force-gid staff
md5sum faasd.tcz > faasd.tcz.md5.txt
echo containerd.tcz > faasd.tcz.dep

sudo ./mkall.sh打包好的tcz各80多m,準備好後我們就可以在第二臺測試了,tce-load -iw faasd後經過測試不滿意可刪除/mnt/sda1/tce/optional下的tcz重啟重來,我們需要不斷mkall並測試生成的二個tcz。

2,測試

第一次測試啟動start-containerd,start-faasd,出現:no cgroup mount found in mountinfo: unknown這就是上面談到tc11不具有自動處理cgroups的邏輯。而containerd依賴它們。tc11中的kernel config中提供了linux對容器的核心支援基礎,只是沒有更進一步。

CGroup 提供了一個 CGroup 虛擬檔案系統,作為進行分組管理和各子系統設定的使用者介面。要使用 CGroup,必須掛載 CGroup 檔案系統。這時通過掛載選項指定使用哪個子系統。
需要注意的是,在使用 systemd 系統的作業系統中,/sys/fs/cgroup 目錄都是由 systemd 在系統啟動的過程中掛載的,並且掛載為只讀的型別。換句話說,系統是不建議我們在 /sys/fs/cgroup 目錄下建立新的目錄並掛載其它子系統的。這一點與之前的作業系統不太一樣。

針對於此,很幸運我們找到了https://gitee.com/binave/tiny4containerd/blob/master/src/rootfs/usr/local/etc/init.d/cgroupfs.sh,它使用old docker,並且基於https://github.com/tianon/cgroupfs-mount/(這個工程https://gitee.com/binave/tiny4containerd/src/rootfs/usr/local/這裡的lvm動態擴充套件分割槽指令碼和docker服務,cert處理等函式也不錯,可為未來所用),裡面有幾句。

mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup

如果你沒有上面這句mount 接下來會mkdir: can't create directory 'cpu': No such file or directory,因為/sys/fs/cgroup只是核心給的fake fs

cd /sys/fs/cgroup;

# get/mount list of enabled cgroup controllers
for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do
    mkdir -p $sys
    if ! _mountpoint -q $sys; then
        if ! mount -n -t cgroup -o $sys cgroup $sys; then
            rmdir $sys || true
        fi
    fi
done

我們把cgroupfs放跟containerd-root/usr/local/etc/init.d/containerd並排,在containerd指令碼中啟動containerd前加入/usr/local/etc/init.d/cgroupfs.sh mount這句。打包再測試:出現jailing process inside rootfs caused: pivot_root invalid argument: unknown(我也一直沒有測試https://gitee.com/binave/tiny4containerd/中的docker會不會出現這錯誤,不過聽說有遇到了https://forums.docker.com/t/tinycore-8-0-x86-pivot-root-invalid-argument/32633),

In a system running entirely in memory, after an upgrade from 17.09.1-ce to 17.12.0-ce, docker stopped creating containers, failing with message like docker: Error response from daemon: OCI runtime create failed: container_linux.go:296: starting container process caused "process_linux.go:398: container init caused "rootfs_linux.go:107: jailing process inside rootfs caused \"pivot_root invalid argument\""": unknown..

查網上說要使用DOCKER_RAMFS=true環變,我試了沒用。

在其它非tc上相似的容器產品也有人遇到了:https://engineeringjobs4u.co.uk/how-we-use-hashicorp-nomad,針對於此它們做了一個核心補丁:https://lore.kernel.org/linux-fsdevel/[email protected]/

The main need for this is to support container runtimes on stateless Linux system (pivot_root system call from initramfs). Normally, the task of initramfs is to mount and switch to a "real" root filesystem. However, on stateless systems (booting over the network) it is just convenient to have your "real" filesystem as initramfs from the start.

對linux543/fs/namespace.c進行手動patch,mnt_init()定義前增加,和中間增加新加的程式碼。但是沒用。因此按《利用hashicorp packer把dbcolinux匯出為虛擬機器和docker格式(3)》的方法轉為傳統硬碟安裝方式。問題解決。

然後又出現了:
Error creating CNI for basic-auth-plugin: Failed to setup network for task "basic-auth-plugin-1210": failed to create bridge "openfaas0": could not add "openfaas0": operation not supported: failed to create bridge "openfaas0": could not add "openfaas0": operation not supported

這個問題其實在意料之中,因為從前面文章的經驗來看,我們一直對containerd中的那個cni必須要起作用留了個心,可是faasd up產生了10openfaas.conflist後,我一直嘗試ifconfig,都沒看到第三個網絡卡。

網上有人提示說是CONFIG_BRIDGE_VLAN_FILTERING,看tc11的kernel,config_bridge被作為模組了,它的file應該是bridge.ko之類。但modprobe bridge沒用,tce-load -iw original-modules-5.4.3-tinycore64,這下成功了。(安裝了這個包之後,控制檯顯示好多裝置都認到了)

再測試:
Error: Failed to setup network for task "basic-auth-plugin-3894": failed to locate iptables: exec: "iptables": executable file not found in $PATH: failed to locate iptables: exec: "iptables": executable file not found in $PATH,需要tce-load -iw iptables,

至此,faad up啟動成功。containerd控制檯顯示warning,memory cgroup not supported,應該是kernel config,又沒設好。

我們接下來要做的,就是把usr/local/etc/init.d下的幾個服務檔案做完善點。參考https://github.com/MSumulong/vmware-tools-on-tiny-core-linux/blob/tiny-core-6.3/additional-files/etc/init.d/open-vm-tools和https://gitee.com/binave/tiny4containerd/blob/master/src/rootfs/usr/local/etc/init.d/