Kubernetes 源码 (10) CoreDNS

Submitted by Lizhe on Tue, 07/14/2020 - 02:18

曾几何时,我第一次使用kubeadm安装 kubernetes 1.10 时,kubernetes自带的还是 kube-dns,

在一些教材中也一直把kube-dns作为dns服务在k8s上的默认实现。

趁此机会这里我要好好捋一捋,在kubernetes1.11开始,CoreDNS就开始作为 kubeadm的默认实现了

传统的kubeDNS由3个部分组成

  1. kubedns: 依赖 client-go 中的 informer 机制监视 k8s 中的 Service 和 Endpoint 的变化,并将这些结构维护进内存来服务内部 DNS 解析请求。
  2. dnsmasq: 区分 Domain 是集群内部还是外部,给外部域名提供上游解析,内部域名发往 10053 端口,并将解析结果缓存,提高解析效率。
  3. sidecar: 对 kubedns 和 dnsmasq 进行健康检查和收集监控指标。

 

在 kubedns 包含两个部分, kubedns 和 skydns。

Kubernetes 源码 (9) 阶段总结一

Submitted by Lizhe on Tue, 07/14/2020 - 02:01

目前为止,我们已经使用源码编译过了kubernetes的代码,并且使用编译的代码手动启动了一套简单的kubernetes实现

我们使用最基本的三个组件运行了基础 pod

  1. kubelet:在集群中每个节点上运行的代理,负责容器真正运行的核心组件
  2. 为 api-server 安装了 etcd
  3. kube-apiserver:Kubernetes 控制平面的组件,提供资源操作的唯一入口
  4. 容器运行时(Docker)

 

然后使用

5. kube-scheduler 自动分配pod 到 node 节点
6. 并且配合 kube-controller-manager 自动创建了 pod instance
7. 使用kube-proxy 基于 nodepot 对外暴露了 nginx 服务

 

这样一个最基本的kubernetes集群就启动起来了,下面我会尝试一些非必要组件 

Kubernetes 源码 (8) kube-proxy

Submitted by Lizhe on Mon, 07/13/2020 - 06:52

kube-proxy是Kubernetes的核心组件,部署在每个Node节点上,它是实现Kubernetes Service的通信与负载均衡机制的重要组件; kube-proxy负责为Pod创建代理服务,从apiserver获取所有server信息,并根据server信息创建代理服务,实现server到Pod的请求路由和转发,从而实现K8s层级的虚拟转发网络。

我们知道kube-proxy支持 iptables 和 ipvs 两种模式, 在kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于netfilter的,那么 ipvs 模式和 iptables 模式之间有哪些差异呢?

Kubernetes 源码 (7) kube-controller-manager

Submitted by Lizhe on Sun, 07/12/2020 - 09:45

先来一个备注,如果按照下面内容启动之后 你的pod仍然 pending

要注意 请按照下面顺序启动以下这三个组件

 

sudo ./kubelet --pod-manifest-path=pods --fail-swap-on=false --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.2 --kubeconfig=kubeconfig.yaml

./kube-scheduler --kubeconfig=kubeconfig.yaml

./kube-controller-manager --kubeconfig=kubeconfig.yaml

书接上回,上一篇文章里我们启动了 scheduler 之后,pod 确实被自动分配了,但是状态却仍然是pending

这里的根本原因是我们还没有启动 kube-controller-manager , 

Kubernetes 源码 (6) kube-scheduler

Submitted by Lizhe on Wed, 07/08/2020 - 03:08

 

Scheduler 是以一种 多人负责同一工作,然后基于投票激活一个主工作节点 的方式运作的。

领导者选举机制可以保证高可用性,但是正常工作的Scheduler节点只有一个,其他节点作为候选节点处于阻塞状态。

在领导者节点因某些原因而退出后,其他候选节点则通过选举机制竞选,成为新领导的节点将接替原来节点的工作。

 

选举机制是通过分布式锁来实现的,

  1. 分布式锁依赖于 Etcd 上的一个 key,key 的操作都是原子操作,将 key 作为分布式锁,它有两种状态——存在和不存在。

  2. key(分布式锁)不存在时:多节点中的一个节点成功创建该 key(获得锁)并写入自身节点的信息,获得锁的节点被称为领导者节点。领导者节点会定时更新(续约)该 key 的信息。

  3. key(分布式锁)存在时:其他节点处于阻塞状态并定时获取锁,这些节点被称为候选节点。候选节点定时获取锁的过程如下:定时获取 key 的数据,验证数据中领导者租约是否到期,如果未到期则不能抢占它,如果已到期则更新 key 并写入自身节点的信息,更新成功则成为领导者节点。

Kubernetes 源码 (5) 最小化启动

Submitted by Lizhe on Tue, 07/07/2020 - 06:06

这里将尝试使用之前编译完的源码来构建一个最小化启动的集群

20200707020919

要运行一个最小级别的 Kubernetes 至少要包括如下三个基本组件:

  1. kubelet:在集群中每个节点上运行的代理,负责容器真正运行的核心组件
  2. kube-apiserver:Kubernetes 控制平面的组件,提供资源操作的唯一入口
  3. 容器运行时(Docker)

 

我们创建一个 minik8s 的文件夹用来实验

拷贝 kubectl 和 kubelet 两个可执行二进制文件到这个文件夹中,然后创建一个 pods 文件夹

Kubernetes 源码 (4) kube-apiserver

Submitted by Lizhe on Thu, 07/02/2020 - 09:07

kube-apiserver 负责对外暴露管理用的Restful 服务。它是几乎所有其他组件沟通的主要桥梁。

参考下面 Pod 资源创建流程如下:

  1. 使用 Kubectl 工具向 Api Server 发起创建 Pod 资源请求
  2. Api Server 验证请求并将其保存到 Etcd
  3. Api Server 基于Watch机制通知scheduler
  4. Scheduler 根据调度算法为Pod资源对象选择最优节点并通知Api Server
  5. Api Server 将最优节点保存到 Etcd
  6. Api Server 通知该节点上的 kubelet
  7. Kubelet 调用docker环境
  8. Kubelet 将状态报告至 Api Server
  9. Api Server 保存容器状态到 Etcd

由此可见,Api Server 是一切动作交互的桥梁

 

kube-apiserver的启动流程如下

Kubernetes 源码 (3) 万事开头难 Kubectl

Submitted by Lizhe on Thu, 07/02/2020 - 02:49

 

kubectl 命令应该是使用 k8s 的人接触最多的命令了,我们从它开始,

这里我使用的是 vscode , 在debug 配置文件中

 

{

    // Use IntelliSense to learn about possible attributes.

    // Hover to view descriptions of existing attributes.

    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387

    "version": "0.2.0",

    "configurations": [

        {

            "name": "Launch",

            "type": "go",

            "request": "launch",

            "mode": "auto",

Kubernetes 源码 (2) 万物皆有入口

Submitted by Lizhe on Thu, 07/02/2020 - 01:46

 根据 Go语言项目标准项目结构

/cmd

该项目的主程序.

每个程序目录的名字应该和可执行文件的名字保持一致 (比如 /cmd/myapp).

不要在程序目录中放太多代码. 如果你觉得这些代码会被其他项目引用, 那它们应该被放在 /pkg 目录中. 如果这些代码不能被重用, 或者说你不希望别人重用这些代码, 那么就把它们放在 /internal 目录中. 你也许会惊讶于别人使用你代码的方式, 所以一定要保持你的意图足够明确!

一般来说一个足够小的 main 函数, 用于引入并执行 /internal/pkg 下的代码就足够了.

下面我们来看看cmd