k3s的單進(jìn)程模式如何運(yùn)行整個K8S服務(wù)

為了提升k3s的使用體驗(yàn),我們將推出由k3s開發(fā)人員撰寫的“k3s黑魔法”系列文章來詳細(xì)介紹k3s功能、原理等方面的內(nèi)容。本篇文章是該系列的第一篇,文章詳細(xì)分析了k3s的單進(jìn)程模式如何運(yùn)行整個Kubernetes服務(wù)。

同時,歡迎大家添加k3s助手(微信號:k3s2019),加入官方微信群和大家一起交流。

前 言

Rancher Labs一直致力于云基礎(chǔ)設(shè)施的建設(shè),我們發(fā)布了很多產(chǎn)品Rancher1.x、Rancher2.x、RancherOS、Longhorn、Rio等來滿足基礎(chǔ)設(shè)施應(yīng)用的各種場景,但這其中沒有一款產(chǎn)品可以和k3s的發(fā)展速度相比,整個社區(qū)對它的認(rèn)可超乎我們的想象。發(fā)布了僅僅10個月的k3s項(xiàng)目,就在Github上獲得超9000顆star數(shù),我們也正星夜兼程,爭取在11月份發(fā)布1.0GA版本。我將撰寫一系列文章來介紹k3s所使用的技術(shù)及其原理,尤其是這其中使用的一些黑魔法,它讓k3s的體驗(yàn)變得無比美好。更深入更細(xì)節(jié)得了解k3s,才能將它使用好,讓工具本身產(chǎn)生事半功倍的效用,同時也能讓大家有機(jī)會一起參與k3s社區(qū)的建設(shè)。

在這里插入圖片描述

很多人在體驗(yàn)k3s時,都對它的無比精簡感到折服。我們都了解Kubernetes(以下簡稱K8s)是個非常復(fù)雜的架構(gòu),controlplane中就包括apiserver/controller-manager/scheduler等,worker中還需要有kubelet/kube-proxy,元數(shù)據(jù)還需要存儲在etcd上。這些服務(wù)每一項(xiàng)都需要單獨(dú)部署,還需要進(jìn)行配置聯(lián)動,盡管我們可以借用很多開源工具(比如RKE),但是部署前你還是需要準(zhǔn)備大量鏡像或者二進(jìn)制文件等。k3s的部署就非常簡便,它通過一個binary就可以部署上面提到的大部分服務(wù),這也就是本文要介紹的內(nèi)容,k3s的黑魔法之一“單進(jìn)程k8s”。

單進(jìn)程k8s分析

我們先不管具體如何實(shí)現(xiàn),先來看一下單進(jìn)程k8s的表面現(xiàn)象。我們安裝一個k3s,但禁用agent,這樣更有利于觀察結(jié)果:

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable-agent" sh -

這時使用kubectl是看不到node信息,但是我們能夠獲取namespace信息,這就說明k8s的controlplane相關(guān)服務(wù)已經(jīng)啟動了:

# kubectl get no
No resources found in default namespace.
 
# kubectl get ns
NAME              STATUS   AGE
default           Active   10s
kube-system       Active   10s
kube-public       Active   10s
kube-node-lease   Active   10s

使用ps命令觀察k3s程序運(yùn)行結(jié)果,下方可以看到k3s只啟動了一個進(jìn)程:

# ps aux | grep k3s
root      1900  2.8 40.8 564468 411436 ?       Ssl  12:01   0:21 /usr/local/bin/k3s server --disable-agent

那么controlplane其他服務(wù)apiserver/scheduler/controller-manager等是如何啟動的,我們查看k3s對應(yīng)的thread:

# ps -T 1900
  PID  SPID TTY      STAT   TIME COMMAND
1900  1900 ?        Ssl    0:01 /usr/local/bin/k3s server --disable-agent
1900  1910 ?        Ssl    0:06 /usr/local/bin/k3s server --disable-agent
1900  1911 ?        Ssl    0:01 /usr/local/bin/k3s server --disable-agent
1900  1912 ?        Ssl    0:00 /usr/local/bin/k3s server --disable-agent
1900  1916 ?        Ssl    0:00 /usr/local/bin/k3s server --disable-agent
1900  1917 ?        Ssl    0:06 /usr/local/bin/k3s server --disable-agent
1900  1918 ?        Ssl    0:10 /usr/local/bin/k3s server --disable-agent
1900  1948 ?        Ssl    0:06 /usr/local/bin/k3s server --disable-agent
1900  1957 ?        Ssl    0:00 /usr/local/bin/k3s server --disable-agent

我們知道k3s是純粹Golang實(shí)現(xiàn)的,而Golang通常并不會直接使用thread,一般是通過goroutine來使用系統(tǒng)的thread,分析源碼中k3s server的實(shí)現(xiàn),可以看到api-server/scheduler等服務(wù)確實(shí)是goroutine來啟動的:

# https://github.com/rancher/k3s/blob/master/pkg/daemons/control/server.go
 
---------
go func() {
        logrus.Infof("Running kube-scheduler %s", config.ArgString(args))
        logrus.Fatalf("scheduler exited: %v", command.Execute())
}()
---------
 
---------
go func() {
        logrus.Infof("Running kube-apiserver %s", config.ArgString(args))
        logrus.Fatalf("apiserver exited: %v", command.Execute())
}()
startupConfig := <-app.StartupConfig
return startupConfig.Authenticator, startupConfig.Handler, nil
---------

以kube-apiserver為例,在k3s server的thread中執(zhí)行它,還需另外兩項(xiàng)工作:

  1. 在k3s中引入kube-apiserver代碼,并將其編譯到k3s binary中,這部分在源碼中的go.mod中有所體現(xiàn)

  2. 由于是在thread中執(zhí)行,所以k3s不能執(zhí)行apiserver的main函數(shù),這部分在上面提到server.go源碼中也有體現(xiàn)

k3s server的goroutine除了剛才提到的controlplane相關(guān)服務(wù)外,還包括默認(rèn)內(nèi)置運(yùn)行的flannel/ingress controller,更有一些k3s擴(kuò)展的一些高級controller,這部分我們會以單獨(dú)的文章進(jìn)行分析。

以上內(nèi)容,我們只是在單獨(dú)的k3s server層面分析,一旦我們加入一個節(jié)點(diǎn)作為worker,那么worker節(jié)點(diǎn)上會怎樣的展現(xiàn)?

curl -sfL https://get.k3s.io | K3S_URL=https://myserver:6443 K3S_TOKEN=XXX sh -

我們依然按照上面的思路,先看一下worker節(jié)點(diǎn)上k3s相關(guān)的進(jìn)程和線程情況:

# ps aux | grep k3s
root      1949  0.8 12.2 220060 123648 ?       Ssl  13:12   1:03 /usr/local/bin/k3s agent
root      1967  0.3 13.0 220932 131340 ?       Sl   13:13   0:23 containerd -c /var/lib/rancher/k3s/agent/etc/containerd/config.toml -a /run/k3s/containerd/containerd.sock --state /run/k3s/containerd --root /var/lib/rancher/k3s/agent/containerd
 
# ps -T 1949
  PID  SPID TTY      STAT   TIME COMMAND
1949  1949 ?        Ssl    0:01 /usr/local/bin/k3s agent
1949  1954 ?        Ssl    0:06 /usr/local/bin/k3s agent
1949  1955 ?        Ssl    0:00 /usr/local/bin/k3s agent
1949  1956 ?        Ssl    0:00 /usr/local/bin/k3s agent
1949  1960 ?        Ssl    0:00 /usr/local/bin/k3s agent
1949  1961 ?        Ssl    0:14 /usr/local/bin/k3s agent
...

worker節(jié)點(diǎn)的kubelet和kube-proxy的運(yùn)行方式與k3s server上運(yùn)行api-server/scheduler等服務(wù)的方式是一樣的,也包括agent上flannel和tunnel proxy等服務(wù),都是通過goroutine調(diào)用,并在操作系統(tǒng)上以thread方式運(yùn)行。而worker節(jié)點(diǎn)中,有一個特立獨(dú)行的存在就是containerd(如果你還是喜歡使用docker,請忽略以下內(nèi)容),containerd是作為一個k3s agent的子進(jìn)程來運(yùn)行。

containerd因?yàn)橛衅涮厥庑?,它會為每個容器創(chuàng)建單獨(dú)的containerd-shim進(jìn)程為容器提供運(yùn)行時支持,正因?yàn)檫@樣containerd本身必須是進(jìn)程級別的,它可以擁有獨(dú)立的上下文,進(jìn)而提供容器管理能力。較新版本的k3s,已經(jīng)使用了containerd-shim-runc-v2來運(yùn)行容器,這種模式對k8s的Pod更加友好,早期containerd-shim v1版本,pod的pause容器需要單獨(dú)運(yùn)行一個containerd-shim進(jìn)程,v2版本可以把Pod內(nèi)的容器都放在一個containerd-shim進(jìn)程下運(yùn)行,Pod內(nèi)每個容器會成為這個containerd-shim的子進(jìn)程。比如coredns Pod對應(yīng)的containerd-shim進(jìn)程Pid是2325,那么它的兩個子進(jìn)程分別是coredns本身和pause容器服務(wù):

# pstree -p -aT 2325
containerd-shim,2325 -namespace k8s.io -id 5aad2ea4d09f997baab6a0343dfb10abd86971601bae29200e39cffb5709b938-a
  ├─coredns,2598 -conf /etc/coredns/Corefile
  └─pause,2392

后 記

本文向大家分析了k3s這種單進(jìn)程模式如何運(yùn)行整個k8s服務(wù),相當(dāng)于我們對k3s的原理有了一個基本了解。然而,k3s仍然有很多未解之謎,agent和server如何通信組建集群?k3s內(nèi)置的rootfs起到什么作用?k3s內(nèi)置的CLI工具如何使用?k3s如何實(shí)現(xiàn)使用sqllite/mysql來代替etcd等等,這些問題我們會在后續(xù)文章中一一解答。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容