zoukankan      html  css  js  c++  java
  • k3s的单进程模式如何运行整个K8S服务_转载

    转自:https://juejin.im/post/5dcd0ab4e51d4507fb0d492c

    前 言

    Rancher Labs一直致力于云基础设施的建设,我们发布了很多产品Rancher1.x、Rancher2.x、RancherOS、Longhorn、Rio等来满足基础设施应用的各种场景,但这其中没有一款产品可以和k3s的发展速度相比,整个社区对它的认可超乎我们的想象。发布了仅仅10个月的k3s项目,就在Github上获得超9000颗star数,我们也正星夜兼程,争取在11月份发布1.0GA版本。我将撰写一系列文章来介绍k3s所使用的技术及其原理,尤其是这其中使用的一些黑魔法,它让k3s的体验变得无比美好。更深入更细节得了解k3s,才能将它使用好,让工具本身产生事半功倍的效用,同时也能让大家有机会一起参与k3s社区的建设。

    在这里插入图片描述

    很多人在体验k3s时,都对它的无比精简感到折服。我们都了解Kubernetes(以下简称K8s)是个非常复杂的架构,controlplane中就包括apiserver/controller-manager/scheduler等,worker中还需要有kubelet/kube-proxy,元数据还需要存储在etcd上。这些服务每一项都需要单独部署,还需要进行配置联动,尽管我们可以借用很多开源工具(比如RKE),但是部署前你还是需要准备大量镜像或者二进制文件等。k3s的部署就非常简便,它通过一个binary就可以部署上面提到的大部分服务,这也就是本文要介绍的内容,k3s的黑魔法之一“单进程k8s”。

    单进程k8s分析

    我们先不管具体如何实现,先来看一下单进程k8s的表面现象。我们安装一个k3s,但禁用agent,这样更有利于观察结果:

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

    这时使用kubectl是看不到node信息,但是我们能够获取namespace信息,这就说明k8s的controlplane相关服务已经启动了:

    # 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程序运行结果,下方可以看到k3s只启动了一个进程:

    # 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其他服务apiserver/scheduler/controller-manager等是如何启动的,我们查看k3s对应的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实现的,而Golang通常并不会直接使用thread,一般是通过goroutine来使用系统的thread,分析源码中k3s server的实现,可以看到api-server/scheduler等服务确实是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中执行它,还需另外两项工作:

    1. 在k3s中引入kube-apiserver代码,并将其编译到k3s binary中,这部分在源码中的go.mod中有所体现

    2. 由于是在thread中执行,所以k3s不能执行apiserver的main函数,这部分在上面提到server.go源码中也有体现

    k3s server的goroutine除了刚才提到的controlplane相关服务外,还包括默认内置运行的flannel/ingress controller,更有一些k3s扩展的一些高级controller,这部分我们会以单独的文章进行分析。

    以上内容,我们只是在单独的k3s server层面分析,一旦我们加入一个节点作为worker,那么worker节点上会怎样的展现?

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

    我们依然按照上面的思路,先看一下worker节点上k3s相关的进程和线程情况:

    # 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节点的kubelet和kube-proxy的运行方式与k3s server上运行api-server/scheduler等服务的方式是一样的,也包括agent上flannel和tunnel proxy等服务,都是通过goroutine调用,并在操作系统上以thread方式运行。而worker节点中,有一个特立独行的存在就是containerd(如果你还是喜欢使用docker,请忽略以下内容),containerd是作为一个k3s agent的子进程来运行。

    containerd因为有其特殊性,它会为每个容器创建单独的containerd-shim进程为容器提供运行时支持,正因为这样containerd本身必须是进程级别的,它可以拥有独立的上下文,进而提供容器管理能力。较新版本的k3s,已经使用了containerd-shim-runc-v2来运行容器,这种模式对k8s的Pod更加友好,早期containerd-shim v1版本,pod的pause容器需要单独运行一个containerd-shim进程,v2版本可以把Pod内的容器都放在一个containerd-shim进程下运行,Pod内每个容器会成为这个containerd-shim的子进程。比如coredns Pod对应的containerd-shim进程Pid是2325,那么它的两个子进程分别是coredns本身和pause容器服务:

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

    后 记

    本文向大家分析了k3s这种单进程模式如何运行整个k8s服务,相当于我们对k3s的原理有了一个基本了解。然而,k3s仍然有很多未解之谜,agent和server如何通信组建集群?k3s内置的rootfs起到什么作用?k3s内置的CLI工具如何使用?k3s如何实现使用sqllite/mysql来代替etcd等等,这些问题我们会在后续文章中一一解答。


    作者:k3s中文社区
    链接:https://juejin.im/post/5dcd0ab4e51d4507fb0d492c
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    Django(三十二)—— Django中建表方式
    Django(三十一)——Django ORM常用字段类型
    IIS部署muweb(需主程序 4.0.0以上版本)
    吴裕雄--天生自然--SPRINGBOOT开发实战学习笔记--创建用户表
    吴裕雄--天生自然--SpringBoot开发实战学习笔记--Oracle11g创建表空间和用户并授权
    吴裕雄--天生自然--SpringBoot开发实战学习笔记--spring boot打jar包发布的方法
    吴裕雄--天生自然--SpringBoot开发实战学习笔记--处理Error creating bean with name 'springApplicationAdminRegistrar' defined in class path resource
    吴裕雄--天生自然--SpringBoot开发实战学习笔记--配置MAVEN
    吴裕雄--天生自然SPRINGBOOT开发实战--SpringBoot 打包
    吴裕雄--天生自然SPRINGBOOT开发实战--SpringBoot DevTools
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/12343298.html
Copyright © 2011-2022 走看看